From 28239ec0fb604c4ec49f963e0dcc9f71c0afd50f Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 17 Dec 2020 11:22:00 +0100 Subject: [PATCH 001/219] Remove enchanting particles on collision --- mods/CORE/mcl_enchanting/init.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/CORE/mcl_enchanting/init.lua b/mods/CORE/mcl_enchanting/init.lua index d1f351b62..79dd2aee0 100644 --- a/mods/CORE/mcl_enchanting/init.lua +++ b/mods/CORE/mcl_enchanting/init.lua @@ -252,7 +252,9 @@ minetest.register_abm({ acceleration = {x = 0, y = -9.81, z = 0}, expirationtime = 2, size = 2, - texture = "mcl_enchanting_glyph_" .. math.random(18) .. ".png" + texture = "mcl_enchanting_glyph_" .. math.random(18) .. ".png", + collision_detection = true, + collision_removal = true, }) end end From 6c3588bad8da4a164fc53049513aec1a7fce6094 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 17 Dec 2020 13:29:21 +0100 Subject: [PATCH 002/219] Rework inventory --- mods/HUD/mcl_inventory/depends.txt | 1 - mods/HUD/mcl_inventory/init.lua | 1 - mods/ITEMS/mcl_enchanting/engine.lua | 120 +++++++++++++-------------- mods/ITEMS/mcl_enchanting/init.lua | 3 + 4 files changed, 59 insertions(+), 66 deletions(-) diff --git a/mods/HUD/mcl_inventory/depends.txt b/mods/HUD/mcl_inventory/depends.txt index 27231e5df..cf04c75ef 100644 --- a/mods/HUD/mcl_inventory/depends.txt +++ b/mods/HUD/mcl_inventory/depends.txt @@ -5,4 +5,3 @@ _mcl_autogroup? mcl_armor? mcl_brewing? mcl_potions? -mcl_enchanting diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index a4bd0e167..c6f97185d 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -141,7 +141,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) return_fields(player,"craft") return_fields(player,"enchanting_lapis") return_fields(player,"enchanting_item") - mcl_enchanting.reload_inventory(player) if not minetest.is_creative_enabled(player:get_player_name()) and (formname == "" or formname == "main") then set_inventory(player) end diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index ac12857b9..043d11860 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -393,15 +393,19 @@ function mcl_enchanting.show_enchanting_formspec(player) .. "formspec_version[3]" .. "label[0,0;" .. C("#313131") .. F(table_name) .. "]" .. mcl_formspec.get_itemslot_bg(0.2, 2.4, 1, 1) - .. "list[detached:" .. name .. "_enchanting;enchanting;0.2,2.4;1,1;1]" + .. "list[current_player;enchanting_item;0.2,2.4;1,1]" .. mcl_formspec.get_itemslot_bg(1.1, 2.4, 1, 1) .. "image[1.1,2.4;1,1;mcl_enchanting_lapis_background.png]" - .. "list[detached:" .. name .. "_enchanting;enchanting;1.1,2.4;1,1;2]" + .. "list[current_player;enchanting_lapis;1.1,2.4;1,1]" .. "label[0,4;" .. C("#313131") .. F(S("Inventory")).."]" .. mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3) .. mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1) .. "list[current_player;main;0,4.5;9,3;9]" - .. "listring[detached:" .. name .. "_enchanting;enchanting]" + .. "listring[current_player;enchanting_item]" + .. "listring[current_player;main]" + .. "listring[current_player;enchanting]" + .. "listring[current_player;main]" + .. "listring[current_player;enchanting_lapis]" .. "listring[current_player;main]" .. "list[current_player;main;0,7.74;9,1;]" .. "real_coordinates[true]" @@ -420,7 +424,7 @@ function mcl_enchanting.show_enchanting_formspec(player) local hover_ending = (can_enchant and "_hovered" or "_off") formspec = formspec .. "container[3.2," .. y .. "]" - .. (slot and "tooltip[button_" .. i .. ";" .. C("#818181") .. F(slot.description) .. " " .. C("#FFFFFF") .. " . . . ?\n\n" .. (enough_levels and C(enough_lapis and "#818181" or "#FC5454") .. F(S("@1 × Lapis Lazuli", i)) .. "\n" .. C("#818181") .. F(S("Enchantment levels: @1", i)) or C("#FC5454") .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "") + .. (slot and "tooltip[button_" .. i .. ";" .. C("#818181") .. F(slot.description) .. " " .. C("#FFFFFF") .. " . . . ?\n\n" .. (enough_levels and C(enough_lapis and "#818181" or "#FC5454") .. F(S("@1 Lapis Lazuli", i)) .. "\n" .. C("#818181") .. F(S("@1 Enchantment Levels", i)) or C("#FC5454") .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "") .. "style[button_" .. i .. ";bgimg=mcl_enchanting_button" .. ending .. ".png;bgimg_hovered=mcl_enchanting_button" .. hover_ending .. ".png;bgimg_pressed=mcl_enchanting_button" .. hover_ending .. ".png]" .. "button[0,0;7.5,1.3;button_" .. i .. ";]" .. (slot and "image[0,0;1.3,1.3;mcl_enchanting_number_" .. i .. ending .. ".png]" or "") @@ -474,74 +478,62 @@ function mcl_enchanting.handle_formspec_fields(player, formname, fields) end function mcl_enchanting.initialize_player(player) - local player_inv = player:get_inventory() - player_inv:set_size("enchanting_lapis", 1) - player_inv:set_size("enchanting_item", 1) - local name = player:get_player_name() - local detached_inv = minetest.create_detached_inventory(name .. "_enchanting", { - allow_put = function(inv, listname, index, stack, player) - if player:get_player_name() ~= name then - return 0 - end - if stack:get_name() == "mcl_dye:blue" and index ~= 2 then - return math.min(inv:get_stack(listname, 3):get_free_space(), stack:get_count()) - elseif index ~= 3 and inv:get_stack(listname, 2):get_count() == 0 then + local inv = player:get_inventory() + inv:set_size("enchanting", 1) + inv:set_size("enchanting_item", 1) + inv:set_size("enchanting_item", 1) +end + +function mcl_enchanting.is_enchanting_inventory_action(action, inventory, inventory_info) + if inventory:get_location().type == "player" then + local enchanting_lists = mcl_enchanting.enchanting_lists + if action == "move" then + local is_from = table.indexof(enchanting_lists, inventory_info.from_list) ~= -1 + local is_to = table.indexof(enchanting_lists, inventory_info.to_list) ~= -1 + return is_from or is_to, is_to + elseif (action == "put" or action == "take") and table.indexof(enchanting_lists, inventory_info.listname) ~= -1 then + return true + end + else + return false + end +end + +function mcl_enchanting.allow_inventory_action(player, action, inventory, inventory_info) + local is_enchanting_action, do_limit = mcl_enchanting.is_enchanting_inventory_action(action, inventory, inventory_info) + if is_enchanting_action and do_limit then + if action == "move" then + local listname = inventory_info.to_list + local stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) + if stack:get_name() == "mcl_dye:blue" and listname ~= "enchanting_item" then + return math.min(inventory:get_stack("enchanting_lapis", 1):get_free_space(), stack:get_count()) + elseif inventory:get_stack("enchanting_item", 1):get_count() == 0 and listname ~= "enchanting_lapis" then return 1 else return 0 end - end, - allow_take = function(inv, listname, index, stack, player) - if player:get_player_name() ~= name or index == 1 then - return 0 - end - return stack:get_count() - end, - allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) + else return 0 - end, - on_put = function(inv, listname, index, stack, player) - local result_list - if index == 1 then - if stack:get_name() == "mcl_dye:blue" then - result_list = "lapis" - stack:add_item(inv:get_stack(listname, 3)) - inv:set_stack(listname, 1, nil) - inv:set_stack(listname, 3, stack) - else - result_list = "item" - inv:set_stack(listname, 1, nil) - inv:set_stack(listname, 2, stack) - end - elseif index == 2 then - result_list = "item" - elseif index == 3 then - result_list = "lapis" - stack = inv:get_stack(listname, 3) - end - player:get_inventory():set_stack("enchanting_" .. result_list, 1, stack) - mcl_enchanting.show_enchanting_formspec(player) - end, - on_take = function(inv, listname, index, stack, player) - local result_list - if index == 2 then - result_list = "item" - elseif index == 3 then - result_list = "lapis" - end - player:get_inventory():set_stack("enchanting_" .. result_list, 1, nil) - mcl_enchanting.show_enchanting_formspec(player) end - }, name) - detached_inv:set_size("enchanting", 3) - mcl_enchanting.reload_inventory(player) + end end -function mcl_enchanting.reload_inventory(player) - local player_inv = player:get_inventory() - local detached_inv = minetest.get_inventory({type = "detached", name = player:get_player_name() .. "_enchanting"}) - detached_inv:set_stack("enchanting", 2, player_inv:get_stack("enchanting_item", 1)) - detached_inv:set_stack("enchanting", 3, player_inv:get_stack("enchanting_lapis", 1)) +function mcl_enchanting.on_inventory_action(player, action, inventory, inventory_info) + if mcl_enchanting.is_enchanting_inventory_action(action, inventory, inventory_info) then + if action == "move" and inventory_info.to_list == "enchanting" then + local stack = inventory:get_stack("enchanting", 1) + local result_list + if stack:get_name() == "mcl_dye:blue" then + result_list = "enchanting_lapis" + stack:add_item(inventory:get_stack("enchanting_lapis", 1)) + else + result_list = "enchanting_item" + end + inventory:set_stack(result_list, 1, stack) + inventory:set_stack("enchanting", 1, nil) + end + mcl_enchanting.show_enchanting_formspec(player) + end end function mcl_enchanting.schedule_book_animation(self, anim) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index 78c5b7f93..8e72cf782 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -9,6 +9,7 @@ mcl_enchanting = { roman_numerals = dofile(modpath .. "/roman_numerals.lua"), -- https://exercism.io/tracks/lua/exercises/roman-numerals/solutions/73c2fb7521e347209312d115f872fa49 enchantments = {}, overlay = "^[colorize:white:50^[colorize:purple:50", + enchanting_lists = {"enchanting", "enchanting_item", "enchanting_lapis"}, bookshelf_positions = { {x = -2, y = 0, z = -2}, {x = -2, y = 1, z = -2}, {x = -1, y = 0, z = -2}, {x = -1, y = 1, z = -2}, @@ -324,4 +325,6 @@ minetest.register_lbm({ minetest.register_on_mods_loaded(mcl_enchanting.initialize) minetest.register_on_joinplayer(mcl_enchanting.initialize_player) minetest.register_on_player_receive_fields(mcl_enchanting.handle_formspec_fields) +minetest.register_allow_player_inventory_action(mcl_enchanting.allow_inventory_action) +minetest.register_on_player_inventory_action(mcl_enchanting.on_inventory_action) table.insert(tt.registered_snippets, 1, mcl_enchanting.enchantments_snippet) From 19726241c3d1cdeb08036e8edc1f535c70ac039e Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 17 Dec 2020 18:53:44 +0100 Subject: [PATCH 003/219] Fixed lapis slot --- mods/ITEMS/mcl_enchanting/engine.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 043d11860..82c4b2a2b 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -481,7 +481,7 @@ function mcl_enchanting.initialize_player(player) local inv = player:get_inventory() inv:set_size("enchanting", 1) inv:set_size("enchanting_item", 1) - inv:set_size("enchanting_item", 1) + inv:set_size("enchanting_lapis", 1) end function mcl_enchanting.is_enchanting_inventory_action(action, inventory, inventory_info) From 0477e729f52ff4126cc1e0088d02279ad667c224 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 17 Dec 2020 18:58:07 +0100 Subject: [PATCH 004/219] Fixed crash --- mods/ITEMS/mcl_enchanting/engine.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 82c4b2a2b..c5e93c442 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -472,7 +472,6 @@ function mcl_enchanting.handle_formspec_fields(player, formname, fields) inv:set_stack("enchanting_item", 1, itemstack) minetest.sound_play("mcl_enchanting_enchant", {to_player = name, gain = 5.0}) mcl_enchanting.reset_table_slots(player) - mcl_enchanting.reload_inventory(player) mcl_enchanting.show_enchanting_formspec(player) end end From 66eb5c35da5126fea9ff5b8876855a8a442a04a2 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 18 Dec 2020 15:57:52 +0100 Subject: [PATCH 005/219] Fix enchanted book --- mods/ITEMS/mcl_enchanting/engine.lua | 7 ++++--- mods/ITEMS/mcl_enchanting/init.lua | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index c5e93c442..0746d211a 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -2,7 +2,7 @@ local S = minetest.get_translator("mcl_enchanting") local F = minetest.formspec_escape function mcl_enchanting.is_book(itemname) - return itemname == "mcl_books:book" or itemname == "mcl_enchanting:book_enchanted" + return itemname == "mcl_books:book" or itemname == "mcl_enchanting:book_enchanted" or itemname == "mcl_books:book_enchanted" end function mcl_enchanting.get_enchantments(itemstack) @@ -147,7 +147,8 @@ function mcl_enchanting.combine(itemstack, combine_with) local itemname = itemstack:get_name() local combine_name = combine_with:get_name() local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname) - if enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(itemname) then + if enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then + print(combine_name, mcl_enchanting.is_book(combine_name)) return false end local enchantments = mcl_enchanting.get_enchantments(itemstack) @@ -211,7 +212,7 @@ function mcl_enchanting.initialize() local register_tool_list = {} local register_item_list = {} for itemname, itemdef in pairs(minetest.registered_items) do - if mcl_enchanting.can_enchant_freshly(itemname) then + if mcl_enchanting.can_enchant_freshly(itemname) and not mcl_enchanting.is_book(itemname) then local new_name = itemname .. "_enchanted" minetest.override_item(itemname, {_mcl_enchanting_enchanted_tool = new_name}) local new_def = table.copy(itemdef) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index 8e72cf782..f5b5b8644 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -143,6 +143,8 @@ minetest.register_craftitem("mcl_enchanting:book_enchanted", { stack_max = 1, }) +minetest.register_alias("mcl_books:book_enchanted", "mcl_enchanting:book_enchanted") + local spawn_book_entity = function(pos, respawn) if respawn then -- Check if we already have a book From 977489de043c5f8146a946a5d91721cbd1ff5a23 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 18 Dec 2020 17:33:02 +0100 Subject: [PATCH 006/219] Fixed efficiency drops --- mods/ENTITIES/mcl_item_entity/init.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 641348132..337da7359 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -193,6 +193,12 @@ local check_can_drop = function(node_name, tool_capabilities) if toolgroupcaps[plus] then return true end + for e=1,5 do + local effplus = plus .. "_efficiency_" .. e + if toolgroupcaps[effplus] then + return true + end + end end end for b=1, #basegroups do @@ -204,6 +210,12 @@ local check_can_drop = function(node_name, tool_capabilities) if toolgroupcaps[plus] then return true end + for e=1,5 do + local effplus = plus .. "_efficiency_" .. e + if toolgroupcaps[effplus] then + return true + end + end end end end From 1f0fc01d206fc0e23e0b856bf06084313355b08e Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 18 Dec 2020 19:03:08 +0100 Subject: [PATCH 007/219] Store XP in furnaces instead of immediately dropping it --- mods/ITEMS/mcl_furnaces/init.lua | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index 5bd2d0cfc..e92075714 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -69,6 +69,18 @@ local receive_fields = function(pos, formname, fields, sender) end end +local function drop_xp(pos) + if mcl_experience.throw_experience then + local meta = minetest.get_meta(pos) + local dir = vector.divide(minetest.facedir_to_dir(minetest.get_node(pos).param2),-1.95) + local xp = meta:get_int("xp") + if xp > 0 then + mcl_experience.throw_experience(vector.add(pos, dir), ) + meta:set_int("xp", 0) + end + end +end + -- -- Node callback functions that are the same for active and inactive furnace -- @@ -143,6 +155,7 @@ local function on_metadata_inventory_take(pos, listname, index, stack, player) elseif stack:get_name() == "mcl_fishing:fish_cooked" then awards.unlock(player:get_player_name(), "mcl:cookFish") end + drop_xp(pos) end end @@ -344,11 +357,8 @@ local function furnace_node_timer(pos, elapsed) srclist = inv:get_list("src") src_time = 0 - - if mcl_experience.throw_experience then - local dir = vector.divide(minetest.facedir_to_dir(minetest.get_node(pos).param2),-1.95) - mcl_experience.throw_experience(vector.add(pos, dir), 1) - end + + meta:set_int("xp", meta:get_int("xp") + 1) -- ToDo give each recipe an idividial XP count end end @@ -462,6 +472,7 @@ minetest.register_node("mcl_furnaces:furnace", { end, on_destruct = function(pos) mcl_particles.delete_node_particlespawners(pos) + drop_xp(pos) end, on_metadata_inventory_move = function(pos) @@ -529,6 +540,7 @@ minetest.register_node("mcl_furnaces:furnace_active", { end, on_destruct = function(pos) mcl_particles.delete_node_particlespawners(pos) + drop_xp(pos) end, allow_metadata_inventory_put = allow_metadata_inventory_put, From 1f124476f2338ab6f63b61fc228da2705d31a37c Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 19 Dec 2020 11:45:41 +0100 Subject: [PATCH 008/219] Remove NC enchanting sound --- .../sounds/mcl_enchanting_enchant.ogg | Bin 14918 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.ogg diff --git a/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.ogg b/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.ogg deleted file mode 100644 index 882e9ee23f2018985157f2948615fc3a58bc9d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14918 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 IA&m(}cR;q*iA zI&st3T%S$VM_)L_8XO4YlnAcoe%IPvAmAYFf_{`Q4AFUilY%Ez8bMZMtP*HtfwPUk z&yvKu9IzF$Ac7Ry9pruOQ#{GbP?m2XPn3O3h#o>rbX=YXwbYdO)so9Afl;~CR5F5Q zC>*upI(n5EP`>$bmY;C}iXC-m>ZB>-p-0ITZvmN~4S}2b6r^+T`SPcu{>B`_ABEWV zyb{7G4>FsBjMT(q7vf_4#-`SZp5oh2fVIrTNIe)G3?rbvjW44o%)q^H44PiFT+JFm ziks?77Yt5Iuk&^h(`RvGr<1@yqdH3dRj;}zt+ld0Y_DvqYz33sCZAEwfhTPP&#hr&ahb)b9Ty^mM4y8 z8eiO-dLvFu)6Mv~Owof3y&*cnVOPELkR1pr^GKLTu@0e=5-b`EB*6S+9d#ihSzc@uYgEfG?mpJJG0*Z9_j$#e*oq)o!|ff From 753be59d953c97289c7e7265b3f7f39a37526100 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 19 Dec 2020 11:53:59 +0100 Subject: [PATCH 009/219] Fixed crash --- mods/ITEMS/mcl_furnaces/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index e92075714..327184890 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -75,7 +75,7 @@ local function drop_xp(pos) local dir = vector.divide(minetest.facedir_to_dir(minetest.get_node(pos).param2),-1.95) local xp = meta:get_int("xp") if xp > 0 then - mcl_experience.throw_experience(vector.add(pos, dir), ) + mcl_experience.throw_experience(vector.add(pos, dir), xp) meta:set_int("xp", 0) end end From 4f18f77db0533ba458436f53fb31d08b7ebea27c Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 19 Dec 2020 13:02:13 +0100 Subject: [PATCH 010/219] Drop xp for empty furnaces too --- mods/ITEMS/mcl_furnaces/init.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index 327184890..82e82807e 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -486,11 +486,15 @@ minetest.register_node("mcl_furnaces:furnace", { -- start timer function, it will sort out whether furnace can burn or not. minetest.get_node_timer(pos):start(1.0) end, - on_metadata_inventory_take = function(pos) + on_metadata_inventory_take = function(pos, listname) -- Reset accumulated game time when player works with furnace: furnace_reset_delta_time(pos) -- start timer function, it will helpful if player clears dst slot minetest.get_node_timer(pos):start(1.0) + + if listname == "dst" then + drop_xp(pos) + end end, allow_metadata_inventory_put = allow_metadata_inventory_put, From 6eeeb83c0d1a02d2ddcfdeaa9d80bb3ff1545f6a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 19 Dec 2020 15:00:15 +0100 Subject: [PATCH 011/219] Let enderdragon drop Xp --- mods/ENTITIES/mobs_mc/ender_dragon.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mods/ENTITIES/mobs_mc/ender_dragon.lua b/mods/ENTITIES/mobs_mc/ender_dragon.lua index dd68cbcce..85b72008f 100644 --- a/mods/ENTITIES/mobs_mc/ender_dragon.lua +++ b/mods/ENTITIES/mobs_mc/ender_dragon.lua @@ -49,6 +49,8 @@ mobs:register_mob("mobs_mc:enderdragon", { arrow = "mobs_mc:dragon_fireball", shoot_interval = 0.5, shoot_offset = -1.0, + xp_min = 12000, + xp_max = 12000, animation = { fly_speed = 8, stand_speed = 8, stand_start = 0, stand_end = 20, From e22b766ffa6afe1edfa9ae567549b4582e1d9c7a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 19 Dec 2020 15:32:32 +0100 Subject: [PATCH 012/219] Remove enchanted compass (caused a crash) --- mods/ITEMS/mcl_compass/depends.txt | 1 - mods/ITEMS/mcl_compass/init.lua | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/mods/ITEMS/mcl_compass/depends.txt b/mods/ITEMS/mcl_compass/depends.txt index 0389d3050..53261d53c 100644 --- a/mods/ITEMS/mcl_compass/depends.txt +++ b/mods/ITEMS/mcl_compass/depends.txt @@ -2,4 +2,3 @@ mcl_core mcl_worlds mesecons doc? -mcl_enchanting diff --git a/mods/ITEMS/mcl_compass/init.lua b/mods/ITEMS/mcl_compass/init.lua index 66553dfc0..b0cf5627e 100644 --- a/mods/ITEMS/mcl_compass/init.lua +++ b/mods/ITEMS/mcl_compass/init.lua @@ -57,9 +57,6 @@ minetest.register_globalstep(function(dtime) if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and minetest.get_item_group(stack:get_name(), "compass")-1 ~= compass_image then local itemname = "mcl_compass:"..compass_image - if mcl_enchanting.is_enchanted(stack:get_name()) then - itemname = itemname .. "_enchanted" - end stack:set_name(itemname) player:get_inventory():set_stack("main", j, stack) end @@ -98,7 +95,7 @@ for i,img in ipairs(images) do inventory_image = img, wield_image = img, stack_max = 64, - groups = {not_in_creative_inventory=inv, compass=i, tool=1, disable_repair=1, enchantability=1 } + groups = {not_in_creative_inventory=inv, compass=i, tool=1, disable_repair=1 } }) -- Help aliases. Makes sure the lookup tool works correctly From 821af9367590502a18e5ab187afb8a5a0c1b2038 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 19 Dec 2020 16:07:34 +0100 Subject: [PATCH 013/219] Translate mcl_experience,mcl_enchanting to de --- .../locale/mcl_experience.de.tr | 7 ++ .../locale/mcl_experience.ru.tr | 1 + .../locale/mlc_experience.fr.tr | 1 + mods/HUD/mcl_experience/locale/template.txt | 2 +- .../locale/mcl_enchanting.de.tr | 100 ++++++++++++++++++ mods/ITEMS/mcl_enchanting/locale/template.txt | 100 ++++++++++++++++++ 6 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 mods/HUD/mcl_experience/locale/mcl_experience.de.tr create mode 100644 mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr create mode 100644 mods/ITEMS/mcl_enchanting/locale/template.txt diff --git a/mods/HUD/mcl_experience/locale/mcl_experience.de.tr b/mods/HUD/mcl_experience/locale/mcl_experience.de.tr new file mode 100644 index 000000000..351cf1911 --- /dev/null +++ b/mods/HUD/mcl_experience/locale/mcl_experience.de.tr @@ -0,0 +1,7 @@ +# textdomain: mcl_experience +[[] ]=[[] ] +Gives a player some XP=Gibt einen Spieler ein paar EP +Error: Too many parameters!=Fehler: Zu viele Parameter! +Error: Incorrect value of XP=Fehler: Ungültiger EP-Wert +Error: Player not found=Fehler: Spieler nicht gefunden +Added @1 XP to @2, total: @3, experience level: @4=@1 EP an @2 gegeben, gesamt: @3, Erfahrungsstufe: @4 diff --git a/mods/HUD/mcl_experience/locale/mcl_experience.ru.tr b/mods/HUD/mcl_experience/locale/mcl_experience.ru.tr index 42cc9ec43..a87840aff 100644 --- a/mods/HUD/mcl_experience/locale/mcl_experience.ru.tr +++ b/mods/HUD/mcl_experience/locale/mcl_experience.ru.tr @@ -1,3 +1,4 @@ +# textdomain: mcl_experience [[] ]=[[<игрок>] ] Gives a player some XP=Даёт игроку XP Error: Too many parameters!=Ошибка: слишком много параметров! diff --git a/mods/HUD/mcl_experience/locale/mlc_experience.fr.tr b/mods/HUD/mcl_experience/locale/mlc_experience.fr.tr index a186b549b..0644e2596 100644 --- a/mods/HUD/mcl_experience/locale/mlc_experience.fr.tr +++ b/mods/HUD/mcl_experience/locale/mlc_experience.fr.tr @@ -1,3 +1,4 @@ +# textdomain: mcl_experience [[] ]=[[] ] Gives a player some XP=Donne de l'XP à un joueur Error: Too many parameters!=Erreur: Trop de paramètres! diff --git a/mods/HUD/mcl_experience/locale/template.txt b/mods/HUD/mcl_experience/locale/template.txt index 8494504e9..a355cbbac 100644 --- a/mods/HUD/mcl_experience/locale/template.txt +++ b/mods/HUD/mcl_experience/locale/template.txt @@ -1,7 +1,7 @@ +# textdomain: mcl_experience [[] ]= Gives a player some XP= Error: Too many parameters!= Error: Incorrect value of XP= Error: Player not found= Added @1 XP to @2, total: @3, experience level: @4= -XP are disabled!= diff --git a/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr b/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr new file mode 100644 index 000000000..58933cb86 --- /dev/null +++ b/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr @@ -0,0 +1,100 @@ +# textdomain: mcl_enchanting +Aqua Affinity=Aquaaffinität +Increases underwater mining speed.=Erhöht Unterwassergrabegeschwindigkeit. +Bane of Arthropods=Schrecken der Gliederfüßler +Increases damage and applies Slowness IV to arthropod mobs (spiders, cave spiders, silverfish and endermites).=Erhöht Schaden und gibt Langsamkeit IV an Gliederfüßlern (Spinnen, Höhlenspinenn, Silberfischchen und Endermilben). +Blast Protection=Explosionsschutz +Reduces explosion damage and knockback.=Reduziert Explosionsschaden und -rückschlag. +Channeling=Kanalisierung +Channels a bolt of lightning toward a target. Works only during thunderstorms and if target is unobstructed with opaque blocks.=Kanalisiert einen Blitz zu einem Ziel. Funktioniert nur während Gewitterstürmen und solange kein undurchsichtiger Block im Weg ist. +Curse of Binding=Fluch der Bindung +Item cannot be removed from armor slots except due to death, breaking or in Creative Mode.=Gegenstand kann nicht von den Rüstungsplätzen entfernt werden, außer beim Tod, Zerbrechen oder im Kreativmodus. +Curse of Vanishing=Fluch des Verschwindens +Item destroyed on death.=Gegenstand wird bei Tod zerstört. +Depth Strider=Tiefenstreicher +Increases underwater movement speed.=Erhöht Bewegungsgeschwindigkeit im Wasser. +Efficiency=Effizienz +Increases mining speed.=Erhöht Grabegeschwindigkeit. +Feather Falling=Federfall +Reduces fall damage.=Reduziert Fallschaden. +Fire Aspect=Feieraspekt +Sets target on fire.=Zündes das Ziel an. +Fire Protection=Feuerschutz +Reduces fire damage.=Reduziert Feuerschaden +Flame=Flamme +Arrows set target on fire.=Pfeile zünden Ziel an. +Fortune=Glück +Increases certain block drops.=Erhöht bestimmte Blockabwürfe. +Frost Walker=Frostläufer +Turns water beneath the player into frosted ice and prevents the damage from magma blocks.=Verwandelt Wasser unter dem Spieler zu brüchigem Eis und verhindert Schaden von Magmablöcken. +Impaling=Aufspießen +Trident deals additional damage to ocean mobs.=Dreizack richtet Zusatzschaden an Ozeanmobs an. +Infinity=Unendlichkeit +Shooting consumes no regular arrows.=Schüsse verbrauchen keine regulären Pfeile. +Knockback=Rückschlag. +Increases knockback.=Verstärkt Rückschlag. +Looting=Plünderer +Increases mob loot.=Erhöht Abwürfe von Mobs. +Loyalty=Loyalität +Trident returns after being thrown. Higher levels reduce return time.=Dreizack kehrt nach Wurf zurück. Höhere Stufen reduzieren die Rückkehrzeit. +Luck of the Sea=Glück des Meeres +Increases rate of good loot (enchanting books, etc.)=Erhöht die Rate von guten Abwürfen (verzauberte Bücher, usw.) +Lure=Köder +Decreases time until rod catches something.=Reduziert die Zeit, bis die Angel etwas fängt. +Mending=Ausbessern +Repair the item while gaining XP orbs.=Gegenstand reparieren, während man Erfahrungskugeln erhält. +Multishot=Mehrschuss +Shoot 3 arrows at the cost of one.=3 Pfeile zum Preis von 1 schießen. +Piercing=Durchbohren +Arrows passes through multiple objects.=Pfeile durchdringen mehrere Objekte. +Power=Stärke +Increases arrow damage.=Erhöht Pfeilschaden. +Projectile Protection=Projektilprojektion +Reduces projectile damage.=Reduziert Projektilschaden. +Protection=Schutz +Reduces most types of damage by 4% for each level.=Reduziert die meisten Schadensarten um 4% je Stufe. +Punch=Schlag +Increases arrow knockback.=Erhöht Pfeilrückschlag. +Quick Charge=Schnellladen +Decreases crossbow charging time.=Reduziert Armbrustladezeit. +Respiration=Atmung +Extends underwater breathing time.=Erhöht Unterwasseratemzeit. +Riptide=Strömung +Trident launches player with itself when thrown. Works only in water or rain.=Dreizack wirft den Spieler mit. Funktioniert nur im Wasser oder Regen. +Sharpness=Schärfe +Increases damage.=Erhöht Schaden. +Silk Touch=Sorgfalt +Mined blocks drop themselves.=Abgebaute Blöcke werfen sich selbst ab. +Smite=Qual +Increases damage to undead mobs.=Erhöht Schaden für untote Mobs. +Soul Speed=Schnelle Seele +Increases walking speed on soul sand.=Erhöht Gehgeschwindigkeit auf Seelensand. +Sweeping Edge=Schwungklinge +Increases sweeping attack damage.=Erhöht Schwungangriffsschaden. +Thorns=Dornen +Reflects some of the damage taken when hit, at the cost of reducing durability with each proc.=Reflektiert etwas des Schadens beim Erleiden eines Treffers, auf Kosten der Haltbarkeit. +Unbreaking=Haltbarkeit +Increases item durability.=Erhöht Haldbarkeit des Gegenstands. +Inventory=Inventar +@1 × Lapis Lazuli=@1 × Lapislazuli +Enchantment levels: @1=Verzauberungsstufen: @1 +Level requirement: @1=Level benötigt: @1 +Enchant an item=Gegenstand verzaubern + []= [] +Usage: /enchant []=Verwendung: /enchant [] +Player '@1' cannot be found.=Spieler „@1“ kann nicht gefunden werden. +There is no such enchantment '@1'.=Es gibt keine Verzauberung namens „@1“. +The target doesn't hold an item.=Das Ziel hält keinen Gegenstand. +The selected enchantment can't be added to the target item.=Die gewählte Verzauberug kann nicht dem Ziel gegeben werden. +'@1' is not a valid number='@1' ist keine gültige Zahl +The number you have entered (@1) is too big, it must be at most @2.=Die eingegebene Zahl (@1) ist zu groß, maximal @1 erlaubt. +The number you have entered (@1) is too small, it must be at least @2.=Die eingegebene Zahl (@1) ist zu klein, minimal @1 erlaubt. +@1 can't be combined with @2.=@1 kann nicht mit @2 kombiniert werden. +Enchanting succeded.=Verzauberug erfolgreich. +Forcefully enchant an item=Einen Gegenstand zwangsweise verzaubern +Usage: /forceenchant []=Verwendung: /forceenchant [] +The target item is not enchantable.=Der Zielgegenstand ist nicht verzauberbar. +'@1' is not a valid number.='@1' ist keine gültige Zahl. +Enchanted Book=Verzaubertes Buch +Enchanting Table=Zaubertisch +Enchant=Verzaubern diff --git a/mods/ITEMS/mcl_enchanting/locale/template.txt b/mods/ITEMS/mcl_enchanting/locale/template.txt new file mode 100644 index 000000000..f186ef37b --- /dev/null +++ b/mods/ITEMS/mcl_enchanting/locale/template.txt @@ -0,0 +1,100 @@ +# textdomain: mcl_enchanting +Aqua Affinity= +Increases underwater mining speed.= +Bane of Arthropods= +Increases damage and applies Slowness IV to arthropod mobs (spiders, cave spiders, silverfish and endermites).= +Blast Protection= +Reduces explosion damage and knockback.= +Channeling= +Channels a bolt of lightning toward a target. Works only during thunderstorms and if target is unobstructed with opaque blocks.= +Curse of Binding= +Item cannot be removed from armor slots except due to death, breaking or in Creative Mode.= +Curse of Vanishing= +Item destroyed on death.= +Depth Strider= +Increases underwater movement speed.= +Efficiency= +Increases mining speed.= +Feather Falling= +Reduces fall damage.= +Fire Aspect= +Sets target on fire.= +Fire Protection= +Reduces fire damage.= +Flame= +Arrows set target on fire.= +Fortune= +Increases certain block drops.= +Frost Walker= +Turns water beneath the player into frosted ice and prevents the damage from magma blocks.= +Impaling= +Trident deals additional damage to ocean mobs.= +Infinity= +Shooting consumes no regular arrows.= +Knockback= +Increases knockback.= +Looting= +Increases mob loot.= +Loyalty= +Trident returns after being thrown. Higher levels reduce return time.= +Luck of the Sea= +Increases rate of good loot (enchanting books, etc.)= +Lure= +Decreases time until rod catches something.= +Mending= +Repair the item while gaining XP orbs.= +Multishot= +Shoot 3 arrows at the cost of one.= +Piercing= +Arrows passes through multiple objects.= +Power= +Increases arrow damage.= +Projectile Protection= +Reduces projectile damage.= +Protection= +Reduces most types of damage by 4% for each level.= +Punch= +Increases arrow knockback.= +Quick Charge= +Decreases crossbow charging time.= +Respiration= +Extends underwater breathing time.= +Riptide= +Trident launches player with itself when thrown. Works only in water or rain.= +Sharpness= +Increases damage.= +Silk Touch= +Mined blocks drop themselves.= +Smite= +Increases damage to undead mobs.= +Soul Speed= +Increases walking speed on soul sand.= +Sweeping Edge= +Increases sweeping attack damage.= +Thorns= +Reflects some of the damage taken when hit, at the cost of reducing durability with each proc.= +Unbreaking= +Increases item durability.= +Inventory= +@1 × Lapis Lazuli= +Enchantment levels: @1= +Level requirement: @1= +Enchant an item= + []= +Usage: /enchant []= +Player '@1' cannot be found.= +There is no such enchantment '@1'.= +The target doesn't hold an item.= +The selected enchantment can't be added to the target item.= +'@1' is not a valid number= +The number you have entered (@1) is too big, it must be at most @2.= +The number you have entered (@1) is too small, it must be at least @2.= +@1 can't be combined with @2.= +Enchanting succeded.= +Forcefully enchant an item= +Usage: /forceenchant []= +The target item is not enchantable.= +'@1' is not a valid number.= +Enchanted Book= +Enchanting Table= +Enchant= From 39a0fdd24c1afec86aaa0f8528d35fa2acc2e830 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 19 Dec 2020 16:18:54 +0100 Subject: [PATCH 014/219] No enchant 4 flint&steel,pumpkin,head,screwdriver --- mods/ITEMS/mcl_farming/pumpkin.lua | 1 - mods/ITEMS/mcl_fire/flint_and_steel.lua | 2 +- mods/ITEMS/mcl_heads/init.lua | 2 +- mods/ITEMS/screwdriver/init.lua | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_farming/pumpkin.lua b/mods/ITEMS/mcl_farming/pumpkin.lua index 990da549d..72b4e5412 100644 --- a/mods/ITEMS/mcl_farming/pumpkin.lua +++ b/mods/ITEMS/mcl_farming/pumpkin.lua @@ -112,7 +112,6 @@ pumpkin_face_base_def._doc_items_longdesc = S("A pumpkin can be worn as a helmet pumpkin_face_base_def._doc_items_usagehelp = nil pumpkin_face_base_def.tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_face.png"} pumpkin_face_base_def.groups.armor_head=1 -pumpkin_face_base_def.groups.enchantability=1 pumpkin_face_base_def._mcl_armor_mob_range_factor = 0 pumpkin_face_base_def._mcl_armor_mob_range_mob = "mobs_mc:enderman" pumpkin_face_base_def.groups.non_combat_armor=1 diff --git a/mods/ITEMS/mcl_fire/flint_and_steel.lua b/mods/ITEMS/mcl_fire/flint_and_steel.lua index 7b585f348..79771baad 100644 --- a/mods/ITEMS/mcl_fire/flint_and_steel.lua +++ b/mods/ITEMS/mcl_fire/flint_and_steel.lua @@ -9,7 +9,7 @@ minetest.register_tool("mcl_fire:flint_and_steel", { inventory_image = "mcl_fire_flint_and_steel.png", liquids_pointable = false, stack_max = 1, - groups = { tool = 1, enchantability = 1 }, + groups = { tool = 1, }, on_place = function(itemstack, user, pointed_thing) -- Use pointed node's on_rightclick function first, if present local node = minetest.get_node(pointed_thing.under) diff --git a/mods/ITEMS/mcl_heads/init.lua b/mods/ITEMS/mcl_heads/init.lua index 7502bf115..a8e9f2cb5 100644 --- a/mods/ITEMS/mcl_heads/init.lua +++ b/mods/ITEMS/mcl_heads/init.lua @@ -42,7 +42,7 @@ local function addhead(name, texture, desc, longdesc, rangemob, rangefactor) { -0.25, -0.5, -0.25, 0.25, 0.0, 0.25, }, }, }, - groups = {handy=1, armor_head=1,non_combat_armor=1, head=1, deco_block=1, dig_by_piston=1, enchantability=1}, + groups = {handy=1, armor_head=1,non_combat_armor=1, head=1, deco_block=1, dig_by_piston=1 }, -- The head textures are based off the textures of an actual mob. tiles = { -- Note: bottom texture is overlaid over top texture to get rid of possible transparency. diff --git a/mods/ITEMS/screwdriver/init.lua b/mods/ITEMS/screwdriver/init.lua index bf264a50c..ec4f1a2ad 100644 --- a/mods/ITEMS/screwdriver/init.lua +++ b/mods/ITEMS/screwdriver/init.lua @@ -176,7 +176,7 @@ minetest.register_tool("screwdriver:screwdriver", { description = S("Screwdriver"), inventory_image = "screwdriver.png", wield_image = "screwdriver.png^[transformFX", - groups = { tool = 1, not_in_creative_inventory = 1, enchantability = 1 }, + groups = { tool = 1, not_in_creative_inventory = 1 }, on_use = function(itemstack, user, pointed_thing) screwdriver.handler(itemstack, user, pointed_thing, screwdriver.ROTATE_FACE, 200) return itemstack From fd53198c9a8cf87d5210177153e63449ef87ceab Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 19 Dec 2020 16:29:55 +0100 Subject: [PATCH 015/219] No enchant for shears --- mods/ITEMS/mcl_tools/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 5df422f08..6dc8d1e0d 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -576,7 +576,7 @@ minetest.register_tool("mcl_tools:shears", { inventory_image = "default_tool_shears.png", wield_image = "default_tool_shears.png", stack_max = 1, - groups = { tool=1, shears=1, dig_speed_class=4, enchantability=1 }, + groups = { tool=1, shears=1, dig_speed_class=4, }, tool_capabilities = { full_punch_interval = 0.5, max_drop_level=1, From b91b58787619b59accbcf4d45a0889e14664cae6 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 20 Dec 2020 16:32:04 +0100 Subject: [PATCH 016/219] Fix Lure --- mods/ITEMS/mcl_fishing/init.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 3b7ba37c0..21f549169 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -248,7 +248,8 @@ local bobber_on_step = function(self, dtime) else if not self._waittime or self._waittime <= 0 then -- wait for random number of ticks. local lure_enchantment = wield and mcl_enchanting.get_enchantment(wield, "lure") or 0 - self._waittime = math.random(5, 30) - lure_enchantment * 5 + local reduced = lure_enchantment * 5 + self._waittime = math.random(math.max(0, 5 - reduced), 30 - reduced) else if self._time < self._waittime then self._time = self._time + dtime From d820c35937f4b198b3324a7648ac532d235c3142 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 20 Dec 2020 17:33:24 +0100 Subject: [PATCH 017/219] Fishing & Mineshaft loot --- mods/CORE/mcl_loot/init.lua | 40 +++++++++++++++++----------- mods/ITEMS/mcl_enchanting/engine.lua | 17 ++++++++++++ mods/ITEMS/mcl_fishing/init.lua | 3 +-- mods/MAPGEN/mcl_dungeons/init.lua | 3 +-- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/mods/CORE/mcl_loot/init.lua b/mods/CORE/mcl_loot/init.lua index 35c72539d..cb371c284 100644 --- a/mods/CORE/mcl_loot/init.lua +++ b/mods/CORE/mcl_loot/init.lua @@ -11,12 +11,15 @@ Parameters: stacks_max = 3, -- Maximum number of item stacks to get. Default: 1 items = { -- Table of possible loot items. This function selects between stacks_min and stacks_max of these. { + weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1) + + itemstack = ItemStack("example:item1"), -- Itemstack to select + -- OR itemstring = "example:item1", -- Which item to select amount_min = 1, -- Minimum size of itemstack. Must not be larger than 6553. Optional (default: 1) amount_max = 10, -- Maximum size of item stack. Must not be larger than item definition's stack_max or 6553. Optional (default: 1) wear_min = 1, -- Minimum wear value. Must be at least 1. Optional (default: no wear) wear_max = 1, -- Maxiumum wear value. Must be at least 1. Optional (default: no wear) - weight = 5, -- Likelihood of this item being selected (see below). Optional (default: 1) }, { -- more tables like above, one table per item stack } } @@ -56,24 +59,29 @@ function mcl_loot.get_loot(loot_definitions, pr) end if item then local itemstring = item.itemstring - if item.amount_min and item.amount_max then - itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max) - end - if item.wear_min and item.wear_max then - -- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10 - local wear_min = math.floor(item.wear_min / 10) - local wear_max = math.floor(item.wear_max / 10) - local wear = pr:next(wear_min, wear_max) * 10 - - if not item.amount_min and not item.amount_max then - itemstring = itemstring .. " 1" + local itemstack = item.itemstack + if itemstring then + if item.amount_min and item.amount_max then + itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max) end + if item.wear_min and item.wear_max then + -- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10 + local wear_min = math.floor(item.wear_min / 10) + local wear_max = math.floor(item.wear_max / 10) + local wear = pr:next(wear_min, wear_max) * 10 + + if not item.amount_min and not item.amount_max then + itemstring = itemstring .. " 1" + end - itemstring = itemstring .. " " .. tostring(wear) + itemstring = itemstring .. " " .. tostring(wear) + end + table.insert(items, itemstring) + elseif itemstack then + table.insert(items, itemstack) + else + minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!") end - table.insert(items, itemstring) - else - minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!") end end diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 0746d211a..9956aca15 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -320,6 +320,23 @@ function mcl_enchanting.get_randomly_enchanted_book(enchantment_level, treasure, return mcl_enchanting.enchant_randomly(enchantment_level, treasure, no_reduced_bonus_chance) end +function mcl_enchanting.get_uniform_randomly_enchanted_book(except) + except = except or except + local stack = ItemStack("mcl_enchanting:book_enchanted") + local list = {} + for enchantment in pairs(mcl_enchanting.enchantments) do + if table.indexof(except, enchantment) == -1 then + table.insert(list, enchantment) + end + end + local index = math.random(#list) + local enchantment = list[index] + local enchantment_def = mcl_enchanting.enchantments[enchantment] + local level = math.random(enchantment_def.max_level) + mcl_enchanting.enchant(stack, enchantment, level) + return stack +end + function mcl_enchanting.get_random_glyph_row() local glyphs = "" local x = 1.3 diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 21f549169..bf63a3c5c 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -88,8 +88,7 @@ local fish = function(itemstack, player) items = { -- TODO: Enchanted Bow { itemstring = "mcl_bows:bow", wear_min = 49144, wear_max = 65535 }, -- 75%-100% damage - -- TODO: Enchanted Book - { itemstring = "mcl_books:book" }, + { itemstack = mcl_enchanting.get_randomly_enchanted_book(30, true, true)}, -- TODO: Enchanted Fishing Rod { itemstring = "mcl_fishing:fishing_rod", wear_min = 49144, wear_max = 65535 }, -- 75%-100% damage { itemstring = "mcl_mobs:nametag", }, diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index b270e6527..6661b1467 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -21,8 +21,7 @@ local get_loot = function() { itemstring = "mcl_jukebox:record_4", weight = 15 }, { itemstring = "mobs_mc:iron_horse_armor", weight = 15 }, { itemstring = "mcl_core:apple_gold", weight = 15 }, - -- TODO: Enchanted Book - { itemstring = "mcl_books:book", weight = 10 }, + { itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}), weight = 10 }, { itemstring = "mobs_mc:gold_horse_armor", weight = 10 }, { itemstring = "mobs_mc:diamond_horse_armor", weight = 5 }, -- TODO: Enchanted Golden Apple From b0dc0ecc9cbe9aa4bc35a146a82ca37626a54cc2 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 21 Dec 2020 13:13:01 +0100 Subject: [PATCH 018/219] Fix possible nil crashes in mcl_jukebox --- mods/ITEMS/mcl_jukebox/init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_jukebox/init.lua b/mods/ITEMS/mcl_jukebox/init.lua index 9a101e33f..db9f25312 100644 --- a/mods/ITEMS/mcl_jukebox/init.lua +++ b/mods/ITEMS/mcl_jukebox/init.lua @@ -81,7 +81,7 @@ local function now_playing(player, track_id) if not player or not player:is_player() or not active_huds[playername] or not hud_sequence_numbers[playername] or seq ~= hud_sequence_numbers[playername] then return end - if id == active_huds[playername] then + if id ~= nil and id == active_huds[playername] then player:hud_remove(active_huds[playername]) active_huds[playername] = nil end @@ -162,8 +162,10 @@ minetest.register_node("mcl_jukebox:jukebox", { inv:set_stack("main", 1, "") if active_tracks[cname] ~= nil then minetest.sound_stop(active_tracks[cname]) - clicker:hud_remove(active_huds[cname]) active_tracks[cname] = nil + end + if active_huds[cname] ~= nil then + clicker:hud_remove(active_huds[cname]) active_huds[cname] = nil end else @@ -219,8 +221,10 @@ minetest.register_node("mcl_jukebox:jukebox", { dropped_item:set_yaw(math.pi/2) if active_tracks[name] ~= nil then minetest.sound_stop(active_tracks[name]) - digger:hud_remove(active_huds[name]) active_tracks[name] = nil + end + if active_huds[name] ~= nil then + digger:hud_remove(active_huds[name]) active_huds[name] = nil end end From fdbfd4c654468a77bb65917b6c36e102d003772b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 21 Dec 2020 13:57:09 +0100 Subject: [PATCH 019/219] Mineshaft Loot --- mods/MAPGEN/tsm_railcorridors/gameconfig.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/MAPGEN/tsm_railcorridors/gameconfig.lua b/mods/MAPGEN/tsm_railcorridors/gameconfig.lua index 615abdc8b..3cea633a6 100644 --- a/mods/MAPGEN/tsm_railcorridors/gameconfig.lua +++ b/mods/MAPGEN/tsm_railcorridors/gameconfig.lua @@ -66,7 +66,7 @@ function tsm_railcorridors.get_treasures(pr) items = { { itemstring = "mcl_mobs:nametag", weight = 30 }, { itemstring = "mcl_core:apple_gold", weight = 20 }, - { itemstring = "mcl_books:book", weight = 10 }, -- TODO: Enchanted Book + { itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}), weight = 10 }, -- TODO: Enchanted Book { itemstring = "", weight = 5}, { itemstring = "mcl_core:pick_iron", weight = 5 }, { itemstring = "mcl_core:apple_gold", weight = 1 }, -- TODO: Enchanted Golden Apple From a4d9d22bb084ee14eb347e23a9082554a7b65d01 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 21 Dec 2020 15:12:24 +0100 Subject: [PATCH 020/219] Mending --- mods/HUD/mcl_experience/init.lua | 70 +++++++++++++++++++++- mods/ITEMS/mcl_bows/bow.lua | 2 + mods/ITEMS/mcl_enchanting/enchantments.lua | 6 +- mods/ITEMS/mcl_fire/flint_and_steel.lua | 1 + mods/ITEMS/mcl_fishing/init.lua | 1 + 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 048bd43c6..28ac779fe 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -331,7 +331,75 @@ local function xp_step(self, dtime) acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z) self.object:add_velocity(vector.add(acceleration,player_velocity)) elseif distance < 0.4 then - mcl_experience.add_experience(collector, self._xp) + local xp = self._xp + local inv = collector:get_inventory() + local candidates = { + {list = "main", index = collector:get_wield_index()}, + {list = "armor", index = 2}, + {list = "armor", index = 3}, + {list = "armor", index = 4}, + {list = "armor", index = 5}, + } + local final_candidates = {} + for _, can in ipairs(candidates) do + local stack = inv:get_stack(can.list, can.index) + local wear = stack:get_wear() + if mcl_enchanting.has_enchantment(stack, "mending") and wear > 0 then + can.stack = stack + can.wear = wear + table.insert(final_candidates, can) + end + end + if #final_candidates > 0 then + local can = final_candidates[math.random(#final_candidates)] + local stack, list, index, wear = can.stack, can.list, can.index, can.wear + local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking") + local uses + local armor_uses = minetest.get_item_group(stack:get_name(), "mcl_armor_uses") + if armor_uses > 0 then + uses = armor_uses + if unbreaking_level > 0 then + uses = uses / (0.6 + 0.4 / (unbreaking_level + 1)) + end + else + local def = stack:get_definition() + if def then + local fixed_uses = def._mcl_uses + if fixed_uses then + uses = fixed_uses + if unbreaking_level > 0 then + uses = uses * (unbreaking_level + 1) + end + end + end + if not uses then + local toolcaps = stack:get_tool_capabilities() + local groupcaps = toolcaps.groupcaps + for _, v in pairs(groupcaps) do + uses = v.uses + break + end + end + end + uses = uses or 0 + local repair = (65536 / uses) * xp * 2 + local new_wear = wear - repair + if new_wear < 0 then + xp = math.floor(-new_wear / 2) + new_wear = 0 + else + xp = 0 + end + stack:set_wear(math.floor(new_wear)) + inv:set_stack(list, index, stack) + if can.list == "armor" then + local armor_inv = minetest.get_inventory({type = "detached", name = collector:get_player_name() .. "_armor"}) + armor_inv:set_stack(list, index, stack) + end + end + if xp > 0 then + mcl_experience.add_experience(collector, xp) + end self.object:remove() end return diff --git a/mods/ITEMS/mcl_bows/bow.lua b/mods/ITEMS/mcl_bows/bow.lua index d4c5fb081..9d09b4414 100644 --- a/mods/ITEMS/mcl_bows/bow.lua +++ b/mods/ITEMS/mcl_bows/bow.lua @@ -132,6 +132,7 @@ S("The speed and damage of the arrow increases the longer you charge. The regula -- Trick to disable digging as well on_use = function() return end, groups = {weapon=1,weapon_ranged=1,bow=1,enchantability=1}, + _mcl_uses = 385, }) -- Iterates through player inventory and resets all the bows in "charging" state back to their original stage @@ -189,6 +190,7 @@ for level=0, 2 do on_place = function(itemstack) return itemstack end, + _mcl_uses = 385, }) end diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index c3bfa05df..1e09fabed 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -409,8 +409,8 @@ mcl_enchanting.enchantments.lure = { power_range_table = {{15, 61}, {24, 71}, {33, 81}}, } --- unimplemented ---[[mcl_enchanting.enchantments.mending = { +-- implemented in mcl_experience +mcl_enchanting.enchantments.mending = { name = S("Mending"), max_level = 1, primary = {}, @@ -424,7 +424,7 @@ mcl_enchanting.enchantments.lure = { requires_tool = true, treasure = true, power_range_table = {{25, 75}}, -}]]-- +} -- requires missing MineClone2 feature --[[mcl_enchanting.enchantments.multishot = { diff --git a/mods/ITEMS/mcl_fire/flint_and_steel.lua b/mods/ITEMS/mcl_fire/flint_and_steel.lua index 7b585f348..39ead4557 100644 --- a/mods/ITEMS/mcl_fire/flint_and_steel.lua +++ b/mods/ITEMS/mcl_fire/flint_and_steel.lua @@ -70,6 +70,7 @@ minetest.register_tool("mcl_fire:flint_and_steel", { return stack end, sound = { breaks = "default_tool_breaks" }, + _mcl_uses = 65, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index bf63a3c5c..4fbc1d0b2 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -330,6 +330,7 @@ minetest.register_tool("mcl_fishing:fishing_rod", { on_place = fish, on_secondary_use = fish, sound = { breaks = "default_tool_breaks" }, + _mcl_uses = 65, }) minetest.register_craft({ From 5fe64ff6f140859d80e5ecc93b4ff9877dbf7b1d Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 21 Dec 2020 17:02:39 +0100 Subject: [PATCH 021/219] Better XP bar --- mods/HUD/mcl_experience/init.lua | 24 ++++++++++-------- .../textures/experience_bar.png | Bin 3745 -> 1540 bytes .../textures/experience_bar_background.png | Bin 2861 -> 1538 bytes 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 28ac779fe..eb9639050 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -77,6 +77,8 @@ hud_manager.add_hud = function(player,hud_name,def) size = def.size, offset = def.offset, z_index = def.z_index, + alignment = def.alignment, + scale = def.scale, }) -- create new 3d array here -- depends.txt is not needed @@ -164,14 +166,14 @@ minetest.register_on_joinplayer(function(player) hud_manager.add_hud(player,"experience_bar", { - hud_elem_type = "statbar", position = {x=0.5, y=1}, - name = "experience bar", - text = "experience_bar.png", - text2 = "experience_bar_background.png", - number = temp_pool.bar, item = 36, - direction = 0, - offset = {x = (-8 * 28) - 29, y = -(48 + 24 + 16)}, - size = { x=28, y=28 }, z_index = 11, + hud_elem_type = "image", + name = "experience bar", + text = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270", + position = {x=0.5, y=1}, + offset = {x = (-9 * 28), y = -(48 + 24 + 16 - 7)}, + scale = {x = 2.75, y = 2.75}, + alignment = { x = 1, y = 1 }, + z_index = 11, }) hud_manager.add_hud(player,"xp_level", @@ -181,7 +183,7 @@ minetest.register_on_joinplayer(function(player) number = 0xFFFFFF, offset = {x = 0, y = -(48 + 24 + 24)}, z_index = 12, - }) + }) end) function mcl_experience.xp_to_level(xp) @@ -247,7 +249,7 @@ function mcl_experience.add_experience(player, experience) end if old_bar ~= temp_pool.bar then - hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "number", data = math.floor(temp_pool.bar)}) + hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",}) end if experience > 0 and minetest.get_us_time()/1000000 - temp_pool.last_time > 0.01 then @@ -283,7 +285,7 @@ minetest.register_on_dieplayer(function(player) temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level) hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(temp_pool.level)}) - hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "number", data = math.floor(temp_pool.bar)}) + hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",}) mcl_experience.throw_experience(player:get_pos(), xp_amount) end) diff --git a/mods/HUD/mcl_experience/textures/experience_bar.png b/mods/HUD/mcl_experience/textures/experience_bar.png index d43a03d641f48a750d8971a6724f8d9f645df5ff..19a2c029d8d47ad9b08c0f53e45a95786a98d41f 100644 GIT binary patch literal 1540 zcma)+4NMbf7{^~$DNx2&p+mlAVGfxH>y@wC0HM%Q>I&Qdiy(|%+bccS_UiQ*9}}m{ zfK(HK8HNfh+guUH#~i~%lsP5>A={h_3__T)$<&~Zsca0`=3a0zO=_~_-g|S;|M$P= zdG2|0)o7a3h2_fv0Jz9f#2Ik6hwJnj2E1Qem+Jz6-7X?22_@8O077cZYvWQbB=}z} z$owd1)K%fWa|mtPWU&Z#a4cxx2&-M#khf@`>RadKE$!=`ni^D%_Fc@$cE}dF{|Ro^To5^eTC}iDB`N?F$7;jkft0Cqto$&b-j+5Tw9N9kU4!8 zP%!`N-QU88yC&XSGS8jJIbauGTT<_1O+6=y?Irvg=c_NYaX;?A(f?s^e$5}Xw=9EX zwT@sXojFGKBF$ID($@dQTUb+55etYj5H&o_Qo~m!40IUnO=Vu51O5rOL4R{X zEMveJs;r3&RW^YBI#1SGah%UuaexbVylbzBVxq1mDj6ZO1oLtPV@D-pSlO6|xP2A;+eJ6ecq&!xsBvMaO znI=q)1H|pvGcqU!u8Lwk5BT!ketX}VTx#%X}W z2qwQ*?1nOXRhAjBLR^j;3uzsQI@Q@DdcwS-W)m7HA_D$?{&#Iq{;!uzQcD+O6b_`a zRFumPM|k0g;Dzh?5s+HHnu6998B|7$(A(~v>o=DPd4C&x5@|3|xYEo2JV)*gxd0pQd#oLPRP=u4q89{1Y=B!(iBx8!aZ0VjjD>hINf|I2MDQZpq?dHi z^YZ`o{QG4QWHU0WJPwaL*l5Fw>PVV2;50?3SF*yUX^dX!n$5BJLKoMD>){bvK1?W4 zg6l!Vk7HlwLe_7Yg}+gunlzPCM4^rbXpu@!sJUX&fDy*iwa9je1wFzvxLHjRrj>jv zgH#m}dOD0Sa?KgiM0uge6VjYVv;i{~X)!fjMB&uR+~v(R!w_&?1xO7nX4$%3DNBM1 NkV(?S9f`_{e*i2WBUbv(p_Z4=A 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 Date: Mon, 21 Dec 2020 18:00:35 +0100 Subject: [PATCH 022/219] Fix translations --- mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr b/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr index 58933cb86..68077578c 100644 --- a/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr +++ b/mods/ITEMS/mcl_enchanting/locale/mcl_enchanting.de.tr @@ -76,8 +76,8 @@ Reflects some of the damage taken when hit, at the cost of reducing durability w Unbreaking=Haltbarkeit Increases item durability.=Erhöht Haldbarkeit des Gegenstands. Inventory=Inventar -@1 × Lapis Lazuli=@1 × Lapislazuli -Enchantment levels: @1=Verzauberungsstufen: @1 +@1 Lapis Lazuli=@1 Lapislazuli +@1 Enchantment Levels=@1 Verzauberungsstufen Level requirement: @1=Level benötigt: @1 Enchant an item=Gegenstand verzaubern []= [] From e152e346eaba7cbe7b9f34aae1198cab608b99f9 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 21 Dec 2020 18:27:58 +0100 Subject: [PATCH 023/219] Improve XP bar position --- mods/HUD/mcl_experience/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index eb9639050..1186ad45e 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -170,8 +170,8 @@ minetest.register_on_joinplayer(function(player) name = "experience bar", text = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270", position = {x=0.5, y=1}, - offset = {x = (-9 * 28), y = -(48 + 24 + 16 - 7)}, - scale = {x = 2.75, y = 2.75}, + offset = {x = (-9 * 28) - 3, y = -(48 + 24 + 16 - 5)}, + scale = {x = 2.8, y = 3.0}, alignment = { x = 1, y = 1 }, z_index = 11, }) From 3161668d26eb42d991ba0b859a466ab81b9d4aa3 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Tue, 22 Dec 2020 10:42:22 +0100 Subject: [PATCH 024/219] Color tweaks --- mods/HUD/mcl_experience/init.lua | 4 +++- mods/ITEMS/mcl_enchanting/init.lua | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 1186ad45e..0043c05ca 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -180,7 +180,7 @@ minetest.register_on_joinplayer(function(player) { hud_elem_type = "text", position = {x=0.5, y=1}, name = "xp_level", text = tostring(temp_pool.level), - number = 0xFFFFFF, + number = 0x80FF20, offset = {x = 0, y = -(48 + 24 + 24)}, z_index = 12, }) @@ -401,6 +401,8 @@ local function xp_step(self, dtime) end if xp > 0 then mcl_experience.add_experience(collector, xp) + else + minetest.sound_play("experience",{gain=0.1,to_player = name,pitch=math.random(75,99)/100}) end self.object:remove() end diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index f5b5b8644..2d4d33dae 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -8,7 +8,8 @@ mcl_enchanting = { book_animation_speed = 40, roman_numerals = dofile(modpath .. "/roman_numerals.lua"), -- https://exercism.io/tracks/lua/exercises/roman-numerals/solutions/73c2fb7521e347209312d115f872fa49 enchantments = {}, - overlay = "^[colorize:white:50^[colorize:purple:50", + overlay = "^[colorize:purple:50", + --overlay = "^[invert:rgb^[multiply:#4df44d:50^[invert:rgb", enchanting_lists = {"enchanting", "enchanting_item", "enchanting_lapis"}, bookshelf_positions = { {x = -2, y = 0, z = -2}, {x = -2, y = 1, z = -2}, From 6ba3fc869ce7b4ecbc8bd318a95813f1cccbf477 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Tue, 22 Dec 2020 12:00:04 +0100 Subject: [PATCH 025/219] Make villagers sell enchanted stuff --- mods/ENTITIES/mobs_mc/villager.lua | 55 +++++++++++++++------------- mods/ITEMS/mcl_enchanting/engine.lua | 10 ++--- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 9788d58c6..477392b7d 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -99,8 +99,7 @@ local professions = { { { { "mcl_fishing:fish_raw", 6, 6, "mcl_core:emerald", 1, 1 }, { "mcl_fishing:fish_cooked", 6, 6 } }, { { "mcl_mobitems:string", 15, 20 }, E1 }, - -- TODO: replace with enchanted fishing rod - { { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod", 1, 1} }, + { { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod_enchanted", 1, 1} }, }, }, }, @@ -154,23 +153,27 @@ local professions = { trades = { { { { "mcl_core:paper", 24, 36 }, E1 }, - -- TODO: enchanted book { { "mcl_books:book", 8, 10 }, E1 }, { { "mcl_core:emerald", 10, 12 }, { "mcl_compass:compass", 1 ,1 }}, { { "mcl_core:emerald", 3, 4 }, { "mcl_books:bookshelf", 1 ,1 }}, + { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, }, { { { "mcl_books:written_book", 2, 2 }, E1 }, { { "mcl_core:emerald", 10, 12 }, { "mcl_clock:clock", 1, 1 } }, { E1, { "mcl_core:glass", 3, 5 } }, + { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, }, { { E1, { "mcl_core:glass", 3, 5 } }, + { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, + }, + + { + { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, }, - - -- TODO: 2 enchanted book tiers { { { "mcl_core:emerald", 20, 22 }, { "mcl_mobs:nametag", 1, 1 } }, @@ -214,8 +217,7 @@ local professions = { { { { "mcl_core:diamond", 3, 4 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond", 1, 1 } }, + { { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond_enchanted", 1, 1 } }, }, { @@ -236,8 +238,7 @@ local professions = { }, { - -- TODO: enchant - { { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather", 1, 1 } }, + { { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather_enchanted", 1, 1 } }, }, { @@ -272,16 +273,13 @@ local professions = { { { { "mcl_core:iron_ingot", 7, 9 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron", 1, 1 } }, + { { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron_enchanted", 1, 1 } }, }, { { { "mcl_core:diamond", 3, 4 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond", 1, 1 } }, - -- TODO: enchant - { { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond", 1, 1 } }, + { { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond_enchanted", 1, 1 } }, + { { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } }, }, }, }, @@ -291,20 +289,17 @@ local professions = { trades = { { { { "mcl_core:coal_lump", 16, 24 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron", 1, 1 } }, + { { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron_enchanted", 1, 1 } }, }, { { { "mcl_core:iron_ingot", 7, 9 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron", 1, 1 } }, + { { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron_enchanted", 1, 1 } }, }, { { { "mcl_core:diamond", 3, 4 }, E1 }, - -- TODO: enchant - { { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond", 1, 1 } }, + { { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond_enchanted", 1, 1 } }, }, }, }, @@ -407,7 +402,16 @@ local init_trades = function(self, inv) local wanted1_count = math.random(trade[1][2], trade[1][3]) local offered_item = trade[2][1] local offered_count = math.random(trade[2][2], trade[2][3]) - + + local offered_stack = ItemStack({name = offered_item, count = offered_count}) + if mcl_enchanting.is_enchanted(offered_item) then + if mcl_enchanting.is_book(offered_item) then + offered_stack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}) + else + mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true) + end + end + local wanted = { wanted1_item .. " " ..wanted1_count } if trade[1][4] then local wanted2_item = trade[1][4] @@ -417,7 +421,7 @@ local init_trades = function(self, inv) table.insert(trades, { wanted = wanted, - offered = offered_item .. " " .. offered_count, + offered = offered_stack:to_table(), tier = tiernum, -- tier of this trade traded_once = false, -- true if trade was traded at least once trade_counter = 0, -- how often the this trade was mate after the last time it got unlocked @@ -426,6 +430,7 @@ local init_trades = function(self, inv) end end self._trades = minetest.serialize(trades) + minetest.deserialize(self._trades) end local set_trade = function(trader, player, inv, concrete_tradenum) @@ -494,7 +499,7 @@ local function show_trade_formspec(playername, trader, tradenum) local wanted1 = inv:get_stack("wanted", 1) local wanted2 = inv:get_stack("wanted", 2) local offered = inv:get_stack("offered", 1) - + local w2_formspec = "" if not wanted2:is_empty() then w2_formspec = "item_image[3,1;1,1;"..wanted2:to_string().."]" @@ -513,7 +518,7 @@ local function show_trade_formspec(playername, trader, tradenum) .."item_image[2,1;1,1;"..wanted1:to_string().."]" .."tooltip[2,1;0.8,0.8;"..F(wanted1:get_description()).."]" ..w2_formspec - .."item_image[5.76,1;1,1;"..offered:to_string().."]" + .."item_image[5.76,1;1,1;"..offered:get_name().." "..offered:get_count().."]" .."tooltip[5.76,1;0.8,0.8;"..F(offered:get_description()).."]" .."list["..tradeinv..";input;2,2.5;2,1;]" .."list["..tradeinv..";output;5.76,2.55;1,1;]" diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 9956aca15..43127b30d 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -252,9 +252,9 @@ function mcl_enchanting.get_possible_enchantments(itemstack, enchantment_level, return possible_enchantments, weights, accum_weight end -function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance) +function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) local itemname = itemstack:get_name() - if not mcl_enchanting.can_enchant_freshly(itemname) then + if not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted then return end itemstack = ItemStack(itemstack) @@ -307,8 +307,8 @@ function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_leve return enchantments, description end -function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance) - local enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance) +function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) + local enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) if enchantments then mcl_enchanting.set_enchanted_itemstring(itemstack) mcl_enchanting.set_enchantments(itemstack, enchantments) @@ -317,7 +317,7 @@ function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, end function mcl_enchanting.get_randomly_enchanted_book(enchantment_level, treasure, no_reduced_bonus_chance) - return mcl_enchanting.enchant_randomly(enchantment_level, treasure, no_reduced_bonus_chance) + return mcl_enchanting.enchant_randomly(ItemStack("mcl_enchanting:book_enchanted"), enchantment_level, treasure, no_reduced_bonus_chance, true) end function mcl_enchanting.get_uniform_randomly_enchanted_book(except) From b56ae38939bd1389cd4227aade573d608fad4b7b Mon Sep 17 00:00:00 2001 From: MysticTempest Date: Tue, 22 Dec 2020 08:29:24 -0600 Subject: [PATCH 026/219] Make lava/fire wait 2 seconds before destroying items to allow chance for pickup, fix dogs following when sitting, and add some rotation so mobs don't idle at cliffs. --- mods/ENTITIES/mcl_item_entity/init.lua | 13 ++++++++----- mods/ENTITIES/mcl_mobs/api.lua | 10 ++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 641348132..214ee5504 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -632,12 +632,15 @@ minetest.register_entity(":__builtin:item", { local fg = minetest.get_item_group(nn, "fire") local dg = minetest.get_item_group(nn, "destroys_items") if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then - if dg ~= 2 then - minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5}, true) + --Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed. + if self.age > 2 then + if dg ~= 2 then + minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.5}) + end + self._removed = true + self.object:remove() + return end - self._removed = true - self.object:remove() - return end -- Push item out when stuck inside solid opaque node diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 596843ac6..dffbd8b39 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2059,6 +2059,7 @@ local follow_flop = function(self) or self.order == "follow") and not self.following and self.state ~= "attack" + and self.order ~= "sit" and self.state ~= "runaway" then local s = self.object:get_pos() @@ -2079,6 +2080,7 @@ local follow_flop = function(self) if self.type == "npc" and self.order == "follow" and self.state ~= "attack" + and self.order ~= "sit" and self.owner ~= "" then -- npc stop following player if not owner @@ -2364,6 +2366,8 @@ local do_states = function(self, dtime) set_velocity(self, 0) self.state = "stand" set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) else set_velocity(self, self.walk_velocity) @@ -2390,6 +2394,8 @@ local do_states = function(self, dtime) set_velocity(self, 0) self.state = "stand" set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) else set_velocity(self, self.run_velocity) set_animation(self, "run") @@ -2622,6 +2628,8 @@ local do_states = function(self, dtime) set_velocity(self, 0) set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) else if self.path.stuck then @@ -3516,6 +3524,8 @@ local mob_step = function(self, dtime) set_velocity(self, 0) self.state = "stand" set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) end -- Despawning: when lifetimer expires, remove mob From 8f62a3fe0c20381671d3f7d128731ce32ceecbc4 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 23 Dec 2020 12:25:18 +0100 Subject: [PATCH 027/219] Enchanted book loot in desert temple --- mods/MAPGEN/mcl_structures/init.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 7723a2688..5b4b6c837 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -402,8 +402,7 @@ mcl_structures.generate_desert_temple = function(pos) { itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 }, { itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 }, { itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 }, - -- TODO: Enchanted Book - { itemstring = "mcl_books:book", weight = 20, }, + { itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}), weight = 20, }, { itemstring = "mcl_mobitems:saddle", weight = 20, }, { itemstring = "mcl_core:apple_gold", weight = 20, }, { itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 }, From 38f89fc9634aa22f96df165a16f83c56d9061fb4 Mon Sep 17 00:00:00 2001 From: MysticTempest Date: Wed, 23 Dec 2020 06:23:55 -0600 Subject: [PATCH 028/219] Fix concrete powder mechanics. --- mods/ITEMS/mcl_colorblocks/init.lua | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/mods/ITEMS/mcl_colorblocks/init.lua b/mods/ITEMS/mcl_colorblocks/init.lua index dad97f62f..4981b39b0 100644 --- a/mods/ITEMS/mcl_colorblocks/init.lua +++ b/mods/ITEMS/mcl_colorblocks/init.lua @@ -97,7 +97,7 @@ for _, row in ipairs(block.dyes) do _doc_items_create_entry = create_entry, _doc_items_entry_name = ename_cp, tiles = {"mcl_colorblocks_concrete_powder_"..name..".png"}, - groups = {handy=1,shovely=1, concrete_powder=1,building_block=1,falling_node=1, material_sand=1}, + groups = {handy=1,shovely=1, concrete_powder=1,building_block=1,falling_node=1, material_sand=1, float=1}, stack_max = 64, is_ground_content = false, sounds = mcl_sounds.node_sound_sand_defaults(), @@ -208,11 +208,20 @@ minetest.register_abm({ neighbors = {"group:water"}, action = function(pos, node) local harden_to = minetest.registered_nodes[node.name]._mcl_colorblocks_harden_to - -- It should be impossible for harden_to to be nil, but a Minetest bug might call - -- the ABM on the new concrete node, which isn't part of this ABM! - if harden_to then - node.name = harden_to - minetest.set_node(pos, node) - end + -- It should be impossible for harden_to to be nil, but a Minetest bug might call + -- the ABM on the new concrete node, which isn't part of this ABM! + if harden_to then + node.name = harden_to + --Fix "float" group not lowering concrete into the water by 1. + local water_pos = { x = pos.x, y = pos.y-1, z = pos.z } + local water_node = minetest.get_node(water_pos) + if minetest.get_item_group(water_node.name, "water") == 0 then + minetest.set_node(pos, node) + else + minetest.set_node(water_pos,node) + minetest.set_node(pos, {name = "air"}) + minetest.check_for_falling(pos) -- Update C. Powder that stacked above so they fall down after setting air. + end + end end, }) From a7ff5be28b0ee981b7147c6526e635a0f1aa702c Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 23 Dec 2020 15:18:20 +0100 Subject: [PATCH 029/219] Luck of the Sea --- mods/ITEMS/mcl_enchanting/enchantments.lua | 5 ++--- mods/ITEMS/mcl_fishing/init.lua | 11 ++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index 1e09fabed..7d53f012b 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -375,8 +375,7 @@ end power_range_table = {{12, 50}, {19, 50}, {26, 50}}, }]]-- --- unimplemented ---[[mcl_enchanting.enchantments.luck_of_the_sea = { +mcl_enchanting.enchantments.luck_of_the_sea = { name = S("Luck of the Sea"), max_level = 3, primary = {fishing_rod = true}, @@ -390,7 +389,7 @@ end requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, -}]]-- +} -- implemented in mcl_fishing mcl_enchanting.enchantments.lure = { diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 4fbc1d0b2..c95dd20e5 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -52,10 +52,15 @@ local fish = function(itemstack, player) local items local itemcount = 1 local itemwear = 0 - -- FIXME: Maybe use a better seeding local pr = PseudoRandom(os.time() * math.random(1, 100)) local r = pr:next(1, 100) - if r <= 85 then + local fish_values = {85, 84.8, 84.7, 84.5} + local junk_values = {10, 8.1, 6.1, 4.2} + local luck_of_the_sea = math.min(mcl_enchanting.get_enchantment(itemstack, "luck_of_the_sea"), 3) + local index = luck_of_the_sea + 1 + local fish_value = fish_values[index] + local junk_value = junk_values[index] + fish_value + if r <= fish_value then -- Fish items = mcl_loot.get_loot({ items = { @@ -65,7 +70,7 @@ local fish = function(itemstack, player) { itemstring = "mcl_fishing:pufferfish_raw", weight = 13 }, } }, pr) - elseif r <= 95 then + elseif r <= junk_value then -- Junk items = mcl_loot.get_loot({ items = { From da7240d6c1863e04e84f7297e1801ed5361eea4b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 23 Dec 2020 17:41:42 +0100 Subject: [PATCH 030/219] looting --- mods/ENTITIES/mcl_mobs/api.lua | 38 +++++++++++++++---- mods/ENTITIES/mobs_mc/blaze.lua | 3 +- mods/ENTITIES/mobs_mc/chicken.lua | 6 ++- mods/ENTITIES/mobs_mc/cow+mooshroom.lua | 6 ++- mods/ENTITIES/mobs_mc/creeper.lua | 5 ++- mods/ENTITIES/mobs_mc/enderman.lua | 3 +- mods/ENTITIES/mobs_mc/ghast.lua | 4 +- mods/ENTITIES/mobs_mc/guardian.lua | 25 ++++++++---- mods/ENTITIES/mobs_mc/guardian_elder.lua | 25 ++++++++---- mods/ENTITIES/mobs_mc/horse.lua | 3 +- mods/ENTITIES/mobs_mc/llama.lua | 3 +- mods/ENTITIES/mobs_mc/parrot.lua | 3 +- mods/ENTITIES/mobs_mc/pig.lua | 3 +- mods/ENTITIES/mobs_mc/polar_bear.lua | 6 ++- mods/ENTITIES/mobs_mc/rabbit.lua | 8 ++-- mods/ENTITIES/mobs_mc/sheep.lua | 6 ++- mods/ENTITIES/mobs_mc/shulker.lua | 8 ++-- mods/ENTITIES/mobs_mc/skeleton+stray.lua | 26 +++++++++---- mods/ENTITIES/mobs_mc/skeleton_wither.lua | 9 +++-- mods/ENTITIES/mobs_mc/spider.lua | 6 ++- mods/ENTITIES/mobs_mc/squid.lua | 3 +- mods/ENTITIES/mobs_mc/villager_evoker.lua | 3 +- mods/ENTITIES/mobs_mc/villager_vindicator.lua | 8 ++-- mods/ENTITIES/mobs_mc/villager_zombie.lua | 15 ++++++-- mods/ENTITIES/mobs_mc/witch.lua | 14 +++---- mods/ENTITIES/mobs_mc/zombie.lua | 15 ++++++-- mods/ENTITIES/mobs_mc/zombiepig.lua | 14 ++++--- mods/ITEMS/mcl_enchanting/enchantments.lua | 7 ++-- 28 files changed, 188 insertions(+), 87 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 596843ac6..c769fee05 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -643,11 +643,13 @@ end -- drop items -local item_drop = function(self, cooked) +local item_drop = function(self, cooked, looting_level) -- no drops if disabled by setting if not mobs_drop_items then return end - + + looting_level = looting_level or 0 + -- no drops for child mobs (except monster) if (self.child and self.type ~= "monster") then return @@ -659,11 +661,33 @@ local item_drop = function(self, cooked) self.drops = self.drops or {} -- nil check for n = 1, #self.drops do - - if random(1, self.drops[n].chance) == 1 then - - num = random(self.drops[n].min or 1, self.drops[n].max or 1) - item = self.drops[n].name + local dropdef = self.drops[n] + local chance = 1 / dropdef.chance + local looting_type = dropdef.looting + + if looting_level > 0 then + local chance_function = dropdef.looting_chance_function + if chance_function then + chance = chance_function(looting_level) + elseif looting_type == "rare" then + chance = chance + (dropdef.looting_factor or 0.01) * looting_level + end + end + + local num = 0 + local do_common_looting = (looting_level > 0 and looting_type == "common") + if random() < chance then + num = random(dropdef.min or 1, dropdef.max or 1) + elseif not dropdef.looting_ignore_chance then + do_common_looting = false + end + + if do_common_looting then + num = num + math.floor(math.random(0, looting_level) + 0.5) + end + + if num > 0 then + item = dropdef.name -- cook items when true if cooked then diff --git a/mods/ENTITIES/mobs_mc/blaze.lua b/mods/ENTITIES/mobs_mc/blaze.lua index aae82a39b..3e0af9ab1 100644 --- a/mods/ENTITIES/mobs_mc/blaze.lua +++ b/mods/ENTITIES/mobs_mc/blaze.lua @@ -41,7 +41,8 @@ mobs:register_mob("mobs_mc:blaze", { {name = mobs_mc.items.blaze_rod, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common",}, }, animation = { stand_speed = 25, diff --git a/mods/ENTITIES/mobs_mc/chicken.lua b/mods/ENTITIES/mobs_mc/chicken.lua index 618d1e0f0..325371e2b 100644 --- a/mods/ENTITIES/mobs_mc/chicken.lua +++ b/mods/ENTITIES/mobs_mc/chicken.lua @@ -32,11 +32,13 @@ mobs:register_mob("mobs_mc:chicken", { {name = mobs_mc.items.chicken_raw, chance = 1, min = 1, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.feather, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, }, fall_damage = 0, fall_speed = -2.25, diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index e8482d820..005af2980 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -23,11 +23,13 @@ local cow_def = { {name = mobs_mc.items.beef_raw, chance = 1, min = 1, - max = 3,}, + max = 3, + looting = "common",}, {name = mobs_mc.items.leather, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, }, runaway = true, sounds = { diff --git a/mods/ENTITIES/mobs_mc/creeper.lua b/mods/ENTITIES/mobs_mc/creeper.lua index a52e6e1e1..325d78b15 100644 --- a/mods/ENTITIES/mobs_mc/creeper.lua +++ b/mods/ENTITIES/mobs_mc/creeper.lua @@ -78,7 +78,7 @@ mobs:register_mob("mobs_mc:creeper", { end, on_die = function(self, pos) -- Drop a random music disc - -- TODO: Only do this if killed by skeleton + -- TODO: Only do this if killed by skeleton or stray if math.random(1, 200) == 1 then local r = math.random(1, #mobs_mc.items.music_discs) minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, mobs_mc.items.music_discs[r]) @@ -89,7 +89,8 @@ mobs:register_mob("mobs_mc:creeper", { {name = mobs_mc.items.gunpowder, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, -- Head -- TODO: Only drop if killed by charged creeper diff --git a/mods/ENTITIES/mobs_mc/enderman.lua b/mods/ENTITIES/mobs_mc/enderman.lua index 934497a10..1b572fac6 100644 --- a/mods/ENTITIES/mobs_mc/enderman.lua +++ b/mods/ENTITIES/mobs_mc/enderman.lua @@ -220,7 +220,8 @@ mobs:register_mob("mobs_mc:enderman", { {name = mobs_mc.items.ender_pearl, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common"}, }, animation = select_enderman_animation("normal"), _taken_node = "", diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 713333085..5bd05b860 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -38,8 +38,8 @@ mobs:register_mob("mobs_mc:ghast", { walk_velocity = 1.6, run_velocity = 3.2, drops = { - {name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2,}, - {name = mobs_mc.items.ghast_tear, chance = 3,min = 0,max = 1,}, + {name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"}, + {name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true}, }, animation = { stand_speed = 50, walk_speed = 50, run_speed = 50, diff --git a/mods/ENTITIES/mobs_mc/guardian.lua b/mods/ENTITIES/mobs_mc/guardian.lua index dd273c1eb..13c857ea3 100644 --- a/mods/ENTITIES/mobs_mc/guardian.lua +++ b/mods/ENTITIES/mobs_mc/guardian.lua @@ -46,7 +46,8 @@ mobs:register_mob("mobs_mc:guardian", { {name = mobs_mc.items.prismarine_shard, chance = 1, min = 0, - max = 32,}, + max = 32, + looting = "common",}, -- TODO: Reduce of drops when ocean monument is ready. -- The following drops are approximations @@ -54,29 +55,39 @@ mobs:register_mob("mobs_mc:guardian", { {name = mobs_mc.items.fish_raw, chance = 4, min = 1, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.prismarine_crystals, chance = 4, min = 1, - max = 2,}, + max = 2, + looting = "common",}, -- Rare drop: fish {name = mobs_mc.items.fish_raw, chance = 160, -- 2.5% / 4 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.0025,}, {name = mobs_mc.items.salmon_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.0025,}, {name = mobs_mc.items.clownfish_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.0025,}, {name = mobs_mc.items.pufferfish_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.0025,}, }, fly = true, makes_footstep_sound = false, diff --git a/mods/ENTITIES/mobs_mc/guardian_elder.lua b/mods/ENTITIES/mobs_mc/guardian_elder.lua index 7094dee24..a58a4a5b7 100644 --- a/mods/ENTITIES/mobs_mc/guardian_elder.lua +++ b/mods/ENTITIES/mobs_mc/guardian_elder.lua @@ -51,7 +51,8 @@ mobs:register_mob("mobs_mc:guardian_elder", { {name = mobs_mc.items.prismarine_shard, chance = 1, min = 1, - max = 64,}, + max = 64, + looting = "common",}, -- TODO: Only drop if killed by player {name = mobs_mc.items.wet_sponge, @@ -64,29 +65,39 @@ mobs:register_mob("mobs_mc:guardian_elder", { {name = mobs_mc.items.fish_raw, chance = 4, min = 1, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.prismarine_crystals, chance = 1, min = 1, - max = 10,}, + max = 10, + looting = "common",}, -- Rare drop: fish {name = mobs_mc.items.fish_raw, chance = 160, -- 2.5% / 4 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 4,}, {name = mobs_mc.items.salmon_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 4,}, {name = mobs_mc.items.clownfish_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 4,}, {name = mobs_mc.items.pufferfish_raw, chance = 160, min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 4,}, }, fly = true, makes_footstep_sound = false, diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index 95a02bfca..b9d82660c 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -127,7 +127,8 @@ local horse = { {name = mobs_mc.items.leather, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, }, do_custom = function(self, dtime) diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 58a70de2f..36d020a65 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -54,7 +54,8 @@ mobs:register_mob("mobs_mc:llama", { {name = mobs_mc.items.leather, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, }, fear_height = 4, sounds = { diff --git a/mods/ENTITIES/mobs_mc/parrot.lua b/mods/ENTITIES/mobs_mc/parrot.lua index 90bf215ed..407cb4466 100644 --- a/mods/ENTITIES/mobs_mc/parrot.lua +++ b/mods/ENTITIES/mobs_mc/parrot.lua @@ -37,7 +37,8 @@ mobs:register_mob("mobs_mc:parrot", { {name = mobs_mc.items.feather, chance = 1, min = 1, - max = 2,}, + max = 2, + looting = "common",}, }, animation = { stand_speed = 50, diff --git a/mods/ENTITIES/mobs_mc/pig.lua b/mods/ENTITIES/mobs_mc/pig.lua index 09bda3199..38700b6ca 100644 --- a/mods/ENTITIES/mobs_mc/pig.lua +++ b/mods/ENTITIES/mobs_mc/pig.lua @@ -27,7 +27,8 @@ mobs:register_mob("mobs_mc:pig", { {name = mobs_mc.items.porkchop_raw, chance = 1, min = 1, - max = 3,}, + max = 3, + looting = "common",}, }, fear_height = 4, sounds = { diff --git a/mods/ENTITIES/mobs_mc/polar_bear.lua b/mods/ENTITIES/mobs_mc/polar_bear.lua index d974c7a60..459ca29b4 100644 --- a/mods/ENTITIES/mobs_mc/polar_bear.lua +++ b/mods/ENTITIES/mobs_mc/polar_bear.lua @@ -36,12 +36,14 @@ mobs:register_mob("mobs_mc:polar_bear", { {name = mobs_mc.items.fish_raw, chance = 2, min = 0, - max = 2,}, + max = 2, + looting = "common",}, -- 1/4 to drop raw salmon {name = mobs_mc.items.salmon_raw, chance = 4, min = 0, - max = 2,}, + max = 2, + looting = "common",}, }, floats = 1, diff --git a/mods/ENTITIES/mobs_mc/rabbit.lua b/mods/ENTITIES/mobs_mc/rabbit.lua index e2f9d213f..e167649f6 100644 --- a/mods/ENTITIES/mobs_mc/rabbit.lua +++ b/mods/ENTITIES/mobs_mc/rabbit.lua @@ -41,11 +41,9 @@ local rabbit = { runaway = true, jump = true, drops = { - {name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1}, - {name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1}, - {name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1}, - -- TODO: Drop rabbit's foot when it's useful - --{name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, max = 1}, + {name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1, looting = "common",}, + {name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1, looting = "common",}, + {name = mobs_mc.items.rabbit_foot, chance = 10, min = 0, max = 1, looting = "rare", looting_factor = 0.03,}, }, fear_height = 4, animation = { diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index ecf3ad5c0..681c68e1b 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -63,11 +63,13 @@ mobs:register_mob("mobs_mc:sheep", { {name = mobs_mc.items.mutton_raw, chance = 1, min = 1, - max = 2,}, + max = 2, + looting = "common",}, {name = colors["unicolor_white"][1], chance = 1, min = 1, - max = 1,}, + max = 1, + looting = "common",}, }, fear_height = 4, sounds = { diff --git a/mods/ENTITIES/mobs_mc/shulker.lua b/mods/ENTITIES/mobs_mc/shulker.lua index 97de5aba6..faaf2ac40 100644 --- a/mods/ENTITIES/mobs_mc/shulker.lua +++ b/mods/ENTITIES/mobs_mc/shulker.lua @@ -35,9 +35,11 @@ mobs:register_mob("mobs_mc:shulker", { jump = false, drops = { {name = mobs_mc.items.shulker_shell, - chance = 1, - min = 0, - max = 1,}, + chance = 2, + min = 1, + max = 1, + looting = "rare", + looting_factor = 0.0625}, }, animation = { stand_speed = 25, walk_speed = 25, run_speed = 50, punch_speed = 25, diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index 45cc6b979..f3ef3c4b1 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -46,15 +46,18 @@ local skeleton = { {name = mobs_mc.items.arrow, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, {name = mobs_mc.items.bow, - chance = 11, + chance = 100 / 8.5, min = 1, - max = 1,}, + max = 1, + looting = "rare",}, {name = mobs_mc.items.bone, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, -- Head -- TODO: Only drop if killed by charged creeper @@ -116,12 +119,21 @@ stray.textures = { -- TODO: different sound (w/ echo) -- TODO: stray's arrow inflicts slowness status table.insert(stray.drops, { - -- Chance to drop additional arrow. - -- TODO: Should be tipped arrow of slowness - name = mobs_mc.items.arrow, + name = "mcl_potions:slowness_arrow", chance = 2, min = 1, max = 1, + looting = "rare", + looting_chance_function = function(lvl) + local chance = 0.5 + for i = 1, lvl do + if chance > 1 then + return 1 + end + chance = chance + (1 - chance) / 2 + end + return chance + end, }) mobs:register_mob("mobs_mc:stray", stray) diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index 6dd2fcdbe..7684dc409 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -45,17 +45,20 @@ mobs:register_mob("mobs_mc:witherskeleton", { {name = mobs_mc.items.coal, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.bone, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, -- Head {name = mobs_mc.items.head_wither_skeleton, chance = 40, -- 2.5% chance min = 1, - max = 1,}, + max = 1, + looting = "rare",}, }, animation = { stand_start = 0, diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index 72a996038..0bb03a9c7 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -49,8 +49,10 @@ local spider = { view_range = 16, floats = 1, drops = { - {name = mobs_mc.items.string, chance = 1, min = 0, max = 2,}, - {name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1,}, + {name = mobs_mc.items.string, chance = 1, min = 0, max = 2, looting = "common"}, + {name = mobs_mc.items.spider_eye, chance = 3, min = 1, max = 1, looting = "common", looting_chance_function = function(lvl) + return 1 - 2 / (lvl + 3) + end}, }, specific_attack = { "player", "mobs_mc:iron_golem" }, fear_height = 4, diff --git a/mods/ENTITIES/mobs_mc/squid.lua b/mods/ENTITIES/mobs_mc/squid.lua index 392143321..1877a2104 100644 --- a/mods/ENTITIES/mobs_mc/squid.lua +++ b/mods/ENTITIES/mobs_mc/squid.lua @@ -42,7 +42,8 @@ mobs:register_mob("mobs_mc:squid", { {name = mobs_mc.items.black_dye, chance = 1, min = 1, - max = 3,}, + max = 3, + looting = "common",}, }, visual_size = {x=3, y=3}, makes_footstep_sound = false, diff --git a/mods/ENTITIES/mobs_mc/villager_evoker.lua b/mods/ENTITIES/mobs_mc/villager_evoker.lua index b865a2bd5..226c82a32 100644 --- a/mods/ENTITIES/mobs_mc/villager_evoker.lua +++ b/mods/ENTITIES/mobs_mc/villager_evoker.lua @@ -55,7 +55,8 @@ mobs:register_mob("mobs_mc:evoker", { {name = mobs_mc.items.emerald, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.totem, chance = 1, min = 1, diff --git a/mods/ENTITIES/mobs_mc/villager_vindicator.lua b/mods/ENTITIES/mobs_mc/villager_vindicator.lua index 825ffd88f..31ff597ba 100644 --- a/mods/ENTITIES/mobs_mc/villager_vindicator.lua +++ b/mods/ENTITIES/mobs_mc/villager_vindicator.lua @@ -41,11 +41,13 @@ mobs:register_mob("mobs_mc:vindicator", { {name = mobs_mc.items.emerald, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common",}, {name = mobs_mc.items.iron_axe, - chance = 11, + chance = 100 / 8.5, min = 1, - max = 1,}, + max = 1, + looting = "rare",}, }, -- TODO: sounds animation = { diff --git a/mods/ENTITIES/mobs_mc/villager_zombie.lua b/mods/ENTITIES/mobs_mc/villager_zombie.lua index 524a918de..e385185d5 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -44,19 +44,26 @@ mobs:register_mob("mobs_mc:villager_zombie", { {name = mobs_mc.items.rotten_flesh, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, {name = mobs_mc.items.iron_ingot, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, {name = mobs_mc.items.carrot, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, {name = mobs_mc.items.potato, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, }, sounds = { random = "mobs_mc_zombie_growl", diff --git a/mods/ENTITIES/mobs_mc/witch.lua b/mods/ENTITIES/mobs_mc/witch.lua index 5cddd5b42..d301fcb59 100644 --- a/mods/ENTITIES/mobs_mc/witch.lua +++ b/mods/ENTITIES/mobs_mc/witch.lua @@ -41,13 +41,13 @@ mobs:register_mob("mobs_mc:witch", { dogshoot_count_max =1.8, max_drops = 3, drops = { - {name = mobs_mc.items.glass_bottle, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.glowstone_dust, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.redstone, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.spider_eye, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2,}, - {name = mobs_mc.items.stick, chance = 4, min = 0, max = 2,}, + {name = mobs_mc.items.glass_bottle, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.glowstone_dust, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.gunpowder, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.redstone, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.spider_eye, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.sugar, chance = 8, min = 0, max = 2, looting = "common",}, + {name = mobs_mc.items.stick, chance = 4, min = 0, max = 2, looting = "common",}, }, -- TODO: sounds animation = { diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index beb51d89f..75c8273c6 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -13,19 +13,26 @@ local drops_common = { {name = mobs_mc.items.rotten_flesh, chance = 1, min = 0, - max = 2,}, + max = 2, + looting = "common",}, {name = mobs_mc.items.iron_ingot, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, {name = mobs_mc.items.carrot, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, {name = mobs_mc.items.potato, chance = 120, -- 2.5% / 3 min = 1, - max = 1,}, + max = 1, + looting = "rare", + looting_factor = 0.01 / 3,}, } local drops_zombie = table.copy(drops_common) diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index a552f6d23..5b79e53b5 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -50,19 +50,23 @@ local pigman = { {name = mobs_mc.items.rotten_flesh, chance = 1, min = 1, - max = 1,}, + max = 1, + looting = "common"}, {name = mobs_mc.items.gold_nugget, chance = 1, min = 0, - max = 1,}, + max = 1, + looting = "common"}, {name = mobs_mc.items.gold_ingot, chance = 40, -- 2.5% min = 1, - max = 1,}, + max = 1, + looting = "rare"}, {name = mobs_mc.items.gold_sword, - chance = 12, -- 8.333%, approximation to 8.5% + chance = 100 / 8.5, min = 1, - max = 1,}, + max = 1, + looting = "rare"}, }, animation = { stand_speed = 25, diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index 7d53f012b..709a647f8 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -341,8 +341,8 @@ function minetest.calculate_knockback(player, hitter, time_from_last_punch, tool return knockback end --- unimplemented ---[[mcl_enchanting.enchantments.looting = { +-- implemented in mcl_mobs and mobs_mc +mcl_enchanting.enchantments.looting = { name = S("Looting"), max_level = 3, primary = {sword = true}, @@ -356,7 +356,7 @@ end requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, -}]]-- +} -- requires missing MineClone2 feature --[[mcl_enchanting.enchantments.loyalty = { @@ -375,6 +375,7 @@ end power_range_table = {{12, 50}, {19, 50}, {26, 50}}, }]]-- +-- implemented in mcl_fishing mcl_enchanting.enchantments.luck_of_the_sea = { name = S("Luck of the Sea"), max_level = 3, From b017fd74050c1080f6903a73a2ef95c9e98b0ab8 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 23 Dec 2020 19:01:49 +0100 Subject: [PATCH 031/219] Looting actually works now --- mods/ENTITIES/mcl_mobs/api.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index c769fee05..878745188 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -776,9 +776,16 @@ local check_for_death = function(self, cause, cmi_cause) local function death_handle(self) -- dropped cooked item if mob died in fire or lava if cause == "lava" or cause == "fire" then - item_drop(self, true) + item_drop(self, true, 0) else - item_drop(self, nil) + local looting = 0 + if cause == "hit" then + local puncher = cmi_cause.puncher + if puncher then + looting = mcl_enchanting.get_enchantment(puncher:get_wielded_item(), "looting") + end + end + item_drop(self, nil, looting) end local pos = self.object:get_pos() From c85f2f60646eb7a65125ba00f59ea17ea811d3d0 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 24 Dec 2020 04:05:07 +0100 Subject: [PATCH 032/219] Version 0.69.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83bd4d861..eab5068cc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.68.0 +Version: 0.69.0 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From 7545e29f580972666dceaebed5b0d949620a3658 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 24 Dec 2020 17:48:40 +0100 Subject: [PATCH 033/219] Burning objects --- mods/ENTITIES/mcl_burning/init.lua | 190 +++++++++++++++++++++ mods/ENTITIES/mcl_mobs/api.lua | 13 +- mods/ENTITIES/mobs_mc/blaze.lua | 1 + mods/ENTITIES/mobs_mc/ender_dragon.lua | 3 +- mods/ENTITIES/mobs_mc/ghast.lua | 1 + mods/ENTITIES/mobs_mc/skeleton_wither.lua | 1 + mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 3 +- mods/ENTITIES/mobs_mc/zombiepig.lua | 1 + mods/ITEMS/mcl_armor/armor.lua | 2 +- 9 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 mods/ENTITIES/mcl_burning/init.lua diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua new file mode 100644 index 000000000..768afb324 --- /dev/null +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -0,0 +1,190 @@ +mcl_burning = {} + +local S = minetest.get_translator("mcl_burning") + +function mcl_burning.play_sound(obj, soundname) + minetest.sound_play(soundname, { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) +end + +function mcl_burning.get_collisionbox(obj) + local box = obj:get_properties().collisionbox + return vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6]) +end + +function mcl_burning.is_touching_nodes(obj, nodes) + local pos = obj:get_pos() + local box = obj:get_properties().collisionbox + local minp, maxp = mcl_burning.get_collisionbox(obj) + local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodes) + return #nodes > 0 +end + +function mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, old_spawner) + local new_spawner + if old_spawner == 0 then + old_spawner = nil + end + local delete_old_spawner = false + if burn_time and (not old_spawner or burn_time >= old_burn_time) then + delete_old_spawner = true + local minp, maxp = mcl_burning.get_collisionbox(obj) + new_spawner = minetest.add_particlespawner({ + amount = 1000 * burn_time, + time = burn_time, + minpos = minp, + maxpos = maxp, + minvel = {x = -0.5, y = 1, z = -0.5}, + maxvel = {x = 0.5, y = 2, z = -0.5}, + minacc = {x = -0.1, y = 8, z = -0.1}, + maxacc = {x = 0.1, y = 10, z = 0.1}, + minexptime = 0.2, + maxexptime = 0.3, + minsize = 1, + maxsize = 2, + collisiondetection = true, + texture = "fire_basic_flame.png", + attached = obj, + }) + elseif not burn_time and old_spawner then + delete_old_spawner = true + end + if delete_old_spawner and old_spawner then + minetest.delete_particlespawner(old_spawner) + old_spawner = nil + end + return new_spawner or old_spawner +end + +function mcl_burning.analyse(obj, meta, is_player) + if meta then + return meta, is_player + end + is_player = obj:is_player() + if is_player then + meta = obj:get_meta() + else + meta = obj:get_luaentity() + end + return meta, is_player +end + +function mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player) + meta, is_player = mcl_burning.analyse(obj, meta, is_player) + old_burn_time = old_burn_time or mcl_burning.get_burning(obj, meta, is_player) + if burn_time <= 0 then + burn_time = nil + end + if is_player then + if burn_time then + meta:set_float("mcl_burning:burn_time", burn_time) + elseif old_burn_time > 0 then + meta:set_string("mcl_burning:burn_time", "") + mcl_burning.play_sound(obj, "fire_extinguish_flame") + end + local fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta:get_int("mcl_burning:fire_spawner")) + if fire_spawner then + meta:set_int("mcl_burning:fire_spawner", fire_spawner) + else + meta:set_string("mcl_burning:fire_spawner", "") + end + elseif not meta._fire_resistant then + meta._burn_time = burn_time + meta._fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta._fire_spawner) + if not burn_time and old_burn_time > 0 then + mcl_burning.play_sound(obj, "fire_extinguish_flame") + end + end +end + +function mcl_burning.get_burning(obj, meta, is_player) + meta, is_player = mcl_burning.analyse(obj, meta, is_player) + if is_player then + return meta:get_float("mcl_burning:burn_time") + else + return meta._burn_time or 0 + end +end + +function mcl_burning.damage(obj, meta, is_player) + local hp + if is_player then + hp = obj:get_hp() + else + hp = meta.health or 0 + end + if hp <= 0 then + return + end + meta, is_player = mcl_burning.analyse(obj, meta, is_player) + local do_damage = true + if is_player then + if mcl_potions.player_has_effect(obj, "fire_resistance") then + do_damage = false + else + local name = obj:get_player_name() + armor.last_damage_types[name] = "fire" + mcl_death_messages.player_damage(obj, S("@1 burned to a crisp.", name)) + end + end + if do_damage then + if is_player then + obj:set_hp(hp - 1) + else + meta.health = hp - 1 + end + end +end + +local etime = 0 + +function mcl_burning.step(obj, dtime) + local burn_time, old_burn_time, meta, is_player + meta, is_player = mcl_burning.analyse(obj) + old_burn_time = mcl_burning.get_burning(obj, meta, is_player) + burn_time = old_burn_time - dtime + if burn_time < 5 and mcl_burning.is_touching_nodes(obj, {"mcl_fire:fire", "mcl_fire:eternal_fire", "mcl_core:lava_source", "mcl_core:lava_flowing"}) then + burn_time = 5 + end + if burn_time > 0 or old_burn_time > 0 then + if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, {"mcl_core:water_source", "mcl_core:water_flowing"}) then + burn_time = math.min(burn_time, 0.25) + end + mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player) + end + if burn_time > 0 then + if math.random() < dtime then + mcl_burning.play_sound(obj, "fire_fire") + end + if etime > 1 then + mcl_burning.damage(obj, meta, is_player) + end + end +end + +minetest.register_globalstep(function(dtime) + if etime > 1 then + etime = 0 + end + etime = etime + dtime + for _, player in ipairs(minetest.get_connected_players()) do + mcl_burning.step(player, dtime) + end +end) + +minetest.register_on_respawnplayer(function(player) + mcl_burning.set_burning(player, 0) +end) + +minetest.register_chatcommand("burn", { + func = function(name, param) + local player = minetest.get_player_by_name(name) + local burn_time = tonumber(param) or 5 + if player then + mcl_burning.set_burning(player, burn_time) + end + end +}) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 878745188..15232c246 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -778,6 +778,7 @@ local check_for_death = function(self, cause, cmi_cause) if cause == "lava" or cause == "fire" then item_drop(self, true, 0) else + local cooked = nil local looting = 0 if cause == "hit" then local puncher = cmi_cause.puncher @@ -785,7 +786,10 @@ local check_for_death = function(self, cause, cmi_cause) looting = mcl_enchanting.get_enchantment(puncher:get_wielded_item(), "looting") end end - item_drop(self, nil, looting) + if self._burn_time and self._burn_time > 0 then + cooked = true + end + item_drop(self, cooked, looting) end local pos = self.object:get_pos() @@ -3354,7 +3358,11 @@ end -- main mob function local mob_step = function(self, dtime) - + + if not self.fire_resistant then + mcl_burning.step(self.object, dtime) + end + if use_cmi then cmi.notify_step(self.object, dtime) end @@ -3781,6 +3789,7 @@ minetest.register_entity(name, { suffocation_timer = 0, follow_velocity = def.follow_velocity or 2.4, instant_death = def.instant_death or false, + fire_resistant = def.fire_resistant or false, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mobs_mc/blaze.lua b/mods/ENTITIES/mobs_mc/blaze.lua index 3e0af9ab1..d9275c7ae 100644 --- a/mods/ENTITIES/mobs_mc/blaze.lua +++ b/mods/ENTITIES/mobs_mc/blaze.lua @@ -74,6 +74,7 @@ mobs:register_mob("mobs_mc:blaze", { makes_footstep_sound = false, fear_height = 0, glow = 14, + fire_resistant = true, }) mobs:spawn_specific("mobs_mc:blaze", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 5000, 3, mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) diff --git a/mods/ENTITIES/mobs_mc/ender_dragon.lua b/mods/ENTITIES/mobs_mc/ender_dragon.lua index 85b72008f..c579213a0 100644 --- a/mods/ENTITIES/mobs_mc/ender_dragon.lua +++ b/mods/ENTITIES/mobs_mc/ender_dragon.lua @@ -67,7 +67,8 @@ mobs:register_mob("mobs_mc:enderdragon", { --end end minetest.add_item(own_pos, mobs_mc.items.dragon_egg) - end + end, + fire_resistant = true, }) diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 5bd05b860..679a28c13 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -62,6 +62,7 @@ mobs:register_mob("mobs_mc:ghast", { fly = true, makes_footstep_sound = false, instant_death = true, + fire_resistant = true, }) diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index 7684dc409..e4a1f86fc 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -90,6 +90,7 @@ mobs:register_mob("mobs_mc:witherskeleton", { dogshoot_count_max =0.5, fear_height = 4, harmed_by_heal = true, + fire_resistant = true, }) --spawn diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 743733930..3848d5919 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -108,7 +108,8 @@ local slime_big = { jump_height = 5.2, fear_height = 0, spawn_small_alternative = "mobs_mc:slime_small", - on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5) + on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5), + fire_resistant = true, } mobs:register_mob("mobs_mc:slime_big", slime_big) diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index 5b79e53b5..08e82f62e 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -86,6 +86,7 @@ local pigman = { fear_height = 4, view_range = 16, harmed_by_heal = true, + fire_resistant = true, } mobs:register_mob("mobs_mc:pigman", pigman) diff --git a/mods/ITEMS/mcl_armor/armor.lua b/mods/ITEMS/mcl_armor/armor.lua index 69801d010..6151a2812 100644 --- a/mods/ITEMS/mcl_armor/armor.lua +++ b/mods/ITEMS/mcl_armor/armor.lua @@ -540,7 +540,7 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason) epf = epf + blast_protection_level * 2 end local fire_protection_level = enchantments.fire_protection or 0 - if fire_protection_level > 0 and (damage_type == "fireball" or reason.type == "node_damage" and + if fire_protection_level > 0 and (damage_type == "burning" or damage_type == "fireball" or reason.type == "node_damage" and (reason.node == "mcl_fire:fire" or reason.node == "mcl_core:lava_source" or reason.node == "mcl_core:lava_flowing")) then epf = epf + fire_protection_level * 2 end From 758a3470f3935469a2c38eaad287797fb078b209 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 24 Dec 2020 17:55:33 +0100 Subject: [PATCH 034/219] Fire resistance potion working --- mods/ENTITIES/mcl_burning/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index 768afb324..daaf6d9e5 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -122,7 +122,7 @@ function mcl_burning.damage(obj, meta, is_player) meta, is_player = mcl_burning.analyse(obj, meta, is_player) local do_damage = true if is_player then - if mcl_potions.player_has_effect(obj, "fire_resistance") then + if mcl_potions.player_has_effect(obj, "fire_proof") then do_damage = false else local name = obj:get_player_name() From 5385a3f2027bcb326cae61e0e12551369e8badc0 Mon Sep 17 00:00:00 2001 From: kay27 Date: Sun, 27 Dec 2020 17:11:22 +0400 Subject: [PATCH 035/219] Fix piston protection check --- mods/ITEMS/REDSTONE/mesecons_mvps/init.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua b/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua index a9a11bce5..669edbcbb 100644 --- a/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua @@ -145,7 +145,7 @@ function mesecon.mvps_get_stack(pos, dir, maximum, piston_pos) if not node_replaceable(nn.name) then if #nodes >= maximum then return nil, false end - table.insert(nodes, {node = nn, pos = np}) + table.insert(nodes, {node = nn, pos = {x=np.x, y=np.y, z=np.z}}) -- add connected nodes to frontiers, connected is a vector list -- the vectors must be absolute positions @@ -195,10 +195,9 @@ function mesecon.mvps_set_owner(pos, placer) end end -local function are_protected(positions, player_name) - local name = player_name - for _, pos in pairs(positions) do - if is_protected(pos, name) then +local function are_protected(nodes, player_name) + for _, node in pairs(nodes) do + if minetest.is_protected(node.pos, player_name) then return true end end From a4b2172ac5395368b284c65524ec918f7fecacd3 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sun, 27 Dec 2020 16:59:34 +0100 Subject: [PATCH 036/219] Version 0.69.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eab5068cc..139e2b51c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.69.0 +Version: 0.69.1 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From e8573189d81d8e5a38e0689243d99c43fad3f596 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 28 Dec 2020 15:32:24 +0100 Subject: [PATCH 037/219] Fix XP bar overflow after enchant --- mods/HUD/mcl_experience/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 048bd43c6..b2768013f 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -148,7 +148,7 @@ function mcl_experience.set_player_xp_level(player,level) return end pool[name].level = level - pool[name].xp, pool[name].bar_step, pool[name].next_level = mcl_experience.bar_to_xp(pool[name].bar, level) + pool[name].xp, pool[name].bar_step, pool[name].xp_next_level = mcl_experience.bar_to_xp(pool[name].bar, level) hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(level)}) -- we may don't update the bar end From a6eed5c5b31533915ad5c83880550903a7624673 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Tue, 29 Dec 2020 22:08:38 +0100 Subject: [PATCH 038/219] Rework system --- mods/ENTITIES/mcl_burning/init.lua | 281 +++++++++++++++------------- mods/ENTITIES/mcl_mobs/api.lua | 3 +- mods/ENTITIES/mobs_mc/zombiepig.lua | 2 +- 3 files changed, 153 insertions(+), 133 deletions(-) diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index daaf6d9e5..259346bda 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -1,13 +1,34 @@ -mcl_burning = {} - local S = minetest.get_translator("mcl_burning") -function mcl_burning.play_sound(obj, soundname) - minetest.sound_play(soundname, { - object = obj, - gain = 0.18, - max_hear_distance = 32, - }) +mcl_burning = {} + +function mcl_burning.get_default(datatype) + local default_table = {string = "", float = 0.0, int = 0, bool = false} + return default_table[datatype] +end + +function mcl_burning.get(obj, datatype, name) + local key + if obj:is_player() then + local meta = obj:get_meta() + return meta["get_" .. datatype](meta, "mcl_burning:" .. name) + else + local luaentity = obj:get_luaentity() + return luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype) + end +end + +function mcl_burning.set(obj, datatype, name, value) + if obj:is_player() then + local meta = obj:get_meta() + meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype)) + else + local luaentity = obj:get_luaentity() + if mcl_burning.get_default(datatype) == value then + value = nil + end + luaentity["mcl_burning_" .. name] = value + end end function mcl_burning.get_collisionbox(obj) @@ -23,168 +44,166 @@ function mcl_burning.is_touching_nodes(obj, nodes) return #nodes > 0 end -function mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, old_spawner) - local new_spawner - if old_spawner == 0 then - old_spawner = nil - end - local delete_old_spawner = false - if burn_time and (not old_spawner or burn_time >= old_burn_time) then - delete_old_spawner = true - local minp, maxp = mcl_burning.get_collisionbox(obj) - new_spawner = minetest.add_particlespawner({ - amount = 1000 * burn_time, - time = burn_time, - minpos = minp, - maxpos = maxp, - minvel = {x = -0.5, y = 1, z = -0.5}, - maxvel = {x = 0.5, y = 2, z = -0.5}, - minacc = {x = -0.1, y = 8, z = -0.1}, - maxacc = {x = 0.1, y = 10, z = 0.1}, - minexptime = 0.2, - maxexptime = 0.3, - minsize = 1, - maxsize = 2, - collisiondetection = true, - texture = "fire_basic_flame.png", - attached = obj, - }) - elseif not burn_time and old_spawner then - delete_old_spawner = true - end - if delete_old_spawner and old_spawner then - minetest.delete_particlespawner(old_spawner) - old_spawner = nil - end - return new_spawner or old_spawner -end +function mcl_burning.damage(obj) + local luaentity = obj:get_luaentity() + local health -function mcl_burning.analyse(obj, meta, is_player) - if meta then - return meta, is_player - end - is_player = obj:is_player() - if is_player then - meta = obj:get_meta() - else - meta = obj:get_luaentity() - end - return meta, is_player -end - -function mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player) - meta, is_player = mcl_burning.analyse(obj, meta, is_player) - old_burn_time = old_burn_time or mcl_burning.get_burning(obj, meta, is_player) - if burn_time <= 0 then - burn_time = nil - end - if is_player then - if burn_time then - meta:set_float("mcl_burning:burn_time", burn_time) - elseif old_burn_time > 0 then - meta:set_string("mcl_burning:burn_time", "") - mcl_burning.play_sound(obj, "fire_extinguish_flame") - end - local fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta:get_int("mcl_burning:fire_spawner")) - if fire_spawner then - meta:set_int("mcl_burning:fire_spawner", fire_spawner) - else - meta:set_string("mcl_burning:fire_spawner", "") - end - elseif not meta._fire_resistant then - meta._burn_time = burn_time - meta._fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta._fire_spawner) - if not burn_time and old_burn_time > 0 then - mcl_burning.play_sound(obj, "fire_extinguish_flame") - end - end -end - -function mcl_burning.get_burning(obj, meta, is_player) - meta, is_player = mcl_burning.analyse(obj, meta, is_player) - if is_player then - return meta:get_float("mcl_burning:burn_time") - else - return meta._burn_time or 0 - end -end - -function mcl_burning.damage(obj, meta, is_player) - local hp - if is_player then - hp = obj:get_hp() - else - hp = meta.health or 0 + if luaentity then + health = luaentity.health end + + local hp = health or obj:get_hp() + if hp <= 0 then return end - meta, is_player = mcl_burning.analyse(obj, meta, is_player) + local do_damage = true - if is_player then + + if obj:is_player() then if mcl_potions.player_has_effect(obj, "fire_proof") then do_damage = false else local name = obj:get_player_name() armor.last_damage_types[name] = "fire" - mcl_death_messages.player_damage(obj, S("@1 burned to a crisp.", name)) + local deathmsg = S("@1 burned to death.", name) + local reason = mcl_burning.get(obj, "string", "reason") + if reason ~= "" then + deathmsg = S("@1 was burned by @2.", name, reason) + end + mcl_death_messages.player_damage(obj, deathmsg) + end + else + if luaentity.fire_damage_resistant then + do_damage = false end end + if do_damage then - if is_player then - obj:set_hp(hp - 1) - else - meta.health = hp - 1 + local damage = mcl_burning.get(obj, "float", "damage") + if damage == 0 then + damage = 1 + end + local new_hp = hp - damage + obj:set_hp(new_hp) + if health then + luaentity.health = new_hp end end end -local etime = 0 +function mcl_burning.set_on_fire(obj, burn_time, damage, reason) + local luaentity = obj:get_luaentity() + if luaentity and luaentity.fire_resistant then + return + end -function mcl_burning.step(obj, dtime) - local burn_time, old_burn_time, meta, is_player - meta, is_player = mcl_burning.analyse(obj) - old_burn_time = mcl_burning.get_burning(obj, meta, is_player) - burn_time = old_burn_time - dtime - if burn_time < 5 and mcl_burning.is_touching_nodes(obj, {"mcl_fire:fire", "mcl_fire:eternal_fire", "mcl_core:lava_source", "mcl_core:lava_flowing"}) then - burn_time = 5 - end - if burn_time > 0 or old_burn_time > 0 then - if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, {"mcl_core:water_source", "mcl_core:water_flowing"}) then - burn_time = math.min(burn_time, 0.25) + local old_burn_time = mcl_burning.get(obj, "float", "burn_time") + local max_fire_prot_lvl = 0 + + if obj:is_player() then + local inv = obj:get_inventory() + + for i = 2, 5 do + local stack = inv:get_stack("armor", i) + + local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection") + max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl) end - mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player) end - if burn_time > 0 then + + if max_fire_prot_lvl > 0 then + burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) + end + + if old_burn_time <= burn_time then + mcl_burning.set(obj, "float", "burn_time", burn_time) + mcl_burning.set(obj, "float", "damage", damage or 0) + mcl_burning.set(obj, "string", "reason", reason or "") + + end +end + +function mcl_burning.extinguish(obj) + local old_burn_time = mcl_burning.get(obj, "float", "burn_time") + + if old_burn_time > 0 then + minetest.sound_play("fire_extinguish_flame", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) + + mcl_burning.delete_particlespawner(obj) + + mcl_burning.set(obj, "float", "damage") + mcl_burning.set(obj, "string", "reason") + mcl_burning.set(obj, "float", "burn_time") + mcl_burning.set(obj, "float", "damage_timer") + end +end + +function mcl_burning.catch_fire_tick(obj, dtime) + local lava_nodes = {"mcl_core:lava_source", "mcl_core:lava_flowing"} + local fire_nodes = {"mcl_fire:fire", "mcl_fire:eternal_fire"} + local water_nodes = {"mcl_core:water_source", "mcl_core:water_flowing"} + + if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, water_nodes) then + mcl_burning.extinguish(obj) + elseif mcl_burning.is_touching_nodes(obj, lava_nodes) then + mcl_burning.set_on_fire(obj, 15) + elseif mcl_burning.is_touching_nodes(obj, fire_nodes) then + mcl_burning.set_on_fire(obj, 8) + end +end + +function mcl_burning.tick(obj, dtime) + local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime + + if burn_time <= 0 then + mcl_burning.extinguish(obj) + else + mcl_burning.set(obj, "float", "burn_time", burn_time) + if math.random() < dtime then - mcl_burning.play_sound(obj, "fire_fire") + minetest.sound_play("fire_fire", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) end - if etime > 1 then - mcl_burning.damage(obj, meta, is_player) + + local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime + + if damage_timer >= 1 then + damage_timer = 0 + mcl_burning.damage(obj) end + + mcl_burning.set(obj, "float", "damage_timer", damage_timer) end + + mcl_burning.catch_fire_tick(obj, dtime) end minetest.register_globalstep(function(dtime) - if etime > 1 then - etime = 0 - end - etime = etime + dtime for _, player in ipairs(minetest.get_connected_players()) do - mcl_burning.step(player, dtime) + mcl_burning.tick(player, dtime) end end) minetest.register_on_respawnplayer(function(player) - mcl_burning.set_burning(player, 0) + mcl_burning.extinguish(player) end) minetest.register_chatcommand("burn", { func = function(name, param) local player = minetest.get_player_by_name(name) - local burn_time = tonumber(param) or 5 + local sparam = param:split(" ") + local burn_time = tonumber(sparam[1]) or 5 + local damage = tonumber(sparam[2]) or 5 if player then - mcl_burning.set_burning(player, burn_time) + mcl_burning.set_on_fire(player, burn_time, damage) end end }) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 15232c246..fdf36a21a 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3360,7 +3360,7 @@ end local mob_step = function(self, dtime) if not self.fire_resistant then - mcl_burning.step(self.object, dtime) + mcl_burning.tick(self.object, dtime) end if use_cmi then @@ -3790,6 +3790,7 @@ minetest.register_entity(name, { follow_velocity = def.follow_velocity or 2.4, instant_death = def.instant_death or false, fire_resistant = def.fire_resistant or false, + fire_damage_resistant = def.fire_damage_resistant or false, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index 08e82f62e..89649c4a8 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -86,7 +86,7 @@ local pigman = { fear_height = 4, view_range = 16, harmed_by_heal = true, - fire_resistant = true, + fire_damage_resistant = true, } mobs:register_mob("mobs_mc:pigman", pigman) From 071ba77bb068e6ad66138f5c1bd0accaee20fae3 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 1 Jan 2021 19:25:47 +0100 Subject: [PATCH 039/219] mcl_burning fully working --- GROUPS.md | 4 + mods/ENTITIES/mcl_burning/LICENSE | 674 ++++++++++++++++++ mods/ENTITIES/mcl_burning/engine.lua | 298 ++++++++ mods/ENTITIES/mcl_burning/init.lua | 205 +----- mods/ENTITIES/mcl_burning/mod.conf | 3 + mods/ENTITIES/mcl_mobs/api.lua | 11 +- mods/ENTITIES/mobs_mc/villager_vindicator.lua | 1 - mods/ENTITIES/mobs_mc/villager_zombie.lua | 1 - mods/ENTITIES/mobs_mc/witch.lua | 1 - mods/ITEMS/mcl_core/nodes_liquid.lua | 4 +- mods/ITEMS/mcl_fire/init.lua | 4 +- settingtypes.txt | 6 + 12 files changed, 1016 insertions(+), 196 deletions(-) create mode 100644 mods/ENTITIES/mcl_burning/LICENSE create mode 100644 mods/ENTITIES/mcl_burning/engine.lua create mode 100644 mods/ENTITIES/mcl_burning/mod.conf diff --git a/GROUPS.md b/GROUPS.md index 1ac531b8a..f94b04979 100644 --- a/GROUPS.md +++ b/GROUPS.md @@ -70,6 +70,7 @@ Please read to learn how digging times * `coral_fan=X`: Coral fan (1 = alive, 2 = dead) * `coral_block=X`: Coral block (1 = alive, 2 = dead) * `coral_species=X`: Specifies the species of a coral; equal X means equal species +* `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching #### Footnotes @@ -96,6 +97,8 @@ Please read to learn how digging times * `carpet=1:` (Wool) carpet * `stick=1`: Stick * `water_bucket=1`: Bucket containing a liquid of group “water” +* `enchantability=X`: How good the enchantments are the item gets (1 equals book) +* `enchanted=1`: The item is already enchanted, meaning that it can't be enchanted using an enchanting table ### Material groups @@ -197,6 +200,7 @@ These groups are used mostly for informational purposes * `building_block=1`: Block is a building block * `deco_block=1`: Block is a decorational block + ## Fake item groups These groups put similar items together which should all be treated by the gameplay or the GUI as a single item. You should not add custom items to these groups for no good reason, this is likely to cause a ton of conflicts. diff --git a/mods/ENTITIES/mcl_burning/LICENSE b/mods/ENTITIES/mcl_burning/LICENSE new file mode 100644 index 000000000..9cecc1d46 --- /dev/null +++ b/mods/ENTITIES/mcl_burning/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/mods/ENTITIES/mcl_burning/engine.lua b/mods/ENTITIES/mcl_burning/engine.lua new file mode 100644 index 000000000..6046f17c4 --- /dev/null +++ b/mods/ENTITIES/mcl_burning/engine.lua @@ -0,0 +1,298 @@ +local S = minetest.get_translator("mcl_burning") + +function mcl_burning.get_default(datatype) + local default_table = {string = "", float = 0.0, int = 0, bool = false} + return default_table[datatype] +end + +function mcl_burning.get(obj, datatype, name) + local key + if obj:is_player() then + local meta = obj:get_meta() + return meta["get_" .. datatype](meta, "mcl_burning:" .. name) + else + local luaentity = obj:get_luaentity() + return luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype) + end +end + +function mcl_burning.set(obj, datatype, name, value) + if obj:is_player() then + local meta = obj:get_meta() + meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype)) + else + local luaentity = obj:get_luaentity() + if mcl_burning.get_default(datatype) == value then + value = nil + end + luaentity["mcl_burning_" .. name] = value + end +end + +function mcl_burning.is_burning(obj) + return mcl_burning.get(obj, "float", "burn_time") > 0 +end + +function mcl_burning.is_affected_by_rain(obj) + return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) +end + +function mcl_burning.get_collisionbox(obj) + local box = obj:get_properties().collisionbox + return vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6]) +end + +function mcl_burning.get_touching_nodes(obj, nodenames) + local pos = obj:get_pos() + local box = obj:get_properties().collisionbox + local minp, maxp = mcl_burning.get_collisionbox(obj) + local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames) + return nodes +end + +function mcl_burning.get_highest_group_value(obj, groupname) + local nodes = mcl_burning.get_touching_nodes(obj, "group:" .. groupname, true) + local highest_group_value = 0 + + for _, pos in pairs(nodes) do + local node = minetest.get_node(pos) + local group_value = minetest.get_item_group(node.name, groupname) + if group_value > highest_group_value then + highest_group_value = group_value + end + end + + return highest_group_value +end + +function mcl_burning.damage(obj) + local luaentity = obj:get_luaentity() + local health + + if luaentity then + health = luaentity.health + end + + local hp = health or obj:get_hp() + + if hp <= 0 then + return + end + + local do_damage = true + + if obj:is_player() then + if mcl_potions.player_has_effect(obj, "fire_proof") then + do_damage = false + else + local name = obj:get_player_name() + armor.last_damage_types[name] = "fire" + local deathmsg = S("@1 burned to death.", name) + local reason = mcl_burning.get(obj, "string", "reason") + if reason ~= "" then + deathmsg = S("@1 was burned by @2.", name, reason) + end + mcl_death_messages.player_damage(obj, deathmsg) + end + else + if luaentity.fire_damage_resistant then + do_damage = false + end + end + + if do_damage then + local damage = mcl_burning.get(obj, "float", "damage") + if damage == 0 then + damage = 1 + end + local new_hp = hp - damage + obj:set_hp(new_hp) + if health then + luaentity.health = new_hp + end + end +end + +function mcl_burning.set_on_fire(obj, burn_time, damage, reason) + local luaentity = obj:get_luaentity() + if luaentity and luaentity.fire_resistant then + return + end + + local old_burn_time = mcl_burning.get(obj, "float", "burn_time") + local max_fire_prot_lvl = 0 + + if obj:is_player() then + local inv = obj:get_inventory() + + for i = 2, 5 do + local stack = inv:get_stack("armor", i) + + local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection") + max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl) + end + end + + if max_fire_prot_lvl > 0 then + burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) + end + + if old_burn_time <= burn_time then + local sound_id = mcl_burning.get(obj, "int", "sound_id") + if sound_id == 0 then + sound_id = minetest.sound_play("fire_fire", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + loop = true, + }) + 1 + end + + local hud_id + if obj:is_player() then + hud_id = mcl_burning.get(obj, "int", "hud_id") + if hud_id == 0 then + hud_id = obj:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -100, y = -100}, + text = "fire_basic_flame.png", + z_index = 1000, + }) + 1 + end + end + mcl_burning.set(obj, "float", "burn_time", burn_time) + mcl_burning.set(obj, "float", "damage", damage) + mcl_burning.set(obj, "string", "reason", reason) + mcl_burning.set(obj, "int", "hud_id", hud_id) + mcl_burning.set(obj, "int", "sound_id", sound_id) + + local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire") + local minp, maxp = mcl_burning.get_collisionbox(obj) + local obj_size = obj:get_properties().visual_size + + local vertical_grow_factor = 1.1 + local horizontal_grow_factor = 0.9 + local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor) + + local size = vector.subtract(maxp, minp) + size = vector.multiply(size, grow_vector) + size = vector.divide(size, obj_size) + local offset = vector.new(0, size.y * 10 / 2, 0) + + fire_entity:set_properties({visual_size = size}) + fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0}) + mcl_burning.update_animation_frame(obj, fire_entity, 0) + end +end + +function mcl_burning.extinguish(obj) + if mcl_burning.is_burning(obj) then + local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1 + minetest.sound_stop(sound_id) + + if obj:is_player() then + local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1 + obj:hud_remove(hud_id) + end + + minetest.sound_play("fire_extinguish_flame", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) + + mcl_burning.set(obj, "float", "damage") + mcl_burning.set(obj, "string", "reason") + mcl_burning.set(obj, "float", "burn_time") + mcl_burning.set(obj, "float", "damage_timer") + mcl_burning.set(obj, "int", "hud_id") + mcl_burning.set(obj, "int", "sound_id") + end +end + +function mcl_burning.catch_fire_tick(obj, dtime) + if mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire") > 0 then + mcl_burning.extinguish(obj) + else + local set_on_fire_value = mcl_burning.get_highest_group_value(obj, "set_on_fire") + + if set_on_fire_value > 0 then + mcl_burning.set_on_fire(obj, set_on_fire_value) + end + end +end + +function mcl_burning.tick(obj, dtime) + local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime + + if burn_time <= 0 then + mcl_burning.extinguish(obj) + else + mcl_burning.set(obj, "float", "burn_time", burn_time) + + local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime + + if damage_timer >= 1 then + damage_timer = 0 + mcl_burning.damage(obj) + end + + mcl_burning.set(obj, "float", "damage_timer", damage_timer) + end + + mcl_burning.catch_fire_tick(obj, dtime) +end + +function mcl_burning.update_animation_frame(obj, fire_entity, animation_frame) + local fire_texture = "fire_basic_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame + fire_entity:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}}) + if obj:is_player() then + local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1 + obj:hud_change(hud_id, "text", fire_texture) + end +end + +function mcl_burning.fire_entity_step(self, dtime) + if self.removed then + return + end + + local obj = self.object + local parent = obj:get_attach() + local do_remove + + self.doing_step = true + + if not parent or not mcl_burning.is_burning(parent) then + do_remove = true + else + for _, other in ipairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do + local luaentity = obj:get_luaentity() + if luaentity and luaentity.name == "mcl_burning:fire" and not luaentity.doing_step and not luaentity.removed then + do_remove = true + break + end + end + end + + self.doing_step = false + + if do_remove then + self.removed = true + obj:remove() + return + end + + local animation_timer = self.animation_timer + dtime + if animation_timer >= 0.015 then + animation_timer = 0 + local animation_frame = self.animation_frame + 1 + if animation_frame > mcl_burning.animation_frames - 1 then + animation_frame = 0 + end + mcl_burning.update_animation_frame(parent, obj, animation_frame) + self.animation_frame = animation_frame + end + self.animation_timer = animation_timer +end diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index 259346bda..f25e7b671 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -1,190 +1,25 @@ local S = minetest.get_translator("mcl_burning") +local modpath = minetest.get_modpath("mcl_burning") -mcl_burning = {} +mcl_burning = { + animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8 +} -function mcl_burning.get_default(datatype) - local default_table = {string = "", float = 0.0, int = 0, bool = false} - return default_table[datatype] -end +dofile(modpath .. "/engine.lua") -function mcl_burning.get(obj, datatype, name) - local key - if obj:is_player() then - local meta = obj:get_meta() - return meta["get_" .. datatype](meta, "mcl_burning:" .. name) - else - local luaentity = obj:get_luaentity() - return luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype) - end -end - -function mcl_burning.set(obj, datatype, name, value) - if obj:is_player() then - local meta = obj:get_meta() - meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype)) - else - local luaentity = obj:get_luaentity() - if mcl_burning.get_default(datatype) == value then - value = nil - end - luaentity["mcl_burning_" .. name] = value - end -end - -function mcl_burning.get_collisionbox(obj) - local box = obj:get_properties().collisionbox - return vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6]) -end - -function mcl_burning.is_touching_nodes(obj, nodes) - local pos = obj:get_pos() - local box = obj:get_properties().collisionbox - local minp, maxp = mcl_burning.get_collisionbox(obj) - local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodes) - return #nodes > 0 -end - -function mcl_burning.damage(obj) - local luaentity = obj:get_luaentity() - local health - - if luaentity then - health = luaentity.health - end +minetest.register_entity("mcl_burning:fire", { + initial_properties = { + physical = false, + collisionbox = {0, 0, 0, 0, 0, 0}, + visual = "cube", + pointable = false, + glow = -1, + }, - local hp = health or obj:get_hp() - - if hp <= 0 then - return - end - - local do_damage = true - - if obj:is_player() then - if mcl_potions.player_has_effect(obj, "fire_proof") then - do_damage = false - else - local name = obj:get_player_name() - armor.last_damage_types[name] = "fire" - local deathmsg = S("@1 burned to death.", name) - local reason = mcl_burning.get(obj, "string", "reason") - if reason ~= "" then - deathmsg = S("@1 was burned by @2.", name, reason) - end - mcl_death_messages.player_damage(obj, deathmsg) - end - else - if luaentity.fire_damage_resistant then - do_damage = false - end - end - - if do_damage then - local damage = mcl_burning.get(obj, "float", "damage") - if damage == 0 then - damage = 1 - end - local new_hp = hp - damage - obj:set_hp(new_hp) - if health then - luaentity.health = new_hp - end - end -end - -function mcl_burning.set_on_fire(obj, burn_time, damage, reason) - local luaentity = obj:get_luaentity() - if luaentity and luaentity.fire_resistant then - return - end - - local old_burn_time = mcl_burning.get(obj, "float", "burn_time") - local max_fire_prot_lvl = 0 - - if obj:is_player() then - local inv = obj:get_inventory() - - for i = 2, 5 do - local stack = inv:get_stack("armor", i) - - local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection") - max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl) - end - end - - if max_fire_prot_lvl > 0 then - burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) - end - - if old_burn_time <= burn_time then - mcl_burning.set(obj, "float", "burn_time", burn_time) - mcl_burning.set(obj, "float", "damage", damage or 0) - mcl_burning.set(obj, "string", "reason", reason or "") - - end -end - -function mcl_burning.extinguish(obj) - local old_burn_time = mcl_burning.get(obj, "float", "burn_time") - - if old_burn_time > 0 then - minetest.sound_play("fire_extinguish_flame", { - object = obj, - gain = 0.18, - max_hear_distance = 32, - }) - - mcl_burning.delete_particlespawner(obj) - - mcl_burning.set(obj, "float", "damage") - mcl_burning.set(obj, "string", "reason") - mcl_burning.set(obj, "float", "burn_time") - mcl_burning.set(obj, "float", "damage_timer") - end -end - -function mcl_burning.catch_fire_tick(obj, dtime) - local lava_nodes = {"mcl_core:lava_source", "mcl_core:lava_flowing"} - local fire_nodes = {"mcl_fire:fire", "mcl_fire:eternal_fire"} - local water_nodes = {"mcl_core:water_source", "mcl_core:water_flowing"} - - if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, water_nodes) then - mcl_burning.extinguish(obj) - elseif mcl_burning.is_touching_nodes(obj, lava_nodes) then - mcl_burning.set_on_fire(obj, 15) - elseif mcl_burning.is_touching_nodes(obj, fire_nodes) then - mcl_burning.set_on_fire(obj, 8) - end -end - -function mcl_burning.tick(obj, dtime) - local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime - - if burn_time <= 0 then - mcl_burning.extinguish(obj) - else - mcl_burning.set(obj, "float", "burn_time", burn_time) - - if math.random() < dtime then - minetest.sound_play("fire_fire", { - object = obj, - gain = 0.18, - max_hear_distance = 32, - }) - end - - local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime - - if damage_timer >= 1 then - damage_timer = 0 - mcl_burning.damage(obj) - end - - mcl_burning.set(obj, "float", "damage_timer", damage_timer) - end - - mcl_burning.catch_fire_tick(obj, dtime) -end + animation_frame = 0, + animation_timer = 0, + on_step = mcl_burning.fire_entity_step, +}) minetest.register_globalstep(function(dtime) for _, player in ipairs(minetest.get_connected_players()) do @@ -196,12 +31,16 @@ minetest.register_on_respawnplayer(function(player) mcl_burning.extinguish(player) end) +minetest.register_on_leaveplayer(function(player) + mcl_burning.set(player, "int", "hud_id") +end) + minetest.register_chatcommand("burn", { func = function(name, param) local player = minetest.get_player_by_name(name) local sparam = param:split(" ") local burn_time = tonumber(sparam[1]) or 5 - local damage = tonumber(sparam[2]) or 5 + local damage = tonumber(sparam[2]) or 0 if player then mcl_burning.set_on_fire(player, burn_time, damage) end diff --git a/mods/ENTITIES/mcl_burning/mod.conf b/mods/ENTITIES/mcl_burning/mod.conf new file mode 100644 index 000000000..c64959cbb --- /dev/null +++ b/mods/ENTITIES/mcl_burning/mod.conf @@ -0,0 +1,3 @@ +name = mcl_burning +description = Burning Objects for MineClone2 +author = Fleckenstein diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index fdf36a21a..2d032232d 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -778,17 +778,15 @@ local check_for_death = function(self, cause, cmi_cause) if cause == "lava" or cause == "fire" then item_drop(self, true, 0) else - local cooked = nil - local looting = 0 + local wielditem = ItemStack() if cause == "hit" then local puncher = cmi_cause.puncher if puncher then - looting = mcl_enchanting.get_enchantment(puncher:get_wielded_item(), "looting") + wielditem = puncher:get_wielded_item() end end - if self._burn_time and self._burn_time > 0 then - cooked = true - end + local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.get_enchantment(wielditem, "fire_aspect") + local looting = mcl_enchanting.get_enchantment(wielditem, "looting") item_drop(self, cooked, looting) end @@ -3791,6 +3789,7 @@ minetest.register_entity(name, { instant_death = def.instant_death or false, fire_resistant = def.fire_resistant or false, fire_damage_resistant = def.fire_damage_resistant or false, + fire_entity_properties = def.fire_entity_properties or nil, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mobs_mc/villager_vindicator.lua b/mods/ENTITIES/mobs_mc/villager_vindicator.lua index 31ff597ba..3e611acdd 100644 --- a/mods/ENTITIES/mobs_mc/villager_vindicator.lua +++ b/mods/ENTITIES/mobs_mc/villager_vindicator.lua @@ -68,7 +68,6 @@ mobs:register_mob("mobs_mc:vindicator", { }, view_range = 16, fear_height = 4, - }) -- spawn eggs diff --git a/mods/ENTITIES/mobs_mc/villager_zombie.lua b/mods/ENTITIES/mobs_mc/villager_zombie.lua index e385185d5..f6927aa41 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -86,7 +86,6 @@ mobs:register_mob("mobs_mc:villager_zombie", { view_range = 16, fear_height = 4, harmed_by_heal = true, - }) mobs:spawn_specific("mobs_mc:villager_zombie", mobs_mc.spawn.village, {"air"}, 0, 7, 30, 4090, 4, mobs_mc.spawn_height.water+1, mobs_mc.spawn_height.overworld_max) diff --git a/mods/ENTITIES/mobs_mc/witch.lua b/mods/ENTITIES/mobs_mc/witch.lua index d301fcb59..e95357564 100644 --- a/mods/ENTITIES/mobs_mc/witch.lua +++ b/mods/ENTITIES/mobs_mc/witch.lua @@ -68,7 +68,6 @@ mobs:register_mob("mobs_mc:witch", { }, view_range = 16, fear_height = 4, - }) -- potion projectile (EXPERIMENTAL) diff --git a/mods/ITEMS/mcl_core/nodes_liquid.lua b/mods/ITEMS/mcl_core/nodes_liquid.lua index 57b3e588f..4769975b9 100644 --- a/mods/ITEMS/mcl_core/nodes_liquid.lua +++ b/mods/ITEMS/mcl_core/nodes_liquid.lua @@ -142,7 +142,7 @@ minetest.register_node("mcl_core:lava_flowing", { damage_per_second = 4*2, _mcl_node_death_message = lava_death_messages, post_effect_color = {a=245, r=208, g=73, b=10}, - groups = { lava=3, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1}, + groups = { lava=3, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15}, _mcl_blast_resistance = 100, -- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode _mcl_hardness = -1, @@ -198,7 +198,7 @@ S("• When lava is directly above water, the water turns into stone."), _mcl_node_death_message = lava_death_messages, post_effect_color = {a=245, r=208, g=73, b=10}, stack_max = 64, - groups = { lava=3, lava_source=1, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1}, + groups = { lava=3, lava_source=1, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15}, _mcl_blast_resistance = 100, -- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode _mcl_hardness = -1, diff --git a/mods/ITEMS/mcl_fire/init.lua b/mods/ITEMS/mcl_fire/init.lua index 2daaf1e5d..50303e3b2 100644 --- a/mods/ITEMS/mcl_fire/init.lua +++ b/mods/ITEMS/mcl_fire/init.lua @@ -117,7 +117,7 @@ minetest.register_node("mcl_fire:fire", { sunlight_propagates = true, damage_per_second = 1, _mcl_node_death_message = fire_death_messages, - groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston=1, destroys_items=1 }, + groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston=1, destroys_items=1, set_on_fire=8}, floodable = true, on_flood = function(pos, oldnode, newnode) if minetest.get_item_group(newnode.name, "water") ~= 0 then @@ -248,7 +248,7 @@ minetest.register_node("mcl_fire:eternal_fire", { sunlight_propagates = true, damage_per_second = 1, _mcl_node_death_message = fire_death_messages, - groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston = 1, destroys_items = 1}, + groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston = 1, destroys_items = 1, set_on_fire=8}, floodable = true, on_flood = function(pos, oldnode, newnode) if minetest.get_item_group(newnode.name, "water") ~= 0 then diff --git a/settingtypes.txt b/settingtypes.txt index 18471d7bf..49274244a 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -85,6 +85,12 @@ mobs_disable_blood (Disable mob damage particles) bool false # Enable flame sound. flame_sound (Flame sound) bool true +[Graphics] +# How many vertical animation frames the fire texture (fire_basic_flame_animated.png) has. +# This may vary depending on the texture pack you use. +# Form: Image height / Image width +fire_animation_frames (Fire Animation Frames) int 8 + [Experimental] # Whether ice is translucent. If disabled, ice is fully opaque. # From 92bf8648074f658504bd92bfaea67b486fdc0a24 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 1 Jan 2021 19:51:31 +0100 Subject: [PATCH 040/219] Fire Aspect --- mods/ENTITIES/mcl_mobs/api.lua | 1 - mods/ITEMS/mcl_enchanting/enchantments.lua | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 2d032232d..dd6191da2 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3789,7 +3789,6 @@ minetest.register_entity(name, { instant_death = def.instant_death or false, fire_resistant = def.fire_resistant or false, fire_damage_resistant = def.fire_damage_resistant or false, - fire_entity_properties = def.fire_entity_properties or nil, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index 709a647f8..f9b8e0959 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -172,8 +172,8 @@ mcl_enchanting.enchantments.feather_falling = { power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}}, } --- requires missing MineClone2 feature ---[[mcl_enchanting.enchantments.fire_aspect = { +-- implemented via register_on_punchplayer callback +mcl_enchanting.enchantments.fire_aspect = { name = S("Fire Aspect"), max_level = 2, primary = {sword = true}, @@ -187,7 +187,19 @@ mcl_enchanting.enchantments.feather_falling = { requires_tool = false, treasure = false, power_range_table = {{10, 61}, {30, 71}}, -}]]-- +} + +minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage) + if hitter and hitter:is_player() then + local wielditem = hitter:get_wielded_item() + if wielditem then + local fire_aspect_level = mcl_enchanting.get_enchantment(wielditem, "fire_aspect") + if fire_aspect_level > 0 then + mcl_burning.set_on_fire(player, 4, fire_aspect_level * 2, hitter:get_player_name()) + end + end + end +end) -- implemented in mcl_armor mcl_enchanting.enchantments.fire_protection = { From 29328379510f60dc4e88816cc78551de87d50d51 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 1 Jan 2021 19:52:34 +0100 Subject: [PATCH 041/219] Fix mobs always dropping cooked loot --- mods/ENTITIES/mcl_mobs/api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index dd6191da2..3452b83c3 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -785,7 +785,7 @@ local check_for_death = function(self, cause, cmi_cause) wielditem = puncher:get_wielded_item() end end - local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.get_enchantment(wielditem, "fire_aspect") + local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.has_enchantment(wielditem, "fire_aspect") local looting = mcl_enchanting.get_enchantment(wielditem, "looting") item_drop(self, cooked, looting) end From 212e895c1a92352a9382dc55bffeedd1f81ea169 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 1 Jan 2021 19:59:34 +0100 Subject: [PATCH 042/219] Fire Aspect for Mobs --- mods/ENTITIES/mcl_mobs/api.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 3452b83c3..c8dc7143e 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2947,6 +2947,13 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) * tmp * ((armor[group] or 0) / 100.0) end end + + if weapon then + local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect") + if fire_aspect_level > 0 then + mcl_burning.set_on_fire(self.object, 4, fire_aspect_level * 2) + end + end -- check for tool immunity or special damage for n = 1, #self.immune_to do From d42ee00290719d1080841dc81f672440cfad89f8 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 1 Jan 2021 22:53:13 +0000 Subject: [PATCH 043/219] Fix piston owner metadata storage --- mods/ITEMS/REDSTONE/mesecons_pistons/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_pistons/init.lua b/mods/ITEMS/REDSTONE/mesecons_pistons/init.lua index fba702ede..3230d9804 100644 --- a/mods/ITEMS/REDSTONE/mesecons_pistons/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_pistons/init.lua @@ -97,7 +97,7 @@ local piston_on = function (pos, node) local meta = minetest.get_meta(pos) local success, stack, oldstack = mesecon.mvps_push(np, dir, PISTON_MAXIMUM_PUSH, meta:get_string("owner"), pos) if success then - minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname}) + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname}) minetest.set_node(np, {param2 = node.param2, name = pistonspec.pusher}) local below = minetest.get_node({x=np.x,y=np.y-1,z=np.z}) if below.name == "mcl_farming:soil" or below.name == "mcl_farming:soil_wet" then @@ -115,7 +115,7 @@ end local piston_off = function (pos, node) local pistonspec = minetest.registered_nodes[node.name].mesecons_piston - minetest.add_node(pos, {param2 = node.param2, name = pistonspec.offname}) + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.offname}) piston_remove_pusher (pos, node) if not pistonspec.sticky then return From fbd4a3a5160ff556e985182cce39b24c8082bfe6 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 10:56:40 +0100 Subject: [PATCH 044/219] Fix burning sound keeping playing --- mods/ENTITIES/mcl_mobs/api.lua | 11 +++++++++-- mods/ITEMS/mcl_enchanting/enchantments.lua | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index c8dc7143e..b7a709103 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -812,6 +812,7 @@ local check_for_death = function(self, cause, cmi_cause) if on_die_exit == true then self.state = "die" + mcl_burning.extinguish(self.object) self.object:remove() return true end @@ -874,6 +875,7 @@ local check_for_death = function(self, cause, cmi_cause) local dpos = self.object:get_pos() local cbox = self.collisionbox local yaw = self.object:get_rotation().y + mcl_burning.extinguish(self.object) self.object:remove() mobs.death_effect(dpos, yaw, cbox, not self.instant_death) end @@ -1022,6 +1024,7 @@ local do_env_damage = function(self) -- remove mob if beyond map limits if not within_limits(pos, 0) then + mcl_burning.extinguish(self.object) self.object:remove() return true end @@ -2544,6 +2547,7 @@ local do_states = function(self, dtime) effect(pos, 32, "mcl_particles_smoke.png", nil, nil, node_break_radius, 1, 0) end end + mcl_burning.extinguish(self.object) self.object:remove() return true @@ -3162,6 +3166,7 @@ local mob_staticdata = function(self) and self.lifetimer <= 20 then minetest.log("action", "Mob "..name.." despawns in mob_staticdata at "..minetest.pos_to_string(self.object.get_pos())) + mcl_burning.extinguish(self.object) self.object:remove() return ""-- nil @@ -3200,7 +3205,7 @@ local mob_activate = function(self, staticdata, def, dtime) -- remove monsters in peaceful mode if self.type == "monster" and minetest.settings:get_bool("only_peaceful_mobs", false) then - + mcl_burning.extinguish(self.object) self.object:remove() return @@ -3583,6 +3588,7 @@ local mob_step = function(self, dtime) else if math.random(1,10) <= 3 then minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) + mcl_burning.extinguish(self.object) self.object:remove() return end @@ -3590,6 +3596,7 @@ local mob_step = function(self, dtime) end else minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) + mcl_burning.extinguish(self.object) self.object:remove() return end @@ -4152,7 +4159,7 @@ function mobs:register_arrow(name, def) if self.switch == 0 or self.timer > 150 or not within_limits(pos, 0) then - + mcl_burning.extinguish(self.object) self.object:remove(); return diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index f9b8e0959..d2803be14 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -172,7 +172,7 @@ mcl_enchanting.enchantments.feather_falling = { power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}}, } --- implemented via register_on_punchplayer callback +-- implemented in mcl_mobs and via register_on_punchplayer callback mcl_enchanting.enchantments.fire_aspect = { name = S("Fire Aspect"), max_level = 2, From 2bc5a281f5e3a2d662d1fdb69149d1c858c30a24 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 10:57:33 +0100 Subject: [PATCH 045/219] Player damage texture modifier --- mods/PLAYER/mcl_player/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/PLAYER/mcl_player/init.lua b/mods/PLAYER/mcl_player/init.lua index d2dca49ca..dcd232a05 100644 --- a/mods/PLAYER/mcl_player/init.lua +++ b/mods/PLAYER/mcl_player/init.lua @@ -59,6 +59,7 @@ function mcl_player.player_set_model(player, model_name) textures = player_textures[name] or model.textures, visual = "mesh", visual_size = model.visual_size or {x=1, y=1}, + damage_texture_modifier = "^[colorize:red:130", }) mcl_player.player_set_animation(player, "stand") else From 883056bbc229582f3e91d127c5ff4207e5d1494f Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 11:15:32 +0100 Subject: [PATCH 046/219] Fix #16 --- mods/ITEMS/mcl_tools/init.lua | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 6dc8d1e0d..18638b189 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -173,16 +173,16 @@ minetest.register_tool("mcl_tools:pick_diamond", { }) local get_shovel_dig_group = function(itemstring) - local def = minetest.registered_items[itemstring] - if itemstring == "mcl_tools:shovel_wood" then + local string_start = itemstring:sub(1, 21) + if string_start == "mcl_tools:shovel_wood" then return "shovely_dig_wood" - elseif itemstring == "mcl_tools:shovel_stone" then + elseif string_start == "mcl_tools:shovel_ston" then return "shovely_dig_stone" - elseif itemstring == "mcl_tools:shovel_iron" then + elseif string_start == "mcl_tools:shovel_iron" then return "shovely_dig_iron" - elseif itemstring == "mcl_tools:shovel_gold" then + elseif string_start == "mcl_tools:shovel_gold" then return "shovely_dig_gold" - elseif itemstring == "mcl_tools:shovel_diamond" then + elseif string_start == "mcl_tools:shovel_diam" then return "shovely_dig_diamond" else -- Fallback @@ -218,8 +218,9 @@ local make_grass_path = function(itemstack, placer, pointed_thing) local toolname = itemstack:get_name() local def = minetest.registered_items[toolname] local group = get_shovel_dig_group(toolname) - local base_uses = def.tool_capabilities.groupcaps[group].uses - local maxlevel = def.tool_capabilities.groupcaps[group].maxlevel + local toolcaps = itemstack:get_tool_capabilities() + local base_uses = toolcaps.groupcaps[group].uses + local maxlevel = toolcaps.groupcaps[group].maxlevel local uses = base_uses * math.pow(3, maxlevel) local wear = math.ceil(65535 / uses) itemstack:add_wear(wear) From 939a73dd7712a6ef7dcf404a2d985c90ed583a10 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 11:18:18 +0100 Subject: [PATCH 047/219] Remove Licenses from mcl_burning and mcl_enchanting --- mods/ENTITIES/mcl_burning/LICENSE | 674 ------------------------------ mods/ITEMS/mcl_enchanting/LICENSE | 674 ------------------------------ 2 files changed, 1348 deletions(-) delete mode 100644 mods/ENTITIES/mcl_burning/LICENSE delete mode 100644 mods/ITEMS/mcl_enchanting/LICENSE diff --git a/mods/ENTITIES/mcl_burning/LICENSE b/mods/ENTITIES/mcl_burning/LICENSE deleted file mode 100644 index 9cecc1d46..000000000 --- a/mods/ENTITIES/mcl_burning/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/mods/ITEMS/mcl_enchanting/LICENSE b/mods/ITEMS/mcl_enchanting/LICENSE deleted file mode 100644 index 9cecc1d46..000000000 --- a/mods/ITEMS/mcl_enchanting/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. From ab079d0c9bc210b43b22d5ad068b5c4d9bf7a2a7 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:11:16 +0100 Subject: [PATCH 048/219] Fix missing enchantability of golden shovel --- mods/ITEMS/mcl_tools/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 18638b189..8e9b45332 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -341,7 +341,7 @@ minetest.register_tool("mcl_tools:shovel_gold", { inventory_image = "default_tool_goldshovel.png", wield_image = "default_tool_goldshovel.png^[transformR90", wield_scale = wield_scale, - groups = { tool=1, shovel=1, dig_speed_class=6, }, + groups = { tool=1, shovel=1, dig_speed_class=6, enchantability=22 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=2, From 64e510a7305e46514194f1ac8cd268d4c8d49928 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:21:35 +0100 Subject: [PATCH 049/219] Better bookshelf counting --- mods/ITEMS/mcl_enchanting/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index 2d4d33dae..0ee9352fd 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -235,7 +235,8 @@ minetest.register_node("mcl_enchanting:table", { if table_name == "" then table_name = S("Enchant") end - player_meta:set_int("mcl_enchanting:num_bookshelves", num_bookshelves) + local bookshelves = mcl_enchanting.get_bookshelves(pos) + player_meta:set_int("mcl_enchanting:num_bookshelves", math.min(15, #bookshelves)) player_meta:set_string("mcl_enchanting:table_name", table_name) mcl_enchanting.show_enchanting_formspec(clicker) -- Respawn book entity just in case it got lost @@ -310,7 +311,6 @@ minetest.register_abm({ }) end end - minetest.get_meta(pos):set_int("mcl_enchanting:num_bookshelves", math.min(15, #absolute)) end }) From 7d805ff7891026d37ad95ffa09cf8f706a6c19eb Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:28:38 +0100 Subject: [PATCH 050/219] Fix duplicate bookshelf positions --- mods/ITEMS/mcl_enchanting/init.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index 0ee9352fd..bd7e05ee4 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -26,8 +26,8 @@ mcl_enchanting = { {x = -2, y = 0, z = -1}, {x = -2, y = 1, z = -1}, {x = -2, y = 0, z = 0}, {x = -2, y = 1, z = 0}, {x = -2, y = 0, z = 1}, {x = -2, y = 1, z = 1}, - {x = -2, y = 0, z = 2}, {x = -2, y = 1, z = 2}, - {x = 2, y = 0, z = -2}, {x = 2, y = 1, z = -2}, + -- {x = -2, y = 0, z = 2}, {x = -2, y = 1, z = 2}, + -- {x = 2, y = 0, z = -2}, {x = 2, y = 1, z = -2}, {x = 2, y = 0, z = -1}, {x = 2, y = 1, z = -1}, {x = 2, y = 0, z = 0}, {x = 2, y = 1, z = 0}, {x = 2, y = 0, z = 1}, {x = 2, y = 1, z = 1}, @@ -48,8 +48,8 @@ mcl_enchanting = { {x = -1, y = 0, z = -1}, {x = -1, y = 1, z = -1}, {x = -1, y = 0, z = 0}, {x = -1, y = 1, z = 0}, {x = -1, y = 0, z = 1}, {x = -1, y = 1, z = 1}, - {x = -1, y = 0, z = 1}, {x = -1, y = 1, z = 1}, - {x = 1, y = 0, z = -1}, {x = 1, y = 1, z = -1}, + -- {x = -1, y = 0, z = 1}, {x = -1, y = 1, z = 1}, + -- {x = 1, y = 0, z = -1}, {x = 1, y = 1, z = -1}, {x = 1, y = 0, z = -1}, {x = 1, y = 1, z = -1}, {x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, {x = 1, y = 0, z = 1}, {x = 1, y = 1, z = 1}, From 8ba8f62527fa227c1122456bfe403ba813cf1668 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:34:02 +0100 Subject: [PATCH 051/219] Document fire_resistant and fire_damage_resistant --- mods/ENTITIES/mcl_mobs/api.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index d1c478a99..7c85ea566 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -249,6 +249,8 @@ functions needed for the mob to work properly which contains the following: 'instant_death' If true, mob dies instantly (no death animation or delay) (default: false) 'xp_min' the minimum XP it drops on death (default: 0) 'xp_max' the maximum XP it drops on death (default: 0) + 'fire_resistant' If true, the mob can't burn + 'fire_damage_resistant' If true the mob will not take damage when burning From 081ae7fbff9737a8baac7523d1a65bd2e864ba22 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:43:50 +0100 Subject: [PATCH 052/219] Make undead mobs burn in sunlight instead of dealing damage directly --- mods/ENTITIES/mcl_mobs/api.lua | 8 ++++++-- mods/ENTITIES/mcl_mobs/api.txt | 1 + mods/ENTITIES/mobs_mc/skeleton+stray.lua | 2 +- mods/ENTITIES/mobs_mc/villager_zombie.lua | 3 ++- mods/ENTITIES/mobs_mc/zombie.lua | 2 ++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 91157e12e..e9e3caa81 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -1053,8 +1053,11 @@ local do_env_damage = function(self) if mod_worlds then _, dim = mcl_worlds.y_to_layer(pos.y) end - if self.sunlight_damage ~= 0 and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" then - if deal_light_damage(self, pos, self.sunlight_damage) then + if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" then + if self.ignited_by_sunlight then + mcl_burning.set_on_fire(self.object, 10, self.sunlight_damage or 1) + else + deal_light_damage(self, pos, self.sunlight_damage) return true end end @@ -3813,6 +3816,7 @@ minetest.register_entity(name, { instant_death = def.instant_death or false, fire_resistant = def.fire_resistant or false, fire_damage_resistant = def.fire_damage_resistant or false, + ignited_by_sunlight = def.ignited_by_sunlight or false, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index 7c85ea566..ee97489b5 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -251,6 +251,7 @@ functions needed for the mob to work properly which contains the following: 'xp_max' the maximum XP it drops on death (default: 0) 'fire_resistant' If true, the mob can't burn 'fire_damage_resistant' If true the mob will not take damage when burning + 'ignited_by_sunlight' If true the mod will burn at daytime. (Takes sunlight_damage per second) diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index f3ef3c4b1..cb12e905d 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -81,7 +81,7 @@ local skeleton = { die_speed = 15, die_loop = false, }, - sunlight_damage = 1, + ignited_by_sunlight = true, view_range = 16, fear_height = 4, attack_type = "dogshoot", diff --git a/mods/ENTITIES/mobs_mc/villager_zombie.lua b/mods/ENTITIES/mobs_mc/villager_zombie.lua index f6927aa41..8bbd3c530 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -82,7 +82,8 @@ mobs:register_mob("mobs_mc:villager_zombie", { run_start = 0, run_end = 20, }, - sunlight_damage = 1, + sunlight_damage = 2, + ignited_by_sunlight = true, view_range = 16, fear_height = 4, harmed_by_heal = true, diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index 75c8273c6..df9727d34 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -85,6 +85,7 @@ local zombie = { walk_start = 0, walk_end = 40, run_start = 0, run_end = 40, }, + ignited_by_sunlight = true, sunlight_damage = 2, view_range = 16, attack_type = "dogfight", @@ -111,6 +112,7 @@ mobs:register_mob("mobs_mc:baby_zombie", baby_zombie) -- Desert variant of the zombie local husk = table.copy(zombie) husk.textures = {{"mobs_mc_husk.png"}} +husk.ignited_by_sunlight = false husk.sunlight_damage = 0 husk.drops = drops_common -- TODO: Husks avoid water From 7d45055a594e4cb95d85596ee262727e90f97954 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 12:45:23 +0100 Subject: [PATCH 053/219] Remove minetest.env in mcl_mobs API --- mods/ENTITIES/mcl_mobs/api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index e9e3caa81..e35d73d20 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -226,7 +226,7 @@ local collision = function(self) local z = 0 local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5 - for _,object in ipairs(minetest.env:get_objects_inside_radius(pos, width)) do + for _,object in ipairs(minetest.get_objects_inside_radius(pos, width)) do if object:is_player() or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then From c2521885ff6671d0cfd481068fb96b6590df4459 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sat, 2 Jan 2021 14:03:50 +0100 Subject: [PATCH 054/219] Remove extinguish sound --- mods/ENTITIES/mcl_burning/engine.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mods/ENTITIES/mcl_burning/engine.lua b/mods/ENTITIES/mcl_burning/engine.lua index 6046f17c4..02e416db7 100644 --- a/mods/ENTITIES/mcl_burning/engine.lua +++ b/mods/ENTITIES/mcl_burning/engine.lua @@ -196,12 +196,6 @@ function mcl_burning.extinguish(obj) obj:hud_remove(hud_id) end - minetest.sound_play("fire_extinguish_flame", { - object = obj, - gain = 0.18, - max_hear_distance = 32, - }) - mcl_burning.set(obj, "float", "damage") mcl_burning.set(obj, "string", "reason") mcl_burning.set(obj, "float", "burn_time") From 30379c823c98560c83a986d25c8764158989e691 Mon Sep 17 00:00:00 2001 From: kay27 Date: Sun, 3 Jan 2021 00:42:07 +0400 Subject: [PATCH 055/219] Clean up some spaces in code after merging https://git.minetest.land/EliasFleckenstein03/MineClone2 --- mods/CORE/mcl_loot/init.lua | 2 +- mods/ENTITIES/mcl_mobs/api.lua | 14 +++++++------- mods/ENTITIES/mobs_mc/villager.lua | 8 ++++---- mods/HUD/mcl_experience/init.lua | 2 +- mods/ITEMS/mcl_enchanting/enchantments.lua | 2 +- mods/ITEMS/mcl_enchanting/engine.lua | 2 +- mods/ITEMS/mcl_furnaces/init.lua | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/mods/CORE/mcl_loot/init.lua b/mods/CORE/mcl_loot/init.lua index cb371c284..e3db73be1 100644 --- a/mods/CORE/mcl_loot/init.lua +++ b/mods/CORE/mcl_loot/init.lua @@ -69,7 +69,7 @@ function mcl_loot.get_loot(loot_definitions, pr) local wear_min = math.floor(item.wear_min / 10) local wear_max = math.floor(item.wear_max / 10) local wear = pr:next(wear_min, wear_max) * 10 - + if not item.amount_min and not item.amount_max then itemstring = itemstring .. " 1" end diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index e35d73d20..be7086e8d 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -664,7 +664,7 @@ local item_drop = function(self, cooked, looting_level) local dropdef = self.drops[n] local chance = 1 / dropdef.chance local looting_type = dropdef.looting - + if looting_level > 0 then local chance_function = dropdef.looting_chance_function if chance_function then @@ -673,7 +673,7 @@ local item_drop = function(self, cooked, looting_level) chance = chance + (dropdef.looting_factor or 0.01) * looting_level end end - + local num = 0 local do_common_looting = (looting_level > 0 and looting_type == "common") if random() < chance then @@ -681,11 +681,11 @@ local item_drop = function(self, cooked, looting_level) elseif not dropdef.looting_ignore_chance then do_common_looting = false end - + if do_common_looting then num = num + math.floor(math.random(0, looting_level) + 0.5) end - + if num > 0 then item = dropdef.name @@ -2962,7 +2962,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) * tmp * ((armor[group] or 0) / 100.0) end end - + if weapon then local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect") if fire_aspect_level > 0 then @@ -3379,11 +3379,11 @@ end -- main mob function local mob_step = function(self, dtime) - + if not self.fire_resistant then mcl_burning.tick(self.object, dtime) end - + if use_cmi then cmi.notify_step(self.object, dtime) end diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index 477392b7d..bc819547b 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -170,7 +170,7 @@ local professions = { { E1, { "mcl_core:glass", 3, 5 } }, { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, }, - + { { { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }}, }, @@ -402,7 +402,7 @@ local init_trades = function(self, inv) local wanted1_count = math.random(trade[1][2], trade[1][3]) local offered_item = trade[2][1] local offered_count = math.random(trade[2][2], trade[2][3]) - + local offered_stack = ItemStack({name = offered_item, count = offered_count}) if mcl_enchanting.is_enchanted(offered_item) then if mcl_enchanting.is_book(offered_item) then @@ -411,7 +411,7 @@ local init_trades = function(self, inv) mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true) end end - + local wanted = { wanted1_item .. " " ..wanted1_count } if trade[1][4] then local wanted2_item = trade[1][4] @@ -499,7 +499,7 @@ local function show_trade_formspec(playername, trader, tradenum) local wanted1 = inv:get_stack("wanted", 1) local wanted2 = inv:get_stack("wanted", 2) local offered = inv:get_stack("offered", 1) - + local w2_formspec = "" if not wanted2:is_empty() then w2_formspec = "item_image[3,1;1,1;"..wanted2:to_string().."]" diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 2368ee761..556f419d4 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -183,7 +183,7 @@ minetest.register_on_joinplayer(function(player) number = 0x80FF20, offset = {x = 0, y = -(48 + 24 + 24)}, z_index = 12, - }) + }) end) function mcl_experience.xp_to_level(xp) diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index d2803be14..d79cb8375 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -353,7 +353,7 @@ function minetest.calculate_knockback(player, hitter, time_from_last_punch, tool return knockback end --- implemented in mcl_mobs and mobs_mc +-- implemented in mcl_mobs and mobs_mc mcl_enchanting.enchantments.looting = { name = S("Looting"), max_level = 3, diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 43127b30d..ead8bb6eb 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -543,7 +543,7 @@ function mcl_enchanting.on_inventory_action(player, action, inventory, inventory if stack:get_name() == "mcl_dye:blue" then result_list = "enchanting_lapis" stack:add_item(inventory:get_stack("enchanting_lapis", 1)) - else + else result_list = "enchanting_item" end inventory:set_stack(result_list, 1, stack) diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index 82e82807e..a0b946955 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -79,7 +79,7 @@ local function drop_xp(pos) meta:set_int("xp", 0) end end -end +end -- -- Node callback functions that are the same for active and inactive furnace @@ -357,7 +357,7 @@ local function furnace_node_timer(pos, elapsed) srclist = inv:get_list("src") src_time = 0 - + meta:set_int("xp", meta:get_int("xp") + 1) -- ToDo give each recipe an idividial XP count end end @@ -491,7 +491,7 @@ minetest.register_node("mcl_furnaces:furnace", { furnace_reset_delta_time(pos) -- start timer function, it will helpful if player clears dst slot minetest.get_node_timer(pos):start(1.0) - + if listname == "dst" then drop_xp(pos) end From ea938237d58a31209935a13c4884f92d5a98e070 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 14:21:35 +0100 Subject: [PATCH 056/219] Animated Chests --- mods/ITEMS/mcl_chests/init.lua | 265 +++++++++++++++--- .../mcl_chests/models/mcl_chests_chest.b3d | Bin 0 -> 6075 bytes .../mcl_chests/models/mcl_chests_chest.obj | 91 ++++++ .../models/mcl_chests_double_chest.b3d | Bin 0 -> 10342 bytes .../mcl_chests/sounds/default_chest_close.ogg | Bin 0 -> 10768 bytes .../mcl_chests/sounds/default_chest_open.ogg | Bin 0 -> 11092 bytes .../textures/mcl_chests_trapped.png | Bin 0 -> 1209 bytes .../textures/mcl_chests_trapped_double.png | Bin 0 -> 2011 bytes 8 files changed, 320 insertions(+), 36 deletions(-) create mode 100644 mods/ITEMS/mcl_chests/models/mcl_chests_chest.b3d create mode 100644 mods/ITEMS/mcl_chests/models/mcl_chests_chest.obj create mode 100644 mods/ITEMS/mcl_chests/models/mcl_chests_double_chest.b3d create mode 100644 mods/ITEMS/mcl_chests/sounds/default_chest_close.ogg create mode 100644 mods/ITEMS/mcl_chests/sounds/default_chest_open.ogg create mode 100644 mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png create mode 100644 mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index 3d5fbbca3..fdfae533a 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -7,6 +7,148 @@ if minetest.get_modpath("screwdriver") then simple_rotate = screwdriver.rotate_simple end +-- Chest Entity +local entity_animations = {} +local entity_animation_speed = 25 + +do + local names = {"open", "opened", "close", "closed"} + local following = {["open"] = "opened", ["close"] = "closed"} + local durations = {10, 0, 10, 5} + local anim_start = 0 + for index, name in ipairs(names) do + local duration = durations[index] + local anim_end = anim_start + duration + entity_animations[name] = { + bounds = {x = anim_start, y = anim_end}, + sched_anim = following[name], + sched_time = duration / entity_animation_speed + } + anim_start = anim_end + end +end + +minetest.register_entity("mcl_chests:chest", { + initial_properties = { + visual = "mesh", + visual_size = {x = 3, y = 3}, + pointable = false, + physical = false, + }, + + set_animation = function(self, animname) + local anim = entity_animations[animname] + self.object:set_animation(anim.bounds, entity_animation_speed, 0, false) + if anim.sched_anim then + self.sched_anim = anim.sched_anim + self.sched_time = anim.sched_time + end + end, + + open = function(self, playername) + self.players[playername] = true + if not self.is_open then + self.is_open = true + self:set_animation("open") + minetest.sound_play("default_chest_open", { + pos = self.node_pos, + }) + end + end, + + close = function(self, playername) + local playerlist = self.players + playerlist[playername] = nil + if self.is_open then + for _ in pairs(playerlist) do + return + end + self.is_open = false + self:set_animation("close") + minetest.sound_play("default_chest_close", { + pos = self.node_pos, + }) + end + end, + + initialize = function(self, node_pos, node_name, textures, dir, double) + self.node_pos = node_pos + self.node_name = node_name + local obj = self.object + obj:set_properties({textures = textures}) + obj:set_yaw(minetest.dir_to_yaw(dir)) + obj:set_properties({mesh = double and "mcl_chests_double_chest.b3d" or "mcl_chests_chest.b3d"}) + end, + + check = function(self) + local node_pos, node_name = self.node_pos, self.node_name + if not node_pos or not node_name then + return false + end + local node = minetest.get_node(node_pos) + if node.name ~= node_name then + return false + end + return true + end, + + on_activate = function(self) + self.object:set_armor_groups({immortal = 1}) + self:set_animation("closed") + self.players = {} + end, + + on_step = function(self, dtime) + local sched_anim, sched_time = self.sched_anim, self.sched_time + if not self:check() then + self.object:remove() + elseif sched_anim and sched_time then + sched_time = sched_time - dtime + if sched_time < 0 then + self:set_animation(sched_anim) + self.sched_time = nil + self.sched_anim = nil + else + self.sched_time = sched_time + end + end + end +}) + +local function get_entity_pos(pos, dir, double) + pos = vector.new(pos) + pos.y = pos.y - 0.4375 + if double then + local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross + pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5)) + end + return pos +end + +local function find_entity(pos) + for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do + local luaentity = obj:get_luaentity() + if luaentity and luaentity.name == "mcl_chests:chest" then + return luaentity + end + end +end + +local function create_entity(pos, node_name, textures, param2, double, dir, entity_pos) + dir = dir or minetest.facedir_to_dir(param2) + entity_pos = entity_pos or get_entity_pos(pos, dir, double) + local obj = minetest.add_entity(entity_pos, "mcl_chests:chest") + local luaentity = obj:get_luaentity() + luaentity:initialize(pos, node_name, textures, dir, double) + return luaentity +end + +local function find_or_create_entity(pos, node_name, textures, param2, double) + local dir = minetest.facedir_to_dir(param2) + local entity_pos = get_entity_pos(pos, dir, double) + return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, dir, entity_pos) +end + --[[ List of open chests. Key: Player name Value: @@ -14,8 +156,10 @@ Value: Otherwise: nil ]] local open_chests = {} -- To be called if a player opened a chest -local player_chest_open = function(player, pos) - open_chests[player:get_player_name()] = { pos = pos } +local player_chest_open = function(player, pos, node_name, textures, param2, double) + local name = player:get_player_name() + open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double} + find_or_create_entity(pos, node_name, textures, param2, double):open(name) end -- Simple protection checking functions @@ -67,11 +211,12 @@ end -- To be called if a player closed a chest local player_chest_close = function(player) local name = player:get_player_name() - if open_chests[name] == nil then + local open_chest = open_chests[name] + if open_chest == nil then return end - local pos = open_chests[name].pos - chest_update_after_close(pos) + find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double):close(name) + chest_update_after_close(open_chest.pos) open_chests[name] = nil end @@ -146,18 +291,34 @@ local on_chest_blast = function(pos) minetest.remove_node(pos) end -minetest.register_node("mcl_chests:"..basename, { +local small_name = "mcl_chests:"..basename +local small_textures = tiles_table.small +local left_name = "mcl_chests:"..basename.."_left" +local left_textures = tiles_table.double + +minetest.register_node(small_name, { description = desc, _tt_help = tt_help, _doc_items_longdesc = longdesc, _doc_items_usagehelp = usagehelp, _doc_items_hidden = hidden, - tiles = tiles_table.small, + drawtype = "airlike", + selection_box = { + type = "fixed", + fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, + }, + collision_box = { + type = "fixed", + fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, + }, + inventory_image = "mcl_chests_normal.png", + tiles = {"blank.png"}, + _chest_entity_textures = small_textures, paramtype = "light", paramtype2 = "facedir", stack_max = 64, drop = drop, - groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1}, + groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1,chest_entity=1}, is_ground_content = false, sounds = mcl_sounds.node_sound_wood_defaults(), on_construct = function(pos) @@ -189,12 +350,15 @@ minetest.register_node("mcl_chests:"..basename, { minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_right",param2=param2}) local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_left", param2 = param2 }) + create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename then minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_left",param2=param2}) + create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 }) else minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename, param2 = param2 }) + create_entity(pos, small_name, small_textures, param2, false) end end, after_place_node = function(pos, placer, itemstack, pointed_thing) @@ -235,7 +399,7 @@ minetest.register_node("mcl_chests:"..basename, { if name == "" then name = S("Chest") end - + minetest.show_formspec(clicker:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, "size[9,8.75]".. @@ -253,6 +417,8 @@ minetest.register_node("mcl_chests:"..basename, { if on_rightclick_addendum then on_rightclick_addendum(pos, node, clicker) end + + player_chest_open(clicker, pos, small_name, small_textures, node.param2, false) end, on_destruct = function(pos) @@ -265,11 +431,21 @@ minetest.register_node("mcl_chests:"..basename, { on_rotate = simple_rotate, }) -minetest.register_node("mcl_chests:"..basename.."_left", { - tiles = tiles_table.left, +minetest.register_node(left_name, { + drawtype = "nodebox", + selection_box = { + type = "fixed", + fixed = {-0.4375, -0.5, -0.4375, 1.4375, 0.375, 0.4375}, + }, + collision_box = { + type = "fixed", + fixed = {-0.4375, -0.5, -0.4375, 1.4375, 0.375, 0.4375}, + }, + tiles = {"blank.png"}, + _chest_entity_textures = left_textures, paramtype = "light", paramtype2 = "facedir", - groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1}, + groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1,chest_entity=1,double_chest=1}, drop = drop, is_ground_content = false, sounds = mcl_sounds.node_sound_wood_defaults(), @@ -281,6 +457,7 @@ minetest.register_node("mcl_chests:"..basename.."_left", { n.name = "mcl_chests:"..canonical_basename minetest.swap_node(pos, n) end + create_entity(pos, left_name, left_textures, param2, true) end, after_place_node = function(pos, placer, itemstack, pointed_thing) minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name")) @@ -305,6 +482,7 @@ minetest.register_node("mcl_chests:"..basename.."_left", { minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z) end minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 }) + create_entity(p, "mcl_chests:"..basename, small_textures, param2, false) end, after_dig_node = drop_items_chest, on_blast = on_chest_blast, @@ -399,16 +577,26 @@ minetest.register_node("mcl_chests:"..basename.."_left", { if on_rightclick_addendum_left then on_rightclick_addendum_left(pos, node, clicker) end + + player_chest_open(clicker, pos, left_name, left_textures, node.param2, true) end, mesecons = mesecons, on_rotate = no_rotate, }) minetest.register_node("mcl_chests:"..basename.."_right", { - tiles = tiles_table.right, + drawtype = "airlike", paramtype = "light", paramtype2 = "facedir", - groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1}, + selection_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, + collision_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, + groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, drop = drop, is_ground_content = false, sounds = mcl_sounds.node_sound_wood_defaults(), @@ -540,6 +728,8 @@ minetest.register_node("mcl_chests:"..basename.."_right", { if on_rightclick_addendum_right then on_rightclick_addendum_right(pos, node, clicker) end + + player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true) end, mesecons = mesecons, on_rotate = no_rotate, @@ -561,29 +751,33 @@ register_chest("chest", chestusage, S("27 inventory slots") .. "\n" .. S("Can be combined to a large chest"), { - small = {"default_chest_top.png", "mcl_chests_chest_bottom.png", + small = {"mcl_chests_normal.png"}, + double = {"mcl_chests_normal_double.png"}, + inv = {"default_chest_top.png", "mcl_chests_chest_bottom.png", "mcl_chests_chest_right.png", "mcl_chests_chest_left.png", "mcl_chests_chest_back.png", "default_chest_front.png"}, - left = {"default_chest_top_big.png", "default_chest_top_big.png", + --[[left = {"default_chest_top_big.png", "default_chest_top_big.png", "mcl_chests_chest_right.png", "mcl_chests_chest_left.png", "default_chest_side_big.png^[transformFX", "default_chest_front_big.png"}, right = {"default_chest_top_big.png^[transformFX", "default_chest_top_big.png^[transformFX", "mcl_chests_chest_right.png", "mcl_chests_chest_left.png", - "default_chest_side_big.png", "default_chest_front_big.png^[transformFX"}, + "default_chest_side_big.png", "default_chest_front_big.png^[transformFX"},]]-- }, false ) local traptiles = { - small = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png", + small = {"mcl_chests_trapped.png"}, + double = {"mcl_chests_trapped_double.png"}, + inv = {"mcl_chests_chest_trapped_top.png", "mcl_chests_chest_trapped_bottom.png", "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png", "mcl_chests_chest_trapped_back.png", "mcl_chests_chest_trapped_front.png"}, - left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png", + --[[left = {"mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_top_big.png", "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png", "mcl_chests_chest_trapped_side_big.png^[transformFX", "mcl_chests_chest_trapped_front_big.png"}, right = {"mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_top_big.png^[transformFX", "mcl_chests_chest_trapped_right.png", "mcl_chests_chest_trapped_left.png", - "mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"}, + "mcl_chests_chest_trapped_side_big.png", "mcl_chests_chest_trapped_front_big.png^[transformFX"},]]-- } register_chest("trapped_chest", @@ -600,7 +794,6 @@ register_chest("trapped_chest", function(pos, node, clicker) minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on", param2 = node.param2}) mesecon.receptor_on(pos, trapped_chest_mesecons_rules) - player_chest_open(clicker, pos) end, function(pos, node, clicker) local meta = minetest.get_meta(pos) @@ -612,8 +805,6 @@ register_chest("trapped_chest", local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_right", param2 = node.param2}) mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules) - - player_chest_open(clicker, pos) end, function(pos, node, clicker) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") @@ -623,8 +814,6 @@ register_chest("trapped_chest", minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2}) mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules) - - player_chest_open(clicker, pos) end ) @@ -634,15 +823,7 @@ register_chest("trapped_chest_on", state = mesecon.state.on, rules = trapped_chest_mesecons_rules, }}, - function(pos, node, clicker) - player_chest_open(clicker, pos) - end, - function(pos, node, clicker) - player_chest_open(clicker, pos) - end, - function(pos, node, clicker) - player_chest_open(clicker, pos) - end, + nil, nil, nil, "trapped_chest", "trapped_chest" ) @@ -676,9 +857,9 @@ local function close_if_trapped_chest(pos, player) end end --- Disable trapped chest when it has been closed +-- Disable chest when it has been closed minetest.register_on_player_receive_fields(function(player, formname, fields) - if formname:find("mcl_chests:trapped_chest_") == 1 then + if formname:find("mcl_chests:") == 1 then if fields.quit then player_chest_close(player) end @@ -1001,6 +1182,18 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv end end) +minetest.register_lbm({ + label = "Spawn Chest entities", + name = "mcl_chests:spawn_chest_entities", + nodenames = {"group:chest_entity"}, + run_at_every_load = true, + action = function(pos, node) + local node_name = node.name + local node_def = minetest.registered_nodes[node_name] + local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 + create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest) + end +}) minetest.register_lbm({ -- Disable active/open trapped chests when loaded because nobody could diff --git a/mods/ITEMS/mcl_chests/models/mcl_chests_chest.b3d b/mods/ITEMS/mcl_chests/models/mcl_chests_chest.b3d new file mode 100644 index 0000000000000000000000000000000000000000..e82c7e3639236824597be75b0126f74156f491a7 GIT binary patch literal 6075 zcma)8Yiw0T5I#VQATI@_JOoO46$Dyt<<-KSOKFQlfym_{Cd8tGgdiY~m`I>2|9r$B zDvA$GN%&((4CNpRfl`QxAp*gu@s)@|)Px`MP@+_kI^WJt_uR{E@0sMgvvX$d?4H?g z&un#dMNL=~1YLq4s9wA@J(;x~Z{D_L?d0n%^|w+)7h5Na|2pl z8ubBPxK(hH7c?sf8fU}5|HIxX^)IDy59 zY5jBTk6nK!`E7mF@Aog?`Wkuto$&+z_kP_UU*F99x z{??zx&raX}W;$%?cKTO>&g6f6G6?o0@x1FViIn<%{ot=}_qV1)!vFpHusZQ0zxw_A z!!P-B`|J6m;OE!>`~2|R{Dk#6zvZ8tuhMpZB!7he@Z0>9&z~=Uq&{|jssGPfADiFR zFT#KL{rsKz^W@LFKX^agKYxDw{zl%v#qSU569oLf4(fyTdw=fr`~AOje!oAt>)W2+ zzF&_0*ZK3kzvYLn&+`}g>ys4~VN3AW>|@Y(@_!=XdEve`tCiofzo=h9)Su0Nqkfm) z`h9%^_DlZUe(*bE{;d4)+xf|@5B@Cvi$9V-i~lx1<@4vuAE{3k|1;)q!TLP^Q2&hi zJM`ztpLc)U`ys#Ox8J|c>M!31-v18jgZ1wLf7G92{lbsj^CN#}``4ad-;b1k@_hsU z?ELDt@8|gqe@1@0KJQ2V0$Q?oe)=#jLoB!txna=F*?8WaQOGD@+~sVH`C1k5bt>q= z=;dsT`!f14dNcYt8{__rdl~mI1~?nzfsFeZ_c8dMXKjp!Fa|RQF@`!D*%&7nxUQBnDx8h+ zG{#iMLyYOp#<-F(lQDx)J*-G_h`5HJJ+c0hEsU0h1sjL|L|AIMUfAPJ>Mlum%D)LBK2sSOo!lAYc^)41<7O5U>aW zc0s^22v`OIo3Kw{88jFN4YompRnTA?G?)hs)`J?2yIEg zI^}Gz5YMZf1{-06bVSXj6aG1##fo)Yj1}wn z8Y{Liuo5fQ@jh0pI~%cL-T8?X>&{rLSa%L%#k#W^E7qOoSh4QR$BK2|g;=rf+Yu|) zeP3e5x^GadSofWZ73;obv0~l#E>Cm4M7HVMtE6AvwK<Q)fs{lp#4ShU6p|5|$eh1{)G~8WQFi5>^=! z#uySd7?PbfB)e!xcF2%a-;h++kW|f(RK$>U2}9B)3`v(TBwfOgbO}S!B@9WIFeF{V zkaP({(j^QPbD>Zt=@N#dOBfpEo{x4~x`d&z&K~EqbO}S!B@9WIFeF{VkaP({(j^Q@ zmoOwy6bMeDcBg)=cFsyU-Jg0MY3CBN<=$L=nC8DuyZ4CrmJ>IpVyIp?%7P-tX&;N6 z8r%2c!NjWf#)PN8SVcXiTu%z`eJtX14UO-vNenxX2>0*XLbqn@O=_3Wcf0NKLiadu ze#*;NXNJ38*+CoL?vvCmp|Qw`IAF$>gJlTaPqNSzZ}_U$m2!n$~9R5*mvbjlbM_rs-1K%FU!#O_aLggdWqr%P{4O=_3WSmaeq z=>B@*xz8ts*Zx^gUww2csa-;2wFc1t?*20I*@mIvu0PUr_|1OqJC(@?>=|;WhqNWu ooaz}K`?iV>{XWTk%Q9m%clLK#yM(R*`8tZ#E}^j+2c4bwe+Tu<9RL6T literal 0 HcmV?d00001 diff --git a/mods/ITEMS/mcl_chests/models/mcl_chests_chest.obj b/mods/ITEMS/mcl_chests/models/mcl_chests_chest.obj new file mode 100644 index 000000000..36268146f --- /dev/null +++ b/mods/ITEMS/mcl_chests/models/mcl_chests_chest.obj @@ -0,0 +1,91 @@ +# Blender v2.76 (sub 0) OBJ File: 'chest.small.facedir.blend' +# www.blender.org +mtllib chest.small.facedir.mtl +o chest_upper_upper +v 0.062513 -0.063134 -0.500468 +v 0.062513 0.186920 -0.500468 +v 0.062514 -0.063134 -0.437955 +v 0.062514 0.186920 -0.437955 +v -0.062514 -0.063134 -0.500468 +v -0.062514 0.186920 -0.500468 +v -0.062514 -0.063134 -0.437955 +v -0.062514 0.186920 -0.437955 +v 0.437907 0.061263 -0.438085 +v 0.437907 0.373830 -0.438085 +v 0.437907 0.061263 0.437729 +v 0.437907 0.373830 0.437729 +v -0.437907 0.061263 -0.438085 +v -0.437907 0.373830 -0.438085 +v -0.437907 0.061263 0.437729 +v -0.437907 0.373830 0.437729 +v 0.437595 -0.500754 -0.437772 +v 0.437595 0.124381 -0.437772 +v 0.437595 -0.500754 0.437417 +v 0.437595 0.124381 0.437417 +v -0.437595 -0.500754 -0.437772 +v -0.437595 0.124381 -0.437772 +v -0.437595 -0.500754 0.437417 +v -0.437595 0.124381 0.437417 +vt 0.015625 0.921875 +vt 0.015625 0.984375 +vt 0.000000 0.984375 +vt 0.000000 0.921875 +vt 0.093750 0.921875 +vt 0.093750 0.984375 +vt 0.062500 0.984375 +vt 0.062500 0.921875 +vt 0.046875 0.984375 +vt 0.046875 0.921875 +vt 0.078125 0.984375 +vt 0.078125 1.000000 +vt 0.046875 1.000000 +vt 0.015625 1.000000 +vt 0.218750 0.703125 +vt 0.218750 0.781250 +vt 0.000000 0.781250 +vt 0.000000 0.703125 +vt 0.875000 0.703125 +vt 0.875000 0.781250 +vt 0.656250 0.781250 +vt 0.656250 0.703125 +vt 0.437500 0.781250 +vt 0.437500 0.703125 +vt 0.656250 1.000000 +vt 0.437500 1.000000 +vt 0.218750 1.000000 +vt 0.218750 0.328125 +vt 0.218750 0.484375 +vt -0.000000 0.484375 +vt -0.000000 0.328125 +vt 0.875000 0.328125 +vt 0.875000 0.484375 +vt 0.656250 0.484375 +vt 0.656250 0.328125 +vt 0.437500 0.484375 +vt 0.437500 0.328125 +vn 1.000000 0.000000 -0.000000 +vn 0.000000 0.000000 1.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +usemtl None +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/5/2 4/6/2 8/7/2 7/8/2 +f 7/8/3 8/7/3 6/9/3 5/10/3 +f 5/10/4 6/9/4 2/2/4 1/1/4 +f 3/9/5 7/11/5 5/12/5 1/13/5 +f 8/13/6 4/14/6 2/2/6 6/9/6 +f 9/15/1 10/16/1 12/17/1 11/18/1 +f 11/19/2 12/20/2 16/21/2 15/22/2 +f 15/22/3 16/21/3 14/23/3 13/24/3 +f 13/24/4 14/23/4 10/16/4 9/15/4 +f 11/25/5 15/26/5 13/23/5 9/21/5 +f 16/26/6 12/27/6 10/16/6 14/23/6 +f 17/28/1 18/29/1 20/30/1 19/31/1 +f 19/32/2 20/33/2 24/34/2 23/35/2 +f 23/35/3 24/34/3 22/36/3 21/37/3 +f 21/37/4 22/36/4 18/29/4 17/28/4 +f 19/22/5 23/24/5 21/36/5 17/34/5 +f 24/24/6 20/15/6 18/29/6 22/36/6 diff --git a/mods/ITEMS/mcl_chests/models/mcl_chests_double_chest.b3d b/mods/ITEMS/mcl_chests/models/mcl_chests_double_chest.b3d new file mode 100644 index 0000000000000000000000000000000000000000..86c44bfeb96b2de946ffe210f23c56910567d2ca GIT binary patch literal 10342 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 literal 0 HcmV?d00001 diff --git a/mods/ITEMS/mcl_chests/sounds/default_chest_open.ogg b/mods/ITEMS/mcl_chests/sounds/default_chest_open.ogg new file mode 100644 index 0000000000000000000000000000000000000000..40b0b93416cbf8a724a255ba202bcbf4ec74f429 GIT binary patch literal 11092 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 F{{dc*pj7|> literal 0 HcmV?d00001 diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped.png new file mode 100644 index 0000000000000000000000000000000000000000..de21d8f2fa5920d54c01431967f5d97c1f8e8355 GIT binary patch literal 1209 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DkxK$!8B)5ZfpLG}_)Usv`!T!NfJCb4TCx&ehGN?apKg7ec#$`gxH8440J^Gfvc zQcDy}^bGV&Q(KKvfkvx%x;TbZ#J!!qH!s9c!0j{7%b?}Hy&4@Z(weHGtfoRiRa{Y4 zN0>jbmDoI7wE2^x{I!bzHx%^KmMng4J@4ZW>EC(}xpwc~efz}OvuD#@-$~xSef#Yn zzkmNedwhHU{vV&dJQM%bp*U?0fB*V=<>G3ibyIEkYdU@GyZz6H|I_h^ueK}Bn;j5gU zbdU*q82S16Z}V1F*`5(}*0J29%+pwT)ZOPc!=r}Fsm%w{?iNfkX9zrQ(hzYiBlWqV z3*++c7k^k3W;^zL?6O+MXcK+2@{I6S#+)t3)qZd?@Fu>y!1h7%V@~SxjTdo8?`?~Xr$f6}EV%x73s=6Gg)4bzh?n?6VUQ#``<`Id6P4CS_n|B_F_WIiif zq%zwC`dxoL{|3jgN@ju9{+)3-{XfMEnRl$p*|B^-BgbY>r#V0W<*A5YY)~=ht7TSr ze01lLonhbpOmi)|Z28T$*6e`4!eg1=@6;2RSKZLkuU&pE+vxbQwm)%|n>elue0h9Y z-uzzVoXJaPREnhYOTOTunGERfB7=IzO!^TNvH zl7ljh0CYTB`-H)FyuP^{05uK<@*d~ z?;{refJDzq*1lIhzG{1Q58=E!>vkD((k<0O=ACFWo%VUtf zbDbf{#&@3PtnVt)iD$0xGMK$Ke{JmAY58-m^!>#Z$1a;KXz%^@#jrNGY~t%Jo1Slf z`rrDDTdULV6E{?n@3{P0C39j%mlpdfAaC}Wjg_UJPZ>V@eR+EL^%-{WpML$it-_4q z{yv-I$FCLd(O-X3M%we=jSniFhW37YoJE6w?pb%>$Avw?uVp8J;>Leb^*^iE=Oq-D zX|c_7kT*VcxZG>6^XFM-Hg3$E9MQ8x=g4Mpw#7DZSD>ik!f7$%yb_y*mR`q)BHRaq?jk(%^R^f|E*15cl>BKMLHt+1JB;!vuWu;$*Z)_Jk{7g9{ R9$2O@c)I$ztaD0e0sw$&O8Wo+ literal 0 HcmV?d00001 diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_trapped_double.png new file mode 100644 index 0000000000000000000000000000000000000000..95f768f97c0e7f1243b73df472b10174c7e69246 GIT binary patch literal 2011 zcmZuydpy(o8~?5y#2QJogC#|j>nhVG3^}Z54pOQacE)j=%eHW0l*2iSKcDye^?9D>^}If*Zs(k!N}5Ul z06?+Mr`=^SQD&H(@-ja#n2;a~-v!#a+5te-ZOAu2IoVk;!r7Yw0LsnV1`^v>wa7pP zD%RCeVN^*~QB6)gsNY%!!KjWGsUG10)M&pb5)k1RM5daONz?-;OwCO#NXf@YGS&~+ z({`RQKA-bn-qa`UP7!J%qmKKjC8eM5mjkP6>^r1-!rXk1Tx)-er}=KP7Atd!(uJau zqEF1~hB9IQ7)4rO8Z)yc7H&K#uj~_xq07tD-F3^~)+KdyuN9^`Ztbhvs`PpJ%SN|l z`212Qj=(z<_R3CN&iOeII(Trt)3PWni{gb&$emp)8V&6V@K-fyUPy}dtOgkl+9qsK zZ*vkhw(fE0o2x!{&q43O^wg!{U@#RS9g3gwS>DvmeMe(G0xidz-##M^L^S-A=WNc9 zH-F?#q$D7LT1y=c=O`=TEwtsCLDeaV?AA>};!q_4r{NI{USyd-e8SDH4j$l|0cfRH z8zXFuzDvc7HD0_>uc2PxY&oPo-}MCQt6R@JfuRq;qhZ3~T)oW_I;b`j$jb^eadXO< zLs2O`nPe8q_~2f-7tFos51e^3?(V_fG4|tzfl9*4PVi1-}0y zumVZ!ZF`zJEAh#0H1Nv&wj-mo=`&mdrPXp$G+`J+2N|YRA#qY+9Idy?0+UZ^Ae_`J z&XlV8R-@UFNcw9lLRanxfR(0;DxOJ1b68h#VeVe#wK1X2*je-f56Jd_5W$PFTuY+F zTKFjlyg1(^%8q1gDzZU^{+t=y$At`ml}PDNWOiH0a8r@3^0+}Jf@-79$nWxVO|eOH zy-Cb=@K0PL`^0^pL>%-r861t`q@{v+|HpJ!=>RzkF4}{1l$~@@j}^Q5KXRp3t6s3b zduFY6CowJ3#)3I-uInItU6@1BGpkmm>*pGFJnJcC2PwC4txM4>V)wpJCk=}Y{Jekv z5?z4M@Mx5v&*8aK1*a%*S@NIZO@9Tg;t}Rhq&SM>khf53)IZ{)ls}b7mg>%h68Ech z^N(F!P{|AltLJ-k)uf!@V=olfcsn-f@^*Em*1p!}Bd+n9zEsxs^46);$o4ASJ$}O1 z3G7$tbCs>mgZ4kVz=~|?;P}JzfRd5&my&LrQS$ix)vDn%im_OC#WybM1m+MDP@Eui zvlK(v_d*6Aq^tKH{97A;#eMRF4zzz~#{m?+buh8!+Yy+NrxOyh(uewzSwJL%sR=7b z@sYK@HS!0J=#?1_YP#uZ0Zn76wWw1_`pMN&YH|+i!@D-`|dt>sAbN`5q+N%s68Z}WnKHj($ z0^GDKF|JPT_Ge_$GdL@>{WQ#6#2i+nWF~vT_(83fHjIfEX>N9WSdhC+8vCDYheeCS zMK@8L@9VPX(9Xg;ti=KKK!{fuK<3?pw!EXMg$KWEeSi;c^0Y;17OQ5pL3QmyEP)WV z#=@z_34M*`=jWS5H+tJ5>ztf#w`1A$6xiGg7Vq|GvYggw>fKn zfHaq`dO3SNl$_l^Nr(?)FvLd8a3}7rP8;v-8k3+A-)M`=QM%fi)L-^ztI&Axu9mHF2S0&EGEwja6mKJGqLRid#;2GuEs!DKEWep*WQB%f0 zvH>56Yj#(e2D$uf{X)T`tg!uBgz#+)O;WynkEC$#Ay9<)L z^KOjzi6omRiln*Lw-3!G^W20T0ouqfle9n(qY zGb#sNc>ff&Ubz$=g*Q(zD43-GChJGcP6Xm`i8y9Yw&GcxC#!kduv^z%B1S6aN7rOq z7nkh1LqX7`3olc4w-o&GYy>VmPAuoYzX-lgt=T69k_~F^t7Lh9h`qOzYei3C=E6}&Z?{1MiL|Kgr4X^M@ z`Db!Qt^4)o-G@CJrsl7kM&`6V8qkkcp{6$OMcy^7A9}T|V;%9A{Whvyok8sy1OH~M ohmTro(S=}T Date: Sun, 3 Jan 2021 14:21:50 +0100 Subject: [PATCH 057/219] Update README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 139e2b51c..6e5712df9 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,10 @@ Or you can play in “creative mode” in which you can build almost anything in #### Gameplay summary -* Sandbox-style gameplay, no goals (for now) +* Sandbox-style gameplay, no goals * Survive: Fight against hostile monsters and hunger * Mine for ores and other treasures +* Magic: Gain experience and enchant your tools * Use the collected blocks to create great buildings, your imagination is the limit * Collect flowers (and other dye sources) and colorize your world * Find some seeds and start farming @@ -102,7 +103,7 @@ big bugs (such as “missing node” errors or even crashes). The following main features are available: * Tools, weapons -* Armor (unbalanced) +* Armor * Crafting system: 2×2 grid, crafting table (3×3 grid), furnace, including a crafting guide * Chests, large chests, ender chests, shulker boxes * Furnaces, hoppers @@ -117,6 +118,8 @@ The following main features are available: * Redstone circuits (partially) * Minecarts (partial) * Status effects (partial) +* Experience +* Enchanting * Brewing, potions, tipped arrow (partial) * Boats * Fire @@ -142,12 +145,9 @@ The following main features are available: The following features are incomplete: * Generated structures (especially villages) -* NPCs * Some monsters and animals * Redstone-related things * The End -* Enchanting -* Experience * Special minecarts * A couple of non-trivial blocks and items @@ -261,7 +261,6 @@ Various sources. See the respective mod directories for details. ## Info for programmers You find interesting and useful infos in `API.md`. -This project is currently mostly a one-person project. ## Legal information This is a fan game, not developed or endorsed by Mojang AB. From 4c2f3f2b7cea5b132d7485b4d54def1fe72b8e46 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sun, 3 Jan 2021 14:22:19 +0100 Subject: [PATCH 058/219] Fix possible crash in mcl_craftguide --- mods/HELP/mcl_craftguide/init.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 86bd742a9..2474d2070 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -1108,8 +1108,12 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] + local inv_items = data.inv_items + if not inv_items then + inv_items = {} + end - meta:set_string("inv_items", serialize(data.inv_items)) + meta:set_string("inv_items", serialize(inv_items)) end M.register_on_leaveplayer(function(player) From 6cc029a6e4e95ea91509bcc0e2c4751d8d832668 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 14:26:05 +0100 Subject: [PATCH 059/219] Fix #931 --- mods/HELP/mcl_craftguide/init.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 86bd742a9..3fd89fbf7 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -1100,7 +1100,7 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] - + data.inv_items = deserialize(meta:get_string("inv_items")) or {} end) @@ -1108,7 +1108,11 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] - + + if not data or not data.inv_items then + return + end + meta:set_string("inv_items", serialize(data.inv_items)) end From 0fe1707c2f26d108bc3a282b2b40b51e2209d490 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 14:32:31 +0100 Subject: [PATCH 060/219] Remove spaces --- mods/HELP/mcl_craftguide/init.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 3fd89fbf7..d1258a71f 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -1100,7 +1100,7 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] - + data.inv_items = deserialize(meta:get_string("inv_items")) or {} end) @@ -1108,11 +1108,11 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] - + if not data or not data.inv_items then return end - + meta:set_string("inv_items", serialize(data.inv_items)) end From 9e97331bdc3a15a63802f9676d68d3fc1c11b3f0 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 15:10:50 +0100 Subject: [PATCH 061/219] Fix mobs despawning while close to player --- mods/ENTITIES/mcl_mobs/api.lua | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index be7086e8d..da2543645 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -647,9 +647,9 @@ local item_drop = function(self, cooked, looting_level) -- no drops if disabled by setting if not mobs_drop_items then return end - + looting_level = looting_level or 0 - + -- no drops for child mobs (except monster) if (self.child and self.type ~= "monster") then return @@ -938,7 +938,7 @@ local is_at_cliff_or_danger = function(self) return true else local def = minetest.registered_nodes[bnode.name] - if def and def.walkable then + if def and def.walkable then return false end end @@ -951,7 +951,7 @@ end -- copy the 'mob facing cliff_or_danger check' from above, and rework to avoid water local is_at_water_danger = function(self) - + if not self.object:get_luaentity() then return false end @@ -976,7 +976,7 @@ local is_at_water_danger = function(self) return true else local def = minetest.registered_nodes[bnode.name] - if def and def.walkable then + if def and def.walkable then return false end end @@ -2350,10 +2350,10 @@ local do_states = function(self, dtime) lp = minetest.find_nodes_in_area_under_air( {x = s.x - 5, y = s.y - 0.5, z = s.z - 5}, {x = s.x + 5, y = s.y + 1, z = s.z + 5}, - {"group:solid"}) + {"group:solid"}) lp = #lp > 0 and lp[random(#lp)] - + -- did we find land? if lp then @@ -3598,15 +3598,15 @@ local mob_step = function(self, dtime) for n = 1, #close_objs do if close_objs[n]:is_player() then self.lifetimer = 20 - else - if math.random(1,10) <= 3 then - minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) - mcl_burning.extinguish(self.object) - self.object:remove() - return - end + return end end + if math.random(1, 10) <= 3 then + minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) + mcl_burning.extinguish(self.object) + self.object:remove() + return + end else minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) mcl_burning.extinguish(self.object) @@ -3842,7 +3842,7 @@ minetest.register_entity(name, { get_staticdata = function(self) return mob_staticdata(self) end, - + harmed_by_heal = def.harmed_by_heal, }) From 1fda78667f7c17e29b9420c702d398e1f693699a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 15:23:29 +0100 Subject: [PATCH 062/219] Properly merge mcl_craftguide --- mods/HELP/mcl_craftguide/init.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 18989529f..e56b5071d 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -1113,15 +1113,11 @@ if progressive_mode then inv_items = {} end -<<<<<<< HEAD if not data or not data.inv_items then return end - meta:set_string("inv_items", serialize(data.inv_items)) -======= meta:set_string("inv_items", serialize(inv_items)) ->>>>>>> 4c2f3f2b7cea5b132d7485b4d54def1fe72b8e46 end M.register_on_leaveplayer(function(player) From 02777b1f65bfe434d07d2fc44c020acecbfdc67a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 15:25:06 +0100 Subject: [PATCH 063/219] Fix mcl_craftguide completely --- mods/HELP/mcl_craftguide/init.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index e56b5071d..eb98bcce0 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -1108,15 +1108,13 @@ if progressive_mode then local meta = player:get_meta() local name = player:get_player_name() local data = player_data[name] - local inv_items = data.inv_items - if not inv_items then - inv_items = {} - end - if not data or not data.inv_items then + if not data then return end + local inv_items = data.inv_items or {} + meta:set_string("inv_items", serialize(inv_items)) end From ae59f9fd3c363cef9e9afcfe0441ca939ac476e2 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 18:16:12 +0100 Subject: [PATCH 064/219] Inventory + Screwdriver support --- mods/ITEMS/mcl_chests/init.lua | 131 +++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 39 deletions(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index fdfae533a..ff533ef5a 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -1,12 +1,6 @@ local S = minetest.get_translator("mcl_chests") local mod_doc = minetest.get_modpath("doc") -local no_rotate, simple_rotate -if minetest.get_modpath("screwdriver") then - no_rotate = screwdriver.disallow - simple_rotate = screwdriver.rotate_simple -end - -- Chest Entity local entity_animations = {} local entity_animation_speed = 25 @@ -35,7 +29,7 @@ minetest.register_entity("mcl_chests:chest", { pointable = false, physical = false, }, - + set_animation = function(self, animname) local anim = entity_animations[animname] self.object:set_animation(anim.bounds, entity_animation_speed, 0, false) @@ -44,7 +38,7 @@ minetest.register_entity("mcl_chests:chest", { self.sched_time = anim.sched_time end end, - + open = function(self, playername) self.players[playername] = true if not self.is_open then @@ -55,7 +49,7 @@ minetest.register_entity("mcl_chests:chest", { }) end end, - + close = function(self, playername) local playerlist = self.players playerlist[playername] = nil @@ -76,10 +70,18 @@ minetest.register_entity("mcl_chests:chest", { self.node_name = node_name local obj = self.object obj:set_properties({textures = textures}) - obj:set_yaw(minetest.dir_to_yaw(dir)) obj:set_properties({mesh = double and "mcl_chests_double_chest.b3d" or "mcl_chests_chest.b3d"}) + self:set_yaw(dir) end, - + + reinitialize = function(self, node_name) + self.node_name = node_name + end, + + set_yaw = function(self, dir) + self.object:set_yaw(minetest.dir_to_yaw(dir)) + end, + check = function(self) local node_pos, node_name = self.node_pos, self.node_name if not node_pos or not node_name then @@ -97,7 +99,7 @@ minetest.register_entity("mcl_chests:chest", { self:set_animation("closed") self.players = {} end, - + on_step = function(self, dtime) local sched_anim, sched_time = self.sched_anim, self.sched_time if not self:check() then @@ -149,6 +151,20 @@ local function find_or_create_entity(pos, node_name, textures, param2, double) return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, dir, entity_pos) end +local no_rotate, simple_rotate +if minetest.get_modpath("screwdriver") then + no_rotate = screwdriver.disallow + simple_rotate = function(pos, node, user, mode, new_param2) + if screwdriver.rotate_simple(pos, node, user, mode, new_param2) ~= false then + local nodename = node.name + local nodedef = minetest.registered_nodes[nodename] + find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false):set_yaw(minetest.facedir_to_dir(new_param2)) + else + return false + end + end +end + --[[ List of open chests. Key: Player name Value: @@ -291,11 +307,34 @@ local on_chest_blast = function(pos) minetest.remove_node(pos) end -local small_name = "mcl_chests:"..basename +local small_name = "mcl_chests:"..basename.."_small" local small_textures = tiles_table.small local left_name = "mcl_chests:"..basename.."_left" local left_textures = tiles_table.double +minetest.register_node("mcl_chests:"..basename, { + description = desc, + _tt_help = tt_help, + _doc_items_longdesc = longdesc, + _doc_items_usagehelp = usagehelp, + _doc_items_hidden = hidden, + drawtype = "mesh", + mesh = "mcl_chests_chest.obj", + tiles = small_textures, + paramtype = "light", + paramtype2 = "facedir", + stack_max = 64, + sounds = mcl_sounds.node_sound_wood_defaults(), + on_construct = function(pos, node) + local node = minetest.get_node(pos) + node.name = small_name + minetest.set_node(pos, node) + end, + after_place_node = function(pos, placer, itemstack, pointed_thing) + minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name")) + end, +}) + minetest.register_node(small_name, { description = desc, _tt_help = tt_help, @@ -311,7 +350,6 @@ minetest.register_node(small_name, { type = "fixed", fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, - inventory_image = "mcl_chests_normal.png", tiles = {"blank.png"}, _chest_entity_textures = small_textures, paramtype = "light", @@ -346,18 +384,18 @@ minetest.register_node(small_name, { -- BEGIN OF LISTRING WORKAROUND inv:set_size("input", 1) -- END OF LISTRING WORKAROUND - if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..canonical_basename then + if minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "right")).name == "mcl_chests:"..canonical_basename.."_small" then minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_right",param2=param2}) local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_left", param2 = param2 }) create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) - elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename then + elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename.."_small" then minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_left",param2=param2}) create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 }) else - minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename, param2 = param2 }) + minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename.."_small", param2 = param2 }) create_entity(pos, small_name, small_textures, param2, false) end end, @@ -399,7 +437,7 @@ minetest.register_node(small_name, { if name == "" then name = S("Chest") end - + minetest.show_formspec(clicker:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, "size[9,8.75]".. @@ -417,7 +455,7 @@ minetest.register_node(small_name, { if on_rightclick_addendum then on_rightclick_addendum(pos, node, clicker) end - + player_chest_open(clicker, pos, small_name, small_textures, node.param2, false) end, @@ -435,11 +473,11 @@ minetest.register_node(left_name, { drawtype = "nodebox", selection_box = { type = "fixed", - fixed = {-0.4375, -0.5, -0.4375, 1.4375, 0.375, 0.4375}, + fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, }, collision_box = { type = "fixed", - fixed = {-0.4375, -0.5, -0.4375, 1.4375, 0.375, 0.4375}, + fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, }, tiles = {"blank.png"}, _chest_entity_textures = left_textures, @@ -454,7 +492,7 @@ minetest.register_node(left_name, { local param2 = n.param2 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left") if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_right" then - n.name = "mcl_chests:"..canonical_basename + n.name = "mcl_chests:"..canonical_basename.."_small" minetest.swap_node(pos, n) end create_entity(pos, left_name, left_textures, param2, true) @@ -464,7 +502,7 @@ minetest.register_node(left_name, { end, on_destruct = function(pos) local n = minetest.get_node(pos) - if n.name == "mcl_chests:"..basename then + if n.name == small_name then return end @@ -481,8 +519,8 @@ minetest.register_node(left_name, { for pl=1, #players do minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z) end - minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 }) - create_entity(p, "mcl_chests:"..basename, small_textures, param2, false) + minetest.swap_node(p, { name = small_name, param2 = param2 }) + create_entity(p, small_name, small_textures, param2, false) end, after_dig_node = drop_items_chest, on_blast = on_chest_blast, @@ -577,7 +615,7 @@ minetest.register_node(left_name, { if on_rightclick_addendum_left then on_rightclick_addendum_left(pos, node, clicker) end - + player_chest_open(clicker, pos, left_name, left_textures, node.param2, true) end, mesecons = mesecons, @@ -590,11 +628,11 @@ minetest.register_node("mcl_chests:"..basename.."_right", { paramtype2 = "facedir", selection_box = { type = "fixed", - fixed = {0, 0, 0, 0, 0, 0}, + fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, collision_box = { type = "fixed", - fixed = {0, 0, 0, 0, 0, 0}, + fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, drop = drop, @@ -605,7 +643,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { local param2 = n.param2 local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right") if not p or minetest.get_node(p).name ~= "mcl_chests:"..canonical_basename.."_left" then - n.name = "mcl_chests:"..canonical_basename + n.name = "mcl_chests:"..canonical_basename.."_small" minetest.swap_node(pos, n) end end, @@ -614,7 +652,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { end, on_destruct = function(pos) local n = minetest.get_node(pos) - if n.name == "mcl_chests:"..basename then + if n.name == small_name then return end @@ -631,7 +669,8 @@ minetest.register_node("mcl_chests:"..basename.."_right", { for pl=1, #players do minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z) end - minetest.swap_node(p, { name = "mcl_chests:"..basename, param2 = param2 }) + minetest.swap_node(p, { name = small_name, param2 = param2 }) + create_entity(p, small_name, small_textures, param2, false) local meta = minetest.get_meta(pos) end, after_dig_node = drop_items_chest, @@ -728,7 +767,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { if on_rightclick_addendum_right then on_rightclick_addendum_right(pos, node, clicker) end - + player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true) end, mesecons = mesecons, @@ -736,8 +775,8 @@ minetest.register_node("mcl_chests:"..basename.."_right", { }) if mod_doc then - doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_left") - doc.add_entry_alias("nodes", "mcl_chests:"..basename, "nodes", "mcl_chests:"..basename.."_right") + doc.add_entry_alias("nodes", small_name, "nodes", "mcl_chests:"..basename.."_left") + doc.add_entry_alias("nodes", small_name, "nodes", "mcl_chests:"..basename.."_right") end -- END OF register_chest FUNCTION BODY @@ -1182,16 +1221,30 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv end end) +local function select_and_spawn_entity(pos, node) + local node_name = node.name + local node_def = minetest.registered_nodes[node_name] + local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 + create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest) +end + minetest.register_lbm({ label = "Spawn Chest entities", name = "mcl_chests:spawn_chest_entities", nodenames = {"group:chest_entity"}, run_at_every_load = true, + action = select_and_spawn_entity, +}) + +minetest.register_lbm({ + label = "Replace old chest nodes", + name = "mcl_chests:replace_old", + nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on"}, + run_at_every_load = false, action = function(pos, node) - local node_name = node.name - local node_def = minetest.registered_nodes[node_name] - local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 - create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest) + node.name = node.name .. "_small" + minetest.set_node(pos, node) + select_and_spawn_entity(pos, node) end }) @@ -1201,7 +1254,7 @@ minetest.register_lbm({ -- Fixes redstone weirdness. label = "Disable active trapped chests", name = "mcl_chests:reset_trapped_chests", - nodenames = { "mcl_chests:trapped_chest_on", "mcl_chests:trapped_chest_on_left", "mcl_chests:trapped_chest_on_right" }, + nodenames = { "mcl_chests:trapped_chest_on_small", "mcl_chests:trapped_chest_on_left", "mcl_chests:trapped_chest_on_right" }, run_at_every_load = true, action = function(pos, node) minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos)) From 10d6ca4107c3b4cb5320e050251b9065b23d68ef Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 18:22:33 +0100 Subject: [PATCH 065/219] Change max_hear_distance of fire sound and tweak fire entity size --- mods/ENTITIES/mcl_burning/engine.lua | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/mods/ENTITIES/mcl_burning/engine.lua b/mods/ENTITIES/mcl_burning/engine.lua index 02e416db7..266aa791f 100644 --- a/mods/ENTITIES/mcl_burning/engine.lua +++ b/mods/ENTITIES/mcl_burning/engine.lua @@ -53,7 +53,7 @@ end function mcl_burning.get_highest_group_value(obj, groupname) local nodes = mcl_burning.get_touching_nodes(obj, "group:" .. groupname, true) local highest_group_value = 0 - + for _, pos in pairs(nodes) do local node = minetest.get_node(pos) local group_value = minetest.get_item_group(node.name, groupname) @@ -61,7 +61,7 @@ function mcl_burning.get_highest_group_value(obj, groupname) highest_group_value = group_value end end - + return highest_group_value end @@ -72,15 +72,15 @@ function mcl_burning.damage(obj) if luaentity then health = luaentity.health end - + local hp = health or obj:get_hp() - + if hp <= 0 then return end local do_damage = true - + if obj:is_player() then if mcl_potions.player_has_effect(obj, "fire_proof") then do_damage = false @@ -121,33 +121,33 @@ function mcl_burning.set_on_fire(obj, burn_time, damage, reason) local old_burn_time = mcl_burning.get(obj, "float", "burn_time") local max_fire_prot_lvl = 0 - + if obj:is_player() then local inv = obj:get_inventory() - + for i = 2, 5 do local stack = inv:get_stack("armor", i) - + local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection") max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl) end end - + if max_fire_prot_lvl > 0 then burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) end - + if old_burn_time <= burn_time then local sound_id = mcl_burning.get(obj, "int", "sound_id") if sound_id == 0 then sound_id = minetest.sound_play("fire_fire", { object = obj, gain = 0.18, - max_hear_distance = 32, + max_hear_distance = 16, loop = true, }) + 1 end - + local hud_id if obj:is_player() then hud_id = mcl_burning.get(obj, "int", "hud_id") @@ -166,14 +166,14 @@ function mcl_burning.set_on_fire(obj, burn_time, damage, reason) mcl_burning.set(obj, "string", "reason", reason) mcl_burning.set(obj, "int", "hud_id", hud_id) mcl_burning.set(obj, "int", "sound_id", sound_id) - + local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire") local minp, maxp = mcl_burning.get_collisionbox(obj) local obj_size = obj:get_properties().visual_size - local vertical_grow_factor = 1.1 - local horizontal_grow_factor = 0.9 - local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor) + local vertical_grow_factor = 1.2 + local horizontal_grow_factor = 1.1 + local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor) local size = vector.subtract(maxp, minp) size = vector.multiply(size, grow_vector) @@ -190,7 +190,7 @@ function mcl_burning.extinguish(obj) if mcl_burning.is_burning(obj) then local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1 minetest.sound_stop(sound_id) - + if obj:is_player() then local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1 obj:hud_remove(hud_id) @@ -210,7 +210,7 @@ function mcl_burning.catch_fire_tick(obj, dtime) mcl_burning.extinguish(obj) else local set_on_fire_value = mcl_burning.get_highest_group_value(obj, "set_on_fire") - + if set_on_fire_value > 0 then mcl_burning.set_on_fire(obj, set_on_fire_value) end @@ -219,19 +219,19 @@ end function mcl_burning.tick(obj, dtime) local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime - + if burn_time <= 0 then mcl_burning.extinguish(obj) else mcl_burning.set(obj, "float", "burn_time", burn_time) - + local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime - + if damage_timer >= 1 then damage_timer = 0 mcl_burning.damage(obj) end - + mcl_burning.set(obj, "float", "damage_timer", damage_timer) end @@ -255,9 +255,9 @@ function mcl_burning.fire_entity_step(self, dtime) local obj = self.object local parent = obj:get_attach() local do_remove - + self.doing_step = true - + if not parent or not mcl_burning.is_burning(parent) then do_remove = true else @@ -269,15 +269,15 @@ function mcl_burning.fire_entity_step(self, dtime) end end end - + self.doing_step = false - + if do_remove then self.removed = true obj:remove() return end - + local animation_timer = self.animation_timer + dtime if animation_timer >= 0.015 then animation_timer = 0 From 978aa38196a5c29e1991b318d11cef3b65bc9586 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 18:52:24 +0100 Subject: [PATCH 066/219] Trapped chests support --- mods/ITEMS/mcl_chests/init.lua | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index ff533ef5a..d8ef0f188 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -69,8 +69,10 @@ minetest.register_entity("mcl_chests:chest", { self.node_pos = node_pos self.node_name = node_name local obj = self.object - obj:set_properties({textures = textures}) - obj:set_properties({mesh = double and "mcl_chests_double_chest.b3d" or "mcl_chests_chest.b3d"}) + obj:set_properties({ + textures = textures, + mesh = double and "mcl_chests_double_chest.b3d" or "mcl_chests_chest.b3d", + }) self:set_yaw(dir) end, @@ -204,11 +206,13 @@ local trapped_chest_mesecons_rules = mesecon.rules.pplate local chest_update_after_close = function(pos) local node = minetest.get_node(pos) - if node.name == "mcl_chests:trapped_chest_on" then - minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2}) + if node.name == "mcl_chests:trapped_chest_on_small" then + minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_small") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) elseif node.name == "mcl_chests:trapped_chest_on_left" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -220,6 +224,7 @@ local chest_update_after_close = function(pos) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules) end end @@ -831,7 +836,8 @@ register_chest("trapped_chest", rules = trapped_chest_mesecons_rules, }}, function(pos, node, clicker) - minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on", param2 = node.param2}) + minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_small", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_on_small") mesecon.receptor_on(pos, trapped_chest_mesecons_rules) end, function(pos, node, clicker) @@ -839,6 +845,7 @@ register_chest("trapped_chest", meta:set_int("players", 1) minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_on_left") mesecon.receptor_on(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -852,6 +859,7 @@ register_chest("trapped_chest", mesecon.receptor_on(pos, trapped_chest_mesecons_rules) minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2}) + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_on_left") mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules) end ) @@ -870,13 +878,15 @@ register_chest("trapped_chest_on", local function close_if_trapped_chest(pos, player) local node = minetest.get_node(pos) - if node.name == "mcl_chests:trapped_chest_on" then - minetest.swap_node(pos, {name="mcl_chests:trapped_chest", param2 = node.param2}) + if node.name == "mcl_chests:trapped_chest_on_small" then + minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_small") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) player_chest_close(player) elseif node.name == "mcl_chests:trapped_chest_on_left" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) + find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -890,6 +900,7 @@ local function close_if_trapped_chest(pos, player) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules) player_chest_close(player) @@ -1242,9 +1253,14 @@ minetest.register_lbm({ nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on"}, run_at_every_load = false, action = function(pos, node) - node.name = node.name .. "_small" + local node_name = node.name + node.name = node_name .. "_small" minetest.set_node(pos, node) select_and_spawn_entity(pos, node) + if node_name == "mcl_chests:trapped_chest_on" then + minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos)) + chest_update_after_close(pos) + end end }) From 2d9ec679c0552ad0c21bc995742133aeda0b2d5a Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 18:55:41 +0100 Subject: [PATCH 067/219] Fix floating chest entity --- mods/ITEMS/mcl_chests/init.lua | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index d8ef0f188..0a5883f77 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -121,7 +121,7 @@ minetest.register_entity("mcl_chests:chest", { local function get_entity_pos(pos, dir, double) pos = vector.new(pos) - pos.y = pos.y - 0.4375 + pos.y = pos.y - 0.5 if double then local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5)) @@ -476,11 +476,7 @@ minetest.register_node(small_name, { minetest.register_node(left_name, { drawtype = "nodebox", - selection_box = { - type = "fixed", - fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, - }, - collision_box = { + node_box = { type = "fixed", fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, }, @@ -628,17 +624,14 @@ minetest.register_node(left_name, { }) minetest.register_node("mcl_chests:"..basename.."_right", { - drawtype = "airlike", + drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", - selection_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, - }, - collision_box = { + node_box = { type = "fixed", fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, + tiles = {"blank.png"}, groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, drop = drop, is_ground_content = false, From 84cd8195c6dd8b7455e9420da4df187b67421a44 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 19:05:07 +0100 Subject: [PATCH 068/219] Fix invalid migration of small chests --- mods/ITEMS/mcl_chests/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index 0a5883f77..cfeb6a682 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -1248,7 +1248,7 @@ minetest.register_lbm({ action = function(pos, node) local node_name = node.name node.name = node_name .. "_small" - minetest.set_node(pos, node) + minetest.swap_node(pos, node) select_and_spawn_entity(pos, node) if node_name == "mcl_chests:trapped_chest_on" then minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos)) From 0cfb60a82650e4e8bc9e10574457a1c24583cb92 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 19:20:23 +0100 Subject: [PATCH 069/219] Fix #941 --- mods/ITEMS/REDSTONE/mcl_observers/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mcl_observers/init.lua b/mods/ITEMS/REDSTONE/mcl_observers/init.lua index 841ab98b4..759e05996 100644 --- a/mods/ITEMS/REDSTONE/mcl_observers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_observers/init.lua @@ -24,7 +24,7 @@ local rules_up = {{ x = 0, y = -1, z = 0, spread = true }} function mcl_observers.observer_activate(pos) minetest.after(mcl_vars.redstone_tick, function(pos) - node = minetest.get_node(pos) + local node = minetest.get_node(pos) if not node then return end From 41a364b3199456ad239bdb9501cbe7f2e2fd176b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 3 Jan 2021 20:08:53 +0100 Subject: [PATCH 070/219] Crack texture is now displayed --- mods/ITEMS/mcl_chests/init.lua | 14 +++++--------- .../mcl_chests/textures/mcl_chests_blank.png | Bin 0 -> 570 bytes 2 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 mods/ITEMS/mcl_chests/textures/mcl_chests_blank.png diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index cfeb6a682..b4f8e5ae0 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -346,16 +346,12 @@ minetest.register_node(small_name, { _doc_items_longdesc = longdesc, _doc_items_usagehelp = usagehelp, _doc_items_hidden = hidden, - drawtype = "airlike", - selection_box = { + drawtype = "nodebox", + node_box = { type = "fixed", fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, - collision_box = { - type = "fixed", - fixed = {-0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, - }, - tiles = {"blank.png"}, + tiles = {"mcl_chests_blank.png"}, _chest_entity_textures = small_textures, paramtype = "light", paramtype2 = "facedir", @@ -480,7 +476,7 @@ minetest.register_node(left_name, { type = "fixed", fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, }, - tiles = {"blank.png"}, + tiles = {"mcl_chests_blank.png"}, _chest_entity_textures = left_textures, paramtype = "light", paramtype2 = "facedir", @@ -631,7 +627,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { type = "fixed", fixed = {-0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375}, }, - tiles = {"blank.png"}, + tiles = {"mcl_chests_blank.png"}, groups = {handy=1,axey=1, container=6,not_in_creative_inventory=1, material_wood=1,flammable=-1,double_chest=2}, drop = drop, is_ground_content = false, diff --git a/mods/ITEMS/mcl_chests/textures/mcl_chests_blank.png b/mods/ITEMS/mcl_chests/textures/mcl_chests_blank.png new file mode 100644 index 0000000000000000000000000000000000000000..baee128d431db678799b44e683939c65a391d717 GIT binary patch literal 570 zcmV-A0>%A_P)EX>4Tx04R}tkv&MmP!xqvQ;Q-MhjtKg$WWauNELC^DionYs1;guFnQ@8G-*gu zTpR`0f`dPcRRQHpmtPfoUlBkM5rmMCnPtpLQX0PXbx++?cX6KO-}h$?s0E7w0g-r?8KzCVK|H-_ z8=UuvqpU2e#OK80CS8#Dk?V@bZ=6dm3p_JwW;64|QDU*w#Yz{mvZ)bI5yw=bb>jVfs16O*-Uuyz0pQJZB zTI>iI+y*YLJDRcwT zjFl*R-RIqX-E;f5r#-(PFD!D5_eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{000t6L_t(I%VS^|1*2dTi~T%77XSbN literal 0 HcmV?d00001 From abdb76c2a065d8d4391cd6802953bb527c83a010 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 10:09:44 +0100 Subject: [PATCH 071/219] Fix #942 --- mods/ITEMS/mcl_core/functions.lua | 7 +++++-- mods/ITEMS/mcl_core/nodes_base.lua | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/mods/ITEMS/mcl_core/functions.lua b/mods/ITEMS/mcl_core/functions.lua index 0d9a1f601..288828844 100644 --- a/mods/ITEMS/mcl_core/functions.lua +++ b/mods/ITEMS/mcl_core/functions.lua @@ -1450,10 +1450,11 @@ end -- * tiles: Optional custom tiles -- * sounds: Optional custom sounds -- * clear_colorization: Optional. If true, will clear all paramtype2="color" related node def. fields +-- * desc: Item description -- -- The snowable nodes also MUST have _mcl_snowed defined to contain the name -- of the snowed node. -mcl_core.register_snowed_node = function(itemstring_snowed, itemstring_clear, tiles, sounds, clear_colorization) +mcl_core.register_snowed_node = function(itemstring_snowed, itemstring_clear, tiles, sounds, clear_colorization, desc) local def = table.copy(minetest.registered_nodes[itemstring_clear]) local create_doc_alias if def.description then @@ -1462,7 +1463,7 @@ mcl_core.register_snowed_node = function(itemstring_snowed, itemstring_clear, ti create_doc_alias = false end -- Just some group clearing - def.description = nil + def.description = desc def._doc_items_longdesc = nil def._doc_items_usagehelp = nil def._doc_items_create_entry = false @@ -1503,6 +1504,8 @@ mcl_core.register_snowed_node = function(itemstring_snowed, itemstring_clear, ti def.sounds = sounds end + def._mcl_silk_touch_drop = {itemstring_clear} + -- Register stuff minetest.register_node(itemstring_snowed, def) diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index 82ce39e1a..658b39081 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -380,7 +380,7 @@ minetest.register_node("mcl_core:dirt_with_grass", { _mcl_hardness = 0.6, _mcl_silk_touch_drop = true, }) -mcl_core.register_snowed_node("mcl_core:dirt_with_grass_snow", "mcl_core:dirt_with_grass", nil, nil, true) +mcl_core.register_snowed_node("mcl_core:dirt_with_grass_snow", "mcl_core:dirt_with_grass", nil, nil, true, S("Dirt with Snow")) minetest.register_node("mcl_core:grass_path", { tiles = {"mcl_core_grass_path_top.png", "default_dirt.png", "mcl_core_grass_path_side.png"}, @@ -424,7 +424,7 @@ minetest.register_node("mcl_core:mycelium", { _mcl_hardness = 0.6, _mcl_silk_touch_drop = true, }) -mcl_core.register_snowed_node("mcl_core:mycelium_snow", "mcl_core:mycelium") +mcl_core.register_snowed_node("mcl_core:mycelium_snow", "mcl_core:mycelium", nil, nil, false, S("Mycelium with Snow")) minetest.register_node("mcl_core:podzol", { description = S("Podzol"), @@ -441,7 +441,7 @@ minetest.register_node("mcl_core:podzol", { _mcl_hardness = 0.6, _mcl_silk_touch_drop = true, }) -mcl_core.register_snowed_node("mcl_core:podzol_snow", "mcl_core:podzol") +mcl_core.register_snowed_node("mcl_core:podzol_snow", "mcl_core:podzol", nil, nil, false, S("Podzol with Snow")) minetest.register_node("mcl_core:dirt", { description = S("Dirt"), @@ -924,7 +924,7 @@ for i=1,8 do desc = S("Top Snow") tt_help = S("Stackable") longdesc = S("Top snow is a layer of snow. It melts near light sources other than the sun with a light level of 12 or higher.").."\n"..S("Top snow can be stacked and has one of 8 different height levels. At levels 2-8, top snow is collidable. Top snow drops 2-9 snowballs, depending on its height.") - usagehelp = S("This block can only be placed on full solid blocks and on another top snow (which increases its height).") + usagehelp = S("This block can only be placed on full solid blocks and on another top snow (which increases its height).") walkable = false else id = "mcl_core:snow_"..i From c36dc165275800c5cd46278ceeb30d7ef395db62 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 10:15:28 +0100 Subject: [PATCH 072/219] Fix #948 --- mods/ENTITIES/mcl_item_entity/init.lua | 10 +++++----- mods/ITEMS/mcl_core/nodes_base.lua | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index dda2bc91c..946f21997 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -297,9 +297,9 @@ function minetest.handle_node_drops(pos, drops, digger) * true: Drop itself when dug by shears / silk touch tool * table: Drop every itemstring in this table when dug by shears _mcl_silk_touch_drop ]] - + local enchantments = tool and mcl_enchanting.get_enchantments(tool, "silk_touch") - + local silk_touch_drop = false local nodedef = minetest.registered_nodes[dug_node.name] if toolcaps ~= nil and toolcaps.groupcaps and toolcaps.groupcaps.shearsy_dig and nodedef._mcl_shears_drop then @@ -316,7 +316,7 @@ function minetest.handle_node_drops(pos, drops, digger) drops = nodedef._mcl_silk_touch_drop end end - + if tool and nodedef._mcl_fortune_drop and enchantments.fortune then local fortune_level = enchantments.fortune local fortune_drop = nodedef._mcl_fortune_drop @@ -331,7 +331,7 @@ function minetest.handle_node_drops(pos, drops, digger) end else -- Fixed Behavior - local drop = get_fortune_drops(fortune_drops, fortune_level) + local drop = get_fortune_drops(fortune_drop, fortune_level) drops = get_drops(drop, tool:get_name(), dug_node.param2, nodedef.paramtype2) end end @@ -342,7 +342,7 @@ function minetest.handle_node_drops(pos, drops, digger) mcl_experience.throw_experience(pos, experience_amount) end end - + for _,item in ipairs(drops) do local count if type(item) == "string" then diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index 658b39081..01dd2d365 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -503,7 +503,7 @@ minetest.register_node("mcl_core:gravel", { {items = {'mcl_core:gravel'}} } }, - [3] = "mcl_core:flint" + [3] = "mcl_core:flint", }, }) From ce4e86549bf180826546a5bb28c83f1148a7eb57 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 11:26:07 +0100 Subject: [PATCH 073/219] Enderchest Support --- mods/ITEMS/mcl_chests/init.lua | 136 +++++++++++------- ..._chest.b3d => mcl_chests_chest_double.b3d} | Bin mods/ITEMS/mcl_chests/sounds/attributions.txt | 2 + .../sounds/mcl_chests_enderchest_close.ogg | Bin 0 -> 17310 bytes .../sounds/mcl_chests_enderchest_open.ogg | Bin 0 -> 14882 bytes 5 files changed, 88 insertions(+), 50 deletions(-) rename mods/ITEMS/mcl_chests/models/{mcl_chests_double_chest.b3d => mcl_chests_chest_double.b3d} (100%) create mode 100644 mods/ITEMS/mcl_chests/sounds/attributions.txt create mode 100644 mods/ITEMS/mcl_chests/sounds/mcl_chests_enderchest_close.ogg create mode 100644 mods/ITEMS/mcl_chests/sounds/mcl_chests_enderchest_open.ogg diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index b4f8e5ae0..ecd21cba0 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -44,7 +44,7 @@ minetest.register_entity("mcl_chests:chest", { if not self.is_open then self.is_open = true self:set_animation("open") - minetest.sound_play("default_chest_open", { + minetest.sound_play(self.sound_prefix .. "_open", { pos = self.node_pos, }) end @@ -59,19 +59,20 @@ minetest.register_entity("mcl_chests:chest", { end self.is_open = false self:set_animation("close") - minetest.sound_play("default_chest_close", { + minetest.sound_play(self.sound_prefix .. "_close", { pos = self.node_pos, }) end end, - initialize = function(self, node_pos, node_name, textures, dir, double) + initialize = function(self, node_pos, node_name, textures, dir, double, sound_prefix, mesh_prefix) self.node_pos = node_pos self.node_name = node_name + self.sound_prefix = sound_prefix local obj = self.object obj:set_properties({ textures = textures, - mesh = double and "mcl_chests_double_chest.b3d" or "mcl_chests_chest.b3d", + mesh = mesh_prefix .. (double and "_double" or "") .. ".b3d", }) self:set_yaw(dir) end, @@ -138,19 +139,19 @@ local function find_entity(pos) end end -local function create_entity(pos, node_name, textures, param2, double, dir, entity_pos) +local function create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir, entity_pos) dir = dir or minetest.facedir_to_dir(param2) entity_pos = entity_pos or get_entity_pos(pos, dir, double) local obj = minetest.add_entity(entity_pos, "mcl_chests:chest") local luaentity = obj:get_luaentity() - luaentity:initialize(pos, node_name, textures, dir, double) + luaentity:initialize(pos, node_name, textures, dir, double, sound_prefix, mesh_prefix) return luaentity end -local function find_or_create_entity(pos, node_name, textures, param2, double) +local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix) local dir = minetest.facedir_to_dir(param2) local entity_pos = get_entity_pos(pos, dir, double) - return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, dir, entity_pos) + return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir, entity_pos) end local no_rotate, simple_rotate @@ -160,7 +161,7 @@ if minetest.get_modpath("screwdriver") then if screwdriver.rotate_simple(pos, node, user, mode, new_param2) ~= false then local nodename = node.name local nodedef = minetest.registered_nodes[nodename] - find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false):set_yaw(minetest.facedir_to_dir(new_param2)) + find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false, nodedef._chest_entity_sound, nodedef._chest_entity_mesh):set_yaw(minetest.facedir_to_dir(new_param2)) else return false end @@ -174,10 +175,10 @@ Value: Otherwise: nil ]] local open_chests = {} -- To be called if a player opened a chest -local player_chest_open = function(player, pos, node_name, textures, param2, double) +local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh) local name = player:get_player_name() - open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double} - find_or_create_entity(pos, node_name, textures, param2, double):open(name) + open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double, sound = sound, mesh = mesh} + find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh):open(name) end -- Simple protection checking functions @@ -208,11 +209,11 @@ local chest_update_after_close = function(pos) if node.name == "mcl_chests:trapped_chest_on_small" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_small") + find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_small") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) elseif node.name == "mcl_chests:trapped_chest_on_left" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") + find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -224,7 +225,7 @@ local chest_update_after_close = function(pos) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) - find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules) end end @@ -236,7 +237,7 @@ local player_chest_close = function(player) if open_chest == nil then return end - find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double):close(name) + find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh):close(name) chest_update_after_close(open_chest.pos) open_chests[name] = nil @@ -330,6 +331,7 @@ minetest.register_node("mcl_chests:"..basename, { paramtype2 = "facedir", stack_max = 64, sounds = mcl_sounds.node_sound_wood_defaults(), + groups = {deco_block=1}, on_construct = function(pos, node) local node = minetest.get_node(pos) node.name = small_name @@ -353,11 +355,13 @@ minetest.register_node(small_name, { }, tiles = {"mcl_chests_blank.png"}, _chest_entity_textures = small_textures, + _chest_entity_sound = "default_chest", + _chest_entity_mesh = "mcl_chests_chest", paramtype = "light", paramtype2 = "facedir", stack_max = 64, drop = drop, - groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1,chest_entity=1}, + groups = {handy=1,axey=1, container=2, deco_block=1, material_wood=1,flammable=-1,chest_entity=1, not_in_creative_inventory=1}, is_ground_content = false, sounds = mcl_sounds.node_sound_wood_defaults(), on_construct = function(pos) @@ -389,15 +393,15 @@ minetest.register_node(small_name, { minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_right",param2=param2}) local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "right") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_left", param2 = param2 }) - create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) + create_entity(p, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest") elseif minetest.get_node(mcl_util.get_double_container_neighbor_pos(pos, param2, "left")).name == "mcl_chests:"..canonical_basename.."_small" then minetest.swap_node(pos, {name="mcl_chests:"..canonical_basename.."_left",param2=param2}) - create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true) + create_entity(pos, "mcl_chests:"..canonical_basename.."_left", left_textures, param2, true, "default_chest", "mcl_chests_chest") local p = mcl_util.get_double_container_neighbor_pos(pos, param2, "left") minetest.swap_node(p, { name = "mcl_chests:"..canonical_basename.."_right", param2 = param2 }) else minetest.swap_node(pos, { name = "mcl_chests:"..canonical_basename.."_small", param2 = param2 }) - create_entity(pos, small_name, small_textures, param2, false) + create_entity(pos, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest") end end, after_place_node = function(pos, placer, itemstack, pointed_thing) @@ -457,7 +461,7 @@ minetest.register_node(small_name, { on_rightclick_addendum(pos, node, clicker) end - player_chest_open(clicker, pos, small_name, small_textures, node.param2, false) + player_chest_open(clicker, pos, small_name, small_textures, node.param2, false, "default_chest", "mcl_chests_chest") end, on_destruct = function(pos) @@ -478,6 +482,8 @@ minetest.register_node(left_name, { }, tiles = {"mcl_chests_blank.png"}, _chest_entity_textures = left_textures, + _chest_entity_sound = "default_chest", + _chest_entity_mesh = "mcl_chests_chest", paramtype = "light", paramtype2 = "facedir", groups = {handy=1,axey=1, container=5,not_in_creative_inventory=1, material_wood=1,flammable=-1,chest_entity=1,double_chest=1}, @@ -492,7 +498,7 @@ minetest.register_node(left_name, { n.name = "mcl_chests:"..canonical_basename.."_small" minetest.swap_node(pos, n) end - create_entity(pos, left_name, left_textures, param2, true) + create_entity(pos, left_name, left_textures, param2, true, "default_chest", "mcl_chests_chest") end, after_place_node = function(pos, placer, itemstack, pointed_thing) minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name")) @@ -517,7 +523,7 @@ minetest.register_node(left_name, { minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z) end minetest.swap_node(p, { name = small_name, param2 = param2 }) - create_entity(p, small_name, small_textures, param2, false) + create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest") end, after_dig_node = drop_items_chest, on_blast = on_chest_blast, @@ -613,7 +619,7 @@ minetest.register_node(left_name, { on_rightclick_addendum_left(pos, node, clicker) end - player_chest_open(clicker, pos, left_name, left_textures, node.param2, true) + player_chest_open(clicker, pos, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest") end, mesecons = mesecons, on_rotate = no_rotate, @@ -664,7 +670,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { minetest.close_formspec(players[pl]:get_player_name(), "mcl_chests:"..canonical_basename.."_"..p.x.."_"..p.y.."_"..p.z) end minetest.swap_node(p, { name = small_name, param2 = param2 }) - create_entity(p, small_name, small_textures, param2, false) + create_entity(p, small_name, small_textures, param2, false, "default_chest", "mcl_chests_chest") local meta = minetest.get_meta(pos) end, after_dig_node = drop_items_chest, @@ -762,7 +768,7 @@ minetest.register_node("mcl_chests:"..basename.."_right", { on_rightclick_addendum_right(pos, node, clicker) end - player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true) + player_chest_open(clicker, pos_other, left_name, left_textures, node.param2, true, "default_chest", "mcl_chests_chest") end, mesecons = mesecons, on_rotate = no_rotate, @@ -826,7 +832,7 @@ register_chest("trapped_chest", }}, function(pos, node, clicker) minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_small", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_on_small") + find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_on_small") mesecon.receptor_on(pos, trapped_chest_mesecons_rules) end, function(pos, node, clicker) @@ -834,7 +840,7 @@ register_chest("trapped_chest", meta:set_int("players", 1) minetest.swap_node(pos, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_on_left") + find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_on_left") mesecon.receptor_on(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -848,7 +854,7 @@ register_chest("trapped_chest", mesecon.receptor_on(pos, trapped_chest_mesecons_rules) minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_on_left", param2 = node.param2}) - find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_on_left") + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_on_left") mesecon.receptor_on(pos_other, trapped_chest_mesecons_rules) end ) @@ -869,13 +875,13 @@ local function close_if_trapped_chest(pos, player) if node.name == "mcl_chests:trapped_chest_on_small" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false):reinitialize("mcl_chests:trapped_chest_small") + find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_small") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) player_chest_close(player) elseif node.name == "mcl_chests:trapped_chest_on_left" then minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) - find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") + find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos, trapped_chest_mesecons_rules) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left") @@ -889,7 +895,7 @@ local function close_if_trapped_chest(pos, player) local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right") minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2}) - find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true):reinitialize("mcl_chests:trapped_chest_left") + find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest"):reinitialize("mcl_chests:trapped_chest_left") mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules) player_chest_close(player) @@ -930,6 +936,26 @@ minetest.register_craft({ burntime = 15 }) +minetest.register_node("mcl_chests:ender_chest", { + description = S("Ender Chest"), + _tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"), + _doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."), + _doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."), + drawtype = "mesh", + mesh = "mcl_chests_chest.obj", + tiles = {"mcl_chests_ender.png"}, + paramtype = "light", + paramtype2 = "facedir", + stack_max = 64, + groups = {deco_block=1}, + sounds = mcl_sounds.node_sound_stone_defaults(), + on_construct = function(pos, node) + local node = minetest.get_node(pos) + node.name = "mcl_chests:ender_chest_small" + minetest.set_node(pos, node) + end, +}) + local formspec_ender_chest = "size[9,8.75]".. "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]".. "list[current_player;enderchest;0,0.5;9,3;]".. @@ -943,17 +969,26 @@ local formspec_ender_chest = "size[9,8.75]".. "listring[current_player;main]" -minetest.register_node("mcl_chests:ender_chest", { +minetest.register_node("mcl_chests:ender_chest_small", { description = S("Ender Chest"), _tt_help = S("27 interdimensional inventory slots") .. "\n" .. S("Put items inside, retrieve them from any ender chest"), _doc_items_longdesc = S("Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This inventory is the same no matter from which ender chest you access it from. If you put one item into one ender chest, you will find it in all other ender chests. Each player will only see their own items, but not the items of other players."), _doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."), - tiles = {"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png", + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = {-0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375}, + }, + _chest_entity_textures = {"mcl_chests_ender.png"}, + _chest_entity_sound = "mcl_chests_enderchest", + _chest_entity_mesh = "mcl_chests_chest", + tiles = {"mcl_chests_blank.png"}, + --[[{"mcl_chests_ender_chest_top.png", "mcl_chests_ender_chest_bottom.png", "mcl_chests_ender_chest_right.png", "mcl_chests_ender_chest_left.png", - "mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"}, + "mcl_chests_ender_chest_back.png", "mcl_chests_ender_chest_front.png"},]]-- -- Note: The “container” group is missing here because the ender chest does not -- have an inventory on its own - groups = {pickaxey=1, deco_block=1, material_stone=1}, + groups = {pickaxey=1, deco_block=1, material_stone=1, chest_entity=1, not_in_creative_inventory=1}, is_ground_content = false, paramtype = "light", light_source = 7, @@ -963,10 +998,19 @@ minetest.register_node("mcl_chests:ender_chest", { on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("formspec", formspec_ender_chest) + create_entity(pos, "mcl_chests:ender_chest_small", {"mcl_chests_ender.png"}, minetest.get_node(pos).param2, false, "mcl_chests_enderchest", "mcl_chests_chest") + end, + on_rightclick = function(pos, node, clicker) + player_chest_open(clicker, pos, "mcl_chests:ender_chest_small", {"mcl_chests_ender.png"}, minetest.get_node(pos).param2, false, "mcl_chests_enderchest", "mcl_chests_chest") + end, + on_receive_fields = function(pos, formname, fields, sender) + if fields.quit then + player_chest_close(sender) + end end, _mcl_blast_resistance = 3000, _mcl_hardness = 22.5, - _mcl_silk_touch_drop = true, + _mcl_silk_touch_drop = {"mcl_chests:ender_chest"}, on_rotate = simple_rotate, }) @@ -1225,7 +1269,7 @@ local function select_and_spawn_entity(pos, node) local node_name = node.name local node_def = minetest.registered_nodes[node_name] local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 - create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest) + create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh) end minetest.register_lbm({ @@ -1239,7 +1283,7 @@ minetest.register_lbm({ minetest.register_lbm({ label = "Replace old chest nodes", name = "mcl_chests:replace_old", - nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on"}, + nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on", "mcl_chests:ender_chest"}, run_at_every_load = false, action = function(pos, node) local node_name = node.name @@ -1249,6 +1293,9 @@ minetest.register_lbm({ if node_name == "mcl_chests:trapped_chest_on" then minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " ..minetest.pos_to_string(pos)) chest_update_after_close(pos) + elseif node_name == "mcl_chests:ender_chest" then + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec_ender_chest) end end }) @@ -1267,17 +1314,6 @@ minetest.register_lbm({ end, }) --- Legacy -minetest.register_lbm({ - label = "Update ender chest formspecs (0.60.0)", - name = "mcl_chests:update_ender_chest_formspecs_0_60_0", - nodenames = { "mcl_chests:ender_chest" }, - run_at_every_load = false, - action = function(pos, node) - local meta = minetest.get_meta(pos) - meta:set_string("formspec", formspec_ender_chest) - end, -}) minetest.register_lbm({ label = "Update shulker box formspecs (0.60.0)", name = "mcl_chests:update_shulker_box_formspecs_0_60_0", diff --git a/mods/ITEMS/mcl_chests/models/mcl_chests_double_chest.b3d b/mods/ITEMS/mcl_chests/models/mcl_chests_chest_double.b3d similarity index 100% rename from mods/ITEMS/mcl_chests/models/mcl_chests_double_chest.b3d rename to mods/ITEMS/mcl_chests/models/mcl_chests_chest_double.b3d diff --git a/mods/ITEMS/mcl_chests/sounds/attributions.txt b/mods/ITEMS/mcl_chests/sounds/attributions.txt new file mode 100644 index 000000000..2943aecc0 --- /dev/null +++ b/mods/ITEMS/mcl_chests/sounds/attributions.txt @@ -0,0 +1,2 @@ +default_chest_open and default_chest_close - Taken from minetest_game https://github.com/minetest/minetest_game +mcl_chests_enderchest_open and mcl_chests_enderchest_close - https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/resource-packs/1245112-snowsong-the-epic-sound-pack-sound-resource-pack diff --git a/mods/ITEMS/mcl_chests/sounds/mcl_chests_enderchest_close.ogg b/mods/ITEMS/mcl_chests/sounds/mcl_chests_enderchest_close.ogg new file mode 100644 index 0000000000000000000000000000000000000000..7ecf4c98d6c16864eaf0bb1284a22cafa11e4d97 GIT binary patch literal 17310 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 literal 0 HcmV?d00001 From 5939baee526f3d90d108f0090a62e409385c2b93 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 13:02:55 +0100 Subject: [PATCH 074/219] Enchanted books in creative inventory --- mods/HUD/mcl_inventory/creative.lua | 52 ++++++++++++--- mods/HUD/mcl_inventory/depends.txt | 1 + mods/ITEMS/mcl_enchanting/enchantments.lua | 78 +++++++++++++++++++++- 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index a63c85548..b98656551 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -16,6 +16,18 @@ for _, f in pairs(builtin_filter_ids) do inventory_lists[f] = {} end +local function replace_enchanted_books(tbl) + for k, item in ipairs(tbl) do + if item:find("mcl_enchanting:book_enchanted") == 1 then + local _, enchantment, level = item:match("(%a+) ([_%w]+) (%d+)") + level = level and tonumber(level) + if enchantment and level then + tbl[k] = mcl_enchanting.enchant(ItemStack("mcl_enchanting:book_enchanted"), enchantment, level) + end + end + end +end + --[[ Populate all the item tables. We only do this once. Note this mod must be loaded after _mcl_autogroup for this to work, because it required certain groups to be set. ]] @@ -82,11 +94,33 @@ do end end + for ench, def in pairs(mcl_enchanting.enchantments) do + local str = "mcl_enchanting:book_enchanted " .. ench .. " " .. def.max_level + if def.inv_tool_tab then + table.insert(inventory_lists["tools"], str) + end + if def.inv_combat_tab then + table.insert(inventory_lists["combat"], str) + end + table.insert(inventory_lists["all"], str) + end + for _, to_sort in pairs(inventory_lists) do table.sort(to_sort) + replace_enchanted_books(to_sort) end end +local function filter_item(name, description, lang, filter) + local desc + if not lang then + desc = string.lower(description) + else + desc = string.lower(minetest.get_translated_string(lang, description)) + end + return string.find(name, filter) or string.find(desc, filter) +end + local function set_inv_search(filter, player) local playername = player:get_player_name() local inv = minetest.get_inventory({type="detached", name="creative_"..playername}) @@ -94,19 +128,21 @@ local function set_inv_search(filter, player) local lang = minetest.get_player_information(playername).lang_code for name,def in pairs(minetest.registered_items) do if (not def.groups.not_in_creative_inventory or def.groups.not_in_creative_inventory == 0) and def.description and def.description ~= "" then - local name = string.lower(def.name) - local desc - if not lang then - desc = string.lower(def.description) - else - desc = string.lower(minetest.get_translated_string(lang, def.description)) - end - if string.find(name, filter) or string.find(desc, filter) then + if filter_item(string.lower(def.name), def.description, lang, filter) then table.insert(creative_list, name) end end end + for ench, def in pairs(mcl_enchanting.enchantments) do + for i = 1, def.max_level do + local stack = mcl_enchanting.enchant(ItemStack("mcl_enchanting:book_enchanted"), ench, i) + if filter_item("mcl_enchanting:book_enchanted", minetest.strip_colors(stack:get_description()), lang, filter) then + table.insert(creative_list, "mcl_enchanting:book_enchanted " .. ench .. " " .. i) + end + end + end table.sort(creative_list) + replace_enchanted_books(creative_list) inv:set_size("main", #creative_list) inv:set_list("main", creative_list) diff --git a/mods/HUD/mcl_inventory/depends.txt b/mods/HUD/mcl_inventory/depends.txt index cf04c75ef..27231e5df 100644 --- a/mods/HUD/mcl_inventory/depends.txt +++ b/mods/HUD/mcl_inventory/depends.txt @@ -5,3 +5,4 @@ _mcl_autogroup? mcl_armor? mcl_brewing? mcl_potions? +mcl_enchanting diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index d79cb8375..ca0b85404 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -25,6 +25,8 @@ end requires_tool = false, treasure = false, power_range_table = {{1, 41}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented via on_enchant and additions in mobs_mc; Slowness IV part unimplemented @@ -42,6 +44,8 @@ mcl_enchanting.enchantments.bane_of_arthropods = { requires_tool = false, treasure = false, power_range_table = {{5, 25}, {13, 33}, {21, 41}, {29, 49}, {37, 57}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_armor @@ -59,6 +63,8 @@ mcl_enchanting.enchantments.blast_protection = { requires_tool = false, treasure = false, power_range_table = {{5, 13}, {13, 21}, {21, 29}, {29, 37}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- requires missing MineClone2 feature @@ -76,6 +82,8 @@ mcl_enchanting.enchantments.blast_protection = { requires_tool = false, treasure = false, power_range_table = {{25, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_armor @@ -93,6 +101,8 @@ mcl_enchanting.enchantments.curse_of_binding = { requires_tool = false, treasure = true, power_range_table = {{25, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_death_drop @@ -110,6 +120,8 @@ mcl_enchanting.enchantments.curse_of_vanishing = { requires_tool = false, treasure = true, power_range_table = {{25, 50}}, + inv_combat_tab = true, + inv_tool_tab = true, } -- unimplemented @@ -127,6 +139,8 @@ mcl_enchanting.enchantments.curse_of_vanishing = { requires_tool = false, treasure = false, power_range_table = {{10, 25}, {20, 35}, {30, 45}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented via on_enchant @@ -154,6 +168,8 @@ mcl_enchanting.enchantments.efficiency = { requires_tool = false, treasure = false, power_range_table = {{1, 61}, {11, 71}, {21, 81}, {31, 91}, {41, 101}}, + inv_combat_tab = false, + inv_tool_tab = true, } -- implemented in mcl_armor @@ -170,6 +186,8 @@ mcl_enchanting.enchantments.feather_falling = { requires_tool = false, treasure = false, power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_mobs and via register_on_punchplayer callback @@ -187,6 +205,8 @@ mcl_enchanting.enchantments.fire_aspect = { requires_tool = false, treasure = false, power_range_table = {{10, 61}, {30, 71}}, + inv_combat_tab = true, + inv_tool_tab = false, } minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage) @@ -216,6 +236,8 @@ mcl_enchanting.enchantments.fire_protection = { requires_tool = false, treasure = false, power_range_table = {{10, 18}, {18, 26}, {26, 34}, {34, 42}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- requires missing MineClone2 feature @@ -233,6 +255,8 @@ mcl_enchanting.enchantments.fire_protection = { requires_tool = false, treasure = false, power_range_table = {{20, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_item_entity @@ -250,6 +274,8 @@ mcl_enchanting.enchantments.fortune = { requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, + inv_combat_tab = false, + inv_tool_tab = true, } -- implemented via walkover.register_global @@ -267,6 +293,8 @@ mcl_enchanting.enchantments.frost_walker = { requires_tool = false, treasure = true, power_range_table = {{10, 25}, {20, 35}}, + inv_combat_tab = true, + inv_tool_tab = false, } walkover.register_global(function(pos, _, player) @@ -301,6 +329,8 @@ end) requires_tool = false, treasure = false, power_range_table = {{1, 21}, {9, 29}, {17, 37}, {25, 45}, {33, 53}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_bows @@ -318,6 +348,8 @@ mcl_enchanting.enchantments.infinity = { requires_tool = false, treasure = false, power_range_table = {{20, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented via minetest.calculate_knockback @@ -335,6 +367,8 @@ mcl_enchanting.enchantments.knockback = { requires_tool = false, treasure = false, power_range_table = {{5, 61}, {25, 71}}, + inv_combat_tab = true, + inv_tool_tab = false, } local old_calculate_knockback = minetest.calculate_knockback @@ -368,6 +402,8 @@ mcl_enchanting.enchantments.looting = { requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- requires missing MineClone2 feature @@ -385,6 +421,8 @@ mcl_enchanting.enchantments.looting = { requires_tool = false, treasure = false, power_range_table = {{12, 50}, {19, 50}, {26, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_fishing @@ -402,6 +440,8 @@ mcl_enchanting.enchantments.luck_of_the_sea = { requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, + inv_combat_tab = false, + inv_tool_tab = true, } -- implemented in mcl_fishing @@ -419,6 +459,8 @@ mcl_enchanting.enchantments.lure = { requires_tool = false, treasure = false, power_range_table = {{15, 61}, {24, 71}, {33, 81}}, + inv_combat_tab = false, + inv_tool_tab = true, } -- implemented in mcl_experience @@ -436,6 +478,8 @@ mcl_enchanting.enchantments.mending = { requires_tool = true, treasure = true, power_range_table = {{25, 75}}, + inv_combat_tab = true, + inv_tool_tab = true, } -- requires missing MineClone2 feature @@ -453,6 +497,8 @@ mcl_enchanting.enchantments.mending = { requires_tool = false, treasure = false, power_range_table = {{20, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- requires missing MineClone2 feature @@ -470,6 +516,8 @@ mcl_enchanting.enchantments.mending = { requires_tool = false, treasure = false, power_range_table = {{1, 50}, {11, 50}, {21, 50}, {31, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_bows @@ -487,6 +535,8 @@ mcl_enchanting.enchantments.power = { requires_tool = false, treasure = false, power_range_table = {{1, 16}, {11, 26}, {21, 36}, {31, 46}, {41, 56}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_armor @@ -504,6 +554,8 @@ mcl_enchanting.enchantments.projectile_protection = { requires_tool = false, treasure = false, power_range_table = {{1, 16}, {11, 26}, {21, 36}, {31, 46}, {41, 56}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_armor @@ -521,6 +573,8 @@ mcl_enchanting.enchantments.protection = { requires_tool = false, treasure = false, power_range_table = {{1, 12}, {12, 23}, {23, 34}, {34, 45}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented via minetest.calculate_knockback (together with the Knockback enchantment) and mcl_bows @@ -538,6 +592,8 @@ mcl_enchanting.enchantments.punch = { requires_tool = false, treasure = false, power_range_table = {{12, 37}, {32, 57}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- requires missing MineClone2 feature @@ -555,6 +611,8 @@ mcl_enchanting.enchantments.punch = { requires_tool = false, treasure = false, power_range_table = {{12, 50}, {32, 50}, {52, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- unimplemented @@ -572,6 +630,8 @@ mcl_enchanting.enchantments.punch = { requires_tool = false, treasure = false, power_range_table = {{10, 40}, {20, 50}, {30, 60}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- requires missing MineClone2 feature @@ -589,6 +649,8 @@ mcl_enchanting.enchantments.punch = { requires_tool = false, treasure = false, power_range_table = {{17, 50}, {24, 50}, {31, 50}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented via on_enchant @@ -606,6 +668,8 @@ mcl_enchanting.enchantments.sharpness = { requires_tool = false, treasure = false, power_range_table = {{1, 21}, {12, 32}, {23, 43}, {34, 54}, {45, 65}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_item_entity @@ -623,6 +687,8 @@ mcl_enchanting.enchantments.silk_touch = { requires_tool = false, treasure = false, power_range_table = {{15, 61}}, + inv_combat_tab = false, + inv_tool_tab = true, } -- implemented via on_enchant and additions in mobs_mc @@ -640,6 +706,8 @@ mcl_enchanting.enchantments.smite = { requires_tool = false, treasure = false, power_range_table = {{5, 25}, {13, 33}, {21, 41}, {29, 49}, {37, 57}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- implemented in mcl_playerplus @@ -657,6 +725,8 @@ mcl_enchanting.enchantments.soul_speed = { requires_tool = false, treasure = true, power_range_table = {{10, 25}, {20, 35}, {30, 45}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- requires missing MineClone2 feature @@ -674,6 +744,8 @@ mcl_enchanting.enchantments.soul_speed = { requires_tool = false, treasure = false, power_range_table = {{5, 20}, {14, 29}, {23, 38}}, + inv_combat_tab = true, + inv_tool_tab = false, }]]-- -- implemented in mcl_armor @@ -691,6 +763,8 @@ mcl_enchanting.enchantments.thorns = { requires_tool = false, treasure = false, power_range_table = {{10, 61}, {30, 71}, {50, 81}}, + inv_combat_tab = true, + inv_tool_tab = false, } -- for tools & weapons implemented via on_enchant; for bows implemented in mcl_bows; for armor implemented in mcl_armor and mcl_tt; for fishing rods implemented in mcl_fishing @@ -704,7 +778,7 @@ mcl_enchanting.enchantments.unbreaking = { weight = 5, description = S("Increases item durability."), curse = false, - on_enchant = function(itemstack, level) + on_enchant = function(itemstack, level) local tool_capabilities = itemstack:get_tool_capabilities() for group, capability in pairs(tool_capabilities.groupcaps) do capability.uses = capability.uses * (1 + level) @@ -715,4 +789,6 @@ mcl_enchanting.enchantments.unbreaking = { requires_tool = true, treasure = false, power_range_table = {{5, 61}, {13, 71}, {21, 81}}, + inv_combat_tab = true, + inv_tool_tab = true, } From f86cf37ac9663e89cfee7fdc3c5c22376925ec75 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 13:30:30 +0100 Subject: [PATCH 075/219] Fix zombies sometimes just disappearing when dieing to fire --- mods/ENTITIES/mcl_burning/engine.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_burning/engine.lua b/mods/ENTITIES/mcl_burning/engine.lua index 266aa791f..d7728f897 100644 --- a/mods/ENTITIES/mcl_burning/engine.lua +++ b/mods/ENTITIES/mcl_burning/engine.lua @@ -106,9 +106,10 @@ function mcl_burning.damage(obj) damage = 1 end local new_hp = hp - damage - obj:set_hp(new_hp) if health then luaentity.health = new_hp + else + obj:set_hp(new_hp) end end end From 269ebc2718bbfd715855f020db2783ba9f6417f5 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 13:34:57 +0100 Subject: [PATCH 076/219] Fix Silk Touch drop of Top Snow --- mods/ITEMS/mcl_core/nodes_base.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index 01dd2d365..3dedca209 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -1028,7 +1028,7 @@ for i=1,8 do drop = "mcl_throwing:snowball "..(i+1), _mcl_blast_resistance = 0.1, _mcl_hardness = 0.1, - _mcl_silk_touch_drop = true, + _mcl_silk_touch_drop = {"mcl_core:snow " .. (i+1)}, }) end From 507f2d872b9b266718b0d436671ae1e352910d91 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 14:21:28 +0100 Subject: [PATCH 077/219] Fix #949 --- mods/ENTITIES/mcl_boats/init.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index 9d0e45557..dda6321f9 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -59,6 +59,15 @@ local boat = { _animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards } +local function detach_player(player) + player:set_detach() + player:set_properties({visual_size = {x=1, y=1}}) + mcl_player.player_attached[player:get_player_name()] = false + mcl_player.player_set_animation(player, "stand" , 30) +end + +minetest.register_on_respawnplayer(detach_player) + function boat.on_rightclick(self, clicker) if not clicker or not clicker:is_player() then return @@ -66,10 +75,7 @@ function boat.on_rightclick(self, clicker) local name = clicker:get_player_name() if self._driver and clicker == self._driver then self._driver = nil - clicker:set_detach() - clicker:set_properties({visual_size = {x=1, y=1}}) - mcl_player.player_attached[name] = false - mcl_player.player_set_animation(clicker, "stand" , 30) + detach_player(clicker) local pos = clicker:get_pos() pos = {x = pos.x, y = pos.y + 0.2, z = pos.z} clicker:set_pos(pos) From a4d7bd03e183817196742e61ca2f2ae6d72bc87e Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 16:19:14 +0100 Subject: [PATCH 078/219] Change itemframe entity drawtype from wielditem to item --- mods/ITEMS/mcl_itemframes/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_itemframes/init.lua b/mods/ITEMS/mcl_itemframes/init.lua index 40321efe9..238c1144d 100644 --- a/mods/ITEMS/mcl_itemframes/init.lua +++ b/mods/ITEMS/mcl_itemframes/init.lua @@ -4,7 +4,7 @@ local VISUAL_SIZE = 0.3 minetest.register_entity("mcl_itemframes:item",{ hp_max = 1, - visual = "wielditem", + visual = "item", visual_size = {x=VISUAL_SIZE, y=VISUAL_SIZE}, physical = false, pointable = false, From ac54e3caf3709fa9dcc80874a535437ea9b4f5b5 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 16:40:18 +0100 Subject: [PATCH 079/219] Fix despawning once and for all (hopefully) --- mods/ENTITIES/mcl_mobs/api.lua | 57 ++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index da2543645..bb558cd86 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3586,35 +3586,20 @@ local mob_step = function(self, dtime) and ((not self.nametag) or (self.nametag == "")) then self.lifetimer = self.lifetimer - dtime - if self.lifetimer <= 10 then - - -- only despawn away from player - local far_objs = minetest.get_objects_inside_radius(pos, 48) - for n = 1, #far_objs do - - if far_objs[n]:is_player() then - - local close_objs = minetest.get_objects_inside_radius(pos, 16) - for n = 1, #close_objs do - if close_objs[n]:is_player() then - self.lifetimer = 20 - return - end - end - if math.random(1, 10) <= 3 then - minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) - mcl_burning.extinguish(self.object) - self.object:remove() - return - end - else - minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) - mcl_burning.extinguish(self.object) - self.object:remove() - return - end + local despawn = self.despawn_immediately + if not despawn and self.lifetimer <= 10 then + if math.random(10) < 4 then + despawn = true + else + self.lifetimer = 20 end end + if despawn then + minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos)) + mcl_burning.extinguish(self.object) + self.object:remove() + end + self.despawn_immediately = true end end @@ -4556,3 +4541,21 @@ function mobs:alias_mob(old_name, new_name) }) end + +minetest.register_globalstep(function() + for _, player in ipairs(minetest.get_connected_players()) do + local pos = player:get_pos() + for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 24)) do + local lua = obj:get_luaentity() + if lua and lua._cmi_is_mob then + lua.lifetimer = 20 + end + end + for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 32)) do + local lua = obj:get_luaentity() + if lua and lua._cmi_is_mob then + lua.despawn_immediately = false + end + end + end +end) From e26a644df06fbc97d57d11ac209e72ee2e984fbb Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 17:02:36 +0100 Subject: [PATCH 080/219] Fix ender chest migration --- mods/ITEMS/mcl_chests/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index ecd21cba0..6932be9e4 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -1015,9 +1015,9 @@ minetest.register_node("mcl_chests:ender_chest_small", { }) minetest.register_lbm({ - label = "Update ender chest + shulker box formspecs (0.51.0)", + label = "Update shulker box formspecs (0.51.0)", name = "mcl_chests:update_formspecs_0_51_0", - nodenames = { "mcl_chests:ender_chest", "group:shulker_box" }, + nodenames = { "group:shulker_box" }, action = function(pos, node) minetest.registered_nodes[node.name].on_construct(pos) minetest.log("action", "[mcl_chests] Node formspec updated at "..minetest.pos_to_string(pos)) From de810cee81b29de3ac65ecccc0c669f6ecea02fb Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 17:10:07 +0100 Subject: [PATCH 081/219] Fix chest migration in general --- mods/ITEMS/mcl_chests/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index 6932be9e4..bb0206cc4 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -1269,7 +1269,7 @@ local function select_and_spawn_entity(pos, node) local node_name = node.name local node_def = minetest.registered_nodes[node_name] local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 - create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh) + find_or_create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh) end minetest.register_lbm({ @@ -1284,7 +1284,7 @@ minetest.register_lbm({ label = "Replace old chest nodes", name = "mcl_chests:replace_old", nodenames = {"mcl_chests:chest", "mcl_chests:trapped_chest", "mcl_chests:trapped_chest_on", "mcl_chests:ender_chest"}, - run_at_every_load = false, + run_at_every_load = true, action = function(pos, node) local node_name = node.name node.name = node_name .. "_small" From 17ff0c9be5b16c99aa26f8c9b8207a5c74edb609 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 17:14:51 +0100 Subject: [PATCH 082/219] No static_save for chest entities --- mods/ITEMS/mcl_chests/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index bb0206cc4..ebe7a0611 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -28,6 +28,7 @@ minetest.register_entity("mcl_chests:chest", { visual_size = {x = 3, y = 3}, pointable = false, physical = false, + static_save = false, }, set_animation = function(self, animname) From 378dca593e9d60f9a30af8d198a4b0ed7c75163b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 17:16:48 +0100 Subject: [PATCH 083/219] Always create chest entities --- mods/ITEMS/mcl_chests/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index ebe7a0611..e7609bef1 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -1270,7 +1270,7 @@ local function select_and_spawn_entity(pos, node) local node_name = node.name local node_def = minetest.registered_nodes[node_name] local double_chest = minetest.get_item_group(node_name, "double_chest") > 0 - find_or_create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh) + create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest, node_def._chest_entity_sound, node_def._chest_entity_mesh) end minetest.register_lbm({ From aea051fe37a80dcdf51774d30066c0010d2f5d17 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 17:53:49 +0100 Subject: [PATCH 084/219] Proper fire aspect damage --- mods/ITEMS/mcl_enchanting/enchantments.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index d79cb8375..3b9513e2c 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -195,7 +195,7 @@ minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, if wielditem then local fire_aspect_level = mcl_enchanting.get_enchantment(wielditem, "fire_aspect") if fire_aspect_level > 0 then - mcl_burning.set_on_fire(player, 4, fire_aspect_level * 2, hitter:get_player_name()) + mcl_burning.set_on_fire(player, 4, fire_aspect_level * 4 - 1, hitter:get_player_name()) end end end @@ -704,7 +704,7 @@ mcl_enchanting.enchantments.unbreaking = { weight = 5, description = S("Increases item durability."), curse = false, - on_enchant = function(itemstack, level) + on_enchant = function(itemstack, level) local tool_capabilities = itemstack:get_tool_capabilities() for group, capability in pairs(tool_capabilities.groupcaps) do capability.uses = capability.uses * (1 + level) From cfc86bcf3dc273c217b1c26d935e12d5e682348f Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 18:06:31 +0100 Subject: [PATCH 085/219] Fix #952 and other occurences of get_player_velocity --- mods/HUD/mcl_experience/init.lua | 20 ++++++++++---------- mods/ITEMS/mcl_beds/functions.lua | 2 +- mods/PLAYER/mcl_hunger/hunger.lua | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 556f419d4..a443399f8 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -163,7 +163,7 @@ minetest.register_on_joinplayer(function(player) name = player:get_player_name() temp_pool = pool[name] - + hud_manager.add_hud(player,"experience_bar", { hud_elem_type = "image", @@ -175,7 +175,7 @@ minetest.register_on_joinplayer(function(player) alignment = { x = 1, y = 1 }, z_index = 11, }) - + hud_manager.add_hud(player,"xp_level", { hud_elem_type = "text", position = {x=0.5, y=1}, @@ -279,7 +279,7 @@ minetest.register_on_dieplayer(function(player) name = player:get_player_name() temp_pool = pool[name] xp_amount = temp_pool.xp - + temp_pool.xp = 0 temp_pool.level = 0 temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level) @@ -312,11 +312,11 @@ local function xp_step(self, dtime) --get the variables pos = self.object:get_pos() pos2 = collector:get_pos() - - player_velocity = collector:get_player_velocity() - + + player_velocity = collector:get_velocity() + pos2.y = pos2.y + 0.8 - + direction = vector.direction(pos,pos2) distance = vector.distance(pos2,pos) multiplier = distance @@ -413,7 +413,7 @@ local function xp_step(self, dtime) end end - + self.age = self.age + dtime if self.age > max_orb_age then self.object:remove() @@ -598,8 +598,8 @@ function mcl_experience.throw_experience(pos, amount) return false end obj:set_velocity({ - x=math.random(-2,2)*math.random(), - y=math.random(2,5), + x=math.random(-2,2)*math.random(), + y=math.random(2,5), z=math.random(-2,2)*math.random() }) i = i + xp diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index df1a2317b..f7f4ebfc9 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -92,7 +92,7 @@ local function lay_down(player, pos, bed_pos, state, skip) -- FIXME: Velocity threshold should be 0.01 but Minetest 5.3.0 -- sometimes reports incorrect Y speed. A velocity threshold -- of 0.125 still seems good enough. - if vector.length(player:get_player_velocity()) > 0.125 then + if vector.length(player:get_velocity()) > 0.125 then minetest.chat_send_player(name, S("You have to stop moving before going to bed!")) return false end diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index 5a1e34ee3..a70d79eb8 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -156,7 +156,7 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso -- Special item definition field: _food_particles -- If false, force item to not spawn any food partiles when eaten if def._food_particles ~= false and texture and texture ~= "" then - local v = user:get_player_velocity() + local v = user:get_velocity() local minvel = vector.add(v, {x=-1, y=1, z=-1}) local maxvel = vector.add(v, {x=1, y=2, z=1}) From b0b23b753239a2fa242e8607626ad485385a8795 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 20:23:14 +0100 Subject: [PATCH 086/219] Call on_rightclick when clicking a node with fishing rod --- mods/ITEMS/mcl_fishing/init.lua | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index c95dd20e5..d3e5a48be 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -25,21 +25,31 @@ local bobber_ENTITY={ objtype="fishing", } -local fish = function(itemstack, player) +local fish = function(itemstack, player, pointed_thing) + if pointed_thing and pointed_thing.type == "node" then + -- Call on_rightclick if the pointed node defines it + local node = minetest.get_node(pointed_thing.under) + if player and not player:get_player_control().sneak then + if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then + return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, player, itemstack) or itemstack + end + end + end + local pos = player:get_pos() local objs = minetest.get_objects_inside_radius(pos, 125) local num = 0 local ent = nil local noent = true - - + + local durability = 65 local unbreaking = mcl_enchanting.get_enchantment(itemstack, "unbreaking") if unbreaking > 0 then durability = durability * (unbreaking + 1) end - + --Check for bobber if so handle. for n = 1, #objs do ent = objs[n]:get_luaentity() @@ -253,7 +263,7 @@ local bobber_on_step = function(self, dtime) -- wait for random number of ticks. local lure_enchantment = wield and mcl_enchanting.get_enchantment(wield, "lure") or 0 local reduced = lure_enchantment * 5 - self._waittime = math.random(math.max(0, 5 - reduced), 30 - reduced) + self._waittime = math.random(math.max(0, 5 - reduced), 30 - reduced) else if self._time < self._waittime then self._time = self._time + dtime From dc5ff374493d07d0664b7b8f03209cd4b3c6235f Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 4 Jan 2021 20:44:35 +0100 Subject: [PATCH 087/219] Fix #954 --- mods/HUD/mcl_experience/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index a443399f8..da2d11f2a 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -331,7 +331,7 @@ local function xp_step(self, dtime) velocity = vector.multiply(direction,multiplier) goal = velocity acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z) - self.object:add_velocity(vector.add(acceleration,player_velocity)) + self.object:add_velocity(vector.add(acceleration,player_velocity or vector.new(0, 0, 0))) elseif distance < 0.4 then local xp = self._xp local inv = collector:get_inventory() From c2a14e2eaec697d1973619c146bd0818883e4a1a Mon Sep 17 00:00:00 2001 From: kay27 Date: Mon, 4 Jan 2021 21:58:53 +0400 Subject: [PATCH 088/219] Make glyph particles more close to MC and visible only for players in radius 15 --- mods/ITEMS/mcl_enchanting/init.lua | 40 ++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/mods/ITEMS/mcl_enchanting/init.lua b/mods/ITEMS/mcl_enchanting/init.lua index bd7e05ee4..239eb52a8 100644 --- a/mods/ITEMS/mcl_enchanting/init.lua +++ b/mods/ITEMS/mcl_enchanting/init.lua @@ -295,20 +295,38 @@ minetest.register_abm({ chance = 1, nodenames = "mcl_enchanting:table", action = function(pos) + local playernames = {} + for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 15)) do + if obj:is_player() then + table.insert(playernames, obj:get_player_name()) + end + end + if #playernames < 1 then + return + end local absolute, relative = mcl_enchanting.get_bookshelves(pos) for i, ap in ipairs(absolute) do - if math.random(10) == 1 then + if math.random(5) == 1 then local rp = relative[i] - minetest.add_particle({ - pos = ap, - velocity = vector.subtract(vector.new(0, 5, 0), rp), - acceleration = {x = 0, y = -9.81, z = 0}, - expirationtime = 2, - size = 2, - texture = "mcl_enchanting_glyph_" .. math.random(18) .. ".png", - collision_detection = true, - collision_removal = true, - }) + local t = math.random()+1 --time + local d = {x = rp.x, y=rp.y-0.7, z=rp.z} --distance + local v = {x = -math.random()*d.x, y = math.random(), z = -math.random()*d.z} --velocity + local a = {x = 2*(-v.x*t - d.x)/t/t, y = 2*(-v.y*t - d.y)/t/t, z = 2*(-v.z*t - d.z)/t/t} --acceleration + local s = math.random()+0.9 --size + t = t - 0.1 --slightly decrease time to avoid texture overlappings + local tx = "mcl_enchanting_glyph_" .. math.random(18) .. ".png" + for _, name in pairs(playernames) do + minetest.add_particle({ + pos = ap, + velocity = v, + acceleration = a, + expirationtime = t, + size = s, + texture = tx, + collisiondetection = false, + playername = name + }) + end end end end From 4d547665902acbdd597a31f03d1b562c022fb098 Mon Sep 17 00:00:00 2001 From: kay27 Date: Tue, 5 Jan 2021 00:25:58 +0400 Subject: [PATCH 089/219] quick fix of https://git.minetest.land/Wuzzy/MineClone2/issues/954 --- mods/HUD/mcl_experience/init.lua | 2 +- mods/ITEMS/mcl_beds/functions.lua | 2 +- mods/PLAYER/mcl_hunger/hunger.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index da2d11f2a..f9f300069 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -313,7 +313,7 @@ local function xp_step(self, dtime) pos = self.object:get_pos() pos2 = collector:get_pos() - player_velocity = collector:get_velocity() + player_velocity = collector:get_velocity() or collector:get_player_velocity() pos2.y = pos2.y + 0.8 diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index f7f4ebfc9..917b1123d 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -92,7 +92,7 @@ local function lay_down(player, pos, bed_pos, state, skip) -- FIXME: Velocity threshold should be 0.01 but Minetest 5.3.0 -- sometimes reports incorrect Y speed. A velocity threshold -- of 0.125 still seems good enough. - if vector.length(player:get_velocity()) > 0.125 then + if vector.length(player:get_velocity() or player:get_player_velocity()) > 0.125 then minetest.chat_send_player(name, S("You have to stop moving before going to bed!")) return false end diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index a70d79eb8..393bdc9a9 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -156,7 +156,7 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso -- Special item definition field: _food_particles -- If false, force item to not spawn any food partiles when eaten if def._food_particles ~= false and texture and texture ~= "" then - local v = user:get_velocity() + local v = user:get_velocity() or user:get_player_velocity() local minvel = vector.add(v, {x=-1, y=1, z=-1}) local maxvel = vector.add(v, {x=1, y=2, z=1}) From 6fcf1cf09f50311f5571752c0e74d8b178b80b91 Mon Sep 17 00:00:00 2001 From: kay27 Date: Tue, 5 Jan 2021 06:37:06 +0400 Subject: [PATCH 090/219] Make catching XP orbs easier --- mods/HUD/mcl_experience/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index f9f300069..9a8378b0c 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -331,8 +331,8 @@ local function xp_step(self, dtime) velocity = vector.multiply(direction,multiplier) goal = velocity acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z) - self.object:add_velocity(vector.add(acceleration,player_velocity or vector.new(0, 0, 0))) - elseif distance < 0.4 then + self.object:add_velocity(vector.add(acceleration,player_velocity)) + elseif distance < 0.8 then local xp = self._xp local inv = collector:get_inventory() local candidates = { From ebc2ec9f726084af9320a15955a6431c0e5b0f20 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Tue, 5 Jan 2021 12:37:15 +0100 Subject: [PATCH 091/219] Add missing enchanting sound --- .../sounds/mcl_enchanting_enchant.0.ogg | Bin 0 -> 33302 bytes .../sounds/mcl_enchanting_enchant.1.ogg | Bin 0 -> 33154 bytes .../sounds/mcl_enchanting_enchant.2.ogg | Bin 0 -> 31764 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.0.ogg create mode 100644 mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.1.ogg create mode 100644 mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.2.ogg diff --git a/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.0.ogg b/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.0.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a7f357f03530c5da91915290febcdd9f259f1f3b GIT binary patch literal 33302 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 c!x27hV>@WR#<%1 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 literal 0 HcmV?d00001 diff --git a/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.2.ogg b/mods/ITEMS/mcl_enchanting/sounds/mcl_enchanting_enchant.2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4ad66d9a25ea8b60b6a7cb07c3bcd8423ed1c403 GIT binary patch literal 31764 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