2015-11-29 00:05:37 +00:00
|
|
|
ctf_stats = {}
|
|
|
|
|
2019-08-28 16:05:59 +00:00
|
|
|
local _needs_save = false
|
2017-10-12 23:09:25 +00:00
|
|
|
local storage = minetest.get_mod_storage()
|
2019-03-17 01:37:20 +00:00
|
|
|
local prev_match_summary = storage:get_string("prev_match_summary")
|
2017-10-12 23:09:25 +00:00
|
|
|
local data_to_persist = { "matches", "players" }
|
|
|
|
|
2019-03-17 01:37:20 +00:00
|
|
|
function ctf_stats.get_prev_match_summary()
|
|
|
|
return prev_match_summary
|
|
|
|
end
|
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
function ctf_stats.load_legacy()
|
2017-10-12 23:09:25 +00:00
|
|
|
local file = io.open(minetest.get_worldpath() .. "/ctf_stats.txt", "r")
|
2018-01-09 02:40:18 +00:00
|
|
|
if not file then
|
|
|
|
return false
|
|
|
|
end
|
2017-10-12 23:09:25 +00:00
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
local table = minetest.deserialize(file:read("*all"))
|
|
|
|
file:close()
|
|
|
|
if type(table) ~= "table" then
|
|
|
|
return false
|
|
|
|
end
|
2017-11-07 00:32:20 +00:00
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
ctf.log("ctf_stats", "Migrating stats...")
|
|
|
|
ctf_stats.matches = table.matches
|
|
|
|
ctf_stats.players = table.players
|
2017-11-07 00:32:20 +00:00
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
for name, player_stats in pairs(ctf_stats.players) do
|
|
|
|
if not player_stats.score or player_stats.score < 0 then
|
|
|
|
player_stats.score = 0
|
|
|
|
end
|
|
|
|
if player_stats.score > 300 then
|
|
|
|
player_stats.score = (player_stats.score - 300) / 30 + 300
|
|
|
|
end
|
|
|
|
if player_stats.score > 800 then
|
|
|
|
player_stats.score = 800
|
|
|
|
end
|
2017-11-07 00:32:20 +00:00
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
player_stats.wins = player_stats.wins or {}
|
|
|
|
if player_stats.blue_wins then
|
|
|
|
player_stats.wins.blue = player_stats.blue_wins
|
|
|
|
player_stats.blue_wins = nil
|
2017-10-12 23:09:25 +00:00
|
|
|
end
|
2018-01-09 02:40:18 +00:00
|
|
|
if player_stats.red_wins then
|
|
|
|
player_stats.wins.red = player_stats.red_wins
|
|
|
|
player_stats.red_wins = nil
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
2018-01-09 02:40:18 +00:00
|
|
|
player_stats.wins.blue = player_stats.wins.blue or 0
|
|
|
|
player_stats.wins.red = player_stats.wins.red or 0
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
ctf_stats.matches.wins = ctf_stats.matches.wins or {
|
|
|
|
red = ctf_stats.matches.red_wins or 0,
|
|
|
|
blue = ctf_stats.matches.blue_wins or 0,
|
|
|
|
}
|
|
|
|
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2018-01-09 02:41:46 +00:00
|
|
|
|
|
|
|
os.remove(minetest.get_worldpath() .. "/ctf_stats.txt")
|
2018-01-09 02:40:18 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function ctf_stats.load()
|
|
|
|
if not ctf_stats.load_legacy() then
|
|
|
|
for _, key in pairs(data_to_persist) do
|
|
|
|
ctf_stats[key] = minetest.parse_json(storage:get_string(key))
|
2018-01-03 00:23:38 +00:00
|
|
|
end
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2018-01-03 00:23:38 +00:00
|
|
|
end
|
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
-- Make sure all tables are present
|
|
|
|
ctf_stats.players = ctf_stats.players or {}
|
2017-10-12 23:09:25 +00:00
|
|
|
ctf_stats.matches = ctf_stats.matches or {
|
|
|
|
wins = {
|
|
|
|
blue = 0,
|
2018-01-09 02:40:18 +00:00
|
|
|
red = 0,
|
2017-10-12 23:09:25 +00:00
|
|
|
},
|
2018-01-09 02:40:18 +00:00
|
|
|
skipped = 0,
|
2015-11-29 00:05:37 +00:00
|
|
|
}
|
2017-10-12 23:09:25 +00:00
|
|
|
ctf_stats.current = ctf_stats.current or {
|
2015-11-29 00:05:37 +00:00
|
|
|
red = {},
|
|
|
|
blue = {}
|
|
|
|
}
|
|
|
|
|
2018-04-18 20:49:47 +00:00
|
|
|
ctf_stats.start = os.time()
|
|
|
|
|
2018-01-09 02:40:18 +00:00
|
|
|
-- Strip players which have no score
|
|
|
|
for name, player_stats in pairs(ctf_stats.players) do
|
|
|
|
if not player_stats.score or player_stats.score <= 0 then
|
|
|
|
ctf_stats.players[name] = nil
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2018-04-19 00:01:19 +00:00
|
|
|
else
|
|
|
|
player_stats.bounty_kills = player_stats.bounty_kills or 0
|
2018-01-09 02:40:18 +00:00
|
|
|
end
|
|
|
|
end
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
|
|
|
|
2019-08-28 16:05:59 +00:00
|
|
|
function ctf_stats.save()
|
|
|
|
if not _needs_save then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
_needs_save = false
|
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
for _, key in pairs(data_to_persist) do
|
|
|
|
storage:set_string(key, minetest.write_json(ctf_stats[key]))
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
|
|
|
|
2019-08-28 16:05:59 +00:00
|
|
|
minetest.after(13, ctf_stats.save)
|
|
|
|
end
|
|
|
|
minetest.after(13, ctf_stats.save)
|
2015-11-29 00:05:37 +00:00
|
|
|
|
2018-01-02 23:51:38 +00:00
|
|
|
function ctf_stats.player_or_nil(name)
|
|
|
|
return ctf_stats.players[name], ctf_stats.current.red[name] or ctf_stats.current.blue[name]
|
|
|
|
end
|
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
-- Returns a tuple: `player_stats`, `match_player_stats`
|
2015-11-29 00:05:37 +00:00
|
|
|
function ctf_stats.player(name)
|
2017-10-12 23:09:25 +00:00
|
|
|
local player_stats = ctf_stats.players[name]
|
|
|
|
if not player_stats then
|
|
|
|
player_stats = {
|
2015-12-03 23:57:28 +00:00
|
|
|
name = name,
|
2017-10-12 23:09:25 +00:00
|
|
|
wins = {
|
|
|
|
red = 0,
|
|
|
|
blue = 0,
|
|
|
|
},
|
2015-11-29 00:05:37 +00:00
|
|
|
kills = 0,
|
|
|
|
deaths = 0,
|
2015-12-03 23:57:28 +00:00
|
|
|
captures = 0,
|
2017-10-12 00:19:23 +00:00
|
|
|
attempts = 0,
|
2017-10-12 23:09:25 +00:00
|
|
|
score = 0,
|
2018-04-18 23:57:21 +00:00
|
|
|
bounty_kills = 0,
|
2015-11-29 00:05:37 +00:00
|
|
|
}
|
2017-10-12 23:09:25 +00:00
|
|
|
ctf_stats.players[name] = player_stats
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
local match_player_stats =
|
|
|
|
ctf_stats.current.red[name] or ctf_stats.current.blue[name]
|
2015-11-29 00:05:37 +00:00
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
return player_stats, match_player_stats
|
2015-11-29 00:05:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
ctf.register_on_join_team(function(name, tname)
|
2017-10-12 23:09:25 +00:00
|
|
|
ctf_stats.current[tname][name] = ctf_stats.current[tname][name] or {
|
2015-11-29 00:05:37 +00:00
|
|
|
kills = 0,
|
2017-10-12 23:09:25 +00:00
|
|
|
kills_since_death = 0,
|
2015-11-29 00:05:37 +00:00
|
|
|
deaths = 0,
|
2015-12-03 23:46:52 +00:00
|
|
|
attempts = 0,
|
2017-10-12 23:09:25 +00:00
|
|
|
captures = 0,
|
|
|
|
score = 0,
|
2018-04-18 22:00:15 +00:00
|
|
|
bounty_kills = 0,
|
2015-11-29 00:05:37 +00:00
|
|
|
}
|
|
|
|
end)
|
|
|
|
|
2018-04-18 20:49:47 +00:00
|
|
|
local winner_team = "-"
|
|
|
|
local winner_player = "-"
|
|
|
|
|
2018-11-20 13:21:42 +00:00
|
|
|
table.insert(ctf_flag.registered_on_capture, 1, function(name, flag)
|
2015-12-03 23:57:28 +00:00
|
|
|
local main, match = ctf_stats.player(name)
|
|
|
|
if main and match then
|
2017-10-12 23:09:25 +00:00
|
|
|
main.captures = main.captures + 1
|
2017-10-12 23:57:09 +00:00
|
|
|
main.score = main.score + 25
|
2015-12-03 23:57:28 +00:00
|
|
|
match.captures = match.captures + 1
|
2017-10-12 23:57:09 +00:00
|
|
|
match.score = match.score + 25
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2015-12-03 23:46:52 +00:00
|
|
|
end
|
2018-04-18 20:49:47 +00:00
|
|
|
winner_player = name
|
2019-03-19 17:04:41 +00:00
|
|
|
|
|
|
|
hud_score.new(name, {
|
|
|
|
name = "ctf_stats:flag_capture",
|
|
|
|
color = "0xFF00FF",
|
|
|
|
value = 25
|
|
|
|
})
|
2015-12-03 23:46:52 +00:00
|
|
|
end)
|
|
|
|
|
2015-11-29 00:05:37 +00:00
|
|
|
ctf_match.register_on_winner(function(winner)
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2017-10-12 23:09:25 +00:00
|
|
|
ctf_stats.matches.wins[winner] = ctf_stats.matches.wins[winner] + 1
|
2018-04-18 20:49:47 +00:00
|
|
|
winner_team = winner
|
2018-11-14 12:48:05 +00:00
|
|
|
|
|
|
|
-- Show match summary
|
|
|
|
local fs = ctf_stats.get_formspec_match_summary(ctf_stats.current,
|
2018-11-20 13:21:42 +00:00
|
|
|
winner_team, winner_player, os.time() - ctf_stats.start)
|
2018-11-14 12:48:05 +00:00
|
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
|
|
minetest.show_formspec(player:get_player_name(), "ctf_stats:eom", fs)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Set prev_match_summary and write to mod_storage
|
|
|
|
prev_match_summary = fs
|
|
|
|
storage:set_string("prev_match_summary", fs)
|
2015-11-29 00:05:37 +00:00
|
|
|
end)
|
|
|
|
|
2018-11-14 12:48:05 +00:00
|
|
|
ctf_match.register_on_skip_map(function()
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2018-11-14 12:48:05 +00:00
|
|
|
ctf_stats.matches.skipped = ctf_stats.matches.skipped + 1
|
|
|
|
|
|
|
|
-- Show match summary
|
|
|
|
local fs = ctf_stats.get_formspec_match_summary(ctf_stats.current,
|
|
|
|
winner_team, winner_player, os.time()-ctf_stats.start)
|
|
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
2015-12-03 23:46:52 +00:00
|
|
|
minetest.show_formspec(player:get_player_name(), "ctf_stats:eom", fs)
|
|
|
|
end
|
2015-11-29 00:05:37 +00:00
|
|
|
|
2018-11-14 12:48:05 +00:00
|
|
|
-- Set prev_match_summary and write to mod_storage
|
|
|
|
prev_match_summary = fs
|
|
|
|
storage:set_string("prev_match_summary", fs)
|
|
|
|
end)
|
|
|
|
|
|
|
|
ctf_match.register_on_new_match(function()
|
2015-11-29 00:05:37 +00:00
|
|
|
ctf_stats.current = {
|
|
|
|
red = {},
|
|
|
|
blue = {}
|
|
|
|
}
|
2018-04-18 20:49:47 +00:00
|
|
|
winner_team = "-"
|
|
|
|
winner_player = "-"
|
|
|
|
ctf_stats.start = os.time()
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2015-11-29 00:05:37 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
ctf_flag.register_on_pick_up(function(name, flag)
|
|
|
|
local main, match = ctf_stats.player(name)
|
2015-11-29 23:55:27 +00:00
|
|
|
if main and match then
|
2017-10-12 23:09:25 +00:00
|
|
|
main.attempts = main.attempts + 1
|
2019-03-19 17:04:41 +00:00
|
|
|
main.score = main.score + 10
|
2015-11-29 23:55:27 +00:00
|
|
|
match.attempts = match.attempts + 1
|
2017-10-12 23:57:09 +00:00
|
|
|
match.score = match.score + 10
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2015-11-29 23:55:27 +00:00
|
|
|
end
|
2019-03-19 17:04:41 +00:00
|
|
|
|
|
|
|
hud_score.new(name, {
|
|
|
|
name = "ctf_stats:flag_pick_up",
|
|
|
|
color = "0xAA00AA",
|
|
|
|
value = 10
|
|
|
|
})
|
2015-11-29 00:05:37 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
ctf_flag.register_on_precapture(function(name, flag)
|
|
|
|
local tplayer = ctf.player(name)
|
2018-04-06 13:04:56 +00:00
|
|
|
local main, _ = ctf_stats.player(name)
|
2015-11-29 23:55:27 +00:00
|
|
|
if main then
|
2017-10-12 23:09:25 +00:00
|
|
|
main.wins[tplayer.team] = main.wins[tplayer.team] + 1
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2015-11-29 23:55:27 +00:00
|
|
|
end
|
2015-11-29 00:05:37 +00:00
|
|
|
return true
|
|
|
|
end)
|
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
local good_weapons = {
|
|
|
|
"default:sword_steel",
|
2018-02-11 15:44:10 +00:00
|
|
|
"default:sword_bronze",
|
|
|
|
"default:sword_mese",
|
|
|
|
"default:sword_diamond",
|
2018-02-18 08:30:50 +00:00
|
|
|
"default:pick_mese",
|
|
|
|
"default:pick_diamond",
|
|
|
|
"default:axe_mese",
|
|
|
|
"default:axe_diamond",
|
|
|
|
"default:shovel_mese",
|
|
|
|
"default:shovel_diamond",
|
2017-10-12 23:09:25 +00:00
|
|
|
"shooter:grenade",
|
|
|
|
"shooter:shotgun",
|
|
|
|
"shooter:rifle",
|
|
|
|
"shooter:machine_gun",
|
|
|
|
}
|
2018-02-15 08:04:34 +00:00
|
|
|
|
2017-10-12 23:09:25 +00:00
|
|
|
local function invHasGoodWeapons(inv)
|
|
|
|
for _, weapon in pairs(good_weapons) do
|
|
|
|
if inv:contains_item("main", weapon) then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
local function calculateKillReward(victim, killer)
|
|
|
|
local vmain, victim_match = ctf_stats.player(victim)
|
|
|
|
|
|
|
|
-- +5 for every kill they've made since last death in this match.
|
|
|
|
local reward = victim_match.kills_since_death * 5
|
2017-10-12 23:57:09 +00:00
|
|
|
ctf.log("ctf_stats", "Player " .. victim .. " has made " .. reward ..
|
|
|
|
" score worth of kills since last death")
|
2017-10-12 23:09:25 +00:00
|
|
|
|
2018-02-15 08:04:34 +00:00
|
|
|
-- 30 * K/D ratio, with variable based on player's score
|
2017-10-13 01:05:21 +00:00
|
|
|
local kdreward = 30 * vmain.kills / (vmain.deaths + 1)
|
|
|
|
local max = vmain.score / 6
|
2017-10-12 23:09:25 +00:00
|
|
|
if kdreward > max then
|
|
|
|
kdreward = max
|
|
|
|
end
|
2017-10-13 01:05:21 +00:00
|
|
|
if kdreward > 80 then
|
|
|
|
kdreward = 80
|
2017-10-12 23:09:25 +00:00
|
|
|
end
|
2017-10-12 23:57:09 +00:00
|
|
|
reward = reward + kdreward
|
2017-10-12 23:09:25 +00:00
|
|
|
|
2018-02-15 08:04:34 +00:00
|
|
|
-- Limited to 0 <= X <= 200
|
|
|
|
if reward > 200 then
|
|
|
|
reward = 200
|
2017-10-13 01:05:21 +00:00
|
|
|
elseif reward < 14 then
|
|
|
|
reward = 14
|
2017-10-12 23:09:25 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Half if no good weapons
|
2019-03-17 01:37:20 +00:00
|
|
|
local inv = minetest.get_inventory({ type = "player", name = victim })
|
2017-10-12 23:09:25 +00:00
|
|
|
if not invHasGoodWeapons(inv) then
|
|
|
|
ctf.log("ctf_stats", "Player " .. victim .. " has no good weapons")
|
|
|
|
reward = reward * 0.5
|
|
|
|
else
|
|
|
|
ctf.log("ctf_stats", "Player " .. victim .. " has good weapons")
|
|
|
|
end
|
|
|
|
|
|
|
|
return reward
|
|
|
|
end
|
|
|
|
|
2015-12-04 00:15:03 +00:00
|
|
|
ctf.register_on_killedplayer(function(victim, killer)
|
2018-11-29 15:52:43 +00:00
|
|
|
-- Suicide is not encouraged here at CTF
|
|
|
|
if victim == killer then
|
|
|
|
return
|
|
|
|
end
|
2015-12-04 00:15:03 +00:00
|
|
|
local main, match = ctf_stats.player(killer)
|
|
|
|
if main and match then
|
2017-10-12 23:09:25 +00:00
|
|
|
local reward = calculateKillReward(victim, killer)
|
|
|
|
main.kills = main.kills + 1
|
|
|
|
main.score = main.score + reward
|
2015-12-04 00:15:03 +00:00
|
|
|
match.kills = match.kills + 1
|
2017-10-12 23:09:25 +00:00
|
|
|
match.score = match.score + reward
|
|
|
|
match.kills_since_death = match.kills_since_death + 1
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2019-03-17 01:35:51 +00:00
|
|
|
|
|
|
|
reward = math.floor(reward * 100) / 100
|
|
|
|
|
|
|
|
hud_score.new(killer, {
|
|
|
|
name = "ctf_stats:kill_score",
|
|
|
|
color = "0x00FF00",
|
|
|
|
value = reward
|
|
|
|
})
|
2015-12-04 00:15:03 +00:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2015-11-29 00:05:37 +00:00
|
|
|
minetest.register_on_dieplayer(function(player)
|
|
|
|
local main, match = ctf_stats.player(player:get_player_name())
|
2015-11-29 23:55:27 +00:00
|
|
|
if main and match then
|
|
|
|
main.deaths = main.deaths + 1
|
|
|
|
match.deaths = match.deaths + 1
|
2017-10-12 23:09:25 +00:00
|
|
|
match.kills_since_death = 0
|
2019-08-28 16:05:59 +00:00
|
|
|
_needs_save = true
|
2015-11-29 23:55:27 +00:00
|
|
|
end
|
2015-11-29 00:05:37 +00:00
|
|
|
end)
|
|
|
|
|
2018-11-14 12:48:05 +00:00
|
|
|
minetest.register_chatcommand("summary", {
|
2019-03-17 01:37:20 +00:00
|
|
|
func = function(name)
|
|
|
|
local fs = ctf_stats.get_formspec_match_summary(ctf_stats.current,
|
|
|
|
winner_team, winner_player, os.time() - ctf_stats.start)
|
|
|
|
|
|
|
|
fs = fs .. "button[6,7.5;4,1;b_prev;<< Previous match]"
|
2018-11-14 12:48:05 +00:00
|
|
|
|
2019-03-17 01:37:20 +00:00
|
|
|
minetest.show_formspec(name, "ctf_stats:match_summary", fs)
|
2018-11-14 12:48:05 +00:00
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2019-03-17 01:37:20 +00:00
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
|
|
if formname ~= "ctf_stats:match_summary" then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local fs
|
|
|
|
if fields.b_prev then
|
|
|
|
fs = prev_match_summary
|
|
|
|
fs = fs .. "button[6,7.5;4,1;b_curr;Current match >>]"
|
|
|
|
elseif fields.b_curr then
|
|
|
|
fs = ctf_stats.get_formspec_match_summary(ctf_stats.current,
|
|
|
|
winner_team, winner_player, os.time() - ctf_stats.start)
|
|
|
|
fs = fs .. "button[6,7.5;4,1;b_prev;<< Previous match]"
|
|
|
|
else
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
minetest.show_formspec(player:get_player_name(), "ctf_stats:match_summary", fs)
|
|
|
|
end)
|
|
|
|
|
2015-11-29 00:05:37 +00:00
|
|
|
ctf_stats.load()
|
2015-12-03 23:46:52 +00:00
|
|
|
|
2019-03-17 01:37:20 +00:00
|
|
|
dofile(minetest.get_modpath("ctf_stats") .. "/gui.lua")
|