From ab08df8f4a6588ea3541a187cccce5c3c559459a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 25 Jun 2021 22:36:16 +0200 Subject: [PATCH] Code style overhaul - fixed code format and a few performance / style flaws - modernized JavaScript (always use arrow function now) - rewrote main menu, the main menu code itself can now be restarted without having to reload the page (but other pieces of code need to be made compatible still) - better inventory hiding / showing - use EventTarget for some things that were previously done by callbacks - added basic support for running as a chrome app (e.g. the quit button closing the app) - focus more on chrome / chromium instead of firefox, fix graphical flaws caused by chromium acting different than chrome - automatic error reporting - gui tweaks, especially in main menu - some terminology changes and simplification of internal structures, less polluted dragonblocks namespace - more effective interaction with backend, do more things backend-side - use saved DOM element references instead of IDs in some cases - use less object orientation in cases where it does not make sense to use OOP --- api.php | 94 ++++-- credits.json | 2 +- engine/assets.js | 66 ++++ engine/builtin.js | 31 +- engine/chat.js | 155 ++++++--- engine/chatcommands.js | 44 ++- engine/craftfield.js | 63 ++-- engine/creative_inventory.js | 119 ++++--- engine/entity.js | 47 ++- engine/falling_node.js | 40 ++- engine/group.js | 40 ++- engine/gui.js | 224 ++++++++----- engine/hudbar.js | 91 +++-- engine/init.js | 403 +++++++++++----------- engine/inventory.js | 264 +++++++-------- engine/inventory_container.js | 96 ++++-- engine/inventory_group.js | 72 ++-- engine/item.js | 113 ++++--- engine/item_entity.js | 21 +- engine/item_stack.js | 263 +++++++++++++++ engine/itemstack.js | 122 ------- engine/key_handler.js | 101 ++++-- engine/mainmenu.js | 614 +++++++++++++++++++++------------- engine/map.js | 201 ++++++----- engine/map_interaction.js | 228 ++++++++----- engine/map_node.js | 48 ++- engine/mapgen.js | 339 ++++++++++++------- engine/menu.js | 77 +++-- engine/node.js | 150 +++++---- engine/out_stack.js | 47 +++ engine/pixel_manipulator.js | 106 +++--- engine/player.js | 304 +++++++++++------ engine/recipe.js | 66 ++-- engine/ressources.js | 89 ----- engine/skin.js | 70 ++-- engine/spawned_entity.js | 293 +++++++++++----- engine/timer.js | 32 +- engine/tool.js | 51 +-- engine/world.js | 66 ++-- game/chest/init.js | 4 +- game/furnace/inventory.js | 52 +-- game/furnace/itemdef.js | 4 +- game/plants/plants.js | 16 +- game/skins/ui.js | 19 +- game/tnt/init.js | 2 +- index.html | 29 +- lib/dblib.js | 4 - settings.json | 8 - style.css | 2 +- version.json | 8 + 50 files changed, 3319 insertions(+), 2081 deletions(-) create mode 100644 engine/assets.js create mode 100644 engine/item_stack.js delete mode 100644 engine/itemstack.js create mode 100644 engine/out_stack.js delete mode 100644 engine/ressources.js create mode 100644 version.json diff --git a/api.php b/api.php index 3479aaf..ea390e5 100644 --- a/api.php +++ b/api.php @@ -1,55 +1,107 @@ /dev/null")); array_pop($base); echo json_encode($base); } - function check_worldname($name){ + + function walk_directory($path, $func) + { + $data = array(); + + $files = scandir($path); + + foreach ($files as $filename) { + if ($filename[0] == ".") + continue; + + $result = $func($filename, $path . "/" . $filename); + + $data[$filename] = $result; + } + + echo json_encode($data); + } + + function check_worldname($name) + { return preg_match("/^[a-zA-Z0-9]+$/", $name); } - function world_exists($name){ + + function world_exists($name) + { return check_worldname($name) && file_exists("worlds/" . $name); } - switch($_POST["call"]){ + + function get_mods($path) + { + walk_directory($path, function($modname, $modpath) { + $dependencies = file_get_contents($modpath . "/dependencies.txt"); + + return array( + "name" => $modname, + "description" => file_get_contents($modpath . "/description.txt"), + "dependencies" => $dependencies ? array_values(array_filter(explode("\n", $dependencies))) : array(), + "path" => $modpath, + ); + }); + } + + switch($_POST["call"]) { case "getGamemods": - get_directory("game"); + get_mods("game"); break; + case "getMods": - get_directory("mods"); + get_mods("mods"); break; + case "getWorlds": - get_directory("worlds"); + walk_directory("worlds", function($worldname, $path) { + return array( + "name" => $worldname, + "owned" => is_loggedin() && get_username() == file_get_contents($path . "/owner.txt"), + ); + }); break; + case "getTextures": - get_directory("textures/* game/*/textures/* mods/*/textures/*"); + get_files("textures/* game/*/textures/* mods/*/textures/*"); break; + case "getSounds": - get_directory("sounds/* game/*/sounds/* mods/*/sounds/*"); + get_files("sounds/* game/*/sounds/* mods/*/sounds/*"); break; + case "isLoggedin": echo json_encode(is_loggedin()); break; + case "getUsername": echo get_username(); break; - case "checkWorldname": - echo json_encode(check_worldname($_POST["name"]) || false); - break; + case "saveWorld": - if(! is_loggedin()) - break; - if(! $_POST["name"]) - break; - if(! check_worldname($_POST["name"])) - break; - if(! world_exists($_POST["name"])) + if (! is_loggedin()) + return; + else if (! $_POST["name"]) + return; + else if (! check_worldname($_POST["name"])) + return; + + if (! world_exists($_POST["name"])) mkdir("worlds/" . $_POST["name"]); - else if(file_get_contents("worlds/" . $_POST["name"] . "/owner.txt") != get_username()) + else if (file_get_contents("worlds/" . $_POST["name"] . "/owner.txt") != get_username()) return; + file_put_contents("worlds/" . $_POST["name"] . "/world.json", $_POST["world"]); file_put_contents("worlds/" . $_POST["name"] . "/owner.txt", get_username()); break; + case "commitID": echo shell_exec("git rev-parse --short HEAD"); break; diff --git a/credits.json b/credits.json index c3ff50d..8316d75 100644 --- a/credits.json +++ b/credits.json @@ -5,7 +5,7 @@ "

HimbeerserverDE

", "

SC++

", "

THANKS TO

", - "

The Elidragon Team

The game could have never been done without your support!

", + "

The Elidragon Team

The game could have never been possible without your support!

", "

Our Javascript Teachers

", "

Minetest

" ] diff --git a/engine/assets.js b/engine/assets.js new file mode 100644 index 0000000..aef2340 --- /dev/null +++ b/engine/assets.js @@ -0,0 +1,66 @@ +/* + * assets.js + * + * Copyright 2020 Elias Fleckenstein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +let loadAssets = type => { + let obj = {}; + dragonblocks[type] = obj; + + let paths = dragonblocks.backendCall("get" + type[0].toUpperCase() + type.slice(1, type.length)); + for (path of paths) { + let name = path.slice(path.lastIndexOf("/") + 1, path.length); + obj[name] = path; + } +}; + +loadAssets("textures"); +loadAssets("sounds"); + +dragonblocks.getTexture = name => { + if (! name) + return "none"; + + let path = dragonblocks.textures[name]; + + return path ? "url(" + path + ")" : name; +}; + +dragonblocks.resolveTextures = elem => { + if (elem.nodeName == "IMG" && elem.attributes["texture"]) { + let name = elem.attributes["texture"].nodeValue; + elem.src = dragonblocks.textures[name] || name; + } + + for (let child of elem.children) + dragonblocks.resolveTextures(child); +}; + +dragonblocks.getSound = name => { + if(! name) + return ""; + + return dragonblocks.sounds[name] || name; +}; + +dragonblocks.playSound = name => { + new Audio(dragonblocks.getSound(name)).play(); +}; diff --git a/engine/builtin.js b/engine/builtin.js index 03b95bf..b33c8d9 100644 --- a/engine/builtin.js +++ b/engine/builtin.js @@ -1,25 +1,26 @@ /* * builtin.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ + dragonblocks.registerNode({ name: "air", texture: "none", @@ -31,41 +32,47 @@ dragonblocks.registerNode({ return false; } }); + dragonblocks.registerGroup({ name: "default", - sounds:{ + sounds: { dig: "sounds/dig.ogg", dug: "sounds/dug.ogg", place: "sounds/place.ogg", } }); + dragonblocks.registerGroup({ name: "cracky", - sounds:{ + sounds: { dig: "sounds/dig_cracky.ogg", } }); + dragonblocks.registerGroup({ name: "crumbly", - sounds:{ + sounds: { dig: "sounds/dig_crumbly.ogg", } }); + dragonblocks.registerGroup({ name: "snappy", - sounds:{ + sounds: { dig: "sounds/dig_snappy.ogg", } }); + dragonblocks.registerGroup({ name: "choppy", - sounds:{ + sounds: { dig: "sounds/dig_choppy.ogg", } }); + dragonblocks.registerGroup({ name: "liquid", - sounds:{ + sounds: { dig: "", dug: "", place: "", diff --git a/engine/chat.js b/engine/chat.js index 136c794..2548394 100644 --- a/engine/chat.js +++ b/engine/chat.js @@ -1,42 +1,50 @@ /* * chat.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Chat = class{ - constructor(){ + +dragonblocks.Chat = class +{ + constructor() + { this.input = [""]; this.history = -1; this.lines = dragonblocks.settings.chat.lines; + this.addGraphics(); this.clear(); + dragonblocks.keyHandler.down("t", _ => { dragonblocks.chat.open(); }); + dragonblocks.keyHandler.down("/", event => { dragonblocks.chat.open(); document.getElementById("dragonblocks.chat.input").value = "/"; }); } - addGraphics(){ - let display = document.createElement("div"); + + addGraphics() + { + let display = document.body.appendChild(document.createElement("div")); display.id = "dragonblocks.chat"; display.style.position = "fixed"; display.style.top = "0px"; @@ -51,8 +59,8 @@ dragonblocks.Chat = class{ display.style.overflowY = "scroll"; display.style.scrollbarWidth = "none"; display.style.visibility = "hidden"; - document.body.appendChild(display); - let input = document.createElement("input"); + + let input = document.body.appendChild(document.createElement("input")); input.id = "dragonblocks.chat.input"; input.style.position = "fixed"; input.style.top = 23 * this.lines + "px"; @@ -68,80 +76,127 @@ dragonblocks.Chat = class{ input.style.caretHeight = "20px"; input.style.fontFamily = "monospace"; input.style.visibility = "hidden"; + + let self = this; + input.addEventListener("keydown", event => { - switch(event.key){ + switch (event.key) { case "Enter": - if(event.srcElement.value == "") - return; - dragonblocks.chat.input[dragonblocks.chat.input.length - 1] = event.srcElement.value; - dragonblocks.chat.send(event.srcElement.value); + let message = event.srcElement.value; event.srcElement.value = ""; - dragonblocks.chat.input.push(""); - dragonblocks.chat.history = -1; + + if (message == "") + return; + + self.input[self.input.length - 1] = message; + self.send(message); + self.input.push(""); + + self.history = -1; break; + case "Escape": - dragonblocks.chat.close(); + self.close(); break; + case "ArrowUp": - event.srcElement.value = dragonblocks.chat.historyUp(); + event.srcElement.value = self.historyUp(); break; + case "ArrowDown": - event.srcElement.value = dragonblocks.chat.historyDown(); + event.srcElement.value = self.historyDown(); break; } }); - input.addEventListener("input", _ => { dragonblocks.chat.input[dragonblocks.chat.input.length - 1] = event.srcElement.value }); - document.body.appendChild(input); - } - open(){ + + input.addEventListener("input", event => { + self.input[self.input.length - 1] = event.srcElement.value; + }); + } + + open() + { dragonblocks.keyHandler.lockAll(); + document.getElementById("dragonblocks.chat").style.visibility = "visible"; - document.getElementById("dragonblocks.chat.input").style.visibility = "visible"; - document.getElementById("dragonblocks.chat.input").focus(); + + let input = document.getElementById("dragonblocks.chat.input"); + input.style.visibility = "visible"; + input.focus(); } - close(){ - setTimeout(_ => {dragonblocks.keyHandler.unlockAll();}); + + close() + { + setTimeout(_ => { + dragonblocks.keyHandler.unlockAll(); + }); + document.getElementById("dragonblocks.chat").style.visibility = "hidden"; - document.getElementById("dragonblocks.chat.input").style.visibility = "hidden"; - document.getElementById("dragonblocks.chat.input").blur(); + + let input = document.getElementById("dragonblocks.chat.input"); + input.style.visibility = "hidden"; + input.blur(); } - write(text){ + + write(text) + { text = text || ""; - if(text.startsWith("!HTML")) + + if (text.startsWith("!HTML")) text = text.replace("!HTML", ""); else text = dblib.htmlEntities(text); + text += "
"; - document.getElementById("dragonblocks.chat").innerHTML += text; - document.getElementById("dragonblocks.chat").lastChild.scrollIntoView(); + + let display = document.getElementById("dragonblocks.chat"); + display.innerHTML += text; + display.lastChild.scrollIntoView(); } - send(input){ - for(let func of dragonblocks.onChatMessageFunctions) - if(func(input) == false) + + send(input) + { + for (let func of dragonblocks.onChatMessageCallbacks) + if (func(input) == false) return false; + this.write(input); } - historyUp(){ + + historyUp() + { this.history--; - if(this.input[this.input.length + this.history] == undefined) + + if (this.input[this.input.length + this.history] == undefined) this.history++; + return this.input[this.input.length + this.history]; } - historyDown(){ + + historyDown() + { this.history++; - if(this.input[this.input.length + this.history] == undefined) + + if (this.input[this.input.length + this.history] == undefined) this.history--; + return this.input[this.input.length + this.history]; } - clear(){ + + clear() + { document.getElementById("dragonblocks.chat").innerHTML = "
".repeat(this.lines); } }; + dragonblocks.chat = new dragonblocks.Chat(); -dragonblocks.chatMessage = function(msg){ + +dragonblocks.chatMessage = msg => { dragonblocks.chat.write(msg); -} -dragonblocks.onChatMessageFunctions = []; -dragonblocks.registerOnChatMessage = function(func){ - dragonblocks.onChatMessageFunctions.push(func); -} +}; + +dragonblocks.onChatMessageCallbacks = []; + +dragonblocks.registerOnChatMessage = func => { + dragonblocks.onChatMessageCallbacks.push(func); +}; diff --git a/engine/chatcommands.js b/engine/chatcommands.js index acec78c..9e66fec 100644 --- a/engine/chatcommands.js +++ b/engine/chatcommands.js @@ -1,49 +1,59 @@ /* * chatcommands.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * - */ + * + * + */ + dragonblocks.chatcommands = {}; -dragonblocks.registerChatcommand = function(obj){ - if(! obj || ! obj.name) + +dragonblocks.registerChatcommand = def => { + if (! def || ! def.name) return; - obj.desc = obj.desc || obj.description || "No description"; - obj.param = obj.param || obj.parameters || ""; - dragonblocks.chatcommands[obj.name] = obj; + + def.desc = def.desc || def.description || "No description"; + def.param = def.param || def.params || def.parameter || def.parameters || ""; + + dragonblocks.chatcommands[def.name] = def; } + dragonblocks.registerOnChatMessage(msg => { if( ! msg.startsWith("/")) return true; + msg += " "; + let command = msg.slice(msg.search("/") + 1, msg.search(" ")); + let arg = msg.slice(msg.search(" ") + 1); arg = arg.slice(0, arg.length - 1); - if(dragonblocks.chatcommands[command]){ + + if (dragonblocks.chatcommands[command]) { try { dragonblocks.chatcommands[command].func(arg); } - catch(e){ - dragonblocks.chatMessage("!HTML " + e.toString() + ""); + catch (err) { + dragonblocks.chatMessage("!HTML " + err.toString() + ""); } - } - else + } else { dragonblocks.chatMessage("Invalid Command: " + command); + } + return false; }); diff --git a/engine/craftfield.js b/engine/craftfield.js index 345ade9..38a981b 100644 --- a/engine/craftfield.js +++ b/engine/craftfield.js @@ -1,59 +1,76 @@ /* * craftfield.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Craftfield = class extends dragonblocks.Inventory{ - constructor(width, height){ + +dragonblocks.Craftfield = class extends dragonblocks.Inventory +{ + constructor(width, height) + { super(width * height, width); + this.width = width; this.height = height; + + this.resultfield = new dragonblocks.ItemStack(); + let self = this; - this.resultfield = new dragonblocks.Itemstack(); this.resultfield.action = out => { out.add(self.resultfield) && self.reduce(); } - this.addUpdateListener(_ => { + + this.addEventListener("updateStack", _ => { self.update(); }); } - calculateWidth(){ + + calculateWidth() + { return super.calculateWidth() + dragonblocks.settings.inventory.scale * 1.1 * 2; } - draw(parent, x, y){ - if (!super.draw(parent, x, y)) + + draw(parent, x, y) + { + if (! super.draw(parent, x, y)) return false; - dragonblocks.Inventory.drawStack(this.getDisplay(), dragonblocks.settings.inventory.scale * 0.1 + (this.width + 1) * dragonblocks.settings.inventory.scale * 1.1, dragonblocks.settings.inventory.scale * 0.1 + (this.height / 2 - 0.5) * dragonblocks.settings.inventory.scale * 1.1, this.resultfield) + + this.resultfield.draw(this.getDisplay(), dragonblocks.settings.inventory.scale * 0.1 + (this.width + 1) * dragonblocks.settings.inventory.scale * 1.1, dragonblocks.settings.inventory.scale * 0.1 + (this.height / 2 - 0.5) * dragonblocks.settings.inventory.scale * 1.1); } - reduce(){ - for(let stack of this.list){ - let vstack = dragonblocks.createItemstack(); + + reduce() + { + for (let stack of this.list) { + let vstack = new dragonblocks.ItemStack(); vstack.addOne(stack); } this.update(); } - update(){ - this.resultfield.parse(""); - for(let recipe of dragonblocks.recipes){ - if(recipe.match(this)) - return this.resultfield.parse(recipe.result); + + update() + { + this.resultfield.deserialize(""); + + for (let recipe of dragonblocks.recipes) { + if (recipe.match(this)) + return this.resultfield.deserialize(recipe.result); } } -} +}; diff --git a/engine/creative_inventory.js b/engine/creative_inventory.js index 7c134f7..b85331f 100644 --- a/engine/creative_inventory.js +++ b/engine/creative_inventory.js @@ -1,102 +1,125 @@ /* * creative_inventory.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.CreativeInventory = class extends dragonblocks.Inventory{ - constructor(slots, list, columns){ + +dragonblocks.CreativeInventory = class extends dragonblocks.Inventory +{ + constructor(slots, list, columns) + { super(slots, columns); + this.fullList = list || this.list; + this.page = 0; this.pages = Math.ceil(this.fullList.length / this.list.length); - let inventory = this; - for(let i = 0; i < this.slots; i++){ - i = parseInt(i); - this.list[i].addUpdateListener(_ => { - if(inventory.list[i].refilling) + + let self = this; + + for (let i = 0; i < this.slots; i++) { + let stack = this.list[i]; + stack.addEventListener("update", event => { + if (event.stack.refilling) return; - inventory.list[i].refilling = true; - inventory.list[i].parse(inventory.fullList[inventory.slots * inventory.page + i] || ""); - inventory.list[i].refilling = false; + + stack.refilling = true; + stack.deserialize(self.fullList[self.slots * self.page + i] || ""); + stack.refilling = false; }); } } - calculateHeight(){ + + calculateHeight() + { return super.calculateHeight() + dragonblocks.settings.inventory.scale; } - draw(parent, x, y){ - if (!super.draw(parent, x, y)) + + draw(parent, x, y) + { + if (! super.draw(parent, x, y)) return false; - let inventory = this; - this.getDisplay().style.height = this.calculateHeight(); - let creativeDisplay = document.createElement("div"); + + let display = this.getDisplay(); + display.style.height = this.calculateHeight(); + + let creativeDisplay = display.appendChild(document.createElement("div")); creativeDisplay.id = "dragonblocks.inventory[" + this.id + "].creative"; creativeDisplay.style.height = dragonblocks.settings.inventory.scale + "px"; - creativeDisplay.style.width = this.calculateWidth(); + creativeDisplay.style.width = this.calculateWidth() + "px"; creativeDisplay.style.left = "0px"; creativeDisplay.style.top = super.calculateHeight() + "px"; creativeDisplay.style.position = "absolute"; - this.getDisplay().appendChild(creativeDisplay); - creativeDisplay = document.getElementById(creativeDisplay.id); - let pageDisplay = document.createElement("span"); + + let pageDisplay = creativeDisplay.appendChild(document.createElement("span")); pageDisplay.id = "dragonblocks.inventory[" + this.id + "].creative.page"; - pageDisplay.style.color = "343434"; + pageDisplay.style.color = "#343434"; pageDisplay.style.position = "absolute"; pageDisplay.style.left = dragonblocks.settings.inventory.scale * 1.1 + "px"; pageDisplay.style.width = "100%"; - pageDisplay.style.fontSize = dragonblocks.settings.inventory.scale / (5/3) + "px"; - pageDisplay.style.height = dragonblocks.settings.inventory.scale / (5/3) + "px"; - creativeDisplay.appendChild(pageDisplay); - dblib.centerVertical(document.getElementById(pageDisplay.id)); - for(let dir of ["left", "right"]){ - let arrow = document.createElement("div"); + pageDisplay.style.fontSize = dragonblocks.settings.inventory.scale / (5 / 3) + "px"; + pageDisplay.style.height = dragonblocks.settings.inventory.scale / (5 / 3) + "px"; + + dblib.centerVertical(pageDisplay); + + let self = this; + + for (let dir of ["left", "right"]) { + let arrow = creativeDisplay.appendChild(document.createElement("div")); arrow.id = "dragonblocks.inventory[" + this.id + "].creative.arrow." + dir; arrow.style.position = "absolute"; arrow.style.width = dragonblocks.settings.inventory.scale + "px"; arrow.style.height = dragonblocks.settings.inventory.scale + "px"; - arrow.style.position = "absolute"; arrow.style[dir] = "0px"; arrow.style.background = dragonblocks.getTexture("arrow.png"); arrow.style.backgroundSize = "cover"; arrow.style.cursor = "pointer"; - if(dir == "right") + + if (dir == "right") arrow.style.transform = "rotate(180deg)"; + arrow.addEventListener("click", _ => { if(dir == "right") - inventory.page++; + self.page++; else - inventory.page--; - inventory.update(); + self.page--; + self.update(); }); - creativeDisplay.appendChild(arrow); - dblib.centerVertical(document.getElementById(arrow.id)); + + dblib.centerVertical(arrow); } + this.update(); - } - update(){ - if(this.page == -1) - this.page = 0; - if(this.page == this.pages) + } + + update() + { + if (this.page == -1) + this.page++; + + if (this.page == this.pages) this.page--; - document.getElementById("dragonblocks.inventory[" + this.id + "].creative.page").textContent = "Page " + (this.page + 1 ) + " of " + this.pages; - for(let slot of this.list) + + document.getElementById("dragonblocks.inventory[" + this.id + "].creative.page").textContent = "Page " + (this.page + 1) + " of " + this.pages; + + for (let slot of this.list) slot.update(); } -} +}; diff --git a/engine/entity.js b/engine/entity.js index 1acf4b8..b4799fd 100644 --- a/engine/entity.js +++ b/engine/entity.js @@ -1,41 +1,52 @@ /* * entity.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Entity = class{ - constructor(obj){ - dblib.copy(this, obj); + +dragonblocks.Entity = class +{ + constructor(def) + { + dblib.copy(this, def); + dragonblocks.entities[this.name] = this; dragonblocks.registeredEntities.push(this); } - spawn(x, y){ + + spawn(x, y) + { return new dragonblocks.SpawnedEntity(this, x, y); } -} +}; + dragonblocks.entities = {}; dragonblocks.registeredEntities = []; -dragonblocks.registerEntity = function(obj){ - new dragonblocks.Entity(obj); -} -dragonblocks.spawnEntity = function(name, x, y){ - if(dragonblocks.entities[name]) - return dragonblocks.entities[name].spawn(x, y); -} + +dragonblocks.registerEntity = def => { + new dragonblocks.Entity(def); +}; + +dragonblocks.spawnEntity = (name, x, y) => { + let def = dragonblocks.entities[name]; + + if (def) + return def.spawn(x, y); +}; diff --git a/engine/falling_node.js b/engine/falling_node.js index 99cdfe2..13f2a6e 100644 --- a/engine/falling_node.js +++ b/engine/falling_node.js @@ -1,25 +1,26 @@ /* * falling_node.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ + dragonblocks.registerEntity({ name: "dragonblocks:falling_node", gravity: true, @@ -27,23 +28,34 @@ dragonblocks.registerEntity({ height: 1, texture: this.texture, oncollide: self => { - if(! dragonblocks.getNode(Math.floor(self.x), Math.floor(self.y) + 1) || dragonblocks.getNode(Math.floor(self.x), Math.floor(self.y) + 1).mobstable){ + let under = dragonblocks.getNode(Math.floor(self.x), Math.floor(self.y) + 1); + + if (! under || under.mobstable) { dragonblocks.setNode(Math.floor(self.x), Math.floor(self.y), self.meta.nodeName); self.despawn(); } } -}); +}); dragonblocks.registerOnActivateNode((x, y) => { - if(dragonblocks.getNode(x, y).toNode().physics && dragonblocks.getNode(x, y + 1) && ! dragonblocks.getNode(x, y + 1).mobstable) - dragonblocks.spawnFallingNode(dragonblocks.getNode(x, y).name, x, y) -}) + let node = dragonblocks.getNode(x, y); + if (! node.toNode().physics) + return; + + let under = dragonblocks.getNode(x, y + 1); + if (under && ! under.mobstable) + dragonblocks.spawnFallingNode(node.name, x, y) +}); + +dragonblocks.spawnFallingNode = (nodename, x, y) => { + setTimeout(_ => { + dragonblocks.map.activate(x, y); + }, 50); -dragonblocks.spawnFallingNode = function(nodename, x, y) { - setTimeout(_ => {dragonblocks.map.activate(x, y);}, 50); dragonblocks.setNode(x, y, "air"); + let entity = dragonblocks.spawnEntity("dragonblocks:falling_node", x, y); entity.meta.nodeName = nodename; entity.texture = dragonblocks.nodes[nodename].texture; entity.updateTexture(); -} +}; diff --git a/engine/group.js b/engine/group.js index 0e9ecf5..202b6b5 100644 --- a/engine/group.js +++ b/engine/group.js @@ -1,38 +1,44 @@ /* * group.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Group = class{ - constructor(obj){ - if(!obj) - dragonblocks.error("Can not register group: Missing argument"); - dblib.copy(this, obj); - if(! this.name) - dragonblocks.error("Can not register group: Missing name"); + +dragonblocks.Group = class +{ + constructor(def) + { + def || dragonblocks.error("Cannot register group: Missing argument"); + + dblib.copy(this, def); + + this.name || dragonblocks.error("Cannot register group: Missing name"); + dragonblocks.groups[this.name] = this; dragonblocks.registeredGroups.push(this); } -} +}; + dragonblocks.groups = {}; dragonblocks.registeredGroups = []; -dragonblocks.registerGroup = function(obj){ - new dragonblocks.Group(obj); -} + +dragonblocks.registerGroup = def => { + new dragonblocks.Group(def); +}; diff --git a/engine/gui.js b/engine/gui.js index 3024a83..ddff23f 100644 --- a/engine/gui.js +++ b/engine/gui.js @@ -1,40 +1,30 @@ /* * gui.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ + dragonblocks.gui = {}; -dragonblocks.gui.toggleLayer = function(){ - dragonblocks.gui.layerShown ? dragonblocks.gui.hideLayer() : dragonblocks.gui.showLayer(); -} -dragonblocks.gui.showLayer = dragonblocks.gui.openLayer = function(){ - dragonblocks.gui.layerShown = true; - document.getElementById("dragonblocks.gui.layer").style.visibility = "visible"; -} -dragonblocks.gui.hideLayer = dragonblocks.gui.closeLayer = function(){ - dragonblocks.gui.layerShown = false; - document.getElementById("dragonblocks.gui.layer").style.visibility = "hidden"; -} + { - let layer = document.createElement("div"); - layer.id = "dragonblocks.gui.layer"; + let layer = document.body.appendChild(document.createElement("div")); layer.style.opacity = 0.7; layer.style.position = "fixed"; layer.style.width = "100%"; @@ -43,125 +33,175 @@ dragonblocks.gui.hideLayer = dragonblocks.gui.closeLayer = function(){ layer.style.left = "0px"; layer.style.backgroundColor = "black"; layer.style.visibility = "hidden"; - document.body.appendChild(layer); + + let layerShown = false; + + dragonblocks.gui.toggleLayer = _ => { + layerShown ? dragonblocks.gui.hideLayer() : dragonblocks.gui.showLayer(); + }; + + dragonblocks.gui.showLayer = dragonblocks.gui.openLayer = _ => { + layerShown = true; + layer.style.visibility = "visible"; + }; + + dragonblocks.gui.hideLayer = dragonblocks.gui.closeLayer = _ => { + layerShown = false; + layer.style.visibility = "hidden"; + }; } -dragonblocks.gui.Box = class{ - constructor(properties){ + +dragonblocks.gui.Box = class extends EventTarget +{ + constructor(def) + { + super(); this.moveable = false; this.closeable = true; - this.size = "big"; + this.big = true; this.layer = true; this.scroll = true; this.keylock = false; - if(properties) - dblib.copy(this, properties); - let self = this; + + if (def) + dblib.copy(this, def); + this.id = "dragonblocks.gui.box[" + dragonblocks.getToken() + "]"; + this.x = 0; this.y = 0; + this.dragging = false; - let display = document.createElement("div"); + + let display = document.body.appendChild(document.createElement("div")); display.id = this.id; - display.style.width = "500px"; - display.style.height = "300px"; - if(this.size == "big"){ - display.style.width = "700px"; - display.style.height = "500px"; - } + display.style.width = this.big ? "700px" : "500px"; + display.style.height = this.big ? "500px" : "300px"; display.style.position = "fixed"; display.style.backgroundColor = "#7E7E7E"; display.style.visibility = "hidden"; - if(this.scroll) + dblib.center(display); + dblib.centerVertical(display); + + if (this.scroll) display.style.overflowY = "scroll"; - let moveField = document.createElement("div"); + + this.moveable && this.addMoveField(); + this.closeable && this.addCloseField(); + } + + addMoveField() + { + let moveField = this.create("div"); moveField.id = this.id + ".moveField"; moveField.style.position = "absolute"; moveField.style.left = "0px"; moveField.style.top = "0px"; - moveField.style.width = "30px"; - moveField.style.height = "30px"; - if(this.size == "big"){ - moveField.style.width = "50px"; - moveField.style.height = "50px"; - } + moveField.style.width = this.big ? "50px": "30px"; + moveField.style.height = this.big ? "50px": "30px"; moveField.style.background = dragonblocks.getTexture("move.png"); moveField.style.backgroundSize = "cover" moveField.style.cursor = "move"; - if(this.moveable) - display.appendChild(moveField); - let closeField = document.createElement("div"); - closeField.id = this.id + ".closeField"; - closeField.style.position = "absolute"; - closeField.style.right = "0px"; - closeField.style.top = "0px"; - closeField.style.width = "30px"; - closeField.style.height = "30px"; - if(this.size == "big"){ - closeField.style.width = "50px"; - closeField.style.height = "50px"; - } - closeField.style.background = dragonblocks.getTexture("close.png"); - closeField.style.backgroundSize = "cover"; - closeField.style.cursor = "pointer"; - closeField.addEventListener("mousedown", _ => { - self.close(); - }); - if(this.closeable) - display.appendChild(closeField); + + let self = this; + let display = this.getDisplay(); + display.addEventListener("mousedown", event => { - if(event.srcElement.id != moveField.id) + if (event.srcElement.id != moveField.id) return; + self.x = event.clientX; self.y = event.clientY; + self.dragging = true; }); + display.addEventListener("mousemove", event => { - if(! self.dragging) + if (! self.dragging) return; + let display = self.getDisplay(); - let posX = self.x - event.clientX; - let posY = self.y - event.clientY; + + let x = self.x - event.clientX; + let y = self.y - event.clientY; + self.x = event.clientX; self.y = event.clientY; - display.style.left = display.offsetLeft - posX + "px"; - display.style.top = display.offsetTop - posY + "px"; + + display.style.left = display.offsetLeft - x + "px"; + display.style.top = display.offsetTop - y + "px"; }); + addEventListener("mouseup", event => { self.dragging = false; }); - document.body.appendChild(display); - dblib.center(this.getDisplay()); - dblib.centerVertical(this.getDisplay()); } - getDisplay(){ + + addCloseField() + { + let closeField = this.create("div"); + closeField.id = this.id + ".closeField"; + closeField.style.position = "absolute"; + closeField.style.right = "0px"; + closeField.style.top = "0px"; + closeField.style.width = this.big ? "50px": "30px"; + closeField.style.height = this.big ? "50px": "30px"; + closeField.style.background = dragonblocks.getTexture("close.png"); + closeField.style.backgroundSize = "cover"; + closeField.style.cursor = "pointer"; + + let self = this; + closeField.addEventListener("mousedown", _ => { + self.close(); + }); + } + + getDisplay() + { return document.getElementById(this.id); } - setContent(html){ + + setContent(html) + { this.getDisplay().innerHTML = html; } - open(){ + + open() + { this.getDisplay().style.visibility = "visible"; - if(this.layer) - dragonblocks.gui.openLayer(); - if(this.keylock) - dragonblocks.keyHandler.lockAll(); - this.onopen && this.onopen(); + + this.layer && dragonblocks.gui.openLayer(); + this.keylock && dragonblocks.keyHandler.lockAll(); + + this.dispatchEvent(new dragonblocks.gui.Box.Event("open")); } - close(){ + + close() + { this.getDisplay().style.visibility = "hidden"; - if(this.layer) - dragonblocks.gui.closeLayer(); - if(this.keylock) - dragonblocks.keyHandler.unlockAll(); - this.onclose && this.onclose(); + + this.layer && dragonblocks.gui.closeLayer(); + this.keylock && dragonblocks.keyHandler.unlockAll(); + + this.dispatchEvent(new dragonblocks.gui.Box.Event("close")); } - add(elem){ + + add(elem) + { return this.getDisplay().appendChild(elem); } - create(elementname){ - return this.add(document.createElement(elementname)); + + create(tag) + { + return this.add(document.createElement(tag)); } -} -dragonblocks.gui.createBox = function(properties){ - return new dragonblocks.gui.Box(properties); -} +}; + +dragonblocks.gui.Box.Event = class extends Event +{ + constructor(type, box) + { + super(type); + this.box = box; + } +}; diff --git a/engine/hudbar.js b/engine/hudbar.js index a28b317..354d8d3 100644 --- a/engine/hudbar.js +++ b/engine/hudbar.js @@ -1,39 +1,48 @@ /* * hudbar.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Hudbar = class{ - constructor(inventory, slots){ + +dragonblocks.Hudbar = class +{ + constructor(inventory, slots) + { this.id = dragonblocks.getToken(); + this.inventory = inventory; this.slots = slots; + this.selectedSlot = 0; - let display = document.createElement("div"); + + let display = document.body.insertBefore(document.createElement("div"), document.getElementById("dragonblocks.map").nextSibling); display.id = "dragonblocks.hudbar[" + this.id + "]"; display.style.position = "fixed"; display.style.bottom = "5px"; display.style.height = "60px"; display.style.width = "445px"; + + dblib.center(display); + for(let i = 0; i < this.slots; i++){ - let slotDisplay = document.createElement("div"); + let slotDisplay = display.appendChild(document.createElement("div")); slotDisplay.id = "dragonblocks.hudbar[" + this.id + "].slot[" + i + "]"; slotDisplay.style.position = "absolute"; slotDisplay.style.top = "3px"; @@ -42,65 +51,83 @@ dragonblocks.Hudbar = class{ slotDisplay.style.height = "50px"; slotDisplay.style.backgroundColor = "black"; slotDisplay.style.boxShadow = "0 0 0 3px #C5C5C5"; - let slotCountDisplay = document.createElement("span"); + + let slotCountDisplay = slotDisplay.appendChild(document.createElement("span")); slotCountDisplay.id = slotDisplay.id + ".count"; slotCountDisplay.style.position = "absolute"; slotCountDisplay.style.right = "5px"; slotCountDisplay.style.bottom = "5px"; slotCountDisplay.style.color = "white"; - slotDisplay.appendChild(slotCountDisplay); - display.appendChild(slotDisplay); } - let selectorDisplay = document.createElement("div"); + + let selectorDisplay = display.appendChild(document.createElement("div")); selectorDisplay.id = "dragonblocks.hudbar[" + this.id + "].selector"; selectorDisplay.style.position = "absolute"; selectorDisplay.style.top = "3px"; selectorDisplay.style.width = "50px"; selectorDisplay.style.height = "50px"; selectorDisplay.style.boxShadow = "0 0 0 5px #999999"; - display.appendChild(selectorDisplay); - let itemnameDisplay = document.createElement("span"); + + let itemnameDisplay = display.appendChild(document.createElement("span")); itemnameDisplay.id = "dragonblocks.hudbar[" + this.id + "].itemname"; itemnameDisplay.style.position = "absolute"; itemnameDisplay.style.bottom = "60px"; itemnameDisplay.style.color = "white"; itemnameDisplay.style.fontSize = "20px"; - display.appendChild(itemnameDisplay); - display = document.body.insertBefore(display, document.getElementById("dragonblocks.map").nextSibling); - dblib.center(display); + this.update(); } - nextItem(){ - (this.selectedSlot++ == 7) && (this.selectedSlot = 0); + + nextItem() + { + if (++this.selectedSlot == this.slots) + this.selectedSlot = 0; + this.update(); } - previousItem(){ - (this.selectedSlot-- == 0) && (this.selectedSlot = 7); + + previousItem() + { + if (--this.selectedSlot == -1) + this.selectedSlot = this.slots - 1; this.update(); } - select(i){ + + select(i) + { this.selectedSlot = i; this.update(); } - update(){ + + update() + { let display = document.getElementById("dragonblocks.hudbar[" + this.id + "]"); - if(! display) + + if (! display) return; - for(let i = 0; i < this.slots; i++){ + + for (let i = 0; i < this.slots; i++) { let itemstack = this.inventory.getSlot(i); + let slotDisplay = document.getElementById("dragonblocks.hudbar[" + this.id + "].slot[" + i + "]"); slotDisplay.style.background = itemstack.item ? dragonblocks.getTexture(itemstack.toItem().texture) : "black"; slotDisplay.style.backgroundSize = "cover"; slotDisplay.style.opacity = itemstack.item ? 1 : 0.3; + document.getElementById(slotDisplay.id + ".count").innerHTML = (itemstack.count <= 1) ? "" : itemstack.count; - if(i == this.selectedSlot){ + + if (i == this.selectedSlot) { document.getElementById("dragonblocks.hudbar[" + this.id + "].selector").style.left = slotDisplay.style.left; - document.getElementById("dragonblocks.hudbar[" + this.id + "].itemname").innerHTML = itemstack.item ? itemstack.toItem().desc : ""; - dblib.center(document.getElementById("dragonblocks.hudbar[" + this.id + "].itemname")); + + let itemname_elem = document.getElementById("dragonblocks.hudbar[" + this.id + "].itemname"); + itemname_elem.innerHTML = itemstack.item ? itemstack.toItem().desc : ""; + dblib.center(itemname_elem); } } } - getSelectedItem(){ + + getSelectedItem() + { return this.inventory.getSlot(this.selectedSlot); } -} +}; diff --git a/engine/init.js b/engine/init.js index f3c0523..0f76fb1 100644 --- a/engine/init.js +++ b/engine/init.js @@ -20,199 +20,218 @@ * * */ -$.ajaxSetup({ - async: false, - cache: false -}); -addEventListener("contextmenu", event => { - event.preventDefault(); -}); -dragonblocks = {}; -dragonblocks.settings = $.getJSON("settings.json").responseJSON; -dragonblocks.backlog = ""; -dragonblocks.mods = []; -dragonblocks.settings.version.commit = $.get({ - url: "api.php", - method: "POST", - data: {call: "commitID"} -}).responseText || dragonblocks.settings.version.commit; -dragonblocks.gamemods = $.getJSON({ - method: "POST", - url: "api.php", - data: {call: "getGamemods"}, -}).responseJSON; -dragonblocks.availableMods = $.getJSON({ - method: "POST", - url: "api.php", - data: {call: "getMods"}, -}).responseJSON; -dragonblocks.loggedin = $.getJSON({ - url: "api.php", - method: "POST", - data: {call: "isLoggedin"} -}).responseJSON; -dragonblocks.username = "singleplayer"; -if(dragonblocks.loggedin){ - dragonblocks.username = $.post({ - url: "api.php", - data: {call: "getUsername"} - }).responseText; -} -dragonblocks.log = function(text){ - console.log("[Dragonblocks] " + text); - dragonblocks.backlog += text + "\n"; -} -dragonblocks.error = function(err){ - let error = new Error(err); - dragonblocks.backlog += error; - throw error; -} -dragonblocks.getToken = function(){ - return "#" + (Math.random() * 10).toString().replace(".", ""); -} -dragonblocks.getModpath = function(mod){ - if(dragonblocks.availableMods.indexOf(mod) != -1) - return "mods/" + mod; - if(dragonblocks.gamemods.indexOf(mod) != -1) - return "game/" + mod; -} -dragonblocks.getVersion = function(){ - let version = dragonblocks.settings.version; - return "Dragonblocks " + version.major + "." + version.minor + (version.patch ? "." + version.patch : "") + (version.development ? "-dev-" + version.commit : ""); -} -dragonblocks.start = function(){ - for(let func of dragonblocks.onStartFunctions) - func(); - setTimeout(_ => { - for(let mod of dragonblocks.gamemods) - dragonblocks.loadMod(mod); - for(let mod of dragonblocks.mods) - dragonblocks.loadMod(mod); - new dragonblocks.Map(); - new dragonblocks.Player(); - if(! dragonblocks.worldIsLoaded) - dragonblocks.generateMap(); - for(let func of dragonblocks.onStartedFunctions) - func(); +{ + dragonblocks = {}; + + dragonblocks.backendCall = (call, plain, data) => { + data = data || {}; + data.call = call; + + let fetchFunc = plain ? $.get : $.getJSON; + + let response = fetchFunc({ + url: "api.php", + method: "POST", + data: data, + }); + + return plain ? response.responseText : response.responseJSON; + }; + + dragonblocks.settings = $.getJSON("settings.json").responseJSON; + + let version = dragonblocks.version = $.getJSON("version.json").responseJSON; + version.commit = version.development && (dragonblocks.backendCall("commitID", true) || "?"); + version.string = "Dragonblocks " + + version.major + + "." + version.minor + + (version.patch ? "." + version.patch : "") + + (version.development ? "-dev-" + version.commit : ""); + + dragonblocks.isChromeApp = window.chrome && chrome.app; + + addEventListener("error", event => { + if (confirm(event.message + "\nStack trace: \n" + event.error.stack + "\nPlease report this to the dragonblocks developers.")) + location.href = version.repo + "/issues/new?" + + "title=" + encodeURIComponent(event.message) + + "&body=" + encodeURIComponent(event.error.stack) }); -} -dragonblocks.onStartFunctions = []; -dragonblocks.registerOnStart = function(func){ - dragonblocks.onStartFunctions.push(func); -} -dragonblocks.onStartedFunctions = []; -dragonblocks.registerOnStarted = function(func){ - dragonblocks.onStartedFunctions.push(func); -} -dragonblocks.addFinalStep = function(step){ - dragonblocks.registerOnStarted(step); - dragonblocks.log("dragonblocks.addFinalStep(...) is deprecated. Use dragonblocks.registerOnStarted instead. Trace:"); - console.trace(); -} -dragonblocks.quit = function(){ - for(let func of dragonblocks.onQuitFunctions) - func(); - if(dragonblocks.loggedin) + + dragonblocks.backlog = ""; + + dragonblocks.loadModList = _ => { + dragonblocks.gamemods = dragonblocks.backendCall("getGamemods"); + dragonblocks.mods = dragonblocks.backendCall("getMods"); + }; + + dragonblocks.loggedin = dragonblocks.backendCall("isLoggedin"); + dragonblocks.username = dragonblocks.loggedin ? dragonblocks.backendCall("getUsername", true) : "singleplayer"; + + dragonblocks.log = text => { + console.log("[Dragonblocks] " + text); + dragonblocks.backlog += text + "\n"; + }; + + dragonblocks.error = err => { + let error = new Error(err); + dragonblocks.backlog += error; + + throw error; + }; + + dragonblocks.getToken = _ => { + return "#" + (Math.random() * 10).toString().replace(".", ""); + }; + + dragonblocks.getModInfo = modname => { + return dragonblocks.mods[modname] || dragonblocks.gamemods[modname]; + }; + + dragonblocks.getModpath = modname => { + return dragonblocks.getModInfo(modname).path; + }; + + let loadingMods = {}; + + let loadMod = modname => { + if (loadingMods[modname]) + dragonblocks.error("Circular Mod Dependencies: " + modname); + + if (dragonblocks.loadedMods[modname]) + return; + + let modinfo = dragonblocks.getModInfo(modname); + + if (! modinfo) + dragonblocks.error("Unresolved Mod Dependencies: " + modname); + + loadingMods[modname] = true; + + for (let dependency of modinfo.dependencies) + loadMod(dependency); + + $.getScript(modinfo.path + "/init.js"); + + dragonblocks.loadedMods[modname] = modinfo; + loadingMods[modname] = false; + }; + + dragonblocks.start = selectedMods => { + dragonblocks.log("Starting"); + + for (let func of dragonblocks.onStartCallbacks) + func(); + setTimeout(_ => { - dragonblocks.save(); - location.reload(); + dragonblocks.loadedMods = {}; + + for (let mod in selectedMods) + if (selectedMods[mods]) + loadMod(mod); + + for (let mod in dragonblocks.gamemods) + loadMod(mod); + + dragonblocks.map = new dragonblocks.Map(); + dragonblocks.map.load(); + + dragonblocks.player = new dragonblocks.Player(); + + dragonblocks.worldIsLoaded || dragonblocks.generateMap(); + + for (let func of dragonblocks.onStartedCallbacks) + func(); }); - else - location.reload(); -} -dragonblocks.onQuitFunctions = []; -dragonblocks.registerOnQuit = function(func){ - dragonblocks.onQuitFunctions.push(func); -} -dragonblocks.loadWorld = function(world){ - dragonblocks.worldIsLoaded = true; - dragonblocks.worldname = world; - dragonblocks.world = $.getJSON("worlds/" + world + "/world.json").responseJSON; - dragonblocks.mods = dragonblocks.world.mods; - dragonblocks.start(); -} -dragonblocks.createWorld = function(properties){ - dragonblocks.worldIsLoaded = false; - dragonblocks.worldname = properties.worldname; - dragonblocks.world = dragonblocks.getEmptyWorld(); - dragonblocks.entities["dragonblocks:player"].meta.creative = (properties.gamemode == "creative"); - for(mod in properties.mods) - properties.mods[mod] && dragonblocks.mods.push(mod); - dragonblocks.mapgen.selected = properties.mapgen; - dragonblocks.start(); -} -dragonblocks.loadedMods = []; -dragonblocks.loadingMods = {}; -dragonblocks.loadMod = function(modname){ - if(! modname) - return; - if(dragonblocks.loadingMods[modname]) - dragonblocks.error("Circular Mod Dependencies: " + modname); - if(dragonblocks.loadedMods.indexOf(modname) != -1) - return; - if(dragonblocks.gamemods.indexOf(modname) != -1) - var modpath = "game/" + modname; - else if(dragonblocks.availableMods.indexOf(modname) != -1) - var modpath = "mods/" + modname; - else - dragonblocks.error("Unsolved Mod Dependencies: " + modname); - let dependencyRequest = $.get(modpath + "/dependencies.txt"); - if(dependencyRequest.status == 200){ - let dependencies = dependencyRequest.responseText.split("\n"); - for(let dependency of dependencies) - dragonblocks.loadMod(dependency); - } - $.getScript(modpath + "/init.js"); - dragonblocks.loadedMods.push(modname); - dragonblocks.loadingMods[modname] = false; -} -dragonblocks.modules = [ - "ressources", - "key_handler", - "gui", - "mapgen", - "world", - "item", - "node", - "tool", - "group", - "builtin", - "map_node", - "map", - "itemstack", - "inventory", - "inventory_group", - "hudbar", - "inventory_container", - "creative_inventory", - "recipe", - "craftfield", - "menu", - "skin", - "entity", - "map_interaction", - "spawned_entity", - "item_entity", - "falling_node", - "timer", - "player", - "pixel_manipulator", - "chat", - "chatcommands", - "mainmenu", -]; -dragonblocks.moduleCount = dragonblocks.modules.length; -dragonblocks.loadModule = function(){ - if(dragonblocks.modules[0]){ - document.getElementById("elidragon.status").innerHTML = dragonblocks.modules[0] + ".js"; - $.getScript({ - url: "engine/" + dragonblocks.modules.shift() + ".js", - async: true, - success: _ => { - document.getElementById("elidragon.loadbar").style.width = (dragonblocks.moduleCount - dragonblocks.modules.length) / dragonblocks.moduleCount * 100 + "%"; - dragonblocks.loadModule(); - }, - }); - } + }; + + dragonblocks.onStartCallbacks = []; + dragonblocks.registerOnStart = func => { + dragonblocks.onStartCallbacks.push(func); + }; + + dragonblocks.onStartedCallbacks = []; + dragonblocks.registerOnStarted = func => { + dragonblocks.onStartedCallbacks.push(func); + }; + + dragonblocks.quit = _ => { + for (let func of dragonblocks.onQuitCallbacks) + func(); + + if (dragonblocks.loggedin) + setTimeout(_ => { + dragonblocks.save(); + location.reload(); + }); + else + location.reload(); + }; + + dragonblocks.onQuitCallbacks = []; + dragonblocks.registerOnQuit = func => { + dragonblocks.onQuitCallbacks.push(func); + }; + + let modules = [ + "assets", + "key_handler", + "gui", + "mapgen", + "world", + "item", + "node", + "tool", + "group", + "builtin", + "map_node", + "map", + "item_stack", + "inventory", + "out_stack", + "inventory_group", + "hudbar", + "inventory_container", + "creative_inventory", + "recipe", + "craftfield", + "menu", + "skin", + "entity", + "map_interaction", + "spawned_entity", + "item_entity", + "falling_node", + "timer", + "player", + "pixel_manipulator", + "chat", + "chatcommands", + "mainmenu", + ]; + + let moduleCount = modules.length; + + let status = document.getElementById("elidragon.status"); + let loadbar = document.getElementById("elidragon.loadbar"); + + let loadNextModuleRecursive = _ => { + let nextModule = modules.shift(); + + if (nextModule) { + let filename = nextModule + ".js"; + status.innerHTML = filename; + + $.getScript({ + url: "engine/" + filename, + async: true, + cache: false, + success: _ => { + loadbar.style.width = (moduleCount - modules.length) / moduleCount * 100 + "%"; + loadNextModuleRecursive(); + }, + }); + } + }; + + loadNextModuleRecursive(); } -dragonblocks.loadModule(); diff --git a/engine/inventory.js b/engine/inventory.js index 391b013..b714245 100644 --- a/engine/inventory.js +++ b/engine/inventory.js @@ -1,217 +1,179 @@ /* * inventory.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Inventory = class{ - constructor(slots, columns){ + +dragonblocks.Inventory = class extends EventTarget +{ + constructor(slots, columns) + { + super(); this.id = dragonblocks.getToken(); + this.slots = slots; this.columns = columns; this.list = []; - for(let i = 0; i < this.slots; i++){ - this.list[i] = new dragonblocks.createItemstack(); + + let self = this; + + for (let i = 0; i < this.slots; i++){ + let stack = this.list[i] = new dragonblocks.ItemStack(); + stack.addEventListener("update", event => { + self.dispatchEvent(new dragonblocks.Inventory.Event("updateStack", event.stack)); + }); } + this.display = false; } - stringify(){ - let str = "" - for(let stack of this.list) - str += stack.stringify() + ","; + + serialize() + { + let str = ""; + + for (let stack of this.list) + str += stack.serialize() + ","; + return str; } - parse(str){ - for(let i in this.list) - this.list[i].parse(str.split(",")[i]); - } - add(itemstring){ - var itemstack = dragonblocks.createItemstack(itemstring); - for(let stack of this.list) + + deserialize(str) + { + let strList = str.split(","); + + for (let i in this.list) + this.list[i].deserialize(strList[i]); + } + + add(itemstring) + { + let itemstack = new dragonblocks.ItemStack(itemstring); + + for (let stack of this.list) stack.item == itemstack.item && stack.add(itemstack); - for(let stack of this.list) + + for (let stack of this.list) stack.add(itemstack); + return itemstack; } - isEmpty(){ - for(let stack of this.list) - if(stack.item) + + isEmpty() + { + for (let stack of this.list) + if (stack.item) return false; + return true; } - addUpdateListener(func){ - for(let stack of this.list) - stack.addUpdateListener(func); - } - clear(){ + + clear() + { for(let stack of this.list) stack.clear(); } - calculateWidth(columns){ + + calculateWidth(columns) + { return dragonblocks.settings.inventory.scale * 1.1 * this.columns + (dragonblocks.settings.inventory.scale * 0.1); } - calculateHeight(){ - return dragonblocks.settings.inventory.scale * 1.1 * Math.ceil(this.slots/this.columns) + dragonblocks.settings.inventory.scale * 0.1 - } - draw(parent, x, y){ - if(this.display){ - if(this.getDisplay().parentElement != parent) - this.remove(); - else{ - this.getDisplay().style.left = x + "px"; - this.getDisplay().style.top = y + "px"; + + calculateHeight() + { + return dragonblocks.settings.inventory.scale * 1.1 * Math.ceil(this.slots / this.columns) + dragonblocks.settings.inventory.scale * 0.1 + } + + draw(parent, x, y) + { + if (this.display) { + let display = this.getDisplay(); + if (display.parentElement == parent) { + display.style.left = x + "px"; + display.style.top = y + "px"; return false; + } else { + this.remove(); } } - let display = document.createElement("div"); + + this.display = true; + + let display = parent.appendChild(document.createElement("div")); display.id = "dragonblocks.inventory[" + this.id + "]"; display.style.position = "absolute"; display.style.left = x + "px"; display.style.top = y + "px"; display.style.width = this.calculateWidth() + "px"; display.style.height = this.calculateHeight() + "px"; - for(let i in this.list){ + + let scale = dragonblocks.settings.inventory.scale * 1.1; + let offset = dragonblocks.settings.inventory.scale * 0.1; + + for (let i in this.list) { let x = i % this.columns; let y = (i - x) / this.columns; - dragonblocks.Inventory.drawStack(display, dragonblocks.settings.inventory.scale * 0.1 + x * dragonblocks.settings.inventory.scale * 1.1, dragonblocks.settings.inventory.scale * 0.1 + y * dragonblocks.settings.inventory.scale * 1.1, this.list[i]); + this.list[i].draw(display, offset + x * scale, offset + y * scale); } - parent.appendChild(display); - this.display = true; + return true; } - remove(){ - dblib.remove(this.getDisplay()); + + remove() + { + this.getDisplay().remove(); this.display = false; } - show(){ + + show() + { this.getDisplay().style.visibility = "inherit"; this.update(); } - hide(){ + + hide() + { this.getDisplay().style.visibility = "hidden"; } - update(){ - for(let stack of this.list) + + update() + { + for (let stack of this.list) stack.update(); } - getSlot(i){ + + getSlot(i) + { return this.list[i]; } - getDisplay(){ + + getDisplay() + { return document.getElementById("dragonblocks.inventory[" + this.id + "]"); } - static drawStack(parent, x, y, stack){ - let stackDisplay = document.createElement("div"); - stackDisplay.id = "dragonblocks.itemstack[" + stack.id + "]"; - stackDisplay.stackid = stack.id; - stackDisplay.style.borderStyle = "solid"; - stackDisplay.style.borderWidth = "1px"; - stackDisplay.style.borderColor = "#2D2D2D"; - stackDisplay.style.width = dragonblocks.settings.inventory.scale + "px"; - stackDisplay.style.height = dragonblocks.settings.inventory.scale + "px"; - stackDisplay.style.backgroundColor = "#343434"; - stackDisplay.style.position = "absolute"; - stackDisplay.style.left = x + "px"; - stackDisplay.style.top = y + "px"; - stackDisplay.addEventListener("mousedown", event => { - let out = dragonblocks.Inventory.out; - if(stack.action) - return stack.action(out, event.which); - switch(event.which){ - case 1: - if(out.item) - stack.add(out) || stack.swap(out); - else - out.add(stack); - break; - case 3: - if(out.item) - stack.addOne(out) || stack.swap(out); - else - out.addHalf(stack); - } - }); - stackDisplay.addEventListener("mouseover", event => { - stack.focused = true; - dragonblocks.Inventory.redrawStack(stack); - }); - stackDisplay.addEventListener("mouseleave", event => { - stack.focused = false; - dragonblocks.Inventory.redrawStack(stack); - }); - let stackDisplayCount = document.createElement("span"); - stackDisplayCount.id = "dragonblocks.itemstack[" + stack.id + "].count"; - stackDisplayCount.stackid = stack.id; - stackDisplayCount.style.position = "absolute"; - stackDisplayCount.style.right = "5px"; - stackDisplayCount.style.bottom = "5px"; - stackDisplayCount.style.color = "white"; - stackDisplayCount.style.cursor = "default"; - stackDisplay.appendChild(stackDisplayCount); - parent.appendChild(stackDisplay); - stack.addUpdateListener(_ => { - dragonblocks.Inventory.redrawStack(stack); - }); - stack.update(); - } - static redrawStack(stack){ - let stackDisplay = document.getElementById("dragonblocks.itemstack[" + stack.id + "]"); - if(! stackDisplay) - return; - let stackDisplayCount = document.getElementById("dragonblocks.itemstack[" + stack.id + "].count"); - stackDisplay.title = ""; - stackDisplay.style.background = "none"; - stackDisplayCount.innerHTML = ""; - if(stack.item){ - stackDisplay.style.background = dragonblocks.getTexture(stack.toItem().texture); - stackDisplay.style.backgroundSize = "cover"; - stackDisplay.title = stack.toItem().desc; - if(stack.count > 1) - stackDisplayCount.innerHTML = stack.count; - } - stackDisplay.style.backgroundColor = "#343434"; - if(stack.focused) - stackDisplay.style.backgroundColor = "#7E7E7E"; - if(stack.onredraw) - stack.onredraw(); - } - static getStackDisplay(id){ - return document.getElementById("dragonblocks.itemstack[" + id + "]"); - } - static insertElement(elem){ - document.body.insertBefore(elem, dragonblocks.Inventory.getStackDisplay(dragonblocks.Inventory.out.id)); +}; + +dragonblocks.Inventory.Event = class extends Event +{ + constructor(type, stack) + { + super(type); + this.stack = stack; } }; -setTimeout((function(){ - let out = dragonblocks.Inventory.out = new dragonblocks.createItemstack(); - dragonblocks.Inventory.drawStack(document.body, 0, 0, out); - dragonblocks.Inventory.getStackDisplay(out.id).style.position = "fixed"; - out.addUpdateListener(_ => { - dragonblocks.Inventory.redrawStack(out); - }); - out.onredraw = _ => { - dragonblocks.Inventory.getStackDisplay(out.id).style.backgroundColor = ""; - dragonblocks.Inventory.getStackDisplay(out.id).style.border = "none"; - }; - addEventListener("mousemove", event => { - dragonblocks.Inventory.getStackDisplay(out.id).style.left = event.clientX + 5 + "px"; - dragonblocks.Inventory.getStackDisplay(out.id).style.top = event.clientY + 5 + "px"; - }); - out.update(); -})); diff --git a/engine/inventory_container.js b/engine/inventory_container.js index e3887f9..f3d5c2d 100644 --- a/engine/inventory_container.js +++ b/engine/inventory_container.js @@ -1,79 +1,103 @@ /* * inventory_container.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * - */ -dragonblocks.InventoryContainer = class{ - constructor(obj){ - dblib.copySimple(this, obj); + * + * + */ + +dragonblocks.InventoryContainer = class extends EventTarget +{ + constructor(def) + { + super(); + dblib.copySimple(this, def); } - draw(parent, x, y){ - if(this.display){ - if(this.getDisplay().parentElement != parent) - this.remove(); - else{ - this.getDisplay().style.left = x + "px"; - this.getDisplay().style.top = y + "px"; + + draw(parent, x, y) + { + if (this.display) { + let display = this.getDisplay(); + if (display.parentElement == parent) { + display.style.left = x + "px"; + display.style.top = y + "px"; return false; + } else { + this.remove(); } } - let display = document.createElement("div"); + + let display = parent.appendChild(document.createElement("div")); display.id = "dragonblocks.inventoryContainer[" + this.inventory.id + "]"; display.style.width = this.calculateWidth() + "px"; display.style.height = this.calculateHeight() + "px"; display.style.left = x + "px"; display.style.top = y + "px"; - display = parent.appendChild(display); + this.inventory.draw(display, dragonblocks.settings.inventory.scale * 1.1 * this.left, dragonblocks.settings.inventory.scale * 1.1 * this.top); + this.display = true; return true; } - parse(str){ - this.inventory.parse(str); - } - stringify(str){ - return this.inventory.stringify(); + + serialize() + { + return this.inventory.serialize(); } - addUpdateListener(func){ - this.inventory.addUpdateListener(func); + + deserialize(str) + { + this.inventory.deserialize(str); } - remove(){ - dblib.remove(this.getDisplay()); + + remove() + { + this.getDisplay().remove(); } - show(){ + + show() + { this.getDisplay().style.visibility = "inherit"; this.update(); } - hide(){ + + hide() + { this.getDisplay().style.visibility = "hidden"; } - calculateWidth(){ + + calculateWidth() + { return this.inventory.calculateWidth() + dragonblocks.settings.inventory.scale * 1.1 * (this.left + this.right); } - calculateHeight(){ - return this.inventory.calculateHeight() + dragonblocks.settings.inventory.scale * 1.1 * (this.top + this.bottom); + + calculateHeight() + { + return this.inventory.calculateHeight() + dragonblocks.settings.inventory.scale * 1.1 * (this.top + this.bottom); } - getDisplay(){ + + getDisplay() + { return document.getElementById("dragonblocks.inventoryContainer[" + this.inventory.id + "]"); } - update(){ + + update() + { this.inventory.update(); } -} +}; diff --git a/engine/inventory_group.js b/engine/inventory_group.js index c5dce14..098f993 100644 --- a/engine/inventory_group.js +++ b/engine/inventory_group.js @@ -1,72 +1,96 @@ /* * inventory_group.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.InventoryGroup = class{ - constructor(){ + +dragonblocks.InventoryGroup = class +{ + constructor() + { this.id = dragonblocks.getToken(); + this._elements = []; this.opened = false; - var display = document.createElement("div"); + + let display = dragonblocks.addInventoryMenuDisplay(document.createElement("div")); display.id = "dragonblocks.inventoryGroup[" + this.id + "]"; display.style.position = "fixed"; display.style.backgroundColor = "#535353"; display.style.visibility = "hidden"; - dragonblocks.Inventory.insertElement(display); } - close(){ + + close() + { this.opened = false; + document.getElementById("dragonblocks.inventoryGroup[" + this.id + "]").style.visibility = "hidden"; - dragonblocks.Inventory.getStackDisplay(dragonblocks.Inventory.out.id).style.visibility = "hidden"; + dragonblocks.outStack.getDisplay().style.visibility = "hidden"; + if(this.onNextClose) this.onNextClose(); - this.onNextInventoryClose = null; + + this.onNextClose = null; } - open(){ + + open() + { this.opened = true; - document.getElementById("dragonblocks.inventoryGroup[" + this.id + "]").style.visibility = "visible"; - dragonblocks.Inventory.getStackDisplay(dragonblocks.Inventory.out.id).style.visibility = "visible"; + + document.getElementById("dragonblocks.inventoryGroup[" + this.id + "]").style.visibility = "inherit"; + dragonblocks.outStack.getDisplay().style.visibility = "visible"; } - toggle(){ + + toggle() + { this.opened ? this.close() : this.open(); } - set elements(elements){ - for(let element of this.elements) + + set elements(elements) + { + for (let element of this.elements) element.hide(); + this._elements = elements; + + let container = document.getElementById("dragonblocks.inventoryGroup[" + this.id + "]"); + let height = 0; let width = 0; - let container = document.getElementById("dragonblocks.inventoryGroup[" + this.id + "]"); - for(let element of this.elements){ + + for (let element of this.elements) { element.draw(container, 0, height); height += element.calculateHeight(); width = Math.max(width, element.calculateWidth()); element.show(); } - container.style.width = width + "px"; + + container.style.width = width + "px"; container.style.height = height + "px"; + dblib.center(container); dblib.centerVertical(container); } - get elements(){ + + get elements() + { return this._elements; } -} +}; diff --git a/engine/item.js b/engine/item.js index af832c5..b6ec460 100644 --- a/engine/item.js +++ b/engine/item.js @@ -1,82 +1,95 @@ /* * item.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Item = class{ - constructor(obj){ - if(! obj) - dragonblocks.error("Can not register item: Missing argument"); - dblib.copy(this, obj); - if(! this.name) - dragonblocks.error("Can not register item: Missing name"); - if(! this.texture) - dragonblocks.error("Can not register item: Missing texture"); - if(dragonblocks.items[this.name]) - dragonblocks.error("Can not register item '" + this.name + "': Item already exists"); - if(this.desc != "" && this.description != "") + +dragonblocks.Item = class +{ + constructor(def) + { + def || dragonblocks.error("Cannot register item: Missing argument"); + + dblib.copy(this, def); + + this.name || dragonblocks.error("Cannot register item: Missing name"); + this.texture || dragonblocks.error("Cannot register item: Missing texture"); + dragonblocks.items[this.name] && dragonblocks.error("Cannot register item '" + this.name + "': Item already exists"); + + if (this.desc != "" && this.description != "") this.desc = this.description || this.desc || this.name; + this.stacksize = this.stacksize || dragonblocks.settings.item.defaultStacksize; + this.groups = this.groups || []; this.groups.push("default"); + dragonblocks.items[this.name] = this; dragonblocks.registeredItems.push(this); } - inGroup(name){ - return (this.groups.indexOf(name) != -1); + + inGroup(name) + { + return this.groups.includes(name); } - playSound(s){ - if(this.sounds && this.sounds[s]){ - dragonblocks.playSound(this.sounds[s]); + + playSound(s) + { + let sound = this.sounds && this.sounds[s]; + + if (sound == "") return; - } - else if(this.sounds && this.sounds[s] == "") - return; - for(let groupname of this.groups){ - let group = dragonblocks.groups[groupname]; - if(group && group.sounds && group.sounds[s]){ - dragonblocks.playSound(group.sounds[s]); - return; + + if (sound) { + dragonblocks.playSound(sound); + } else { + for (let groupname of this.groups){ + let group = dragonblocks.groups[groupname]; + let sound = group && group.sounds && group.sounds[s]; + + if (sound == "") + return; + + if (sound) { + dragonblocks.playSound(sound); + return; + } } - else if(group && group.sounds && group.sounds[s] == "") - return; } } -} +}; + dragonblocks.registeredItems = []; dragonblocks.items = {}; -dragonblocks.registerItem = function(obj){ - new dragonblocks.Item(obj); -} -dragonblocks.onUseItemFunctions = []; -dragonblocks.registerOnUseItem = function(func){ - dragonblocks.onUseItemFunctions.push(func); + +dragonblocks.registerItem = def => { + new dragonblocks.Item(def); }; -dragonblocks.itemMatch = function(item1, item2){ - if(dragonblocks.items[item1]) - item1 = dragonblocks.items[item1]; - if(dragonblocks.items[item2]) - item2 = dragonblocks.items[item2]; - if(dragonblocks.groups[item1]) - item1 = dragonblocks.groups[item1]; - if(dragonblocks.groups[item2]) - item2 = dragonblocks.groups[item2]; + +dragonblocks.onUseItemCallbacks = []; +dragonblocks.registerOnUseItem = func => { + dragonblocks.onUseItemCallbacks.push(func); +}; + +dragonblocks.itemMatch = (item1, item2) => { + item1 = dragonblocks.items[item1] || dragonblocks.groups[item1] || item1; + item2 = dragonblocks.items[item2] || dragonblocks.groups[item2] || item2; return item1 == item2 || item1 && item2 && (item1.name == item2.name || item1.inGroup && item1.inGroup(item2.name) || item2.inGroup && item2.inGroup(item1.name)); -} +}; diff --git a/engine/item_entity.js b/engine/item_entity.js index 2e790c3..e263565 100644 --- a/engine/item_entity.js +++ b/engine/item_entity.js @@ -1,25 +1,25 @@ /* * item_entity.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * - */ + * + * + */ dragonblocks.registerEntity({ name: "dragonblocks:item_entity", @@ -36,11 +36,12 @@ dragonblocks.registerEntity({ }, }); -dragonblocks.dropItem = function(itemstack, x, y) { +dragonblocks.dropItem = (itemstack, x, y) => { if (! itemstack || ! itemstack.item || ! itemstack.count) return; + let entity = dragonblocks.spawnEntity("dragonblocks:item_entity", x, y); - entity.meta.itemstring = itemstack.stringify(); + entity.meta.itemstring = itemstack.serialize(); entity.texture = itemstack.toItem().texture; entity.updateTexture(); -} +}; diff --git a/engine/item_stack.js b/engine/item_stack.js new file mode 100644 index 0000000..cee5ee6 --- /dev/null +++ b/engine/item_stack.js @@ -0,0 +1,263 @@ +/* + * item_stack.js + * + * Copyright 2020 Elias Fleckenstein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +dragonblocks.ItemStack = class extends EventTarget +{ + constructor(itemstring) + { + super(); + + this.count = 0; + this.item = null; + this.id = dragonblocks.getToken(); + + if (itemstring) + this.deserialize(itemstring); + } + + serialize() + { + if (! this.item) + return ""; + return this.item + " " + this.count; + } + + deserialize(itemstring) + { + this.item = itemstring ? itemstring.split(" ")[0] : null; + this.count = itemstring ? parseInt(itemstring.split(" ")[1]) || 1 : 1; + + this.update(); + } + + getStacksize() + { + return (this.toItem() && this.toItem().stacksize) || dragonblocks.settings.item.defaultStacksize; + } + + trigger(eventType) + { + this.dispatchEvent(new dragonblocks.ItemStack.Event(eventType, this)); + } + + update() + { + if (this.count <= 0) + this.item = null; + + if (! this.item) + this.count = 0; + + this.trigger("update"); + } + + toItem() + { + return dragonblocks.items[this.item]; + } + + swap(itemstack) + { + [this.count, itemstack.count] = [itemstack.count, this.count]; + [this.item, itemstack.item] = [itemstack.item, this.item]; + + itemstack.update(); + this.update(); + } + + clear() + { + this.item = null; + this.update(); + } + + addItems(itemstack, count) + { + this.update(); + itemstack.update(); + + if (! itemstack.item) + return false; + + if (! this.item) + this.item = itemstack.item; + else if (this.item != itemstack.item) + return false; + + if (this.count == this.getStacksize()) + return false; + + itemstack.count -= count; + this.count += count; + + let less = -itemstack.count; + if (less > 0) { + itemstack.count += less; + this.count -= less; + } + + let more = this.count - this.getStacksize(); + if (more > 0) { + this.count -= more; + itemstack.count += more; + } + + this.update(); + itemstack.update(); + + return true; + } + + add(itemstack) + { + return this.addItems(itemstack, itemstack.count); + } + + addOne(itemstack) + { + return this.addItems(itemstack, 1); + } + + addHalf(itemstack) + { + return this.addItems(itemstack, Math.ceil(itemstack.count / 2)); + } + + getDisplay() + { + return document.getElementById("dragonblocks.itemstack[" + this.id + "]"); + } + + draw(parent, x, y) + { + let display = parent.appendChild(document.createElement("div")); + display.id = "dragonblocks.itemstack[" + this.id + "]"; + display.stackid = this.id; + display.style.borderStyle = "solid"; + display.style.borderWidth = "1px"; + display.style.borderColor = "#2D2D2D"; + display.style.width = dragonblocks.settings.inventory.scale + "px"; + display.style.height = dragonblocks.settings.inventory.scale + "px"; + display.style.backgroundColor = "#343434"; + display.style.position = "absolute"; + display.style.left = x + "px"; + display.style.top = y + "px"; + + let countDisplay = display.appendChild(document.createElement("span")); + countDisplay.id = "dragonblocks.itemstack[" + this.id + "].count"; + countDisplay.stackid = this.id; + countDisplay.style.position = "absolute"; + countDisplay.style.right = "5px"; + countDisplay.style.bottom = "5px"; + countDisplay.style.color = "white"; + countDisplay.style.cursor = "default"; + + let self = this; + + display.addEventListener("mousedown", event => { + let out = dragonblocks.outStack; + + if (self.action) + return self.action(out, event.which); + + switch (event.which) { + case 1: + if (out.item) + self.add(out) || self.swap(out); + else + out.add(self); + break; + + case 3: + if (out.item) + self.addOne(out) || self.swap(out); + else + out.addHalf(self); + } + }); + + display.addEventListener("mouseover", event => { + self.focused = true; + self.redraw(); + }); + + display.addEventListener("mouseleave", event => { + self.focused = false; + self.redraw(); + }); + + this.addEventListener("update", _ => { + self.redraw(); + }); + + this.update(); + } + + redraw() + { + let display = this.getDisplay(); + + if (! display) + return; + + let countDisplay = document.getElementById("dragonblocks.itemstack[" + this.id + "].count"); + + if (this.item) { + let item = this.toItem(); + + display.title = item.desc; + display.style.background = dragonblocks.getTexture(item.texture); + display.style.backgroundSize = "cover"; + + if (this.count > 1) + countDisplay.innerHTML = this.count; + } else { + display.title = ""; + display.style.background = "none"; + + countDisplay.innerHTML = ""; + } + + display.style.backgroundColor = this.focused ? "#7E7E7E" : "#343434"; + + this.trigger("redraw"); + } +}; + +dragonblocks.ItemStack.Event = class extends Event +{ + constructor(type, stack) + { + super(type); + this.stack = stack; + } +}; + +dragonblocks.isValidItemstring = itemstring => { + let item = itemstring && itemstring.split(" ")[0]; + + if (item && ! dragonblocks.items[item]) + return false; + + return true; +}; diff --git a/engine/itemstack.js b/engine/itemstack.js deleted file mode 100644 index 72f50e8..0000000 --- a/engine/itemstack.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * itemstack.js - * - * Copyright 2020 Elias Fleckenstein - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ -dragonblocks.Itemstack = class{ - constructor(){ - this.count = 0; - this.item = null; - this.id = dragonblocks.getToken(); - dragonblocks.itemstacks[this.id] = this; - } - parse(itemstring){ - this.item = itemstring ? itemstring.split(" ")[0] : null; - this.count = itemstring ? parseInt(itemstring.split(" ")[1]) || 1 : 1; - if(this.item && ! this.toItem()) - return false; - this.update(); - return true; - } - getStacksize(){ - return (this.toItem() && this.toItem().stacksize) || dragonblocks.settings.item.defaultStacksize; - } - update(){ - if(this.count < 1) - this.item = null; - if(!this.item) - this.count = 0; - if(this.onupdate) - this.onupdate(); - } - addUpdateListener(func){ - let oldOnupdate = this.onupdate; - this.onupdate = _ => { - if(oldOnupdate) - oldOnupdate(); - func(); - } - } - toItem(){ - return dragonblocks.items[this.item]; - } - swap(itemstack){ - [this.count, itemstack.count] = [itemstack.count, this.count]; - [this.item, itemstack.item] = [itemstack.item, this.item]; - itemstack.update(); - this.update(); - } - clear(){ - this.item = null; - this.count = 0; - this.update(); - } - addItems(itemstack, count){ - this.update(); - itemstack.update(); - if(! itemstack.item) - return false; - if(! this.item) - this.item = itemstack.item; - if(this.item != itemstack.item) - return false; - if(this.count == this.getStacksize()) - return false; - itemstack.count -= count; - this.count += count; - let less = -itemstack.count; - if(less > 0){ - itemstack.count += less; - this.count -= less; - } - let more = this.count - this.getStacksize(); - if(more > 0){ - this.count -= more; - itemstack.count += more; - } - this.update(); - itemstack.update(); - return true; - } - add(itemstack){ - return this.addItems(itemstack, itemstack.count); - } - addOne(itemstack){ - return this.addItems(itemstack, 1); - } - addHalf(itemstack){ - return this.addItems(itemstack, Math.ceil(itemstack.count / 2)); - } - stringify(){ - if(! this.item) - return ""; - return this.item + " " + this.count; - } -}; -dragonblocks.itemstacks = {}; -dragonblocks.createItemstack = function(itemstring){ - let itemstack = new dragonblocks.Itemstack(); - if(itemstring) - itemstack.parse(itemstring); - return itemstack; -} -dragonblocks.isValidItemstring = function(itemstring){ - return new dragonblocks.Itemstack().parse(itemstring); -} diff --git a/engine/key_handler.js b/engine/key_handler.js index 750d37f..e856c2e 100644 --- a/engine/key_handler.js +++ b/engine/key_handler.js @@ -1,93 +1,128 @@ /* * key_handler.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.KeyHandler = class{ - constructor(){ + +dragonblocks.KeyHandler = class +{ + constructor() + { this.locked = {}; this.upHandlers = {}; this.downHandlers = {}; - addEventListener("keydown", event => {dragonblocks.keyHandler.handler(event)}); - addEventListener("keyup", event => {dragonblocks.keyHandler.handler(event)}); - addEventListener("wheel", event => {dragonblocks.keyHandler.handler(event)}); + + let self = this; + + addEventListener("keydown", event => { + self.handle(event); + }); + + addEventListener("keyup", event => { + self.handle(event); + }); + + addEventListener("wheel", event => { + self.handle(event); + }); } - lock(key){ + + lock(key) + { this.locked[key] = true; } - lockAll(){ + + lockAll() + { for(let key in this.upHandlers) this.lock(key); + for(let key in this.downHandlers) this.lock(key); } - unlock(key){ + + unlock(key) + { dragonblocks.keyHandler.locked[key] = false; } - unlockAll(){ - for(let key in this.locked) + + unlockAll() + { + for (let key in this.locked) this.unlock(key); } - down(key, func){ + + down(key, func) + { this.downHandlers[key] = func; this.lock(key); } - up(key, func){ + + up(key, func) + { this.upHandlers[key] = func; this.lock(key); } - handler(event){ - switch(event.type){ + + handle(event) + { + switch (event.type) { case "keydown": case "keypress": - if(this.locked[event.key]) + if (this.locked[event.key]) return; - if(this.downHandlers[event.key]){ + + if (this.downHandlers[event.key]) { event.preventDefault(); (this.downHandlers[event.key])(); } break; + case "keyup": - if(this.locked[event.key]) + if (this.locked[event.key]) return; - if(this.upHandlers[event.key]){ + + if (this.upHandlers[event.key]){ event.preventDefault(); (this.upHandlers[event.key])(); } break; + case "wheel": - if(this.locked["scroll"]) + if (this.locked["scroll"]) return; - if(event.deltaY > 0 && this.downHandlers["scroll"]){ - event.preventDefault(); - (this.downHandlers["scroll"])(); - } - else if(this.upHandlers["scroll"]){ - event.preventDefault(); - (this.upHandlers["scroll"])(); + + if (event.deltaY > 0 && this.downHandlers["scroll"]) { + event.preventDefault(); + (this.downHandlers["scroll"])(); + } else if (this.upHandlers["scroll"]) { + event.preventDefault(); + (this.upHandlers["scroll"])(); } break; } } -} +}; + dragonblocks.keyHandler = new dragonblocks.KeyHandler(); + dragonblocks.registerOnStarted(_ => { dragonblocks.keyHandler.unlockAll(); }); diff --git a/engine/mainmenu.js b/engine/mainmenu.js index 99c4e0f..73d55f1 100644 --- a/engine/mainmenu.js +++ b/engine/mainmenu.js @@ -1,268 +1,430 @@ /* * mainmenu.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.mainmenu = {}; -dragonblocks.registerOnStart(_ => { - document.getElementById("dragonblocks.mainmenu.content").innerHTML = "

Loading...

"; -}); -dragonblocks.registerOnStarted(_ => { - document.getElementById("dragonblocks.mainmenu").style.visibility = "hidden"; -}); -dragonblocks.registerOnQuit(_ => { - document.getElementById("dragonblocks.mainmenu").style.visibility = "visible"; - document.getElementById("dragonblocks.mainmenu.content").innerHTML = "

Saving...

"; -}); + { + document.title = dragonblocks.version.string; + let mainmenu = document.body.insertBefore(document.createElement("div"), document.body.firstChild); - mainmenu.id = "dragonblocks.mainmenu"; mainmenu.style.visibility = "hidden"; + let center = mainmenu.appendChild(document.createElement("center")); - let img = center.appendChild(document.createElement("img")); - img.src = "textures/logo-mainmenu.png"; + + let logo = center.appendChild(document.createElement("img")); + logo.src = "textures/logo-mainmenu.png"; + + let status = center.appendChild(document.createElement("h1")); + status.style.fontSize = "50px"; + status.style.display = "none"; + let content = center.appendChild(document.createElement("div")); content.id = "dragonblocks.mainmenu.content"; content.style.position = "relative"; content.style.top = "50px"; - let buttons = [ - { + + let buttons = []; + let onReload = []; + + let clearChildren = parent => { + while (elem = parent.firstChild) + elem.remove(); + }; + + // Load World Button + + { + let loadWorldGUI, worldlistDisplay, noWorldsNotice; + + if (dragonblocks.loggedin) { + onReload.push(_ => { + if (loadWorldGUI) { + clearChildren(worldlistDisplay); + } else { + loadWorldGUI = new dragonblocks.gui.Box(); + + let headline = loadWorldGUI.create("h1"); + headline.innerHTML = "Select World"; + headline.align = "center"; + + noWorldsNotice = loadWorldGUI.create("center").appendChild(document.createElement("b")); + + worldlistDisplay = loadWorldGUI.create("ul"); + } + + noWorldsNotice.innerHTML = dragonblocks.worlds.length == 0 ? "No Worlds" : ""; + + for (let worldname in dragonblocks.worlds) { + let world = dragonblocks.worlds[worldname]; + + if (world.owned) { + let worldDisplay = worldlistDisplay.appendChild(document.createElement("li")); + worldDisplay.style.fontSize = "20px"; + worldDisplay.textContent = world.name; + worldDisplay.style.postion = "relative"; + + let button = worldDisplay.appendChild(document.createElement("button")); + button.textContent = "Play"; + button.style.position = "absolute"; + button.style.right = "5px"; + button.style.fontSize = "12px"; + button.addEventListener("click", event => { + event.srcElement.blur(); + loadWorldGUI.close(); + + dragonblocks.worldIsLoaded = true; + dragonblocks.worldname = world.name; + dragonblocks.world = $.getJSON("worlds/" + worldname + "/world.json").responseJSON; + + dragonblocks.mods = dragonblocks.world.mods; + + dragonblocks.start(); + }); + } + } + }); + } + + buttons.push({ text: "Load Saved World", - action: _ => { dragonblocks.mainmenu.loadWorldGUI.open() }, + action: _ => { + loadWorldGUI.open() + }, disabled: ! dragonblocks.loggedin, - }, - { - text: "Create New World", - action: _ => { dragonblocks.mainmenu.createWorldGUI.open() } - }, - { - text: "Credits", - action: _ => { dragonblocks.mainmenu.creditsGUI.open() } - }, - { - text: "Quit", - action: _ => { history.back() } + }) + } + + // Create World Button + + { + let createWorldGUI = new dragonblocks.gui.Box(); + let createButton; + + let worldProperties = {}; + + let headline = createWorldGUI.create("h1"); + headline.innerHTML = "New World"; + headline.align = "center"; + + // Worldname + createWorldGUI.create("h2").innerHTML = " World Name"; + + let worldnameInput = createWorldGUI.create("input"); + worldnameInput.type = "text"; + worldnameInput.style.position = "relative"; + worldnameInput.style.left = "40px"; + + let worldnameAlert = createWorldGUI.create("b"); + worldnameAlert.style.position = "relative"; + worldnameAlert.style.left = "50px"; + + worldnameInput.addEventListener("input", _ => { + let worldname = worldnameInput.value; + + if(! dragonblocks.loggedin) { + worldnameAlert.textContent = "Warning: You are not logged in and cannot save worlds."; + worldnameAlert.style.color = "#FF7D00"; + createButton.disabled = false; + } else if (worldname == "") { + worldnameAlert.textContent = ""; + createButton.disabled = true; + } else if (! dragonblocks.checkWorldnameSpelling(worldname)) { + worldnameAlert.textContent = "The world name contains forbidden characters"; + worldnameAlert.style.color = "#FF001F"; + createButton.disabled = true; + } else if (dragonblocks.worlds[worldname]) { + if (dragonblocks.worlds[worldname].owned) { + worldnameAlert.textContent = "Warning: This will overwrite an existing world"; + worldnameAlert.style.color = "#FF7D00"; + createButton.disabled = false; + } else { + worldnameAlert.textContent = "This Worldname is taken"; + worldnameAlert.style.color = "#FF001F"; + createButton.disabled = true; + } + } else { + worldnameAlert.textContent = ""; + createButton.disabled = false; + } + + worldProperties.worldname = worldname; + }); + + // Mods + worldProperties.mods = {}; + + createWorldGUI.create("h2").innerHTML = " Mods"; + + let modlistDisplay; + + let updateModlist = _ => { + if (modlistDisplay) + clearChildren(modlistDisplay); + else + modlistDisplay = createWorldGUI.create("ul"); + + let oldSelectedMods = worldProperties.mods; + worldProperties.mods = {}; + + for (let modname in dragonblocks.mods) { + let modinfo = dragonblocks.mods[modname]; + + let modDisplay = modlistDisplay.appendChild(document.createElement("li")); + modDisplay.style.fontSize = "20px"; + modDisplay.innerHTML = mod; + modDisplay.style.postion = "relative"; + modDisplay.title = modinfo.description; + + let checkbox = modDisplay.appendChild(document.createElement("input")); + checkbox.type = "checkbox"; + checkbox.style.position = "absolute"; + checkbox.style.right = "5px"; + + checkbox.addEventListener("input", _ => { + worldProperties.mods[mod] = checkbox.checked; + }); + + worldProperties.mods[mod] = checkbox.checked = oldSelectedMods[mod]; + } + }; + + // Gamemode + worldProperties.gamemode = "survival"; + + createWorldGUI.create("h2").innerHTML = " Gamemode"; + + for (let gamemode of ["survival", "creative"]){ + let radiobox = createWorldGUI.create("input"); + radiobox.name = "dragonblocks.mainmenu.createWorldGUI.gamemode"; + radiobox.type = "radio"; + radiobox.checked = gamemode == worldProperties.gamemode; + radiobox.style.position = "relative"; + radiobox.style.left = "40px"; + + radiobox.addEventListener("input", _ => { + if (radiobox.checked) + worldProperties.gamemode = gamemode; + }); + + let label = createWorldGUI.create("label"); + label.innerHTML = dblib.humanFormat(gamemode); + label.style.position = "relative"; + label.style.left = "40px"; + } + + // Mapgen + createWorldGUI.create("h2").innerHTML = " Mapgen"; + + let selectMapgen = createWorldGUI.create("select"); + selectMapgen.style.position = "relative"; + selectMapgen.style.left = "40px"; + + selectMapgen.addEventListener("input", _ => { + worldProperties.mapgen = selectMapgen.value; + }); + + for (let mapgen in dragonblocks.mapgen.list) + selectMapgen.appendChild(document.createElement("option")).innerHTML = mapgen; + + worldProperties.mapgen = selectMapgen.value; + + createWorldGUI.create("br"); + createWorldGUI.create("br"); + + // Create Button + createButton = createWorldGUI.create("button"); + createButton.style.position = "absolute"; + createButton.style.left = "1%"; + createButton.style.bottom = "5px"; + createButton.style.width = "98%"; + createButton.style.fontSize = "20px"; + createButton.innerHTML = "Create World"; + + createButton.addEventListener("click", event => { + event.srcElement.blur(); + createWorldGUI.close(); + + dragonblocks.worldIsLoaded = false; + dragonblocks.worldname = worldProperties.worldname; + dragonblocks.world = dragonblocks.getEmptyWorld(); + + dragonblocks.entities["dragonblocks:player"].meta.creative = (worldProperties.gamemode == "creative"); + + dragonblocks.mapgen.selected = worldProperties.mapgen; + + dragonblocks.start(worldProperties.mods); + }); + + createWorldGUI.create("br"); + createWorldGUI.create("br"); + + onReload.push(_ => { + worldnameInput.value = ""; + worldnameAlert.textContent = ""; + createButton.disabled = dragonblocks.loggedin; + + updateModlist(); + }); + + buttons.push({ + text: "Create New World", + action: _ => { + createWorldGUI.open(); + }, + }); + } + + // Credits Button + + { + let creditsGUI = new dragonblocks.gui.Box(); + + let pages = $.getJSON("credits.json").responseJSON; + let page = 0; + + for (let dir of ["left", "right"]) { + let arrow = creditsGUI.create("div"); + arrow.style.position = "absolute"; + arrow.style.width = "80px"; + arrow.style.height = "80px"; + arrow.style.position = "absolute"; + arrow.style[dir] = "3px"; + arrow.style.background = dragonblocks.getTexture("arrow.png"); + arrow.style.backgroundSize = "cover"; + arrow.style.cursor = "pointer"; + + if (dir == "right") + arrow.style.transform = "rotate(180deg)"; + + arrow.addEventListener("click", _ => { + if (dir == "right") + page++; + else + page--; + + creditsGUI.open(); + }); + + dblib.centerVertical(arrow); } - ]; - for(let {text: text, action: action, disabled: disabled} of buttons){ + + let creditsContent = creditsGUI.create("center"); + + creditsGUI.addEventListener("open", _ => { + if (page < 0) + page = pages.length - 1; + else if (page >= pages.length) + page = 0; + + creditsContent.innerHTML = pages[page]; + dragonblocks.resolveTextures(creditsContent); + + // fix to center the dots of the li elements in chromium as well + + let lis = creditsContent.getElementsByTagName("li"); + + for (let li of lis) + li.style.width = "max-content"; + }); + + buttons.push({ + text: "Credits", + action: _ => { + creditsGUI.open(); + }, + }); + } + + // Quit Button + + { + buttons.push({ + text: "Quit", + action: _ => { + if (dragonblocks.isChromeApp) + window.close(); + else + history.back(); + }, + }); + } + + for (let {text, action, disabled} of buttons) { let button = content.appendChild(document.createElement("button")); button.style.fontSize = "40px"; button.style.width = "100%"; button.innerHTML = text; button.disabled = disabled; button.addEventListener("click", action); + content.appendChild(document.createElement("br")); content.appendChild(document.createElement("br")); } - for(let {text: text, side: side} of [{side: "left", text: dragonblocks.getVersion()}, {side: "right", text: dragonblocks.settings.version.copyright}]){ - let span = content.appendChild(document.createElement("span")); - span.style.position = "fixed"; - span.style.bottom = "5px"; - span.style[side] = "5px"; - span.innerHTML = text; + + for (let [side, text] of [["left", dragonblocks.version.string], ["right", dragonblocks.version.copyright]]) { + let notice = content.appendChild(document.createElement("span")); + notice.style.position = "fixed"; + notice.style.bottom = "5px"; + notice.style[side] = "5px"; + notice.innerHTML = text; } - document.title = dragonblocks.getVersion(); - img.addEventListener("load", _ => { - document.body.style.backgroundColor = "skyblue"; - document.getElementById("elidragon").style.display = "none"; - content.style.width = img.offsetWidth + "px"; - mainmenu.style.visibility = "visible"; + + dragonblocks.enterMainMenu = _ => { + dragonblocks.loadModList(); + dragonblocks.loadWorldList(); + + content.style.display = "inherit"; + status.style.display = "none"; + + for (let func of onReload) + func(); + }; + + dragonblocks.registerOnStart(_ => { + content.style.display = "none"; + status.style.display = "inherit"; + + status.innerHTML = "Loading..."; }); -} -if(dragonblocks.loggedin){ - dragonblocks.loadWorldlist(); - let gui = dragonblocks.mainmenu.loadWorldGUI = dragonblocks.gui.createBox(); - let headline = gui.create("h1"); - headline.innerHTML = "Select World"; - headline.align = "center"; - let worldlist = gui.create("ul"); - for(let world of dragonblocks.worlds){ - let worldDisplay = worldlist.appendChild(document.createElement("li")); - worldDisplay.style.fontSize = "20px"; - worldDisplay.textContent = world; - worldDisplay.style.postion = "relative"; - let button = worldDisplay.appendChild(document.createElement("button")); - button.textContent = "Play"; - button.style.position = "absolute"; - button.style.right = "5px"; - button.style.fontSize = "12px"; - button.addEventListener("click", event => { - event.srcElement.blur(); - gui.close(); - dragonblocks.loadWorld(world); - }); - } -} -{ - let gui = dragonblocks.mainmenu.createWorldGUI = dragonblocks.gui.createBox(); - let properties = {}; - let headline = gui.create("h1"); - headline.innerHTML = "New World"; - headline.align = "center"; - // Worldname - gui.create("h2").innerHTML = " World Name"; - let worldnameInput = gui.create("input"); - worldnameInput.type = "text"; - worldnameInput.style.position = "relative"; - worldnameInput.style.left = "40px"; - let worldnameAlert = gui.create("b"); - worldnameAlert.style.position = "relative"; - worldnameAlert.style.left = "50px"; - // Mods - properties.mods = {}; - gui.create("h2").innerHTML = " Mods"; - let modlist = gui.create("ul"); - for(let mod of dragonblocks.availableMods){ - let modDisplay = modlist.appendChild(document.createElement("li")); - modDisplay.style.fontSize = "20px"; - modDisplay.innerHTML = mod; - modDisplay.style.postion = "relative"; - $.get({ - url: "mods/" + mod + "/description.txt", - success: data => { - modDisplay.title = data; - } - }); - let checkbox = modDisplay.appendChild(document.createElement("input")); - checkbox.type = "checkbox"; - checkbox.style.position = "absolute"; - checkbox.style.right = "5px"; - checkbox.addEventListener("input", _ => { properties.mods[mod] = checkbox.checked }); - } - // Gamemode - properties.gamemode = "creative"; - gui.create("h2").innerHTML = " Gamemode"; - for(let gamemode of ["survival", "creative"]){ - let radiobox = gui.create("input"); - radiobox.name = "dragonblocks.mainmenu.createWorldGUI.gamemode"; - radiobox.type = "radio"; - radiobox.checked = (gamemode == properties.gamemode); - radiobox.style.position = "relative"; - radiobox.style.left = "40px"; - radiobox.addEventListener("input", _ => { - if(radiobox.checked) - properties.gamemode = gamemode; - }); - let label = gui.create("label"); - label.innerHTML = dblib.humanFormat(gamemode); - label.for = radiobox.id; - label.style.position = "relative"; - label.style.left = "40px"; - } - // Mapgen - gui.create("h2").innerHTML = " Mapgen"; - let selectMapgen = gui.create("select"); - selectMapgen.style.position = "relative"; - selectMapgen.style.left = "40px"; - selectMapgen.addEventListener("input", _ => { - properties.mapgen = selectMapgen.value; + + dragonblocks.registerOnStarted(_ => { + mainmenu.style.visibility = "hidden"; }); - for(let mapgen in dragonblocks.mapgen.list) - selectMapgen.appendChild(document.createElement("option")).innerHTML = mapgen; - properties.mapgen = selectMapgen.value; - gui.create("br"); - gui.create("br"); - // Button - let button = gui.create("button"); - button.style.position = "relative"; - button.style.left = "1%"; - button.style.width = "98%"; - button.innerHTML = "Create World"; - if(dragonblocks.loggedin) - button.disabled = true; - button.addEventListener("click", event => { - event.srcElement.blur(); - gui.close(); - dragonblocks.createWorld(properties); + + dragonblocks.registerOnQuit(_ => { + mainmenu.style.visibility = "visible"; + status.innerHTML = "Saving..."; }); - gui.create("br"); - gui.create("br"); - // World Name Check - worldnameInput.addEventListener("input", _ => { - if(! dragonblocks.loggedin){ - worldnameAlert.textContent = "You are not logged in and can not save worlds."; - worldnameAlert.style.color = "#FF7D00"; - button.disabled = false; - } - else if(worldnameInput.value == ""){ - worldnameAlert.textContent = ""; - button.disabled = true; - } - else if(! dragonblocks.checkWorldSpelling(worldnameInput.value)){ - worldnameAlert.textContent = "This Worldname contains forbidden characters"; - worldnameAlert.style.color = "#FF001F"; - button.disabled = true; - } - else if(dragonblocks.checkWorldExistance(worldnameInput.value)){ - if(dragonblocks.checkWorldOwnership(worldnameInput.value)){ - worldnameAlert.textContent = "This will overwrite an existing world"; - worldnameAlert.style.color = "#FF7D00"; - button.disabled = false; - } - else{ - worldnameAlert.textContent = "This Worldname is taken"; - worldnameAlert.style.color = "#FF001F"; - button.disabled = true; - } - } - else{ - worldnameAlert.textContent = ""; - button.disabled = false; - } - properties.worldname = worldnameInput.value; - }); -} -{ - let gui = dragonblocks.mainmenu.creditsGUI = dragonblocks.gui.createBox(); - let properties = { - content: $.getJSON("credits.json").responseJSON, - stage: 0, + + let initMainMenu = _ => { + document.body.style.backgroundColor = "skyblue"; + document.getElementById("elidragon").remove(); + content.style.width = logo.offsetWidth + "px"; + mainmenu.style.visibility = "visible"; + + dragonblocks.enterMainMenu(); }; - for(let dir of ["left", "right"]){ - let arrow = gui.create("div"); - arrow.style.position = "absolute"; - arrow.style.width = "80px"; - arrow.style.height = "80px"; - arrow.style.position = "absolute"; - arrow.style[dir] = "3px"; - arrow.style.background = dragonblocks.getTexture("arrow.png"); - arrow.style.backgroundSize = "cover"; - arrow.style.cursor = "pointer"; - if(dir == "right") - arrow.style.transform = "rotate(180deg)"; - arrow.addEventListener("click", _ => { - if(dir == "right") - properties.stage++; - else - properties.stage--; - gui.open(); - }); - dblib.centerVertical(arrow); - } - let content = gui.create("center"); - gui.onopen = _ => { - if(properties.stage < 0) - properties.stage = properties.content.length - 1; - if(!properties.content[properties.stage]) - properties.stage = 0; - content.innerHTML = properties.content[properties.stage]; - dragonblocks.resolveTextures(content); - } + + if (logo.complete) + initMainMenu(); + else + logo.addEventListener("load", initMainMenu); } diff --git a/engine/map.js b/engine/map.js index 3d0ced6..4ff558d 100644 --- a/engine/map.js +++ b/engine/map.js @@ -1,133 +1,182 @@ /* * map.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Map = class{ - constructor(){ - dragonblocks.map = this; + +dragonblocks.Map = class +{ + constructor() + { dblib.copy(this, dragonblocks.world.map); - this.graphicsInit(); - for(let x = 0; x < this.width; x++) - for(let y = 0; y < this.height; y++) - this.setNode(x, y, new dragonblocks.MapNode().createFromMapNode(this.content[x][y])); + this.data = this.data || this.content; + delete this.content; } - setNode(x, y, node){ - if(this.contains(x, y)){ - if(this.content[x][y] instanceof dragonblocks.MapNode && this.content[x][y].toNode().onremove) - this.content[x][y].toNode().onremove(x, y); - for(let func of dragonblocks.onRemoveNodeFunctions) + + load() + { + for (let x = 0; x < this.width; x++) + for (let y = 0; y < this.height; y++) + this.setNode(x, y, new dragonblocks.MapNode().createFromMapNode(this.data[x][y])); + + this.initGraphics(); + } + + setNode(x, y, node) + { + if (this.withinBounds(x, y)) { + let oldNode = this.data[x][y]; + let oldNodeDef = oldNode instanceof dragonblocks.MapNode && oldNode.toNode(); + oldNodeDef && oldNodeDef.onremove && oldNodeDef.onremove(x, y); + + for (let func of dragonblocks.onRemoveNodeCallbacks) func(x, y); - this.content[x][y] = node; - if(node.toNode().onset) - node.toNode().onset(x, y); - for(let func of dragonblocks.onSetNodeFunctions) + + this.data[x][y] = node; + + let nodeDef = node.toNode(); + nodeDef.onset && nodeDef.onset(x, y); + + for (let func of dragonblocks.onSetNodeCallbacks) func(x, y); - this.graphicsUpdateNode(x, y); + + this.updateNodeGraphics(x, y); } } - activate(x, y){ - for(let ix = x - 1; ix <= x + 1; ix++){ - for(let iy = y - 1; iy <= y + 1; iy++){ - if(! this.getNode(ix, iy)) + + activate(x, y) + { + for (let ix = x - 1; ix <= x + 1; ix++) { + for (let iy = y - 1; iy <= y + 1; iy++) { + let node = this.getNode(ix, iy); + + if (! node) continue; - if(this.getNode(ix, iy).toNode().onactivate) - this.getNode(ix, iy).toNode().onactivate(ix, iy); - for(let func of dragonblocks.onActivateNodeFunctions) + + let nodeDef = node.toNode(); + nodeDef.onactivate && nodeDef.onactivate(ix, iy); + + for(let func of dragonblocks.onActivateNodeCallbacks) func(ix, iy); } } } - getNode(x, y){ - if(this.contains(x, y)) - return this.content[x][y]; + + getNode(x, y) + { + if (this.withinBounds(x, y)) + return this.data[x][y]; } - contains(x, y){ + + withinBounds(x, y) + { return x < this.width && y < this.height && x >= 0 && y >= 0; } - getNodeGraphics(x, y){ + + getNodeDisplay(x, y) + { return document.getElementById("dragonblocks.map.node[" + (x - this.displayLeft) + "][" + (y - this.displayTop) + "]"); } - getCoordinate(x, y){ + + getScreenCoordinates(x, y) + { return [Math.floor(x / dragonblocks.settings.map.scale) + this.displayLeft, Math.floor(y / dragonblocks.settings.map.scale) + this.displayTop]; } - graphicsUpdateNode(x, y){ - let nodeDisplay = this.getNodeGraphics(x, y); - let node = this.getNode(x, y).toNode(); - if(!nodeDisplay || !node) + + updateNodeGraphics(x, y) + { + let nodeDisplay = this.getNodeDisplay(x, y); + + if (! nodeDisplay) + return; + + let nodeDef = this.getNode(x, y).toNode(); + + if (! nodeDef) return; - nodeDisplay.style.background = dragonblocks.getTexture(node.texture); + + nodeDisplay.style.background = dragonblocks.getTexture(nodeDef.texture); nodeDisplay.style.backgroundSize = "cover"; - nodeDisplay.style.zIndex = node.zIndex || "1"; + nodeDisplay.style.zIndex = nodeDef.zIndex || "1"; } - graphicsUpdate(){ - if(this.displayLeft < 0) + + updateGraphics() + { + if (this.displayLeft < 0) this.displayLeft = 0; - else if(this.displayLeft + this.displayWidth > this.width) + else if (this.displayLeft + this.displayWidth > this.width) this.displayLeft = this.width - this.displayWidth; - if(this.displayTop < 0) + + if (this.displayTop < 0) this.displayTop = 0; - else if(this.displayTop + this.displayHeight > this.height) + else if (this.displayTop + this.displayHeight > this.height) this.displayTop = this.height - this.displayHeight; - for(let x = 0; x < this.displayWidth; x++){ - for(let y = 0; y < this.displayHeight; y++){ - this.graphicsUpdateNode(x + this.displayLeft, y + this.displayTop); + + for (let x = 0; x < this.displayWidth; x++) { + for(let y = 0; y < this.displayHeight; y++) { + this.updateNodeGraphics(x + this.displayLeft, y + this.displayTop); } } } - graphicsInit(){ + + initGraphics() + { this.displayWidth = Math.min(Math.ceil(innerWidth / dragonblocks.settings.map.scale), this.width); this.displayHeight = Math.min(Math.ceil(innerHeight / dragonblocks.settings.map.scale), this.height); - var map = document.createElement("div"); - map.id = "dragonblocks.map"; - map.style.width = this.displayWidth * dragonblocks.settings.map.scale + "px"; - map.style.height = this.displayHeight * dragonblocks.settings.map.scale + "px"; - map.style.position = "fixed"; - map.style.top = "0px"; - map.style.left = "0px"; - map.style.backgroundColor = "skyblue"; - map.style.visibility = "hidden"; - for(let x = 0; x < this.displayWidth; x++){ - for(let y = 0; y < this.displayHeight; y++){ - var node = document.createElement("div"); - node.id = "dragonblocks.map.node[" + x + "][" + y + "]"; - node.style.position = "absolute"; - node.style.top = y * dragonblocks.settings.map.scale + "px"; - node.style.left = x * dragonblocks.settings.map.scale + "px"; - node.style.width = dragonblocks.settings.map.scale + "px"; - node.style.height = dragonblocks.settings.map.scale + "px"; - map.appendChild(node); + + let display = document.body.insertBefore(document.createElement("div"), document.body.firstChild); + display.id = "dragonblocks.map"; + display.style.width = this.displayWidth * dragonblocks.settings.map.scale + "px"; + display.style.height = this.displayHeight * dragonblocks.settings.map.scale + "px"; + display.style.position = "fixed"; + display.style.top = "0px"; + display.style.left = "0px"; + display.style.backgroundColor = "skyblue"; + display.style.visibility = "hidden"; + + for (let x = 0; x < this.displayWidth; x++){ + for (let y = 0; y < this.displayHeight; y++){ + let nodeDisplay = display.appendChild(document.createElement("div")); + nodeDisplay.id = "dragonblocks.map.node[" + x + "][" + y + "]"; + nodeDisplay.style.position = "absolute"; + nodeDisplay.style.top = y * dragonblocks.settings.map.scale + "px"; + nodeDisplay.style.left = x * dragonblocks.settings.map.scale + "px"; + nodeDisplay.style.width = dragonblocks.settings.map.scale + "px"; + nodeDisplay.style.height = dragonblocks.settings.map.scale + "px"; } } - document.body.insertBefore(map, document.body.firstChild); } -} -dragonblocks.setNode = function(x, y, node){ +}; + +dragonblocks.setNode = (x, y, node) => { dragonblocks.map.setNode(x, y, new dragonblocks.MapNode(node)); -} -dragonblocks.getNode = function(x, y){ +}; + +dragonblocks.getNode = (x, y) => { return dragonblocks.map.getNode(x, y); -} +}; + dragonblocks.registerOnStarted(_ => { document.getElementById("dragonblocks.map").style.visibility = "visible"; }); + dragonblocks.registerOnQuit(_ => { document.getElementById("dragonblocks.map").style.visibility = "hidden"; }); diff --git a/engine/map_interaction.js b/engine/map_interaction.js index 3f2023a..3201da1 100644 --- a/engine/map_interaction.js +++ b/engine/map_interaction.js @@ -1,29 +1,30 @@ /* * map_interaction.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.MapIntercation = { - initMapInteraction(){ - let self = this; - let crack = document.createElement("div"); + +dragonblocks.MapInteraction = { + initMapInteraction() + { + let crack = document.getElementById("dragonblocks.map").appendChild(document.createElement("div")); crack.id = "dragonblocks.crack[" + this.id + "]"; crack.style.position = "absolute"; crack.style.visibility = "hidden"; @@ -32,129 +33,190 @@ dragonblocks.MapIntercation = { crack.style.width = dragonblocks.settings.map.scale + "px"; crack.style.boxShadow = "0 0 0 1px black inset"; crack.style.zIndex = 2; + + let self = this; + crack.addEventListener("mouseleave", event => { self.digStop(); - let [x, y] = dragonblocks.map.getCoordinate(event.srcElement.offsetLeft, event.srcElement.offsetTop); - dragonblocks.map.getNodeGraphics(x, y).style.boxShadow = "none"; + let [x, y] = dragonblocks.map.getScreenCoordinates(event.srcElement.offsetLeft, event.srcElement.offsetTop); + dragonblocks.map.getNodeDisplay(x, y).style.boxShadow = "none"; }); + crack.addEventListener("mouseover", event => { - let [x, y] = dragonblocks.map.getCoordinate(event.srcElement.offsetLeft + document.getElementById("dragonblocks.map").offsetLeft, event.srcElement.offsetTop + document.getElementById("dragonblocks.map").offsetTop); - dragonblocks.map.getNodeGraphics(x, y).style.boxShadow = "0 0 0 1px black inset"; + let [x, y] = dragonblocks.map.getScreenCoordinates(event.srcElement.offsetLeft + document.getElementById("dragonblocks.map").offsetLeft, event.srcElement.offsetTop + document.getElementById("dragonblocks.map").offsetTop); + dragonblocks.map.getNodeDisplay(x, y).style.boxShadow = "0 0 0 1px black inset"; }); - document.getElementById("dragonblocks.map").appendChild(crack); }, - dig(x, y){ - let mapNode = dragonblocks.getNode(x, y); - if(! mapNode) + + dig(x, y) + { + let node = dragonblocks.getNode(x, y); + + if (! node) return false; - let node = mapNode.toNode(); - if(node.ondig && node.ondig(x, y) == false) + + let nodeDef = node.toNode(); + if (nodeDef.ondig && nodeDef.ondig(x, y) == false) return false; - for(let func of dragonblocks.onDigNodeFunctions) - if(func(x, y) == false) + + for (let func of dragonblocks.onDigNodeCallbacks) + if (func(x, y) == false) return false; - node.playSound("dug"); + + nodeDef.playSound("dug"); + dragonblocks.setNode(x, y, "air"); dragonblocks.map.activate(x, y); + return true; }, - digStart(x, y){ - let mapNode = dragonblocks.getNode(x, y); - let node = mapNode.toNode(); - mapNode.meta.hardness = node.hardness; - mapNode.meta.causedDamage = 0; - if(! this.canReach(x, y)) + + digStart(x, y) + { + let node = dragonblocks.getNode(x, y); + let nodeDef = node.toNode(); + + node.meta.hardness = nodeDef.hardness; + node.meta.causedDamage = 0; + + if (! this.canReach(x, y)) return; + let crack = document.getElementById("dragonblocks.crack[" + this.id + "]") crack.style.visibility = "visible"; crack.style.left = (x - dragonblocks.map.displayLeft) * dragonblocks.settings.map.scale + "px"; crack.style.top = (y - dragonblocks.map.displayTop) * dragonblocks.settings.map.scale + "px"; + dragonblocks.log("Punched Node at (" + x + ", " + y + ")"); - node.onpunch && node.onpunch(x,y); - for(let func of dragonblocks.onPunchNodeFunctions) + + nodeDef.onpunch && nodeDef.onpunch(x,y); + + for (let func of dragonblocks.onPunchNodeCallbacks) func(x, y); + dragonblocks.map.activate(x, y); + this.digTick(x, y); }, - digTick(x, y){ + + digTick(x, y) + { let self = this; - let mapNode = dragonblocks.getNode(x, y); - if(! mapNode) + + let node = dragonblocks.getNode(x, y); + if (! node) return; - let node = mapNode.toNode(); - let damage = this.tool.calculateDamage(node); - if(damage == -1) - damage = this.tmp.defaultTool.calculateDamage(node); - mapNode.meta.hardness -= damage; - mapNode.meta.causedDamage += damage; - if(mapNode.meta.hardness <= 0 || isNaN(mapNode.meta.hardness)) + + let nodeDef = node.toNode(); + + let damage = this.tool.calculateDamage(nodeDef); + if (damage == -1) + damage = this.tmp.defaultTool.calculateDamage(nodeDef); + + node.meta.hardness -= damage; + node.meta.causedDamage += damage; + + if (isNaN(node.meta.hardness) || node.meta.hardness <= 0) { this.digEnd(x, y); - else{ - node.playSound("dig"); + } else { + nodeDef.playSound("dig"); + let crack = document.getElementById("dragonblocks.crack[" + this.id + "]"); - crack.style.background = dragonblocks.getTexture("crack" + Math.floor(mapNode.meta.causedDamage / mapNode.toNode().hardness * 5) + ".png"); + crack.style.background = dragonblocks.getTexture("crack" + Math.floor(node.meta.causedDamage / nodeDef.hardness * 5) + ".png"); crack.style.backgroundSize = "cover"; - this.tmp.digTimeout = setTimeout(_ => { self.digTick(x, y) }, this.tool.interval); + + this.tmp.digTimeout = setTimeout(_ => { + self.digTick(x, y); + }, this.tool.interval); } }, - digEnd(x, y){ - let mapNode = dragonblocks.getNode(x, y); - if(! mapNode) + + digEnd(x, y) + { + let node = dragonblocks.getNode(x, y); + + if (! node) return; - let node = mapNode.toNode(); + + let nodeDef = node.toNode(); + if (this.dig(x, y)) - dragonblocks.handleNodeDrop(this.tmp.mainInventory, node, x, y); + dragonblocks.handleNodeDrop(this.tmp.mainInventory, nodeDef, x, y); + document.getElementById("dragonblocks.crack[" + this.id + "]").style.visibility = "hidden"; }, - digStop(){ + + digStop() + { clearTimeout(this.tmp.digTimeout); document.getElementById("dragonblocks.crack[" + this.id + "]").style.visibility = "hidden"; }, - place(x, y, node){ - if(! dragonblocks.getNode(x, y) || dragonblocks.getNode(x, y).stable) + + place(x, y, node) + { + let oldNode = dragonblocks.getNode(x, y); + + if (! oldNode || oldNode.stable) return false; - if(node.onplace && node.onplace(x, y) == false) + + if (node.onplace && node.onplace(x, y) == false) return false; - for(let func of dragonblocks.onPlaceNodeFunctions) - if(func(node, x, y) == false) + + for (let func of dragonblocks.onPlaceNodeCallbacks) + if (func(node, x, y) == false) return false; + dragonblocks.setNode(x, y, node); dragonblocks.map.activate(x, y); + node.playSound("place"); + return true; }, - build(x, y){ - if(this.canReach(x, y)){ - let old = dragonblocks.getNode(x, y).toNode(); - old.onclick && old.onclick(x, y); - for(let func of dragonblocks.onClickNodeFunctions) + + build(x, y) + { + if(this.canReach(x, y)) { + let oldNodeDef = dragonblocks.getNode(x, y).toNode(); + oldNodeDef.onclick && oldNodeDef.onclick(x, y); + + for (let func of dragonblocks.onClickNodeCallbacks) func(x, y); - if(this.touch(x, y)) + + if (this.touch(x, y)) return; - var buildstack = dragonblocks.createItemstack(); - if(! buildstack.addOne(this.getWieldedItem())) + + let wielded = this.getWieldedItem(); + let itemstack = new dragonblocks.ItemStack(); + + if(! itemstack.addOne(wielded)) return; - if(buildstack.toItem() instanceof dragonblocks.Node){ - if(! this.place(x, y, buildstack.toItem()) || this.meta.creative) - this.getWieldedItem().add(buildstack); - } - else{ - if(! buildstack.toItem().onuse || ! buildstack.toItem().onuse(x, y)) - this.getWieldedItem().add(buildstack); - else{ - for(let func of dragonblocks.onUseItemFunctions) - func(buildstack.toItem(), x, y); - if(this.meta.creative) - this.getWieldedItem().add(buildstack); + + let itemDef = itemstack.toItem(); + + if (itemDef instanceof dragonblocks.Node) { + if (! this.place(x, y, itemDef) || this.meta.creative) + wielded.add(itemstack); + } else { + if (! itemDef.onuse || ! itemDef.onuse(x, y)) { + wielded.add(itemstack); + } else { + for (let func of dragonblocks.onUseItemCallbacks) + func(itemDef, x, y); + + if (this.meta.creative) + wielded.add(itemstack); } } } }, - canReach(x, y){ - return (Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2)) <= this.tool.range) || this.meta.creative; - }, -} -dragonblocks.handleNodeDrop = function(inventory, node, x, y) { - dragonblocks.dropItem(inventory.add((node.drops instanceof Function) ? node.drops() : node.drops), x + 0.2, y + 0.2); -} + canReach(x, y) + { + return this.meta.creative || Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2)) <= this.tool.range; + } +}; + +dragonblocks.handleNodeDrop = (inventory, nodeDef, x, y) => { + dragonblocks.dropItem(inventory.add((nodeDef.drops instanceof Function) ? nodeDef.drops() : nodeDef.drops), x + 0.2, y + 0.2); +}; diff --git a/engine/map_node.js b/engine/map_node.js index fb17cdc..5bde9c1 100644 --- a/engine/map_node.js +++ b/engine/map_node.js @@ -1,51 +1,63 @@ /* * map_node.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.MapNode = class{ - constructor(node){ - if(! node) + +dragonblocks.MapNode = class +{ + constructor(node) + { + if (! node) return; - if(dragonblocks.nodes[node]) + + if (dragonblocks.nodes[node]) this.createFromNode(dragonblocks.nodes[node]); - else if(node instanceof dragonblocks.Node) - this.createFromNode(node) - else if(node instanceof dragonblocks.MapNode) + else if (node instanceof dragonblocks.Node) + this.createFromNode(node); + else if (node instanceof dragonblocks.MapNode) this.createFromMapNode(node); else - dragonblocks.error("Can not create Map Node: Invalid argument."); + dragonblocks.error("Cannot create Map Node: Invalid argument."); + this.tmp = {}; } - createFromNode(node){ + + createFromNode(node) + { this.meta = {}; this.name = node.name; this.stable = node.stable; this.mobstable = node.mobstable; + return this; } - createFromMapNode(mapnode){ + + createFromMapNode(mapnode) + { dblib.copy(this, mapnode); return this; } - toNode(){ + + toNode() + { return dragonblocks.nodes[this.name]; } -} +}; diff --git a/engine/mapgen.js b/engine/mapgen.js index 11dc070..8aeba2d 100644 --- a/engine/mapgen.js +++ b/engine/mapgen.js @@ -1,79 +1,109 @@ /* * mapgen.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ + dragonblocks.mapgen = {}; -dragonblocks.mapgen.addStructure = function(name, msg, pos){ + +dragonblocks.mapgen.addStructure = (name, msg, pos) => { let strs = dragonblocks.world.structures; strs[name] = strs[name] || []; strs[name].push({msg: msg, pos: pos}); -} +}; + dragonblocks.mapgen.biomes = []; -dragonblocks.registerBiome = function(obj){ +dragonblocks.registerBiome = obj => { dragonblocks.mapgen.biomes.push(obj); -} +}; + dragonblocks.mapgen.materials = []; -dragonblocks.registerMaterial = function(obj){ +dragonblocks.registerMaterial = obj => { dragonblocks.mapgen.materials.push(obj); -} +}; + dragonblocks.mapgen.ores = []; -dragonblocks.registerOre = function(obj){ +dragonblocks.registerOre = obj => { dragonblocks.mapgen.ores.push(obj); -} +}; + dragonblocks.mapgen.selected = "empty"; dragonblocks.mapgen.list = {}; -dragonblocks.generateMap = function(){ + +dragonblocks.generateMap = _ => { dragonblocks.mapgen.list[dragonblocks.mapgen.selected](); -} -dragonblocks.mapgen.list["v3"] = function(){ +}; + +dragonblocks.mapgen.list["v3"] = _ => { + // Localize variables + let int = parseInt; + let snode = dragonblocks.setNode; let gnode = dragonblocks.getNode; - let pm = dragonblocks.getPixelManipulator; + + let pm = dragonblocks.PixelManipulator; + let rand = dblib.random; + let height = dragonblocks.map.height; let width = dragonblocks.map.width; + + // Biomes + let biomeList = dragonblocks.mapgen.biomes; let biomes = []; let biomeBorders = []; + { - for(let d = 0; d < width;){ + for (let d = 0; d < width;) { let max = 0; - for(let biome of biomeList) + + for (let biome of biomeList) max += biome.probability; + let r = rand(0, max); - for(let i in biomeList){ + + for (let i in biomeList) { r -= biomeList[i].probability; - if(r <= 0){ + + if (r <= 0) { biomeBorders.push(d); + let border = Math.min(d + rand(biomeList[i].size[0], biomeList[i].size[1]), width); + dragonblocks.mapgen.addStructure(biomeList[i].name, "(" + d + " - " + border + ", *)", {x: int((d + border)/2), y: 5}); + for(; d < border; d++) biomes.push(i); + break; } } } } + + // Terrain shape + let ground = []; + { let levels = [ { @@ -140,212 +170,289 @@ dragonblocks.mapgen.list["v3"] = function(){ rise: [0], size: 10, minsize: 0, - low: 50, + low: 50, high: 30, } ]; + let maxprob = 0; - for(let lvl of levels){ + + for (let lvl of levels) { levels[lvl.name] = lvl; maxprob += lvl.probability; } + let level = levels.flat; let leftsize = level.minsize; - let lastground = 40 * height / 100; - let addedstruct = false; - for(let x = 0; x < width; x++){ - if(level.high && level.high * height / 100 > lastground || level.low && level.low * height / 100 < lastground || leftsize <= 0 && rand(0, level.size) == 0){ - if(! addedstruct){ + let groundLast = 40 * height / 100; + let structAdded = false; + + for (let x = 0; x < width; x++){ + if (level.high && level.high * height / 100 > groundLast || level.low && level.low * height / 100 < groundLast || leftsize <= 0 && rand(0, level.size) == 0) { + if (! structAdded) { let start = x - level.minsize + leftsize; let end = x; + let gx = int((start + end) / 2); let gy = ground[gx] - 3; + dragonblocks.mapgen.addStructure(level.name, "(" + start + " - " + end + ", *)", {x: gx, y: gy}); - addedstruct = true; + + structAdded = true; } - if(level.next) + + if (level.next) { level = levels[level.next]; - else{ + } else { let r = rand(0, maxprob); - for(let lvl of levels){ + + for (let lvl of levels) { r -= lvl.probability; - if(r <= 0){ + + if (r <= 0) { level = lvl; break; } } } - + leftsize = level.minsize; x--; continue; } - addedstruct = false; + + structAdded = false; leftsize--; - lastground += level.rise[rand(0, level.rise.length - 1)]; - ground[x] = lastground; + groundLast += level.rise[rand(0, level.rise.length - 1)]; + + ground[x] = groundLast; } } + + // Ores + { - function setore(x, y, ore){ - if(! ground[x] || y < ground[x] || (y / height * 100 - 50) < ore.deep) + let setOre = (x, y, ore) => { + if (! ground[x] || y < ground[x] || (y / height * 100 - 50) < ore.deep) return false; + snode(x, y, ore.name); + return true; - } - for(let x = 0; x < width; x++){ + }; + + for (let x = 0; x < width; x++) { let y, g; + y = g = ground[x]; + let biome = biomeList[biomes[x]]; - for(; y < g + 1; y++) + + for (; y < g + 1; y++) snode(x, y, biome.surface); - for(; y < g + 5; y++) + + for (; y < g + 5; y++) snode(x, y, biome.ground); - for(; y < height; y++){ + + for (; y < height; y++) { snode(x, y, biome.underground); - for(let ore of dragonblocks.mapgen.ores){ - if(dblib.random(0, ore.factor) == 0){ - if(setore(x, y, ore)) + + for (let ore of dragonblocks.mapgen.ores) { + if (dblib.random(0, ore.factor) == 0) { + if (setOre(x, y, ore)) dragonblocks.mapgen.addStructure(ore.name, "(" + x + ", " + y + ")", {x: x, y: y}); - for(let i = 0; i < ore.clustersize; i++) - setore(x + dblib.random(-2, 2), y + dblib.random(-2, 2), ore); - } + + for (let i = 0; i < ore.clustersize; i++) + setOre(x + dblib.random(-2, 2), y + dblib.random(-2, 2), ore); + } } } } } + + // Water + let water = []; + { let top, bottom, start; + top = int(height / 2); - for(let x = 0; x < width; x++){ + + for (let x = 0; x < width; x++) { let biome = biomeList[biomes[x]]; - if(ground[x] > top){ - start = start || x; + if (ground[x] > top) { + start = start || x; water[x] = true; + snode(x, top, biome.watertop); + let y = top + 1; + for(; y < ground[x]; y++) snode(x, y, biome.water); + for(; y < ground[x] + 5; y++) snode(x, y, biome.floor); - } - else if(start){ + } else if (start) { let end = x - 1; dragonblocks.mapgen.addStructure("water", "(" + start + " - " + end + ", " + top + ")", {x: int((start + end) / 2), y: top}); start = 0; } } - if(start){ + + if (start) { let end = width; dragonblocks.mapgen.addStructure("water", "(" + start + " - " + end + ", " + top + ")", {x: int((start + end) / 2), y: top}); } } + + // Trees + { - let nexttree = 0; - for(let x = 0; x < width; x++){ - if(x >= nexttree && ! water[x]){ + let nextTree = 0; + + for (let x = 0; x < width; x++) { + if (x >= nextTree && ! water[x]) { let g = ground[x]; let biome = biomeList[biomes[x]]; - for(let tree of biome.trees){ - if(Math.random() <= tree.chance){ + + for (let tree of biome.trees) { + if (Math.random() <= tree.chance) { snode(x, g - 1, tree.sapling); gnode(x, g - 1) && dragonblocks.finishTimer("growTimer", gnode(x, g - 1).meta); - nexttree = x + tree.width; + nextTree = x + tree.width; break; } } } } } + + // Ressource Blobs (e.g. Gravel, Dirt) + { - function structure(x, y, mat){ - let core = pm([["§" + mat, mat], [mat, mat]]); - core.addFunction((node, x, y) => {return y > ground[x]}); - core.apply(x, y); + let belowGround = (node, x, y) => { + return y > ground[x] + }; + + function structure(x, y, mat) { + new pm([["§" + mat, mat], [mat, mat]]) + .addFunction(belowGround) + .apply(x, y); + let sides = [ - pm([[mat, mat], ["§", ""]]), - pm([["§", "", mat], ["", "", mat]]), - pm([["§", ""], ["", ""], [mat, mat]]), - pm([[mat, "§"], [mat, ""]]), + new pm([[mat, mat], ["§", ""]]), + new pm([["§", "", mat], ["", "", mat]]), + new pm([["§", ""], ["", ""], [mat, mat]]), + new pm([[mat, "§"], [mat, ""]]), ]; - for(let side of sides) - side.addFunction((node, x, y) => {return y > ground[x]}); + + for (let side of sides) + side.addFunction(belowGround); + let moresides = [ - pm([[mat, mat], ["", ""], ["§", ""]]), - pm([["§", "", "", mat], ["", "", "", mat]]), - pm([["§", ""], ["", ""], ["", ""], [mat, mat]]), - pm([[mat, "", "§"], [mat, "", ""]]), + new pm([[mat, mat], ["", ""], ["§", ""]]), + new pm([["§", "", "", mat], ["", "", "", mat]]), + new pm([["§", ""], ["", ""], ["", ""], [mat, mat]]), + new pm([[mat, "", "§"], [mat, "", ""]]), ]; - for(let moreside of moresides) - moreside.addFunction((node, x, y) => {return y > ground[x]}); + + for (let moreside of moresides) + moreside.addFunction(belowGround); + let corners = [ - pm([[mat, ""], ["", "§"]]), - pm([["", "", mat], ["§", "", ""]]), - pm([["§", "", ""], ["", "", ""], ["", "", mat]]), - pm([["§", "", ""], ["", "", ""], ["", "", mat]]), + new pm([[mat, ""], ["", "§"]]), + new pm([["", "", mat], ["§", "", ""]]), + new pm([["§", "", ""], ["", "", ""], ["", "", mat]]), + new pm([["§", "", ""], ["", "", ""], ["", "", mat]]), ]; - for(let corner of corners) - corner.addFunction((node, x, y) => {return y > ground[x]}); - for(let i in sides){ - if(Math.random() * 1.2 < 1){ + + for (let corner of corners) + corner.addFunction(belowGround); + + for (let i in sides) { + if (Math.random() * 1.2 < 1){ sides[i].apply(x, y); - for(let j = i; j <= int(i) + 1; j++){ + + for (let j = i; j <= int(i) + 1; j++){ let corner = corners[j] || corners[0]; - if(Math.random() * 1.5 < 1) + + if (Math.random() * 1.5 < 1) corner.apply(x, y); } - if(Math.random() * 2 < 1) + + if (Math.random() * 2 < 1) moresides[i].apply(x, y); } } } - for(let material of dragonblocks.mapgen.materials) - for(let i = 0; i < width / material.factor; i++) + + for (let material of dragonblocks.mapgen.materials) + for (let i = 0; i < width / material.factor; i++) structure(rand(0, width), rand(0, height), material.name); } + + // Caves + { - function newcave(x, y){ - let r = dblib.random(0, 10) + 1; - if(y < ground[x] + 10) - return false; - cave(x, y, r); - dragonblocks.mapgen.addStructure("cave", "(" + x + ", " + y + ")", {x: x, y: y}); - } - function cave(x, y, r){ + let cave = (x, y, r) => { r *= 2; - let cavepm = pm([ - ["", "air", "air", "air", ""], - ["air", "air", "air", "air", "air"], + + let cavepm = new pm([ + ["", "air", "air", "air", ""], + ["air", "air", "air", "air", "air"], ["air", "air", "§air", "air", "air"], - ["air", "air", "air", "air", "air"], - ["", "air", "air", "air", ""], + ["air", "air", "air", "air", "air"], + ["", "air", "air", "air", ""], ]); - cavepm.addFunction((node, x, y) =>{ - if(y < ground[x]) + + cavepm.addFunction((node, x, y) => { + if (y < ground[x]) return false; - if(dblib.random(0, r) == 0) + + if (dblib.random(0, r) == 0) cave(x, y, r); }); + cavepm.apply(x, y); - } + }; + + let newCave = (x, y) => { + let r = dblib.random(0, 10) + 1; + + if (y < ground[x] + 10) + return false; + + cave(x, y, r); + + dragonblocks.mapgen.addStructure("cave", "(" + x + ", " + y + ")", {x: x, y: y}); + }; + let r = dblib.random(width / 5, width / 15); - for(let i = 0; i < r; i++) - newcave(rand(0, width), rand(0, height)); + + for (let i = 0; i < r; i++) + newCave(rand(0, width), rand(0, height)); } -} -dragonblocks.mapgen.list["flat"] = function(){ - for(let x = 0; x < dragonblocks.map.width; x++){ +}; + +dragonblocks.mapgen.list["flat"] = _ => { + for (let x = 0; x < dragonblocks.map.width; x++) { let y = 0; + for(; y < dragonblocks.map.height - 5; y++) dragonblocks.setNode(x, y, "air"); + for(; y < dragonblocks.map.height - 4; y++) dragonblocks.setNode(x, y, "dirt:grass"); + for(; y < dragonblocks.map.height - 3; y++) dragonblocks.setNode(x, y, "dirt:dirt"); + for(; y < dragonblocks.map.height; y++) dragonblocks.setNode(x, y, "core:stone"); } -} -dragonblocks.mapgen.list["empty"] = function(){} +}; + +dragonblocks.mapgen.list["empty"] = _ => {}; diff --git a/engine/menu.js b/engine/menu.js index a6c3120..ffa8184 100644 --- a/engine/menu.js +++ b/engine/menu.js @@ -1,75 +1,94 @@ /* * menu.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Menu = class{ - constructor(){ - let display = document.createElement("div"); + +dragonblocks.Menu = class +{ + constructor() + { + let display = document.body.appendChild(document.createElement("div")); display.id = "dragonblocks.menu"; display.style.position = "fixed"; display.style.backgroundColor = "#7E7E7E"; display.style.width = "500px"; display.style.height = "10px"; display.style.visibility = "hidden"; - document.body.appendChild(display); - display = document.getElementById(display.id); + dblib.center(display); dblib.centerVertical(display); - dragonblocks.keyHandler.down("Escape", _ => { - dragonblocks.menu.toggle(); - }); - let headlineContainer = document.createElement("div"); - let headline = headlineContainer.appendChild(document.createElement("h2")); + + let head = document.createElement("div"); + + let headline = head.appendChild(document.createElement("h2")); headline.innerHTML = "Options"; headline.align = "center"; - this.addElement(headlineContainer); + + this.addElement(head); } - toggle(){ + + toggle() + { this.opened ? this.close() : this.open(); } - close(){ + + close() + { this.opened = false; + dragonblocks.gui.closeLayer(); dragonblocks.keyHandler.unlockAll(); + document.getElementById("dragonblocks.menu").style.visibility = "hidden"; } - open(){ + + open() + { this.opened = true; + dragonblocks.gui.showLayer(); dragonblocks.keyHandler.lockAll(); dragonblocks.keyHandler.unlock("Escape"); + document.getElementById("dragonblocks.menu").style.visibility = "visible"; } - addElement(elem){ + + addElement(elem) + { let menu = document.getElementById("dragonblocks.menu"); elem = menu.appendChild(elem); + elem.style.position = "absolute"; elem.style.top = menu.offsetHeight + "px"; elem.style.width = "80%"; dblib.center(elem); - menu.style.height = menu.offsetHeight + 10 + elem.offsetHeight + "px"; + + menu.style.height = menu.offsetHeight + 10 + elem.offsetHeight + "px"; dblib.centerVertical(menu); + return elem; } - addButton(html, func){ + + addButton(html, func) + { let elem = document.createElement("button"); elem.innerHTML = html; elem.style.fontSize = "20px"; @@ -78,12 +97,20 @@ dragonblocks.Menu = class{ dragonblocks.menu.close(); func && func(event); }); + this.addElement(elem); } -} +}; + dragonblocks.menu = new dragonblocks.Menu(); dragonblocks.menu.addButton("Continue Playing"); -dragonblocks.registerOnStarted( _ => { + +dragonblocks.registerOnStarted(_ => { dragonblocks.menu.addButton(dragonblocks.loggedin ? "Save and Quit to Title" : "Quit to Title", dragonblocks.quit); }); + dragonblocks.keyHandler.down("F5", _ => {}); + +dragonblocks.keyHandler.down("Escape", _ => { + dragonblocks.menu.toggle(); +}); diff --git a/engine/node.js b/engine/node.js index 95eb19f..8096526 100644 --- a/engine/node.js +++ b/engine/node.js @@ -1,107 +1,127 @@ /* * node.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Node = class extends dragonblocks.Item{ - constructor(obj){ - super(obj); - if(this.drops == "") + +dragonblocks.Node = class extends dragonblocks.Item +{ + constructor(def){ + super(def); + + if (this.drops == "") this.drops = " "; - if(this.drop == "") + + if (this.drop == "") this.drop = " "; + this.drops = this.drops || this.drop || this.name; - if(this.mobstable == undefined) + + if (this.mobstable == undefined) this.mobstable = this.stable; - let self = this; - if(this.liquid){ + + if (this.liquid) { this.hardness = 1; - let oldOndig = this.ondig; - this.ondig = (x, y) => { - if(oldOndig) - return oldOndig(x, y); + + this.ondig = this.ondig || (_ => { return false; - }; - let oldBlast = this.onblast; - this.onblast = (x, y) => { - if(oldBlast) - return oldBlast(x, y); + }); + + this.onblast = this.onblast || (_ => { return false; - }; + }); + let oldOnset = this.onset; + let self = this; + this.onset = (x, y) => { let meta = dragonblocks.getNode(x, y).meta; + meta.liquidInterval = setInterval(_ => { for(let [ix, iy] of [[x + 1, y], [x - 1, y], [x, y + 1]]){ - let mapNode = dragonblocks.getNode(ix, iy); - if(! mapNode || mapNode.stable || mapNode.toNode().liquid) + let node = dragonblocks.getNode(ix, iy); + + if (! node || node.stable || node.toNode().liquid) continue; + dragonblocks.setNode(ix, iy, self.name); } }, self.liquidTickSpeed || 2000); - if(oldOnset) + + if (oldOnset) oldOnset(x, y); + return meta; - } + }; + let oldOnremove = this.onremove; + this.onremove = (x, y) => { - clearInterval(dragonblocks.getNode(x, y).meta.liquidInterval) - if(oldOnremove) + clearInterval(dragonblocks.getNode(x, y).meta.liquidInterval); + + if (oldOnremove) oldOnremove(x, y); - } + }; } - dragonblocks.nodes[this.name] = this; - dragonblocks.registeredNodes.push(this); } -} +}; + dragonblocks.nodes = {}; dragonblocks.registeredNodes = []; -dragonblocks.registerNode = function(obj){ - new dragonblocks.Node(obj); -} -dragonblocks.onSetNodeFunctions = []; -dragonblocks.registerOnSetNode = function(func){ - dragonblocks.onSetNodeFunctions.push(func); -} -dragonblocks.onRemoveNodeFunctions = []; -dragonblocks.registerOnRemoveNode = function(func){ - dragonblocks.onRemoveNodeFunctions.push(func); -} -dragonblocks.onPlaceNodeFunctions = []; -dragonblocks.registerOnPlaceNode = function(func){ - dragonblocks.onPlaceNodeFunctions.push(func); -} -dragonblocks.onDigNodeFunctions = []; -dragonblocks.registerOnDigNode = function(func){ - dragonblocks.onDigNodeFunctions.push(func); -} -dragonblocks.onClickNodeFunctions = []; -dragonblocks.registerOnClickNode = function(func){ - dragonblocks.onClickNodeFunctions.push(func); -} -dragonblocks.onActivateNodeFunctions = []; -dragonblocks.registerOnActivateNode = function(func){ - dragonblocks.onActivateNodeFunctions.push(func); -} -dragonblocks.onPunchNodeFunctions = []; -dragonblocks.registerOnPunchNode = function(func){ - dragonblocks.onPunchNodeFunctions.push(func); -} +dragonblocks.registerNode = def => { + let nodeDef = new dragonblocks.Node(def); + dragonblocks.nodes[nodeDef.name] = nodeDef; + dragonblocks.registeredNodes.push(nodeDef); +}; + +dragonblocks.onSetNodeCallbacks = []; +dragonblocks.registerOnSetNode = func => { + dragonblocks.onSetNodeCallbacks.push(func); +}; + +dragonblocks.onRemoveNodeCallbacks = []; +dragonblocks.registerOnRemoveNode = func => { + dragonblocks.onRemoveNodeCallbacks.push(func); +}; + +dragonblocks.onPlaceNodeCallbacks = []; +dragonblocks.registerOnPlaceNode = func => { + dragonblocks.onPlaceNodeCallbacks.push(func); +}; + +dragonblocks.onDigNodeCallbacks = []; +dragonblocks.registerOnDigNode = func => { + dragonblocks.onDigNodeCallbacks.push(func); +}; + +dragonblocks.onClickNodeCallbacks = []; +dragonblocks.registerOnClickNode = func => { + dragonblocks.onClickNodeCallbacks.push(func); +}; + +dragonblocks.onActivateNodeCallbacks = []; +dragonblocks.registerOnActivateNode = func => { + dragonblocks.onActivateNodeCallbacks.push(func); +}; +dragonblocks.onPunchNodeCallbacks = []; +dragonblocks.registerOnPunchNode = func => { + dragonblocks.onPunchNodeCallbacks.push(func); +}; diff --git a/engine/out_stack.js b/engine/out_stack.js new file mode 100644 index 0000000..3a5380f --- /dev/null +++ b/engine/out_stack.js @@ -0,0 +1,47 @@ +/* + * out_stack.js + * + * Copyright 2021 Elias Fleckenstein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +dragonblocks.addInventoryMenuDisplay = elem => { + return document.body.insertBefore(elem, dragonblocks.outStack.getDisplay()); +}; + +setTimeout(_ => { + let out = dragonblocks.outStack = new dragonblocks.ItemStack(); + + out.draw(document.body, 0, 0); + out.getDisplay().style.position = "fixed"; + + out.addEventListener("redraw", _ => { + let display = out.getDisplay(); + display.style.backgroundColor = ""; + display.style.border = "none"; + }); + + addEventListener("mousemove", event => { + let display = out.getDisplay(); + display.style.left = event.clientX + 5 + "px"; + display.style.top = event.clientY + 5 + "px"; + }); + + out.update(); +}); diff --git a/engine/pixel_manipulator.js b/engine/pixel_manipulator.js index 7cb9767..31a0d31 100644 --- a/engine/pixel_manipulator.js +++ b/engine/pixel_manipulator.js @@ -1,75 +1,105 @@ /* * pixel_manipulator.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.PixelManipulator = class{ - constructor(arr){ - let pos = null; - this.content = []; - for(let y = 0; y < arr.length; y++){ - for(let x = 0; x < arr[y].length; x++){ - if(arr[y][x][0] == "§"){ + +dragonblocks.PixelManipulator = class +{ + constructor(arr) + { + this.data = []; + this.functions = []; + + let pos; + + for (let y = 0; y < arr.length; y++) { + for (let x = 0; x < arr[y].length; x++) { + let node = arr[y][x]; + + if (node[0] == "§") { pos = {x: x, y: y}; - arr[y][x] = arr[y][x].slice(1, arr[y][x].length); + node = node.slice(1, node.length); } - if(arr[y][x] == "") + + if (node == "") continue; - this.content.push({ + + this.data.push({ x: x, y: y, - node: arr[y][x] + node: node, }); } } - if(! pos) + + if (! pos) pos = {x: 0, y: 0}; - for(let pixel of this.content){ + + for (let pixel of this.data) { pixel.x = pixel.x - pos.x; pixel.y = pixel.y - pos.y; } - this.functions = []; - } - apply(x, y){ - for(let pixel of this.content){ - if(! dragonblocks.getNode(pixel.x + x, pixel.y + y)) + + apply(x, y) + { + for (let pixel of this.data) { + let mx, my; + mx = pixel.x + x; + my = pixel.y + y; + + let node = dragonblocks.getNode(mx, my); + if (! node) continue; - let doApply = true - for(let func of this.functions) - if(func(dragonblocks.getNode(pixel.x + x, pixel.y + y).toNode(), pixel.x + x, pixel.y + y, pixel.node) == false) + + let nodeDef = node.toNode(); + + let doApply = true; + + for (let func of this.functions) { + if (func(nodeDef, mx, my, pixel.node) == false) { doApply = false; - if(doApply) - dragonblocks.setNode(pixel.x + x, pixel.y + y, pixel.node); + break; + } + } + + if (doApply) + dragonblocks.setNode(mx, my, pixel.node); } + + return this; } - replace(toReplace, replaceWith){ - for(let pixel of this.content){ - if(pixel.node == toReplace) + + replace(toReplace, replaceWith) + { + for (let pixel of this.data) + if (pixel.node == toReplace) pixel.node = replaceWith; - } + + return this; } - addFunction(func){ + + addFunction(func) + { this.functions.push(func); + return this; } -} -dragonblocks.getPixelManipulator = function(arr){ - return new dragonblocks.PixelManipulator(arr); -} +}; diff --git a/engine/player.js b/engine/player.js index 493c522..5ea986c 100644 --- a/engine/player.js +++ b/engine/player.js @@ -1,24 +1,24 @@ /* * player.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ dragonblocks.registerTool({ name: "dragonblocks:hand", @@ -56,43 +56,62 @@ dragonblocks.registerEntity({ creative: false, } }); + dragonblocks.Player = class extends dragonblocks.SpawnedEntity{ - constructor(){ - if(dragonblocks.worldIsLoaded){ - super(dragonblocks.world.spawnedEntities.filter(entity => { return entity.name == "dragonblocks:player" })[0]); - dragonblocks.world.spawnedEntities = dragonblocks.world.spawnedEntities.filter(entity => { return entity.name != "dragonblocks:player" }); - } - else + constructor() + { + if (dragonblocks.worldIsLoaded) { + super(dragonblocks.world.spawnedEntities.filter(entity => { + return entity.name == "dragonblocks:player"; + })[0]); + + dragonblocks.world.spawnedEntities = dragonblocks.world.spawnedEntities.filter(entity => { + return entity.name != "dragonblocks:player"; + }); + } else { super(dragonblocks.entities["dragonblocks:player"], dragonblocks.map.width / 2, 5); - dragonblocks.player = this; + } + let self = this; + // Skin this.skin = this.meta.skin; + // Inventory - this.tmp.inventory = new dragonblocks.InventoryGroup(); // Create Inventory Group that can hold multible Inventories + this.tmp.inventory = new dragonblocks.InventoryGroup(); // Create Inventory Group that can hold multible Inventories + // Main Inventory - this.tmp.mainInventory = new dragonblocks.Inventory(32, 8); // The Standard Inventory - for(let stack of this.tmp.mainInventory.list){ - stack.addUpdateListener(_ => { - if(dragonblocks.player.gamemode == "creative" && stack.count > 1) // Keep itemcount of every stack at one when in creative - stack.count = 1; - }); - } - if(this.meta.mainInventory) - this.tmp.mainInventory.parse(this.meta.mainInventory); // Load saved Inventory - this.tmp.mainInventory.addUpdateListener(_ => { - self.meta.mainInventory = this.tmp.mainInventory.stringify(); // Save inventory after every change + this.tmp.mainInventory = new dragonblocks.Inventory(32, 8); // The Main Inventory + + if (this.meta.mainInventory) + this.tmp.mainInventory.deserialize(this.meta.mainInventory); // Load saved Inventory + + this.tmp.mainInventory.addEventListener("updateStack", event => { + self.meta.mainInventory = this.tmp.mainInventory.serialize(); // Save inventory after every change + + if (self.gamemode == "creative" && event.stack.count > 1) // Keep itemcount of every stack at one when in creative + event.stack.count = 1; }); - this.tmp.mainInventory.addUpdateListener(_ => { - if(self.tmp.hudbar) + + this.tmp.mainInventory.addEventListener("updateStack", _ => { + if (self.tmp.hudbar) self.tmp.hudbar.update(); }); + // Hudbar - this.tmp.hudbar = new dragonblocks.Hudbar(this.tmp.mainInventory, 8); // The hudbar has 8 slots + this.tmp.hudbar = new dragonblocks.Hudbar(this.tmp.mainInventory, 8); // The hudbar has 8 slots + // Creative Inventory let creativelist = []; - dragonblocks.registeredItems.filter(item => {return ! item.hidden}).forEach(item => {creativelist.push(item.name)}); - this.tmp.creativeInventory = new dragonblocks.CreativeInventory(32, creativelist, 8); // The creative Inventory contains every registered item that is not marked as hidden + + dragonblocks.registeredItems.filter(item => { + return ! item.hidden; + }).forEach(item => { + creativelist.push(item.name); + }); + + this.tmp.creativeInventory = new dragonblocks.CreativeInventory(32, creativelist, 8); // The creative Inventory contains every registered item that is not marked as hidden + // Survival Inventory this.tmp.survivalInventory = new dragonblocks.InventoryContainer({ inventory: new dragonblocks.Craftfield(3, 3), @@ -101,156 +120,251 @@ dragonblocks.Player = class extends dragonblocks.SpawnedEntity{ left: 1, right: 2, }); - if(this.meta.survivalInventory) - this.tmp.survivalInventory.parse(this.meta.survivalInventory); - this.tmp.survivalInventory.addUpdateListener(_ => { - self.meta.survivalInventory = this.tmp.survivalInventory.stringify(); + + if (this.meta.survivalInventory) + this.tmp.survivalInventory.deserialize(this.meta.survivalInventory); + + this.tmp.survivalInventory.addEventListener("updateStack", _ => { + self.meta.survivalInventory = this.tmp.survivalInventory.serialize(); }); - //Init Inventory + + // Init Inventory this.resetInventoryElements(); + // Map Interaction this.tmp.tool = null; - this.tmp.defaultTool = this.meta.creative ? dragonblocks.getTool("dragonblocks:creative_hand") : dragonblocks.getTool("dragonblocks:hand"); + this.tmp.defaultTool = dragonblocks.tools[this.meta.creative ? "dragonblocks:creative_hand" : "dragonblocks:hand"]; this.initMapInteraction(); + // Map Scroll setInterval(_ => { - if(dragonblocks.map.displayLeft + dragonblocks.map.displayWidth < dragonblocks.player.x + dragonblocks.player.width + 3) - dragonblocks.map.displayLeft = parseInt(dragonblocks.player.x + dragonblocks.player.width + 3 - dragonblocks.map.displayWidth); - else if(dragonblocks.map.displayLeft > dragonblocks.player.x - 2) - dragonblocks.map.displayLeft = parseInt(dragonblocks.player.x - 2); - if(dragonblocks.map.displayTop + dragonblocks.map.displayHeight < dragonblocks.player.y + dragonblocks.player.height + 3) - dragonblocks.map.displayTop = parseInt(dragonblocks.player.y + dragonblocks.player.height + 3 - dragonblocks.map.displayHeight); - else if(dragonblocks.map.displayTop > dragonblocks.player.y - 2) - dragonblocks.map.displayTop = parseInt(dragonblocks.player.y - 2); - dragonblocks.map.graphicsUpdate(); + if (dragonblocks.map.displayLeft + dragonblocks.map.displayWidth < self.x + self.width + 3) + dragonblocks.map.displayLeft = parseInt(self.x + self.width + 3 - dragonblocks.map.displayWidth); + else if (dragonblocks.map.displayLeft > self.x - 2) + dragonblocks.map.displayLeft = parseInt(self.x - 2); + if (dragonblocks.map.displayTop + dragonblocks.map.displayHeight < self.y + self.height + 3) + dragonblocks.map.displayTop = parseInt(self.y + self.height + 3 - dragonblocks.map.displayHeight); + else if (dragonblocks.map.displayTop > self.y - 2) + dragonblocks.map.displayTop = parseInt(self.y - 2); + + dragonblocks.map.updateGraphics(); }); + // Controls - dragonblocks.keyHandler.down(" ", _ => { dragonblocks.player.jump() }); - dragonblocks.keyHandler.up(" ", _ => { dragonblocks.player.stopJump() }); - dragonblocks.keyHandler.down("ArrowLeft", _ => { dragonblocks.player.moveLeft() }); - dragonblocks.keyHandler.down("ArrowRight", _ => { dragonblocks.player.moveRight() }); - dragonblocks.keyHandler.up("ArrowLeft", _ => { dragonblocks.player.stop() }); - dragonblocks.keyHandler.up("ArrowRight", _ => { dragonblocks.player.stop() }); - dragonblocks.keyHandler.down("i", _ => { dragonblocks.player.toggleInventory(); }); - dragonblocks.keyHandler.down("n", _ => { dragonblocks.player.nextItem() }); - dragonblocks.keyHandler.down("b", _=>{ dragonblocks.player.previousItem() }); - dragonblocks.keyHandler.down("scroll", _ => { dragonblocks.player.nextItem() }); - dragonblocks.keyHandler.up("scroll", _=>{ dragonblocks.player.previousItem() }); - for(let i = 1; i < 9; i++) - dragonblocks.keyHandler.down(i.toString(), _ => { dragonblocks.player.select(i - 1) }); + dragonblocks.keyHandler.down(" ", _ => { + self.jump(); + }); + + dragonblocks.keyHandler.up(" ", _ => { + self.stopJump(); + }); + + dragonblocks.keyHandler.down("ArrowLeft", _ => { + self.moveLeft(); + }); + + dragonblocks.keyHandler.down("ArrowRight", _ => { + self.moveRight(); + }); + + dragonblocks.keyHandler.up("ArrowLeft", _ => { + self.stop(); + }); + + dragonblocks.keyHandler.up("ArrowRight", _ => { + self.stop(); + }); + + dragonblocks.keyHandler.down("i", _ => { + self.toggleInventory(); + }); + + dragonblocks.keyHandler.down("n", _ => { + self.nextItem(); + }); + + dragonblocks.keyHandler.down("b", _=> { + self.previousItem(); + }); + + dragonblocks.keyHandler.down("scroll", _ => { + self.nextItem(); + }); + + dragonblocks.keyHandler.up("scroll", _=>{ + self.previousItem(); + }); + + for (let i = 1; i < 9; i++) { + dragonblocks.keyHandler.down(i.toString(), _ => { + self.select(i - 1); + }); + } + let mapDisplay = document.getElementById("dragonblocks.map"); + addEventListener("mouseup", event => { - if(event.which == 1) - dragonblocks.player.digStop(); + if (event.which == 1) + self.digStop(); }); + addEventListener("keydown", event => { - if(event.key == "Escape" && dragonblocks.player.inventoryIsOpen()) - dragonblocks.player.closeInventory(); + if (event.key == "Escape" && self.inventoryIsOpen()) + self.closeInventory(); }); + // Map Interaction Controls - for(let x = 0; x < dragonblocks.map.displayWidth; x++){ - for(let y = 0; y < dragonblocks.map.displayHeight; y++){ + for (let x = 0; x < dragonblocks.map.displayWidth; x++) { + for (let y = 0; y < dragonblocks.map.displayHeight; y++) { let nodeDisplay = document.getElementById("dragonblocks.map.node[" + x + "][" + y + "]"); + nodeDisplay.addEventListener("mouseover", event => { - if(dragonblocks.player.canReach(x + dragonblocks.map.displayLeft, y + dragonblocks.map.displayTop)) + if (self.canReach(x + dragonblocks.map.displayLeft, y + dragonblocks.map.displayTop)) event.srcElement.style.boxShadow = "0 0 0 1px black inset"; }); + nodeDisplay.addEventListener("mouseleave", event => { event.srcElement.style.boxShadow = "none"; }); + nodeDisplay.addEventListener("mousedown", event => { - let [ix, iy] = [x + dragonblocks.map.displayLeft, y + dragonblocks.map.displayTop] - switch(event.which){ + let [ix, iy] = [x + dragonblocks.map.displayLeft, y + dragonblocks.map.displayTop]; + + switch(event.which) { case 1: - dragonblocks.player.digStart(ix, iy); + self.digStart(ix, iy); break; + case 3: - dragonblocks.player.build(ix, iy); + self.build(ix, iy); break; - } + }; }); } } } - set skin(value){ + + set skin(value) + { this.meta.skin = value; - this.texture = dragonblocks.skins[value].texture; + this.texture = dragonblocks.registeredSkins[value].texture; this.updateTexture(); } - get skin(){ + + get skin() + { return this.meta.skin; } - set gamemode(mode){ + + set gamemode(mode) + { this.setGamemode(mode); } - get gamemode(){ + + get gamemode() + { return this.meta.creative ? "creative" : "survival"; } - get tool(){ - return dragonblocks.getTool(this.getWieldedItem().item) || this.tmp.defaultTool; + + get tool() + { + return dragonblocks.tools[this.getWieldedItem().item] || this.tmp.defaultTool; } - setGamemode(mode){ - switch(mode.toString().toLowerCase()){ + + setGamemode(mode) + { + switch (mode.toString().toLowerCase()) { case "0": case "survival": this.meta.creative = false; break; + case "1": case "creative": this.meta.creative = true; break; + default: return false; } + this.resetInventoryElements(); - this.tmp.defaultTool = dragonblocks.getTool(this.meta.creative ? "dragonblocks:creative_hand" : "dragonblocks:hand"); + this.tmp.defaultTool = dragonblocks.tools[this.meta.creative ? "dragonblocks:creative_hand" : "dragonblocks:hand"]; + return true; } - inventoryIsOpen(){ + + inventoryIsOpen() + { return this.tmp.inventory.opened; } - openInventory(){ + + openInventory() + { this.tmp.inventory.open(); dragonblocks.keyHandler.lockAll(); dragonblocks.keyHandler.unlock("i"); dragonblocks.gui.showLayer(); } - closeInventory(){ + + closeInventory() + { this.tmp.inventory.close(); dragonblocks.keyHandler.unlockAll(); dragonblocks.gui.hideLayer(); } - toggleInventory(){ + + toggleInventory() + { this.inventoryIsOpen() ? this.closeInventory() : this.openInventory(); } - give(itemstring){ + + give(itemstring) + { return this.tmp.mainInventory.add(itemstring); } - clearInventory(){ + + clearInventory() + { this.tmp.mainInventory.clear(); } - setInventoryElements(elems){ + + setInventoryElements(elems) + { this.tmp.inventory.elements = elems; } - resetInventoryElements(){ + + resetInventoryElements() + { let elems = [this.tmp.mainInventory]; elems.unshift(this.gamemode == "creative" ? this.tmp.creativeInventory : this.tmp.survivalInventory); this.setInventoryElements(elems); } - previousItem(){ + + previousItem() + { this.tmp.hudbar.previousItem(); } - nextItem(){ + + nextItem() + { this.tmp.hudbar.nextItem(); } - select(i){ + + select(i) + { this.tmp.hudbar.select(i); } - getWieldedItem(){ + + getWieldedItem() + { return this.tmp.hudbar.getSelectedItem(); } - set onNextInventoryClose(func){ + + set onNextInventoryClose(func) + { this.tmp.inventory.onNextClose = func; } -} -Object.assign(dragonblocks.Player.prototype, dragonblocks.MapIntercation); //Mixin +}; + +Object.assign(dragonblocks.Player.prototype, dragonblocks.MapInteraction); //Mixin diff --git a/engine/recipe.js b/engine/recipe.js index abbf87e..d9023ef 100644 --- a/engine/recipe.js +++ b/engine/recipe.js @@ -1,59 +1,73 @@ /* * recipe.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Recipe = class{ - constructor(obj){ - if(! obj || ! obj.result || ! obj.recipe instanceof Array || ! obj.recipe[0] instanceof Array) + +dragonblocks.Recipe = class +{ + constructor(def) + { + if (! def || ! def.result || ! def.recipe instanceof Array || ! def.recipe[0] instanceof Array) return; - this.recipe = obj.recipe; - this.result = obj.result; + + this.recipe = def.recipe; + this.result = def.result; + this.height = this.recipe.length; this.width = this.recipe[0].length; + dragonblocks.recipes.push(this); } - match(craftfield){ - if(craftfield.width < this.width || craftfield.height < this.height) + + match(craftfield) + { + if (craftfield.width < this.width || craftfield.height < this.height) return false; - for(let ydiff = 0; ydiff <= craftfield.height - this.height; ydiff++){ - for(let xdiff = 0; xdiff <= craftfield.width - this.width; xdiff++){ + + for (let ydiff = 0; ydiff <= craftfield.height - this.height; ydiff++) { + for (let xdiff = 0; xdiff <= craftfield.width - this.width; xdiff++) { let found = true; - for(let y = 0; y < craftfield.height; y++){ - for(let x = 0; x < craftfield.width; x++){ - if(! this.recipe[y - ydiff] || ! this.recipe[y - ydiff][x - xdiff]){ - if(craftfield.list[y * craftfield.width + x].item) + + for (let y = 0; y < craftfield.height; y++) { + for (let x = 0; x < craftfield.width; x++) { + if (! this.recipe[y - ydiff] || ! this.recipe[y - ydiff][x - xdiff]) { + if (craftfield.list[y * craftfield.width + x].item) found = false; - } - else if(! dragonblocks.itemMatch(craftfield.list[y * craftfield.width + x].item, this.recipe[y - ydiff][x - xdiff])) + } else if (! dragonblocks.itemMatch(craftfield.list[y * craftfield.width + x].item, this.recipe[y - ydiff][x - xdiff])) { found = false; + } } } - if(found) + + if (found) return true; } } + return false; } -} +}; + dragonblocks.recipes = []; -dragonblocks.registerRecipe = function(obj){ - new dragonblocks.Recipe(obj); -} +dragonblocks.registerRecipe = def => { + let recipeDef = new dragonblocks.Recipe(def); + dragonblocks.recipes.push(recipeDef); +}; diff --git a/engine/ressources.js b/engine/ressources.js deleted file mode 100644 index 4aec9a6..0000000 --- a/engine/ressources.js +++ /dev/null @@ -1,89 +0,0 @@ -/* - * ressources.js - * - * Copyright 2020 Elias Fleckenstein - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * - */ -dragonblocks.Texture = class{ - constructor(path){ - this.name = path.slice(path.lastIndexOf("/") + 1, path.length); - this.path = path; - dragonblocks.textures[this.name] = this; - } -} -dragonblocks.textures = {}; -dragonblocks.loadTexture = function(path){ - new dragonblocks.Texture(path); -}; -{ - let textures = $.getJSON({ - url: "api.php", - method: "POST", - data: {call: "getTextures"} - }).responseJSON; - for(let i in textures) - dragonblocks.loadTexture(textures[i]); -} -dragonblocks.getTexture = function(texture){ - if(! texture) - return "none"; - if(dragonblocks.textures[texture]) - return "url(" + dragonblocks.textures[texture].path + ")"; - else - return texture; -}; -dragonblocks.resolveTextures = function(elem){ - if(elem.nodeName == "IMG" && elem.attributes["texture"]){ - let texture = elem.attributes["texture"].nodeValue; - elem.src = dragonblocks.textures[texture] ? dragonblocks.textures[texture].path : texture; - } - for(let child of elem.children) - dragonblocks.resolveTextures(child); -} -dragonblocks.Sound = class{ - constructor(path){ - this.name = path.slice(path.lastIndexOf("/") + 1, path.length); - this.path = path; - dragonblocks.sounds[this.name] = this; - } -} -dragonblocks.sounds = {}; -dragonblocks.loadSound = function(path){ - new dragonblocks.Sound(path); -}; -dragonblocks.getSound = function(sound){ - if(! sound) - return ""; - if(dragonblocks.sounds[sound]) - return dragonblocks.sounds[sound].path; - else - return sound; -}; -{ - let sounds = $.getJSON({ - url: "api.php", - method: "POST", - data: {call: "getSounds"} - }).responseJSON; - for(let i in sounds) - dragonblocks.loadSound(sounds[i]); -} -dragonblocks.playSound = function(sound){ - new Audio(dragonblocks.getSound(sound)).play(); -} diff --git a/engine/skin.js b/engine/skin.js index 69e7bcf..7691e55 100644 --- a/engine/skin.js +++ b/engine/skin.js @@ -1,85 +1,107 @@ /* * skin.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.skins = {}; -dragonblocks.registeredSkins = []; -dragonblocks.registerSkin = function(obj){ - if(!obj || !obj.name || !obj.texture) - dragonblocks.error("Can not register skin"); - dragonblocks.skins[obj.name] = obj; - dragonblocks.registeredSkins.push(obj); -} + +dragonblocks.registeredSkins = {}; + +dragonblocks.registerSkin = def => { + if (! def || ! def.name || ! def.texture) + dragonblocks.error("Cannot register skin"); + + dragonblocks.registeredSkins[def.name] = def; +}; + { - let gui = dragonblocks.gui.createBox({ keylock: true }); + let gui = new dragonblocks.gui.Box({keylock: true}); + let headline = gui.create("h1"); headline.innerHTML = "Skins"; headline.align = "center"; + let status = gui.create("span"); status.style.position = "absolute"; status.style.top = "5px"; status.style.left = "5px"; + let columns = parseInt(parseInt(gui.getDisplay().style.width) / (dragonblocks.settings.map.scale * 1.5)); + let container = gui.create("div"); container.style.width = parseInt(columns * dragonblocks.settings.map.scale * 1.5) + "px"; container.style.position = "absolute"; container.style.top = "80px"; dblib.center(container); + dragonblocks.registerOnStarted(_ => { status.innerHTML = dragonblocks.player.skin; - for(let i in dragonblocks.registeredSkins){ - i = parseInt(i); + + let i = 0; + + for (let skin in dragonblocks.registeredSkins) { let x = i % columns; let y = (i - x) / columns; + + i++; + + let def = dragonblocks.registeredSkins[skin]; + let skinDisplay = container.appendChild(document.createElement("div")); skinDisplay.style.position = "absolute"; skinDisplay.style.left = parseInt(x * dragonblocks.settings.map.scale * 1.5) + "px"; skinDisplay.style.top = parseInt(y * dragonblocks.settings.map.scale * 2 * 1.5) + "px"; skinDisplay.style.width = parseInt(dragonblocks.settings.map.scale) + "px"; skinDisplay.style.height = parseInt(dragonblocks.settings.map.scale * 2) + "px"; - skinDisplay.style.background = dragonblocks.getTexture(dragonblocks.registeredSkins[i].texture); + skinDisplay.style.background = dragonblocks.getTexture(def.texture); skinDisplay.style.backgroundSize = "cover"; - skinDisplay.title = dragonblocks.registeredSkins[i].name + (dragonblocks.registeredSkins[i].desc ? "\n" + dragonblocks.registeredSkins[i].desc : ""); - if(dragonblocks.player.skin == dragonblocks.registeredSkins[i].name) + skinDisplay.title = def.name + (def.desc ? "\n" + def.desc : ""); + + if (dragonblocks.player.skin == def.name) skinDisplay.style.boxShadow = "0 0 0 3px #BEBEBE"; + skinDisplay.addEventListener("click", event => { event.srcElement.style.boxShadow = "0 0 0 3px #BEBEBE"; - dragonblocks.player.skin = dragonblocks.registeredSkins[i].name; + + dragonblocks.player.skin = def.name; status.innerHTML = dragonblocks.player.skin; + container.dispatchEvent(new Event("update")); }); + container.addEventListener("update", event => { - if(dragonblocks.player.skin != dragonblocks.registeredSkins[i].name) + if (dragonblocks.player.skin != def.name) skinDisplay.style.boxShadow = "none"; }); + skinDisplay.addEventListener("mouseover", event => { - if(dragonblocks.player.skin != dragonblocks.registeredSkins[i].name) + if (dragonblocks.player.skin != def.name) event.srcElement.style.boxShadow = "0 0 0 1px black"; }); + skinDisplay.addEventListener("mouseleave", event => { - if(dragonblocks.player.skin != dragonblocks.registeredSkins[i].name) + if (dragonblocks.player.skin != def.name) event.srcElement.style.boxShadow = "none"; }); } }); + dragonblocks.menu.addButton("Change Skin", _ => { gui.open(); }); diff --git a/engine/spawned_entity.js b/engine/spawned_entity.js index 2f08e97..e35e01d 100644 --- a/engine/spawned_entity.js +++ b/engine/spawned_entity.js @@ -1,29 +1,32 @@ /* * spawned_entity.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.SpawnedEntity = class { - constructor(entity, x, y){ - dblib.copy(this, entity); - if(entity instanceof dragonblocks.Entity){ + +dragonblocks.SpawnedEntity = class +{ + constructor(def, x, y){ + dblib.copy(this, def); + + if (def instanceof dragonblocks.Entity) { this.id = dragonblocks.getToken(); this.jumping = this.movingRight = this.movingLeft = this.movingUp = this.movingDown = false; this.x = x; @@ -35,234 +38,342 @@ dragonblocks.SpawnedEntity = class { this.meta = this.meta || {}; this.toEntity().oninit && this.toEntity().oninit(this); } - this.physicsRecover(); + + this.restorePhysics(); this.tmp = {}; + this.addGraphics(); + let self = this; - this.tickInterval = setInterval(_ => {self.tick()}, 100); - this.physicInterval = setInterval(_=>{self.physics()}); - this.toEntity().onspawn && this.toEntity().onspawn(this); - addEventListener("focus", _ => { self.physicsRecover(); }); - addEventListener("blur", _ => { self.physicsRecover(); }); + + this.tickInterval = setInterval(_ => { + self.tick() + }, 100); + this.physicInterval = setInterval(_=>{ + self.physicsTick() + }); + + let entityDef = this.toEntity(); + entityDef.onspawn && entityDef.onspawn(this); + + addEventListener("focus", _ => { + self.restorePhysics(); + }); + + addEventListener("blur", _ => { + self.restorePhysics(); + }); + dragonblocks.spawnedEntities.push(this); } - toEntity(){ + + toEntity() + { return dragonblocks.entities[this.name]; } - despawn(){ - this.toEntity().ondespawn && this.toEntity().ondespawn(this); + + despawn() + { + let entityDef = this.toEntity(); + entityDef.ondespawn && entityDef.ondespawn(this); + let id = this.id; - dragonblocks.spawnedEntities = dragonblocks.spawnedEntities.filter(entity => {return entity.id != id}); + dragonblocks.spawnedEntities = dragonblocks.spawnedEntities.filter(entity => { + return entity.id != id; + }); + clearInterval(this.physicInterval); clearInterval(this.tickInterval); - dblib.remove(document.getElementById("dragonblocks.entity[" + this.id + "]")); + + document.getElementById("dragonblocks.entity[" + this.id + "]").remove(); } - physicsRecover(){ + + restorePhysics() + { this.tx0 = new Date().getTime() / 1000; this.ty0 = new Date().getTime() / 1000; this.x0 = this.x; this.y0 = this.y; } - physicsCheckX(){ - if(this.x < 0) + + collisionX() + { + if (this.x < 0) return false; - if(this.x + this.width > dragonblocks.map.width) + + if (this.x + this.width > dragonblocks.map.width) return false; - return this.physicsCheckBoth(); + + return this.collision(); } - physicsCheckY(){ - if(this.y < 0) + + collisionY() + { + if (this.y < 0) return false; - if(this.y + this.height > dragonblocks.map.height) + + if (this.y + this.height > dragonblocks.map.height) return false; - return this.physicsCheckBoth(); + + return this.collision(); } - physicsCheckBoth(){ - for(let ix = Math.floor(this.x); ix <= Math.ceil(this.x + this.width - 0.01) - 1; ix++) - for(let iy = Math.floor(this.y); iy <= Math.ceil(this.y + this.height - 0.01) - 1; iy++) - if(dragonblocks.getNode(ix, iy).mobstable) + + collision() + { + for (let ix = Math.floor(this.x); ix <= Math.ceil(this.x + this.width - 0.01) - 1; ix++) + for (let iy = Math.floor(this.y); iy <= Math.ceil(this.y + this.height - 0.01) - 1; iy++) + if (dragonblocks.getNode(ix, iy).mobstable) return false; return true; } - physicsResetX(){ + + physicsResetX() + { this.tx0 = new Date().getTime() / 1000; this.vx = 0; this.x0 = this.x; this.x = Math.round(this.x * 10) / 10; } - physicsResetY(){ + + physicsResetY() + { this.ty0 = new Date().getTime() / 1000; this.vy = 0; this.y0 = this.y; this.y = Math.round(this.y * 10) / 10; } - physics(){ + + physicsTick() + { let t = new Date().getTime() / 1000; + var oldX = this.x; var dtx = t - this.tx0; - if(this.ax) + + if (this.ax) this.x = this.ax * dtx * dtx + this.vx * dtx + this.x0; - else if(this.vx) + else if (this.vx) this.x = this.vx * dtx + this.x0; - if(! this.physicsCheckX()) - { + + if (! this.collisionX()) { this.x = oldX; this.physicsResetX(); this.toEntity().oncollide && this.toEntity().oncollide(this); } + var oldY = this.y; var dty = t - this.ty0; - if(this.ay) + + if (this.ay) this.y = this.ay * dty * dty + this.vy * dty + this.y0; - else if(this.vy) + else if (this.vy) this.y = this.vy * dty + this.y0; - if(! this.physicsCheckY()) - { + + if (! this.collisionY()) { this.y = oldY; this.physicsResetY(); this.toEntity().oncollide && this.toEntity().oncollide(this); } + this.y = Math.round(this.y * 50) / 50; + this.updateGraphics(); } - touch(x, y){ - for(let ix = Math.floor(this.x); ix <= Math.ceil(this.x + this.width - 0.01) - 1; ix++) - for(let iy = Math.floor(this.y); iy <= Math.ceil(this.y + this.height - 0.01) - 1; iy++) - if(iy == y && ix == x) + + touch(x, y) + { + for (let ix = Math.floor(this.x); ix <= Math.ceil(this.x + this.width - 0.01) - 1; ix++) + for (let iy = Math.floor(this.y); iy <= Math.ceil(this.y + this.height - 0.01) - 1; iy++) + if (iy == y && ix == x) return true; } - addGraphics(obj){ - var display = document.createElement("div"); + + addGraphics(obj) + { + var display = document.getElementById("dragonblocks.map").appendChild(document.createElement("div")); display.id = "dragonblocks.entity[" + this.id + "]"; display.style.position = "absolute"; display.style.width = this.width * dragonblocks.settings.map.scale + "px"; display.style.height = this.height * dragonblocks.settings.map.scale + "px"; display.style.zIndex = "0"; - let self = this; + + display.addEventListener("mouseover", event => { event.srcElement.style.boxShadow = "0 0 0 1px black inset"; }); + display.addEventListener("mouseleave", event => { event.srcElement.style.boxShadow = "none"; }); + + let self = this; + display.addEventListener("mousedown", event => { - switch(event.which){ + let entityDef = self.toEntity(); + + switch (event.which) { case 1: - self.toEntity().onpunch && self.toEntity().onpunch(self); + entityDef.onpunch && entityDef.onpunch(self); break; + case 3: - self.toEntity().onclick && self.toEntity().onclick(self); + entityDef.onclick && entityDef.onclick(self); break; } }); - document.getElementById("dragonblocks.map").appendChild(display); + this.updateTexture(); this.updateGraphics(); } - async updateGraphics(){ + + async updateGraphics() + { let display = document.getElementById("dragonblocks.entity[" + this.id + "]"); - if(! display) + + if (! display) return; + display.style.left = (this.x - dragonblocks.map.displayLeft) * dragonblocks.settings.map.scale + "px"; display.style.top = (this.y - dragonblocks.map.displayTop) * dragonblocks.settings.map.scale + "px"; } - updateTexture(){ + + updateTexture() + { let display = document.getElementById("dragonblocks.entity[" + this.id + "]"); display.style.background = dragonblocks.getTexture(this.texture); display.style.backgroundSize = "cover"; } - teleport(x, y){ + + teleport(x, y) + { this.physicsResetX(); this.physicsResetY(); this.x = x; this.y = y; } - moveLeft(){ - if(this.vx == -this.horizontalSpeed) + + moveLeft() + { + if (this.vx == -this.horizontalSpeed) return; - if(this.movingRight) + + if (this.movingRight) this.movingRight = false; + this.movingLeft = true; this.physicsResetX(); this.vx = -this.horizontalSpeed; } - moveRight(){ - if(this.vx == this.horizontalSpeed) + + moveRight() + { + if (this.vx == this.horizontalSpeed) return; - if(this.movingLeft) + + if (this.movingLeft) this.movingLeft = false; + this.movingRight = true; this.physicsResetX(); this.vx = this.horizontalSpeed; } - stop(){ + + stop() + { this.movingLeft = false; this.movingRight = false; this.physicsResetX(); } - moveDown(){ - if(this.vy == this.verticalSpeed) + + moveDown() + { + if (this.vy == this.verticalSpeed) return; - if(this.movingDown) + + if (this.movingDown) this.movingDown = false; + this.movingDown = true; this.physicsResetY(); this.vy = this.verticalSpeed; } - moveUp(){ - if(this.vy == -this.verticalSpeed) + + moveUp() + { + if (this.vy == -this.verticalSpeed) return; - if(this.movingUp) + + if (this.movingUp) this.movingUp = false; + this.movingUp = true; this.physicsResetY(); this.vy = -this.verticalSpeed; } - stopFly(){ + + stopFly() + { this.movingUp = false; this.movingDown = false; this.physicsResetY(); } - jump(){ - if(this.vy == -this.verticalSpeed) + + jump() + { + if (this.vy == -this.verticalSpeed) return; + this.jumping = true; this.vy = -this.verticalSpeed; } - stopJump(){ + + stopJump() + { this.jumping = false; } - jumpOnce(){ + + jumpOnce() + { this.vy = -this.verticalSpeed; } - set gravity(value){ + + set gravity(value) + { this._gravity = value; - if(this._gravity) + + if (this._gravity) this.ay = dragonblocks.settings.physics.gravity; else this.ay = 0; } - get gravity(){ + + get gravity() + { return this._gravity; } - tick(){ - if(this.movingLeft) + + tick() + { + if (this.movingLeft) this.moveLeft(); - if(this.movingRight) + if (this.movingRight) this.moveRight(); - if(this.movingUp) + if (this.movingUp) this.moveUp(); - if(this.movingDown) + if (this.movingDown) this.moveDown(); - if(this.jumping) + + if (this.jumping) this.jump(); - if(this.gravity) + + if (this.gravity) this.gravity = true; } -} +}; + dragonblocks.spawnedEntities = []; dragonblocks.registerOnStarted(_ => { - if(dragonblocks.worldIsLoaded) - for(let entity of dragonblocks.world.spawnedEntities) + if (dragonblocks.worldIsLoaded) + for (let entity of dragonblocks.world.spawnedEntities) new dragonblocks.SpawnedEntity(entity); }); diff --git a/engine/timer.js b/engine/timer.js index 70d6b19..8d06cdd 100644 --- a/engine/timer.js +++ b/engine/timer.js @@ -1,42 +1,46 @@ /* * timer.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ + dragonblocks.ticksPerSecond = dragonblocks.settings.timer.tps; -dragonblocks.setTimer = function(name, seconds, onfinish, meta){ + +dragonblocks.setTimer = (name, seconds, onfinish, meta) => { seconds = meta[name] || seconds; meta[name] = seconds; meta[name + "Interval"] = setInterval(_ => { - meta[name] -= 1 / dragonblocks.settings.timer.tps; - if(meta[name] <= 0){ + meta[name] -= 1 / dragonblocks.settings.timer.tps; // This is intended: By changing dragonblocks.settings.timer.tps you can speed up / slow down timer execution + if (meta[name] <= 0) { dragonblocks.clearTimer(name, meta); onfinish(); } }, 1000 / dragonblocks.ticksPerSecond); -} -dragonblocks.finishTimer = function(name, meta){ +}; + +dragonblocks.finishTimer = (name, meta) => { meta[name] = 0; -} -dragonblocks.clearTimer = function(name, meta){ +}; + +dragonblocks.clearTimer = (name, meta) => { clearInterval(meta[name + "Interval"]); delete meta[name]; delete meta[name + "Interval"]; -} +}; diff --git a/engine/tool.js b/engine/tool.js index 048070e..b1f1308 100644 --- a/engine/tool.js +++ b/engine/tool.js @@ -1,49 +1,56 @@ /* * tool.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.Tool = class{ - constructor(obj){ - dblib.copy(this, obj); + +dragonblocks.Tool = class +{ + constructor(def) + { + dblib.copy(this, def); + this.defaultDamage = this.defaultDamage || 1; this.interval = this.interval || 250; this.groups = this.groups || []; this.range = this.range || 4; - dragonblocks.tools[this.name] = this; - dragonblocks.registeredTools.push(this); } - calculateDamage(node){ - var damage = -1; - for(let group of this.groups){ - if(node.inGroup(group.name)) + + calculateDamage(node) + { + let damage = -1; + + for (let group of this.groups) { + if (node.inGroup(group.name)) damage = group.damage; } + return damage / 1000 * this.interval; } -} +}; + dragonblocks.tools = {}; dragonblocks.registeredTools = []; -dragonblocks.registerTool = function(obj){ - new dragonblocks.Tool(obj); -} -dragonblocks.getTool = function(name){ - return dragonblocks.tools[name]; -} +dragonblocks.registerTool = def => { + let toolDef = new dragonblocks.Tool(def); + dragonblocks.tools[toolDef.name] = toolDef; + dragonblocks.registeredTools.push(toolDef); +}; + diff --git a/engine/world.js b/engine/world.js index 7647184..61ccab1 100644 --- a/engine/world.js +++ b/engine/world.js @@ -1,67 +1,51 @@ /* * world.js - * + * * Copyright 2020 Elias Fleckenstein - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ -dragonblocks.getSavestring = function(){ + +dragonblocks.getSavestring = _ => { dragonblocks.world.map = dragonblocks.map; dragonblocks.world.mods = dragonblocks.mods; - dragonblocks.world.spawnedEntities = dblib.removeTmp(dragonblocks.spawnedEntities) + dragonblocks.world.spawnedEntities = dblib.removeTmp(dragonblocks.spawnedEntities); + return JSON.stringify(dragonblocks.world); } -dragonblocks.save = function(){ - if(dragonblocks.loggedin) - $.post({ - url: "api.php", - data: {call: "saveWorld", name: dragonblocks.worldname, world: dragonblocks.getSavestring()} - }); -} -dragonblocks.checkWorldOwnership = function(name){ - return $.get("worlds/" + name + "/owner.txt").responseText == dragonblocks.username; -} -dragonblocks.checkWorldExistance = function(name){ - return $.get("worlds/" + name).status == 200; -} -dragonblocks.checkWorldSpelling = function(name){ - return $.getJSON({ - url: "api.php", - method: "POST", - data: {call: "checkWorldname", name: name}, - }).responseJSON; -} -dragonblocks.loadWorldlist = function(){ - dragonblocks.worlds = []; - let allWorlds = $.getJSON({ - url: "api.php", - method: "POST", - data: {call: "getWorlds"} - }).responseJSON; - for(let world of allWorlds){ - if(dragonblocks.checkWorldOwnership(world)) - dragonblocks.worlds.push(world); - } -} + +dragonblocks.save = _ => { + if (dragonblocks.loggedin) + return dragonblocks.backendCall("saveWorld", true, {name: dragonblocks.worldname, world: dragonblocks.getSavestring()}); +}; + +dragonblocks.checkWorldnameSpelling = name => { + return name.match(/^[a-zA-Z0-9]+$/); +}; + +dragonblocks.loadWorldList = _ => { + dragonblocks.worlds = dragonblocks.backendCall("getWorlds"); +}; + dragonblocks.getEmptyWorld = function(){ return { map:{ - content: Array(dragonblocks.settings.map.width).fill(Array(dragonblocks.settings.map.width).fill(new dragonblocks.MapNode("air"))), + data: Array(dragonblocks.settings.map.width).fill(Array(dragonblocks.settings.map.width).fill(new dragonblocks.MapNode("air"))), width: dragonblocks.settings.map.width, height: dragonblocks.settings.map.height, displayTop: dragonblocks.settings.map.height / 2, diff --git a/game/chest/init.js b/game/chest/init.js index 8b49d6f..a827158 100644 --- a/game/chest/init.js +++ b/game/chest/init.js @@ -9,7 +9,7 @@ dragonblocks.registerNode({ let meta = dragonblocks.getNode(x, y).meta; meta.inventory = new dragonblocks.Inventory(32, 8); if(meta.inventoryString) - meta.inventory.parse(meta.inventoryString); + meta.inventory.deserialize(meta.inventoryString); }, onclick: (x, y) => { let meta = dragonblocks.getNode(x, y).meta; @@ -19,7 +19,7 @@ dragonblocks.registerNode({ dragonblocks.player.onNextInventoryClose = _ => { dragonblocks.player.resetInventoryElements(); dragonblocks.nodes["chest:chest"].playSound("close"); - meta.inventoryString = meta.inventory.stringify(); + meta.inventoryString = meta.inventory.serialize(); }; }, ondig: (x, y) => { diff --git a/game/furnace/inventory.js b/game/furnace/inventory.js index c70864a..d28ba3b 100644 --- a/game/furnace/inventory.js +++ b/game/furnace/inventory.js @@ -8,28 +8,28 @@ furnace.Inventory = class extends dragonblocks.InventoryContainer{ right: 2, }); let self = this; - this.input = new dragonblocks.Itemstack(); - this.input.addUpdateListener(_ => { + this.input = new dragonblocks.ItemStack(); + this.input.addEventListener("update", _ => { self.update(); }); - this.fuel = new dragonblocks.Itemstack(); - this.fuel.addUpdateListener(_ => { + this.fuel = new dragonblocks.ItemStack(); + this.fuel.addEventListener("update", _ => { self.update(); }); - this.burnProgressDisplay = new dragonblocks.Itemstack(); - this.burnProgressDisplay.parse("furnace:burn_progress_0"); + this.burnProgressDisplay = new dragonblocks.ItemStack(); + this.burnProgressDisplay.deserialize("furnace:burn_progress_0"); this.burnProgressDisplay.action = _ => {}; - this.burnProgressDisplay.onredraw = _ => { + this.burnProgressDisplay.addEventListener("redraw", _ => { dragonblocks.Inventory.getStackDisplay(self.burnProgressDisplay.id).style.backgroundColor = ""; dragonblocks.Inventory.getStackDisplay(self.burnProgressDisplay.id).style.border = "none"; - }; - this.fuelProgressDisplay = new dragonblocks.Itemstack(); - this.fuelProgressDisplay.parse("furnace:fuel_progress_0"); + }); + this.fuelProgressDisplay = new dragonblocks.ItemStack(); + this.fuelProgressDisplay.deserialize("furnace:fuel_progress_0"); this.fuelProgressDisplay.action = _ => {}; - this.fuelProgressDisplay.onredraw = _ => { + this.fuelProgressDisplay.addEventListener("redraw", _ => { dragonblocks.Inventory.getStackDisplay(self.fuelProgressDisplay.id).style.backgroundColor = ""; dragonblocks.Inventory.getStackDisplay(self.fuelProgressDisplay.id).style.border = "none"; - }; + }); this.clear(); this.clearFuel(); this.update(); @@ -37,26 +37,26 @@ furnace.Inventory = class extends dragonblocks.InventoryContainer{ draw(parent, x, y){ if(! super.draw(parent, x, y)) return false; - dragonblocks.Inventory.drawStack(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 0.5 * dragonblocks.settings.inventory.scale * 1.1, this.input); - dragonblocks.Inventory.drawStack(this.getDisplay(), 3 * dragonblocks.settings.inventory.scale * 1.1, 1.5 * dragonblocks.settings.inventory.scale * 1.1, this.burnProgressDisplay); - dragonblocks.Inventory.drawStack(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 1.5 * dragonblocks.settings.inventory.scale * 1.1, this.fuelProgressDisplay); - dragonblocks.Inventory.drawStack(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 2.5 * dragonblocks.settings.inventory.scale * 1.1, this.fuel); + this.input.draw(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 0.5 * dragonblocks.settings.inventory.scale * 1.1); + this.burnProgressDisplay.draw(this.getDisplay(), 3 * dragonblocks.settings.inventory.scale * 1.1, 1.5 * dragonblocks.settings.inventory.scale * 1.1); + this.fuelProgressDisplay.draw(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 1.5 * dragonblocks.settings.inventory.scale * 1.1); + this.fuel.draw(this.getDisplay(), 2 * dragonblocks.settings.inventory.scale * 1.1, 2.5 * dragonblocks.settings.inventory.scale * 1.1); return true; } isEmpty(){ return this.inventory.isEmpty() && ! this.fuel.item && ! this.input.item; } - parse(str){ + deserialize(str){ let obj = JSON.parse(str); - this.inventory.parse(obj.inventory); - this.input.parse(obj.input); - this.fuel.parse(obj.fuel); + this.inventory.deserialize(obj.inventory); + this.input.deserialize(obj.input); + this.fuel.deserialize(obj.fuel); } - stringify(){ + serialize(){ return JSON.stringify({ - inventory: this.inventory.stringify(), - input: this.input.stringify(), - fuel: this.fuel.stringify() + inventory: this.inventory.serialize(), + input: this.input.serialize(), + fuel: this.fuel.serializes() }); } getRecipe(){ @@ -114,7 +114,7 @@ furnace.Inventory = class extends dragonblocks.InventoryContainer{ else this.clear(); } - this.burnProgressDisplay.parse("furnace:burn_progress_" + parseInt(this.burnProgress / this.getRecipeTime() * 5)); - this.fuelProgressDisplay.parse("furnace:fuel_progress_" + (parseInt(this.fuelPower / this.fullFuelPower * 5) || 0)); + this.burnProgressDisplay.deserialize("furnace:burn_progress_" + parseInt(this.burnProgress / this.getRecipeTime() * 5)); + this.fuelProgressDisplay.deserialize("furnace:fuel_progress_" + (parseInt(this.fuelPower / this.fullFuelPower * 5) || 0)); } } diff --git a/game/furnace/itemdef.js b/game/furnace/itemdef.js index e45fc1c..c4789be 100644 --- a/game/furnace/itemdef.js +++ b/game/furnace/itemdef.js @@ -9,7 +9,7 @@ dragonblocks.registerNode({ let meta = dragonblocks.getNode(x, y).meta; meta.inventory = new furnace.Inventory(); if(meta.inventoryString) - meta.inventory.parse(meta.inventoryString); + meta.inventory.ceserialize(meta.inventoryString); }, onclick: (x, y) => { let meta = dragonblocks.getNode(x, y).meta; @@ -17,7 +17,7 @@ dragonblocks.registerNode({ dragonblocks.player.openInventory(); dragonblocks.player.onNextInventoryClose = _ => { dragonblocks.player.resetInventoryElements(); - meta.inventoryString = meta.inventory.stringify(); + meta.inventoryString = meta.inventory.serialize(); }; }, ondig: (x, y) => { diff --git a/game/plants/plants.js b/game/plants/plants.js index 288bc13..d62a33f 100644 --- a/game/plants/plants.js +++ b/game/plants/plants.js @@ -14,7 +14,7 @@ doors.registerTrapdoor({ groups: ["choppy"], hardness: 6, material: "plants_wood", -}); +}); doors.registerDoor({ name: "wood", modname: "plants", @@ -24,7 +24,7 @@ doors.registerDoor({ }); plants.registerTree({ name: "apple", - tree: dragonblocks.getPixelManipulator([ + tree: new dragonblocks.PixelManipulator([ ["leaves", "leaves", "leaves"], ["leaves", "leaves", "leaves"], ["leaves", "leaves", "leaves"], @@ -38,7 +38,7 @@ plants.registerTree({ }); plants.registerTree({ name: "pine", - tree: dragonblocks.getPixelManipulator([ + tree: new dragonblocks.PixelManipulator([ ["", "", "leaves", "", ""], ["", "", "leaves", "", ""], ["", "leaves", "leaves", "leaves", ""], @@ -56,7 +56,7 @@ plants.registerTree({ }); plants.registerTree({ name: "acacia", - tree: dragonblocks.getPixelManipulator([ + tree: new dragonblocks.PixelManipulator([ ["", "", "leaves", "leaves", "leaves", "", ""], ["leaves", "leaves", "leaves", "tree", "leaves", "leaves", "leaves"], ["leaves", "tree", "leaves", "tree", "leaves", "tree", "leaves"], @@ -71,7 +71,7 @@ plants.registerTree({ }); plants.registerTree({ name: "jungle", - tree: dragonblocks.getPixelManipulator([ + tree: new dragonblocks.PixelManipulator([ ["", "leaves", "leaves", "leaves", ""], ["leaves", "leaves", "leaves", "leaves", "leaves"], ["leaves", "leaves", "leaves", "leaves", "leaves"], @@ -85,7 +85,7 @@ plants.registerTree({ ["", "", "tree", "", ""], ["", "tree", "tree", "tree", ""], ["", "tree", "§tree", "tree", ""], - + ]), growtimeMin: 40, growtimeMax: 100, @@ -94,7 +94,7 @@ plants.registerTree({ }); plants.registerTree({ name: "aspen", - tree: dragonblocks.getPixelManipulator([ + tree: new dragonblocks.PixelManipulator([ ["leaves", "leaves", "leaves"], ["leaves", "leaves", "leaves"], ["leaves", "leaves", "leaves"], @@ -102,7 +102,7 @@ plants.registerTree({ ["", "tree", ""], ["", "tree", ""], ["", "§tree", ""], - + ]), growtimeMin: 30, growtimeMax: 40, diff --git a/game/skins/ui.js b/game/skins/ui.js index 06e3371..4ac7095 100644 --- a/game/skins/ui.js +++ b/game/skins/ui.js @@ -3,17 +3,18 @@ dragonblocks.registerChatcommand({ param: "[]", desc: "Set your skin or show the skin list", func: arg => { - if(! arg){ - for(let skin of dragonblocks.registeredSkins) - dragonblocks.chatMessage(skin.name + (skin.desc ? ": " + skin.desc : "")); - } - else{ - if(dragonblocks.skins[arg]){ + if (! arg) { + for (let skin in dragonblocks.registeredSkins) { + let def = dragonblocks.registeredSkins[skin]; + dragonblocks.chatMessage(def.name + (def.desc ? ": " + def.desc : "")); + } + } else { + if (dragonblocks.registeredSkins[arg]) { dragonblocks.player.setSkin(arg); dragonblocks.chatMessage("Skin set to " + arg + "."); - } - else + } else { dragonblocks.chatMessage("Unknown skin."); + } } } -}); +}); diff --git a/game/tnt/init.js b/game/tnt/init.js index c5f6244..3cf0031 100644 --- a/game/tnt/init.js +++ b/game/tnt/init.js @@ -1,5 +1,5 @@ tnt = {}; -tnt.explosion = dragonblocks.getPixelManipulator([ +tnt.explosion = new dragonblocks.PixelManipulator([ ["", "air", "air", "air", ""], ["air", "air", "air", "air", "air"], ["air", "air", "§air", "air", "air"], diff --git a/index.html b/index.html index 804c97f..7343787 100644 --- a/index.html +++ b/index.html @@ -6,17 +6,30 @@ + -
- -

init.js

-
-
-
+
+
+
+ +

init.js

+
+
+
+
-
-
+ + diff --git a/lib/dblib.js b/lib/dblib.js index df2189b..7c96ecc 100644 --- a/lib/dblib.js +++ b/lib/dblib.js @@ -9,10 +9,6 @@ class dblib{ parent = document.documentElement; elem.style.top = parent.clientHeight / 2 - parseInt(elem.clientHeight) / 2 + "px"; } - static remove(elem){ - if(elem) - elem.parentNode.removeChild(elem); - } static random(min, max){ return Math.floor(min + Math.random() * (max - min + 1)); } diff --git a/settings.json b/settings.json index 8be3a23..a9e75b7 100644 --- a/settings.json +++ b/settings.json @@ -1,12 +1,4 @@ { - "version": { - "major": 3, - "minor": 1, - "patch": 0, - "development": true, - "commit": "?", - "copyright": "© 2019 - 2021 Elidragon. Please Distribute!" - }, "inventory": { "scale": 50 }, diff --git a/style.css b/style.css index f31e21d..a27cfb3 100644 --- a/style.css +++ b/style.css @@ -1,3 +1,3 @@ @font-face {font-family: Ubuntu; src: url(fonts/Ubuntu.ttf);} -*{font-family: Ubuntu; scrollbar-width: none; -ms-overflow-style: none;} +* {font-family: Ubuntu; scrollbar-width: none; -ms-overflow-style: none;} ::-webkit-scrollbar {width: 0px;} diff --git a/version.json b/version.json new file mode 100644 index 0000000..293e898 --- /dev/null +++ b/version.json @@ -0,0 +1,8 @@ +{ + "major": 3, + "minor": 1, + "patch": 0, + "development": true, + "repo": "https://github.com/EliasFleckenstein03/dragonblocks", + "copyright": "© 2019 - 2021 Elidragon. Feel free to Distribute!" +} -- 2.44.0