parent
edc0dc54bc
commit
a128feb1ad
1
init.lua
1
init.lua
@ -44,7 +44,6 @@ dofile(minetest.get_modpath("fantasy_brawl") .. "/src/deps/visible_wielditem.lua
|
||||
|
||||
dofile(minetest.get_modpath("fantasy_brawl") .. "/src/hud/hud.lua")
|
||||
dofile(minetest.get_modpath("fantasy_brawl") .. "/src/sounds.lua")
|
||||
dofile(minetest.get_modpath("fantasy_brawl") .. "/src/score.lua")
|
||||
dofile(minetest.get_modpath("fantasy_brawl") .. "/src/invulnerability.lua")
|
||||
|
||||
dofile(minetest.get_modpath("fantasy_brawl") .. "/src/utils.lua")
|
||||
|
2
mod.conf
2
mod.conf
@ -1,4 +1,4 @@
|
||||
name = fantasy_brawl
|
||||
depends = skills, arena_lib, controls, panel_lib, hud_fs
|
||||
depends = skills, arena_lib, controls, hud_fs
|
||||
description = The first brawler minigame on Minetest. Choose your class, prepare your skills and defeat them all!
|
||||
author = giov4
|
||||
|
@ -55,7 +55,7 @@ arena_lib.on_celebration("fantasy_brawl", function(arena, winners)
|
||||
end
|
||||
|
||||
for pl_name, _ in pairs(arena.players_and_spectators) do
|
||||
fbrawl.show_podium_HUD(pl_name)
|
||||
fbrawl.show_scoreboard(pl_name)
|
||||
end
|
||||
end)
|
||||
|
||||
@ -63,13 +63,14 @@ end)
|
||||
|
||||
arena_lib.on_death("fantasy_brawl", function(arena, pl_name, reason)
|
||||
arena.classes[pl_name]:on_death(arena, pl_name, reason)
|
||||
fbrawl.update_arena_scores(arena)
|
||||
fbrawl.respawn_player(pl_name)
|
||||
end)
|
||||
|
||||
|
||||
|
||||
arena_lib.on_timeout("fantasy_brawl", function(arena)
|
||||
fbrawl.update_score(arena)
|
||||
fbrawl.update_arena_scores(arena)
|
||||
|
||||
if not arena.scores[2] or (arena.scores[1].score ~= arena.scores[2].score) then
|
||||
arena_lib.load_celebration("fantasy_brawl", arena, arena.scores[1].pl_name)
|
||||
|
@ -4,5 +4,38 @@ ChatCmdBuilder.new("debug", function(cmd)
|
||||
local arena = arena_lib.get_arena_by_player(name)
|
||||
arena.players[name].ultimate_recharge = 5
|
||||
end)
|
||||
end)
|
||||
|
||||
cmd:sub("add_pl :name :score", function(name, target_name, score)
|
||||
local arena = arena_lib.get_arena_by_player("Giov4")
|
||||
if not arena then return end
|
||||
|
||||
score = tonumber(score)
|
||||
if not arena.players[target_name] then
|
||||
arena.players[target_name] = {
|
||||
kills = score,
|
||||
deaths = 0
|
||||
}
|
||||
else
|
||||
arena.players[target_name].kills = arena.players[target_name].kills + score
|
||||
end
|
||||
|
||||
fbrawl.update_arena_scores(arena)
|
||||
end)
|
||||
|
||||
cmd:sub("sounds", function(name)
|
||||
local id = -1
|
||||
local iteration = 0
|
||||
local play = function(self_ref)
|
||||
iteration = iteration + 1
|
||||
local c_id = id
|
||||
id = minetest.sound_play({name="fbrawl_puddle"}, {loop=true, to_player=name})
|
||||
minetest.sound_stop(c_id)
|
||||
if iteration > 20 then
|
||||
minetest.sound_stop(id)
|
||||
return
|
||||
end
|
||||
minetest.after(0.1, self_ref, self_ref)
|
||||
end
|
||||
play(play)
|
||||
end)
|
||||
end)
|
@ -12,7 +12,6 @@ function fbrawl.init_HUD(arena, pl_name, as_spectator)
|
||||
|
||||
local player = minetest.get_player_by_name(pl_name)
|
||||
|
||||
fbrawl.generate_scoreboard(pl_name)
|
||||
fbrawl.generate_timer_HUD(pl_name)
|
||||
if not as_spectator then
|
||||
fbrawl.generate_stats(player, pl_name)
|
||||
@ -53,9 +52,7 @@ function fbrawl.remove_huds(pl_name)
|
||||
player:hud_remove(id)
|
||||
end
|
||||
|
||||
if panel_lib.has_panel(pl_name, "fbrawl:podium") then
|
||||
panel_lib.get_panel(pl_name, "fbrawl:podium"):remove()
|
||||
end
|
||||
hud_fs.close_hud(player, "fantasy_brawl:scoreboard")
|
||||
|
||||
fbrawl.saved_huds[pl_name] = nil
|
||||
end)
|
||||
|
@ -1,157 +1,235 @@
|
||||
function fbrawl.generate_scoreboard(pl_name)
|
||||
local imgs_scale = 4
|
||||
--[[
|
||||
This file implements a dynamic scoreboard HUD that displays player rankings during matches.
|
||||
|
||||
local pl_name_y_offset = 80
|
||||
Features:
|
||||
- displays players ranked by kills, then by score (score = kills - deaths/2)
|
||||
- handles ties correctly: tied players share the same position number and crown
|
||||
- shows crowns for 1st (golden), 2nd (iron), and 3rd (bronze) positions
|
||||
- dynamically adjusts vertical background height based on the number of top-3 positions
|
||||
- highlights the current player's row
|
||||
- shows kills/deaths for each player
|
||||
- shows holding AUX1 key
|
||||
]]
|
||||
|
||||
local crown_x_offset = 16*imgs_scale + 300
|
||||
local crown_y_offset = 16*imgs_scale
|
||||
-- local function prototypes (no prototypes for globals)
|
||||
local function scoreboard_to_ranking(arena) end
|
||||
local function get_crown_material(score_entry, arena) end
|
||||
local function get_podium_count(arena) end
|
||||
local function get_scoreboard_formspec(player_name) end
|
||||
local function show_scoreboard(player_name) end
|
||||
|
||||
local scores_scale = imgs_scale - 1
|
||||
local score_x_offset = 14*scores_scale + 8
|
||||
local score_y_offset = 18*scores_scale + pl_name_y_offset
|
||||
local score_value_y_offset = 14
|
||||
local score_value_x_offset = 16
|
||||
hud_fs.set_scale("fantasy_brawl:scoreboard", 80)
|
||||
local active_scoreboards = {} -- [player_name] = true/nil
|
||||
|
||||
local panel = Panel:new("fbrawl:podium", {
|
||||
player = pl_name,
|
||||
position = {x=0.5, y=0.15},
|
||||
alignment = {x=0, y=0.5},
|
||||
bg_scale = {x = 1000, y = 1000},
|
||||
|
||||
-- IMAGES
|
||||
sub_img_elems = {
|
||||
iron_crown = {
|
||||
scale = {x = imgs_scale, y = imgs_scale},
|
||||
offset = {x = -crown_x_offset, y = crown_y_offset},
|
||||
text = "fbrawl_iron_crown.png",
|
||||
},
|
||||
iron_kills = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = -crown_x_offset - score_x_offset, y = crown_y_offset + score_y_offset},
|
||||
text = "fbrawl_hud_kills_score.png",
|
||||
},
|
||||
iron_deaths = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = -crown_x_offset + score_x_offset, y = crown_y_offset + score_y_offset},
|
||||
text = "fbrawl_hud_deaths_score.png",
|
||||
},
|
||||
|
||||
golden_crown = {
|
||||
scale = {x = imgs_scale, y = imgs_scale},
|
||||
offset = {x = 0, y = 0},
|
||||
text = "fbrawl_golden_crown.png"
|
||||
},
|
||||
golden_kills = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = -score_x_offset, y = score_y_offset},
|
||||
text = "fbrawl_hud_kills_score.png",
|
||||
},
|
||||
golden_deaths = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = score_x_offset, y = score_y_offset},
|
||||
text = "fbrawl_hud_deaths_score.png",
|
||||
},
|
||||
function fbrawl.update_arena_scores(arena)
|
||||
local scores = {}
|
||||
local score_id = 0
|
||||
|
||||
bronze_crown = {
|
||||
scale = {x = imgs_scale, y = imgs_scale},
|
||||
offset = {x = crown_x_offset, y = crown_y_offset},
|
||||
text = "fbrawl_bronze_crown.png"
|
||||
},
|
||||
bronze_kills = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = crown_x_offset - score_x_offset, y = crown_y_offset + score_y_offset},
|
||||
text = "fbrawl_hud_kills_score.png",
|
||||
},
|
||||
bronze_deaths = {
|
||||
scale = {x = scores_scale, y = scores_scale},
|
||||
offset = {x = crown_x_offset + score_x_offset, y = crown_y_offset + score_y_offset},
|
||||
text = "fbrawl_hud_deaths_score.png",
|
||||
},
|
||||
},
|
||||
-- calculate and store scores for each player
|
||||
for player_name, props in pairs(arena.players) do
|
||||
local score = props.kills - (props.deaths / 2)
|
||||
table.insert(scores, {player_name = player_name, kills = props.kills, score = score, id = score_id})
|
||||
score_id = score_id + 1
|
||||
end
|
||||
|
||||
-- TEXTS
|
||||
sub_txt_elems = {
|
||||
iron_pl_name = {
|
||||
offset = {x = -crown_x_offset, y = crown_y_offset + pl_name_y_offset},
|
||||
text = "-",
|
||||
size = {x=2}
|
||||
},
|
||||
iron_kills_value = {
|
||||
offset = {x = -crown_x_offset - score_x_offset + score_value_x_offset, y = crown_y_offset + score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
iron_deaths_value = {
|
||||
offset = {x = -crown_x_offset + score_x_offset - score_value_x_offset, y = crown_y_offset + score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
-- sort scores by kills, then score, then by id
|
||||
table.sort(scores, function(a, b)
|
||||
if a.kills ~= b.kills then
|
||||
return a.kills > b.kills
|
||||
elseif a.score ~= b.score then
|
||||
return a.score > b.score
|
||||
else
|
||||
return a.id > b.id
|
||||
end
|
||||
end)
|
||||
|
||||
golden_pl_name = {
|
||||
offset = {x = 0, y = pl_name_y_offset},
|
||||
text = "-",
|
||||
size = {x=2}
|
||||
},
|
||||
golden_kills_value = {
|
||||
offset = {x = -score_x_offset + score_value_x_offset, y = score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
golden_deaths_value = {
|
||||
offset = {x = score_x_offset - score_value_x_offset, y = score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
|
||||
bronze_pl_name = {
|
||||
offset = {x = crown_x_offset, y = crown_y_offset + pl_name_y_offset},
|
||||
text = "-",
|
||||
size = {x=2}
|
||||
},
|
||||
bronze_kills_value = {
|
||||
offset = {x = crown_x_offset - score_x_offset + score_value_x_offset, y = crown_y_offset + score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
bronze_deaths_value = {
|
||||
offset = {x = crown_x_offset + score_x_offset - score_value_x_offset, y = crown_y_offset + score_y_offset + score_value_y_offset},
|
||||
text = "-",
|
||||
},
|
||||
}
|
||||
})
|
||||
panel:hide()
|
||||
end
|
||||
|
||||
|
||||
function fbrawl.show_podium_HUD(pl_name)
|
||||
if not panel_lib.has_panel(pl_name, "fbrawl:podium") then return end
|
||||
|
||||
local panel = panel_lib.get_panel(pl_name, "fbrawl:podium")
|
||||
|
||||
fbrawl.update_score_hud(pl_name)
|
||||
panel:show()
|
||||
arena.scores = scores
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- get player ranks from scores:
|
||||
-- returns a table where `rank[i]` is the rank of the player at index `i` in the scoreboard
|
||||
-- if `i` and `i-1` have the same score, then `rank[i] == rank[i-1]`
|
||||
function scoreboard_to_ranking(arena)
|
||||
local scores = arena.scores
|
||||
local rank = {}
|
||||
if #scores == 0 then
|
||||
return rank
|
||||
end
|
||||
|
||||
for i, curr in ipairs(scores) do
|
||||
if i == 1 then
|
||||
rank[i] = 1
|
||||
else
|
||||
local prev = scores[i-1]
|
||||
if curr.kills == prev.kills and curr.score == prev.score then
|
||||
rank[i] = rank[i-1]
|
||||
else
|
||||
rank[i] = rank[i-1] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return rank
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- determine the crown type based on rank
|
||||
function get_crown_material(scoreboard_idx, arena)
|
||||
if not scoreboard_idx or #arena.scores == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local entry_rank = scoreboard_to_ranking(arena)[scoreboard_idx]
|
||||
|
||||
if entry_rank == 1 then return "golden" end
|
||||
if entry_rank == 2 then return "iron" end
|
||||
if entry_rank == 3 then return "bronze" end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- get the number of podium positions
|
||||
function get_podium_count(arena)
|
||||
if #arena.scores == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local rankings = scoreboard_to_ranking(arena)
|
||||
local count = 0
|
||||
for _, rank in pairs(rankings or {}) do
|
||||
if rank <= 3 then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- generate the formspec for the scoreboard
|
||||
function get_scoreboard_formspec(player_name)
|
||||
local arena = arena_lib.get_arena_by_player(player_name)
|
||||
if not arena then
|
||||
return ""
|
||||
end
|
||||
|
||||
local podium_positions = get_podium_count(arena)
|
||||
local bg_height = (1.54 / 3) * podium_positions
|
||||
|
||||
local formspec = string.format([[
|
||||
formspec_version[4]
|
||||
size[0.01,8.1]
|
||||
position[0.5,0.5]
|
||||
anchor[0.5,0.5]
|
||||
no_prepend[]
|
||||
bgcolor[#FF00FF00]
|
||||
|
||||
style[small_label;border=false;font_size=*1;font=mono]
|
||||
style[title;border=false;font_size=*2;font=bold]
|
||||
style_type[label;font=mono]
|
||||
|
||||
image[-4.85,0.8;0.6,%f;blank.png^[fill:1x1:#472d3ca9]
|
||||
image[-4.25,0;9.05,0.8;blank.png^[fill:1x1:#7a444a]
|
||||
image[3.05,0;0.8,0.8;fbrawl_warrior_icon.png]
|
||||
image[4.02,0.07;0.65,0.65;fbrawl_kills_icon.png^[transformFX]
|
||||
container[0,-0.45]
|
||||
]], bg_height)
|
||||
|
||||
local rankings = scoreboard_to_ranking(arena)
|
||||
|
||||
-- add each player's data to the formspec
|
||||
for i, score_entry in ipairs(arena.scores) do
|
||||
local y_offset = (i - 1) * 0.5
|
||||
local is_current = (score_entry.player_name == player_name)
|
||||
local bg_color = is_current and "#472d3ca9" or "#472d3c66"
|
||||
local props = arena.players[score_entry.player_name]
|
||||
|
||||
-- bg color and separating line
|
||||
formspec = formspec .. string.format([[
|
||||
container[0,%f]
|
||||
image[-4.25,1.25;9.05,0.5;blank.png^[fill:1x1:%s]
|
||||
image[-4.25,1.75;9.05,0.02;blank.png^[fill:1x1:#472d3c66]
|
||||
]], y_offset, bg_color)
|
||||
|
||||
-- crown icon
|
||||
local crown_type = get_crown_material(i, arena)
|
||||
if crown_type then
|
||||
formspec = formspec .. string.format(
|
||||
"image[-4.75,1.3;0.4,0.4;fbrawl_%s_crown.png]\n",
|
||||
crown_type
|
||||
)
|
||||
end
|
||||
|
||||
-- place. name kills deaths
|
||||
formspec = formspec .. string.format([[
|
||||
label[-4,1.5;%d. %s]
|
||||
button[3,1;1,1;small_label;%d]
|
||||
button[3.85,1;1,1;small_label;%d]
|
||||
container_end[]
|
||||
]], rankings[i], score_entry.player_name, props.kills, props.deaths)
|
||||
end
|
||||
|
||||
formspec = formspec .. "container_end[]"
|
||||
return formspec
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- display the scoreboard HUD
|
||||
function show_scoreboard(player_name)
|
||||
if active_scoreboards[player_name] then
|
||||
return
|
||||
end
|
||||
|
||||
local player = minetest.get_player_by_name(player_name)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
|
||||
active_scoreboards[player_name] = true
|
||||
local formspec = get_scoreboard_formspec(player_name)
|
||||
hud_fs.show_hud(player, "fantasy_brawl:scoreboard", formspec)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- register controls for showing/hiding the scoreboard
|
||||
|
||||
controls.register_on_press(function(player, control_name)
|
||||
local pl_name = player:get_player_name()
|
||||
local mod = arena_lib.get_mod_by_player(pl_name)
|
||||
local arena = arena_lib.get_arena_by_player(pl_name)
|
||||
local player_name = player:get_player_name()
|
||||
local mod = arena_lib.get_mod_by_player(player_name)
|
||||
local arena = arena_lib.get_arena_by_player(player_name)
|
||||
|
||||
if mod == "fantasy_brawl" and arena.in_game and control_name == "aux1" then
|
||||
fbrawl.show_podium_HUD(pl_name)
|
||||
end
|
||||
if mod == "fantasy_brawl" and arena.in_game and control_name == "aux1" then
|
||||
show_scoreboard(player_name)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
controls.register_on_release(function(player, control_name)
|
||||
local pl_name = player:get_player_name()
|
||||
local mod = arena_lib.get_mod_by_player(pl_name)
|
||||
local arena = arena_lib.get_arena_by_player(pl_name)
|
||||
local player_name = player:get_player_name()
|
||||
local mod = arena_lib.get_mod_by_player(player_name)
|
||||
local arena = arena_lib.get_arena_by_player(player_name)
|
||||
|
||||
if
|
||||
mod == "fantasy_brawl" and arena.in_game
|
||||
and not arena.in_celebration and control_name == "aux1"
|
||||
then
|
||||
if not panel_lib.has_panel(pl_name, "fbrawl:podium") then return end
|
||||
local panel = panel_lib.get_panel(pl_name, "fbrawl:podium")
|
||||
panel:hide()
|
||||
end
|
||||
if mod == "fantasy_brawl" and arena.in_game
|
||||
and not arena.in_celebration
|
||||
and control_name == "aux1" then
|
||||
active_scoreboards[player_name] = nil
|
||||
local p = minetest.get_player_by_name(player_name)
|
||||
if p then
|
||||
hud_fs.close_hud(p, "fantasy_brawl:scoreboard")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-- cleanup on player leave
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
active_scoreboards[player:get_player_name()] = nil
|
||||
end)
|
||||
|
@ -1,77 +0,0 @@
|
||||
local function assign_tier() end
|
||||
local function update_tiers_hud() end
|
||||
|
||||
|
||||
function fbrawl.update_score(arena)
|
||||
local scores = {}
|
||||
local score_id = 0
|
||||
|
||||
for pl_name, props in pairs(arena.players) do
|
||||
local score = props.kills - (props.deaths / 2)
|
||||
table.insert(scores, {pl_name = pl_name, kills = props.kills, score = score, id = score_id})
|
||||
score_id = score_id + 1
|
||||
end
|
||||
|
||||
table.sort(scores, function (a, b)
|
||||
if a.kills ~= b.kills then return a.kills > b.kills
|
||||
elseif a.score ~= b.score then return a.score > b.score
|
||||
else return a.id > b.id end
|
||||
end)
|
||||
|
||||
arena.scores = scores
|
||||
end
|
||||
|
||||
|
||||
|
||||
function fbrawl.update_score_hud(pl_name)
|
||||
local arena = arena_lib.get_arena_by_player(pl_name)
|
||||
|
||||
fbrawl.update_score(arena)
|
||||
update_tiers_hud(pl_name)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function update_tiers_hud(pl_name)
|
||||
local arena = arena_lib.get_arena_by_player(pl_name)
|
||||
|
||||
for i=1, 3, 1 do
|
||||
local classified_pl_name = "-"
|
||||
|
||||
if arena.scores[i] then classified_pl_name = arena.scores[i].pl_name end
|
||||
|
||||
if i == 1 then
|
||||
assign_tier("golden", pl_name, classified_pl_name)
|
||||
elseif i == 2 then
|
||||
assign_tier("iron", pl_name, classified_pl_name)
|
||||
elseif i == 3 then
|
||||
assign_tier("bronze", pl_name, classified_pl_name)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function assign_tier(tier, pl_name, classified_pl_name)
|
||||
local panel = panel_lib.get_panel(pl_name, "fbrawl:podium")
|
||||
local arena = arena_lib.get_arena_by_player(pl_name)
|
||||
local override_hud_value = false
|
||||
|
||||
if classified_pl_name == "-" then override_hud_value = "-" end
|
||||
|
||||
if
|
||||
not arena.players
|
||||
or
|
||||
((not arena.players[classified_pl_name] or not arena.players[classified_pl_name].kills) and not override_hud_value)
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
panel:update(nil, {
|
||||
[tier.."_pl_name"] = {text=override_hud_value or classified_pl_name},
|
||||
[tier.."_deaths_value"] = {text=override_hud_value or arena.players[classified_pl_name].deaths},
|
||||
[tier.."_kills_value"] = {text=override_hud_value or arena.players[classified_pl_name].kills},
|
||||
}, nil)
|
||||
end
|
BIN
textures/fbrawl_kills_icon.png
Normal file
BIN
textures/fbrawl_kills_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 246 B |
Loading…
x
Reference in New Issue
Block a user