diff --git a/.luacheckrc b/.luacheckrc index 372ae0b..dda4dca 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -6,6 +6,8 @@ globals = { } read_globals = { + "ItemStack", "vector", "armor", + "xcompat", } diff --git a/README.md b/README.md index d128a5b..585cdc3 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,13 @@ 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. +- **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. - **Custom sounds** - Because bones are not made of gravel. ## Dependencies diff --git a/bones.lua b/bones.lua index 570eed7..3324a16 100644 --- a/bones.lua +++ b/bones.lua @@ -1,16 +1,13 @@ local S = core.get_translator("bones") -local function is_owner(pos, name) - local meta = core.get_meta(pos) - 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 +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 - return false end core.register_node("bones:bones", { @@ -32,36 +29,40 @@ 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 not meta:get("infotext") then + return -- Ignore empty (decorative) bones. + end local name = player:get_player_name() - if meta:get_string("infotext") == "" or not is_owner(pos, name) then + 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 - -- 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) + local items = inv:get_lists() + 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 - -- Remove bones if they have been emptied - if inv:is_empty("main") then - 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) + 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) end - -- Log the bone-taking - core.log("action", name.." takes items from bones at "..core.pos_to_string(pos)) end, on_timer = function(pos, elapsed) local meta = core.get_meta(pos) @@ -73,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.waypoints and function(pos) local name = core.get_meta(pos):get_string("owner") local player = core.get_player_by_name(name) @@ -82,10 +95,9 @@ core.register_node("bones:bones", { end or nil, on_movenode = bones.waypoints 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 ead87b5..e3ef11c 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 @@ -113,32 +91,43 @@ 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) +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..". 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 == "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.") 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" 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)) + return + end + 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 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 @@ -146,42 +135,66 @@ 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 param2 = core.dir_to_facedir(vector.multiply(player:get_look_dir(), -1), true) -- 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 and bones.fallback == "entity") then + local entity = core.add_entity(pos, "bones:entity") + if entity 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 + end + 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) + if bones.mode == "drop" or (not bones_pos and bones.fallback == "drop") then + if drop_item(pos, "bones:bones") then + 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", items, player) + return end - drop_item(pos, "bones:bones") - log_death(pos, name, "drop") + end + if 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 + local replaced = core.get_node(bones_pos) 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) - if bones.share_time > 0 then + 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.sharing 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 + 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 new file mode 100644 index 0000000..9181ed6 --- /dev/null +++ b/entity.lua @@ -0,0 +1,122 @@ + +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", + "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, + damage_texture_modifier = "", + }, + param2 = 0, + items = {}, + owner = "", + timer = 0, + create = function(self, param2, owner, items) + self.param2 = param2 or 0 + self.owner = owner or "" + self.items = items or {} + local infotext + if bones.sharing then + 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 + 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 = { + param2 = self.param2, + owner = self.owner, + items = bones.stacks_to_strings(self.items), + timer = self.timer, + punched = self.punched, + } + 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.param2 and data.owner and data.items then + self.timer = data.timer + self.punched = data.punched + self:create(data.param2, data.owner, bones.strings_to_stacks(data.items)) + end + end, + on_punch = function(self, player) + local name = player:get_player_name() + 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 + 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 + self.punched = 1 + end + return true + end, + on_step = bones.sharing 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.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/functions.lua b/functions.lua new file mode 100644 index 0000000..4cd3f4b --- /dev/null +++ b/functions.lua @@ -0,0 +1,90 @@ + +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.sharing 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) + 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) + else + empty = bones.add_all_items(player, items) + end + -- Remove bones if they have been emptied + 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 + 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_str)) + end + 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_str) + 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 41c9fff..52716cd 100644 --- a/init.lua +++ b/init.lua @@ -1,18 +1,31 @@ bones = { redo = true, - registered_inventories = {}, - 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", + 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), } -if bones.mode ~= "bones" and bones.mode ~= "drop" and bones.mode ~= "keep" then +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" end - -bones.waypoints = bones.waypoint_time > 0 +if bones.fallback ~= "entity" and bones.fallback ~= "drop" and bones.fallback ~= "keep" then + bones.fallback = "entity" +end +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") @@ -21,14 +34,11 @@ if bones.waypoints then end dofile(MP.."/bones.lua") +dofile(MP.."/entity.lua") +dofile(MP.."/obituary.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") +dofile(MP.."/functions.lua") bones.register_inventory("main") bones.register_inventory("craft") @@ -43,21 +53,52 @@ 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 + 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) + 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 + 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) + 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 diff --git a/locale/bones.de.tr b/locale/bones.de.tr index a7b9179..38b2f74 100644 --- a/locale/bones.de.tr +++ b/locale/bones.de.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.eo.tr b/locale/bones.eo.tr index f2644fe..1c7483c 100644 --- a/locale/bones.eo.tr +++ b/locale/bones.eo.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.es.tr b/locale/bones.es.tr index 8db3470..2f7c894 100644 --- a/locale/bones.es.tr +++ b/locale/bones.es.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.fr.tr b/locale/bones.fr.tr index c537683..bdbf789 100644 --- a/locale/bones.fr.tr +++ b/locale/bones.fr.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.id.tr b/locale/bones.id.tr index 6e7c0b4..bc46e12 100644 --- a/locale/bones.id.tr +++ b/locale/bones.id.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.it.tr b/locale/bones.it.tr index 60948a6..485e868 100644 --- a/locale/bones.it.tr +++ b/locale/bones.it.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.ja.tr b/locale/bones.ja.tr index 3855b0a..5964bab 100644 --- a/locale/bones.ja.tr +++ b/locale/bones.ja.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.jbo.tr b/locale/bones.jbo.tr index d76daa0..d9c2e69 100644 --- a/locale/bones.jbo.tr +++ b/locale/bones.jbo.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.ms.tr b/locale/bones.ms.tr index 6e7c0b4..bc46e12 100644 --- a/locale/bones.ms.tr +++ b/locale/bones.ms.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.pt_BR.tr b/locale/bones.pt_BR.tr index 9a1d9e8..2a46026 100644 --- a/locale/bones.pt_BR.tr +++ b/locale/bones.pt_BR.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.ru.tr b/locale/bones.ru.tr index 7ffc0da..15af8f0 100644 --- a/locale/bones.ru.tr +++ b/locale/bones.ru.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.sk.tr b/locale/bones.sk.tr index 1685674..61b9ffd 100644 --- a/locale/bones.sk.tr +++ b/locale/bones.sk.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.sv.tr b/locale/bones.sv.tr index efa23e3..62ebb6d 100644 --- a/locale/bones.sv.tr +++ b/locale/bones.sv.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.uk.tr b/locale/bones.uk.tr index d651772..5db7f78 100644 --- a/locale/bones.uk.tr +++ b/locale/bones.uk.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.zh_CN.tr b/locale/bones.zh_CN.tr index aadf02d..8d866fd 100644 --- a/locale/bones.zh_CN.tr +++ b/locale/bones.zh_CN.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/bones.zh_TW.tr b/locale/bones.zh_TW.tr index 30567a1..75c95e6 100644 --- a/locale/bones.zh_TW.tr +++ b/locale/bones.zh_TW.tr @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/locale/template.txt b/locale/template.txt index 1cca4cd..91beca9 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -6,3 +6,16 @@ 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.= +You don't have room in your inventory for these bones.= +These bones are too heavy to pick up.= +Obituary= +Obituary of @1= +Toggle receiving an obituary when you die.= +Obituary disabled.= +Obituary enabled.= +Name= +Time= +Location= +Inventory at death= diff --git a/mod.conf b/mod.conf index 96614f0..56543ae 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,4 @@ name = bones description = Adds bones that generate on death -optional_depends = 3d_armor -min_minetest_version = 5.3 +optional_depends = 3d_armor, xcompat +min_minetest_version = 5.4.0 diff --git a/obituary.lua b/obituary.lua new file mode 100644 index 0000000..dc0ae83 --- /dev/null +++ b/obituary.lua @@ -0,0 +1,86 @@ + +local S = core.get_translator("bones") + +local formspec = "formspec_version[2]".. + "size[5.4,7.8]".. + "background[-0.5,-0.1;6,8;bones_obituary_ui.png]".. + "hypertext[0,0.2;5.4,2;;