change gameplay mechanics

master
MisterE123 2021-03-11 04:58:55 -05:00
parent 4ccbc012ab
commit f0984828e5
8 changed files with 542 additions and 69 deletions

View File

@ -64,3 +64,40 @@ end, {
]],
privs = { wormball_admin = true }
})
minetest.register_chatcommand("wormball_leaderboard", {
params = "<arena_name>",
description = [[
View the singleplayer leaderboard of a wormball arena
- arena_name -- must be a valid wormball arena name
]],
privs = {},
func = function( name , arena_name)
if not wormball.show_singleplayer_leaderboard( arena_name , name ) then
return "Invalid usage: please specify a valid wormball arena name to view its leaderboard."
end
end,
})
minetest.register_chatcommand("wormball_multiscores", {
params = "<arena_name>",
description = [[
View the scores of players of the last game played in a wormball arena
- arena_name -- must be a valid wormball arena name
]],
privs = {},
func = function( name , arena_name)
if not arena_lib.get_arena_by_name('wormball', arena_name ) then return "Invalid usage: please specify a valid wormball arena name to view its leaderboard." end
local arena_id, arena = arena_lib.get_arena_by_name('wormball', arena_name )
if not arena.multi_scores or arena.multiscores == {} then return "no scores found!" end
if not wormball.show_multi_scores( arena , name , arena.multi_scores ) then
return "Invalid usage: please specify a valid wormball arena name to view its leaderboard."
end
return "error"
end,
})

View File

@ -1,11 +1,12 @@
wormball = {}
wormball.HUD = {}
dofile(minetest.get_modpath("wormball") .. "/globals.lua")
arena_lib.register_minigame("wormball", {
prefix = "[Wormball] ",
--hub_spawn_point = { x = 0, y = 20, z = 0 },
show_minimap = false,
time_mode = 'decremental',
time_mode = 'incremental',
load_time = 5,
min_players = 1,
max_players = 10,
@ -18,37 +19,40 @@ dofile(minetest.get_modpath("wormball") .. "/globals.lua")
sneak = false,
gravity = 1,
},
spectate_mode = false,
spectate_mode = true,
show_nametags = false,
hotbar = {
slots = 1,
},
celebration_time =10,
celebration_time = 10,
disabled_damage_types = {"punch","fall"},
properties = {
area_to_clear_after_game_pos_1 = {x = 0, y = 0, z = 0},
area_to_clear_after_game_pos_2 = {x = 0, y = 0, z = 0},
min_food_factor = 2,
min_food = 20,
highscores = {
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
{'pl_name_placeholder',0},
singleplayer_leaderboard = {},
-- highscores = {
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
-- {'pl_name_placeholder',0},
},
-- },
},
temp_properties = {
mode = 'singleplayer',
dots = {},
num_players = 0,
time_to_next_elim = 60,
multi_scores = {},
},
initial_time = 300,
@ -59,10 +63,11 @@ dofile(minetest.get_modpath("wormball") .. "/globals.lua")
nodes = {},
score = 1,
color = "",
apple = false,
--apple = false,
--textures= {},
move = true,
attached = false,
eliminated = false,
},
})

View File

@ -11,7 +11,7 @@ dofile(minetest.get_modpath("wormball") .. "/minigame_manager/globalstep.lua")
dofile(minetest.get_modpath("wormball") .. "/minigame_manager/on_eliminate.lua")
dofile(minetest.get_modpath("wormball") .. "/minigame_manager/on_timeout.lua")
--dofile(minetest.get_modpath("wormball") .. "/minigame_manager/on_timeout.lua")
dofile(minetest.get_modpath("wormball") .. "/minigame_manager/on_disconnect.lua")

View File

