From 838f4f135fee4fb43401e0e3905f57126d76b1a3 Mon Sep 17 00:00:00 2001 From: Milan2018 Date: Sat, 15 May 2021 22:34:12 +0200 Subject: [PATCH] update --- xdecor/.gitignore | 22 + xdecor/.luacheckrc | 6 +- xdecor/LICENSE | 16 +- xdecor/README.md | 16 +- xdecor/depends.txt | 8 - xdecor/description.txt | 1 - xdecor/handlers/animations.lua | 29 +- xdecor/handlers/helpers.lua | 19 +- xdecor/handlers/nodeboxes.lua | 33 +- xdecor/handlers/registration.lua | 42 +- xdecor/init.lua | 34 +- xdecor/locale/template.txt | 154 ++++ xdecor/locale/xdecor.de.tr | 152 ++++ xdecor/locale/xdecor.fr.tr | 154 ++++ xdecor/locale/xdecor.it.tr | 154 ++++ xdecor/mod.conf | 4 + xdecor/src/alias.lua | 1 - xdecor/src/chess.lua | 758 +++++++++++++++++--- xdecor/src/cooking.lua | 102 ++- xdecor/src/enchanting.lua | 156 ++-- xdecor/src/hive.lua | 49 +- xdecor/src/itemframe.lua | 51 +- xdecor/src/mailbox.lua | 92 ++- xdecor/src/mechanisms.lua | 49 +- xdecor/src/nodes.lua | 493 ++++++++----- xdecor/src/recipes.lua | 56 +- xdecor/src/rope.lua | 15 +- xdecor/src/workbench.lua | 243 ++++--- xdecor/textures/gui_arrow.png | Bin 0 -> 469 bytes xdecor/textures/xdecor_candle_hanging.png | Bin 0 -> 15657 bytes xdecor/textures/xdecor_radio_back.png | Bin 0 -> 1184 bytes xdecor/textures/xdecor_radio_front.png | Bin 0 -> 1208 bytes xdecor/textures/xdecor_radio_side.png | Bin 0 -> 15650 bytes xdecor/textures/xdecor_radio_top.png | Bin 0 -> 1214 bytes xdecor/textures/xdecor_rooster.png | Bin 0 -> 1322 bytes xdecor/textures/xdecor_speaker_back.png | Bin 0 -> 1172 bytes xdecor/textures/xdecor_speaker_front.png | Bin 0 -> 1239 bytes xdecor/textures/xdecor_speaker_side.png | Bin 0 -> 1172 bytes xdecor/textures/xdecor_speaker_top.png | Bin 0 -> 1187 bytes xdecor/textures/xdecor_wooden2_lightbox.png | Bin 0 -> 15686 bytes 40 files changed, 2246 insertions(+), 663 deletions(-) create mode 100644 xdecor/.gitignore delete mode 100644 xdecor/depends.txt delete mode 100644 xdecor/description.txt create mode 100644 xdecor/locale/template.txt create mode 100644 xdecor/locale/xdecor.de.tr create mode 100644 xdecor/locale/xdecor.fr.tr create mode 100644 xdecor/locale/xdecor.it.tr delete mode 100644 xdecor/src/alias.lua create mode 100644 xdecor/textures/gui_arrow.png create mode 100644 xdecor/textures/xdecor_candle_hanging.png create mode 100644 xdecor/textures/xdecor_radio_back.png create mode 100644 xdecor/textures/xdecor_radio_front.png create mode 100644 xdecor/textures/xdecor_radio_side.png create mode 100644 xdecor/textures/xdecor_radio_top.png create mode 100644 xdecor/textures/xdecor_rooster.png create mode 100644 xdecor/textures/xdecor_speaker_back.png create mode 100644 xdecor/textures/xdecor_speaker_front.png create mode 100644 xdecor/textures/xdecor_speaker_side.png create mode 100644 xdecor/textures/xdecor_speaker_top.png create mode 100644 xdecor/textures/xdecor_wooden2_lightbox.png diff --git a/xdecor/.gitignore b/xdecor/.gitignore new file mode 100644 index 0000000..ef02689 --- /dev/null +++ b/xdecor/.gitignore @@ -0,0 +1,22 @@ +## Files related to minetest development cycle +/*.patch +# GNU Patch reject file +*.rej + +## Editors and Development environments +*~ +*.swp +*.bak* +*.orig +# Vim +*.vim +# Kate +.*.kate-swp +.swp.* +# Eclipse (LDT) +.project +.settings/ +.buildpath +.metadata +# Idea IDE +.idea/* diff --git a/xdecor/.luacheckrc b/xdecor/.luacheckrc index 718790b..8cdd8c3 100644 --- a/xdecor/.luacheckrc +++ b/xdecor/.luacheckrc @@ -1,4 +1,3 @@ -unused_args = false allow_defined_top = true read_globals = { @@ -7,6 +6,9 @@ read_globals = { "default", "stairs", "doors", "xpanes", "xdecor", "xbg", - table = { fields = { "copy" } }, + table = {fields = {"copy"}}, + string = {fields = {"split"}}, "unpack", + "stairsplus", + "mesecon" } diff --git a/xdecor/LICENSE b/xdecor/LICENSE index 8b744c6..a026df4 100644 --- a/xdecor/LICENSE +++ b/xdecor/LICENSE @@ -1,15 +1,17 @@ ┌──────────────────────────────────────────────────────────────────────┐ │ Copyright (c) 2015-2017 kilbith │ -│ │ -│ Code: BSD │ -│ Textures: WTFPL (credits: Gambit, kilbith, Cisoun) │ -│ Sounds: │ +│ │ +│ Code: BSD │ +│ Textures: WTFPL (credits: Gambit, kilbith, Cisoun) │ +│ Textures (radio, speaker, hanging candle, rooster) by │ + gigomaf (CC BY-NC 3.0) │ +│ Sounds: │ │ - xdecor_boiling_water.ogg - by Audionautics - CC BY-SA │ -│ freesound.org/people/Audionautics/sounds/133901/ │ +│ freesound.org/people/Audionautics/sounds/133901/ │ │ - xdecor_enchanting.ogg - by Timbre - CC BY-SA-NC │ │ freesound.org/people/Timbre/sounds/221683/ │ -│ - xdecor_bouncy.ogg - by Blender Foundation - CC BY 3.0 │ -│ opengameart.org/content/funny-comic-cartoon-bounce-sound │ +│ - xdecor_bouncy.ogg - by Blender Foundation - CC BY 3.0 │ +│ opengameart.org/content/funny-comic-cartoon-bounce-sound │ └──────────────────────────────────────────────────────────────────────┘ diff --git a/xdecor/README.md b/xdecor/README.md index 187df11..05340a2 100644 --- a/xdecor/README.md +++ b/xdecor/README.md @@ -1,13 +1,17 @@ ## X-Decor ## -##### A decoration mod meant to be simple and well-featured. ##### -##### It adds a bunch of cute cubes, various mechanisms and stuff for [cutting](https://forum.minetest.net/viewtopic.php?f=11&t=14085), [enchanting](https://forum.minetest.net/viewtopic.php?f=11&t=14087), cooking, etc. ##### -##### This mod is a lightweight alternative to Home Decor and More Blocks all together. ##### +[![ContentDB](https://content.minetest.net/packages/jp/xdecor/shields/downloads/)](https://content.minetest.net/packages/jp/xdecor/) + +A decoration mod meant to be simple and well-featured. +It adds a bunch of cute cubes, various mechanisms and stuff for [cutting](https://forum.minetest.net/viewtopic.php?f=11&t=14085), [enchanting](https://forum.minetest.net/viewtopic.php?f=11&t=14087), cooking, etc. +This mod is a lightweight alternative to HomeDecor and MoreBlocks. + +### Requirements ### +This mod requires at least version 5.1 of Minetest. ### Credits ### -##### Special thanks to Gambit for the textures from the PixelBOX pack for Minetest. ##### - -##### Thanks to all contributors that keep this mod alive. ##### +Special thanks to Gambit for the textures from the PixelBOX pack for Minetest. +Thanks to all contributors who keep this mod alive. ![Preview](http://i.imgur.com/AVoyCQy.png) diff --git a/xdecor/depends.txt b/xdecor/depends.txt deleted file mode 100644 index 49669a2..0000000 --- a/xdecor/depends.txt +++ /dev/null @@ -1,8 +0,0 @@ -default -bucket -doors -stairs -xpanes -fire? -oresplus? -moreblocks? \ No newline at end of file diff --git a/xdecor/description.txt b/xdecor/description.txt deleted file mode 100644 index d338743..0000000 --- a/xdecor/description.txt +++ /dev/null @@ -1 +0,0 @@ -A decoration mod meant to be simple and well-featured. diff --git a/xdecor/handlers/animations.lua b/xdecor/handlers/animations.lua index 6cfb098..2849667 100644 --- a/xdecor/handlers/animations.lua +++ b/xdecor/handlers/animations.lua @@ -18,25 +18,30 @@ function xdecor.sit(pos, node, clicker, pointed_thing) if default.player_attached[player_name] then pos.y = pos.y - 0.5 - clicker:setpos(pos) - clicker:set_eye_offset({x=0, y=0, z=0}, {x=0, y=0, z=0}) - clicker:set_physics_override(1, 1, 1) + clicker:set_pos(pos) + clicker:set_eye_offset(vector.new(), vector.new()) + clicker:set_physics_override({speed = 1, jump = 1, gravity = 1}) default.player_attached[player_name] = false default.player_set_animation(clicker, "stand", 30) elseif not default.player_attached[player_name] and node.param2 <= 3 and - not ctrl.sneak and vector.equals(vel, {x=0,y=0,z=0}) then + not ctrl.sneak and vector.equals(vel, vector.new()) then - clicker:set_eye_offset({x=0, y=-7, z=2}, {x=0, y=0, z=0}) - clicker:set_physics_override(0, 0, 0) - clicker:setpos(pos) + clicker:set_eye_offset({x = 0, y = -7, z = 2}, vector.new()) + clicker:set_physics_override({speed = 0, jump = 0, gravity = 1}) + clicker:set_pos(pos) default.player_attached[player_name] = true default.player_set_animation(clicker, "sit", 30) - if node.param2 == 0 then clicker:set_look_yaw(3.15) - elseif node.param2 == 1 then clicker:set_look_yaw(7.9) - elseif node.param2 == 2 then clicker:set_look_yaw(6.28) - elseif node.param2 == 3 then clicker:set_look_yaw(4.75) end + if node.param2 == 0 then + clicker:set_look_yaw(3.15) + elseif node.param2 == 1 then + clicker:set_look_yaw(7.9) + elseif node.param2 == 2 then + clicker:set_look_yaw(6.28) + elseif node.param2 == 3 then + clicker:set_look_yaw(4.75) + end end end @@ -47,6 +52,6 @@ function xdecor.sit_dig(pos, digger) return false end end + return true end - diff --git a/xdecor/handlers/helpers.lua b/xdecor/handlers/helpers.lua index cbb9113..dc14b24 100644 --- a/xdecor/handlers/helpers.lua +++ b/xdecor/handlers/helpers.lua @@ -2,21 +2,31 @@ function xdecor.maxn(T) local n = 0 for k in pairs(T) do - if k > n then n = k end + if k > n then + n = k + end end + return n end -- Returns the length of an hash table. function xdecor.tablelen(T) local n = 0 - for _ in pairs(T) do n = n + 1 end + + for _ in pairs(T) do + n = n + 1 + end + return n end -- Deep copy of a table. Borrowed from mesecons mod (https://github.com/Jeija/minetest-mod-mesecons). function xdecor.tablecopy(T) - if type(T) ~= "table" then return T end -- No need to copy. + if type(T) ~= "table" then + return T -- No need to copy. + end + local new = {} for k, v in pairs(T) do @@ -26,6 +36,7 @@ function xdecor.tablecopy(T) new[k] = v end end + return new end @@ -41,7 +52,7 @@ function xdecor.stairs_valid_def(def) not (def.groups.not_cuttable == 1) and not def.groups.wool and (def.tiles and type(def.tiles[1]) == "string" and not - def.tiles[1]:find("default_mineral")) and + def.tiles[1]:find("default_mineral")) and not def.mesecons and def.description and def.description ~= "" and diff --git a/xdecor/handlers/nodeboxes.lua b/xdecor/handlers/nodeboxes.lua index 63da57e..4a3d8ca 100644 --- a/xdecor/handlers/nodeboxes.lua +++ b/xdecor/handlers/nodeboxes.lua @@ -1,7 +1,13 @@ xdecor.box = { slab_y = function(height, shift) - return {-0.5, -0.5 + (shift or 0), -0.5, 0.5, -0.5 + height + - (shift or 0), 0.5} + return { + -0.5, + -0.5 + (shift or 0), + -0.5, + 0.5, + -0.5 + height + (shift or 0), + 0.5 + } end, slab_z = function(depth) return {-0.5, -0.5, -0.5 + depth, 0.5, 0.5, 0.5} @@ -15,16 +21,18 @@ xdecor.box = { } xdecor.nodebox = { - regular = {type="regular"}, - null = {type="fixed", fixed={0,0,0,0,0,0}} + regular = {type = "regular"}, + null = { + type = "fixed", fixed = {0,0,0,0,0,0} + } } xdecor.pixelbox = function(size, boxes) local fixed = {} - for _, box in pairs(boxes) do + for _, box in ipairs(boxes) do -- `unpack` has been changed to `table.unpack` in newest Lua versions. local x, y, z, w, h, l = unpack(box) - fixed[#fixed+1] = { + fixed[#fixed + 1] = { (x / size) - 0.5, (y / size) - 0.5, (z / size) - 0.5, @@ -33,26 +41,27 @@ xdecor.pixelbox = function(size, boxes) ((z + l) / size) - 0.5 } end - return {type="fixed", fixed=fixed} + + return {type = "fixed", fixed = fixed} end local mt = {} + mt.__index = function(table, key) local ref = xdecor.box[key] local ref_type = type(ref) if ref_type == "function" then return function(...) - return {type="fixed", fixed=ref(...)} + return {type = "fixed", fixed = ref(...)} end elseif ref_type == "table" then - return {type="fixed", fixed=ref} + return {type = "fixed", fixed = ref} elseif ref_type == "nil" then - error(key.."could not be found among nodebox presets and functions") + error(key .. "could not be found among nodebox presets and functions") end - error("unexpected datatype "..tostring(type(ref)).." while looking for "..key) + error("unexpected datatype " .. tostring(type(ref)) .. " while looking for " .. key) end setmetatable(xdecor.nodebox, mt) - diff --git a/xdecor/handlers/registration.lua b/xdecor/handlers/registration.lua index cbeabdb..b16dc4b 100644 --- a/xdecor/handlers/registration.lua +++ b/xdecor/handlers/registration.lua @@ -1,4 +1,4 @@ -xbg = default.gui_bg..default.gui_bg_img..default.gui_slots +xbg = default.gui_bg .. default.gui_bg_img .. default.gui_slots local default_inventory_size = 32 local default_inventory_formspecs = { @@ -6,30 +6,30 @@ local default_inventory_formspecs = { list[context;main;0,0;8,1;] list[current_player;main;0,2;8,4;] listring[current_player;main] - listring[context;main] ]] - ..default.get_hotbar_bg(0,2), + listring[context;main] ]] .. + default.get_hotbar_bg(0,2), ["16"] = [[ size[8,7] list[context;main;0,0;8,2;] list[current_player;main;0,3;8,4;] listring[current_player;main] - listring[context;main] ]] - ..default.get_hotbar_bg(0,3), + listring[context;main] ]] .. + default.get_hotbar_bg(0,3), ["24"] = [[ size[8,8] list[context;main;0,0;8,3;] list[current_player;main;0,4;8,4;] listring[current_player;main] - listring[context;main]" ]] - ..default.get_hotbar_bg(0,4), + listring[context;main]" ]] .. + default.get_hotbar_bg(0,4), ["32"] = [[ size[8,9] list[context;main;0,0.3;8,4;] list[current_player;main;0,4.85;8,1;] list[current_player;main;0,6.08;8,3;8] listring[current_player;main] - listring[context;main] ]] - ..default.get_hotbar_bg(0,4.85) + listring[context;main] ]] .. + default.get_hotbar_bg(0,4.85) } local function get_formspec_by_size(size) @@ -42,13 +42,13 @@ local default_can_dig = function(pos) return inv:is_empty("main") end -function xdecor.register(name, def) - local function xdecor_stairs_alternative(nodename, def) +local function xdecor_stairs_alternative(nodename, def) local mod, name = nodename:match("(.*):(.*)") + for groupname, value in pairs(def.groups) do if groupname ~= "cracky" and groupname ~= "choppy" and groupname ~= "flammable" and groupname ~= "crumbly" and - groupname ~= "snappy" then + groupname ~= "snappy" then def.groups.groupname = nil end end @@ -65,17 +65,18 @@ function xdecor.register(name, def) sounds = def.sounds, } ) - elseif minetest.get_modpath("stairs") then + elseif minetest.get_modpath("stairs") then stairs.register_stair_and_slab(name,nodename, def.groups, def.tiles, ("%s Stair"):format(def.description), ("%s Slab"):format(def.description), def.sounds - ) - end + ) + end end +function xdecor.register(name, def) def.drawtype = def.drawtype or (def.mesh and "mesh") or (def.node_box and "nodebox") def.sounds = def.sounds or default.node_sound_defaults() @@ -108,11 +109,14 @@ function xdecor.register(name, def) local size = inventory.size or default_inventory_size local inv = meta:get_inventory() + inv:set_size("main", size) - meta:set_string("formspec", (inventory.formspec or - get_formspec_by_size(size))..xbg) + meta:set_string("formspec", + (inventory.formspec or get_formspec_by_size(size)) .. xbg) end + def.can_dig = def.can_dig or default_can_dig + elseif infotext and not def.on_construct then def.on_construct = function(pos) local meta = minetest.get_meta(pos) @@ -120,12 +124,12 @@ function xdecor.register(name, def) end end - minetest.register_node("xdecor:"..name, def) + minetest.register_node("xdecor:" .. name, def) local workbench = minetest.settings:get_bool("enable_xdecor_workbench") if workbench == false and - (minetest.get_modpath("moreblocks") or minetest.get_modpath("stairs")) then + (minetest.get_modpath("moreblocks") or minetest.get_modpath("stairs")) then if xdecor.stairs_valid_def(def) then xdecor_stairs_alternative("xdecor:"..name, def) end diff --git a/xdecor/init.lua b/xdecor/init.lua index 6509446..1399a1c 100644 --- a/xdecor/init.lua +++ b/xdecor/init.lua @@ -1,29 +1,15 @@ --local t = os.clock() -local mver_major, mver_minor, mver_patch = 0, 4, 16 -- Minetest 0.4.16 minimum. - -local client_version = minetest.get_version().string -local major, minor, patch = client_version:match("(%d+).(%d+).(%d+)") - -if (major and minor and patch) and - ((tonumber(major) < mver_major) or - (mver_major == tonumber(major) and tonumber(minor) < mver_minor) or - (mver_minor == tonumber(minor) and tonumber(patch) < mver_patch)) then - minetest.log("error", "[xdecor] Your Minetest client is too old to run this mod. Disabling.") - return -end - xdecor = {} local modpath = minetest.get_modpath("xdecor") -dofile(modpath.."/handlers/animations.lua") -dofile(modpath.."/handlers/helpers.lua") -dofile(modpath.."/handlers/nodeboxes.lua") -dofile(modpath.."/handlers/registration.lua") +dofile(modpath .. "/handlers/animations.lua") +dofile(modpath .. "/handlers/helpers.lua") +dofile(modpath .. "/handlers/nodeboxes.lua") +dofile(modpath .. "/handlers/registration.lua") -dofile(modpath.."/src/alias.lua") -dofile(modpath.."/src/nodes.lua") -dofile(modpath.."/src/recipes.lua") +dofile(modpath .. "/src/nodes.lua") +dofile(modpath .. "/src/recipes.lua") local subpart = { "chess", @@ -34,13 +20,13 @@ local subpart = { "mailbox", "mechanisms", "rope", - "workbench" + "workbench", } -for _, name in pairs(subpart) do - local enable = minetest.settings:get_bool("enable_xdecor_"..name) +for _, name in ipairs(subpart) do + local enable = minetest.settings:get_bool("enable_xdecor_" .. name) if enable or enable == nil then - dofile(modpath.."/src/"..name..".lua") + dofile(modpath .. "/src/" .. name .. ".lua") end end diff --git a/xdecor/locale/template.txt b/xdecor/locale/template.txt new file mode 100644 index 0000000..17e37b4 --- /dev/null +++ b/xdecor/locale/template.txt @@ -0,0 +1,154 @@ +# textdomain: xdecor + + +### chess.lua ### + +Black Bishop= +Black King= +Black Knight= +Black Pawn= +Black Queen= +Black Rook= +Chess= +Chess Board= +Dumb AI= +Multiplayer= +New game= +Select a mode:= +Singleplayer= +Someone else plays black pieces!= +Someone else plays white pieces!= +White Bishop= +White King= +White Knight= +White Pawn= +White Queen= +White Rook= + +You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1= + +You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1= + +check= + +### cooking.lua ### + +Bowl= +Bowl of soup= +Cauldron= +Cauldron (active) - Drop foods inside to make a soup= +Cauldron (active) - Use a bowl to eat the soup= +Cauldron (empty)= +Cauldron (idle)= +No room in your inventory to add a bowl of soup.= +No room in your inventory to add a bucket of water.= + +### enchanting.lua ### + +Axe= +Bronze= +Diamond= +Durability= +Efficiency= +Enchanted @1 @2 @3= +Enchantment Table= +Mese= +Pickaxe= +Sharpness= +Shovel= +Steel= +Sword= +Your tool digs faster= +Your tool last longer= +Your weapon inflicts more damages= + +### hive.lua ### + +Artificial Hive= +Bees are busy making honey…= +Honey= + +### itemframe.lua ### + +@1 (owned by @2)= +Item Frame= + +### mailbox.lua ### + +@1's Mailbox= +Last donators= +Mailbox= +Send your goods to@n@1= +The mailbox is full.= + +### mechanisms.lua ### + +Lever= +Stone Pressure Plate= +Wooden Pressure Plate= + +### nodes.lua ### + +Bamboo Frame= +Baricade= +Barrel= +Cactus Brick= +Candle= +Chainlink= +Chair= +Coal Stone Tile= +Cobweb= +Cushion= +Cushion Block= +Desert Stone Tile= +Empty Shelf= +Ender Chest= +Garden Stone Path= +Half Wooden Cabinet= +Hardened Clay= +Iron Light Box= +Ivy= +Japanese Door= +Lantern= +Moon Brick= +Multi Shelf= +Packed Ice= +Painting= +Potted Geranium= +Potted Rose= +Potted Tulip= +Potted Viola= +Potted White Dandelion= +Potted Yellow Dandelion= +Prison Door= +Red Curtain= +Runestone= +Rusty Iron Bars= +Rusty Prison Door= +Screen Door= +Slide Door= +Stone Tile= +Table= +Tatami= +Television= +Trampoline= +Wood Frame= +Wood Framed Glass= +Wooden Cabinet= +Wooden Light Box= +Wooden Tile= +Woodglass Door= + +### rope.lua ### + +Rope= + +### workbench.lua ### + +Back= +Crafting= +Cut= +Hammer= +Repair= +Storage= +Work Bench= diff --git a/xdecor/locale/xdecor.de.tr b/xdecor/locale/xdecor.de.tr new file mode 100644 index 0000000..4188623 --- /dev/null +++ b/xdecor/locale/xdecor.de.tr @@ -0,0 +1,152 @@ +# textdomain: xdecor + + +### chess.lua ### + +Black Bishop=schwarzer Läufer +Black King=schwarter König +Black Knight=schwarzes Pferd +Black Pawn=schwarzer Bauer +Black Queen=schwarze Dame +Black Rook=schwarzer Turm +Chess=Schach +Chess Board=Schachbrett +Dumb AI=dumme KI +Multiplayer=Mehrspieler +New game=neues Spiel +Select a mode:=Wähle einen Modus: +Singleplayer=Einzelspieler +Someone else plays black pieces!=Jemand anderes spielt Schwarz! +Someone else plays white pieces!=Jemand anderes spielt Weiß! +White Bishop=weißer Läufer +White King=weißer König +White Knight=weißes Pferd +White Pawn=weißer Bauer +White Queen=weiße Dame +White Rook=weißer Turm +You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1=Das Schachbrett ist während eines Schachspieles nicht abbaubar. Setze das Spiel zurück, falls du ein Mitspieler bist oder versuche es in @1 erneut. +You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1=Das Schachbrett kann nicht zurückgesetzt werden, da ein Spiel im Gang ist. Versuche es in @1 erneut, falls du kein Mitspieler bist. + +check=Schach + +### cooking.lua ### + +Bowl=Schüssel +Bowl of soup=Suppenschüssel +Cauldron=Kessel +Cauldron (active) - Drop foods inside to make a soup=Kessel (aktiv) - Nahrungsmittel einwerfen, um Suppe zu machen. +Cauldron (active) - Use a bowl to eat the soup=Kessel (aktiv) - Benutze eine Schüssel, um die Suppe zu essen +Cauldron (empty)=Kessel (leer) +Cauldron (idle)=Kessel (untätig) +No room in your inventory to add a bowl of soup.=Zu wenig Platz im Inventar für eine Schüssel voll Suppe. +No room in your inventory to add a bucket of water.=Zu wenig Platz im Inventar für einen Eimer Wasser. + +### enchanting.lua ### + +Axe=axt +Bronze=Bronze +Diamond=Diamant +Durability=Haltbarkeit +Efficiency=Effizienz +Enchanted @1 @2 @3=verzauberte(s) @1@2 @3 +Enchantment Table=Zaubertisch +Mese=Mese +Pickaxe=Spitzhacke +Sharpness=Schärfe +Shovel=Schaufel +Steel=Eisen +Sword=Schwert +Your tool digs faster=Dein Werkzeug arbeitet schneller +Your tool last longer=Dein Werkzeug hält länger +Your weapon inflicts more damages=Deine Waffe erzeugt mehr Schaden + +### hive.lua ### + +Artificial Hive=künstlicher Bienenstock +Bees are busy making honey…=Bienen sind beschäftigt, Honig herzustellen. +Honey=Honig + +### itemframe.lua ### + +@1 (owned by @2)=@1 (gehört @2) +Item Frame=Objektrahmen + +### mailbox.lua ### + +@1's Mailbox=Briefkasten von @1 +Last donators=letzte Spender +Mailbox=Briefkasten +Send your goods to@n@1=Sende deine Waren an@n@1 +The mailbox is full.=Der Briefkasten ist voll. + +### mechanisms.lua ### + +Lever=Schalthebel +Stone Pressure Plate=steinerne Druckplatte +Wooden Pressure Plate=hölzerne Druckplatte + +### nodes.lua ### + +Bamboo Frame=Bambusgerüst +Baricade=Barrikade +Barrel=Fass +Cactus Brick=Kaktusstein +Candle=Kerze +Chainlink=Kettenvorhang +Chair=einfacher Stuhl +Coal Stone Tile=Kohle-Stein-Block +Cobweb=Spinnenwebe +Cushion=Sitzkissen +Cushion Block=Sitzkissenblock +Desert Stone Tile=Wüstensteinblock +Empty Shelf=leeres Regal +Ender Chest=Endertruhe +Garden Stone Path=Steingartenweg +Half Wooden Cabinet=halber Holzschrank +Hardened Clay=gehärteter Ton +Iron Light Box=eiseneingefasster Lichtblock +Ivy=Efeu +Japanese Door=japanische Tür +Lantern=Laterne +Moon Brick=Naturziegelwand +Multi Shelf=Mehrzweckregal +Packed Ice=Packeis +Painting=Gemälde +Potted Geranium=Geranien im Topf +Potted Rose=Rosen im Topf +Potted Tulip=Tulpen im Topf +Potted Viola=Veilchen im Topf +Potted White Dandelion=weißer Löwenzahn im Topf +Potted Yellow Dandelion=gelber Löwenzahn im Topf +Prison Door=Verliestür +Red Curtain=roter Vorhang +Runestone=Runensteinblock +Rusty Iron Bars=rostige Eisenstäbe +Rusty Prison Door=rostige Verliestür +Screen Door=französische Glastür +Slide Door=Schiebetür +Stone Tile=steinerner Block +Table=einfacher Tisch +Tatami=Tatamimatte +Television=Fernseher +Trampoline=Trampolin +Wood Frame=hölzerner Zierrahmen +Wood Framed Glass=holzeingefasstes Glas +Wooden Cabinet=Holzschrank +Wooden Light Box=holzeingefasster Lichtblock +Wooden Tile=hölzerner Dekorblock +Woodglass Door=Tür mit Lichtausschnitt + +### rope.lua ### + +Rope=Seil + +### workbench.lua ### + +Back=Zurück +Crafting=Fertigung +Cut=Zuschnitt +Hammer=Hämmerchen +Repair=Reparatur +Storage=Aufbewahrung +Work Bench=Werkbank diff --git a/xdecor/locale/xdecor.fr.tr b/xdecor/locale/xdecor.fr.tr new file mode 100644 index 0000000..51b3eea --- /dev/null +++ b/xdecor/locale/xdecor.fr.tr @@ -0,0 +1,154 @@ +# textdomain: xdecor + + +### chess.lua ### + +Black Bishop=Fou noir +Black King=Roi noir +Black Knight=Cavalier noir +Black Pawn=Pion noir +Black Queen=Reine noire +Black Rook=Tour noire +Chess=Echecs +Chess Board=Echiquier +Dumb AI=IA stupide +Multiplayer=Multijoueur +New game=Nouvelle partie +Select a mode:=Sélectionnez un mode de jeu: +Singleplayer=Solo +Someone else plays black pieces!=Quelqu’un d’autre joue les pièces noires ! +Someone else plays white pieces!=Quelqu’un d’autre joue les pièces blanches ! +White Bishop=Fou blanc +White King=Roi blanc +White Knight=Cavalier blanc +White Pawn=Pion blanc +White Queen=Reine blanche +White Rook=Tour blanche + +You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1=Vous ne pouvez pas récupérer l’échiquier, une partie à été commencée. Remettez le à zéro si vous c’est votre tour de jouer, ou réessayez dans @1 + +You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1=Vous ne pouvez pas mettre à zéro l’échiquier, une partie a été commencée. Si ce n’est pas votre tour de jouer, réessayez dans @1 + +check=échec + +### cooking.lua ### + +Bowl=Bol +Bowl of soup=Bol de soupe +Cauldron=Chaudron +Cauldron (active) - Drop foods inside to make a soup=Chaudron (actif) - Placez des ingrédients à l’intérieur pour faire une soupe +Cauldron (active) - Use a bowl to eat the soup=Chaudron (actif) - Utilisez un bol pour boire la soupe +Cauldron (empty)=Chaudron (vide) +Cauldron (idle)=Chaudron (inactif) +No room in your inventory to add a bowl of soup.=Pas de place dans votre inventaire pour ajouter un bol de soupe. +No room in your inventory to add a bucket of water.=Pas de place dans votre inventaire pour ajouter un seau d’eau. + +### enchanting.lua ### + +Axe=Hache +Bronze=Bronze +Diamond=Diamant +Durability=Durabilité +Efficiency=Efficacité +Enchanted @1 @2 @3=@2 en @1 enchantée @3 +Enchantment Table=Table d’enchantements +Mese=Mese +Pickaxe=Pioche +Sharpness=Tranchant +Shovel=Pelle +Steel=Fer +Sword=Épée +Your tool digs faster=Votre outil creuse plus vite +Your tool last longer=Votre outil dure plus longtemps +Your weapon inflicts more damages=Votre arme inflige plus de dégâts + +### hive.lua ### + +Artificial Hive=Ruche artificielle +Bees are busy making honey…=Les abeilles sont occupées à fabriquer du miel… +Honey=Miel + +### itemframe.lua ### + +@1 (owned by @2)=@1 (propriété de @2) +Item Frame=Cadre + +### mailbox.lua ### + +@1's Mailbox=Boite aux lettres de @1 +Last donators=Derniers donateurs +Mailbox=Boite aux lettres +Send your goods to@n@1=Envoyer vos biens à@n@1 +The mailbox is full.=La boite aux lettres est pleine. + +### mechanisms.lua ### + +Lever=Levier +Stone Pressure Plate=Plaque de pression en pierre +Wooden Pressure Plate=Plaque de pression en bois + +### nodes.lua ### + +Bamboo Frame=Cadre en bambou +Baricade=Barricade +Barrel=Tonneau +Cactus Brick=Brique en cactus +Candle=Bougie +Chainlink=Maillon de chaîne +Chair=Chaise +Coal Stone Tile=Carreau en charbon et pierre +Cobweb=Toile d’araignée +Cushion=Coussin +Cushion Block=Bloc de coussin +Desert Stone Tile=Carreau en pierre du désert +Empty Shelf=Étagère vide +Ender Chest=Coffre de l’End +Garden Stone Path=Chemin de pierres de jardin +Half Wooden Cabinet=Demi meuble en bois +Hardened Clay=Argile durcie +Iron Light Box=Boite lumineuse en fer +Ivy=Lierre +Japanese Door=Porte japonaise +Lantern=Lanterne +Moon Brick=Brique lunaire +Multi Shelf=Étagères multiple +Packed Ice=Glace compactée +Painting=Tableau +Potted Geranium=Géranium en pot +Potted Rose=Rose en pot +Potted Tulip=Tulipe en pot +Potted Viola=Violette en pot +Potted White Dandelion=Pissenlit blanc en pot +Potted Yellow Dandelion=Pissenlit jaune en pot +Prison Door=Porte de prison +Red Curtain=Rideaux rouge +Runestone=Pierre runique +Rusty Iron Bars=Barreaux en fer rouillé +Rusty Prison Door=Barreaux de prison rouillés +Screen Door=Porte avec moustiquaire +Slide Door=Porte coulissante +Stone Tile=Carreau en pierre +Table=Table +Tatami=Tatami +Television=Télévision +Trampoline=Trampoline +Wood Frame=Cadre en bois +Wood Framed Glass=Verre encadré par du bois +Wooden Cabinet=Meuble en bois +Wooden Light Box=Boite lumineuse en bois +Wooden Tile=Carreau en bois +Woodglass Door=Porte vitrée + +### rope.lua ### + +Rope=Corde + +### workbench.lua ### + +Back=Retour +Crafting=Fabrication +Cut=Couper +Hammer=Marteau +Repair=Réparer +Storage=Stockage +Work Bench=Atelier diff --git a/xdecor/locale/xdecor.it.tr b/xdecor/locale/xdecor.it.tr new file mode 100644 index 0000000..4007620 --- /dev/null +++ b/xdecor/locale/xdecor.it.tr @@ -0,0 +1,154 @@ +# textdomain: xdecor +# Author: Salvo 'LtWorf' Tomaselli + +### chess.lua ### + +Black Bishop=Alfiere nero +Black King=Re nero +Black Knight=Cavallo nero +Black Pawn=Pedone nero +Black Queen=Regina nera +Black Rook=Torre nera +Chess=Scacchi +Chess Board=Scacchiera +Dumb AI=AI stupida +Multiplayer=Multigiocatore +New game=Nuova partita +Select a mode:=Selezionare una modalità +Singleplayer=Singolo giocatore +Someone else plays black pieces!=Qualcun altro gioca con il nero! +Someone else plays white pieces!=Qualcun altro gioca con il bianco! +White Bishop=Alfiere bianco +White King=Re bianco +White Knight=Cavallo bianco +White Pawn=Pedone bianco +White Queen=Regina bianca +White Rook=Torre bianca + +You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1=Non si può scavare la scacchiera, una partita è in corso. Resettarla se si è uno dei giocatori, o riprovare in @1 + +You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1=Non si può resettare la partita, un gioco è in corso. Se non si è uno dei giocatori, riprovare in @1 + +check=scacco + +### cooking.lua ### + +Bowl=Ciotola +Bowl of soup=Ciotola di zuppa +Cauldron=Calderone +Cauldron (active) - Drop foods inside to make a soup=Calderone (attivo) - Mettere gli ingredienti all'interno per fare una zuppa. +Cauldron (active) - Use a bowl to eat the soup=Calderone (actif) - Utilizzare una ciotola per mangiare la zuppa +Cauldron (empty)=Calderone (vuoto) +Cauldron (idle)=Calderone (inattivo) +No room in your inventory to add a bowl of soup.=Non c'è spazio nell'inventario per aggiungere una ciotola di zuppa. +No room in your inventory to add a bucket of water.=Non c'è spazio nell'inventario per aggiungere un secchio di acqua. + +### enchanting.lua ### + +Axe=Ascia +Bronze=Bronzo +Diamond=Diamante +Durability=Durabilità +Efficiency=Efficacia +Enchanted @1 @2 @3=@2 su @1 incantesimo @3 +Enchantment Table=Tavolo per migliorie +Mese=Mese +Pickaxe=Piccone +Sharpness=Affilatezza +Shovel=Pala +Steel=Acciaio +Sword=Spada +Your tool digs faster=Il tuo utensile scava più rapidamente +Your tool last longer=Il tuo utensile dura di più +Your weapon inflicts more damages=La tua arma infligge più danno + +### hive.lua ### + +Artificial Hive=Favo artificiale +Bees are busy making honey…=Le api sono occupate a fare il miele… +Honey=Miele + +### itemframe.lua ### + +@1 (owned by @2)=@1 (proprietà di @2) +Item Frame=Teca + +### mailbox.lua ### + +@1's Mailbox=Cassetta delle lettere di @1 +Last donators=Ultimi donatori +Mailbox=Cassetta delle lettere +Send your goods to@n@1=Invia i tuoi item a@n@1 +The mailbox is full.=La cassetta delle lettere è piena + +### mechanisms.lua ### + +Lever=Leva +Stone Pressure Plate=Placca di pressione di pietra +Wooden Pressure Plate=Placca di pressione di legno + +### nodes.lua ### + +Bamboo Frame=Cornice di bambù +Baricade=Barricata +Barrel=Barile +Cactus Brick=Mattone di cactus +Candle=Candela +Chainlink=Cotta di maglia +Chair=Sedia +Coal Stone Tile=Mattonella di pietra di carbone +Cobweb=Ragnatela +Cushion=Cuscino +Cushion Block=Blocco di cuscini +Desert Stone Tile=Mattonella di pietra del deserto +Empty Shelf=Mensola vuota +Ender Chest=Baule ender +Garden Stone Path=Sentiero da giardino in pietra +Half Wooden Cabinet=Stipo di legno a metà +Hardened Clay=Argilla indurita +Iron Light Box=Scatola luminosa di ferro +Ivy=Edera +Japanese Door=Porta giapponese +Lantern=Lanterna +Moon Brick=Mattone lunare +Multi Shelf=Mensole +Packed Ice=Ghiaccio compatto +Painting=Dipinto +Potted Geranium=Geranio in vaso +Potted Rose=Rosa in vaso +Potted Tulip=Tulipano in vaso +Potted Viola=Violetta in vaso +Potted White Dandelion=Soffione bianco in vaso +Potted Yellow Dandelion=Soffione giallo in vaso +Prison Door=Porta di prigione +Red Curtain=Tenda rossa +Runestone=Pietra runica +Rusty Iron Bars=Sbarre di prigione arrugginite +Rusty Prison Door=Porta di prigione arrugginita +Screen Door=Porta a schermo +Slide Door=Porta scorrevole +Stone Tile=Mattonella di pietra +Table=Tavolo +Tatami=Tatami +Television=Televisione +Trampoline=Trampolino +Wood Frame=Cornice in legno +Wood Framed Glass=Cornice in legno con vetro +Wooden Cabinet=Stipo di legno +Wooden Light Box=Mattonella luminosa di legno +Wooden Tile=Mattonella di legno +Woodglass Door=Porta di vetro + +### rope.lua ### + +Rope=Corda + +### workbench.lua ### + +Back=Indietro +Crafting=Fabbricare +Cut=Tagliare +Hammer=Martello +Repair=Riparare +Storage=Conservare +Work Bench=Banco da lavoro diff --git a/xdecor/mod.conf b/xdecor/mod.conf index 2e97596..62a4a4d 100644 --- a/xdecor/mod.conf +++ b/xdecor/mod.conf @@ -1 +1,5 @@ name = xdecor +description = A decoration mod meant to be simple and well-featured. +depends = default, bucket, doors, farming, stairs, xpanes +optional_depends = fire, oresplus, moreblocks, mesecons +min_minetest_version = 5.1.0 diff --git a/xdecor/src/alias.lua b/xdecor/src/alias.lua deleted file mode 100644 index dc95741..0000000 --- a/xdecor/src/alias.lua +++ /dev/null @@ -1 +0,0 @@ -minetest.register_alias("xdecor:crafting_guide", "craftguide:book") diff --git a/xdecor/src/chess.lua b/xdecor/src/chess.lua index f037eee..d9db38e 100644 --- a/xdecor/src/chess.lua +++ b/xdecor/src/chess.lua @@ -1,10 +1,18 @@ local realchess = {} +local S = minetest.get_translator("xdecor") +local FS = function(...) return minetest.formspec_escape(S(...)) end screwdriver = screwdriver or {} local function index_to_xy(idx) + if not idx then + return nil + end + idx = idx - 1 + local x = idx % 8 local y = (idx - x) / 8 + return x, y end @@ -16,17 +24,9 @@ local function get_square(a, b) return (a * 8) - (8 - b) end -local chat_prefix = minetest.colorize("#FFFF00", "[Chess] ") +local chat_prefix = minetest.colorize("#FFFF00", "["..S("Chess").."] ") local letters = {'A','B','C','D','E','F','G','H'} -local rowDirs = {-1, -1, -1, 0, 0, 1, 1, 1} -local colDirs = {-1, 0, 1, -1, 1, -1, 0, 1} - -local bishopThreats = {true, false, true, false, false, true, false, true} -local rookThreats = {false, true, false, true, true, false, true, false} -local queenThreats = {true, true, true, true, true, true, true, true} -local kingThreats = {true, true, true, true, true, true, true, true} - local function board_to_table(inv) local t = {} for i = 1, 64 do @@ -36,6 +36,431 @@ local function board_to_table(inv) return t end +local piece_values = { + pawn = 10, + knight = 30, + bishop = 30, + rook = 50, + queen = 90, + king = 900 +} + +local function get_possible_moves(board, from_idx) + local piece, color = board[from_idx]:match(":(%w+)_(%w+)") + if not piece then return end + local moves = {} + local from_x, from_y = index_to_xy(from_idx) + + for i = 1, 64 do + local stack_name = board[i] + if stack_name:find((color == "black" and "white" or "black")) or + stack_name == "" then + moves[i] = 0 + end + end + + for to_idx in pairs(moves) do + local pieceTo = board[to_idx] + local to_x, to_y = index_to_xy(to_idx) + + -- PAWN + if piece == "pawn" then + if color == "white" then + local pawnWhiteMove = board[xy_to_index(from_x, from_y - 1)] + -- white pawns can go up only + if from_y - 1 == to_y then + if from_x == to_x then + if pieceTo ~= "" then + moves[to_idx] = nil + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("black") then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + elseif from_y - 2 == to_y then + if pieceTo ~= "" or from_y < 6 or pawnWhiteMove ~= "" then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + + --[[ + if x not changed + ensure that destination cell is empty + elseif x changed one unit left or right + ensure the pawn is killing opponent piece + else + move is not legal - abort + ]] + + if from_x == to_x then + if pieceTo ~= "" then + moves[to_idx] = nil + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("black") then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + + elseif color == "black" then + local pawnBlackMove = board[xy_to_index(from_x, from_y + 1)] + -- black pawns can go down only + if from_y + 1 == to_y then + if from_x == to_x then + if pieceTo ~= "" then + moves[to_idx] = nil + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("white") then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + elseif from_y + 2 == to_y then + if pieceTo ~= "" or from_y > 1 or pawnBlackMove ~= "" then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + + --[[ + if x not changed + ensure that destination cell is empty + elseif x changed one unit left or right + ensure the pawn is killing opponent piece + else + move is not legal - abort + ]] + + if from_x == to_x then + if pieceTo ~= "" then + moves[to_idx] = nil + end + elseif from_x - 1 == to_x or from_x + 1 == to_x then + if not pieceTo:find("white") then + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + else + moves[to_idx] = nil + end + + -- ROOK + elseif piece == "rook" then + if from_x == to_x then + -- Moving vertically + if from_y < to_y then + -- Moving down + -- Ensure that no piece disturbs the way + for i = from_y + 1, to_y - 1 do + if board[xy_to_index(from_x, i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Mocing up + -- Ensure that no piece disturbs the way + for i = to_y + 1, from_y - 1 do + if board[xy_to_index(from_x, i)] ~= "" then + moves[to_idx] = nil + end + end + end + elseif from_y == to_y then + -- Mocing horizontally + if from_x < to_x then + -- mocing right + -- ensure that no piece disturbs the way + for i = from_x + 1, to_x - 1 do + if board[xy_to_index(i, from_y)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Mocing left + -- Ensure that no piece disturbs the way + for i = to_x + 1, from_x - 1 do + if board[xy_to_index(i, from_y)] ~= "" then + moves[to_idx] = nil + end + end + end + else + -- Attempt to move arbitrarily -> abort + moves[to_idx] = nil + end + + -- KNIGHT + elseif piece == "knight" then + -- Get relative pos + local dx = from_x - to_x + local dy = from_y - to_y + + -- Get absolute values + if dx < 0 then + dx = -dx + end + + if dy < 0 then + dy = -dy + end + + -- Sort x and y + if dx > dy then + dx, dy = dy, dx + end + + -- Ensure that dx == 1 and dy == 2 + if dx ~= 1 or dy ~= 2 then + moves[to_idx] = nil + end + -- Just ensure that destination cell does not contain friend piece + -- ^ It was done already thus everything ok + + -- BISHOP + elseif piece == "bishop" then + -- Get relative pos + local dx = from_x - to_x + local dy = from_y - to_y + + -- Get absolute values + if dx < 0 then + dx = -dx + end + + if dy < 0 then + dy = -dy + end + + -- Ensure dx and dy are equal + if dx ~= dy then + moves[to_idx] = nil + end + + if from_x < to_x then + if from_y < to_y then + -- Moving right-down + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x + i, from_y + i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Moving right-up + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x + i, from_y - i)] ~= "" then + moves[to_idx] = nil + end + end + end + else + if from_y < to_y then + -- Moving left-down + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x - i, from_y + i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Moving left-up + -- ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x - i, from_y - i)] ~= "" then + moves[to_idx] = nil + end + end + end + end + + -- QUEEN + elseif piece == "queen" then + local dx = from_x - to_x + local dy = from_y - to_y + + -- Get absolute values + if dx < 0 then + dx = -dx + end + + if dy < 0 then + dy = -dy + end + + -- Ensure valid relative move + if dx ~= 0 and dy ~= 0 and dx ~= dy then + moves[to_idx] = nil + end + + if from_x == to_x then + -- Moving vertically + if from_y < to_y then + -- Moving down + -- Ensure that no piece disturbs the way + for i = from_y + 1, to_y - 1 do + if board[xy_to_index(from_x, i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Mocing up + -- Ensure that no piece disturbs the way + for i = to_y + 1, from_y - 1 do + if board[xy_to_index(from_x, i)] ~= "" then + moves[to_idx] = nil + end + end + end + elseif from_x < to_x then + if from_y == to_y then + -- Goes right + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x + i, from_y)] ~= "" then + moves[to_idx] = nil + end + end + elseif from_y < to_y then + -- Goes right-down + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x + i, from_y + i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Goes right-up + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x + i, from_y - i)] ~= "" then + moves[to_idx] = nil + end + end + end + else + if from_y == to_y then + -- Mocing horizontally + if from_x < to_x then + -- mocing right + -- ensure that no piece disturbs the way + for i = from_x + 1, to_x - 1 do + if board[xy_to_index(i, from_y)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Mocing left + -- Ensure that no piece disturbs the way + for i = to_x + 1, from_x - 1 do + if board[xy_to_index(i, from_y)] ~= "" then + moves[to_idx] = nil + end + end + end + elseif from_y < to_y then + -- Goes left-down + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x - i, from_y + i)] ~= "" then + moves[to_idx] = nil + end + end + else + -- Goes left-up + -- Ensure that no piece disturbs the way + for i = 1, dx - 1 do + if board[xy_to_index(from_x - i, from_y - i)] ~= "" then + moves[to_idx] = nil + end + end + end + end + + -- KING + elseif piece == "king" then + local dx = from_x - to_x + local dy = from_y - to_y + + if dx < 0 then + dx = -dx + end + + if dy < 0 then + dy = -dy + end + + if dx > 1 or dy > 1 then + moves[to_idx] = nil + end + end + end + + if not next(moves) then return end + + for i in pairs(moves) do + local stack_name = board[tonumber(i)] + if stack_name ~= "" then + for p, value in pairs(piece_values) do + if stack_name:find(p) then + moves[i] = value + end + end + end + end + + return moves +end + +local function best_move(moves) + local value, choices = 0, {} + + for from, _ in pairs(moves) do + for to, val in pairs(_) do + if val > value then + value = val + choices = {{ + from = from, + to = to + }} + elseif val == value then + choices[#choices + 1] = { + from = from, + to = to + } + end + end + end + + local random = math.random(1, #choices) + local choice_from, choice_to = choices[random].from, choices[random].to + + return tonumber(choice_from), choice_to +end + +local rowDirs = {-1, -1, -1, 0, 0, 1, 1, 1} +local colDirs = {-1, 0, 1, -1, 1, -1, 0, 1} + +local rowDirsKnight = { 2, 1, 2, 1, -2, -1, -2, -1} +local colDirsKnight = {-1, -2, 1, 2, 1, 2, -1, -2} + +local bishopThreats = {true, false, true, false, false, true, false, true} +local rookThreats = {false, true, false, true, true, false, true, false} +local queenThreats = {true, true, true, true, true, true, true, true} +local kingThreats = {true, true, true, true, true, true, true, true} + local function attacked(color, idx, board) local threatDetected = false local kill = color == "white" @@ -78,6 +503,21 @@ local function attacked(color, idx, board) end end end + + local colK, rowK = index_to_xy(idx) + colK, rowK = colK + 1, rowK + 1 + rowK = rowK + rowDirsKnight[dir] + colK = colK + colDirsKnight[dir] + + if rowK >= 1 and rowK <= 8 and colK >= 1 and colK <= 8 then + local square = get_square(rowK, colK) + local square_name = board[square] + local piece, pieceColor = square_name:match(":(%w+)_(%w+)") + + if piece and pieceColor ~= color and piece == "knight" then + threatDetected = true + end + end end end @@ -147,6 +587,14 @@ for i = 1, #pieces do end pieces_str = pieces_str .. "69=mailbox_blank16.png" +local fs_init = [[ + size[4,1.2;] + no_prepend[] + ]] + .."label[0,0;"..FS("Select a mode:").."]" + .."button[0,0.5;2,1;single;"..FS("Singleplayer").."]" + .."button[2,0.5;2,1;multi;"..FS("Multiplayer").."]" + local fs = [[ size[14.7,10;] no_prepend[] @@ -155,11 +603,39 @@ local fs = [[ list[context;board;0.3,1;8,8;] listcolors[#00000000;#00000000;#00000000;#30434C;#FFF] tableoptions[background=#00000000;highlight=#00000000;border=false] - button[10.5,8.5;2,2;new;New game] -]] .. "tablecolumns[image," .. pieces_str .. + ]] + .."button[10.5,8.5;2,2;new;"..FS("New game").."]" + .."tablecolumns[image," .. pieces_str .. ";text;color;text;color;text;image," .. pieces_str .. "]" -local function get_moves_list(meta, pieceFrom, pieceTo, pieceTo_s, from_x, to_x, from_y, to_y) +local function update_formspec(meta) + local black_king_attacked = meta:get_string("blackAttacked") == "true" + local white_king_attacked = meta:get_string("whiteAttacked") == "true" + + local playerWhite = meta:get_string("playerWhite") + local playerBlack = meta:get_string("playerBlack") + + local moves = meta:get_string("moves") + local eaten_img = meta:get_string("eaten_img") + local lastMove = meta:get_string("lastMove") + local turnBlack = minetest.colorize("#000001", (lastMove == "white" and playerBlack ~= "") and + playerBlack .. "..." or playerBlack) + local turnWhite = minetest.colorize("#000001", (lastMove == "black" and playerWhite ~= "") and + playerWhite .. "..." or playerWhite) + local check_s = minetest.colorize("#FF0000", "\\["..FS("check").."\\]") + + local formspec = fs .. + "label[1.9,0.3;" .. turnBlack .. (black_king_attacked and " " .. check_s or "") .. "]" .. + "label[1.9,9.15;" .. turnWhite .. (white_king_attacked and " " .. check_s or "") .. "]" .. + "table[8.9,1.05;5.07,3.75;moves;" .. moves:sub(1,-2) .. ";1]" .. + eaten_img + + meta:set_string("formspec", formspec) +end + +local function get_moves_list(meta, pieceFrom, pieceTo, pieceTo_s, from_idx, to_idx) + local from_x, from_y = index_to_xy(from_idx) + local to_x, to_y = index_to_xy(to_idx) local moves = meta:get_string("moves") local pieceFrom_s = pieceFrom:match(":(%w+_%w+)") local pieceFrom_si_id = pieces_str:match("(%d+)=" .. pieceFrom_s) @@ -202,7 +678,7 @@ local function get_eaten_list(meta, pieceTo, pieceTo_s) end eaten_img = eaten_img .. - "image[" .. ((X + (is_white and 11.7 or 8.8)) - (X * 0.45)) .. "," .. + "image[" .. ((X + (is_white and 11.67 or 8.8)) - (X * 0.45)) .. "," .. ((Y + 5.56) - (Y * 0.2)) .. ";1,1;" .. eaten_t[i] .. ".png]" end @@ -213,8 +689,8 @@ function realchess.init(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() - meta:set_string("formspec", fs) - meta:set_string("infotext", "Chess Board") + meta:set_string("formspec", fs_init) + meta:set_string("infotext", S("Chess Board")) meta:set_string("playerBlack", "") meta:set_string("playerWhite", "") meta:set_string("lastMove", "") @@ -229,6 +705,7 @@ function realchess.init(pos) meta:set_string("moves", "") meta:set_string("eaten", "") + meta:set_string("mode", "") inv:set_list("board", pieces) inv:set_size("board", 64) @@ -251,7 +728,7 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player if pieceFrom:find("white") then if playerWhite ~= "" and playerWhite ~= playerName then - minetest.chat_send_player(playerName, chat_prefix .. "Someone else plays white pieces!") + minetest.chat_send_player(playerName, chat_prefix .. S("Someone else plays white pieces!")) return 0 end @@ -269,7 +746,7 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player elseif pieceFrom:find("black") then if playerBlack ~= "" and playerBlack ~= playerName then - minetest.chat_send_player(playerName, chat_prefix .. "Someone else plays black pieces!") + minetest.chat_send_player(playerName, chat_prefix .. S("Someone else plays black pieces!")) return 0 end @@ -483,7 +960,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Moving right-down -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then return 0 end end @@ -491,7 +969,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Moving right-up -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then return 0 end end @@ -501,7 +980,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Moving left-down -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then return 0 end end @@ -509,7 +989,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Moving left-up -- ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then return 0 end end @@ -534,16 +1015,16 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player if from_y < to_y then -- Goes down -- Ensure that no piece disturbs the way - for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x, from_y + i)):get_name() ~= "" then + for i = from_y + 1, to_y - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, i)):get_name() ~= "" then return 0 end end else -- Goes up -- Ensure that no piece disturbs the way - for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x, from_y - i)):get_name() ~= "" then + for i = to_y + 1, from_y - 1 do + if inv:get_stack(from_list, xy_to_index(from_x, i)):get_name() ~= "" then return 0 end end @@ -552,8 +1033,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player if from_y == to_y then -- Goes right -- Ensure that no piece disturbs the way - for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x + i, from_y)):get_name() ~= "" then + for i = from_x + 1, to_x - 1 do + if inv:get_stack(from_list, xy_to_index(i, from_y)):get_name() ~= "" then return 0 end end @@ -561,7 +1042,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Goes right-down -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x + i, from_y + i)):get_name() ~= "" then return 0 end end @@ -569,7 +1051,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Goes right-up -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x + i, from_y - i)):get_name() ~= "" then return 0 end end @@ -578,8 +1061,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player if from_y == to_y then -- Goes left -- Ensure that no piece disturbs the way and destination cell does - for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x - i, from_y)):get_name() ~= "" then + for i = to_x + 1, from_x - 1 do + if inv:get_stack(from_list, xy_to_index(i, from_y)):get_name() ~= "" then return 0 end end @@ -587,7 +1070,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Goes left-down -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x - i, from_y + i)):get_name() ~= "" then return 0 end end @@ -595,7 +1079,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player -- Goes left-up -- Ensure that no piece disturbs the way for i = 1, dx - 1 do - if inv:get_stack(from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then + if inv:get_stack( + from_list, xy_to_index(from_x - i, from_y - i)):get_name() ~= "" then return 0 end end @@ -610,7 +1095,7 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player if thisMove == "white" then if from_y == 7 and to_y == 7 then - if to_x == 1 then + if to_x == 2 then local castlingWhiteL = meta:get_int("castlingWhiteL") local idx57 = inv:get_stack(from_list, 57):get_name() @@ -620,8 +1105,9 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player return 0 end end + inv:set_stack(from_list, 57, "") - inv:set_stack(from_list, 59, "realchess:rook_white_1") + inv:set_stack(from_list, 60, "realchess:rook_white_1") check = false end elseif to_x == 6 then @@ -634,6 +1120,7 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player return 0 end end + inv:set_stack(from_list, 62, "realchess:rook_white_2") inv:set_stack(from_list, 64, "") check = false @@ -642,7 +1129,7 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player end elseif thisMove == "black" then if from_y == 0 and to_y == 0 then - if to_x == 1 then + if to_x == 2 then local castlingBlackL = meta:get_int("castlingBlackL") local idx1 = inv:get_stack(from_list, 1):get_name() @@ -654,12 +1141,12 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player end inv:set_stack(from_list, 1, "") - inv:set_stack(from_list, 3, "realchess:rook_black_1") + inv:set_stack(from_list, 4, "realchess:rook_black_1") check = false end elseif to_x == 6 then local castlingBlackR = meta:get_int("castlingBlackR") - local idx8 = inv:get_stack(from_list, 1):get_name() + local idx8 = inv:get_stack(from_list, 8):get_name() if castlingBlackR == 1 and idx8 == "realchess:rook_black_2" then for i = from_index + 1, 7 do @@ -705,11 +1192,15 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player board[from_index] = "" local black_king_idx, white_king_idx = locate_kings(board) + if not black_king_idx or not white_king_idx then + return 0 + end local blackAttacked = attacked("black", black_king_idx, board) local whiteAttacked = attacked("white", white_king_idx, board) if blackAttacked then - if thisMove == "black" and meta:get_string("blackAttacked") == "true" then + if thisMove == "black" then + --[(*)[ and meta:get_string("blackAttacked") == "true" ]] then return 0 else meta:set_string("blackAttacked", "true") @@ -719,7 +1210,8 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player end if whiteAttacked then - if thisMove == "white" and meta:get_string("whiteAttacked") == "true" then + if thisMove == "white" then + --[(*)[ and meta:get_string("whiteAttacked") == "true" ]] then return 0 else meta:set_string("whiteAttacked", "true") @@ -728,47 +1220,139 @@ function realchess.move(pos, from_list, from_index, to_list, to_index, _, player meta:set_string("whiteAttacked", "") end - lastMove = thisMove + --(*) Allow a piece to move and put its king in check. Maybe not in the chess rules though? + lastMove = thisMove meta:set_string("lastMove", lastMove) meta:set_int("lastMoveTime", minetest.get_gametime()) - meta:set_string("playerWhite", playerWhite) - meta:set_string("playerBlack", playerBlack) + + if meta:get_string("playerWhite") == "" then + meta:set_string("playerWhite", playerWhite) + elseif meta:get_string("playerBlack") == "" then + meta:set_string("playerBlack", playerBlack) + end local pieceTo_s = pieceTo ~= "" and pieceTo:match(":(%w+_%w+)") or "" - get_moves_list(meta, pieceFrom, pieceTo, pieceTo_s, from_x, to_x, from_y, to_y) + get_moves_list(meta, pieceFrom, pieceTo, pieceTo_s, from_index, to_index) get_eaten_list(meta, pieceTo, pieceTo_s) return 1 end +local function ai_move(inv, meta) + local board_t = board_to_table(inv) + local lastMove = meta:get_string("lastMove") + + if lastMove == "white" then + update_formspec(meta) + local moves = {} + + for i = 1, 64 do + local possibleMoves = get_possible_moves(board_t, i) + local stack_name = inv:get_stack("board", i):get_name() + + if stack_name:find("black") then + moves[tostring(i)] = possibleMoves + end + end + + local choice_from, choice_to = best_move(moves) + + local pieceFrom = inv:get_stack("board", choice_from):get_name() + local pieceTo = inv:get_stack("board", choice_to):get_name() + local pieceTo_s = pieceTo ~= "" and pieceTo:match(":(%w+_%w+)") or "" + + local board = board_to_table(inv) + local black_king_idx = locate_kings(board) + local blackAttacked = attacked("black", black_king_idx, board) + local kingSafe = true + local bestMoveSaveFrom, bestMoveSaveTo + + if blackAttacked then + kingSafe = false + meta:set_string("blackAttacked", "true") + local save_moves = {} + + for from_idx, _ in pairs(moves) do + for to_idx, value in pairs(_) do + from_idx = tonumber(from_idx) + local from_idx_bak, to_idx_bak = board[from_idx], board[to_idx] + board[to_idx] = board[from_idx] + board[from_idx] = "" + black_king_idx = locate_kings(board) + + if black_king_idx then + blackAttacked = attacked("black", black_king_idx, board) + if not blackAttacked then + save_moves[from_idx] = save_moves[from_idx] or {} + save_moves[from_idx][to_idx] = value + end + end + + board[from_idx], board[to_idx] = from_idx_bak, to_idx_bak + end + end + + if next(save_moves) then + bestMoveSaveFrom, bestMoveSaveTo = best_move(save_moves) + end + end + + minetest.after(1.0, function() + local lastMoveTime = meta:get_int("lastMoveTime") + if lastMoveTime > 0 then + if not kingSafe then + if bestMoveSaveTo then + inv:set_stack("board", bestMoveSaveTo, board[bestMoveSaveFrom]) + inv:set_stack("board", bestMoveSaveFrom, "") + meta:set_string("blackAttacked", "") + else + return + end + else + if pieceFrom:find("pawn") and choice_to >= 57 and choice_to <= 64 then + inv:set_stack("board", choice_to, "realchess:queen_black") + else + inv:set_stack("board", choice_to, pieceFrom) + end + + inv:set_stack("board", choice_from, "") + end + + board = board_to_table(inv) + local _, white_king_idx = locate_kings(board) + local whiteAttacked = attacked("white", white_king_idx, board) + + if whiteAttacked then + meta:set_string("whiteAttacked", "true") + end + + if meta:get_string("playerBlack") == "" then + meta:set_string("playerBlack", S("Dumb AI")) + end + + meta:set_string("lastMove", "black") + meta:set_int("lastMoveTime", minetest.get_gametime()) + + get_moves_list(meta, pieceFrom, pieceTo, pieceTo_s, choice_from, choice_to) + get_eaten_list(meta, pieceTo, pieceTo_s) + + update_formspec(meta) + end + end) + else + update_formspec(meta) + end +end + function realchess.on_move(pos, from_list, from_index) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() - inv:set_stack(from_list, from_index, '') + inv:set_stack(from_list, from_index, "") - local black_king_attacked = meta:get_string("blackAttacked") == "true" - local white_king_attacked = meta:get_string("whiteAttacked") == "true" - - local playerWhite = meta:get_string("playerWhite") - local playerBlack = meta:get_string("playerBlack") - - local moves = meta:get_string("moves") - local eaten_img = meta:get_string("eaten_img") - local lastMove = meta:get_string("lastMove") - local turnBlack = minetest.colorize("#000001", (lastMove == "white" and playerBlack ~= "") and - playerBlack .. "..." or playerBlack) - local turnWhite = minetest.colorize("#000001", (lastMove == "black" and playerWhite ~= "") and - playerWhite .. "..." or playerWhite) - local check_s = minetest.colorize("#FF0000", "\\[check\\]") - - local formspec = fs .. - "label[1.9,0.3;" .. turnBlack .. (black_king_attacked and " " .. check_s or "") .. "]" .. - "label[1.9,9.15;" .. turnWhite .. (white_king_attacked and " " .. check_s or "") .. "]" .. - "table[8.9,1.05;5.07,3.75;moves;" .. moves:sub(1,-2) .. ";1]" .. - eaten_img - - meta:set_string("formspec", formspec) + if meta:get_string("mode") == "single" then + ai_move(inv, meta) + end return false end @@ -794,20 +1378,26 @@ function realchess.fields(pos, _, fields, sender) local lastMoveTime = meta:get_int("lastMoveTime") if fields.quit then return end + if fields.single or fields.multi then + meta:set_string("mode", (fields.single and "single" or "multi")) + update_formspec(meta) + return + end + -- Timeout is 5 min. by default for resetting the game (non-players only) if fields.new then if (playerWhite == playerName or playerBlack == playerName) then realchess.init(pos) - elseif lastMoveTime ~= 0 then + elseif lastMoveTime > 0 then if minetest.get_gametime() >= timeout_limit and (playerWhite ~= playerName or playerBlack ~= playerName) then realchess.init(pos) else minetest.chat_send_player(playerName, chat_prefix .. - "You can't reset the chessboard, a game has been started. " .. - "If you aren't a current player, try again in " .. - timeout_format(timeout_limit)) + S("You can't reset the chessboard, a game has been started. " .. + "If you aren't a current player, try again in @1", + timeout_format(timeout_limit))) end end end @@ -826,13 +1416,13 @@ function realchess.dig(pos, player) -- Timeout is 5 min. by default for digging the chessboard (non-players only) return (lastMoveTime == 0 and minetest.get_gametime() > timeout_limit) or minetest.chat_send_player(playerName, chat_prefix .. - "You can't dig the chessboard, a game has been started. " .. - "Reset it first if you're a current player, or dig it again in " .. - timeout_format(timeout_limit)) + S("You can't dig the chessboard, a game has been started. " .. + "Reset it first if you're a current player, or dig it again in @1", + timeout_format(timeout_limit))) end minetest.register_node(":realchess:chessboard", { - description = "Chess Board", + description = S("Chess Board"), drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", @@ -852,11 +1442,11 @@ minetest.register_node(":realchess:chessboard", { allow_metadata_inventory_take = function() return 0 end }) -local function register_piece(name, count) +local function register_piece(name, white_desc, black_desc, count) for _, color in pairs({"black", "white"}) do if not count then minetest.register_craftitem(":realchess:" .. name .. "_" .. color, { - description = color:gsub("^%l", string.upper) .. " " .. name:gsub("^%l", string.upper), + description = (color == "black") and black_desc or white_desc, inventory_image = name .. "_" .. color .. ".png", stack_max = 1, groups = {not_in_creative_inventory=1} @@ -864,7 +1454,7 @@ local function register_piece(name, count) else for i = 1, count do minetest.register_craftitem(":realchess:" .. name .. "_" .. color .. "_" .. i, { - description = color:gsub("^%l", string.upper) .. " " .. name:gsub("^%l", string.upper), + description = (color == "black") and black_desc or white_desc, inventory_image = name .. "_" .. color .. ".png", stack_max = 1, groups = {not_in_creative_inventory=1} @@ -874,12 +1464,12 @@ local function register_piece(name, count) end end -register_piece("pawn", 8) -register_piece("rook", 2) -register_piece("knight", 2) -register_piece("bishop", 2) -register_piece("queen") -register_piece("king") +register_piece("pawn", S("White Pawn"), S("Black Pawn"), 8) +register_piece("rook", S("White Rook"), S("Black Rook"), 2) +register_piece("knight", S("White Knight"), S("Black Knight"), 2) +register_piece("bishop", S("White Bishop"), S("Black Bishop"), 2) +register_piece("queen", S("White Queen"), S("Black Queen")) +register_piece("king", S("White King"), S("Black King")) -- Recipes diff --git a/xdecor/src/cooking.lua b/xdecor/src/cooking.lua index 8cc2d38..fb0699e 100644 --- a/xdecor/src/cooking.lua +++ b/xdecor/src/cooking.lua @@ -1,4 +1,5 @@ local cauldron, sounds = {}, {} +local S = minetest.get_translator("xdecor") -- Add more ingredients here that make a soup. local ingredients_list = { @@ -17,7 +18,9 @@ cauldron.cbox = { function cauldron.stop_sound(pos) local spos = minetest.hash_node_position(pos) - if sounds[spos] then minetest.sound_stop(sounds[spos]) end + if sounds[spos] then + minetest.sound_stop(sounds[spos]) + end end function cauldron.idle_construct(pos) @@ -29,11 +32,14 @@ end function cauldron.boiling_construct(pos) local spos = minetest.hash_node_position(pos) sounds[spos] = minetest.sound_play("xdecor_boiling_water", { - pos=pos, max_hear_distance=5, gain=0.8, loop=true + pos = pos, + max_hear_distance = 5, + gain = 0.8, + loop = true }) local meta = minetest.get_meta(pos) - meta:set_string("infotext", "Cauldron (active) - Drop some foods inside to make a soup") + meta:set_string("infotext", S("Cauldron (active) - Drop foods inside to make a soup")) local timer = minetest.get_node_timer(pos) timer:start(5.0) @@ -51,29 +57,31 @@ function cauldron.filling(pos, node, clicker, itemstack) inv:add_item("main", "bucket:bucket_water 1") else minetest.chat_send_player(clicker:get_player_name(), - "No room in your inventory to add a bucket of water.") + S("No room in your inventory to add a bucket of water.")) return itemstack end else itemstack:replace("bucket:bucket_water") end - minetest.set_node(pos, {name="xdecor:cauldron_empty", param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2}) + elseif wield_item:sub(-6) == "_water" and node.name:sub(-6) == "_empty" then - minetest.set_node(pos, {name="xdecor:cauldron_idle", param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:cauldron_idle", param2 = node.param2}) itemstack:replace("bucket:bucket_empty") end + return itemstack end end function cauldron.idle_timer(pos) - local below_node = {x=pos.x, y=pos.y-1, z=pos.z} + local below_node = {x = pos.x, y = pos.y - 1, z = pos.z} if not minetest.get_node(below_node).name:find("fire") then return true end local node = minetest.get_node(pos) - minetest.set_node(pos, {name="xdecor:cauldron_boiling", param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:cauldron_boiling", param2 = node.param2}) return true end @@ -82,13 +90,17 @@ local function eatable(itemstring) local item = itemstring:match("[%w_:]+") local on_use_def = minetest.registered_items[item].on_use if not on_use_def then return end + return string.format("%q", string.dump(on_use_def)):find("item_eat") end function cauldron.boiling_timer(pos) local node = minetest.get_node(pos) local objs = minetest.get_objects_inside_radius(pos, 0.5) - if not next(objs) then return true end + + if not next(objs) then + return true + end local ingredients = {} for _, obj in pairs(objs) do @@ -96,60 +108,68 @@ function cauldron.boiling_timer(pos) local itemstring = obj:get_luaentity().itemstring local food = itemstring:match(":([%w_]+)") - for _, ingredient in pairs(ingredients_list) do + for _, ingredient in ipairs(ingredients_list) do if food and (eatable(itemstring) or food:find(ingredient)) then - ingredients[#ingredients+1] = food break + ingredients[#ingredients + 1] = food + break end end end end if #ingredients >= 2 then - for _, obj in pairs(objs) do obj:remove() end - minetest.set_node(pos, {name="xdecor:cauldron_soup", param2=node.param2}) + for _, obj in pairs(objs) do + obj:remove() + end + + minetest.set_node(pos, {name = "xdecor:cauldron_soup", param2 = node.param2}) end - local node_under = {x=pos.x, y=pos.y-1, z=pos.z} + local node_under = {x = pos.x, y = pos.y - 1, z = pos.z} + if not minetest.get_node(node_under).name:find("fire") then - minetest.set_node(pos, {name="xdecor:cauldron_idle", param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:cauldron_idle", param2 = node.param2}) end + return true end function cauldron.take_soup(pos, node, clicker, itemstack) local inv = clicker:get_inventory() local wield_item = clicker:get_wielded_item() + local item_name = wield_item:get_name() - if wield_item:get_name() == "xdecor:bowl" then + if item_name == "xdecor:bowl" or item_name == "farming:bowl" then if wield_item:get_count() > 1 then if inv:room_for_item("main", "xdecor:bowl_soup 1") then itemstack:take_item() inv:add_item("main", "xdecor:bowl_soup 1") else minetest.chat_send_player(clicker:get_player_name(), - "No room in your inventory to add a bowl of soup.") + S("No room in your inventory to add a bowl of soup.")) return itemstack end else itemstack:replace("xdecor:bowl_soup 1") end - minetest.set_node(pos, {name="xdecor:cauldron_empty", param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2}) end + return itemstack end xdecor.register("cauldron_empty", { - description = "Cauldron", + description = S("Cauldron"), groups = {cracky=2, oddly_breakable_by_hand=1}, on_rotate = screwdriver.rotate_simple, tiles = {"xdecor_cauldron_top_empty.png", "xdecor_cauldron_sides.png"}, - infotext = "Cauldron (empty)", + infotext = S("Cauldron (empty)"), + collision_box = xdecor.pixelbox(16, cauldron.cbox), + on_rightclick = cauldron.filling, on_construct = function(pos) cauldron.stop_sound(pos) end, - on_rightclick = cauldron.filling, - collision_box = xdecor.pixelbox(16, cauldron.cbox) }) xdecor.register("cauldron_idle", { @@ -157,58 +177,66 @@ xdecor.register("cauldron_idle", { on_rotate = screwdriver.rotate_simple, tiles = {"xdecor_cauldron_top_idle.png", "xdecor_cauldron_sides.png"}, drop = "xdecor:cauldron_empty", - infotext = "Cauldron (idle)", + infotext = S("Cauldron (idle)"), collision_box = xdecor.pixelbox(16, cauldron.cbox), on_rightclick = cauldron.filling, on_construct = cauldron.idle_construct, - on_timer = cauldron.idle_timer + on_timer = cauldron.idle_timer, }) xdecor.register("cauldron_boiling", { groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1}, on_rotate = screwdriver.rotate_simple, drop = "xdecor:cauldron_empty", - infotext = "Cauldron (active) - Drop foods inside to make a soup", + infotext = S("Cauldron (active) - Drop foods inside to make a soup"), damage_per_second = 2, - tiles = {{name="xdecor_cauldron_top_anim_boiling_water.png", - animation={type="vertical_frames", length=3.0}}, - "xdecor_cauldron_sides.png"}, + tiles = { + { + name = "xdecor_cauldron_top_anim_boiling_water.png", + animation = {type = "vertical_frames", length = 3.0} + }, + "xdecor_cauldron_sides.png" + }, collision_box = xdecor.pixelbox(16, cauldron.cbox), on_rightclick = cauldron.filling, on_construct = cauldron.boiling_construct, + on_timer = cauldron.boiling_timer, on_destruct = function(pos) cauldron.stop_sound(pos) end, - on_timer = cauldron.boiling_timer }) xdecor.register("cauldron_soup", { - groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1}, + groups = {cracky = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1}, on_rotate = screwdriver.rotate_simple, drop = "xdecor:cauldron_empty", - infotext = "Cauldron (active) - Use a bowl to eat the soup", + infotext = S("Cauldron (active) - Use a bowl to eat the soup"), damage_per_second = 2, - tiles = {{name="xdecor_cauldron_top_anim_soup.png", - animation={type="vertical_frames", length=3.0}}, - "xdecor_cauldron_sides.png"}, + tiles = { + { + name = "xdecor_cauldron_top_anim_soup.png", + animation = {type = "vertical_frames", length = 3.0} + }, + "xdecor_cauldron_sides.png" + }, collision_box = xdecor.pixelbox(16, cauldron.cbox), on_rightclick = cauldron.take_soup, on_destruct = function(pos) cauldron.stop_sound(pos) - end + end, }) -- Craft items minetest.register_craftitem("xdecor:bowl", { - description = "Bowl", + description = S("Bowl"), inventory_image = "xdecor_bowl.png", wield_image = "xdecor_bowl.png", groups = {food_bowl = 1, flammable = 2}, }) minetest.register_craftitem("xdecor:bowl_soup", { - description = "Bowl of soup", + description = S("Bowl of soup"), inventory_image = "xdecor_bowl_soup.png", wield_image = "xdecor_bowl_soup.png", groups = {not_in_creative_inventory=1}, diff --git a/xdecor/src/enchanting.lua b/xdecor/src/enchanting.lua index 5e30d59..0cfd192 100644 --- a/xdecor/src/enchanting.lua +++ b/xdecor/src/enchanting.lua @@ -1,5 +1,8 @@ screwdriver = screwdriver or {} +local S = minetest.get_translator("xdecor") +local FS = function(...) return minetest.formspec_escape(S(...)) end local ceil, abs, random = math.ceil, math.abs, math.random +local reg_tools = minetest.registered_tools -- Cost in Mese crystal(s) for enchanting. local mese_cost = 1 @@ -11,13 +14,17 @@ local enchanting = { damages = 1, -- Sharpness } -local function cap(S) return S:gsub("^%l", string.upper) end +local function cap(str) return + str:gsub("^%l", string.upper) +end + local function to_percent(orig_value, final_value) return abs(ceil(((final_value - orig_value) / orig_value) * 100)) end function enchanting:get_tooltip(enchant, orig_caps, fleshy) - local bonus = {durable=0, efficiency=0, damages=0} + local bonus = {durable = 0, efficiency = 0, damages = 0} + if orig_caps then bonus.durable = to_percent(orig_caps.uses, orig_caps.uses * enchanting.uses) local sum_caps_times = 0 @@ -28,45 +35,57 @@ function enchanting:get_tooltip(enchant, orig_caps, fleshy) bonus.efficiency = to_percent(average_caps_time, average_caps_time - enchanting.times) end + if fleshy then bonus.damages = to_percent(fleshy, fleshy + enchanting.damages) end local specs = { -- not finished, to complete - durable = {"#00baff", " (+"..bonus.durable.."%)"}, - fast = {"#74ff49", " (+"..bonus.efficiency.."%)"}, - sharp = {"#ffff00", " (+"..bonus.damages.."%)"}, + durable = {"#00baff", " (+" .. bonus.durable .. "%)"}, + fast = {"#74ff49", " (+" .. bonus.efficiency .. "%)"}, + sharp = {"#ffff00", " (+" .. bonus.damages .. "%)"}, } + + local enchant_loc = { + fast = S("Efficiency"), + durable = S("Durability"), + sharp = S("Sharpness"), + } + return minetest.colorize and minetest.colorize(specs[enchant][1], - "\n"..cap(enchant)..specs[enchant][2]) or - "\n"..cap(enchant)..specs[enchant][2] + "\n" .. enchant_loc[enchant] .. specs[enchant][2]) or + "\n" .. enchant_loc[enchant] .. specs[enchant][2] end local enchant_buttons = { - [[ image_button[3.9,0.85;4,0.92;bg_btn.png;fast;Efficiency] - image_button[3.9,1.77;4,1.12;bg_btn.png;durable;Durability] ]], - "image_button[3.9,2.9;4,0.92;bg_btn.png;sharp;Sharpness]", + "image_button[3.9,0.85;4,0.92;bg_btn.png;fast;"..FS("Efficiency").."]" .. + "image_button[3.9,1.77;4,1.12;bg_btn.png;durable;"..FS("Durability").."]", + "image_button[3.9,2.9;4,0.92;bg_btn.png;sharp;"..FS("Sharpness").."]", } function enchanting.formspec(pos, num) local meta = minetest.get_meta(pos) - local formspec = [[ size[9,9;] + local formspec = [[ + size[9,8.6;] + no_prepend[] bgcolor[#080808BB;true] - background[0,0;9,9;ench_ui.png] + listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF] + background9[0,0;9,9;ench_ui.png;6] list[context;tool;0.9,2.9;1,1;] list[context;mese;2,2.9;1,1;] - list[current_player;main;0.5,4.5;8,4;] + list[current_player;main;0.55,4.5;8,4;] listring[current_player;main] listring[context;tool] listring[current_player;main] listring[context;mese] image[2,2.9;1,1;mese_layout.png] - tooltip[sharp;Your weapon inflicts more damages] - tooltip[durable;Your tool last longer] - tooltip[fast;Your tool digs faster] ]] - ..default.gui_slots..default.get_hotbar_bg(0.5,4.5) + ]] + .."tooltip[sharp;"..FS("Your weapon inflicts more damages").."]" + .."tooltip[durable;"..FS("Your tool last longer").."]" + .."tooltip[fast;"..FS("Your tool digs faster").."]" + ..default.gui_slots .. default.get_hotbar_bg(0.55, 4.5) - formspec = formspec..(enchant_buttons[num] or "") + formspec = formspec .. (enchant_buttons[num] or "") meta:set_string("formspec", formspec) end @@ -78,7 +97,7 @@ function enchanting.on_put(pos, listname, _, stack) "sword", } - for idx, tools in pairs(tool_groups) do + for idx, tools in ipairs(tool_groups) do if tools:find(stackname:match(":(%w+)")) then enchanting.formspec(pos, idx) end @@ -93,11 +112,14 @@ function enchanting.fields(pos, _, fields, sender) local mese = inv:get_stack("mese", 1) local orig_wear = tool:get_wear() local mod, name = tool:get_name():match("(.*):(.*)") - local enchanted_tool = (mod or "")..":enchanted_"..(name or "").."_"..next(fields) + local enchanted_tool = (mod or "") .. ":enchanted_" .. (name or "") .. "_" .. next(fields) - if mese:get_count() >= mese_cost and minetest.registered_tools[enchanted_tool] then + if mese:get_count() >= mese_cost and reg_tools[enchanted_tool] then minetest.sound_play("xdecor_enchanting", { - to_player=sender:get_player_name(), gain=0.8}) + to_player = sender:get_player_name(), + gain = 0.8 + }) + tool:replace(enchanted_tool) tool:add_wear(orig_wear) mese:take_item(mese_cost) @@ -112,37 +134,43 @@ function enchanting.dig(pos) end local function allowed(tool) - if not tool then return false end - for item in pairs(minetest.registered_tools) do - if item:find("enchanted_"..tool) then return true end + if not tool then return end + + for item in pairs(reg_tools) do + if item:find("enchanted_" .. tool) then + return true + end end - return false end function enchanting.put(_, listname, _, stack) local stackname = stack:get_name() - if listname == "mese" and stackname == "default:mese_crystal" then + if listname == "mese" and (stackname == "default:mese_crystal" or + stackname == "imese:industrial_mese_crystal") then return stack:get_count() elseif listname == "tool" and allowed(stackname:match("[^:]+$")) then return 1 end + return 0 end function enchanting.on_take(pos, listname) - if listname == "tool" then enchanting.formspec(pos, nil) end + if listname == "tool" then + enchanting.formspec(pos) + end end function enchanting.construct(pos) local meta = minetest.get_meta(pos) - meta:set_string("infotext", "Enchantment Table") - enchanting.formspec(pos, nil) + meta:set_string("infotext", S("Enchantment Table")) + enchanting.formspec(pos) local inv = meta:get_inventory() inv:set_size("tool", 1) inv:set_size("mese", 1) - minetest.add_entity({x=pos.x, y=pos.y+0.85, z=pos.z}, "xdecor:book_open") + minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open") local timer = minetest.get_node_timer(pos) timer:start(0.5) end @@ -160,39 +188,45 @@ end function enchanting.timer(pos) local num = #minetest.get_objects_inside_radius(pos, 0.9) if num == 0 then - minetest.add_entity({x=pos.x, y=pos.y+0.85, z=pos.z}, "xdecor:book_open") + minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open") end - local minp = {x=pos.x-2, y=pos.y, z=pos.z-2} - local maxp = {x=pos.x+2, y=pos.y+1, z=pos.z+2} + local minp = {x = pos.x - 2, y = pos.y, z = pos.z - 2} + local maxp = {x = pos.x + 2, y = pos.y + 1, z = pos.z + 2} + local bookshelves = minetest.find_nodes_in_area(minp, maxp, "default:bookshelf") - if #bookshelves == 0 then return true end + if #bookshelves == 0 then + return true + end local bookshelf_pos = bookshelves[random(1, #bookshelves)] local x = pos.x - bookshelf_pos.x local y = bookshelf_pos.y - pos.y local z = pos.z - bookshelf_pos.z - if tostring(x..z):find(2) then + if tostring(x .. z):find(2) then minetest.add_particle({ pos = bookshelf_pos, - velocity = {x=x, y=2-y, z=z}, - acceleration = {x=0, y=-2.2, z=0}, + velocity = {x = x, y = 2 - y, z = z}, + acceleration = {x = 0, y = -2.2, z = 0}, expirationtime = 1, size = 1.5, glow = 5, - texture = "xdecor_glyph"..random(1,18)..".png" + texture = "xdecor_glyph" .. random(1,18) .. ".png" }) end + return true end xdecor.register("enchantment_table", { - description = "Enchantment Table", - tiles = {"xdecor_enchantment_top.png", "xdecor_enchantment_bottom.png", - "xdecor_enchantment_side.png", "xdecor_enchantment_side.png", - "xdecor_enchantment_side.png", "xdecor_enchantment_side.png"}, - groups = {cracky=1, level=1}, + description = S("Enchantment Table"), + tiles = { + "xdecor_enchantment_top.png", "xdecor_enchantment_bottom.png", + "xdecor_enchantment_side.png", "xdecor_enchantment_side.png", + "xdecor_enchantment_side.png", "xdecor_enchantment_side.png" + }, + groups = {cracky = 1, level = 1}, light_source = 6, sounds = default.node_sound_stone_defaults(), on_rotate = screwdriver.rotate_simple, @@ -204,7 +238,9 @@ xdecor.register("enchantment_table", { on_metadata_inventory_put = enchanting.on_put, on_metadata_inventory_take = enchanting.on_take, allow_metadata_inventory_put = enchanting.put, - allow_metadata_inventory_move = function() return 0 end + allow_metadata_inventory_move = function() + return 0 + end, }) minetest.register_entity("xdecor:book_open", { @@ -214,8 +250,8 @@ minetest.register_entity("xdecor:book_open", { physical = false, textures = {"xdecor_book_open.png"}, on_activate = function(self) - local pos = self.object:getpos() - local pos_under = {x=pos.x, y=pos.y-1, z=pos.z} + local pos = self.object:get_pos() + local pos_under = {x = pos.x, y = pos.y - 1, z = pos.z} if minetest.get_node(pos_under).name ~= "xdecor:enchantment_table" then self.object:remove() @@ -227,7 +263,7 @@ function enchanting:register_tools(mod, def) for tool in pairs(def.tools) do for material in def.materials:gmatch("[%w_]+") do for enchant in def.tools[tool].enchants:gmatch("[%w_]+") do - local original_tool = minetest.registered_tools[mod..":"..tool.."_"..material] + local original_tool = reg_tools[mod .. ":" .. tool .. "_" .. material] if not original_tool then break end local original_toolcaps = original_tool.tool_capabilities @@ -251,12 +287,13 @@ function enchanting:register_tools(mod, def) fleshy = fleshy + enchanting.damages end - minetest.register_tool(":"..mod..":enchanted_"..tool.."_"..material.."_"..enchant, { - description = "Enchanted "..cap(material).." "..cap(tool).. - self:get_tooltip(enchant, original_groupcaps[group], fleshy), - inventory_image = original_tool.inventory_image.."^[colorize:violet:50", + minetest.register_tool(":" .. mod .. ":enchanted_" .. tool .. "_" .. material .. "_" .. enchant, { + description = S("Enchanted @1 @2 @3", + def.material_desc[material] or cap(material), def.tools[tool].desc or cap(tool), + self:get_tooltip(enchant, original_groupcaps[group], fleshy)), + inventory_image = original_tool.inventory_image .. "^[colorize:violet:50", wield_image = original_tool.wield_image, - groups = {not_in_creative_inventory=1}, + groups = {not_in_creative_inventory = 1}, tool_capabilities = { groupcaps = groupcaps, damage_groups = {fleshy = fleshy}, full_punch_interval = full_punch_interval, @@ -271,12 +308,13 @@ end enchanting:register_tools("default", { materials = "steel, bronze, mese, diamond", + material_desc = {steel = S("Steel"), bronze = S("Bronze"), mese = S("Mese"), diamond = S("Diamond")}, tools = { - axe = {enchants = "durable, fast"}, - pick = {enchants = "durable, fast"}, - shovel = {enchants = "durable, fast"}, - sword = {enchants = "sharp"} - } + axe = {enchants = "durable, fast", desc = S("Axe")}, + pick = {enchants = "durable, fast", desc = S("Pickaxe")}, + shovel = {enchants = "durable, fast", desc = S("Shovel")}, + sword = {enchants = "sharp", desc = S("Sword")} + }, }) -- Recipes @@ -288,4 +326,4 @@ minetest.register_craft({ {"default:diamond", "default:obsidian", "default:diamond"}, {"default:obsidian", "default:obsidian", "default:obsidian"} } -}) \ No newline at end of file +}) diff --git a/xdecor/src/hive.lua b/xdecor/src/hive.lua index eb52901..2aa9910 100644 --- a/xdecor/src/hive.lua +++ b/xdecor/src/hive.lua @@ -1,22 +1,24 @@ local hive = {} +local S = minetest.get_translator("xdecor") +local FS = function(...) return minetest.formspec_escape(S(...)) end local honey_max = 16 function hive.construct(pos) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() - local formspec = [[ size[8,5;] - label[0.5,0;Bees are busy making honey...] - image[6,0;1,1;hive_bee.png] - image[5,0;1,1;hive_layout.png] - list[context;honey;5,0;1,1;] - list[current_player;main;0,1.35;8,4;] + local formspec = "size[8,6;]" + .."label[0.5,0;"..FS("Bees are busy making honey…").."]" + ..[[ image[6,1;1,1;hive_bee.png] + image[5,1;1,1;hive_layout.png] + list[context;honey;5,1;1,1;] + list[current_player;main;0,2.35;8,4;] listring[current_player;main] - listring[context;honey] ]] - ..xbg..default.get_hotbar_bg(0,1.35) + listring[context;honey] ]] .. + xbg .. default.get_hotbar_bg(0,2.35) meta:set_string("formspec", formspec) - meta:set_string("infotext", "Artificial Hive") + meta:set_string("infotext", S("Artificial Hive")) inv:set_size("honey", 1) local timer = minetest.get_node_timer(pos) @@ -25,7 +27,9 @@ end function hive.timer(pos) local time = (minetest.get_timeofday() or 0) * 24000 - if time < 5500 or time > 18500 then return true end + if time < 5500 or time > 18500 then + return true + end local inv = minetest.get_meta(pos):get_inventory() local honeystack = inv:get_stack("honey", 1) @@ -40,27 +44,35 @@ function hive.timer(pos) inv:add_item("honey", "xdecor:honey") elseif honey == honey_max then local timer = minetest.get_node_timer(pos) - timer:stop() return true + timer:stop() + return true end + return true end xdecor.register("hive", { - description = "Artificial Hive", + description = S("Artificial Hive"), tiles = {"xdecor_hive_top.png", "xdecor_hive_top.png", "xdecor_hive_side.png", "xdecor_hive_side.png", "xdecor_hive_side.png", "xdecor_hive_front.png"}, groups = {choppy=3, oddly_breakable_by_hand=2, flammable=1}, on_construct = hive.construct, on_timer = hive.timer, + can_dig = function(pos) local inv = minetest.get_meta(pos):get_inventory() return inv:is_empty("honey") end, + on_punch = function(_, _, puncher) puncher:set_hp(puncher:get_hp() - 2) end, - allow_metadata_inventory_put = function() return 0 end, + + allow_metadata_inventory_put = function() + return 0 + end, + on_metadata_inventory_take = function(pos, _, _, stack) if stack:get_count() == honey_max then local timer = minetest.get_node_timer(pos) @@ -72,11 +84,16 @@ xdecor.register("hive", { -- Craft items minetest.register_craftitem("xdecor:honey", { - description = "Honey", + description = S("Honey"), inventory_image = "xdecor_honey.png", wield_image = "xdecor_honey.png", - groups = {food_honey = 1, food_sugar = 1, flammable = 2, not_in_creative_inventory=1}, - on_use = minetest.item_eat(2) + on_use = minetest.item_eat(2), + groups = { + food_honey = 1, + food_sugar = 1, + flammable = 2, + not_in_creative_inventory = 1, + }, }) -- Recipes diff --git a/xdecor/src/itemframe.lua b/xdecor/src/itemframe.lua index 5253224..38dcc0a 100644 --- a/xdecor/src/itemframe.lua +++ b/xdecor/src/itemframe.lua @@ -1,4 +1,5 @@ local itemframe, tmp = {}, {} +local S = minetest.get_translator("xdecor") screwdriver = screwdriver or {} local function remove_item(pos, node) @@ -6,15 +7,18 @@ local function remove_item(pos, node) if not objs then return end for _, obj in pairs(objs) do - if obj and obj:get_luaentity() and - obj:get_luaentity().name == "xdecor:f_item" then + local ent = obj:get_luaentity() + if obj and ent and ent.name == "xdecor:f_item" then obj:remove() break end end end local facedir = { - [0] = {x=0, y=0, z=1}, {x=1, y=0, z=0}, {x=0, y=0, z=-1}, {x=-1, y=0, z=0} + [0] = {x = 0, y = 0, z = 1}, + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}, + {x = -1, y = 0, z = 0} } local function update_item(pos, node) @@ -29,8 +33,8 @@ local function update_item(pos, node) tmp.texture = ItemStack(itemstring):get_name() local entity = minetest.add_entity(pos, "xdecor:f_item") - local yaw = math.pi*2 - node.param2 * math.pi/2 - entity:setyaw(yaw) + local yaw = (math.pi * 2) - node.param2 * (math.pi / 2) + entity:set_yaw(yaw) local timer = minetest.get_node_timer(pos) timer:start(15.0) @@ -53,7 +57,7 @@ function itemframe.after_place(pos, placer, itemstack) local meta = minetest.get_meta(pos) local name = placer:get_player_name() meta:set_string("owner", name) - meta:set_string("infotext", "Item Frame (owned by "..name..")") + meta:set_string("infotext", S("@1 (owned by @2)", S("Item Frame"), name)) end function itemframe.timer(pos) @@ -64,6 +68,7 @@ function itemframe.timer(pos) if num == 0 and meta:get_string("item") ~= "" then update_item(pos, node) end + return true end @@ -81,7 +86,11 @@ function itemframe.rightclick(pos, node, clicker, itemstack) local itemstring = itemstack:take_item():to_string() meta:set_string("item", itemstring) update_item(pos, node) - + if itemstring == "" then + meta:set_string("infotext", S("@1 (owned by @2)", S("Item Frame"), owner)) + else + meta:set_string("infotext", S("@1 (owned by @2)", itemstring, owner)) + end return itemstack end @@ -91,8 +100,9 @@ function itemframe.punch(pos, node, puncher) local owner = meta:get_string("owner") local admin = minetest.check_player_privs(player_name, "protection_bypass") - if not admin and player_name ~= owner then return end - drop_item(pos, node) + if admin and player_name == owner then + drop_item(pos, node) + end end function itemframe.dig(pos, player) @@ -106,15 +116,17 @@ function itemframe.dig(pos, player) end xdecor.register("itemframe", { - description = "Item Frame", - groups = {choppy=3, oddly_breakable_by_hand=2, flammable=3}, + description = S("Item Frame"), + groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3}, sounds = default.node_sound_wood_defaults(), on_rotate = screwdriver.disallow, sunlight_propagates = true, inventory_image = "xdecor_itemframe.png", node_box = xdecor.nodebox.slab_z(0.9375), - tiles = {"xdecor_wood.png", "xdecor_wood.png", "xdecor_wood.png", - "xdecor_wood.png", "xdecor_wood.png", "xdecor_itemframe.png"}, + tiles = { + "xdecor_wood.png", "xdecor_wood.png", "xdecor_wood.png", + "xdecor_wood.png", "xdecor_wood.png", "xdecor_itemframe.png" + }, after_place_node = itemframe.after_place, on_timer = itemframe.timer, on_rightclick = itemframe.rightclick, @@ -125,12 +137,12 @@ xdecor.register("itemframe", { minetest.register_entity("xdecor:f_item", { visual = "wielditem", - visual_size = {x=0.33, y=0.33}, + visual_size = {x = 0.33, y = 0.33}, collisionbox = {0}, physical = false, textures = {"air"}, on_activate = function(self, staticdata) - local pos = self.object:getpos() + local pos = self.object:get_pos() if minetest.get_node(pos).name ~= "xdecor:itemframe" then self.object:remove() end @@ -148,13 +160,16 @@ minetest.register_entity("xdecor:f_item", { end end if self.texture then - self.object:set_properties({textures={self.texture}}) + self.object:set_properties({ + textures = {self.texture} + }) end end, get_staticdata = function(self) if self.nodename and self.texture then - return self.nodename..";"..self.texture + return self.nodename .. ";" .. self.texture end + return "" end }) @@ -168,4 +183,4 @@ minetest.register_craft({ {"group:stick", "default:paper", "group:stick"}, {"group:stick", "group:stick", "group:stick"} } -}) \ No newline at end of file +}) diff --git a/xdecor/src/mailbox.lua b/xdecor/src/mailbox.lua index 5c2dcd2..78a3ed3 100644 --- a/xdecor/src/mailbox.lua +++ b/xdecor/src/mailbox.lua @@ -1,18 +1,28 @@ local mailbox = {} screwdriver = screwdriver or {} +local S = minetest.get_translator("xdecor") +local FS = function(...) return minetest.formspec_escape(S(...)) end local function get_img(img) + if not img then return end local img_name = img:match("(.*)%.png") - if img_name then return img_name..".png" end + + if img_name then + return img_name .. ".png" + end end local function img_col(stack) local def = minetest.registered_items[stack] - if not def then return "" end + if not def then + return "" + end if def.inventory_image ~= "" then local img = get_img(def.inventory_image) - if img then return img end + if img then + return img + end end if def.tiles then @@ -22,53 +32,58 @@ local function img_col(stack) elseif type(tile) == "string" then img = get_img(tile) end - if img then return img end + + if img then + return img + end end return "" end function mailbox:formspec(pos, owner, is_owner) - local spos = pos.x..","..pos.y..","..pos.z + local spos = pos.x .. "," .. pos.y .. "," .. pos.z local meta = minetest.get_meta(pos) local giver, img = "", "" if is_owner then for i = 1, 7 do - local giving = meta:get_string("giver"..i) + local giving = meta:get_string("giver" .. i) if giving ~= "" then - local stack = meta:get_string("stack"..i) + local stack = meta:get_string("stack" .. i) local giver_name = giving:sub(1,12) local stack_name = stack:match("[%w_:]+") local stack_count = stack:match("%s(%d+)") or 1 - giver = giver.."#FFFF00,"..giver_name..","..i.. - ",#FFFFFF,x "..stack_count.."," - img = img..i.."=".. - img_col(stack_name).."^\\[resize:16x16," + giver = giver .. "#FFFF00," .. giver_name .. "," .. i .. + ",#FFFFFF,x " .. stack_count .. "," + + img = img .. i .. "=" .. + img_col(stack_name) .. "^\\[resize:16x16," end end - return [[ size[9.5,9] - label[0,0;Mailbox] - label[6,0;Last donators] - box[6,0.72;3.3,3.5;#555555] + return "size[9.5,9]" + .."label[0,0;"..FS("Mailbox").."]" + .."label[6,0;"..FS("Last donators").."]" + ..[[ box[6,0.72;3.3,3.5;#555555] listring[current_player;main] list[current_player;main;0.75,5.25;8,4;] - tableoptions[background=#00000000;highlight=#00000000;border=false] ]].. - "tablecolumns[color;text;image,"..img.."0;color;text]".. - "table[6,0.75;3.3,4;givers;"..giver.."]".. - "list[nodemeta:"..spos..";mailbox;0,0.75;6,4;]".. - "listring[nodemeta:"..spos..";mailbox]".. - xbg..default.get_hotbar_bg(0.75,5.25) + tableoptions[background=#00000000;highlight=#00000000;border=false] ]] .. + "tablecolumns[color;text;image," .. img .. "0;color;text]" .. + "table[6,0.75;3.3,4;givers;" .. giver .. "]" .. + "list[nodemeta:" .. spos .. ";mailbox;0,0.75;6,4;]" .. + "listring[nodemeta:" .. spos .. ";mailbox]" .. + xbg .. default.get_hotbar_bg(0.75, 5.25) end - return [[ size[8,5] - list[current_player;main;0,1.25;8,4;] ]].. - "label[0,0;Send your goods to\n".. + + return "size[8,5]" .. + "list[current_player;main;0,1.25;8,4;]" .. + "label[0,0;"..FS("Send your goods to\n@1", (minetest.colorize and - minetest.colorize("#FFFF00", owner) or owner).."]".. - "list[nodemeta:"..spos..";drop;3.5,0;1,1;]".. - xbg..default.get_hotbar_bg(0,1.25) + minetest.colorize("#FFFF00", owner) or owner)) .. "]" .. + "list[nodemeta:" .. spos .. ";drop;3.5,0;1,1;]" .. + xbg .. default.get_hotbar_bg(0, 1.25) end function mailbox.dig(pos, player) @@ -85,10 +100,10 @@ function mailbox.after_place_node(pos, placer) local player_name = placer:get_player_name() meta:set_string("owner", player_name) - meta:set_string("infotext", player_name.."'s Mailbox") + meta:set_string("infotext", S("@1's Mailbox", player_name)) local inv = meta:get_inventory() - inv:set_size("mailbox", 6*4) + inv:set_size("mailbox", 6 * 4) inv:set_size("drop", 1) end @@ -97,8 +112,9 @@ function mailbox.rightclick(pos, node, clicker, itemstack, pointed_thing) local player = clicker:get_player_name() local owner = meta:get_string("owner") - minetest.show_formspec(player, "xdecor:mailbox", mailbox:formspec(pos, - owner, (player == owner))) + minetest.show_formspec(player, "xdecor:mailbox", + mailbox:formspec(pos, owner, (player == owner))) + return itemstack end @@ -109,9 +125,10 @@ function mailbox.put(pos, listname, _, stack, player) return -1 else minetest.chat_send_player(player:get_player_name(), - "The mailbox is full") + S("The mailbox is full.")) end end + return 0 end @@ -124,8 +141,8 @@ function mailbox.on_put(pos, listname, _, stack, player) inv:add_item("mailbox", stack) for i = 7, 2, -1 do - meta:set_string("giver"..i, meta:get_string("giver"..(i-1))) - meta:set_string("stack"..i, meta:get_string("stack"..(i-1))) + meta:set_string("giver" .. i, meta:get_string("giver" .. (i - 1))) + meta:set_string("stack" .. i, meta:get_string("stack" .. (i - 1))) end meta:set_string("giver1", player:get_player_name()) @@ -139,6 +156,7 @@ function mailbox.allow_take(pos, listname, index, stack, player) if player:get_player_name() ~= meta:get_string("owner") then return 0 end + return stack:get_count() end @@ -147,11 +165,11 @@ function mailbox.allow_move(pos) end xdecor.register("mailbox", { - description = "Mailbox", + description = S("Mailbox"), tiles = {"xdecor_mailbox_top.png", "xdecor_mailbox_bottom.png", "xdecor_mailbox_side.png", "xdecor_mailbox_side.png", "xdecor_mailbox.png", "xdecor_mailbox.png"}, - groups = {cracky=3, oddly_breakable_by_hand=1}, + groups = {cracky = 3, oddly_breakable_by_hand = 1}, on_rotate = screwdriver.rotate_simple, can_dig = mailbox.dig, on_rightclick = mailbox.rightclick, @@ -171,4 +189,4 @@ minetest.register_craft({ {"dye:red", "default:paper", "dye:red"}, {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"} } -}) \ No newline at end of file +}) diff --git a/xdecor/src/mechanisms.lua b/xdecor/src/mechanisms.lua index b065c90..328f503 100644 --- a/xdecor/src/mechanisms.lua +++ b/xdecor/src/mechanisms.lua @@ -5,21 +5,24 @@ minetest.setting_set("nodetimer_interval", 0.1) local plate = {} screwdriver = screwdriver or {} +local S = minetest.get_translator("xdecor") + local function door_toggle(pos_actuator, pos_door, player) local player_name = player:get_player_name() local actuator = minetest.get_node(pos_actuator) local door = doors.get(pos_door) + if not door then return end if actuator.name:sub(-4) == "_off" then minetest.set_node(pos_actuator, - {name=actuator.name:gsub("_off", "_on"), param2=actuator.param2}) + {name = actuator.name:gsub("_off", "_on"), param2 = actuator.param2}) end door:open(player) minetest.after(2, function() if minetest.get_node(pos_actuator).name:sub(-3) == "_on" then minetest.set_node(pos_actuator, - {name=actuator.name, param2=actuator.param2}) + {name = actuator.name, param2 = actuator.param2}) end -- Re-get player object (or nil) because 'player' could -- be an invalid object at this time (player left) @@ -35,25 +38,27 @@ end function plate.timer(pos) local objs = minetest.get_objects_inside_radius(pos, 0.8) if not next(objs) or not doors.get then return true end - local minp = {x=pos.x-2, y=pos.y, z=pos.z-2} - local maxp = {x=pos.x+2, y=pos.y, z=pos.z+2} + + local minp = {x = pos.x - 2, y = pos.y, z = pos.z - 2} + local maxp = {x = pos.x + 2, y = pos.y, z = pos.z + 2} local doors = minetest.find_nodes_in_area(minp, maxp, "group:door") for _, player in pairs(objs) do if player:is_player() then - for i=1, #doors do + for i = 1, #doors do door_toggle(pos, doors[i], player) end break end end + return true end function plate.register(material, desc, def) - xdecor.register("pressure_"..material.."_off", { - description = desc.." Pressure Plate", - tiles = {"xdecor_pressure_"..material..".png"}, + xdecor.register("pressure_" .. material .. "_off", { + description = def.description or (desc .. " Pressure Plate"), + tiles = {"xdecor_pressure_" .. material .. ".png"}, drawtype = "nodebox", node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 1, 14}}), groups = def.groups, @@ -63,13 +68,13 @@ function plate.register(material, desc, def) on_construct = plate.construct, on_timer = plate.timer }) - xdecor.register("pressure_"..material.."_on", { - tiles = {"xdecor_pressure_"..material..".png"}, + xdecor.register("pressure_" .. material .. "_on", { + tiles = {"xdecor_pressure_" .. material .. ".png"}, drawtype = "nodebox", node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 0.4, 14}}), groups = def.groups, sounds = def.sounds, - drop = "xdecor:pressure_"..material.."_off", + drop = "xdecor:pressure_" .. material .. "_off", sunlight_propagates = true, on_rotate = screwdriver.rotate_simple }) @@ -77,32 +82,36 @@ end plate.register("wood", "Wooden", { sounds = default.node_sound_wood_defaults(), - groups = {choppy=3, oddly_breakable_by_hand=2, flammable=2} + groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2}, + description = S("Wooden Pressure Plate"), }) plate.register("stone", "Stone", { sounds = default.node_sound_stone_defaults(), - groups = {cracky=3, oddly_breakable_by_hand=2} + groups = {cracky = 3, oddly_breakable_by_hand = 2}, + description = S("Stone Pressure Plate"), }) xdecor.register("lever_off", { - description = "Lever", + description = S("Lever"), tiles = {"xdecor_lever_off.png"}, drawtype = "nodebox", node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}), - groups = {cracky=3, oddly_breakable_by_hand=2}, + groups = {cracky = 3, oddly_breakable_by_hand = 2}, sounds = default.node_sound_stone_defaults(), sunlight_propagates = true, on_rotate = screwdriver.rotate_simple, + on_rightclick = function(pos, node, clicker, itemstack) if not doors.get then return itemstack end - local minp = {x=pos.x-2, y=pos.y-1, z=pos.z-2} - local maxp = {x=pos.x+2, y=pos.y+1, z=pos.z+2} + local minp = {x = pos.x - 2, y = pos.y - 1, z = pos.z - 2} + local maxp = {x = pos.x + 2, y = pos.y + 1, z = pos.z + 2} local doors = minetest.find_nodes_in_area(minp, maxp, "group:door") - for i=1, #doors do + for i = 1, #doors do door_toggle(pos, doors[i], clicker) end + return itemstack end }) @@ -111,7 +120,7 @@ xdecor.register("lever_on", { tiles = {"xdecor_lever_on.png"}, drawtype = "nodebox", node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}), - groups = {cracky=3, oddly_breakable_by_hand=2, not_in_creative_inventory=1}, + groups = {cracky = 3, oddly_breakable_by_hand = 2, not_in_creative_inventory = 1}, sounds = default.node_sound_stone_defaults(), sunlight_propagates = true, on_rotate = screwdriver.rotate_simple, @@ -138,4 +147,4 @@ minetest.register_craft({ {"group:stick"}, {"group:stone"} } -}) \ No newline at end of file +}) diff --git a/xdecor/src/nodes.lua b/xdecor/src/nodes.lua index 20bd72e..f4dd20c 100644 --- a/xdecor/src/nodes.lua +++ b/xdecor/src/nodes.lua @@ -1,146 +1,177 @@ screwdriver = screwdriver or {} +local S = minetest.get_translator("xdecor") local function register_pane(name, desc, def) xpanes.register_pane(name, { description = desc, - tiles = {"xdecor_"..name..".png"}, + tiles = {"xdecor_" .. name .. ".png"}, drawtype = "airlike", paramtype = "light", - textures = {"xdecor_"..name..".png", "xdecor_"..name..".png", "xpanes_space.png"}, - inventory_image = "xdecor_"..name..".png", - wield_image = "xdecor_"..name..".png", + textures = {"xdecor_" .. name .. ".png", "" ,"xdecor_" .. name .. ".png"}, + inventory_image = "xdecor_" .. name .. ".png", + wield_image = "xdecor_" .. name .. ".png", groups = def.groups, sounds = def.sounds or default.node_sound_defaults(), recipe = def.recipe }) end -register_pane("bamboo_frame", "Bamboo Frame", { - groups = {choppy=3, oddly_breakable_by_hand=2, pane=1, flammable=2}, - recipe = {{"default:papyrus", "default:papyrus", "default:papyrus"}, - {"default:papyrus", "farming:cotton", "default:papyrus"}, - {"default:papyrus", "default:papyrus", "default:papyrus"}} +register_pane("bamboo_frame", S("Bamboo Frame"), { + groups = {choppy = 3, oddly_breakable_by_hand = 2, pane = 1, flammable = 2}, + recipe = { + {"default:papyrus", "default:papyrus", "default:papyrus"}, + {"default:papyrus", "farming:cotton", "default:papyrus"}, + {"default:papyrus", "default:papyrus", "default:papyrus"} + } }) -register_pane("chainlink", "Chainlink", { - groups = {cracky=3, oddly_breakable_by_hand=2, pane=1}, - recipe = {{"default:steel_ingot", "", "default:steel_ingot"}, - {"", "default:steel_ingot", ""}, - {"default:steel_ingot", "", "default:steel_ingot"}} +register_pane("chainlink", S("Chainlink"), { + groups = {cracky = 3, oddly_breakable_by_hand = 2, pane = 1}, + recipe = { + {"default:steel_ingot", "", "default:steel_ingot"}, + {"", "default:steel_ingot", ""}, + {"default:steel_ingot", "", "default:steel_ingot"} + } }) -register_pane("rusty_bar", "Rusty Iron Bars", { +register_pane("rusty_bar", S("Rusty Iron Bars"), { sounds = default.node_sound_stone_defaults(), - groups = {cracky=2, pane=1}, - recipe = {{"", "default:dirt", ""}, - {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, - {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}} + groups = {cracky = 2, pane = 1}, + recipe = { + {"", "default:dirt", ""}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"} + } }) -register_pane("wood_frame", "Wood Frame", { +register_pane("wood_frame", S("Wood Frame"), { sounds = default.node_sound_wood_defaults(), - groups = {choppy=2, pane=1, flammable=2}, - recipe = {{"group:wood", "group:stick", "group:wood"}, - {"group:stick", "group:stick", "group:stick"}, - {"group:wood", "group:stick", "group:wood"}} + groups = {choppy = 2, pane = 1, flammable = 2}, + recipe = { + {"group:wood", "group:stick", "group:wood"}, + {"group:stick", "group:stick", "group:stick"}, + {"group:wood", "group:stick", "group:wood"} + } }) xdecor.register("baricade", { - description = "Baricade", + description = S("Baricade"), drawtype = "plantlike", paramtype2 = "facedir", inventory_image = "xdecor_baricade.png", tiles = {"xdecor_baricade.png"}, - groups = {choppy=2, oddly_breakable_by_hand=1, flammable=2}, + groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, damage_per_second = 4, selection_box = xdecor.nodebox.slab_y(0.3), collision_box = xdecor.pixelbox(2, {{0, 0, 1, 2, 2, 0}}) }) xdecor.register("barrel", { - description = "Barrel", + description = S("Barrel"), tiles = {"xdecor_barrel_top.png", "xdecor_barrel_top.png", "xdecor_barrel_sides.png"}, on_place = minetest.rotate_node, - groups = {choppy=2, oddly_breakable_by_hand=1, flammable=2}, + groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, sounds = default.node_sound_wood_defaults() }) local function register_storage(name, desc, def) xdecor.register(name, { description = desc, - inventory = {size=def.inv_size or 24}, + inventory = {size = def.inv_size or 24}, infotext = desc, tiles = def.tiles, node_box = def.node_box, on_rotate = def.on_rotate, on_place = def.on_place, - groups = def.groups or {choppy=2, oddly_breakable_by_hand=1, flammable=2}, + groups = def.groups or {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, sounds = default.node_sound_wood_defaults() }) end -register_storage("cabinet", "Wooden Cabinet", { +register_storage("cabinet", S("Wooden Cabinet"), { on_rotate = screwdriver.rotate_simple, - tiles = {"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", - "xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", - "xdecor_cabinet_sides.png", "xdecor_cabinet_front.png"} + tiles = { + "xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", + "xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", + "xdecor_cabinet_sides.png", "xdecor_cabinet_front.png" + } }) -register_storage("cabinet_half", "Half Wooden Cabinet", { +register_storage("cabinet_half", S("Half Wooden Cabinet"), { inv_size = 8, node_box = xdecor.nodebox.slab_y(0.5, 0.5), on_rotate = screwdriver.rotate_simple, - tiles = {"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", - "xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_sides.png", - "xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_front.png"} + tiles = { + "xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png", + "xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_sides.png", + "xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_front.png" + } }) -register_storage("empty_shelf", "Empty Shelf", { - on_rotate = screwdriver.rotate_simple, - tiles = {"default_wood.png", "default_wood.png", "default_wood.png", - "default_wood.png", "default_wood.png^xdecor_empty_shelf.png"} -}) +if minetest.get_modpath("moreblocks") then + minetest.register_alias("xdecor:empty_shelf", "moreblocks:empty_shelf") +else + register_storage("empty_shelf", S("Empty Shelf"), { + on_rotate = screwdriver.rotate_simple, + tiles = { + "default_wood.png", "default_wood.png", "default_wood.png", + "default_wood.png", "default_wood.png^xdecor_empty_shelf.png" + } + }) +end -register_storage("multishelf", "Multi Shelf", { +register_storage("multishelf", S("Multi Shelf"), { on_rotate = screwdriver.rotate_simple, - tiles = {"default_wood.png", "default_wood.png", "default_wood.png", - "default_wood.png", "default_wood.png^xdecor_multishelf.png"}, + tiles = { + "default_wood.png", "default_wood.png", "default_wood.png", + "default_wood.png", "default_wood.png^xdecor_multishelf.png" + }, }) xdecor.register("candle", { - description = "Candle", + description = S("Candle"), light_source = 12, drawtype = "torchlike", inventory_image = "xdecor_candle_inv.png", wield_image = "xdecor_candle_wield.png", paramtype2 = "wallmounted", walkable = false, - groups = {dig_immediate=3, attached_node=1}, - tiles = {{name = "xdecor_candle_floor.png", - animation = {type="vertical_frames", length=1.5}}, - {name = "xdecor_candle_floor.png", - animation = {type="vertical_frames", length=1.5}}, - {name = "xdecor_candle_wall.png", - animation = {type="vertical_frames", length=1.5}} + groups = {dig_immediate = 3, attached_node = 1}, + tiles = { + { + name = "xdecor_candle_floor.png", + animation = {type="vertical_frames", length = 1.5} + }, + { + name = "xdecor_candle_hanging.png", + animation = {type="vertical_frames", length = 1.5} + }, + { + name = "xdecor_candle_wall.png", + animation = {type="vertical_frames", length = 1.5} + } }, selection_box = { type = "wallmounted", - wall_top = {-0.25, -0.5, -0.25, 0.25, 0.1, 0.25}, + wall_top = {-0.25, -0.3, -0.25, 0.25, 0.5, 0.25}, wall_bottom = {-0.25, -0.5, -0.25, 0.25, 0.1, 0.25}, wall_side = {-0.5, -0.35, -0.15, -0.15, 0.4, 0.15} } }) xdecor.register("chair", { - description = "Chair", + description = S("Chair"), tiles = {"xdecor_wood.png"}, sounds = default.node_sound_wood_defaults(), - groups = {choppy=3, oddly_breakable_by_hand=2, flammable=2}, + groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2}, on_rotate = screwdriver.rotate_simple, node_box = xdecor.pixelbox(16, { - {3, 0, 11, 2, 16, 2}, {11, 0, 11, 2, 16, 2}, - {5, 9, 11.5, 6, 6, 1}, {3, 0, 3, 2, 6, 2}, - {11, 0, 3, 2, 6, 2}, {3, 6, 3, 10, 2, 8} + {3, 0, 11, 2, 16, 2}, + {11, 0, 11, 2, 16, 2}, + {5, 9, 11.5, 6, 6, 1}, + {3, 0, 3, 2, 6, 2}, + {11, 0, 3, 2, 6, 2}, + {3, 6, 3, 10, 2, 8} }), can_dig = xdecor.sit_dig, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) @@ -151,7 +182,7 @@ xdecor.register("chair", { }) xdecor.register("cobweb", { - description = "Cobweb", + description = S("Cobweb"), drawtype = "plantlike", tiles = {"xdecor_cobweb.png"}, inventory_image = "xdecor_cobweb.png", @@ -163,59 +194,61 @@ xdecor.register("cobweb", { liquid_range = 0, walkable = false, selection_box = {type = "regular"}, - groups = {snappy=3, liquid=3, flammable=3}, + groups = {snappy = 3, liquid = 3, flammable = 3}, sounds = default.node_sound_leaves_defaults() }) local curtain_colors = { - "red", + red = S("Red Curtain"), } -for _, c in pairs(curtain_colors) do - xdecor.register("curtain_"..c, { - description = c:gsub("^%l", string.upper).." Curtain", +for c, desc in pairs(curtain_colors) do + xdecor.register("curtain_" .. c, { + description = desc, walkable = false, tiles = {"wool_white.png"}, color = c, - inventory_image = "wool_white.png^[colorize:"..c.. + inventory_image = "wool_white.png^[colorize:" .. c .. ":170^xdecor_curtain_open_overlay.png^[makealpha:255,126,126", - wield_image = "wool_white.png^[colorize:"..c..":170", + wield_image = "wool_white.png^[colorize:" .. c .. ":170", drawtype = "signlike", paramtype2 = "colorwallmounted", - groups = {dig_immediate=3, flammable=3}, - selection_box = {type="wallmounted"}, + groups = {dig_immediate = 3, flammable = 3}, + selection_box = {type = "wallmounted"}, on_rightclick = function(pos, node, _, itemstack) - minetest.set_node(pos, {name="xdecor:curtain_open_"..c, param2=node.param2}) + minetest.set_node(pos, {name = "xdecor:curtain_open_" .. c, param2 = node.param2}) return itemstack end }) - xdecor.register("curtain_open_"..c, { + xdecor.register("curtain_open_" .. c, { tiles = {"wool_white.png^xdecor_curtain_open_overlay.png^[makealpha:255,126,126"}, color = c, drawtype = "signlike", paramtype2 = "colorwallmounted", walkable = false, - groups = {dig_immediate=3, flammable=3, not_in_creative_inventory=1}, + groups = {dig_immediate = 3, flammable = 3, not_in_creative_inventory = 1}, selection_box = {type="wallmounted"}, - drop = "xdecor:curtain_"..c, + drop = "xdecor:curtain_" .. c, on_rightclick = function(pos, node, _, itemstack) - minetest.set_node(pos, {name="xdecor:curtain_"..c, param2=node.param2}) + minetest.set_node(pos, {name="xdecor:curtain_" .. c, param2 = node.param2}) return itemstack end }) minetest.register_craft({ - output = "xdecor:curtain_"..c.." 4", - recipe = {{"", "wool:"..c, ""}, - {"", "wool:"..c, ""}} + output = "xdecor:curtain_" .. c .. " 4", + recipe = { + {"", "wool:" .. c, ""}, + {"", "wool:" .. c, ""} + } }) end xdecor.register("cushion", { - description = "Cushion", + description = S("Cushion"), tiles = {"xdecor_cushion.png"}, - groups = {snappy=3, flammable=3, fall_damage_add_percent=-50}, + groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -50}, on_place = minetest.rotate_node, node_box = xdecor.nodebox.slab_y(0.5), can_dig = xdecor.sit_dig, @@ -227,9 +260,9 @@ xdecor.register("cushion", { }) xdecor.register("cushion_block", { - description = "Cushion Block", + description = S("Cushion Block"), tiles = {"xdecor_cushion.png"}, - groups = {snappy=3, flammable=3, fall_damage_add_percent=-75, not_in_creative_inventory=1} + groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -75, not_in_creative_inventory = 1} }) local function door_access(name) @@ -238,49 +271,98 @@ end local xdecor_doors = { japanese = { - {"group:wood", "default:paper"}, - {"default:paper", "group:wood"}, - {"group:wood", "default:paper"} }, + recipe = { + {"group:wood", "default:paper"}, + {"default:paper", "group:wood"}, + {"group:wood", "default:paper"} + }, + desc = S("Japanese Door"), + }, prison = { - {"xpanes:bar_flat", "xpanes:bar_flat",}, - {"xpanes:bar_flat", "xpanes:bar_flat",}, - {"xpanes:bar_flat", "xpanes:bar_flat"} }, + recipe = { + {"xpanes:bar_flat", "xpanes:bar_flat",}, + {"xpanes:bar_flat", "xpanes:bar_flat",}, + {"xpanes:bar_flat", "xpanes:bar_flat"} + }, + desc = S("Prison Door"), + }, rusty_prison = { - {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",}, - {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",}, - {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat"} }, + recipe = { + {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",}, + {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",}, + {"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat"} + }, + desc = S("Rusty Prison Door"), + }, screen = { - {"group:wood", "group:wood"}, - {"xpanes:chainlink_flat", "xpanes:chainlink_flat"}, - {"group:wood", "group:wood"} }, + recipe = { + {"group:wood", "group:wood"}, + {"xpanes:chainlink_flat", "xpanes:chainlink_flat"}, + {"group:wood", "group:wood"} + }, + desc = S("Screen Door"), + }, slide = { - {"default:paper", "default:paper"}, - {"default:paper", "default:paper"}, - {"group:wood", "group:wood"} }, + recipe = { + {"default:paper", "default:paper"}, + {"default:paper", "default:paper"}, + {"group:wood", "group:wood"} + }, + desc = S("Slide Door"), + }, woodglass = { - {"default:glass", "default:glass"}, - {"group:wood", "group:wood"}, - {"group:wood", "group:wood"} } + recipe = { + {"default:glass", "default:glass"}, + {"group:wood", "group:wood"}, + {"group:wood", "group:wood"} + }, + desc = S("Woodglass Door"), + }, } -for name, recipe in pairs(xdecor_doors) do +local mesecons_register + +if minetest.global_exists("mesecon") then + mesecons_register = { effector = { + action_on = function(pos, node) + local door = doors.get(pos) + if door then + door:open() + end + end, + action_off = function(pos, node) + local door = doors.get(pos) + if door then + door:close() + end + end, + rules = mesecon.rules.pplate + }} +end + +for name, def in pairs(xdecor_doors) do if not doors.register then break end - doors.register(name.."_door", { - tiles = {{name = "xdecor_"..name.."_door.png", backface_culling=true}}, - description = name:gsub("%f[%w]%l", string.upper):gsub("_", " ").." Door", - inventory_image = "xdecor_"..name.."_door_inv.png", + doors.register(name .. "_door", { + tiles = { + {name = "xdecor_" .. name .. "_door.png", backface_culling = true} + }, + description = def.desc, + inventory_image = "xdecor_" .. name .. "_door_inv.png", protected = door_access(name), - groups = {choppy=2, cracky=2, oddly_breakable_by_hand=1, door=1}, - recipe = recipe + groups = {choppy = 2, cracky = 2, oddly_breakable_by_hand = 1, door = 1}, + recipe = def.recipe, + mesecons = mesecons_register, }) end xdecor.register("enderchest", { - description = "Ender Chest", - tiles = {"xdecor_enderchest_top.png", "xdecor_enderchest_top.png", - "xdecor_enderchest_side.png", "xdecor_enderchest_side.png", - "xdecor_enderchest_side.png", "xdecor_enderchest_front.png"}, - groups = {cracky=1, choppy=1}, + description = S("Ender Chest"), + tiles = { + "xdecor_enderchest_top.png", "xdecor_enderchest_top.png", + "xdecor_enderchest_side.png", "xdecor_enderchest_side.png", + "xdecor_enderchest_side.png", "xdecor_enderchest_front.png" + }, + groups = {cracky = 1, choppy = 1}, sounds = default.node_sound_stone_defaults(), on_rotate = screwdriver.rotate_simple, on_construct = function(pos) @@ -290,8 +372,9 @@ xdecor.register("enderchest", { list[current_player;main;0,5;8,4;] listring[current_player;enderchest] listring[current_player;main] ]] - ..xbg..default.get_hotbar_bg(0,5)) - meta:set_string("infotext", "Ender Chest") + .. xbg .. default.get_hotbar_bg(0,5)) + + meta:set_string("infotext", S("Ender Chest")) end }) @@ -301,11 +384,11 @@ minetest.register_on_joinplayer(function(player) end) xdecor.register("ivy", { - description = "Ivy", + description = S("Ivy"), drawtype = "signlike", walkable = false, climbable = true, - groups = {snappy=3, flora=1, attached_node=1, plant=1, flammable=3}, + groups = {snappy = 3, flora = 1, attached_node = 1, plant = 1, flammable = 3}, paramtype2 = "wallmounted", selection_box = {type="wallmounted"}, tiles = {"xdecor_ivy.png"}, @@ -314,46 +397,76 @@ xdecor.register("ivy", { sounds = default.node_sound_leaves_defaults() }) +xdecor.register("rooster", { + description = S("Rooster"), + drawtype = "torchlike", + inventory_image = "xdecor_rooster.png", + walkable = false, + groups = {snappy = 3, attached_node = 1}, + tiles = {"xdecor_rooster.png"}, +}) + xdecor.register("lantern", { - description = "Lantern", + description = S("Lantern"), light_source = 13, drawtype = "plantlike", inventory_image = "xdecor_lantern_inv.png", wield_image = "xdecor_lantern_inv.png", paramtype2 = "wallmounted", walkable = false, - groups = {snappy=3, attached_node=1}, - tiles = {{name="xdecor_lantern.png", animation={type="vertical_frames", length=1.5}}}, + groups = {snappy = 3, attached_node = 1}, + tiles = { + { + name = "xdecor_lantern.png", + animation = {type="vertical_frames", length = 1.5} + } + }, selection_box = xdecor.pixelbox(16, {{4, 0, 4, 8, 16, 8}}) }) -for _, l in pairs({"iron", "wooden"}) do - xdecor.register(l.."_lightbox", { - description = l:gsub("^%l", string.upper).." Light Box", - tiles = {"xdecor_"..l.."_lightbox.png"}, - groups = {cracky=3, choppy=3, oddly_breakable_by_hand=2}, +local xdecor_lightbox = { + iron = S("Iron Light Box"), + wooden = S("Wooden Light Box"), + wooden2 = S("Wooden Light Box 2"), +} + +for l, desc in pairs(xdecor_lightbox) do + xdecor.register(l .. "_lightbox", { + description = desc, + tiles = {"xdecor_" .. l .. "_lightbox.png"}, + groups = {cracky = 3, choppy = 3, oddly_breakable_by_hand = 2}, light_source = 13, sounds = default.node_sound_glass_defaults() }) end -for _, f in pairs({"dandelion_white", "dandelion_yellow", "geranium", - "rose", "tulip", "viola"}) do - xdecor.register("potted_"..f, { - description = "Potted "..f:gsub("%f[%w]%l", string.upper):gsub("_", " "), +local xdecor_potted = { + dandelion_white = S("Potted White Dandelion"), + dandelion_yellow = S("Potted Yellow Dandelion"), + geranium = S("Potted Geranium"), + rose = S("Potted Rose"), + tulip = S("Potted Tulip"), + viola = S("Potted Viola"), +} + +for f, desc in pairs(xdecor_potted) do + xdecor.register("potted_" .. f, { + description = desc, walkable = false, - groups = {snappy=3, flammable=3, plant=1, flower=1}, - tiles = {"xdecor_"..f.."_pot.png"}, - inventory_image = "xdecor_"..f.."_pot.png", + groups = {snappy = 3, flammable = 3, plant = 1, flower = 1}, + tiles = {"xdecor_" .. f .. "_pot.png"}, + inventory_image = "xdecor_" .. f .. "_pot.png", drawtype = "plantlike", sounds = default.node_sound_leaves_defaults(), selection_box = xdecor.nodebox.slab_y(0.3) }) minetest.register_craft({ - output = "xdecor:potted_"..f, - recipe = {{"default:clay_brick", "flowers:"..f, - "default:clay_brick"}, {"", "default:clay_brick", ""}} + output = "xdecor:potted_" .. f, + recipe = { + {"default:clay_brick", "flowers:" .. f, "default:clay_brick"}, + {"", "default:clay_brick", ""} + } }) end @@ -365,45 +478,52 @@ local painting_box = { } xdecor.register("painting_1", { - description = "Painting", + description = S("Painting"), tiles = {"xdecor_painting_1.png"}, inventory_image = "xdecor_painting_empty.png", wield_image = "xdecor_painting_empty.png", paramtype2 = "wallmounted", sunlight_propagates = true, - groups = {choppy=3, oddly_breakable_by_hand=2, flammable=2, attached_node=1}, + groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2, attached_node = 1}, sounds = default.node_sound_wood_defaults(), node_box = painting_box, node_placement_prediction = "", on_place = function(itemstack, placer, pointed_thing) local num = math.random(4) local leftover = minetest.item_place_node( - ItemStack("xdecor:painting_"..num), placer, pointed_thing) + ItemStack("xdecor:painting_" .. num), placer, pointed_thing) + if leftover:get_count() == 0 and not minetest.setting_getbool("creative_mode") then itemstack:take_item() end + return itemstack end }) for i = 2, 4 do - xdecor.register("painting_"..i, { - tiles = {"xdecor_painting_"..i..".png"}, + xdecor.register("painting_" .. i, { + tiles = {"xdecor_painting_" .. i .. ".png"}, paramtype2 = "wallmounted", drop = "xdecor:painting_1", sunlight_propagates = true, - groups = {choppy=3, oddly_breakable_by_hand=2, flammable=2, - attached_node=1, not_in_creative_inventory=1}, + groups = { + choppy = 3, + oddly_breakable_by_hand = 2, + flammable = 2, + attached_node = 1, + not_in_creative_inventory = 1 + }, sounds = default.node_sound_wood_defaults(), node_box = painting_box }) end xdecor.register("stonepath", { - description = "Garden Stone Path", + description = S("Garden Stone Path"), tiles = {"default_stone.png"}, - groups = {snappy=3}, + groups = {snappy = 3}, on_rotate = screwdriver.rotate_simple, sounds = default.node_sound_stone_defaults(), sunlight_propagates = true, @@ -418,32 +538,34 @@ local function register_hard_node(name, desc, def) def = def or {} xdecor.register(name, { description = desc, - tiles = {"xdecor_"..name..".png"}, - groups = def.groups or {cracky=1}, + tiles = {"xdecor_" .. name .. ".png"}, + groups = def.groups or {cracky = 1}, sounds = def.sounds or default.node_sound_stone_defaults() }) end -register_hard_node("cactusbrick", "Cactus Brick") -register_hard_node("coalstone_tile", "Coal Stone Tile") -register_hard_node("desertstone_tile", "Desert Stone Tile") -register_hard_node("hard_clay", "Hardened Clay") -register_hard_node("moonbrick", "Moon Brick") -register_hard_node("stone_tile", "Stone Tile") -register_hard_node("stone_rune", "Runestone") -register_hard_node("packed_ice", "Packed Ice", { - groups = {cracky=1, puts_out_fire=1, slippery=3}, +register_hard_node("cactusbrick", S("Cactus Brick")) +register_hard_node("coalstone_tile", S("Coal Stone Tile")) +register_hard_node("desertstone_tile", S("Desert Stone Tile")) +register_hard_node("hard_clay", S("Hardened Clay")) +register_hard_node("moonbrick", S("Moon Brick")) +register_hard_node("stone_tile", S("Stone Tile")) +register_hard_node("stone_rune", S("Runestone")) + +register_hard_node("packed_ice", S("Packed Ice"), { + groups = {cracky = 1, puts_out_fire = 1, slippery = 3}, sounds = default.node_sound_glass_defaults() }) -register_hard_node("wood_tile", "Wooden Tile", { - groups = {choppy=1, wood=1, flammable=2}, + +register_hard_node("wood_tile", S("Wooden Tile"), { + groups = {choppy = 1, wood = 1, flammable = 2}, sounds = default.node_sound_wood_defaults() }) xdecor.register("table", { - description = "Table", + description = S("Table"), tiles = {"xdecor_wood.png"}, - groups = {choppy=2, oddly_breakable_by_hand=1, flammable=2}, + groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2}, sounds = default.node_sound_wood_defaults(), node_box = xdecor.pixelbox(16, { {0, 14, 0, 16, 2, 16}, {5.5, 0, 5.5, 5, 14, 6} @@ -451,40 +573,65 @@ xdecor.register("table", { }) xdecor.register("tatami", { - description = "Tatami", + description = S("Tatami"), tiles = {"xdecor_tatami.png"}, wield_image = "xdecor_tatami.png", - groups = {snappy=3, flammable=3}, + groups = {snappy = 3, flammable = 3}, sunlight_propagates = true, node_box = xdecor.nodebox.slab_y(0.0625) }) xdecor.register("trampoline", { - description = "Trampoline", + description = S("Trampoline"), tiles = {"xdecor_trampoline.png", "mailbox_blank16.png", "xdecor_trampoline_sides.png"}, - groups = {cracky=3, oddly_breakable_by_hand=1, fall_damage_add_percent=-80, bouncy=90}, + groups = {cracky = 3, oddly_breakable_by_hand = 1, fall_damage_add_percent = -80, bouncy = 90}, node_box = xdecor.nodebox.slab_y(0.5), - sounds = {footstep = {name="xdecor_bouncy", gain=0.8}} + sounds = { + footstep = { + name = "xdecor_bouncy", + gain = 0.8 + } + } }) xdecor.register("tv", { - description = "Television", + description = S("Television"), light_source = 11, - groups = {cracky=3, oddly_breakable_by_hand=2}, + groups = {cracky = 3, oddly_breakable_by_hand = 2}, on_rotate = screwdriver.rotate_simple, - tiles = {"xdecor_television_left.png^[transformR270", - "xdecor_television_left.png^[transformR90", - "xdecor_television_left.png^[transformFX", - "xdecor_television_left.png", "xdecor_television_back.png", - {name="xdecor_television_front_animated.png", - animation = {type="vertical_frames", length=80.0}} } + tiles = { + "xdecor_television_left.png^[transformR270", + "xdecor_television_left.png^[transformR90", + "xdecor_television_left.png^[transformFX", + "xdecor_television_left.png", "xdecor_television_back.png", + { + name = "xdecor_television_front_animated.png", + animation = {type = "vertical_frames", length = 80.0} + } + } }) xdecor.register("woodframed_glass", { - description = "Wood Framed Glass", + description = S("Wood Framed Glass"), drawtype = "glasslike_framed", sunlight_propagates = true, tiles = {"xdecor_woodframed_glass.png", "xdecor_woodframed_glass_detail.png"}, - groups = {cracky=2, oddly_breakable_by_hand=1}, + groups = {cracky = 2, oddly_breakable_by_hand = 1}, sounds = default.node_sound_glass_defaults() }) + +for _, v in ipairs({"radio", "speaker"}) do + xdecor.register(v, { + description = v:gsub("^%l", string.upper), + on_rotate = screwdriver.rotate_simple, + tiles = { + "xdecor_" .. v .. "_top.png", + "xdecor_" .. v .. "_side.png", + "xdecor_" .. v .. "_side.png", + "xdecor_" .. v .. "_side.png", + "xdecor_" .. v .. "_back.png", + "xdecor_" .. v .. "_front.png", + }, + groups = {cracky = 2, not_cuttable = 1}, + }) +end diff --git a/xdecor/src/recipes.lua b/xdecor/src/recipes.lua index cb7ad19..10fd33a 100644 --- a/xdecor/src/recipes.lua +++ b/xdecor/src/recipes.lua @@ -66,9 +66,9 @@ minetest.register_craft({ minetest.register_craft({ output = "xdecor:cobweb", recipe = { - {"farming:cotton", "", "farming:cotton"}, - {"", "farming:cotton", ""}, - {"farming:cotton", "", "farming:cotton"} + {"farming:string", "", "farming:string"}, + {"", "farming:string", ""}, + {"farming:string", "", "farming:string"} } }) @@ -95,14 +95,16 @@ minetest.register_craft({ } }) -minetest.register_craft({ - output = "xdecor:empty_shelf", - recipe = { - {"group:wood", "group:wood", "group:wood"}, - {"", "", ""}, - {"group:wood", "group:wood", "group:wood"} - } -}) +if not minetest.get_modpath("moreblocks") then + minetest.register_craft({ + output = "xdecor:empty_shelf", + recipe = { + {"group:wood", "group:wood", "group:wood"}, + {"", "", ""}, + {"group:wood", "group:wood", "group:wood"} + } + }) +end minetest.register_craft({ output = "xdecor:enderchest", @@ -174,7 +176,31 @@ minetest.register_craft({ minetest.register_craft({ output = "xdecor:painting_1", recipe = { - {"default:sign_wall_wood", "dye:blue"} + {"default:sign_wall_wood", "group:dye"} + } +}) + +minetest.register_craft({ + output = "xdecor:radio", + type = "shapeless", + recipe = {"xdecor:speaker", "xdecor:speaker"} +}) + +minetest.register_craft({ + output = "xdecor:rooster", + recipe = { + {"default:gold_ingot", "", "default:gold_ingot"}, + {"", "default:gold_ingot", ""}, + {"default:gold_ingot", "", "default:gold_ingot"} + } +}) + +minetest.register_craft({ + output = "xdecor:speaker", + recipe = { + {"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"}, + {"default:copper_ingot", "", "default:copper_ingot"}, + {"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"} } }) @@ -265,3 +291,9 @@ minetest.register_craft({ } }) +minetest.register_craft({ + output = "xdecor:wooden2_lightbox", + type = "shapeless", + recipe = {"xdecor:wooden_lightbox"}, +}) + diff --git a/xdecor/src/rope.lua b/xdecor/src/rope.lua index b6d9452..4380205 100644 --- a/xdecor/src/rope.lua +++ b/xdecor/src/rope.lua @@ -1,4 +1,5 @@ local rope = {} +local S = minetest.get_translator("xdecor") -- Code by Mirko K. (modified by Temperest, Wulfsdad and kilbith) (License: GPL). function rope.place(itemstack, placer, pointed_thing) @@ -6,6 +7,7 @@ function rope.place(itemstack, placer, pointed_thing) local pos = pointed_thing.above local oldnode = minetest.get_node(pos) local stackname = itemstack:get_name() + if minetest.is_protected(pos, placer:get_player_name()) then return itemstack end @@ -18,12 +20,13 @@ function rope.place(itemstack, placer, pointed_thing) oldnode = minetest.get_node(pos) end end + return itemstack end function rope.remove(pos, oldnode, digger, rope_name) local num = 0 - local below = {x=pos.x, y=pos.y, z=pos.z} + local below = {x = pos.x, y = pos.y, z = pos.z} local digger_inv = digger:get_inventory() while minetest.get_node(below).name == rope_name do @@ -31,24 +34,28 @@ function rope.remove(pos, oldnode, digger, rope_name) below.y = below.y - 1 num = num + 1 end + if num == 0 then return end digger_inv:add_item("main", rope_name.." "..num) + return true end xdecor.register("rope", { - description = "Rope", + description = S("Rope"), drawtype = "plantlike", walkable = false, climbable = true, - groups = {snappy=3, flammable=3}, + groups = {snappy = 3, flammable = 3}, tiles = {"xdecor_rope.png"}, inventory_image = "xdecor_rope_inv.png", wield_image = "xdecor_rope_inv.png", selection_box = xdecor.pixelbox(8, {{3, 0, 3, 2, 8, 2}}), on_place = rope.place, + on_punch = function(pos, node, puncher, pointed_thing) local player_name = puncher:get_player_name() + if not minetest.is_protected(pos, player_name) or minetest.get_player_privs(player_name).protection_bypass then rope.remove(pos, node, puncher, "xdecor:rope") @@ -65,4 +72,4 @@ minetest.register_craft({ {"farming:string"}, {"farming:string"} } -}) \ No newline at end of file +}) diff --git a/xdecor/src/workbench.lua b/xdecor/src/workbench.lua index f3846b3..66567f1 100644 --- a/xdecor/src/workbench.lua +++ b/xdecor/src/workbench.lua @@ -1,121 +1,117 @@ local workbench = {} -WB = {} +local nodes = {} + screwdriver = screwdriver or {} local min, ceil = math.min, math.ceil -local registered_nodes = minetest.registered_nodes +local S = minetest.get_translator("xdecor") +local FS = function(...) return minetest.formspec_escape(S(...)) end -- Nodes allowed to be cut -- Only the regular, solid blocks without metas or explosivity can be cut -local nodes = {} -for node, def in pairs(registered_nodes) do +for node, def in pairs(minetest.registered_nodes) do if xdecor.stairs_valid_def(def) then - nodes[#nodes+1] = node + nodes[#nodes + 1] = node end end --- Optionally, you can register custom cuttable nodes in the workbench -WB.custom_nodes_register = { - -- "default:leaves", -} - -setmetatable(nodes, { - __concat = function(t1, t2) - for i=1, #t2 do - t1[#t1+1] = t2[i] - end - return t1 - end -}) - -nodes = nodes..WB.custom_nodes_register - -- Nodeboxes definitions workbench.defs = { - -- Name Yield X Y Z W H L + -- Name YieldX YZ WH L {"nanoslab", 16, { 0, 0, 0, 8, 1, 8 }}, {"micropanel", 16, { 0, 0, 0, 16, 1, 8 }}, {"microslab", 8, { 0, 0, 0, 16, 1, 16 }}, {"thinstair", 8, { 0, 7, 0, 16, 1, 8 }, - { 0, 15, 8, 16, 1, 8 }}, + { 0, 15, 8, 16, 1, 8 }}, {"cube", 4, { 0, 0, 0, 8, 8, 8 }}, {"panel", 4, { 0, 0, 0, 16, 8, 8 }}, {"slab", 2, nil }, {"doublepanel", 2, { 0, 0, 0, 16, 8, 8 }, - { 0, 8, 8, 16, 8, 8 }}, + { 0, 8, 8, 16, 8, 8 }}, {"halfstair", 2, { 0, 0, 0, 8, 8, 16 }, - { 0, 8, 8, 8, 8, 8 }}, - {"outerstair", 1, { 0, 0, 0, 16, 8, 16 }, - { 0, 8, 8, 8, 8, 8 }}, + { 0, 8, 8, 8, 8, 8 }}, + {"stair_outer", 1, nil }, {"stair", 1, nil }, - {"innerstair", 1, { 0, 0, 0, 16, 8, 16 }, - { 0, 8, 8, 16, 8, 8 }, - { 0, 8, 0, 8, 8, 8 }} + {"stair_inner", 1, nil } } +local repairable_tools = {"pick", "axe", "shovel", "sword", "hoe", "armor", "shield"} + -- Tools allowed to be repaired function workbench:repairable(stack) - local tools = {"pick", "axe", "shovel", "sword", "hoe", "armor", "shield"} - for _, t in pairs(tools) do - if stack:find(t) then return true end + for _, t in ipairs(repairable_tools) do + if stack:find(t) then + return true + end end - return false end function workbench:get_output(inv, input, name) local output = {} - for i=1, #self.defs do + for i = 1, #self.defs do local nbox = self.defs[i] local count = min(nbox[2] * input:get_count(), input:get_stack_max()) - local item = name.."_"..nbox[1] - item = nbox[3] and item or "stairs:"..nbox[1].."_"..name:match(":(.*)") - output[#output+1] = item.." "..count + local item = name .. "_" .. nbox[1] + + item = nbox[3] and item or "stairs:" .. nbox[1] .. "_" .. name:match(":(.*)") + output[i] = item .. " " .. count end inv:set_list("forms", output) end +local main_fs = "label[0.9,1.23;"..FS("Cut").."]" + .."label[0.9,2.23;"..FS("Repair").."]" + ..[[ box[-0.05,1;2.05,0.9;#555555] + box[-0.05,2;2.05,0.9;#555555] ]] + .."button[0,0;2,1;craft;"..FS("Crafting").."]" + .."button[2,0;2,1;storage;"..FS("Storage").."]" + ..[[ image[3,1;1,1;gui_arrow.png] + image[0,1;1,1;worktable_saw.png] + image[0,2;1,1;worktable_anvil.png] + image[3,2;1,1;hammer_layout.png] + list[context;input;2,1;1,1;] + list[context;tool;2,2;1,1;] + list[context;hammer;3,2;1,1;] + list[context;forms;4,0;4,3;] + listring[current_player;main] + listring[context;tool] + listring[current_player;main] + listring[context;hammer] + listring[current_player;main] + listring[context;forms] + listring[current_player;main] + listring[context;input] +]] + +local crafting_fs = "image[5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]" + .."button[0,0;1.5,1;back;< "..FS("Back").."]" + ..[[ list[current_player;craft;2,0;3,3;] + list[current_player;craftpreview;6,1;1,1;] + listring[current_player;main] + listring[current_player;craft] +]] + +local storage_fs = "list[context;storage;0,1;8,2;]" + .."button[0,0;1.5,1;back;< "..FS("Back").."]" + ..[[listring[context;storage] + listring[current_player;main] +]] + local formspecs = { -- Main formspec - [[ label[0.9,1.23;Cut] - label[0.9,2.23;Repair] - box[-0.05,1;2.05,0.9;#555555] - box[-0.05,2;2.05,0.9;#555555] - button[0,0;2,1;craft;Crafting] - button[2,0;2,1;storage;Storage] - image[3,1;1,1;gui_furnace_arrow_bg.png^[transformR270] - image[0,1;1,1;worktable_saw.png] - image[0,2;1,1;worktable_anvil.png] - image[3,2;1,1;hammer_layout.png] - list[context;input;2,1;1,1;] - list[context;tool;2,2;1,1;] - list[context;hammer;3,2;1,1;] - list[context;forms;4,0;4,3;] - listring[current_player;main] - listring[context;tool] - listring[current_player;main] - listring[context;hammer] - listring[current_player;main] - listring[context;forms] - listring[current_player;main] - listring[context;input] ]], + main_fs, + -- Crafting formspec - [[ image[5,1;1,1;gui_furnace_arrow_bg.png^[transformR270] - button[0,0;1.5,1;back;< Back] - list[current_player;craft;2,0;3,3;] - list[current_player;craftpreview;6,1;1,1;] - listring[current_player;main] - listring[current_player;craft] ]], + crafting_fs, + -- Storage formspec - [[ list[context;storage;0,1;8,2;] - button[0,0;1.5,1;back;< Back] - listring[context;storage] - listring[current_player;main] ]] + storage_fs, } function workbench:set_formspec(meta, id) meta:set_string("formspec", - "size[8,7;]list[current_player;main;0,3.25;8,4;]".. - formspecs[id]..xbg..default.get_hotbar_bg(0,3.25)) + "size[8,7;]list[current_player;main;0,3.25;8,4;]" .. + formspecs[id] .. xbg .. default.get_hotbar_bg(0,3.25)) end function workbench.construct(pos) @@ -128,17 +124,17 @@ function workbench.construct(pos) inv:set_size("forms", 4*3) inv:set_size("storage", 8*2) - meta:set_string("infotext", "Work Bench") + meta:set_string("infotext", S("Work Bench")) workbench:set_formspec(meta, 1) end function workbench.fields(pos, _, fields) if fields.quit then return end + local meta = minetest.get_meta(pos) - local id = fields.back and 1 or - fields.craft and 2 or - fields.storage and 3 + local id = fields.back and 1 or fields.craft and 2 or fields.storage and 3 if not id then return end + workbench:set_formspec(meta, id) end @@ -159,32 +155,30 @@ function workbench.timer(pos) return end - -- Tool's wearing range: 0-65535 | 0 = new condition + -- Tool's wearing range: 0-65535; 0 = new condition tool:add_wear(-500) hammer:add_wear(700) inv:set_stack("tool", 1, tool) inv:set_stack("hammer", 1, hammer) + return true end -function workbench.put(_, listname, _, stack) +function workbench.allow_put(pos, listname, index, stack, player) local stackname = stack:get_name() if (listname == "tool" and stack:get_wear() > 0 and - workbench:repairable(stackname)) or - (listname == "input" and registered_nodes[stackname.."_cube"]) or + workbench:repairable(stackname)) or + (listname == "input" and minetest.registered_nodes[stackname .. "_cube"]) or (listname == "hammer" and stackname == "xdecor:hammer") or listname == "storage" then return stack:get_count() end + return 0 end -function workbench.move(_, from_list, _, to_list, _, count) - return (to_list == "storage" and from_list ~= "forms") and count or 0 -end - -function workbench.on_put(pos, listname, _, stack) +function workbench.on_put(pos, listname, index, stack, player) local inv = minetest.get_meta(pos):get_inventory() if listname == "input" then local input = inv:get_stack("input", 1) @@ -195,6 +189,24 @@ function workbench.on_put(pos, listname, _, stack) end end +function workbench.allow_move(pos, from_list, from_index, to_list, to_index, count, player) + return (to_list == "storage" and from_list ~= "forms") and count or 0 +end + +function workbench.on_move(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local from_stack = inv:get_stack(from_list, from_index) + local to_stack = inv:get_stack(to_list, to_index) + + workbench.on_take(pos, from_list, from_index, from_stack, player) + workbench.on_put(pos, to_list, to_index, to_stack, player) +end + +function workbench.allow_take(pos, listname, index, stack, player) + return stack:get_count() +end + function workbench.on_take(pos, listname, index, stack, player) local inv = minetest.get_meta(pos):get_inventory() local input = inv:get_stack("input", 1) @@ -202,7 +214,7 @@ function workbench.on_take(pos, listname, index, stack, player) local stackname = stack:get_name() if listname == "input" then - if stackname == inputname and registered_nodes[inputname.."_cube"] then + if stackname == inputname and minetest.registered_nodes[inputname .. "_cube"] then workbench:get_output(inv, input, stackname) else inv:set_list("forms", {}) @@ -223,12 +235,14 @@ function workbench.on_take(pos, listname, index, stack, player) end xdecor.register("workbench", { - description = "Work Bench", - groups = {cracky=2, choppy=2, oddly_breakable_by_hand=1}, + description = S("Work Bench"), + groups = {cracky = 2, choppy = 2, oddly_breakable_by_hand = 1}, sounds = default.node_sound_wood_defaults(), - tiles = {"xdecor_workbench_top.png", "xdecor_workbench_top.png", - "xdecor_workbench_sides.png", "xdecor_workbench_sides.png", - "xdecor_workbench_front.png", "xdecor_workbench_front.png"}, + tiles = { + "xdecor_workbench_top.png","xdecor_workbench_top.png", + "xdecor_workbench_sides.png", "xdecor_workbench_sides.png", + "xdecor_workbench_front.png", "xdecor_workbench_front.png" + }, on_rotate = screwdriver.rotate_simple, can_dig = workbench.dig, on_timer = workbench.timer, @@ -236,17 +250,19 @@ xdecor.register("workbench", { on_receive_fields = workbench.fields, on_metadata_inventory_put = workbench.on_put, on_metadata_inventory_take = workbench.on_take, - allow_metadata_inventory_put = workbench.put, - allow_metadata_inventory_move = workbench.move + on_metadata_inventory_move = workbench.on_move, + allow_metadata_inventory_put = workbench.allow_put, + allow_metadata_inventory_take = workbench.allow_take, + allow_metadata_inventory_move = workbench.allow_move }) -for _, d in pairs(workbench.defs) do -for i=1, #nodes do - pcall(function() +for _, d in ipairs(workbench.defs) do +for i = 1, #nodes do local node = nodes[i] - local def = registered_nodes[node] + local mod_name, item_name = node:match("^(.-):(.*)") + local def = minetest.registered_nodes[node] - if d[3] then + if item_name and d[3] then local groups = {} local tiles groups.not_in_creative_inventory = 1 @@ -267,14 +283,16 @@ for i=1, #nodes do tiles = {def.tile_images[1]} end - if not registered_nodes["stairs:slab_"..node:match(":(.*)")] then - stairs.register_stair_and_slab(node:match(":(.*)"), node, - groups, tiles, def.description.." Stair", - def.description.." Slab", def.sounds) + --TODO: Translation support for Stairs/Slab + if not minetest.registered_nodes["stairs:slab_" .. item_name] then + stairs.register_stair_and_slab(item_name, node, + groups, tiles, def.description .. " Stair", + def.description .. " Slab", def.sounds) end - minetest.register_node(":"..node.."_"..d[1], { - description = def.description.." "..d[1]:gsub("^%l", string.upper), + minetest.register_node(":" .. node .. "_" .. d[1], { + --TODO: Translation support + description = def.description .. " " .. d[1]:gsub("^%l", string.upper), paramtype = "light", paramtype2 = "facedir", drawtype = "nodebox", @@ -286,18 +304,29 @@ for i=1, #nodes do sunlight_propagates = true, on_place = minetest.rotate_node }) + + elseif item_name and mod_name then + minetest.register_alias_force( + ("%s:%s_innerstair"):format(mod_name, item_name), + ("stairs:stair_inner_%s"):format(item_name) + ) + minetest.register_alias_force( + ("%s:%s_outerstair"):format(mod_name, item_name), + ("stairs:stair_outer_%s"):format(item_name) + ) end - end) end end -- Craft items minetest.register_tool("xdecor:hammer", { - description = "Hammer", + description = S("Hammer"), inventory_image = "xdecor_hammer.png", wield_image = "xdecor_hammer.png", - on_use = function() do return end end + on_use = function() do + return end + end }) -- Recipes diff --git a/xdecor/textures/gui_arrow.png b/xdecor/textures/gui_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..df1bbdb4be285ca651ec29982267e61da0cc639c GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^DIm+Rjsxy=p?Y!B@P zQ)k#YDSmOb*K2WFFd;@PlV7onFVgKzPfO0v4NUb4a);CmjS*mXxxB63mrXkTum1YY z+J4?I{D|SnDJiQ8S$3{-XPlX-v9~E9u!_xb(HFiZXF--WB@P}}0f{aJ0};mrjiv(u zER72}n249KzvmUjCUN>ed5+ho(76AbZBNd6GBc(2`L?SMpM2hUktcp9TR-piDao$& zokn{$o{V%B`L4L37HVDd{fns@)uuaJ1B92<9^ZL#R*G;-V`0@I4Gs=x0f}Sz?vckC z%Iz*?macv0e|_^ghizFKtj$6VBzl(Ix96L2`s7WYLk03ohXq*L6ghZ+I@%NrcpMWX znhqGSG$wM8CQ-$HFj3|2zl7!cLd#TbQ=c=@kj+`MMFuE8# MUHx3vIVCg!0F!X3YybcN literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_candle_hanging.png b/xdecor/textures/xdecor_candle_hanging.png new file mode 100644 index 0000000000000000000000000000000000000000..b8595a7ec119b61b6ab38201bb0cadd5d8fa8934 GIT binary patch literal 15657 zcmeI3du$xV9mgk1N{rKlR6&W;N@jIQODep#kK23f=I-EpXUA52!LeQ9l+v)bJ7+Js zyFGT-xr=EFqErf?N^OKlYtgDzD^VoEOGuS4Q6SV+K&@m`A*4`33o2^TR92{HN+ce$ z_gv524OYdUS4FK3UJd_$k-<#3`(6X)9_s;MH)l*tI+N)UMKkk$RW~!xU(Od%Zvdh~T`s7yJZE7(do z=Bwx`=(pR<`It%<=WxuIa1%0<=}{(WT966)L#)P!!c1893&C($3imN0F9bP0zy)|# z3@8$>NFr1F^ToT-uc)PGm9f-dEgiCAzG=rPDjZiTmHefE-?XMUL6&8X7dcU6Q4iKW zT5!}dTd;RjMd~^!Xls^HbPTh=xVmb_oN;14pPQ)hSG%r!F`aItD%dr8h$B~4i=5!+ zxqO~$7il|VusO)Kk@m#VBIL%PZO&L4MBR6^7aBN%MpwJqRR|3nfd!|n6q+-#P`muP z)`%(2Sh)&lUE^R5=20FSF%a4UC{CM>X-}ISQa0Qbi0u+PMz#Y$*V8c!mW>W!uBRGS zsj2EzM-h~CTDjFSQ2DF5l&Q_Q*EO7qBZpr%bR`_@?@uQC!y#cn6odh}KP4vRK_SsE zCL)p;9*lAwC7KmgOVdU^nc#y-o)3h1IpE6619CVih2&tOUyg)>QeEB?+9Eq#upPCa z!P=+|H0ppZXLTu(VPy>pEFY2tHX}fh4Fn^C8WJTzfSJ0qC%i>E1uf$U)CVmyUs)_g z)v}>mxG`V7avQ6wMzm7;iqSeIiRXDet3fsZBO9TJ#ES~g*N0l^)mg+gvrb91U}6d_ zy?FJ&7_ILgOfp$HAedbTjDl{K>~GdpSB7<#*QV9N6x8EfJ+R(@heSDd>T<@)nX9(0 zoX~o8v=)H7(v_qIRa6)grkPvK<=`RBaW&OoN_C)@G%qVsSP>hf8zR-7m`2*vjqFie z1D`Ed!_yPjKqtGdI_j!aynQ`7x~61JE3Z0nBd<s?blg|kmC@%)!+&EP6et#)IqmikI6UgRXEQTJGO4^p&-)yi%qM7fqW&s0@>lkO>!o2m2< zi|ByhIl=v`g?in1=s|L**NulZBfnKJoVZxahBbSl++Z++@l?w-mO!e+!{n4DM(fc(555LiYicWR*aVqZU}5IM1DJrL3#1=)M`JkWGq<%m?#QTo@3tNpX?+U|xy~ z141?_E;1j?OL1X9$R@=_=7V`DE({3Sq`1g@FfYZ00U?_d7nu*{rMNI4WRv0|^TE6n z7Y2lEQe0#{n3v+hfRIfhuI}bju&{t0eJ!D9T-i^2$I$b!j5aiu24ME<0NnRO06zK@ zeO~}zh6mu{od76517MqZ{LsQ60Bg`ggNcdqxl1RW-TTVu=0Bd^_QJZ6#ILtr7(H?P z^_$KY0usJ=PuhnSvP)s zPkR0S^NGK`{Pz5OY59Zqe#ty2J-d6~@2-FAw%F3(-nafbeQq5Cy59NPGfU5J`L|_k z>RuRoclOCIpZVvb7hV_dIQ!h9zVzW;UjoxV_ajf{8*_ciYbVbRe|ziPrAy^=YyW#| z=7puc=O1}(?R{OnSG#VzYjHky`P5e7x}Cpy`qVvVi?J7<5PGh@sJx@kZG82A!K>$) zT<`v096EF6Upqb+?0s`v{;8A8UGwiPUb*J=_~wUic>H_!{NTo`FTMSbgTIYL;_vo> zKJ!}RE6b0E{_v;AF3KuJ hqNCBCz47&6=fiz}&pi3SPWNHv;emarr~2=_|1(U#Dg*!k literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_radio_back.png b/xdecor/textures/xdecor_radio_back.png new file mode 100644 index 0000000000000000000000000000000000000000..35ee768f0e10a12594f85416ce2ba66a04c21372 GIT binary patch literal 1184 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvryA&s6}2k5wiXH#j?6 zI60db0Nw9m0dl{EqnoRxv7?crxr>FfrMaaNRBs9vzeDvJ;nb@Sbc{YIa*-k%CIn1D zASOKN0y*%+pPC0u@kPL--SsmCn7bGSJY5_^DsD{)I?Z>`LBw^LO2~yg6`{nZ8#jrT z{X3xl!zOyZL(W>8u&G|+Vo{6M$nsqe@k+XMZ_dv5#^2T44;MX}zxV@xmFVgagU?|P z-t!**&@4RV0)qn+w}k&RFQ?e+jb~=x%-VWxb;adI2g93plehEhhcn#%#P@Ha-?mVd zcjeaKU5x!bT`QcWZ+|b@*HPe*QSps2Y_{&FnLBgTCbKzIX|QfcUz(m}nq{wLV^zOJ zxboPm}Yg-owYC@$9kkvAowAUCR!!A7C-8W7s2C6QTI?ebs#y35H&y Vjbi1AEv}$4!_(EzWt~$(699t>kx~Ev literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_radio_front.png b/xdecor/textures/xdecor_radio_front.png new file mode 100644 index 0000000000000000000000000000000000000000..6300aa81ce94f317aae205199998973daaa66dd7 GIT binary patch literal 1208 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvryA&s6}2k5wiXHy9ci z8oHUgnVT89xPsm9W@&0+VQOq*=xFI|>0+S-)tiFF?@+xKIQ8lS9itD5T%^c`2?0|O zhzU=+Kn^_dr{)1ud=W5dzmJ{Z!oa|&;pyTSQgJKEhi_7X0_z5bjhnY_nV?|Lzy8AS za{b82$oqT$bBM5XF-STHooF)-%inp7=^}ed;*75%oh*h8&zy1@Uf12ad$;wt>e8jD zMMYga?(>Ztb6UEURv%a;yo7Oy=v9L?Z`}LeF?+ftXsEi~Iul>llJKMDSB9f4?-i~m z49=WMY(*y&xSeA7zJB@Ju75seUz?PjLR;s$4U6{t=w6VoeqY}Bem<*6V$+E^JO6xp zValk$+{@C%EXjXA-l5ZiW5cyy4O3Zmxs=W|J2Lk|K$8XEYF+{McJXPFKQ$NrIOy`7 zo%wLIk90#FgVDWxw|V>H#X5K$=D&QE!E`g;Zh!M~nGO+y1$l4(GYGnKseKk+5S{O}4GMJTDo|INNz;I~G9Ja%mtE53?iKnZd%Q~loCID7dmdyYF literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_radio_side.png b/xdecor/textures/xdecor_radio_side.png new file mode 100644 index 0000000000000000000000000000000000000000..cf6074062937f96cfe16e3afc3ad384b30a695ff GIT binary patch literal 15650 zcmeI3du$X%9LJ~iAE{|VghWHs90w8z-tF$~J(ugz(!1I!S4vx<6$SQo=i0S*x99Da zUJ(O|%ELzhMIM2~D4-#c5FsWY3gICdMTDpbF_lD&AXQKT1{1;Adw1?`tO{Aw$KzpG8)LIsP!EgNAJfI8C8mu_ zi)3~DP?Hi$TvybX$$Rx!$!&zCTOi(aL4vR)h zMrwL1%&)BEfLeQh95Ss?Q+pE-b>`nFcspDyyI9rLyYM(aA%itmTgOgW-eo==$bg(@Z)^6e4?VMe3 z*aV)P%-RH&Ef7if#597ctc3fEG#rA17kF2pMnO+p10|v?>f*3e3i}S#2?m9xn5K&{ z2{!qCXzf--kp-CxyThU^SvZ$lv_OYFWC^)gw?%Y{V#s3?Stl>17CAJ$NZPMTy~aVx zNXtk%z`9*Fm&@hk0xZV`Je~%R+i!EB#(RpHER}em+Rtn|8}(SL*mD<$}<>at=d&so1$j=w~Dp zRMy2v0V`t%{|)965(Se$YG{~7MML@1UogJ0Zlk!i!6%2dW*re_m>ZMZ9#qly2V%*lzmKg zW!VNi#LF047g7F;J2$+-Q?&8;67#2{^v>mr?Ehfr()&3y6|?1|ICZ_UB!tyORMdS+ zRP2IGJl5r9@{M_v-rQYWs8=Iu0^N(CkM}aAnhTCAbVqBgvLhf%j9 zy{Y~#8;d>+XZ&VD3*C5VCpomxjfdtVABict&z2btYc7Z~9x~D}+R%eF^f?_4-r;5N zW;~)rNy12nUqQD*%_wjjsy?Y0+)*;Hvs_?-BNLcD3I&hAsT@zYq6cjBY|rE#?u*ht zS6FZ5pZtn$r7EUH2f=`lO^S=m2lG-~7!a~aagq68UWy9?LN+NbG9S!KabZBnCdEbO zgLx?~3<%kzxX64kFU5rcA)6EznGfcrxG*4Olj0)t!Mqd~283)JkWGq< z%m?#QTo@3tNpX?+U|xy~141?_E;1j?OL1X9$R@=_=7V`DE({3Sq`1g@FfYZ00U?_d z7nu*{rMNI4WRv0|^TE6n7Y2lEQe0#{n3v+hfRIg!i_8b}Qd}4ivPp4~`Cwj(3j;zn zDK0V}%u8`$K*%N$S5^LXSr|j_$o8R^VaLB$Js!PCYmypUg8(eNAAluG0l0n>T`vI8 z%L4H8d;o;?0NkannRlcCfC_(;zpg!b=Cw7!hY!_`eBt}o4^P`W_S17Mb&qXqo4RlL z?&ar?Ej~N%@=yI&2ahd1>uDG{yVBGC$%L)S@%y$-mrm6GvGa2)f5ms@#Gd_AJ|26t zBL39V(`LT0X#3#7-pA)yDq2Q=`$W@BQ2WxdqhGE5((3|?epEJJZrgYInd)V){`S|k z8*9T8wpG?DJ%D?D>$~cXFDkk>pWPGppP2R8$#1q_S}}Rqke1${bk0*{pTNg=l7=ThmT(qcHdk)>D-i@7X&r b^)|3%+R?SGu_g7!Tg**?X8(?9^Pl}2wbUx` literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_radio_top.png b/xdecor/textures/xdecor_radio_top.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5f88a9b8e51c7a92d1ad42c1d57503f05eb4c3 GIT binary patch literal 1214 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvryA&s6}2k5wiXH<&q_ z8XH?!8Ux*60CK;hiJO75k&~&jvx%dDqnVQuRBs9vzeDw!;MA)Rbc{YIa*-k%CIn1D zASOKN0y*%+pPC0u@kPL-ZPE4SE&~Ijo~MgrNX4xwlMZ?v4iIq7^)NF%`mJs^i0VDNy5+?3#}MZ5_LSSQZ~coxr@DVxyx=m=lH3Ei5$$TG zuh(VHU;UKz=|!FyKUZy>{CMX5CCVOsj=;=@U=qqih6Ibrh zu#f%y`oj1BK_3cM&Sty89edMb-4Tz(4X>-}xeXX%7wr9%x!x}jRHAsg`njxgN@xNA Dz`U#j literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_rooster.png b/xdecor/textures/xdecor_rooster.png new file mode 100644 index 0000000000000000000000000000000000000000..b68a173e0e15bf415371e8dd039cb81f03584945 GIT binary patch literal 1322 zcmaJ>ZEVzJ9PdEcB*URDz%Gz#IJ)+^t!{l;+wE@4 zKqP#@h#}bkmu$iK!Ng<`VxmzO93d!9lYKA-WjcHzVUi_cH1TDF#i!eD@?oJ#`#gR6 z|NZ{I|67kYH9WInePBI;AR7{O(G*Y9CxGyjaHDZ)Lrl;s8X_tX6;~ z45baEfTHzwO@L|yS$jlJXS_`ESy8nNLh)^gykSE$f>hV!ZAI+>9@+}pbTfk885_q? zU5jANp(K^GWzeqI^*LaFUqf2$>re#^tJ#BA=S4_h08c^lMyKhD`3SbiE5f~hOk(Jw ziPsUqmPBQeO{i=+01Xiwu2LM2@&ZAJcs|JQLK%tkP?Fox_n{Ko1h>ZSRJs&`VJDL-#HPEPD3~%buh=9_P^4k_aV=WAUJCp#V^wQ6-D?9f1zfA! zQDHr@+Y4Zry9Yb+4WSyb(a~X1l+LK7b{oL-643|-zYvK)z^R*JkNE{yy`B;fzsM;7GkFioPEHOd>n=oBZF;!6Tt3$ub zSmA+KQFeghSx(xrItv}p)NXl}+iuyYEH73Z-Px?0nw4{(_Di%BaTGXu576R{WuS{W z7WGv$a9J8?D(n^kFaTGSU>H|aMZm*aFvw9rP~n0tM@Ht#O5Qwrep}T) zKg7lcdwx56P_j?_dy8oM=)*w%$&YUhwB(-3K6>){L{aJ7jqg$y7edX`fy2k1OAS?S z9L%mMsTnyp7-FXy$)7(MKi4zcTlV^wKYd@{I+Gghmk)f~9sYDK{dZTc{Pb&^XD%MO zb79-qC~{exs=(0V`q`-y#XHpGzWEWNvS{kv>o1*YyxAXoiwk6)e`x2%;M(}Et(qt9W&*iGS05u@o_zJ4<4E%Y ss?Yb&E(~v8*z(nlKUz*z)~qQ--ur#@^G^c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvxv7((k+Yeh ztC69htEHo%qnopZo3W*{k&B75n+r^@XI^nhVqS78Om8MauM=LqR?bDKi6!|(A^G_^ zu-FU8$S=t+&d4uNaCQdAmV!ojW?o8ud9fxac%iOMEy^rQO>ryA&s6}2k5wiXH#iwt zn3-BSxtJNcSb*K{VrXt@YGmT#X5eUOWCnCUL~jZfzeDx9;?%1Tbc{YIa*-k%CIn1D zASOKN0y*%+pPC0u@kPL-UAN_UE&~H2i>HfYNX4xwK?k{-90bl@=+=B%wPNzawMzN5 zp8GGnFXQNWrN+rB7vwYffH(iLG)^0PEqcc4pY>>!vVpr&$Dcd>M@yz|BslOsJyIW6w zUikOjQPt~j%IpQcU1j{D)us-eb?i!?1nowAR%IM`nS_2~Sr) Jmvv4FO#rybjL851 literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_speaker_front.png b/xdecor/textures/xdecor_speaker_front.png new file mode 100644 index 0000000000000000000000000000000000000000..b19b8352411fa10dd581a32ec036658e2e6447bc GIT binary patch literal 1239 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvP;hnz$CiRdcxGNoetEGbD0rc+O)bhSOHFYr%Fk5*hmTbz7B?6g zxf;6~IJuY^y10Pc?_^?OY-!-+YG`C(U}j=yp#;^Ng2nGpy{H{644~kr*$c704 zQxJ#=Pr5)3Jn^UI0aJVtFlpBuR$0fu!07Jj;uunKE6Im%Qi1~O28NBD>kKAbxq7kY z|2tJ}?bo}%%Qwa-I@T#LdobN}ICk9MzM;o>`h6qEFPf*i?W;=uf1aMdzy3elDbut6 zqAq;pS;VnOeg(s#Nt}7&M+_Fs>(u_w*2Fl0QLx=ZaSjX1clmuRlm67m?6HaY`Osc% zT@3$|XYIz$J?#;#ix`t4$`!?reB(^zDVWdTxqw^om!Oo|6i>!j{uGRbb$Dl-*VLw<=~^=y%KYzt0`}%*seoTCL;-YZTrbi!6q%|&a{4;Og-xr#5 ccm)y|b{(D^^4cWqC8((JboFyt=akR{09Cr8#sB~S literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_speaker_side.png b/xdecor/textures/xdecor_speaker_side.png new file mode 100644 index 0000000000000000000000000000000000000000..7b28936c50c96811c5b606fcf43ab8d2537cbd88 GIT binary patch literal 1172 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvxv7((k+Yeh ztC69htEHo%qnopZo3W*{k&B75n+r^@XI^nhVqS78Om8MauM=LqR?bDKi6!|(A^G_^ zu-FU8$S=t+&d4uNaCQdAmV!ojW?o8ud9fxac%iOMEy^rQO>ryA&s6}2k5wiXH#iwt zn3-BSxtJNcSb*K{VrXt@YGmT#X5eUOWCnCUL~jZfzeDx9;?%1Tbc{YIa*-k%CIn1D zASOKN0y*%+pPC0u@kPL-UAN_UE&~H2i>HfYNX4xwK?k{-90bl@=+=B%wPNzawMzN5 zp8GGnFXQNWrN+rB7vwYffH(iLG)^0PEqcc4pY>>!vVpr&$Dcd>M@yz|BslOsJyIW6w zUikOjQPt~j%IpQcU1j{D)us-eb?i!?1nowAR%IM`nS_2~Sr) Jmvv4FO#rybjL851 literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_speaker_top.png b/xdecor/textures/xdecor_speaker_top.png new file mode 100644 index 0000000000000000000000000000000000000000..b45f3f14278f943d260bc1ad967de07272cea0c8 GIT binary patch literal 1187 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAI{vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvryA&s6}2k5wiXH&_@r zI=h+~S(+KTSc2Sd>Fj9g=w{(;;p%4KW^C@L1l5~@#qUtPjyUz|10ACeid>|~h6w>v z5Qqs+xRCzBw~EPV&l28E?~>wZ`xD&ChSnugUxJr=+;BkF{1VeDl@A zclX^{ni=&@J1@zO^})f0S0Da<`gK$7fZnvvZ_AkHr93{mh(TahZ+nBfdf|fm$A7U* zU2L*3wdX=v!0Q|#%NCxr^(JfVrp;x`>s)!trsYIIuE@^jG`_yX*{=@89hm>$V~*Cg zWslgjBqrVPzH=pkKXT|s~pWA-l#hvGW cyEia0+}ga!XTyQ>7eU2_r>mdKI;Vst03hO}j{pDw literal 0 HcmV?d00001 diff --git a/xdecor/textures/xdecor_wooden2_lightbox.png b/xdecor/textures/xdecor_wooden2_lightbox.png new file mode 100644 index 0000000000000000000000000000000000000000..a53ad96a37caa56485ebe46b8a76ba13a09c18ac GIT binary patch literal 15686 zcmeI3eQ*@z9mkh2q#-Q8b=h@Hmw*Tzr6?MyI6_ylY7&fc6#!(NhbEI!U9{7E7u+0E2Geb2k z0)~Bip7foDJv($ehEYDQu~}?(JwSQ*KqbxaZniQK2!YxdW?m8r(VlizRJd6m7pzi_ z|Msv_!7)|JCcR7T3fb8;TBz5HX6@*%&$JJU~t5y+O zN~flDgd+Y?S_;8GbC~f`^$useIS^GT+e9%$;dob9S7n#Bk`McEjmc!f)dWruDo{fu zbO%K`q6!M7F_VOkgB3hsE+le%P$Bu!ZoWgTQYxi}lAri}1wt-YvZ$*h?|V|R$f>sf*C2zyviy)?T~btmXu{BEaURNcu2#jI9f%+N;J z+Gjk;oKQ#D9|g^LaMsTTKsy3ppvej#)W(av(8lLzGATzPW@}jFyg2|$O3pMk!sSSl zlvrAHPQ`}W44}AN)bcO~ra$d>@SYCozG@v7AXG9OLy>x$&2G1m22C}g(Nvpk4#IA7 zYOFTGYSa;=(~Re|NX@8tGg<7dCWqZV$n-YKCoX zP!Q>$hmH4|1HCpFXohrq2o<5xGb)zU=~YHX&#Fvbn$>w&l4iU~>$LO?YX=+VI$6dU z<^$2i5~9NbD^1)gWn$(gS67^9bm~)FW}gU#F|m45uhQ%Ew2Gv4UX{^EGb)c;f59yLL!!F-BYMQi0Y5qPiIMTc3d4=glG?08s_*ew)xd-OO^+||Sd8NN%XNVrZ; z%Wdyzqk}${vEYfsL;;*)#-*Y2bCX9dRyuh=6SE_80!ZtcvWHn3OpHdJ_fO?^;FMIq zQf{n+7Fme2PD^Rj3DQZESWU>o#WS3@JB!Dp(ULsUYQi4i9A{{eo{~#?-83J@LwWgd zfEF!WfcCL?DCjfeslv3H$@74+^L{=Iy2Vl;-jJcECfxpQ=sXO{6T_G>I z5eNu6lyRZ?K&p%j0)h@@TxdR!D&vBHphFoKnh&JPxF8_tP{xJk1F14D2nafqaiRG@ zs*DQ)f(~U|Xg-iCa#)akssWL7I2s)H;q4_|nj0*yS4rN?u zK9DNof`Fhy85f!lq{_G;Am~uWh2{gPGA;-RI+Sst`9P|S3j%@;Wn5@JkSgPXfS^Me z7n%>G%D5mP=upOm<^!oRE(i!ZlyRZ?K&p%j0)h@@TxdR!D&vBHphFoKnh&JPxF8_t z5Q(cW_4X(m1h0&Cfp%<1 zhGDnyTUw7eF)Xj8)?saoj4}1gYlxrk!c09ZL-}}b* zyt?wSgT(#|4T~{jb=~OY{OPk!Uw3p`{#tx|Z0nm9#PHkL3-stjpR@SdHp|41_s##~ zHC53W`^7~);_%$1k9eQn`PRYe$9-7n0nOp9cPu=9Y132Be5c`!hL?tvzVZ?5AKO2h zccRk&@^7}cYIiy@$H<#P=fB>oXv8i*nt!r{GMg|4QxT*nahqFqs`s) z`HSWkKN#r`8cz(AxyKF|-Z@*o;nI;?o-kII|8(hxTXcKpp2&alx#br(J+-F%aH@`7za!_fUNufNyt9$Dz>eevYqw`k{ZOB?2o-njlPLrIbI zl{HQ0j#gZ;em*+z=iY;Tdf&vMQx^t)_38Dm^D*1SyI)$=yknj8rgLp|onyak?GOG7 D;Yw#) literal 0 HcmV?d00001