Aaron Suen fb77ef190c Set default watch location above player's head.
The "pretend to be in 3rd person view" camera angle
never really worked, and using the actual F7 key
seems to override this anyway, so let's try setting the
default offset to to something more useful maybe.
2019-12-11 22:30:29 -05:00

187 lines
5.0 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local minetest, pairs, rawset, type
= minetest, pairs, rawset, type
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local vzero = vector.new()
local function playerize(param)
if (not param) or (param == "") then return end
if type(param) == "string" then
local player = minetest.get_player_by_name(param)
if player then return player, param end
return
end
return param, param:get_player_name()
end
local function setprivs(pname, setfunc)
local privs = minetest.get_player_privs(pname)
local r = setfunc(privs)
if r ~= nil then return r end
minetest.set_player_privs(pname, privs)
end
local watchdata_cache = {}
local function watchdata_get(player, pname)
pname = pname or player:get_player_name()
local c = watchdata_cache[pname]
if c then return c end
c = player:get_meta():get_string(modname)
if (not c) or (c == "") then return end
c = minetest.deserialize(c)
watchdata_cache[pname] = c
return c
end
local function watchdata_set(player, pname, data)
pname = pname or player:get_player_name()
watchdata_cache[pname] = data
return player:get_meta():set_string(modname, minetest.serialize(data))
end
local function watch_restore(dtime, wplayer, wname)
wname = wname or wplayer:get_player_name()
local data = watchdata_get(wplayer, wname)
if not data then return end
if data.target then
return wplayer:set_breath(11)
end
if not data.restore then return end
local restore = data.restore
for k, v in pairs({
ttl = 1,
eye1 = {x = 0, y = 0, z = 0},
eye2 = {x = 0, y = 0, z = 0},
visual_size = {x = 1, y = 1},
makes_footstep_sound = true,
collisionbox = {-0.3, -1, -0.3, 0.3, 1, 0.3},
interact = false,
pos = {x = 0, y = 0, z = 0}
}) do
restore[k] = restore[k] or v
end
restore.ttl = restore.ttl - dtime
wplayer:set_detach()
wplayer:set_eye_offset(restore.eye1, restore.eye2)
wplayer:set_properties({
visual_size = restore.visual_size,
makes_footstep_sound = restore.makes_footstep_sound,
collisionbox = restore.collisionbox
})
setprivs(wname, function(x) x.interact = restore.interact end)
if restore.inv then
for k, v in pairs(restore.inv) do
wplayer:get_inventory():set_list(k, v)
end
data.restore.inv = nil
end
if vector.distance(wplayer:get_pos(), restore.pos) < 16 then
wplayer:set_hp(restore.hp or 20)
end
wplayer:set_pos(restore.pos)
if data.restore.ttl < 0 then data.restore = nil end
return watchdata_set(wplayer, wname, data)
end
local function watch_damage(wplayer, hp)
local wname = wplayer:get_player_name()
local data = watchdata_get(wplayer, wname)
if data and data.target then return 0 end
return hp
end
local function watch_stop(wparam, tparam)
local wplayer, wname = playerize(wparam)
if not wplayer then return false, "watcher not found" end
local data = watchdata_get(wplayer, wname)
if not data then return false, "not watching anybody" end
local _, tname = playerize(tparam)
if tname and tname ~= data.target then
return false, "not watching specified target"
end
data.restore = data.saved or data.restore
if data.restore then data.restore.ttl = 0.5 end
data.saved = nil
data.target = nil
watchdata_set(wplayer, wname, data)
watch_restore(0, wplayer)
return true
end
local function watch_start(wparam, tparam)
local wplayer, wname = playerize(wparam)
if not wplayer then return false, "watcher not found" end
local tplayer, tname = playerize(tparam)
if not tplayer then return false, "target not found" end
if wname == tname then return watch_stop(wparam) end
local data = watchdata_get(wplayer, wname) or {}
if data.target == tname then return end
data.saved = data.saved or data.restore
if not data.saved then
local props = wplayer:get_properties()
local eye1, eye2 = wplayer:get_eye_offset()
data.saved = {
pos = wplayer:get_pos(),
interact = setprivs(wname, function(x) return x.interact or false end),
visual_size = props.visual_size,
makes_footstep_sound = props.makes_footstep_sound,
collisionbox = props.collisionbox,
eye1 = eye1,
eye2 = eye2,
inv = {
main = wplayer:get_inventory():get_list("main") or {},
craft = wplayer:get_inventory():get_list("craft") or {}
},
hp = wplayer:get_hp()
}
for n, l in pairs(data.saved.inv) do
for k, v in pairs(l) do
if type(v) == "userdata" then
l[k] = v:to_string()
end
end
wplayer:get_inventory():set_list(n, {})
end
end
data.saved.ttl = nil
data.restore = nil
data.target = tname
watchdata_set(wplayer, wname, data)
wplayer:set_attach(tplayer, "", vector.new(0, 5, 0), vzero)
wplayer:set_eye_offset(vector.new(0, 5, 0), vzero)
wplayer:set_properties({
visual_size = {x = 0, y = 0},
makes_footstep_sound = false,
collisionbox = {0}
})
wplayer:set_hp(20)
setprivs(wname, function(x) x.interact = nil end)
return true
end
rawset(_G, modname, {
dataget = watchdata_get,
dataset = watchdata_set,
damage = watch_damage,
restore = watch_restore,
stop = watch_stop,
start = watch_start
})