1016 lines
24 KiB
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)
|