Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ globals = {
}

read_globals = {
"ItemStack",
"vector",
"armor",
}
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
98 changes: 57 additions & 41 deletions bones.lua
Original file line number Diff line number Diff line change
@@ -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", {
Expand All @@ -24,44 +21,51 @@ core.register_node("bones:bones", {
"bones_front.png"
},
paramtype2 = "facedir",
groups = {dig_immediate = 2},
groups = { dig_immediate = 2 },
is_ground_content = false,
sounds = {
footstep = {name = "bones_footstep", gain = 1.1},
dig = {name = "bones_dig", gain = 0.9},
dug = {name = "bones_dug", gain = 0.8},
place = {name = "bones_place", gain = 0.7},
footstep = { name = "bones_footstep", gain = 1.1 },
dig = { name = "bones_dig", gain = 0.9 },
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_rightclick = function (pos, _, player)
bones.show_formspec(pos, player, core.get_meta(pos):get_inventory():get_lists())
end,
on_timer = function(pos, elapsed)
local meta = core.get_meta(pos)
Expand All @@ -73,28 +77,40 @@ 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)
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)
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.
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
bones.remove_waypoint(from_pos, player)
bones.add_waypoint(to_pos, player)
end
local from = core.pos_to_string(from_pos)
local to = core.pos_to_string(to_pos)
core.log("action", "Bones of "..owner.." moved from "..from.." to "..to)
core.log("action", "Bones of " .. owner .. " moved from " .. from .. " to " .. to)
end or nil,
on_blast = function() end,
})
83 changes: 44 additions & 39 deletions death.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -113,15 +91,19 @@ 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 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
Expand All @@ -130,57 +112,80 @@ 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))
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
log_death(pos, name, "keep")
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)
local items = 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 and bones.fallback == "entity") then
local entity = core.add_entity(pos, "bones:entity")
if entity then
entity:get_luaentity():create(param2, name, items)
log_death(pos, name, "entity")
if bones.waypoint_time > 0 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
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")
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)
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
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
bones.add_waypoint(bones_pos, player)
end
Expand Down
Loading