@ -7,10 +7,12 @@
minetest.register_globalstep(function(dtime)
--every server_step, check if the players in-game are attached to their worm heads. Iff they are not, then spawn a new entity and attach them
--note, the entities have a 10 min timeout (wormball games last 5 min). A MT 5.3 engine bug can detach players unexpectedly, this is a workaround.
for _,player in ipairs(minetest.get_connected_players()) do
local pl_name = player:get_player_name()
@ -28,8 +30,34 @@ minetest.register_globalstep(function(dtime)
end
end
end
-- -- this makes spectating possible... Hopefully, and needs testing
if arena_lib.is_player_in_arena(pl_name, "wormball") and arena_lib.is_player_spectating(pl_name) then
local att = player:get_attach()
if att and att:is_player() then
local attatt = att:get_attach()
if attatt and attatt:get_luaentity() and attatt:get_luaentity().name and attatt:get_luaentity().name == "wormball:player_att" then
player:set_attach(attatt)
end
end
end
end
--clear HUDs when not needed
for _,player in ipairs(minetest.get_connected_players()) do
local p_name = player:get_player_name()
if not arena_lib.is_player_in_arena(p_name, "wormball") then
if wormball.HUD[p_name] then
player:hud_remove(wormball.HUD[p_name].scores)
wormball.HUD[p_name] = nil
end
end
end
--we will only run worm movement code about every 0.4 seconds, if not 0.4 seconds yet; return
@ -68,6 +96,11 @@ minetest.register_globalstep(function(dtime)
local died --used to determine whether to elim player
if stats.eliminated == true then
died = true
arena.players[pl_name].eliminated = false
end
-- if players are alive, move the worms (add to the length, subtract from the tail)
@ -289,7 +322,7 @@ minetest.register_globalstep(function(dtime)
if tail_pos then --nil check
-- if the player is dead, then we will slowly convert them into food (of their color)
-- if the player is dead, then we will convert them into food (of their color)
-- if they are still alive, then we will place air there to delete the tail
if arena.players[pl_name].alive == false then
local item = "wormball:power_"..color
@ -305,8 +338,12 @@ minetest.register_globalstep(function(dtime)
-- if players have no nodes, eliminate them. (this can happen if they eat a 'bad' dot while only 1 long) if they have run into an obstacle, elim also
if #arena.players[pl_name].nodes == 0 or died == true then --if you eat a bad powerup with only 1 point, then you lose!
minetest.chat_send_player(pl_name, 'Game Over! Your score is '..arena.players[pl_name].score)
minetest.chat_send_player(pl_name, "You did not make the highscore list because you did not survive for the full game! Try again!")
if arena.mode and arena.mode == 'singleplayer' then
minetest.chat_send_player(pl_name, 'Game Over! Your score is '..arena.players[pl_name].score)
end
--esp for multiplayer games, save the score in the record for end of game documentation.
table.insert( arena.multi_scores , 1 , { arena.players[ pl_name ] .score , pl_name } )
for _,node_pos in pairs(arena.players[pl_name].nodes) do
local item = "wormball:power_"..color
@ -314,15 +351,21 @@ minetest.register_globalstep(function(dtime)
end
arena.players[pl_name].alive = false
wormball.detach(pl_name)
minetest.sound_play('sumo_lose', {
to_player = pl_name,
gain = 2.0,
})
minetest.after(.3,function(pl_name)
arena_lib.remove_player_from_arena(pl_name, 1)
wormball.detach(pl_name)
if arena.mode == 'multiplayer' then
minetest.sound_play('sumo_lose', {
to_player = pl_name,
gain = 2.0,
})
end
minetest.after(.3,function(pl_name, arena)
if arena.mode == 'singleplayer' then
arena_lib.load_celebration('wormball', arena, pl_name)
else
arena_lib.remove_player_from_arena(pl_name, 1)
end
end,pl_name)
end,pl_name, arena)
end
end

View File

@ -1,3 +1,130 @@
-- scoreboards
local storage = minetest.get_mod_storage()
wormball.show_multi_scores = function( arena , player , scores )
local leaderboard = scores
--minetest.chat_send_all(dump(arena))
local player_list = ""
if not leaderboard or not leaderboard[1] then return end
for idx , winner_table in ipairs( leaderboard ) do
local max_len = 30
local p_name = winner_table [ 2 ]
local name_len = string.len( winner_table [ 2 ] )
if name_len > 20 then
p_name = string.sub(p_name, 1, 20)
name_len = 20
end
local pts = tostring( winner_table [ 1 ] )
local pts_len = string.len( pts )
local spaces = max_len - name_len - pts_len
player_list = player_list .. p_name
for i = 1, spaces do
player_list = player_list .. " "
end
player_list = player_list .. pts .. ","
end
local formspec = "formspec_version[4]"..
"size[8,9]"..
"box[0,0;8,1;#ff4800]"..
"label[2.5,0.5;Multiplayer Scores]"..
"box[0,1;8,1;#ff8000]"..
"label[3,1.5;" .. arena.name .. "]"..
"box[0,2;8,7;#191359]"..
"textlist[0.5,2.5;7,6;;".. player_list ..";1;true]"
minetest.show_formspec(player, 'multiscoreboard', formspec)
end
wormball.show_singleplayer_leaderboard = function( arena_name , playername )
if not arena_lib.get_arena_by_name('wormball', arena_name ) then return false end
local arena_id, arena = arena_lib.get_arena_by_name('wormball', arena_name )
local leaderboard = arena.singleplayer_leaderboard
--minetest.chat_send_all(dump(arena))
local player_list = ""
if not leaderboard or not leaderboard[1] then return end
for idx , winner_table in ipairs( leaderboard ) do
local max_len = 30
local p_name = winner_table [ 2 ]
local name_len = string.len( winner_table [ 2 ] )
if name_len > 20 then
p_name = string.sub(p_name, 1, 20)
name_len = 20
end
local pts = tostring( winner_table [ 1 ] )
local pts_len = string.len( pts )
local spaces = max_len - name_len - pts_len
player_list = player_list .. p_name
for i = 1, spaces do
player_list = player_list .. " "
end
player_list = player_list .. pts .. ","
end
local formspec = "formspec_version[4]"..
"size[8,9]"..
"box[0,0;8,1;#ff4800]"..
"label[3,0.5;Leaderboard]"..
"box[0,1;8,1;#ff8000]"..
"label[3,1.5;" .. arena_name .. "]"..
"box[0,2;8,7;#191359]"..
"textlist[0.5,2.5;7,6;;".. player_list ..";1;true]"
minetest.show_formspec(playername, 'scoreboard', formspec)
end
arena_lib.on_celebration('wormball', function(arena, winner_name)
--reset player textures back to the texture they were... (wormball sets player textures to clear)
@ -14,39 +141,182 @@ arena_lib.on_celebration('wormball', function(arena, winner_name)
if type(winner_name) == 'string' then
--Highscores are stored per number of players...
--in a crash report, highscore was nil... WHY!? #BUG
--crash (hopefully) prevented with nil check... place debug code here
--note: crash occured when arena edit mode was entered while arena had crashed due to another bug, and the arena was still active (in_celebration)
--note2: this will also prevent crashes due to arena editors messing with the highscores table.
local highscore = arena.highscores[arena.num_players]
if not highscore then --nil check
arena.highscores[arena.num_players] = {'pl_name_placeholder',0}
highscore = {'pl_name_placeholder',0}
if arena.mode == 'singleplayer' then
-- leaderboard will be a table with the following format
-- {
-- {score,plname}
-- {score,plname}
-- }
-- it will always be ordered, with the highest score first.
local new_highscore = false
local leaderboard = arena.singleplayer_leaderboard
local score = arena.players [ winner_name ] .score
if not leaderboard then leaderboard = {} end
if # leaderboard == 0 then
leaderboard [ 1 ] = { score , winner_name }
new_highscore = true
else
local insert = true
for idx , winner_table in ipairs( leaderboard ) do
if winner_table [ 2 ] == winner_name then --if the player already has a score on the board...
if score > winner_table[1] then -- new higher score achieved... we will now remove the old score so we can input the new score at the correct location
table.remove(leaderboard , idx )
else -- the score wasn't higher, so no need to insert a new score
insert = false
end
end
end
if insert then
for idx , winner_table in ipairs( leaderboard ) do
if score > winner_table [ 1 ] then
table.insert( leaderboard , idx , { score , winner_name } )
if idx == 1 then
new_highscore = true
end
break
end
end
end
end
--arena_lib.change_arena_property(winner_name, 'wormball', arena.name, "singleplayer_leaderboard", leaderboard)
-- arena_lib.change_arena_property('wormball' , 'wormball' , arena.name , "singleplayer_leaderboard" , leaderboard )
--save (update) the highscore data to disk
local wormball_highscores = storage:get_string("wormball_highscores") or {}
if wormball_highscores ~= {} then
wormball_highscores = minetest.deserialize(wormball_highscores)
end
wormball_highscores [ arena.name ] = arena.singleplayer_leaderboard
local serial = minetest.serialize(wormball_highscores)
storage:set_string("wormball_highscores", serial)
if new_highscore then
arena_lib.HUD_send_msg_all("title", arena, 'New High Score!', 2 ,'sumo_win',0xAEAE00)
else
arena_lib.HUD_send_msg_all("title", arena, 'Game Over!', 2 ,'sumo_win',0xAEAE00)
end
minetest.after( 3 , function( arena , score , leaderboard )
arena_lib.HUD_send_msg_all("title", arena , 'You had ' .. score .. ' pts!', 3 ,'sumo_win',0xAEAE00)
minetest.after( 3 , function( arena , score , leaderboard )
for pl_name , stats in pairs(arena.players_and_spectators) do
wormball.show_singleplayer_leaderboard( arena.name , pl_name )
end
end , arena , score , leaderboard )
end , arena , score , leaderboard )
else --arena.mode == 'multiplayer'
arena_lib.HUD_send_msg_all("title", arena, 'New High Score!', 2 ,'sumo_win',0xAEAE00)
local scores = arena.multi_scores
if minetest.get_modpath( 'panel_lib' ) then
minetest.after( 2 , function( arena , scores )
for pl_name , stats in pairs(arena.players_and_spectators) do
wormball.show_multi_scores( arena , pl_name , scores )
end
-- show the scoreboard here
end , arena , scores )
end
end
--old highscore info if existing
local high_name = highscore[1] or ''
local high_num = highscore[2] or 0
--current winner pts
local winner_pts = arena.players[winner_name].score
--HUD info sent to players
arena_lib.HUD_send_msg_all("title", arena, winner_name..' won with '..winner_pts.. ' pts!', 9,'sumo_win',0xAEAE00)
arena_lib.HUD_send_msg_all("hotbar", arena, 'Highscore: '..high_name.. ' '..high_num, 9,nil,0x0000FF)
--if highscore was broken, 2 sec later, another HUD info abt that...
if high_num < winner_pts then
--set highscore info
arena.highscores[arena.num_players] = {winner_name,winner_pts} --could this have cause the bug?
minetest.after(2,function(arena,winner_name,winner_pts)
arena_lib.HUD_send_msg_all("title", arena, 'NEW HIGH SCORE '.. arena.num_players ..' PLAYER!', 7,'sumo_win',0xAEAE00)
arena_lib.HUD_send_msg_all("hotbar", arena, 'Highscore: '..winner_name.. ' '..winner_pts, 7,nil,0x0000FF)
end,arena,winner_name,winner_pts)
end
-- --Highscores are stored per number of players...
-- --in a crash report, highscore was nil... WHY!? #BUG
-- --crash (hopefully) prevented with nil check... place debug code here
-- --note: crash occured when arena edit mode was entered while arena had crashed due to another bug, and the arena was still active (in_celebration)
-- --note2: this will also prevent crashes due to arena editors messing with the highscores table.
-- local highscore = arena.highscores[arena.num_players]
-- if not highscore then --nil check
-- local highscore_tbl = arena.highscores
-- highscore_tbl[arena.num_players] = {'pl_name_placeholder',0}
-- arena_lib.change_arena_property(nil, 'wormball', arena.name, highscores, highscore_tbl)
-- if arena.mode == 'singleplayer' then
-- local splb = arena.singleplayer_leaderboard
-- table.insert(splb, {})
-- highscore = {'pl_name_placeholder',0}
-- end
-- --old highscore info if existing
-- local high_name = highscore[1] or ''
-- local high_num = highscore[2] or 0
-- --current winner pts
-- local winner_pts = arena.players[winner_name].score
-- --HUD info sent to players
-- arena_lib.HUD_send_msg_all("title", arena, winner_name..' won with '..winner_pts.. ' pts!', 9,'sumo_win',0xAEAE00)
-- arena_lib.HUD_send_msg_all("hotbar", arena, 'Highscore: '..high_name.. ' '..high_num, 9,nil,0x0000FF)
-- --if highscore was broken, 2 sec later, another HUD info abt that...
-- if high_num < winner_pts then
-- --set highscore info
-- arena.highscores[arena.num_players] = {winner_name,winner_pts} --could this have cause the bug?
-- minetest.after(2,function(arena,winner_name,winner_pts)
-- arena_lib.HUD_send_msg_all("title", arena, 'NEW HIGH SCORE '.. arena.num_players ..' PLAYER!', 7,'sumo_win',0xAEAE00)
-- arena_lib.HUD_send_msg_all("hotbar", arena, 'Highscore: '..winner_name.. ' '..winner_pts, 7,nil,0x0000FF)
-- end,arena,winner_name,winner_pts)
-- end
end

View File

@ -1,4 +1,4 @@
local storage = minetest.get_mod_storage()
local function send_message(arena,num_str)
arena_lib.HUD_send_msg_all("title", arena, "Game Begins In "..num_str, 1,nil,0xFF0000)
-- ref: arena_lib.HUD_send_msg_all(HUD_type, arena, msg, <duration>, <sound>, <color>)
@ -6,6 +6,25 @@ end
arena_lib.on_load("wormball", function(arena)
-- load the saved highscore data from disk
local wormball_highscores = storage:get_string("wormball_highscores") or {}
local leaderboard = {}
if wormball_highscores ~= {} then
wormball_highscores = minetest.deserialize(wormball_highscores)
local leaderboard = wormball_highscores [ arena.name ]
if not leaderboard then
leaderboard = {}
end
end
arena.singleplayer_leaderboard = leaderboard
--HUD countdown
send_message(arena,'5')
minetest.after(1, function(arena)
@ -110,6 +129,15 @@ arena_lib.on_load("wormball", function(arena)
arena.mode = 'multiplayer'
end
idx = idx + 1
end
--disable spectate for singleplayer, allow it for multiplayer. Spectate is buggy with singleplayer... but works with multi now.
if arena.mode == 'singleplayer' then
arena.spectate_mode = false
else
arena.spectate_mode = true
end
end)

View File

@ -4,21 +4,111 @@ arena_lib.on_time_tick('wormball', function(arena)
----------------------------------------------
----------------------------------------------
-- send HUD with time, set color based on time left
-- send HUD with highscore and scores of current players
----------------------------------------------
----------------------------------------------
local c = 0x00FF00
if arena.current_time < 60 then
c = 0xFFFF00
local string = ""
if arena.mode == 'singleplayer' then
local leader = arena.singleplayer_leaderboard[1]
if leader then
string = "highscore: ".. leader[1] .. "\n"
end
end
if arena.current_time < 10 then
c = 0xFF0000
local scores = nil
for pl_name, stats in pairs(arena.players) do
if stats.score then
local score_info = {pl_name,stats.score}
if not scores then
scores = {score_info}
else
local inserted = false
for idx , score_tbl in ipairs(scores) do
if score_info[2] >= score_tbl[2] then
table.insert(scores,idx,score_info)
inserted = true
break
end
end
if not inserted then
table.insert(scores,#scores + 1, score_info)
end
end
end
end
if arena.current_time < arena.initial_time - 5 then
arena_lib.HUD_send_msg_all('hotbar', arena, 'TIME: '..arena.current_time, 1,nil,c)
if scores then
for idx,score_tbl in ipairs(scores) do
string = string .. score_tbl[1] .. ": ".. score_tbl[2] .. "\n"
end
end
for pl_name,stats in pairs(arena.players) do
local player = minetest.get_player_by_name(pl_name)
if not wormball.HUD[pl_name] then
--minetest.chat_send_all('we got here')
local new_hud = {}
new_hud.scores = player:hud_add({
hud_elem_type = "text",
position = {x = 0, y = 1},
name = "wormball_highscores",
text = string,
scale = {x = 3, y = 3},
alignment = {x = 1, y = -1},
offset = {x = 5, y = -5}
})
wormball.HUD[pl_name] = new_hud
else
local id = wormball.HUD[pl_name].scores
player:hud_change(id, "text", string)
end
end
------------------------------------------------------------------
--==============================================================--
--========= If in multiplayer, eliminate 1 player every 60 sec
--==============================================================--
------------------------------------------------------------------
if arena.mode == 'multiplayer' and #scores > 1 then --
arena.time_to_next_elim = arena.time_to_next_elim - 1
--minetest.chat_send_all ('we got to here')
--eliminate a player
if arena.time_to_next_elim == 0 then
arena.time_to_next_elim = 60
local pl_name = scores[#scores][1]
local pl_score = scores[#scores][2]
local color = arena.players[ pl_name ].color
minetest.chat_send_player(pl_name, 'Game Over! You were eliminated with ' .. pl_score .. ' pts.')
--this is sufficent to kill them on the next globalstep
arena.players[pl_name].eliminated = true
arena.players[pl_name].alive = false
arena_lib.HUD_send_msg_all('broadcast', arena, pl_name .. ' was eliminated with ' .. pl_score .. ' pts', 2,nil,0xFFFF00)
end
local c = 0x00FF00
if arena.time_to_next_elim <= 10 then
c = 0xFFFF00
end
if arena.time_to_next_elim <= 5 then
c = 0xFF0000
end
if arena.current_time > 5 then
arena_lib.HUD_send_msg_all('hotbar', arena, 'Next Elimination In '.. arena.time_to_next_elim, 1,nil,c)
end
end

View File

@ -1,4 +1,4 @@
name = wormball
description = Wormball subgame
depends = default, arena_lib, player_api, dye
depends_optional = lib_chatcmdbuilder
depends = default, arena_lib, player_api, dye
depends_optional = lib_chatcmdbuilder, panel_lib