From 25d1ee42e77680ffaaba99ab0e99b1b83d7b5f4b Mon Sep 17 00:00:00 2001 From: OgelGames Date: Sun, 2 Nov 2025 14:28:32 +1100 Subject: [PATCH 01/18] refactor inventory handling --- bones.lua | 18 ++++---- death.lua | 36 +++------------ init.lua | 60 +++++++++++++++---------- inventories.lua | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 60 deletions(-) create mode 100644 inventories.lua diff --git a/bones.lua b/bones.lua index 570eed7..8b12e9c 100644 --- a/bones.lua +++ b/bones.lua @@ -43,22 +43,24 @@ core.register_node("bones:bones", { end -- Move as many items as possible to the player's inventory local inv = meta:get_inventory() - local player_inv = player:get_inventory() - for i=1, inv:get_size("main") do - local stack = inv:get_stack("main", i) - if player_inv:room_for_item("main", stack) then - player_inv:add_item("main", stack) - inv:set_stack("main", i, nil) - end + local inv_lists = inv:get_lists() + local empty + if meta:get_string("owner") == name then + empty = bones.restore_all_items(player, inv_lists) + else + empty = bones.add_all_items(player, inv_lists) end -- Remove bones if they have been emptied - if inv:is_empty("main") then + if empty then + local player_inv = player:get_inventory() if player_inv:room_for_item("main", "bones:bones") then player_inv:add_item("main", "bones:bones") else core.add_item(pos, "bones:bones") end core.remove_node(pos) + else + inv:set_lists(inv_lists) end -- Log the bone-taking core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) diff --git a/death.lua b/death.lua index ead87b5..de15615 100644 --- a/death.lua +++ b/death.lua @@ -83,28 +83,6 @@ local function find_replaceable_pos(origin) end end end end -local function get_all_items(player) - local items = {} - local player_inv = player:get_inventory() - for _,inv in pairs(bones.registered_inventories) do - local list - if type(inv) == "function" then - list = inv(player) - else - list = player_inv:get_list(inv) - player_inv:set_list(inv, {}) - end - if list then - for _,stack in pairs(list) do - if stack:get_count() > 0 then - items[#items+1] = stack - end - end - end - end - return items -end - local function drop_item(pos, stack) local obj = core.add_item(pos, stack) if obj then @@ -146,11 +124,11 @@ core.register_on_dieplayer(function(player) return end -- Check if player has items, do nothing if they don't - local items = get_all_items(player) - if #items == 0 then + if not bones.has_any_items(player) then log_death(pos, name, "none") return end + local inv_lists = bones.take_all_items(player) -- Check if it's possible to place bones local bones_pos if bones.mode == "bones" then @@ -158,8 +136,10 @@ core.register_on_dieplayer(function(player) end -- Drop items on the ground if bones.mode == "drop" or not bones_pos then - for _,stack in pairs(items) do - drop_item(pos, stack) + for _,list in ipairs(inv_lists) do + for _,stack in pairs(list) do + drop_item(pos, stack) + end end drop_item(pos, "bones:bones") log_death(pos, name, "drop") @@ -169,9 +149,7 @@ core.register_on_dieplayer(function(player) local param2 = core.dir_to_facedir(player:get_look_dir()) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) - local inv = meta:get_inventory() - inv:set_size("main", #items) - inv:set_list("main", items) + meta:get_inventory():set_lists(inv_lists) if bones.share_time > 0 then meta:set_string("infotext", S("@1's fresh bones", name)) meta:set_string("owner", name) diff --git a/init.lua b/init.lua index 41c9fff..11099df 100644 --- a/init.lua +++ b/init.lua @@ -1,7 +1,6 @@ bones = { redo = true, - registered_inventories = {}, share_time = tonumber(core.settings:get("bones_share_time")) or 1200, waypoint_time = tonumber(core.settings:get("bones_waypoint_time")) or 3600, mode = core.settings:get("bones_mode") or "bones", @@ -22,13 +21,7 @@ end dofile(MP.."/bones.lua") dofile(MP.."/death.lua") - --- Can either be the name of a list in the player's inventory, or a function that returns a list -function bones.register_inventory(inv) - if type(inv) == "string" or type(inv) == "function" then - table.insert(bones.registered_inventories, inv) - end -end +dofile(MP.."/inventories.lua") bones.register_inventory("main") bones.register_inventory("craft") @@ -43,21 +36,42 @@ if core.get_modpath("3d_armor") then break end end - -- Register the inventory function - bones.register_inventory(function(player) - local name, inv = armor:get_valid_player(player, "[on_dieplayer]") - if not name then - return - end - local items = inv:get_list("armor") - for i,stack in pairs(items) do - if stack:get_count() > 0 then - armor:run_callbacks("on_unequip", player, i, stack) + -- Register the armor inventory + bones.register_inventory("armor", { + has_items = function(player) + local name, inv = armor:get_valid_player(player) + if not name then + return + end + return not inv:is_empty("armor") + end, + take_items = function(player) + local name, inv = armor:get_valid_player(player) + if not name then + return + end + local items = inv:get_list("armor") + inv:set_list("armor", {}) + for i, stack in ipairs(items) do + if not stack:is_empty() then + armor:run_callbacks("on_unequip", player, i, stack) + end + end + armor:save_armor_inventory(player) + armor:set_player_armor(player) + return items + end, + restore_items = function(player, items) + local name = armor:get_valid_player(player) + if not name then + return items + end + for i, stack in ipairs(items) do + if not stack:is_empty() then + items[i] = armor:equip(player, stack) + end end + return items end - inv:set_list("armor", {}) - armor:save_armor_inventory(player) - armor:set_player_armor(player) - return items - end) + }) end diff --git a/inventories.lua b/inventories.lua new file mode 100644 index 0000000..3ab222d --- /dev/null +++ b/inventories.lua @@ -0,0 +1,113 @@ + +bones.registered_inventories = {} + +function bones.register_inventory(id, def) + if type(id) ~= "string" then + core.log("error", "[bones] Invalid call to bones.register_inventory.") + return + end + bones.registered_inventories[id] = def or { + has_items = function(player) + return not player:get_inventory():is_empty(id) + end, + take_items = function(player) + local inv = player:get_inventory() + local items = inv:get_list(id) + inv:set_list(id, {}) + return items + end, + restore_items = function(player, items) + local player_inv = player:get_inventory() + if player_inv:is_empty(id) then + player_inv:set_list(id, items) + return {} + end + local list = player_inv:get_list(id) + for i, stack in ipairs(list) do + if items[i] and stack:is_empty() then + list[i], items[i] = items[i], list[i] + end + end + player_inv:set_list(id, list) + for i, stack in ipairs(items) do + if not stack:is_empty() then + items[i] = player_inv:add_item(id, stack) + end + end + return items + end + } +end + +local function is_list_empty(list) + for _,stack in ipairs(list) do + if not stack:is_empty() then + return false + end + end + return true +end + +function bones.has_any_items(player) + for _,inv in pairs(bones.registered_inventories) do + if inv.has_items(player) then + return true + end + end + return false +end + +function bones.take_all_items(player) + local inv_lists = {} + for id, inv in pairs(bones.registered_inventories) do + if inv.has_items(player) then + inv_lists[id] = inv.take_items(player) + end + end + return inv_lists +end + +function bones.restore_all_items(player, inv_lists) + local unknown_lists = {} + for id, list in pairs(inv_lists) do + local inv = bones.registered_inventories[id] + if inv then + inv_lists[id] = inv.restore_items(player, list) + if is_list_empty(inv_lists[id]) then + inv_lists[id] = nil + end + else + unknown_lists[id] = list + end + end + -- Dump items in any unknown lists into the main inventory + if next(unknown_lists) then + local player_inv = player:get_inventory() + for id, list in pairs(unknown_lists) do + for i, stack in ipairs(list) do + if not stack:is_empty() then + list[i] = player_inv:add_item("main", stack) + end + end + if is_list_empty(list) then + inv_lists[id] = nil + end + end + end + return next(inv_lists) == nil +end + +function bones.add_all_items(player, inv_lists) + local player_inv = player:get_inventory() + for id, list in pairs(inv_lists) do + for i, stack in ipairs(list) do + if not stack:is_empty() then + list[i] = player_inv:add_item("main", stack) + end + end + if is_list_empty(list) then + inv_lists[id] = nil + end + end + return next(inv_lists) == nil +end From d67a67b93916730f7a8958d70ea945ee55bae507 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Mon, 3 Nov 2025 16:35:39 +1100 Subject: [PATCH 02/18] add entity mode --- .luacheckrc | 1 + bones.lua | 5 +- death.lua | 26 ++++++++--- entity.lua | 116 +++++++++++++++++++++++++++++++++++++++++++++++ init.lua | 9 +++- settingtypes.txt | 18 +++++--- waypoints.lua | 16 ++----- 7 files changed, 161 insertions(+), 30 deletions(-) create mode 100644 entity.lua diff --git a/.luacheckrc b/.luacheckrc index 372ae0b..7a7173c 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -6,6 +6,7 @@ globals = { } read_globals = { + "ItemStack", "vector", "armor", } diff --git a/bones.lua b/bones.lua index 8b12e9c..f921231 100644 --- a/bones.lua +++ b/bones.lua @@ -1,8 +1,7 @@ local S = core.get_translator("bones") -local function is_owner(pos, name) - local meta = core.get_meta(pos) +local function is_owner(meta, name) if meta:get_int("time") >= bones.share_time then return true end @@ -38,7 +37,7 @@ core.register_node("bones:bones", { on_punch = function(pos, node, player) local meta = core.get_meta(pos) local name = player:get_player_name() - if meta:get_string("infotext") == "" or not is_owner(pos, name) then + if meta:get_string("infotext") == "" or not is_owner(meta, name) then return end -- Move as many items as possible to the player's inventory diff --git a/death.lua b/death.lua index de15615..24bdc0b 100644 --- a/death.lua +++ b/death.lua @@ -128,14 +128,27 @@ core.register_on_dieplayer(function(player) log_death(pos, name, "none") return end + local param2 = core.dir_to_facedir(player:get_look_dir()) local inv_lists = bones.take_all_items(player) -- Check if it's possible to place bones local bones_pos if bones.mode == "bones" then bones_pos = find_replaceable_pos(pos) end + -- Create bones entity + if bones.mode == "entity" or not bones_pos then + local entity = core.add_entity(pos, "bones:entity") + if entity then + entity:get_luaentity():create(param2, name, inv_lists) + log_death(pos, name, "bones") + if bones.waypoints then + bones.add_waypoint(pos, player) + end + return + end + end -- Drop items on the ground - if bones.mode == "drop" or not bones_pos then + if bones.drop_items and (bones.mode == "drop" or not bones_pos) then for _,list in ipairs(inv_lists) do for _,stack in pairs(list) do drop_item(pos, stack) @@ -144,22 +157,23 @@ core.register_on_dieplayer(function(player) drop_item(pos, "bones:bones") log_death(pos, name, "drop") return + elseif not bones_pos then + log_death(pos, name, "keep") + return end - -- Place bones - local param2 = core.dir_to_facedir(player:get_look_dir()) + -- Place bones node core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) meta:get_inventory():set_lists(inv_lists) + meta:set_string("owner", name) if bones.share_time > 0 then meta:set_string("infotext", S("@1's fresh bones", name)) - meta:set_string("owner", name) core.get_node_timer(bones_pos):start(10) else meta:set_string("infotext", S("@1's bones", name)) end log_death(bones_pos, name, "bones") - -- Add waypoint - if bones.waypoint_time > 0 then + if bones.waypoints then bones.add_waypoint(bones_pos, player) end end) diff --git a/entity.lua b/entity.lua new file mode 100644 index 0000000..11fa72f --- /dev/null +++ b/entity.lua @@ -0,0 +1,116 @@ + +local S = core.get_translator("bones") + +local function is_owner(self, name) + if self.timer >= bones.share_time then + return true + end + if self.owner == "" or self.owner == name or core.check_player_privs(name, "protection_bypass") then + return true + end + return false +end + +local function to_strings(inventory) + for _,list in pairs(inventory) do + for i, stack in ipairs(list) do + list[i] = stack:to_string() + end + end + return inventory +end + +local function to_stacks(inventory) + for _,list in pairs(inventory) do + for i, str in ipairs(list) do + list[i] = ItemStack(str) + end + end + return inventory +end + +core.register_entity("bones:entity", { + initial_properties = { + visual = "cube", + textures = { + "bones_top.png^[transform2", + "bones_bottom.png", + "bones_side.png", + "bones_side.png^[transform4", + "bones_rear.png", + "bones_front.png" + }, + collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, + physical = true, + collide_with_objects = true, + }, + rotation = 0, + inventory = {}, + timer = 0, + create = function(self, rotation, owner, inventory) + self.rotation = rotation + self.owner = owner + self.inventory = inventory + local infotext + if bones.share_time > 0 then + infotext = S("@1's fresh bones", owner) + else + infotext = S("@1's bones", owner) + end + self.object:set_properties({ + infotext = infotext, + }) + end, + get_staticdata = function(self) + local data = { + rotation = self.rotation, + owner = self.owner, + inventory = to_strings(self.inventory), + timer = self.timer, + } + return core.serialize(data) + end, + on_activate = function(self, staticdata) + local data = core.deserialize(staticdata) + if data and data.rotation and data.owner and data.inventory then + self:create(data.rotation, data.owner, to_stacks(data.inventory)) + self.timer = data.timer + end + end, + on_punch = function(self, player) + local name = player:get_player_name() + if not is_owner(self, name) then + return true + end + local pos = self.object:get_pos() + -- Move as many items as possible to the player's inventory + local empty + if self.owner == name then + empty = bones.restore_all_items(player, self.inventory) + else + empty = bones.add_all_items(player, self.inventory) + end + -- Remove bones if they have been emptied + if empty then + local player_inv = player:get_inventory() + if player_inv:room_for_item("main", "bones:bones") then + player_inv:add_item("main", "bones:bones") + else + core.add_item(pos, "bones:bones") + end + self.object:remove() + end + -- Log the bone-taking + core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) + return true + end, + on_deactivate = bones.waypoints and function(self, removal) + if not removal then + return + end + local player = core.get_player_by_name(self.owner) + if player then + bones.remove_waypoint(self.object:get_pos(), player) + end + end or nil, +}) diff --git a/init.lua b/init.lua index 11099df..98e77cb 100644 --- a/init.lua +++ b/init.lua @@ -1,15 +1,19 @@ bones = { redo = true, - share_time = tonumber(core.settings:get("bones_share_time")) or 1200, + share_time = tonumber(core.settings:get("bones_share_time")) or 1800, waypoint_time = tonumber(core.settings:get("bones_waypoint_time")) or 3600, mode = core.settings:get("bones_mode") or "bones", position_message = core.settings:get_bool("bones_position_message", true), + drop_items = core.settings:get_bool("bones_drop_items", true), } -if bones.mode ~= "bones" and bones.mode ~= "drop" and bones.mode ~= "keep" then +if bones.mode ~= "bones" and bones.mode ~= "entity" and bones.mode ~= "drop" and bones.mode ~= "keep" then bones.mode = "bones" end +if bones.mode == "drop" and not bones.drop_items then + bones.mode = "keep" +end bones.waypoints = bones.waypoint_time > 0 @@ -20,6 +24,7 @@ if bones.waypoints then end dofile(MP.."/bones.lua") +dofile(MP.."/entity.lua") dofile(MP.."/death.lua") dofile(MP.."/inventories.lua") diff --git a/settingtypes.txt b/settingtypes.txt index c8bf90a..8e6c831 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -1,16 +1,22 @@ # Sets the behaviour of bones when a player dies. -# - bones: Store items in a bone node where possible, otherwise drop items. +# - bones: Store items in a bone node where possible. +# - entity: Store items in an bone entity. # - drop: Drop items on the ground. # - keep: Player keeps items. -bones_mode (Bones mode) enum bones bones,drop,keep +# Each mode falls back to the lower mode if it fails. +bones_mode (Bones mode) enum bones bones,entity,drop,keep # The time in seconds after which the bones of a dead player can be looted by everyone. -# Setting this to 0 will disable sharing of bones completely. -bones_share_time (Bones share time) int 1200 0 +# Setting this to 0 will disable sharing of bones. +bones_share_time (Bones share time) int 1800 0 # Inform player of location and condition of new bones. -bones_position_message (Bones message) bool true +bones_position_message (Bones location message) bool true # The time in seconds that bone waypoints will be shown. # Setting this to 0 will disable waypoints. -bones_waypoint_time (Bones waypoint time) int 3600 0 +bones_waypoint_time (Waypoint lifetime) int 3600 0 + +# Sets whether items are dropped if bones cannot be placed. +# If false all items will be kept. +bones_drop_items (Drop items) bool true diff --git a/waypoints.lua b/waypoints.lua index ca843cd..2e135d2 100644 --- a/waypoints.lua +++ b/waypoints.lua @@ -22,7 +22,7 @@ end function bones.add_waypoint(pos, player) local meta = player:get_meta() local waypoints = core.deserialize(meta:get_string("bone_waypoints")) or {} - local pos_string = core.pos_to_string(pos) + local pos_string = core.pos_to_string(pos):gsub("-0", "0") if not waypoints[pos_string] then waypoints[pos_string] = { pos = pos, @@ -36,7 +36,7 @@ end function bones.remove_waypoint(pos, player) local meta = player:get_meta() local waypoints = core.deserialize(meta:get_string("bone_waypoints")) or {} - local pos_string = core.pos_to_string(pos) + local pos_string = core.pos_to_string(pos):gsub("-0", "0") if waypoints[pos_string] then player:hud_remove(waypoints[pos_string].id) waypoints[pos_string] = nil @@ -46,21 +46,11 @@ end core.register_on_joinplayer(function(player) local meta = player:get_meta() - local name = player:get_player_name() local waypoints = core.deserialize(meta:get_string("bone_waypoints")) or {} local current_time = os.time() for pos_string, waypoint in pairs(waypoints) do if current_time < waypoint.expiry then - local node = core.get_node_or_nil(waypoint.pos) - if not node then - core.load_area(waypoint.pos) - node = core.get_node(waypoint.pos) - end - if node.name == "bones:bones" and core.get_meta(waypoint.pos):get_string("owner") == name then - add_to_hud(player, waypoint) - else - waypoints[pos_string] = nil - end + add_to_hud(player, waypoint) else waypoints[pos_string] = nil end From bde0d2823a5d40ba764a81776e01673daf8c40ae Mon Sep 17 00:00:00 2001 From: OgelGames Date: Tue, 4 Nov 2025 14:05:43 +1100 Subject: [PATCH 03/18] entity timer and replace node --- bones.lua | 12 +++++++++--- death.lua | 8 ++++++-- entity.lua | 35 ++++++++++++++++++++++++++++------- init.lua | 4 +--- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/bones.lua b/bones.lua index f921231..deb4424 100644 --- a/bones.lua +++ b/bones.lua @@ -57,7 +57,13 @@ core.register_node("bones:bones", { else core.add_item(pos, "bones:bones") end - core.remove_node(pos) + local replaced = core.deserialize(meta:get_string("replaced")) + if replaced then + core.set_node(pos, replaced) + else + core.remove_node(pos) + end + core.sound_play("bones_dug", {gain = 0.8}, true) else inv:set_lists(inv_lists) end @@ -74,14 +80,14 @@ core.register_node("bones:bones", { meta:set_string("infotext", S("@1's old bones", meta:get_string("owner"))) end end, - on_destruct = bones.waypoints and function(pos) + on_destruct = bones.waypoint_time > 0 and function(pos) local name = core.get_meta(pos):get_string("owner") local player = core.get_player_by_name(name) if player then bones.remove_waypoint(pos, player) end end or nil, - on_movenode = bones.waypoints and function(from_pos, to_pos) + on_movenode = bones.waypoint_time > 0 and function(from_pos, to_pos) local meta = core.get_meta(to_pos) local owner = meta:get_string("owner") -- Ignore empty (decorative) bones. diff --git a/death.lua b/death.lua index 24bdc0b..5e1339b 100644 --- a/death.lua +++ b/death.lua @@ -141,7 +141,7 @@ core.register_on_dieplayer(function(player) if entity then entity:get_luaentity():create(param2, name, inv_lists) log_death(pos, name, "bones") - if bones.waypoints then + if bones.waypoint_time > 0 then bones.add_waypoint(pos, player) end return @@ -162,10 +162,14 @@ core.register_on_dieplayer(function(player) return end -- Place bones node + local replaced = core.get_node(pos) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) meta:get_inventory():set_lists(inv_lists) meta:set_string("owner", name) + if replaced.name ~= "air" then + meta:set_string("replaced", core.serialize(replaced)) + end if bones.share_time > 0 then meta:set_string("infotext", S("@1's fresh bones", name)) core.get_node_timer(bones_pos):start(10) @@ -173,7 +177,7 @@ core.register_on_dieplayer(function(player) meta:set_string("infotext", S("@1's bones", name)) end log_death(bones_pos, name, "bones") - if bones.waypoints then + if bones.waypoint_time > 0 then bones.add_waypoint(bones_pos, player) end end) diff --git a/entity.lua b/entity.lua index 11fa72f..49a5d81 100644 --- a/entity.lua +++ b/entity.lua @@ -43,17 +43,23 @@ core.register_entity("bones:entity", { collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, physical = true, collide_with_objects = true, + damage_texture_modifier = "", }, rotation = 0, inventory = {}, + owner = "", timer = 0, create = function(self, rotation, owner, inventory) - self.rotation = rotation - self.owner = owner - self.inventory = inventory + self.rotation = rotation or 0 + self.owner = owner or "" + self.inventory = inventory or {} local infotext if bones.share_time > 0 then - infotext = S("@1's fresh bones", owner) + if self.timer >= bones.share_time then + infotext = S("@1's old bones", owner) + else + infotext = S("@1's fresh bones", owner) + end else infotext = S("@1's bones", owner) end @@ -71,10 +77,11 @@ core.register_entity("bones:entity", { return core.serialize(data) end, on_activate = function(self, staticdata) + self.object:set_armor_groups({immortal = 1}) local data = core.deserialize(staticdata) if data and data.rotation and data.owner and data.inventory then - self:create(data.rotation, data.owner, to_stacks(data.inventory)) self.timer = data.timer + self:create(data.rotation, data.owner, to_stacks(data.inventory)) end end, on_punch = function(self, player) @@ -82,8 +89,8 @@ core.register_entity("bones:entity", { if not is_owner(self, name) then return true end - local pos = self.object:get_pos() -- Move as many items as possible to the player's inventory + local pos = self.object:get_pos() local empty if self.owner == name then empty = bones.restore_all_items(player, self.inventory) @@ -99,12 +106,26 @@ core.register_entity("bones:entity", { core.add_item(pos, "bones:bones") end self.object:remove() + core.sound_play("bones_dug", {gain = 0.8}, true) + else + core.sound_play("bones_dig", {gain = 0.9}, true) end -- Log the bone-taking core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) return true end, - on_deactivate = bones.waypoints and function(self, removal) + on_step = bones.share_time > 0 and function(self, dtime) + if self.timer >= bones.share_time then + return + end + self.timer = self.timer + dtime + if self.timer >= bones.share_time then + self.object:set_properties({ + infotext = S("@1's old bones", self.owner), + }) + end + end or nil, + on_deactivate = bones.waypoint_time > 0 and function(self, removal) if not removal then return end diff --git a/init.lua b/init.lua index 98e77cb..83134e1 100644 --- a/init.lua +++ b/init.lua @@ -15,11 +15,9 @@ if bones.mode == "drop" and not bones.drop_items then bones.mode = "keep" end -bones.waypoints = bones.waypoint_time > 0 - local MP = core.get_modpath("bones") -if bones.waypoints then +if bones.waypoint_time > 0 then dofile(MP.."/waypoints.lua") end From b40eb48ba8fea5fcb4c6a7ff29f0e367f5ea8dd8 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Tue, 4 Nov 2025 14:23:57 +1100 Subject: [PATCH 04/18] respect soulbound armor --- init.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/init.lua b/init.lua index 83134e1..e1264e2 100644 --- a/init.lua +++ b/init.lua @@ -46,7 +46,12 @@ if core.get_modpath("3d_armor") then if not name then return end - return not inv:is_empty("armor") + for i, stack in ipairs(inv:get_list("armor")) do + if not stack:is_empty() and core.get_item_group(stack:get_name(), "soulbound") == 0 then + return true + end + end + return false end, take_items = function(player) local name, inv = armor:get_valid_player(player) @@ -57,7 +62,12 @@ if core.get_modpath("3d_armor") then inv:set_list("armor", {}) for i, stack in ipairs(items) do if not stack:is_empty() then - armor:run_callbacks("on_unequip", player, i, stack) + if core.get_item_group(stack:get_name(), "soulbound") ~= 0 then + inv:set_stack("armor", i, stack) + items[i] = ItemStack() + else + armor:run_callbacks("on_unequip", player, i, stack) + end end end armor:save_armor_inventory(player) From 558faf2aa59cac8f02b521667140d0046a26a64a Mon Sep 17 00:00:00 2001 From: OgelGames Date: Tue, 4 Nov 2025 14:34:38 +1100 Subject: [PATCH 05/18] only restore items on the first punch --- bones.lua | 3 ++- entity.lua | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bones.lua b/bones.lua index deb4424..706888d 100644 --- a/bones.lua +++ b/bones.lua @@ -44,7 +44,7 @@ core.register_node("bones:bones", { local inv = meta:get_inventory() local inv_lists = inv:get_lists() local empty - if meta:get_string("owner") == name then + if meta:get_string("owner") == name and not meta:get("punched") then empty = bones.restore_all_items(player, inv_lists) else empty = bones.add_all_items(player, inv_lists) @@ -65,6 +65,7 @@ core.register_node("bones:bones", { end core.sound_play("bones_dug", {gain = 0.8}, true) else + meta:set_int("punched", 1) inv:set_lists(inv_lists) end -- Log the bone-taking diff --git a/entity.lua b/entity.lua index 49a5d81..c685000 100644 --- a/entity.lua +++ b/entity.lua @@ -73,6 +73,7 @@ core.register_entity("bones:entity", { owner = self.owner, inventory = to_strings(self.inventory), timer = self.timer, + punched = self.punched, } return core.serialize(data) end, @@ -81,6 +82,7 @@ core.register_entity("bones:entity", { local data = core.deserialize(staticdata) if data and data.rotation and data.owner and data.inventory then self.timer = data.timer + self.punched = data.punched self:create(data.rotation, data.owner, to_stacks(data.inventory)) end end, @@ -92,7 +94,7 @@ core.register_entity("bones:entity", { -- Move as many items as possible to the player's inventory local pos = self.object:get_pos() local empty - if self.owner == name then + if self.owner == name and not self.punched then empty = bones.restore_all_items(player, self.inventory) else empty = bones.add_all_items(player, self.inventory) @@ -108,6 +110,7 @@ core.register_entity("bones:entity", { self.object:remove() core.sound_play("bones_dug", {gain = 0.8}, true) else + self.punched = 1 core.sound_play("bones_dig", {gain = 0.9}, true) end -- Log the bone-taking From a7855591c8d9895f9aa7719a40206c88a996eddc Mon Sep 17 00:00:00 2001 From: OgelGames Date: Tue, 4 Nov 2025 15:43:34 +1100 Subject: [PATCH 06/18] multi-inventory can_dig and more chat messages --- bones.lua | 25 +++++++++++++++++++++---- entity.lua | 9 ++++++++- locale/bones.de.tr | 2 ++ locale/bones.eo.tr | 2 ++ locale/bones.es.tr | 2 ++ locale/bones.fr.tr | 2 ++ locale/bones.id.tr | 2 ++ locale/bones.it.tr | 2 ++ locale/bones.ja.tr | 2 ++ locale/bones.jbo.tr | 2 ++ locale/bones.ms.tr | 2 ++ locale/bones.pt_BR.tr | 2 ++ locale/bones.ru.tr | 2 ++ locale/bones.sk.tr | 2 ++ locale/bones.sv.tr | 2 ++ locale/bones.uk.tr | 2 ++ locale/bones.zh_CN.tr | 2 ++ locale/bones.zh_TW.tr | 2 ++ locale/template.txt | 2 ++ 19 files changed, 63 insertions(+), 5 deletions(-) diff --git a/bones.lua b/bones.lua index 706888d..0f91d4d 100644 --- a/bones.lua +++ b/bones.lua @@ -31,13 +31,24 @@ core.register_node("bones:bones", { dug = {name = "bones_dug", gain = 0.8}, place = {name = "bones_place", gain = 0.7}, }, - can_dig = function(pos, player) - return core.get_meta(pos):get_inventory():is_empty("main") + can_dig = function(pos) + local inv = core.get_meta(pos):get_inventory() + for name in pairs(inv:get_lists()) do + if not inv:is_empty(name) then + return false + end + end + return true end, on_punch = function(pos, node, player) local meta = core.get_meta(pos) + if meta:get_string("infotext") == "" then + return + end + local owner = meta:get_string("owner") local name = player:get_player_name() - if meta:get_string("infotext") == "" or not is_owner(meta, name) then + if not is_owner(meta, name) then + core.chat_send_player(name, S("These bones belong to @1.", owner)) return end -- Move as many items as possible to the player's inventory @@ -50,6 +61,7 @@ core.register_node("bones:bones", { empty = bones.add_all_items(player, inv_lists) end -- Remove bones if they have been emptied + local pos_string = core.pos_to_string(pos) if empty then local player_inv = player:get_inventory() if player_inv:room_for_item("main", "bones:bones") then @@ -64,12 +76,17 @@ core.register_node("bones:bones", { core.remove_node(pos) end core.sound_play("bones_dug", {gain = 0.8}, true) + if owner ~= name then + core.chat_send_player(name, S("You collected @1's bones at @2.", owner, pos_string)) + end + core.log("action", name.." removes bones at "..pos_string) + return else meta:set_int("punched", 1) inv:set_lists(inv_lists) end -- Log the bone-taking - core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) + core.log("action", name.." takes items from bones at "..pos_string) end, on_timer = function(pos, elapsed) local meta = core.get_meta(pos) diff --git a/entity.lua b/entity.lua index c685000..d0f6291 100644 --- a/entity.lua +++ b/entity.lua @@ -89,6 +89,7 @@ core.register_entity("bones:entity", { on_punch = function(self, player) local name = player:get_player_name() if not is_owner(self, name) then + core.chat_send_player(name, S("These bones belong to @1.", self.owner)) return true end -- Move as many items as possible to the player's inventory @@ -100,6 +101,7 @@ core.register_entity("bones:entity", { empty = bones.add_all_items(player, self.inventory) end -- Remove bones if they have been emptied + local pos_string = core.pos_to_string(pos) if empty then local player_inv = player:get_inventory() if player_inv:room_for_item("main", "bones:bones") then @@ -109,12 +111,17 @@ core.register_entity("bones:entity", { end self.object:remove() core.sound_play("bones_dug", {gain = 0.8}, true) + if self.owner ~= name then + core.chat_send_player(name, S("You collected @1's bones at @2.", self.owner, pos_string)) + end + core.log("action", name.." removes bones at "..pos_string) + return else self.punched = 1 core.sound_play("bones_dig", {gain = 0.9}, true) end -- Log the bone-taking - core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) + core.log("action", name.." takes items from bones at "..pos_string) return true end, on_step = bones.share_time > 0 and function(self, dtime) diff --git a/locale/bones.de.tr b/locale/bones.de.tr index a7b9179..968f163 100644 --- a/locale/bones.de.tr +++ b/locale/bones.de.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.=Du bist gestorben. Knochen wurden in @1 platz @1's old bones=Alte Knochen von @1 @1's fresh bones=Frische Knochen von @1 @1's bones=Knochen von @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.eo.tr b/locale/bones.eo.tr index f2644fe..c0f024e 100644 --- a/locale/bones.eo.tr +++ b/locale/bones.eo.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=La malnova ostoj de @1 @1's fresh bones=La nova ostoj de @1 @1's bones=La ostoj de @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.es.tr b/locale/bones.es.tr index 8db3470..635e9e0 100644 --- a/locale/bones.es.tr +++ b/locale/bones.es.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.=Moriste. Se colocaron tus huesos en @1. @1's old bones=Huesos viejos de @1 @1's fresh bones=Huesos recientes de @1 @1's bones=Huesos de @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.fr.tr b/locale/bones.fr.tr index c537683..6b4e3c4 100644 --- a/locale/bones.fr.tr +++ b/locale/bones.fr.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.=Tu es mort. Tes os ont été placés à @1. @1's old bones=Vieux os de @1 @1's fresh bones=Os frais de @1 @1's bones=Os de @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.id.tr b/locale/bones.id.tr index 6e7c0b4..aa89b5f 100644 --- a/locale/bones.id.tr +++ b/locale/bones.id.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=Tulang lama @1 @1's fresh bones=Tulang segar @1 @1's bones=Tulang @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.it.tr b/locale/bones.it.tr index 60948a6..3d00fe5 100644 --- a/locale/bones.it.tr +++ b/locale/bones.it.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.=Sei morto a @1. Furono poste le ossa. @1's old bones=Ossa vecchie di @1 @1's fresh bones=Ossa fresche di @1 @1's bones=Ossa di @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.ja.tr b/locale/bones.ja.tr index 3855b0a..940c6e7 100644 --- a/locale/bones.ja.tr +++ b/locale/bones.ja.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=@1の古い骨 @1's fresh bones=@1の新鮮な骨 @1's bones=@1の骨 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.jbo.tr b/locale/bones.jbo.tr index d76daa0..9bb7fcd 100644 --- a/locale/bones.jbo.tr +++ b/locale/bones.jbo.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=.i ti tolci'o ke bongu gunma po'a la'o zo'i.@1.zo'i @1's fresh bones=.i ti cnino ke bongu gunma po'a la'o zo'i.@1.zo'i @1's bones=.i ti bongu gunma po'a la'o zo'i.@1.zo'i +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.ms.tr b/locale/bones.ms.tr index 6e7c0b4..aa89b5f 100644 --- a/locale/bones.ms.tr +++ b/locale/bones.ms.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=Tulang lama @1 @1's fresh bones=Tulang segar @1 @1's bones=Tulang @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.pt_BR.tr b/locale/bones.pt_BR.tr index 9a1d9e8..f028e38 100644 --- a/locale/bones.pt_BR.tr +++ b/locale/bones.pt_BR.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.=Morreste em @1. Ossos foram colocados. @1's old bones=Ossos antigos de @1 @1's fresh bones=Ossos recentes de @1 @1's bones=Ossos de @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.ru.tr b/locale/bones.ru.tr index 7ffc0da..6a9a7aa 100644 --- a/locale/bones.ru.tr +++ b/locale/bones.ru.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=Старые кости @1 @1's fresh bones=новые кости @1 @1's bones=кости @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.sk.tr b/locale/bones.sk.tr index 1685674..47fe8d9 100644 --- a/locale/bones.sk.tr +++ b/locale/bones.sk.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=Staré kosti hráča @1 @1's fresh bones=Čerstvé kosti hráča @1 @1's bones=Kosti hráča @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.sv.tr b/locale/bones.sv.tr index efa23e3..82bcbbb 100644 --- a/locale/bones.sv.tr +++ b/locale/bones.sv.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=@1s Gamla ben @1's fresh bones=@1s färska ben @1's bones=@1s ben +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.uk.tr b/locale/bones.uk.tr index d651772..d93b524 100644 --- a/locale/bones.uk.tr +++ b/locale/bones.uk.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=старі кістки @1 @1's fresh bones=нові кістки @1 @1's bones=кістки @1 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.zh_CN.tr b/locale/bones.zh_CN.tr index aadf02d..e84dc53 100644 --- a/locale/bones.zh_CN.tr +++ b/locale/bones.zh_CN.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=@1的旧骨骸 @1's fresh bones=@1的新鲜骨骸 @1's bones=@1的骨骸 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/bones.zh_TW.tr b/locale/bones.zh_TW.tr index 30567a1..5da3c88 100644 --- a/locale/bones.zh_TW.tr +++ b/locale/bones.zh_TW.tr @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones=@1的舊骨骸 @1's fresh bones=@1的新鮮骨骸 @1's bones=@1的骨骸 +These bones belong to @1.= +You collected @1's bones at @2.= diff --git a/locale/template.txt b/locale/template.txt index 1cca4cd..7d78dad 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -6,3 +6,5 @@ You died at @1. Bones were placed.= @1's old bones= @1's fresh bones= @1's bones= +These bones belong to @1.= +You collected @1's bones at @2.= From 3c0572ef4d4596330b5111911c61563372215474 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Tue, 4 Nov 2025 17:17:11 +1100 Subject: [PATCH 07/18] fallback mode setting instead of drop items --- death.lua | 22 +++++++++++++--------- init.lua | 8 ++++++-- settingtypes.txt | 12 +++++++----- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/death.lua b/death.lua index 5e1339b..7129b0c 100644 --- a/death.lua +++ b/death.lua @@ -91,7 +91,9 @@ local function drop_item(pos, stack) y = math.random( 1, 20) / 10, z = math.random(-10, 10) / 10, }) + return true end + return false end local function log_death(pos, name, action) @@ -136,7 +138,7 @@ core.register_on_dieplayer(function(player) bones_pos = find_replaceable_pos(pos) end -- Create bones entity - if bones.mode == "entity" or not bones_pos then + if bones.mode == "entity" or (not bones_pos and bones.fallback == "entity") then local entity = core.add_entity(pos, "bones:entity") if entity then entity:get_luaentity():create(param2, name, inv_lists) @@ -148,16 +150,18 @@ core.register_on_dieplayer(function(player) end end -- Drop items on the ground - if bones.drop_items and (bones.mode == "drop" or not bones_pos) then - for _,list in ipairs(inv_lists) do - for _,stack in pairs(list) do - drop_item(pos, stack) + if bones.mode == "drop" or (not bones_pos and bones.fallback == "drop") then + if drop_item(pos, "bones:bones") then + for _,list in ipairs(inv_lists) do + for _,stack in pairs(list) do + drop_item(pos, stack) + end end + log_death(pos, name, "drop") + return end - drop_item(pos, "bones:bones") - log_death(pos, name, "drop") - return - elseif not bones_pos then + end + if not bones_pos then log_death(pos, name, "keep") return end diff --git a/init.lua b/init.lua index e1264e2..9649adf 100644 --- a/init.lua +++ b/init.lua @@ -4,14 +4,18 @@ bones = { share_time = tonumber(core.settings:get("bones_share_time")) or 1800, waypoint_time = tonumber(core.settings:get("bones_waypoint_time")) or 3600, mode = core.settings:get("bones_mode") or "bones", + fallback = core.settings:get("bones_fallback_mode") or "entity", position_message = core.settings:get_bool("bones_position_message", true), - drop_items = core.settings:get_bool("bones_drop_items", true), } +-- Some checks for bad settings if bones.mode ~= "bones" and bones.mode ~= "entity" and bones.mode ~= "drop" and bones.mode ~= "keep" then bones.mode = "bones" end -if bones.mode == "drop" and not bones.drop_items then +if bones.fallback ~= "entity" and bones.fallback ~= "drop" and bones.fallback ~= "keep" then + bones.fallback = "entity" +end +if bones.mode == "drop" and bones.fallback == "drop" then bones.mode = "keep" end diff --git a/settingtypes.txt b/settingtypes.txt index 8e6c831..77503c2 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -3,9 +3,15 @@ # - entity: Store items in an bone entity. # - drop: Drop items on the ground. # - keep: Player keeps items. -# Each mode falls back to the lower mode if it fails. bones_mode (Bones mode) enum bones bones,entity,drop,keep +# Sets the fallback behaviour for when bones can't be created. +# - entity: Store items in an bone entity. +# - drop: Drop items on the ground. +# - keep: Player keeps items. +Both 'entity' and 'drop' modes fallback to 'keep'. +bones_fallback_mode (Bones mode) enum entity entity,drop,keep + # The time in seconds after which the bones of a dead player can be looted by everyone. # Setting this to 0 will disable sharing of bones. bones_share_time (Bones share time) int 1800 0 @@ -16,7 +22,3 @@ bones_position_message (Bones location message) bool true # The time in seconds that bone waypoints will be shown. # Setting this to 0 will disable waypoints. bones_waypoint_time (Waypoint lifetime) int 3600 0 - -# Sets whether items are dropped if bones cannot be placed. -# If false all items will be kept. -bones_drop_items (Drop items) bool true From 8290646fdcadedd97485586f6ee05d85b9430238 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Wed, 5 Nov 2025 02:36:02 +1100 Subject: [PATCH 08/18] Update README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d128a5b..1e8a4ac 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,12 @@ A redo of the bones mod from Minetest Game. ## Improvements from MTG - **Dynamically sized inventory** - To fit ALL your items. -- **Better bone generation** - Always finds somewhere to place bones, 99% guaranteed. -- **Waypoints** - Bones are marked by a waypoint for some time. -- **New textures** - More detailed and... well, that's about it. +- **Inventory restoration** - Items return to the original places when collecting bones. +- **Better bone generation** - Always finds somewhere to place bones, 98% guaranteed. +- **No lost items** - Bones have multiple fallback modes and if they all fail you keep your items. +- **Waypoints** - Bones are marked by a waypoint for a configurable amount of time. +- **Game independent** - Doesn't depend on the `default` mod. +- **New textures** - More detailed and... better. - **Custom sounds** - Because bones are not made of gravel. ## Dependencies From 5061fb4e08c010b85b74ed22ac4aae001b815c5c Mon Sep 17 00:00:00 2001 From: OgelGames Date: Wed, 5 Nov 2025 12:35:37 +1100 Subject: [PATCH 09/18] reduce code duplication --- bones.lua | 55 ++++++++-------------------------------- death.lua | 22 +++++++++------- entity.lua | 70 +++++++-------------------------------------------- functions.lua | 60 +++++++++++++++++++++++++++++++++++++++++++ init.lua | 8 ++++-- 5 files changed, 98 insertions(+), 117 deletions(-) create mode 100644 functions.lua diff --git a/bones.lua b/bones.lua index 0f91d4d..0d03649 100644 --- a/bones.lua +++ b/bones.lua @@ -1,17 +1,6 @@ local S = core.get_translator("bones") -local function is_owner(meta, name) - if meta:get_int("time") >= bones.share_time then - return true - end - local owner = meta:get_string("owner") - if owner == "" or owner == name or core.check_player_privs(name, "protection_bypass") then - return true - end - return false -end - core.register_node("bones:bones", { description = S("Bones"), tiles = { @@ -42,51 +31,28 @@ core.register_node("bones:bones", { end, on_punch = function(pos, node, player) local meta = core.get_meta(pos) - if meta:get_string("infotext") == "" then - return + local owner = meta:get("owner") + if not owner then + return -- Ignore empty (decorative) bones. end - local owner = meta:get_string("owner") local name = player:get_player_name() - if not is_owner(meta, name) then + if not bones.can_collect(name, owner, meta:get_int("time")) then core.chat_send_player(name, S("These bones belong to @1.", owner)) return end - -- Move as many items as possible to the player's inventory local inv = meta:get_inventory() - local inv_lists = inv:get_lists() - local empty - if meta:get_string("owner") == name and not meta:get("punched") then - empty = bones.restore_all_items(player, inv_lists) - else - empty = bones.add_all_items(player, inv_lists) - end - -- Remove bones if they have been emptied - local pos_string = core.pos_to_string(pos) - if empty then - local player_inv = player:get_inventory() - if player_inv:room_for_item("main", "bones:bones") then - player_inv:add_item("main", "bones:bones") - else - core.add_item(pos, "bones:bones") - end + local items = inv:get_lists() + if bones.collect_bones(pos, player, owner, items, meta:get("punched")) then local replaced = core.deserialize(meta:get_string("replaced")) if replaced then core.set_node(pos, replaced) else core.remove_node(pos) end - core.sound_play("bones_dug", {gain = 0.8}, true) - if owner ~= name then - core.chat_send_player(name, S("You collected @1's bones at @2.", owner, pos_string)) - end - core.log("action", name.." removes bones at "..pos_string) - return else meta:set_int("punched", 1) - inv:set_lists(inv_lists) + inv:set_lists(items) end - -- Log the bone-taking - core.log("action", name.." takes items from bones at "..pos_string) end, on_timer = function(pos, elapsed) local meta = core.get_meta(pos) @@ -107,10 +73,9 @@ core.register_node("bones:bones", { end or nil, on_movenode = bones.waypoint_time > 0 and function(from_pos, to_pos) local meta = core.get_meta(to_pos) - local owner = meta:get_string("owner") - -- Ignore empty (decorative) bones. - if owner == "" then - return + local owner = meta:get("owner") + if not owner then + return -- Ignore empty (decorative) bones. end local player = core.get_player_by_name(owner) if player then diff --git a/death.lua b/death.lua index 7129b0c..a8975ce 100644 --- a/death.lua +++ b/death.lua @@ -99,9 +99,11 @@ end local function log_death(pos, name, action) local pos_str = core.pos_to_string(pos) if action == "keep" or action == "none" then - core.log("action", name.." dies at "..pos_str..". No bones placed.") + core.log("action", name.." dies at "..pos_str..".") elseif action == "bones" then core.log("action", name.." dies at "..pos_str..". Bones placed.") + elseif action == "bones" then + core.log("action", name.." dies at "..pos_str..". Entity created.") elseif action == "drop" then core.log("action", name.." dies at "..pos_str..". Inventory dropped.") end @@ -110,7 +112,7 @@ local function log_death(pos, name, action) end if action == "keep" or action == "none" then core.chat_send_player(name, S("You died at @1.", pos_str)) - elseif action == "bones" then + elseif action == "bones" or action == "entity" then core.chat_send_player(name, S("You died at @1. Bones were placed.", pos_str)) elseif action == "drop" then core.chat_send_player(name, S("You died at @1. Your inventory was dropped.", pos_str)) @@ -131,7 +133,7 @@ core.register_on_dieplayer(function(player) return end local param2 = core.dir_to_facedir(player:get_look_dir()) - local inv_lists = bones.take_all_items(player) + local items = bones.take_all_items(player) -- Check if it's possible to place bones local bones_pos if bones.mode == "bones" then @@ -141,8 +143,8 @@ core.register_on_dieplayer(function(player) if bones.mode == "entity" or (not bones_pos and bones.fallback == "entity") then local entity = core.add_entity(pos, "bones:entity") if entity then - entity:get_luaentity():create(param2, name, inv_lists) - log_death(pos, name, "bones") + entity:get_luaentity():create(param2, name, items) + log_death(pos, name, "entity") if bones.waypoint_time > 0 then bones.add_waypoint(pos, player) end @@ -152,9 +154,11 @@ core.register_on_dieplayer(function(player) -- Drop items on the ground if bones.mode == "drop" or (not bones_pos and bones.fallback == "drop") then if drop_item(pos, "bones:bones") then - for _,list in ipairs(inv_lists) do - for _,stack in pairs(list) do - drop_item(pos, stack) + for _,list in pairs(items) do + for _,stack in ipairs(list) do + if not stack:is_empty() then + drop_item(pos, stack) + end end end log_death(pos, name, "drop") @@ -169,7 +173,7 @@ core.register_on_dieplayer(function(player) local replaced = core.get_node(pos) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) - meta:get_inventory():set_lists(inv_lists) + meta:get_inventory():set_lists(items) meta:set_string("owner", name) if replaced.name ~= "air" then meta:set_string("replaced", core.serialize(replaced)) diff --git a/entity.lua b/entity.lua index d0f6291..cdc08f8 100644 --- a/entity.lua +++ b/entity.lua @@ -1,34 +1,6 @@ local S = core.get_translator("bones") -local function is_owner(self, name) - if self.timer >= bones.share_time then - return true - end - if self.owner == "" or self.owner == name or core.check_player_privs(name, "protection_bypass") then - return true - end - return false -end - -local function to_strings(inventory) - for _,list in pairs(inventory) do - for i, stack in ipairs(list) do - list[i] = stack:to_string() - end - end - return inventory -end - -local function to_stacks(inventory) - for _,list in pairs(inventory) do - for i, str in ipairs(list) do - list[i] = ItemStack(str) - end - end - return inventory -end - core.register_entity("bones:entity", { initial_properties = { visual = "cube", @@ -46,13 +18,13 @@ core.register_entity("bones:entity", { damage_texture_modifier = "", }, rotation = 0, - inventory = {}, + items = {}, owner = "", timer = 0, - create = function(self, rotation, owner, inventory) + create = function(self, rotation, owner, items) self.rotation = rotation or 0 self.owner = owner or "" - self.inventory = inventory or {} + self.items = items or {} local infotext if bones.share_time > 0 then if self.timer >= bones.share_time then @@ -71,7 +43,7 @@ core.register_entity("bones:entity", { local data = { rotation = self.rotation, owner = self.owner, - inventory = to_strings(self.inventory), + items = bones.stacks_to_strings(self.items), timer = self.timer, punched = self.punched, } @@ -80,48 +52,24 @@ core.register_entity("bones:entity", { on_activate = function(self, staticdata) self.object:set_armor_groups({immortal = 1}) local data = core.deserialize(staticdata) - if data and data.rotation and data.owner and data.inventory then + if data and data.rotation and data.owner and data.items then self.timer = data.timer self.punched = data.punched - self:create(data.rotation, data.owner, to_stacks(data.inventory)) + self:create(data.rotation, data.owner, bones.strings_to_stacks(data.items)) end end, on_punch = function(self, player) local name = player:get_player_name() - if not is_owner(self, name) then + if not bones.can_collect(name, self.owner, self.timer) then core.chat_send_player(name, S("These bones belong to @1.", self.owner)) - return true + return end - -- Move as many items as possible to the player's inventory local pos = self.object:get_pos() - local empty - if self.owner == name and not self.punched then - empty = bones.restore_all_items(player, self.inventory) - else - empty = bones.add_all_items(player, self.inventory) - end - -- Remove bones if they have been emptied - local pos_string = core.pos_to_string(pos) - if empty then - local player_inv = player:get_inventory() - if player_inv:room_for_item("main", "bones:bones") then - player_inv:add_item("main", "bones:bones") - else - core.add_item(pos, "bones:bones") - end + if bones.collect_bones(pos, player, self.owner, self.items, self.punched) then self.object:remove() - core.sound_play("bones_dug", {gain = 0.8}, true) - if self.owner ~= name then - core.chat_send_player(name, S("You collected @1's bones at @2.", self.owner, pos_string)) - end - core.log("action", name.." removes bones at "..pos_string) - return else self.punched = 1 - core.sound_play("bones_dig", {gain = 0.9}, true) end - -- Log the bone-taking - core.log("action", name.." takes items from bones at "..pos_string) return true end, on_step = bones.share_time > 0 and function(self, dtime) diff --git a/functions.lua b/functions.lua new file mode 100644 index 0000000..0539ad1 --- /dev/null +++ b/functions.lua @@ -0,0 +1,60 @@ + +local S = core.get_translator("bones") + +function bones.stacks_to_strings(inventory) + for _,list in pairs(inventory) do + for i, stack in ipairs(list) do + list[i] = stack:to_string() + end + end + return inventory +end + +function bones.strings_to_stacks(inventory) + for _,list in pairs(inventory) do + for i, str in ipairs(list) do + list[i] = ItemStack(str) + end + end + return inventory +end + +function bones.can_collect(name, owner, elapsed) + if bones.share_time > 0 and elapsed >= bones.share_time then + return true + end + if owner == "" or owner == name or core.check_player_privs(name, "protection_bypass") then + return true + end + return false +end + +function bones.collect_bones(pos, player, owner, items, punched) + -- Move as many items as possible to the player's inventory + local name = player:get_player_name() + local empty + if owner == name and not punched then + empty = bones.restore_all_items(player, items) + else + empty = bones.add_all_items(player, items) + end + -- Remove bones if they have been emptied + local pos_string = core.pos_to_string(pos) + if empty then + local player_inv = player:get_inventory() + if player_inv:room_for_item("main", "bones:bones") then + player_inv:add_item("main", "bones:bones") + else + core.add_item(pos, "bones:bones") + end + if owner ~= name then + core.chat_send_player(name, S("You collected @1's bones at @2.", owner, pos_string)) + end + core.log("action", name.." removes bones at "..pos_string) + core.sound_play("bones_dug", {gain = 0.8}, true) + return true + end + -- Log the bone-taking + core.log("action", name.." takes items from bones at "..pos_string) + return false +end diff --git a/init.lua b/init.lua index 9649adf..073200f 100644 --- a/init.lua +++ b/init.lua @@ -15,8 +15,11 @@ end if bones.fallback ~= "entity" and bones.fallback ~= "drop" and bones.fallback ~= "keep" then bones.fallback = "entity" end -if bones.mode == "drop" and bones.fallback == "drop" then - bones.mode = "keep" +if bones.mode == "entity" and bones.fallback ~= "keep" then + bones.fallback = "drop" +end +if bones.mode == "drop" then + bones.fallback = "keep" end local MP = core.get_modpath("bones") @@ -29,6 +32,7 @@ dofile(MP.."/bones.lua") dofile(MP.."/entity.lua") dofile(MP.."/death.lua") dofile(MP.."/inventories.lua") +dofile(MP.."/functions.lua") bones.register_inventory("main") bones.register_inventory("craft") From 4e177ae058ebd3e044e29bea6d89e15553ac7e33 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Wed, 5 Nov 2025 16:20:24 +1100 Subject: [PATCH 10/18] bone pickup and fix rotation --- README.md | 1 + bones.lua | 38 ++++++++++++++++++++++++++++++-------- death.lua | 7 ++++--- entity.lua | 39 +++++++++++++++++++++++++++++++++------ functions.lua | 32 +++++++++++++++++++++++++++++++- init.lua | 1 + locale/bones.de.tr | 2 ++ locale/bones.eo.tr | 2 ++ locale/bones.es.tr | 2 ++ locale/bones.fr.tr | 2 ++ locale/bones.id.tr | 2 ++ locale/bones.it.tr | 2 ++ locale/bones.ja.tr | 2 ++ locale/bones.jbo.tr | 2 ++ locale/bones.ms.tr | 2 ++ locale/bones.pt_BR.tr | 2 ++ locale/bones.ru.tr | 2 ++ locale/bones.sk.tr | 2 ++ locale/bones.sv.tr | 2 ++ locale/bones.uk.tr | 2 ++ locale/bones.zh_CN.tr | 2 ++ locale/bones.zh_TW.tr | 2 ++ locale/template.txt | 2 ++ settingtypes.txt | 3 +++ 24 files changed, 137 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1e8a4ac..585cdc3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ A redo of the bones mod from Minetest Game. - **Inventory restoration** - Items return to the original places when collecting bones. - **Better bone generation** - Always finds somewhere to place bones, 98% guaranteed. - **No lost items** - Bones have multiple fallback modes and if they all fail you keep your items. +- **Bone pickup** - Bones can be picked up with items inside using sneak+punch. - **Waypoints** - Bones are marked by a waypoint for a configurable amount of time. - **Game independent** - Doesn't depend on the `default` mod. - **New textures** - More detailed and... better. diff --git a/bones.lua b/bones.lua index 0d03649..c9cc2de 100644 --- a/bones.lua +++ b/bones.lua @@ -1,6 +1,15 @@ local S = core.get_translator("bones") +local function remove_node(pos, meta) + local replaced = core.deserialize(meta:get_string("replaced")) + if replaced then + core.set_node(pos, replaced) + else + core.remove_node(pos) + end +end + core.register_node("bones:bones", { description = S("Bones"), tiles = { @@ -31,24 +40,25 @@ core.register_node("bones:bones", { end, on_punch = function(pos, node, player) local meta = core.get_meta(pos) - local owner = meta:get("owner") - if not owner then + if not meta:get("infotext") then return -- Ignore empty (decorative) bones. end local name = player:get_player_name() + local owner = meta:get_string("owner") if not bones.can_collect(name, owner, meta:get_int("time")) then core.chat_send_player(name, S("These bones belong to @1.", owner)) return end local inv = meta:get_inventory() local items = inv:get_lists() - if bones.collect_bones(pos, player, owner, items, meta:get("punched")) then - local replaced = core.deserialize(meta:get_string("replaced")) - if replaced then - core.set_node(pos, replaced) - else - core.remove_node(pos) + if bones.pickup and player:get_player_control().sneak then + if bones.pickup_bones(pos, items, owner, player) then + remove_node(pos, meta) end + return + end + if bones.collect_bones(pos, player, owner, items, meta:get("punched")) then + remove_node(pos, meta) else meta:set_int("punched", 1) inv:set_lists(items) @@ -64,6 +74,18 @@ core.register_node("bones:bones", { meta:set_string("infotext", S("@1's old bones", meta:get_string("owner"))) end end, + after_place_node = bones.pickup and function(pos, player, stack) + local items = stack:get_meta():get("items") + if items then + items = core.deserialize(core.decompress(core.decode_base64(items), "deflate")) + end + if not items or type(items) ~= "table" or not next(items) then + return + end + local meta = core.get_meta(pos) + meta:get_inventory():set_lists(items) + meta:set_string("infotext", stack:get_description()) + end or nil, on_destruct = bones.waypoint_time > 0 and function(pos) local name = core.get_meta(pos):get_string("owner") local player = core.get_player_by_name(name) diff --git a/death.lua b/death.lua index a8975ce..9023fc4 100644 --- a/death.lua +++ b/death.lua @@ -120,7 +120,8 @@ local function log_death(pos, name, action) end core.register_on_dieplayer(function(player) - local pos = vector.round(player:get_pos()) + -- Move pos up to get the node the player is standing in. + local pos = vector.round(vector.add(player:get_pos(), vector.new(0, 0.25, 0))) local name = player:get_player_name() -- Do nothing if keep inventory is set or player has creative if bones.mode == "keep" or core.is_creative_enabled(name) then @@ -132,7 +133,7 @@ core.register_on_dieplayer(function(player) log_death(pos, name, "none") return end - local param2 = core.dir_to_facedir(player:get_look_dir()) + local param2 = core.dir_to_facedir(vector.multiply(player:get_look_dir(), -1), true) local items = bones.take_all_items(player) -- Check if it's possible to place bones local bones_pos @@ -170,7 +171,7 @@ core.register_on_dieplayer(function(player) return end -- Place bones node - local replaced = core.get_node(pos) + local replaced = core.get_node(bones_pos) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) meta:get_inventory():set_lists(items) diff --git a/entity.lua b/entity.lua index cdc08f8..0c8ffaa 100644 --- a/entity.lua +++ b/entity.lua @@ -1,9 +1,26 @@ local S = core.get_translator("bones") +-- From builtin/game/falling.lua, but only for the values returned from core.dir_to_facedir +local facedir_to_euler = { + [ 0] = {y = 0, x = 0, z = 0}, + [ 1] = {y = -math.pi/2, x = 0, z = 0}, + [ 2] = {y = math.pi, x = 0, z = 0}, + [ 3] = {y = math.pi/2, x = 0, z = 0}, + [ 4] = {y = math.pi/2, x = -math.pi/2, z = math.pi/2}, + [ 6] = {y = math.pi/2, x = math.pi/2, z = math.pi/2}, + [ 8] = {y = -math.pi/2, x = math.pi/2, z = math.pi/2}, + [10] = {y = -math.pi/2, x = -math.pi/2, z = math.pi/2}, + [13] = {y = 0, x = -math.pi/2, z = math.pi/2}, + [15] = {y = 0, x = math.pi/2, z = math.pi/2}, + [17] = {y = math.pi, x = math.pi/2, z = math.pi/2}, + [19] = {y = math.pi, x = -math.pi/2, z = math.pi/2}, +} + core.register_entity("bones:entity", { initial_properties = { visual = "cube", + visual_size = {x = 1.001, y = 1.001, z = 1.001}, -- Avoid Z-fighting if placed inside a node textures = { "bones_top.png^[transform2", "bones_bottom.png", @@ -17,12 +34,12 @@ core.register_entity("bones:entity", { collide_with_objects = true, damage_texture_modifier = "", }, - rotation = 0, + param2 = 0, items = {}, owner = "", timer = 0, - create = function(self, rotation, owner, items) - self.rotation = rotation or 0 + create = function(self, param2, owner, items) + self.param2 = param2 or 0 self.owner = owner or "" self.items = items or {} local infotext @@ -38,10 +55,14 @@ core.register_entity("bones:entity", { self.object:set_properties({ infotext = infotext, }) + local euler = facedir_to_euler[param2] + if euler then + self.object:set_rotation(euler) + end end, get_staticdata = function(self) local data = { - rotation = self.rotation, + param2 = self.param2, owner = self.owner, items = bones.stacks_to_strings(self.items), timer = self.timer, @@ -52,10 +73,10 @@ core.register_entity("bones:entity", { on_activate = function(self, staticdata) self.object:set_armor_groups({immortal = 1}) local data = core.deserialize(staticdata) - if data and data.rotation and data.owner and data.items then + if data and data.param2 and data.owner and data.items then self.timer = data.timer self.punched = data.punched - self:create(data.rotation, data.owner, bones.strings_to_stacks(data.items)) + self:create(data.param2, data.owner, bones.strings_to_stacks(data.items)) end end, on_punch = function(self, player) @@ -65,6 +86,12 @@ core.register_entity("bones:entity", { return end local pos = self.object:get_pos() + if bones.pickup and player:get_player_control().sneak then + if bones.pickup_bones(pos, self.items, self.owner, player) then + self.object:remove() + end + return + end if bones.collect_bones(pos, player, self.owner, self.items, self.punched) then self.object:remove() else diff --git a/functions.lua b/functions.lua index 0539ad1..484935b 100644 --- a/functions.lua +++ b/functions.lua @@ -30,8 +30,8 @@ function bones.can_collect(name, owner, elapsed) end function bones.collect_bones(pos, player, owner, items, punched) - -- Move as many items as possible to the player's inventory local name = player:get_player_name() + -- Move as many items as possible to the player's inventory local empty if owner == name and not punched then empty = bones.restore_all_items(player, items) @@ -58,3 +58,33 @@ function bones.collect_bones(pos, player, owner, items, punched) core.log("action", name.." takes items from bones at "..pos_string) return false end + +function bones.pickup_bones(pos, items, owner, player) + -- Pick up bones with items stored inside + local name = player:get_player_name() + local player_inv = player:get_inventory() + local has_room = false + for _,stack in ipairs(player_inv:get_list("main")) do + if stack:is_empty() then + has_room = true + break + end + end + if not has_room then + core.chat_send_player(name, S("You don't have room in your inventory for these bones.")) + return + end + items = core.encode_base64(core.compress(core.serialize(bones.stacks_to_strings(items))), "deflate") + if #items > 65000 then + core.chat_send_player(name, S("These bones are too heavy to pick up.")) + return + end + local stack = ItemStack("bones:bones") + local meta = stack:get_meta() + meta:set_string("items", items) + meta:set_string("description", S("@1's bones", owner)) + player_inv:add_item("main", stack) + core.sound_play("bones_dug", {gain = 0.8}, true) + core.log("action", name.." picks up bones at "..core.pos_to_string(pos)) + return true +end diff --git a/init.lua b/init.lua index 073200f..de76414 100644 --- a/init.lua +++ b/init.lua @@ -6,6 +6,7 @@ bones = { mode = core.settings:get("bones_mode") or "bones", fallback = core.settings:get("bones_fallback_mode") or "entity", position_message = core.settings:get_bool("bones_position_message", true), + pickup = core.settings:get_bool("bones_pickup", true), } -- Some checks for bad settings diff --git a/locale/bones.de.tr b/locale/bones.de.tr index 968f163..7d4f1a7 100644 --- a/locale/bones.de.tr +++ b/locale/bones.de.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.=Du bist gestorben. Knochen wurden in @1 platz @1's bones=Knochen von @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.eo.tr b/locale/bones.eo.tr index c0f024e..706628e 100644 --- a/locale/bones.eo.tr +++ b/locale/bones.eo.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=La ostoj de @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.es.tr b/locale/bones.es.tr index 635e9e0..0341431 100644 --- a/locale/bones.es.tr +++ b/locale/bones.es.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.=Moriste. Se colocaron tus huesos en @1. @1's bones=Huesos de @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.fr.tr b/locale/bones.fr.tr index 6b4e3c4..04a2256 100644 --- a/locale/bones.fr.tr +++ b/locale/bones.fr.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.=Tu es mort. Tes os ont été placés à @1. @1's bones=Os de @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.id.tr b/locale/bones.id.tr index aa89b5f..2ca0db8 100644 --- a/locale/bones.id.tr +++ b/locale/bones.id.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=Tulang @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.it.tr b/locale/bones.it.tr index 3d00fe5..28a4a0d 100644 --- a/locale/bones.it.tr +++ b/locale/bones.it.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.=Sei morto a @1. Furono poste le ossa. @1's bones=Ossa di @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.ja.tr b/locale/bones.ja.tr index 940c6e7..7bea0ab 100644 --- a/locale/bones.ja.tr +++ b/locale/bones.ja.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=@1の骨 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.jbo.tr b/locale/bones.jbo.tr index 9bb7fcd..4face3f 100644 --- a/locale/bones.jbo.tr +++ b/locale/bones.jbo.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=.i ti bongu gunma po'a la'o zo'i.@1.zo'i These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.ms.tr b/locale/bones.ms.tr index aa89b5f..2ca0db8 100644 --- a/locale/bones.ms.tr +++ b/locale/bones.ms.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=Tulang @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.pt_BR.tr b/locale/bones.pt_BR.tr index f028e38..f68a230 100644 --- a/locale/bones.pt_BR.tr +++ b/locale/bones.pt_BR.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.=Morreste em @1. Ossos foram colocados. @1's bones=Ossos de @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.ru.tr b/locale/bones.ru.tr index 6a9a7aa..c734e52 100644 --- a/locale/bones.ru.tr +++ b/locale/bones.ru.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=кости @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.sk.tr b/locale/bones.sk.tr index 47fe8d9..d66b499 100644 --- a/locale/bones.sk.tr +++ b/locale/bones.sk.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=Kosti hráča @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.sv.tr b/locale/bones.sv.tr index 82bcbbb..0fbc93b 100644 --- a/locale/bones.sv.tr +++ b/locale/bones.sv.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=@1s ben These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.uk.tr b/locale/bones.uk.tr index d93b524..b9ef23c 100644 --- a/locale/bones.uk.tr +++ b/locale/bones.uk.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=кістки @1 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.zh_CN.tr b/locale/bones.zh_CN.tr index e84dc53..bedece3 100644 --- a/locale/bones.zh_CN.tr +++ b/locale/bones.zh_CN.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=@1的骨骸 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/bones.zh_TW.tr b/locale/bones.zh_TW.tr index 5da3c88..5defb30 100644 --- a/locale/bones.zh_TW.tr +++ b/locale/bones.zh_TW.tr @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones=@1的骨骸 These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/locale/template.txt b/locale/template.txt index 7d78dad..c69ee0d 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -8,3 +8,5 @@ You died at @1. Bones were placed.= @1's bones= These bones belong to @1.= You collected @1's bones at @2.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= diff --git a/settingtypes.txt b/settingtypes.txt index 77503c2..af6bb5e 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -22,3 +22,6 @@ bones_position_message (Bones location message) bool true # The time in seconds that bone waypoints will be shown. # Setting this to 0 will disable waypoints. bones_waypoint_time (Waypoint lifetime) int 3600 0 + +# Sets whether picking up bones as an item is enabled. +bones_pickup (Pickup enabled) bool true From ab8e9c6a563011e968bd1337dff311fe8c7138ca Mon Sep 17 00:00:00 2001 From: OgelGames Date: Wed, 5 Nov 2025 19:03:02 +1100 Subject: [PATCH 11/18] Update death.lua --- death.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/death.lua b/death.lua index 9023fc4..86a7ee4 100644 --- a/death.lua +++ b/death.lua @@ -102,7 +102,7 @@ local function log_death(pos, name, action) core.log("action", name.." dies at "..pos_str..".") elseif action == "bones" then core.log("action", name.." dies at "..pos_str..". Bones placed.") - elseif action == "bones" then + elseif action == "entity" then core.log("action", name.." dies at "..pos_str..". Entity created.") elseif action == "drop" then core.log("action", name.." dies at "..pos_str..". Inventory dropped.") From ba61f836c03ae40fea3f316114d2aa10201be464 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Fri, 7 Nov 2025 17:12:38 +1100 Subject: [PATCH 12/18] don't take items until they are put somewhere --- death.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/death.lua b/death.lua index 86a7ee4..a5f090a 100644 --- a/death.lua +++ b/death.lua @@ -134,7 +134,6 @@ core.register_on_dieplayer(function(player) return end local param2 = core.dir_to_facedir(vector.multiply(player:get_look_dir(), -1), true) - local items = bones.take_all_items(player) -- Check if it's possible to place bones local bones_pos if bones.mode == "bones" then @@ -144,7 +143,7 @@ core.register_on_dieplayer(function(player) if bones.mode == "entity" or (not bones_pos and bones.fallback == "entity") then local entity = core.add_entity(pos, "bones:entity") if entity then - entity:get_luaentity():create(param2, name, items) + entity:get_luaentity():create(param2, name, bones.take_all_items(player)) log_death(pos, name, "entity") if bones.waypoint_time > 0 then bones.add_waypoint(pos, player) @@ -155,7 +154,7 @@ core.register_on_dieplayer(function(player) -- Drop items on the ground if bones.mode == "drop" or (not bones_pos and bones.fallback == "drop") then if drop_item(pos, "bones:bones") then - for _,list in pairs(items) do + for _,list in pairs(bones.take_all_items(player)) do for _,stack in ipairs(list) do if not stack:is_empty() then drop_item(pos, stack) @@ -174,7 +173,7 @@ core.register_on_dieplayer(function(player) local replaced = core.get_node(bones_pos) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) - meta:get_inventory():set_lists(items) + meta:get_inventory():set_lists(bones.take_all_items(player)) meta:set_string("owner", name) if replaced.name ~= "air" then meta:set_string("replaced", core.serialize(replaced)) From 993b9c7ea8966b03c8c877dd9e13961263beb875 Mon Sep 17 00:00:00 2001 From: OgelGames Date: Mon, 10 Nov 2025 01:47:10 +1100 Subject: [PATCH 13/18] add obituary --- .luacheckrc | 1 + bones.lua | 4 +- death.lua | 42 +++++++++------- entity.lua | 6 +-- functions.lua | 10 ++-- init.lua | 7 ++- mod.conf | 2 +- obituary.lua | 88 +++++++++++++++++++++++++++++++++ settingtypes.txt | 10 ++-- textures/bones_obituary.png | Bin 0 -> 242 bytes textures/bones_obituary_ui.png | Bin 0 -> 80035 bytes waypoints.lua | 20 ++++---- 12 files changed, 147 insertions(+), 43 deletions(-) create mode 100644 obituary.lua create mode 100644 textures/bones_obituary.png create mode 100644 textures/bones_obituary_ui.png diff --git a/.luacheckrc b/.luacheckrc index 7a7173c..dda4dca 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -9,4 +9,5 @@ read_globals = { "ItemStack", "vector", "armor", + "xcompat", } diff --git a/bones.lua b/bones.lua index c9cc2de..3324a16 100644 --- a/bones.lua +++ b/bones.lua @@ -86,14 +86,14 @@ core.register_node("bones:bones", { meta:get_inventory():set_lists(items) meta:set_string("infotext", stack:get_description()) end or nil, - on_destruct = bones.waypoint_time > 0 and function(pos) + on_destruct = bones.waypoints and function(pos) local name = core.get_meta(pos):get_string("owner") local player = core.get_player_by_name(name) if player then bones.remove_waypoint(pos, player) end end or nil, - on_movenode = bones.waypoint_time > 0 and function(from_pos, to_pos) + on_movenode = bones.waypoints and function(from_pos, to_pos) local meta = core.get_meta(to_pos) local owner = meta:get("owner") if not owner then diff --git a/death.lua b/death.lua index a5f090a..327e75e 100644 --- a/death.lua +++ b/death.lua @@ -96,7 +96,7 @@ local function drop_item(pos, stack) return false end -local function log_death(pos, name, action) +local function log_death(pos, name, action, items, player) local pos_str = core.pos_to_string(pos) if action == "keep" or action == "none" then core.log("action", name.." dies at "..pos_str..".") @@ -107,15 +107,18 @@ local function log_death(pos, name, action) elseif action == "drop" then core.log("action", name.." dies at "..pos_str..". Inventory dropped.") end - if not bones.position_message then - return + if bones.position_message then + if action == "keep" or action == "none" then + core.chat_send_player(name, S("You died at @1.", pos_str)) + elseif action == "bones" or action == "entity" then + core.chat_send_player(name, S("You died at @1. Bones were placed.", pos_str)) + elseif action == "drop" then + core.chat_send_player(name, S("You died at @1. Your inventory was dropped.", pos_str)) + end end - if action == "keep" or action == "none" then - core.chat_send_player(name, S("You died at @1.", pos_str)) - elseif action == "bones" or action == "entity" then - core.chat_send_player(name, S("You died at @1. Bones were placed.", pos_str)) - elseif action == "drop" then - core.chat_send_player(name, S("You died at @1. Your inventory was dropped.", pos_str)) + if bones.obituary and items and player:get_meta():get("bones_obituary") ~= "0" then + local obituary = bones.create_obituary(pos_str, name, items) + player:get_inventory():add_item("main", obituary) end end @@ -143,9 +146,10 @@ core.register_on_dieplayer(function(player) if bones.mode == "entity" or (not bones_pos and bones.fallback == "entity") then local entity = core.add_entity(pos, "bones:entity") if entity then - entity:get_luaentity():create(param2, name, bones.take_all_items(player)) - log_death(pos, name, "entity") - if bones.waypoint_time > 0 then + local items = bones.take_all_items(player) + entity:get_luaentity():create(param2, name, items) + log_death(pos, name, "entity", items, player) + if bones.waypoints then bones.add_waypoint(pos, player) end return @@ -154,14 +158,15 @@ core.register_on_dieplayer(function(player) -- Drop items on the ground if bones.mode == "drop" or (not bones_pos and bones.fallback == "drop") then if drop_item(pos, "bones:bones") then - for _,list in pairs(bones.take_all_items(player)) do + local items = bones.take_all_items(player) + for _,list in pairs(items) do for _,stack in ipairs(list) do if not stack:is_empty() then drop_item(pos, stack) end end end - log_death(pos, name, "drop") + log_death(pos, name, "drop", items, player) return end end @@ -173,19 +178,20 @@ core.register_on_dieplayer(function(player) local replaced = core.get_node(bones_pos) core.set_node(bones_pos, {name = "bones:bones", param2 = param2}) local meta = core.get_meta(bones_pos) - meta:get_inventory():set_lists(bones.take_all_items(player)) + local items = bones.take_all_items(player) + meta:get_inventory():set_lists(items) meta:set_string("owner", name) if replaced.name ~= "air" then meta:set_string("replaced", core.serialize(replaced)) end - if bones.share_time > 0 then + if bones.sharing then meta:set_string("infotext", S("@1's fresh bones", name)) core.get_node_timer(bones_pos):start(10) else meta:set_string("infotext", S("@1's bones", name)) end - log_death(bones_pos, name, "bones") - if bones.waypoint_time > 0 then + log_death(bones_pos, name, "bones", items, player) + if bones.waypoints then bones.add_waypoint(bones_pos, player) end end) diff --git a/entity.lua b/entity.lua index 0c8ffaa..9181ed6 100644 --- a/entity.lua +++ b/entity.lua @@ -43,7 +43,7 @@ core.register_entity("bones:entity", { self.owner = owner or "" self.items = items or {} local infotext - if bones.share_time > 0 then + if bones.sharing then if self.timer >= bones.share_time then infotext = S("@1's old bones", owner) else @@ -99,7 +99,7 @@ core.register_entity("bones:entity", { end return true end, - on_step = bones.share_time > 0 and function(self, dtime) + on_step = bones.sharing and function(self, dtime) if self.timer >= bones.share_time then return end @@ -110,7 +110,7 @@ core.register_entity("bones:entity", { }) end end or nil, - on_deactivate = bones.waypoint_time > 0 and function(self, removal) + on_deactivate = bones.waypoints and function(self, removal) if not removal then return end diff --git a/functions.lua b/functions.lua index 484935b..4cd3f4b 100644 --- a/functions.lua +++ b/functions.lua @@ -20,7 +20,7 @@ function bones.strings_to_stacks(inventory) end function bones.can_collect(name, owner, elapsed) - if bones.share_time > 0 and elapsed >= bones.share_time then + if bones.sharing and elapsed >= bones.share_time then return true end if owner == "" or owner == name or core.check_player_privs(name, "protection_bypass") then @@ -39,7 +39,7 @@ function bones.collect_bones(pos, player, owner, items, punched) empty = bones.add_all_items(player, items) end -- Remove bones if they have been emptied - local pos_string = core.pos_to_string(pos) + local pos_str = core.pos_to_string(pos) if empty then local player_inv = player:get_inventory() if player_inv:room_for_item("main", "bones:bones") then @@ -48,14 +48,14 @@ function bones.collect_bones(pos, player, owner, items, punched) core.add_item(pos, "bones:bones") end if owner ~= name then - core.chat_send_player(name, S("You collected @1's bones at @2.", owner, pos_string)) + core.chat_send_player(name, S("You collected @1's bones at @2.", owner, pos_str)) end - core.log("action", name.." removes bones at "..pos_string) + core.log("action", name.." removes bones at "..pos_str) core.sound_play("bones_dug", {gain = 0.8}, true) return true end -- Log the bone-taking - core.log("action", name.." takes items from bones at "..pos_string) + core.log("action", name.." takes items from bones at "..pos_str) return false end diff --git a/init.lua b/init.lua index de76414..52716cd 100644 --- a/init.lua +++ b/init.lua @@ -7,8 +7,12 @@ bones = { fallback = core.settings:get("bones_fallback_mode") or "entity", position_message = core.settings:get_bool("bones_position_message", true), pickup = core.settings:get_bool("bones_pickup", true), + obituary = core.settings:get_bool("bones_obituary", true), } +bones.waypoints = bones.waypoint_time > 0 +bones.sharing = bones.share_time > 0 + -- Some checks for bad settings if bones.mode ~= "bones" and bones.mode ~= "entity" and bones.mode ~= "drop" and bones.mode ~= "keep" then bones.mode = "bones" @@ -25,12 +29,13 @@ end local MP = core.get_modpath("bones") -if bones.waypoint_time > 0 then +if bones.waypoints then dofile(MP.."/waypoints.lua") end dofile(MP.."/bones.lua") dofile(MP.."/entity.lua") +dofile(MP.."/obituary.lua") dofile(MP.."/death.lua") dofile(MP.."/inventories.lua") dofile(MP.."/functions.lua") diff --git a/mod.conf b/mod.conf index 96614f0..63eef6b 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,4 @@ name = bones description = Adds bones that generate on death -optional_depends = 3d_armor +optional_depends = 3d_armor, xcompat min_minetest_version = 5.3 diff --git a/obituary.lua b/obituary.lua new file mode 100644 index 0000000..e6d0de4 --- /dev/null +++ b/obituary.lua @@ -0,0 +1,88 @@ + +local S = core.get_translator("bones") + +local formspec = [[ + formspec_version[2] + size[5.4,7.8] + bgcolor[#0000;both] + background[-0.5,-0.1;6,8;bones_obituary_ui.png] + hypertext[0,0.2;5.4,2;help;