2017-06-13 13:45:42 +02:00
|
|
|
-- compass configuration interface - adjustable from other mods or minetest.conf settings
|
2020-02-01 22:53:29 -07:00
|
|
|
death_compass = {}
|
2017-04-11 00:18:11 +02:00
|
|
|
|
2020-02-01 22:53:29 -07:00
|
|
|
local S = minetest.get_translator("death_compass")
|
|
|
|
|
|
|
|
-- how many seconds does the death compass work for? 0 for indefinite
|
|
|
|
local duration = tonumber(minetest.settings:get("death_compass_duration")) or 0
|
2017-04-11 22:49:36 +02:00
|
|
|
|
2020-02-01 22:53:29 -07:00
|
|
|
local range_to_inactivate = 5
|
2017-06-13 13:45:42 +02:00
|
|
|
|
2017-06-15 01:24:52 +02:00
|
|
|
-- set a position to the compass stack
|
2020-02-01 22:53:29 -07:00
|
|
|
function set_target(stack, pos, name)
|
2017-06-15 01:24:52 +02:00
|
|
|
local meta=stack:get_meta()
|
2020-02-01 22:53:29 -07:00
|
|
|
meta:set_string("target_pos", minetest.pos_to_string(pos))
|
|
|
|
meta:set_string("target_corpse", name)
|
|
|
|
meta:set_int("time_of_death", minetest.get_gametime())
|
2017-06-15 01:24:52 +02:00
|
|
|
end
|
|
|
|
|
2017-06-13 13:45:42 +02:00
|
|
|
-- Get compass target
|
2017-04-11 22:49:36 +02:00
|
|
|
local function get_destination(player, stack)
|
2017-06-13 13:45:42 +02:00
|
|
|
local posstring = stack:get_meta():get_string("target_pos")
|
|
|
|
if posstring ~= "" then
|
|
|
|
return minetest.string_to_pos(posstring)
|
2017-04-11 00:18:11 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-02-01 22:53:29 -07:00
|
|
|
-- looped ticking sound if there's a duration on this
|
|
|
|
local player_ticking = {}
|
|
|
|
local function start_ticking(player_name)
|
|
|
|
if not player_ticking[player_name] then
|
|
|
|
player_ticking[player_name] = minetest.sound_play("death_compass_tick_tock",
|
|
|
|
{to_player = player_name, gain = 0.125, loop = true})
|
2018-02-17 09:08:36 +01:00
|
|
|
end
|
2020-02-01 22:53:29 -07:00
|
|
|
end
|
|
|
|
local function stop_ticking(player_name)
|
|
|
|
local tick_tock_handle = player_ticking[player_name]
|
|
|
|
if tick_tock_handle then
|
|
|
|
minetest.sound_stop(tick_tock_handle)
|
|
|
|
player_ticking[player_name] = nil
|
2018-02-17 09:08:36 +01:00
|
|
|
end
|
2018-02-14 20:11:14 +01:00
|
|
|
end
|
|
|
|
|
2020-02-01 22:53:29 -07:00
|
|
|
-- get right image number for players compass
|
2017-04-11 22:49:36 +02:00
|
|
|
local function get_compass_stack(player, stack)
|
2017-06-13 13:45:42 +02:00
|
|
|
local target = get_destination(player, stack)
|
2020-02-01 22:53:29 -07:00
|
|
|
if not target then
|
|
|
|
return ItemStack("death_compass:inactive")
|
|
|
|
end
|
|
|
|
local pos = player:get_pos()
|
|
|
|
local dist = vector.distance(pos, target)
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
|
|
|
|
if dist < range_to_inactivate then
|
|
|
|
stop_ticking(player_name)
|
|
|
|
minetest.sound_play("death_compass_bone_crunch", {to_player=player_name, gain = 1.0})
|
|
|
|
return ItemStack("death_compass:inactive")
|
|
|
|
end
|
|
|
|
|
2019-03-27 14:20:20 +01:00
|
|
|
local dir = player:get_look_horizontal()
|
2017-06-13 13:45:42 +02:00
|
|
|
local angle_north = math.deg(math.atan2(target.x - pos.x, target.z - pos.z))
|
2017-04-11 00:18:11 +02:00
|
|
|
if angle_north < 0 then
|
|
|
|
angle_north = angle_north + 360
|
|
|
|
end
|
2019-03-27 14:20:20 +01:00
|
|
|
local angle_dir = math.deg(dir)
|
|
|
|
local angle_relative = (angle_north + angle_dir) % 360
|
2019-09-15 11:57:23 +02:00
|
|
|
local compass_image = math.floor((angle_relative/22.5) + 0.5)%16
|
2017-04-11 22:49:36 +02:00
|
|
|
|
2017-06-13 13:45:42 +02:00
|
|
|
-- create new stack with metadata copied
|
|
|
|
local metadata = stack:get_meta():to_table()
|
2020-02-01 22:53:29 -07:00
|
|
|
local meta_fields = metadata.fields
|
|
|
|
local time_of_death = tonumber(meta_fields.time_of_death)
|
|
|
|
if duration > 0 then
|
|
|
|
local remaining = time_of_death + duration - minetest.get_gametime()
|
|
|
|
if remaining < 0 then
|
|
|
|
stop_ticking(player_name)
|
|
|
|
minetest.sound_play("death_compass_bone_crunch", {to_player=player_name, gain = 1.0})
|
|
|
|
return ItemStack("death_compass:inactive")
|
|
|
|
end
|
|
|
|
start_ticking(player_name)
|
|
|
|
meta_fields.description = S("@1m to @2's corpse, @3s remaining",
|
|
|
|
math.floor(dist), meta_fields.target_corpse, remaining)
|
|
|
|
else
|
|
|
|
meta_fields.description = S("@1m to @2's corpse, died @3s ago",
|
|
|
|
math.floor(dist), meta_fields.target_corpse, minetest.get_gametime() - time_of_death)
|
|
|
|
end
|
|
|
|
|
|
|
|
local newstack = ItemStack("death_compass:dir"..compass_image)
|
2017-06-13 13:45:42 +02:00
|
|
|
if metadata then
|
|
|
|
newstack:get_meta():from_table(metadata)
|
|
|
|
end
|
2017-05-07 23:53:27 +02:00
|
|
|
return newstack
|
2017-04-11 00:18:11 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- update inventory
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
|
|
for i,player in ipairs(minetest.get_connected_players()) do
|
2020-02-01 22:53:29 -07:00
|
|
|
local player_name = player:get_player_name()
|
2017-04-11 00:18:11 +02:00
|
|
|
if player:get_inventory() then
|
|
|
|
for i,stack in ipairs(player:get_inventory():get_list("main")) do
|
2017-06-13 13:45:42 +02:00
|
|
|
if i > 8 then
|
|
|
|
break
|
|
|
|
end
|
2020-02-01 22:53:29 -07:00
|
|
|
if string.sub(stack:get_name(), 0, 17) == "death_compass:dir" then
|
2017-06-13 13:45:42 +02:00
|
|
|
player:get_inventory():set_stack("main", i, get_compass_stack(player, stack))
|
2020-02-01 22:53:29 -07:00
|
|
|
player_name = nil -- don't stop the sound playing
|
2017-04-11 00:18:11 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-02-01 22:53:29 -07:00
|
|
|
if player_name then
|
|
|
|
stop_ticking(player_name)
|
|
|
|
end
|
2017-04-11 00:18:11 +02:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- register items
|
2019-09-15 11:57:23 +02:00
|
|
|
for i = 0, 15 do
|
2020-02-01 22:53:29 -07:00
|
|
|
local image = "death_compass_16_"..i..".png"
|
|
|
|
local groups = {death_compass = 1, not_in_creative_inventory = 1}
|
|
|
|
minetest.register_tool("death_compass:dir"..i, {
|
|
|
|
description = S("Death Compass"),
|
2017-04-11 00:18:11 +02:00
|
|
|
inventory_image = image,
|
|
|
|
wield_image = image,
|
2020-02-01 22:53:29 -07:00
|
|
|
stack_max = 1,
|
2017-06-13 13:45:42 +02:00
|
|
|
groups = groups,
|
2017-04-11 00:18:11 +02:00
|
|
|
})
|
|
|
|
end
|
2020-02-01 22:53:29 -07:00
|
|
|
minetest.register_tool("death_compass:inactive", {
|
|
|
|
description = S("Inactive Death Compass"),
|
|
|
|
inventory_image = "death_compass_inactive.png",
|
|
|
|
wield_image = "death_compass_inactive.png",
|
|
|
|
stack_max = 1,
|
|
|
|
groups = {death_compass = 1},
|
|
|
|
})
|
2017-04-11 00:18:11 +02:00
|
|
|
|
|
|
|
minetest.register_craft({
|
2020-02-01 22:53:29 -07:00
|
|
|
output = 'death_compass:inactive',
|
2017-04-11 00:18:11 +02:00
|
|
|
recipe = {
|
2020-02-01 22:53:29 -07:00
|
|
|
{'', 'bones:bones', ''},
|
|
|
|
{'bones:bones', 'default:mese_crystal_fragment', 'bones:bones'},
|
|
|
|
{'', 'bones:bones', ''}
|
2017-04-11 00:18:11 +02:00
|
|
|
}
|
|
|
|
})
|
2020-02-01 22:53:29 -07:00
|
|
|
|
|
|
|
local player_death_location = {}
|
|
|
|
minetest.register_on_dieplayer(function(player, reason)
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
local inv = minetest.get_inventory({type="player", name=player:get_player_name()})
|
|
|
|
local list = inv:get_list("main")
|
|
|
|
local count = 0
|
|
|
|
for i, itemstack in pairs(list) do
|
|
|
|
if minetest.get_item_group(itemstack:get_name(), "death_compass") > 0 then
|
|
|
|
count = count + itemstack:get_count()
|
|
|
|
list[i] = ItemStack("")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if count > 0 then
|
|
|
|
inv:set_list("main", list)
|
|
|
|
player_death_location[player_name] = {count=count,pos=player:get_pos()}
|
|
|
|
end
|
|
|
|
|
|
|
|
end)
|
|
|
|
-- Called when a player dies
|
|
|
|
-- `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange
|
|
|
|
|
|
|
|
minetest.register_on_respawnplayer(function(player)
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
local compasses = player_death_location[player_name]
|
|
|
|
if compasses then
|
|
|
|
local inv = minetest.get_inventory({type="player", name=player_name})
|
|
|
|
|
|
|
|
-- Remove any death compasses they might still have for some reason
|
|
|
|
local current = inv:get_list("main")
|
|
|
|
for i, item in pairs(current) do
|
|
|
|
if minetest.get_item_group(item:get_name(), "death_compass") > 0 then
|
|
|
|
current[i] = ItemStack("")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
inv:set_list("main", current)
|
|
|
|
|
|
|
|
-- give them new compasses pointing to their place of death
|
|
|
|
for i = 1, compasses.count do
|
|
|
|
local compass = ItemStack("death_compass:dir0")
|
|
|
|
set_target(compass, compasses.pos, player_name)
|
|
|
|
inv:add_item("main", compass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end)
|
|
|
|
-- * Called when player is to be respawned
|
|
|
|
-- * Called _before_ repositioning of player occurs
|
|
|
|
-- * return true in func to disable regular player placement
|