minetest-gamehub/gamehub/functions.lua

1016 lines
24 KiB
Lua

--[[
gamehub mod (C) shivajiva101@hotmail.com 2019
This file is part of gamehub.
gamehub is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
gamehub is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gamehub. If not, see <https://www.gnu.org/licenses/>.
]]
local context = {}
local hud = {}
local dirty = {}
local armor_mod = minetest.get_modpath("3d_armor")
local HSMD = 20
--[[
-----------------------------
Internal Functions
-----------------------------
]]
-- Teleport player to a game
-- @param player: player object
-- @param data: either name of game or table containing pos and facing
-- @return nothing
local tp = function(player, dta)
local pos, facing
local name = player:get_player_name()
if type(dta) == "table" then
pos = dta.pos
facing = dta.facing
elseif type(dta) == "string" then
-- game teleporter
if dta == "world" then
pos = gamehub.player[name].pos
facing = gamehub.player[name].facing
else
pos = gamehub.game[dta].pos
facing = gamehub.game[dta].facing
end
gamehub.player[name].game = dta
end
minetest.sound_play("pad_teleport", {
to_player = name,
gain = 0.1,
loop = false
})
player:set_pos(pos)
player:set_look_horizontal(facing.h)
player:set_look_vertical(facing.v)
end
-- Toggle players game hud
-- @param player: player object
-- @return nothing
local toggle_hud = function(player)
local name = player:get_player_name()
if not gamehub.privs[name].hub_mod then
local game = gamehub.player[name].game
if game == "world" then
player:hud_set_flags({
hotbar = true,
healthbar = true,
wielditem = true}
)
else
player:hud_set_flags({
hotbar = false,
healthbar = false,
wielditem = false}
)
end
end
end
-- Set players name tag colour
-- @param player: minetest player object
-- @param color: ARGB colour table (a=,r=,g=,b=)
-- @return nothing
local set_nametag = function(player, color)
player:set_nametag_attributes({
color = color
})
end
-- Clear a players inventory
-- @param player; minetest player object
-- @return nothing
local inventory_clear = function(player)
local player_name = player:get_player_name()
local player_inv = player:get_inventory()
local bags_inv = minetest.get_inventory({type = 'detached', name = player_name..'_bags'})
local lists = player_inv:get_lists()
-- initialise shadow inventories
if lists.smain == nil then
player_inv:set_size("smain", player_inv:get_size("main"))
end
if lists.scraft == nil then
player_inv:set_size("scraft", player_inv:get_size("craft"))
end
-- shadow contents and delete
if player_inv:is_empty("smain") then -- empty?
player_inv:set_list("smain", player_inv:get_list("main")) -- copy
player_inv:set_list("main", {}) -- clear
else
player_inv:set_list("main", {}) -- clear
end
if player_inv:is_empty("scraft") then -- empty?
player_inv:set_list("scraft", player_inv:get_list("craft")) -- copy
player_inv:set_list("craft", {}) -- clear
else
player_inv:set_list("craft", {}) -- clear
end
if armor_mod then
if lists.sarmor == nil then
player_inv:set_size("sarmor", player_inv:get_size("armor"))
end
if player_inv:is_empty("sarmor") then -- empty?
player_inv:set_list("sarmor", player_inv:get_list("armor")) -- copy
player_inv:set_list("armor", {}) -- clear
armor:set_player_armor(player) --refresh
--armor:update_inventory(player) -- update
else
player_inv:set_list("armor", {}) -- clear
armor:set_player_armor(player) --refresh
end
end
if bags_inv then
for bag = 1, 4 do -- store and clear bags
if not bags_inv:is_empty('bag'..bag) then
-- set inventory size for current bag
player_inv:set_size("sbag"..bag, bags_inv:get_size('bag'..bag))
player_inv:set_list("sbag"..bag, bags_inv:get_list("bag"..bag))
player_inv:set_list("bag"..bag, {})
else
player_inv:set_list("bag"..bag, {})
end
end
end
-- TODO set inventory page
--player:set_inventory_formspec()
end
-- Restore a players inventory
-- @param player; minetest player object
-- @return nothing
local inventory_restore = function(player)
local player_inv = player:get_inventory()
local name = player:get_player_name()
local bags_inv = minetest.get_inventory({type = 'detached', name = name..'_bags'})
if not player_inv:is_empty("smain") then -- contents?
player_inv:set_list("main", player_inv:get_list("smain")) -- copy
player_inv:set_list("smain", {}) -- clear
end
if not player_inv:is_empty("scraft") then -- contents?
player_inv:set_list("craft", player_inv:get_list("scraft")) -- copy
player_inv:set_list("scraft", {}) -- clear
else
player_inv:set_list("craft", {}) -- prevent theft from hub games
end
if armor_mod then
if not player_inv:is_empty("sarmor") then -- contents?
player_inv:set_list("armor", player_inv:get_list("sarmor")) -- copy
player_inv:set_list("sarmor", {}) -- clear
armor:set_player_armor(player) -- refresh
end
end
if bags_inv then
for bag = 1, 4 do -- return bag contents
if not player_inv:is_empty("sbag"..bag) then -- contents
player_inv:set_list("bag"..bag, player_inv:get_list("sbag"..bag)) -- copy
player_inv:set_list("sbag"..bag, {}) -- clear
end
end
end
-- as the function is only called when returning a player to normal
-- reinstate the privileges from the cache
local privs = gamehub.privs[name]
if privs then -- contents
minetest.set_player_privs(name, privs) -- copy
else
minetest.log("error", table.concat({"gamehub.player_restore() ",name,
" is missing from priv cache!"}))
end
toggle_hud(player)
end
-- Enter a subgame, called on login!
-- @param name; player name
-- @param game; name of the game
-- @return nothing
local enter_game = function(name, game)
-- refuse jailed players.
if gamehub.jail[name] then
return
end
-- localise player obj
local player = minetest.get_player_by_name(name)
-- ensure player is present
if not player then return end
local pd = gamehub.player[name] -- player data
local gd = gamehub.game[game] -- game data
if pd.game == "world" then
if not gamehub.privs[name].hub_mod then
-- process normal player
inventory_clear(player)
-- players[name].last_action = minetest.get_gametime()
minetest.set_player_privs(name, gd.privs)
toggle_hud(player)
set_nametag(player, {a=255,r=57,g=255,b=20})
end
pd.counters[game] = (pd.counters[game] or 0) -- initialise
gamehub.tmr[name] = minetest.get_us_time() -- timestamp
-- update current pos details
gamehub.player[name].pos = vector.round(player:get_pos())
gamehub.player[name].facing.h = player:get_look_horizontal()
gamehub.player[name].facing.v = player:get_look_vertical()
end
tp(player, game)
-- update
gamehub.game[game].played = gd.played + 1
dirty[game] = dirty[game] or {}
dirty[game].played = true
-- log event
minetest.log("action", table.concat({name,"entered",game}, " "))
end
-- Load a player from the db, initialising if reqd
-- @param name: player name
-- @return nothing
local load_player = function(name)
local r = gamehub.load_player(name)
if r then
-- split privs from player data
gamehub.player[name] = r
gamehub.privs[name] = r.privs
gamehub.player[name].privs = nil
else
gamehub.new_player(name)
end
-- load players bank account
gamehub.load_bank_account(name)
if not gamehub.bank[name] then
gamehub.new_bank_account(name)
end
-- check if timestamp is reqd
if gamehub.player[name].game ~= "world" then
gamehub.tmr[name] = minetest.get_us_time() -- timestamp
end
end
-- Fetch a form context, initialising if reqd
-- @param name: player name
-- @return current state as a table
local get_context = function(name)
local state = context[name]
if not state then
state = {index = -1}
context[name] = state
end
return state
end
-- check if stats needs initialising
if not gamehub.stats then
gamehub.stats = {}
gamehub.new_stats_data()
end
-- Check node timers, initialising if reqd
-- @return nothing
local function check_node_timers()
for k,v in pairs(gamehub.game) do
local rpad = v.data.rpad
local stages = v.data.stages
if rpad and rpad.pos then
local tmr = minetest.get_node_timer(rpad.pos)
if not tmr:is_started() then
tmr:start(1)
end
end
if stages then
for i,stage in ipairs(stages) do
local tmr = minetest.get_node_timer(stage.pos)
if not tmr:is_started() then
tmr:start(1)
end
end
end
end
end
-- check node timers are all running after loading all mods
minetest.after(0, check_node_timers)
-- Custom sort function
-- @param a: first list element
-- @param b: second list element
-- @return true if first element comes before second in final order
local function mysort(a, b)
return a.time < b.time
end
--[[
--------------
Timers
--------------
]]
-- Update players hud
-- @return nothing
local function p_hud()
for k,v in pairs(gamehub.player) do
local player = minetest.get_player_by_name(k)
local active = hud[k]
if v.game ~= "world" then
local g = gamehub.game[v.game]
local len = v.game:len() + 8
local limit = g.reward * g.cap
local gtext = ([[
%s Info:
Pays: %s
Limit: %s
Plays: %s
Wins: %s
]]):format(v.game, g.reward, limit, g.played, g.completed)
if active then
player:hud_change(active.gtext, "text", gtext)
else
local mply = 1
if len > 17 then
mply = mply + (len-10) * 0.05
end
hud[k] = {}
hud[k].bg = player:hud_add({
hud_elem_type = "image",
name = "bg",
text = "hub_bg.png",
scale = {x=(1 * mply), y=1},
position = {x=0.815 + (mply-1), y=0.285},
alignment = {x=0, y=0},
offset = {x=0, y=0}
})
hud[k].gtext = player:hud_add({
hud_elem_type = "text",
name = "g_hud",
scale = {x=100, y=100},
text = gtext,
number = 0x00FF00,
position = {x=0.8, y=0.3},
alignment = {x=0, y=0},
offset = {x=0, y=0}
})
end
elseif active then
-- cleanup
player:hud_remove(active.gtext)
player:hud_remove(active.bg)
hud[k] = nil
end
end
minetest.after(1, p_hud)
end
p_hud() -- start
-- Check for dirty game data & save
-- @return nothing
local function save_tmr()
local k, v = next(dirty)
if k and v then
if v.played then
gamehub.update_game_played(k)
end
if v.completed then
gamehub.update_game_completed(k)
end
if v.stats then
gamehub.update_stats()
end
dirty[k] = nil
end
minetest.after(15, save_tmr)
end
save_tmr() -- start
if not playerplus then
-- hurt players near cactus
local function player_tmr()
local pos, near
for _,player in ipairs(minetest.get_connected_players()) do
pos = player:get_pos()
near = minetest.find_node_near(pos, 1, "default:cactus")
if near then
for _,obj in ipairs(minetest.get_objects_inside_radius(near, 1.1)) do
if obj:is_player() and obj:get_hp() > 0 then
obj:set_hp(obj:get_hp() - 2)
end
end
end
end
minetest.after(1, player_tmr)
end
player_tmr()
end
--[[
-----------------------------
API
-----------------------------
]]
-- Process player game time for leaderboard
-- @param name: player name string
-- @returns nothing
gamehub.process_stats = function(name)
local input = gamehub.tmr[name]
if not input then
minetest.log("warning", name .. " doesn't have a registered timer!")
return
end
local result = (minetest.get_us_time() - input ) / 1000000
local game = gamehub.player[name].game
local gstat = gamehub.stats[game] or {}
if #gstat < HSMD or result < gstat[#gstat].time then
local record = {
name = name,
time = result,
date = os.time()
}
table.insert(gstat, record)
if #gstat > 1 then
table.sort(gstat, mysort)
end
if #gstat > HSMD then
table.remove(gstat, #gstat)
end
gamehub.stats[game] = gstat
dirty[game] = dirty[game] or {}
dirty[game].stats = true
end
gamehub.tmr[name] = nil -- cleanup
end
-- Reward player on game completion
-- @param name: player name
-- @param game: game player completed
-- @return nothing
gamehub.player_reward = function(name, game)
local limit = gamehub.game[game].cap
local reward = gamehub.game[game].reward
local counters = gamehub.player[name].counters[game] or 0
local msg
-- cache
gamehub.game[game].completed = gamehub.game[game].completed + 1
-- set dirty flag
dirty[game] = dirty[game] or {}
dirty[game].completed = true
-- limit check
if counters >= limit then
msg = name .. " completed " .. game
else
-- increment
counters = counters + 1
gamehub.player[name].counters[game] = counters
-- add reward
gamehub.bank[name].coins = gamehub.bank[name].coins + reward
msg = name .. " was rewarded for finishing " .. game
minetest.sound_play("shop_pay", {
to_player = name,
gain = 0.2,
loop = false
})
end
-- broadcast
minetest.chat_send_all(msg)
end
-- Enter normal mode
-- @param name: player name
-- @return nothing
gamehub.enter_world = function(name)
-- return players normal privs, position and inventory
local player = minetest.get_player_by_name(name)
local old_game = gamehub.player[name].game
tp(player, "world")
minetest.log("action", table.concat({name, " exited ", old_game}))
if not gamehub.privs[name].hub_mod then
minetest.set_player_privs(name, gamehub.privs[name])
set_nametag(player, {a=255,r=255,g=255,b=255})
inventory_restore(player)
end
end
-- Construct game menu formspec
-- @param name: player name
-- @return formspec string
gamehub.get_menu_formspec = function(name)
local fs = get_context(name)
local list = {}
local bgimg = ""
-- create an ipair copy
for k,v in pairs(gamehub.game) do
if v.active == true then
list[#list+1] = v
end
end
if #list > 0 and not fs.list then
context[name].list = list
fs = get_context(name)
end
if default and default.gui_bg_img then
bgimg = default.gui_bg_img
end
local f = {"size[8,5.5]"}
f[#f+1] = bgimg
f[#f+1] = "label[0,0;Games Menu]"
-- contents?
if #list > 0 then
f[#f+1] = "textlist[0,0.5;3,5;games;"
for _,v in ipairs(list) do
f[#f+1] = v.name
f[#f+1] = ","
end
f[#f] = ";" -- replace last comma
f[#f+1] = fs.index
f[#f+1] = "]" -- finalise textlist
-- content?
if fs.index > 0 then
f[#f+1] = "textarea[3.5,0.4;5,4;;Info:;"
f[#f+1] = "Author: "
f[#f+1] = list[fs.index].author
f[#f+1] = "\n"
f[#f+1] = "Credits: "
f[#f+1] = list[fs.index].credits
f[#f+1] = "\n"
f[#f+1] = "Type: "
f[#f+1] = list[fs.index].type
f[#f+1] = "\n"
f[#f+1] = "Description: "
f[#f+1] = list[fs.index].description
f[#f+1] = "\n"
f[#f+1] = "]"
f[#f+1] = "button_exit[3.3,4.9;1.5,0.5;play;Play]"
end
else
f[#f+1] = "textarea[3.5,0.4;3.2,4;;Info:;No games have been added yet]"
end
f[#f+1] = "button_exit[5,4.9;1.5,0.5;quit;Close]"
return table.concat(f)
end
-- Construct add game formspec
-- @param name: player name
-- @return formspec string
gamehub.get_add_formspec = function(name)
local f = {"size[8.5,7]"}
f[#f+1] = "field[0.5,-0.9;3,0.5;game;Game;"..name.."]"
f[#f+1] = "field[0.5,0.9;3,0.5;author;Author;]"
f[#f+1] = "textarea[0.5,1.7;6,1;credits;Credits:;]"
f[#f+1] = "textarea[0.5,3;6,1.5;desc;Description:;]"
f[#f+1] = "textarea[0.5,4.8;6,1;privs;Privileges:;interact,shout]"
f[#f+1] = "textarea[0.5,6.2;6,1;items;Items:;]"
f[#f+1] = "label[6.5,0;Type:]"
f[#f+1] = "label[6.5,1.35;Active:]"
f[#f+1] = "field[6.8,3.5;1.5,0.5;reward;Reward;]"
f[#f+1] = "field[6.8,4.7;1.5,0.5;cap;Limit;]"
f[#f+1] = "dropdown[6.5,0.5;1.5;type;puzzle,parkour,dropper,combo,pvp;1]"
f[#f+1] = "dropdown[6.5,1.8;1.5;active;false,true;1]"
f[#f+1] = "button_exit[6.5,6.15;2,1;save;Save]"
return table.concat(f)
end
-- Construct edit game formspec
-- @param name: player name
-- @return formspec string
gamehub.get_edit_formspec = function(param)
local type = {"puzzle","parkour","dropper","combo","pvp"}
local t_select, a_select
for i,v in ipairs(type) do
if v == gamehub.game[param].type then
t_select = i
end
end
a_select = 1
if gamehub.game[param].active == true then
a_select = 2
end
local reward, cap
reward = gamehub.game[param].reward or 0
cap = gamehub.game[param].cap or 0
local priv_string = minetest.privs_to_string(gamehub.game[param].privs)
local f = {"size[8.5,7]"}
f[#f+1] = "field[0.5,-1;3,0.5;game;Game;"
f[#f+1] = gamehub.game[param].name
f[#f+1] = "]"
f[#f+1] = "field[0.5,0.9;3,0.5;author;Author;"
f[#f+1] = gamehub.game[param].author
f[#f+1] = "]"
f[#f+1] = "textarea[0.5,1.7;6,1;credits;Credits:;"
f[#f+1] = gamehub.game[param].credits
f[#f+1] = "]"
f[#f+1] = "textarea[0.5,3;6,1.5;desc;Description:;"
f[#f+1] = gamehub.game[param].description
f[#f+1] = "]"
f[#f+1] = "textarea[0.5,4.8;6,1;privs;Privileges:;"
f[#f+1] = priv_string
f[#f+1] = "]"
f[#f+1] = "textarea[0.5,6.2;6,1;items;Items:;"
f[#f+1] = gamehub.game[param].items
f[#f+1] = "]"
f[#f+1] = "label[6.5,0;Type:]"
f[#f+1] = "dropdown[6.5,0.5;1.5;type;puzzle,parkour,dropper,combo,pvp;"
f[#f+1] = t_select
f[#f+1] = "]"
f[#f+1] = "label[6.5,1.35;Active:]"
f[#f+1] = "dropdown[6.5,1.8;1.5;active;false,true;"
f[#f+1] = a_select
f[#f+1] = "]"
f[#f+1] = "field[6.8,3.5;1.5,0.5;reward;Reward;"
f[#f+1] = reward
f[#f+1] = "]"
f[#f+1] = "field[6.8,4.7;1.5,0.5;cap;Limit;"
f[#f+1] = cap
f[#f+1] = "]"
f[#f+1] = "button_exit[6.5,6.15;2,1;save;Save]"
return table.concat(f)
end
-- Construct stats formspec
-- @param name: player name
-- @return formspec string
gamehub.get_stats_formspec = function(name)
local fs = get_context(name)
if fs.index == -1 then fs.index = 1 end
local list = {}
local key = {}
for k,v in pairs(gamehub.stats) do
key[#key+1] = k
list[#list+1] = v
end
for i,v in ipairs(list) do
table.sort(v, mysort)
end
local f = {"size[8,7]"}
f[#f+1] = "label[3,0;High Scores]"
f[#f+1] = "label[0.45,0.5;Game:]"
f[#f+1] = "textlist[0.45,1;7,5;stats;"
if #list > 0 then
fs.count = #list
for i,v in ipairs(list[fs.index]) do
f[#f+1] = i
f[#f+1] = ". "
f[#f+1] = v.name
local x = 15 - string.len(v.name)
for y = 1,x do
f[#f+1] = " "
end
f[#f+1] = v.time
f[#f+1] = " s "
f[#f+1] = os.date("%d-%m-%Y %H:%M:%S", v.date)
f[#f+1] = ","
end
else
f[#f+1] = "No statistics available!"
f[#f+1] = ","
end
f[#f] = ";" -- replace last comma
f[#f+1] = "-1"
f[#f+1] = "]" -- finalise textlist
if #list > 0 then
f[#f+1] = "label[1.5,0.5;"
f[#f+1] = key[fs.index]
f[#f+1] = "]"
end
if #list > 1 then
f[#f+1] = "image_button[6.7,0.5;0.5,0.5;hub_left_icon.png;left;]"
f[#f+1] = "image_button[7.1,0.5;0.5,0.5;hub_right_icon.png;right;]"
end
f[#f+1] = "button_exit[3,6.5;2,0.5;quit;Close]"
return table.concat(f)
end
-- Find area id by name
-- @param name: area name
-- @return id as integer
gamehub.get_id = function(name)
for id,area in ipairs(areas.areas) do
if area.name == name then
return id
end
end
end
-- Find area at position
-- @param pos: vector table
-- @return area, area count
gamehub.area_at_pos = function(pos)
local areas = areas:getAreasAtPos(pos)
local ctr = 0
local result
for _, area in pairs(areas) do
if not result then result = area end
ctr = ctr + 1
end
return result, ctr
end
--[[
-----------------------------
CALLBACK REGISTRATIONS
-----------------------------
]]
-- forms
minetest.register_on_player_receive_fields(function(player, formname, fields)
-- validate, unified inventory uses forms with no formname
-- additionally we are only interested in our forms!
if formname == "" or
formname ~= "hub:add" and
formname ~= "hub:edit" and
formname ~= "hub:menu" and
formname ~= "hub:stats" then
return
end
if formname == "hub:add" then
-- security check
local name = player:get_player_name()
if not gamehub.privs[name].hub_admin then
minetest.log("warning",
"[gamehub] Received fields from unauthorized user: "..name)
return
end
-- catch missing reqd fields
if not fields.save then return end -- button pressed?
if not fields.game then return end -- data?
-- form fields reqd for new entry
local pos = vector.round(player:get_pos())
local res = areas:getAreasAtPos(pos)
local area, facing
facing = {
h = player:get_look_horizontal(),
v = player:get_look_vertical()
}
local _,v = next(res)
area = v
if not area then
minetest.chat_send_player(name, "You must create an area first!")
return
end
-- create record
local data = {
name = area.name,
type = fields.type,
pos = pos,
facing = facing,
reward = tonumber(fields.reward),
cap = tonumber(fields.cap),
privs = minetest.string_to_privs(fields.privs),
author = fields.author,
credits = fields.credits,
description = fields.desc,
created = os.time(),
played = 0,
completed = 0,
items = fields.items,
active = fields.active == "true",
data = {
pos1 = area.pos1,
pos2 = area.pos2
}
}
gamehub.new_game(data)
-- add node
pos.y = pos.y - 1.5
minetest.set_node(pos, {name="default:cloud"})
-- inform player of status
minetest.chat_send_player(name, data.name ..
" position set at " .. minetest.pos_to_string(pos))
elseif formname == "hub:edit" then
-- security check
local name = player:get_player_name()
if not gamehub.privs[name].hub_admin then
minetest.log("warning",
"[gamehub] Received fields from unauthorized user: "..name)
return
end
if not fields.save then return end -- button pressed?
local game = gamehub.game[fields.game]
game.type = fields.type
game.privs = fields.privs
game.author = fields.author
game.credits = fields.credits
game.description = fields.desc
game.reward = tonumber(fields.reward)
game.cap = tonumber(fields.cap)
game.items = fields.items
game.active = fields.active == "true"
if not game.data.pos1 then
local id = gamehub.get_id(game.name)
local area = areas.areas[id]
game.data = {
pos1 = area.pos1,
pos2 = area.pos2
}
end
gamehub.game[fields.game] = game
gamehub.update_game_form(game)
elseif formname == "hub:menu" then
local name = player:get_player_name()
local fs = get_context(name)
local ev = minetest.explode_textlist_event(fields.games)
if ev.type == "CHG" or ev.type == "DCL" then
-- update
fs.index = ev.index
minetest.show_formspec(name, "hub:menu", gamehub.get_menu_formspec(name))
end
if fields.play then
enter_game(name, fs.list[fs.index].name)
end
elseif formname == "hub:stats" then
local name = player:get_player_name()
local fs = get_context(name)
if fields.left then
if fs.index == 1 then
fs.index = fs.count -- loop
else
fs.index = fs.index - 1
end
elseif fields.right then
if fs.index == fs.count then
fs.index = 1 -- loop
else
fs.index = fs.index + 1
end
elseif fields.quit then
return
end
minetest.show_formspec(name, "hub:stats", gamehub.get_stats_formspec(name))
end
return true -- return handled
end)
--load
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
load_player(name)
tp(player, gamehub.player[name].game)
end)
-- unload
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
-- save
gamehub.update_on_leaveplayer(player)
gamehub.update_bank_account(name)
-- cleanup
gamehub.player[name] = nil
gamehub.privs[name] = nil
end)
-- respawn
minetest.register_on_respawnplayer(function(player)
if not player then return true end
local name = player:get_player_name()
--handle jailed players
if gamehub.jail.roll[name] then return end
if gamehub.player[name] then
local game = gamehub.player[name].game
-- reset player position
tp(player, game)
-- reset health
player:set_hp(20)
if game ~= 'world' and not gamehub.privs[name].hub_mod then
--reset players game timestamp
gamehub.tmr[name] = minetest.get_us_time()
end
return true -- return as handled
end
end)