191 lines
6.1 KiB
Lua
Raw Normal View History

-- 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
2020-02-01 22:53:29 -07:00
local range_to_inactivate = 5
-- set a position to the compass stack
2020-02-01 22:53:29 -07:00
function set_target(stack, pos, name)
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())
end
-- Get compass target
local function get_destination(player, stack)
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
end
2020-02-01 22:53:29 -07:00
-- get right image number for players compass
local function get_compass_stack(player, stack)
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
local dir = player:get_look_horizontal()
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
local angle_dir = math.deg(dir)
local angle_relative = (angle_north + angle_dir) % 360
local compass_image = math.floor((angle_relative/22.5) + 0.5)%16
-- 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)
if metadata then
newstack:get_meta():from_table(metadata)
end
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
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
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
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,
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