Files
wnsrc/gamemodes/terrortown/gamemode/cl_awards.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

789 lines
22 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Award/highlight generator functions take the events and the scores as
-- produced by SCORING/CLSCORING and return a table if successful, or nil if
-- not and another one should be tried.
-- some globals we'll use a lot
local table = table
local pairs = pairs
local is_dmg = function(dmg_t, bit)
-- deal with large-number workaround for TableToJSON by
-- parsing back to number here
return util.BitSet(tonumber(dmg_t), bit)
end
-- so much text here I'm using shorter names than usual
local T = LANG.GetTranslation
local PT = LANG.GetParamTranslation
-- a common pattern
local function FindHighest(tbl)
local m_num = 0
local m_id = nil
for id, num in pairs(tbl) do
if num > m_num then
m_id = id
m_num = num
end
end
return m_id, m_num
end
local function FirstSuicide(events, scores, players, traitors)
local fs = nil
local fnum = 0
for k, e in pairs(events) do
if e.id == EVENT_KILL and e.att.sid64 == e.vic.sid64 then
fnum = fnum + 1
if fs == nil then
fs = e
end
end
end
if fs then
local award = {nick=fs.att.ni}
if not award.nick then return nil end
if fnum > 1 then
award.title = T("aw_sui1_title")
award.text = T("aw_sui1_text")
else
award.title = T("aw_sui2_title")
award.text = T("aw_sui2_text")
end
-- only high interest if many people died this way
award.priority = fnum
return award
else
return nil
end
end
local function ExplosiveGrant(events, scores, players, traitors)
local bombers = {}
for k, e in pairs(events) do
if e.id == EVENT_KILL and is_dmg(e.dmg.t, DMG_BLAST) then
bombers[e.att.sid64] = (bombers[e.att.sid64] or 0) + 1
end
end
local award = {title= T("aw_exp1_title")}
if not table.IsEmpty(bombers) then
for sid64, num in pairs(bombers) do
-- award goes to whoever reaches this first I guess
if num > 2 then
award.nick = players[sid64]
if not award.nick then return nil end -- if player disconnected or something
award.text = PT("aw_exp1_text", {num = num})
-- rare award, high interest
award.priority = 10 + num
return award
end
end
end
return nil
end
local function ExplodedSelf(events, scores, players, traitors)
for k, e in pairs(events) do
if e.id == EVENT_KILL and is_dmg(e.dmg.t, DMG_BLAST) and e.att.sid64 == e.vic.sid64 then
return {title=T("aw_exp2_title"), text=T("aw_exp2_text"), nick=e.vic.ni, priority=math.random(1, 4)}
end
end
return nil
end
local function FirstBlood(events, scores, players, traitors)
for k, e in pairs(events) do
if e.id == EVENT_KILL and e.att.sid64 != e.vic.sid64 and e.att.sid64 != -1 then
local award = {nick=e.att.ni}
if not award.nick or award.nick == "" then return nil end
if e.att.tr and not e.vic.tr then -- traitor legit k
award.title = T("aw_fst1_title")
award.text = T("aw_fst1_text")
elseif e.att.tr and e.vic.tr then -- traitor tk
award.title = T("aw_fst2_title")
award.text = T("aw_fst2_text")
elseif not e.att.tr and not e.vic.tr then -- inno tk
award.title = T("aw_fst3_title")
award.text = T("aw_fst3_text")
else -- inno legit k
award.title = T("aw_fst4_title")
award.text = T("aw_fst4_text")
end
-- more interesting if there were many players and therefore many kills
award.priority = math.random(-3, math.Round(table.Count(players) / 4))
return award
end
end
end
local function AllKills(events, scores, players, traitors)
-- see if there is one killer responsible for all kills of either team
local tr_killers = {}
local in_killers = {}
for id, s in pairs(scores) do
if s.innos > 0 then
table.insert(in_killers, id)
elseif s.traitors > 0 then
table.insert(tr_killers, id)
end
end
if #tr_killers == 1 then
local id = tr_killers[1]
if not table.HasValue(traitors, id) then
local killer = players[id]
if not killer then return nil end
return {nick=killer, title=T("aw_all1_title"), text=T("aw_all1_text"), priority=math.random(0, table.Count(players))}
end
end
if #in_killers == 1 then
local id = in_killers[1]
if table.HasValue(traitors, id) then
local killer = players[id]
if not killer then return nil end
return {nick=killer, title=T("aw_all2_title"), text=T("aw_all2_text"), priority=math.random(0, table.Count(players))}
end
end
return nil
end
local function NumKills_Traitor(events, scores, players, traitors)
local trs = {}
for id, s in pairs(scores) do
if table.HasValue(traitors, id) then
if s.innos > 0 then
table.insert(trs, id)
end
end
end
local choices = table.Count(trs)
if choices > 0 then
-- award a random killer
local pick = math.random(1, choices)
local sid64 = trs[pick]
local nick = players[sid64]
if not nick then return nil end
local kills = scores[sid64].innos
if kills == 1 then
return {title=T("aw_nkt1_title"), nick=nick, text=T("aw_nkt1_text"), priority=0}
elseif kills == 2 then
return {title=T("aw_nkt2_title"), nick=nick, text=T("aw_nkt2_text"), priority=1}
elseif kills == 3 then
return {title=T("aw_nkt3_title"), nick=nick, text=T("aw_nkt3_text"), priority=kills}
elseif kills >= 4 and kills < 7 then
return {title=T("aw_nkt4_title"), nick=nick, text=PT("aw_nkt4_text", {num = kills}), priority=kills + 2}
elseif kills >= 7 then
return {title=T("aw_nkt5_title"), nick=nick, text=T("aw_nkt5_text"), priority=kills + 5}
end
else
return nil
end
end
local function NumKills_Inno(events, scores, players, traitors)
local ins = {}
for id, s in pairs(scores) do
if not table.HasValue(traitors, id) then
if s.traitors > 0 then
table.insert(ins, id)
end
end
end
local choices = table.Count(ins)
if not table.IsEmpty(ins) then
-- award a random killer
local pick = math.random(1, choices)
local sid64 = ins[pick]
local nick = players[sid64]
if not nick then return nil end
local kills = scores[sid64].traitors
if kills == 1 then
return {title=T("aw_nki1_title"), nick=nick, text=T("aw_nki1_text"), priority = 0}
elseif kills == 2 then
return {title=T("aw_nki2_title"), nick=nick, text=T("aw_nki2_text"), priority = 1}
elseif kills == 3 then
return {title=T("aw_nki3_title"), nick=nick, text=T("aw_nki3_text"), priority= 5}
elseif kills >= 4 then
return {title=T("aw_nki4_title"), nick=nick, text=T("aw_nki4_text"), priority=kills + 10}
end
else
return nil
end
end
local function FallDeath(events, scores, players, traitors)
for k, e in pairs(events) do
if e.id == EVENT_KILL and is_dmg(e.dmg.t, DMG_FALL) then
if e.att.ni != "" then
return {title=T("aw_fal1_title"), nick=e.att.ni, text=T("aw_fal1_text"), priority=math.random(7, 15)}
else
return {title=T("aw_fal2_title"), nick=e.vic.ni, text=T("aw_fal2_text"), priority=math.random(1, 5)}
end
end
end
return nil
end
local function FallKill(events, scores, players, traitors)
for k, e in pairs(events) do
if e.id == EVENT_KILL and is_dmg(e.dmg.t, DMG_CRUSH) and is_dmg(e.dmg.t, DMG_PHYSGUN) then
if e.att.ni != "" then
return {title=T("aw_fal3_title"), nick=e.att.ni, text=T("aw_fal3_text"), priority=math.random(10, 15)}
end
end
end
end
local function Headshots(events, scores, players, traitors)
local hs = {}
for k, e in pairs(events) do
if e.id == EVENT_KILL and e.dmg.h and is_dmg(e.dmg.t, DMG_BULLET) then
hs[e.att.sid64] = (hs[e.att.sid64] or 0) + 1
end
end
if table.IsEmpty(hs) then return nil end
-- find the one with the most shots
local m_id, m_num = FindHighest(hs)
if not m_id then return nil end
local nick = players[m_id]
if not nick then return nil end
local award = {nick=nick, priority=m_num / 2}
if m_num > 1 and m_num < 4 then
award.title = T("aw_hed1_title")
award.text = PT("aw_hed1_text", {num = m_num})
elseif m_num >= 4 and m_num < 6 then
award.title = T("aw_hed2_title")
award.text = PT("aw_hed2_text", {num = m_num})
elseif m_num >= 6 then
award.title = T("aw_hed3_title")
award.text = PT("aw_hed3_text", {num = m_num})
award.priority = m_num + 5
else
return nil
end
return award
end
local function UsedAmmoMost(events, ammotype)
local user = {}
for k, e in pairs(events) do
if e.id == EVENT_KILL and e.dmg.g == ammotype then
user[e.att.sid64] = (user[e.att.sid64] or 0) + 1
end
end
if table.IsEmpty(user) then return nil end
local m_id, m_num = FindHighest(user)
if not m_id then return nil end
return {sid64=m_id, kills=m_num}
end
local function CrowbarUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_CROWBAR)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills + math.random(0, 4)}
local kills = most.kills
if kills > 1 and kills < 3 then
award.title = T("aw_cbr1_title")
award.text = PT("aw_cbr1_text", {num = kills})
elseif kills >= 3 then
award.title = T("aw_cbr2_title")
award.text = PT("aw_cbr2_text", {num = kills})
award.priority = kills + math.random(5, 10)
else
return nil
end
return award
end
local function PistolUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_PISTOL)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_pst1_title")
award.text = PT("aw_pst1_text", {num = kills})
elseif kills >= 4 then
award.title = T("aw_pst2_title")
award.text = PT("aw_pst2_text", {num = kills})
award.priority = award.priority + math.random(0, 5)
else
return nil
end
return award
end
local function ShotgunUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_SHOTGUN)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_sgn1_title")
award.text = PT("aw_sgn1_text", {num = kills})
award.priority = math.Round(kills / 2)
elseif kills >= 4 then
award.title = T("aw_sgn2_title")
award.text = PT("aw_sgn2_text", {num = kills})
else
return nil
end
return award
end
local function RifleUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_RIFLE)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_rfl1_title")
award.text = PT("aw_rfl1_text", {num = kills})
award.priority = math.Round(kills / 2)
elseif kills >= 4 then
award.title = T("aw_rfl2_title")
award.text = PT("aw_rfl2_text", {num = kills})
else
return nil
end
return award
end
local function DeagleUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_DEAGLE)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_dgl1_title")
award.text = PT("aw_dgl1_text", {num = kills})
award.priority = math.Round(kills / 2)
elseif kills >= 4 then
award.title = T("aw_dgl2_title")
award.text = PT("aw_dgl2_text", {num = kills})
award.priority = kills + math.random(2, 6)
else
return nil
end
return award
end
local function MAC10User(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_MAC10)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_mac1_title")
award.text = PT("aw_mac1_text", {num = kills})
award.priority = math.Round(kills / 2)
elseif kills >= 4 then
award.title = T("aw_mac2_title")
award.text = PT("aw_mac2_text", {num = kills})
else
return nil
end
return award
end
local function SilencedPistolUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_SIPISTOL)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 3 then
award.title = T("aw_sip1_title")
award.text = PT("aw_sip1_text", {num = kills})
elseif kills >= 3 then
award.title = T("aw_sip2_title")
award.text = PT("aw_sip2_text", {num = kills})
else
return nil
end
return award
end
local function KnifeUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_KNIFE)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills == 1 then
if table.HasValue(traitors, most.sid64) then
award.title = T("aw_knf1_title")
award.text = PT("aw_knf1_text", {num = kills})
award.priority = 0
else
award.title = T("aw_knf2_title")
award.text = PT("aw_knf2_text", {num = kills})
award.priority = 5
end
elseif kills > 1 and kills < 4 then
award.title = T("aw_knf3_title")
award.text = PT("aw_knf3_text", {num = kills})
elseif kills >= 4 then
award.title = T("aw_knf4_title")
award.text = PT("aw_knf4_text", {num = kills})
else
return nil
end
return award
end
local function FlareUser(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_FLARE)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 3 then
award.title = T("aw_flg1_title")
award.text = PT("aw_flg1_text", {num = kills})
elseif kills >= 3 then
award.title = T("aw_flg2_title")
award.text = PT("aw_flg2_text", {num = kills})
else
return nil
end
return award
end
local function M249User(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_M249)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_hug1_title")
award.text = PT("aw_hug1_text", {num = kills})
elseif kills >= 4 then
award.title = T("aw_hug2_title")
award.text = PT("aw_hug2_text", {num = kills})
else
return nil
end
return award
end
local function M16User(events, scores, players, traitors)
local most = UsedAmmoMost(events, AMMO_M16)
if not most then return nil end
local nick = players[most.sid64]
if not nick then return nil end
local award = {nick=nick, priority=most.kills}
local kills = most.kills
if kills > 1 and kills < 4 then
award.title = T("aw_msx1_title")
award.text = PT("aw_msx1_text", {num = kills})
elseif kills >= 4 then
award.title = T("aw_msx2_title")
award.text = PT("aw_msx2_text", {num = kills})
else
return nil
end
return award
end
local function TeamKiller(events, scores, players, traitors)
local num_traitors = table.Count(traitors)
local num_inno = table.Count(players) - num_traitors
-- find biggest tker
local tker = nil
local pct = 0
for id, s in pairs(scores) do
local kills = s.innos
local team = num_inno - 1
if table.HasValue(traitors, id) then
kills = s.traitors
team = num_traitors - 1
end
if kills > 0 and (kills / team) > pct then
pct = kills / team
tker = id
end
end
-- no tks
if pct == 0 or tker == nil then return nil end
local nick = players[tker]
if not nick then return nil end
local was_traitor = table.HasValue(traitors, tker)
local kills = (was_traitor and scores[tker].traitors > 0 and scores[tker].traitors) or (scores[tker].innos > 0 and scores[tker].innos) or 0
local award = {nick=nick, priority=kills}
if kills == 1 then
award.title = T("aw_tkl1_title")
award.text = T("aw_tkl1_text")
award.priority = 0
elseif kills == 2 then
award.title = T("aw_tkl2_title")
award.text = T("aw_tkl2_text")
elseif kills == 3 then
award.title = T("aw_tkl3_title")
award.text = T("aw_tkl3_text")
elseif pct >= 1.0 then
award.title = T("aw_tkl4_title")
award.text = T("aw_tkl4_text")
award.priority = kills + math.random(3, 6)
elseif pct >= 0.75 and not was_traitor then
award.title = T("aw_tkl5_title")
award.text = T("aw_tkl5_text")
award.priority = kills + 10
elseif pct > 0.5 then
award.title = T("aw_tkl6_title")
award.text = T("aw_tkl6_text")
award.priority = kills + math.random(2, 7)
elseif pct >= 0.25 then
award.title = T("aw_tkl7_title")
award.text = T("aw_tkl7_text")
else
return nil
end
return award
end
local function Burner(events, scores, players, traitors)
local brn = {}
for k, e in pairs(events) do
if e.id == EVENT_KILL and is_dmg(e.dmg.t, DMG_BURN) then
brn[e.att.sid64] = (brn[e.att.sid64] or 0) + 1
end
end
if table.IsEmpty(brn) then return nil end
-- find the one with the most burnings
local m_id, m_num = FindHighest(brn)
if not m_id then return nil end
local nick = players[m_id]
if not nick then return nil end
local award = {nick=nick, priority=m_num * 2}
if m_num > 1 and m_num < 4 then
award.title = T("aw_brn1_title")
award.text = T("aw_brn1_text")
elseif m_num >= 4 and m_num < 7 then
award.title = T("aw_brn2_title")
award.text = T("aw_brn2_text")
elseif m_num >= 7 then
award.title = T("aw_brn3_title")
award.text = T("aw_brn3_text")
award.priority = m_num + math.random(0, 4)
else
return nil
end
return award
end
local function Coroner(events, scores, players, traitors)
local finders = {}
for k, e in pairs(events) do
if e.id == EVENT_BODYFOUND then
finders[e.sid64] = (finders[e.sid64] or 0) + 1
end
end
if table.IsEmpty(finders) then return end
local m_id, m_num = FindHighest(finders)
if not m_id then return nil end
local nick = players[m_id]
if not nick then return nil end
local award = {nick=nick, priority=m_num}
if m_num > 2 and m_num < 6 then
award.title = T("aw_fnd1_title")
award.text = PT("aw_fnd1_text", {num = m_num})
elseif m_num >= 6 and m_num < 10 then
award.title = T("aw_fnd2_title")
award.text = PT("aw_fnd2_text", {num = m_num})
elseif m_num >= 10 then
award.title = T("aw_fnd3_title")
award.text = PT("aw_fnd3_text", {num = m_num})
award.priority = m_num + math.random(0, 4)
else
return nil
end
return award
end
local function CreditFound(events, scores, players, traitors)
local finders = {}
for k, e in pairs(events) do
if e.id == EVENT_CREDITFOUND then
finders[e.sid64] = (finders[e.sid64] or 0) + e.cr
end
end
if table.IsEmpty(finders) then return end
local m_id, m_num = FindHighest(finders)
if not m_id then return nil end
local nick = players[m_id]
if not nick then return nil end
local award = {nick=nick}
if m_num > 2 then
award.title = T("aw_crd1_title")
award.text = PT("aw_crd1_text", {num = m_num})
award.priority = m_num + math.random(0, m_num)
else
return nil
end
return award
end
local function TimeOfDeath(events, scores, players, traitors)
local near = 10
local time_near_start = CLSCORE.StartTime + near
local time_near_end = nil
local traitor_win = nil
local e = nil
for i=#events, 1, -1 do
e = events[i]
if e.id == EVENT_FINISH then
time_near_end = e.t - near
traitor_win = (e.win == WIN_TRAITOR)
elseif e.id == EVENT_KILL and e.vic then
if time_near_end and
e.t > time_near_end and e.vic.tr == traitor_win then
return {
nick = e.vic.ni,
title = T("aw_tod1_title"),
text = T("aw_tod1_text"),
priority = (e.t - time_near_end) * 2
};
elseif e.t < time_near_start then
return {
nick = e.vic.ni,
title = T("aw_tod2_title"),
text = T("aw_tod2_text"),
priority = (time_near_start - e.t) * 2
};
end
end
end
end
-- New award functions must be added to this to be used by CLSCORE.
-- Note that AWARDS is global. You can just go: table.insert(AWARDS, myawardfn) in your SWEPs.
AWARDS = { FirstSuicide, ExplosiveGrant, ExplodedSelf, FirstBlood, AllKills, NumKills_Traitor, NumKills_Inno, FallDeath, Headshots, PistolUser, ShotgunUser, RifleUser, DeagleUser, MAC10User, CrowbarUser, TeamKiller, Burner, SilencedPistolUser, KnifeUser, FlareUser, Coroner, M249User, M16User, CreditFound, FallKill, TimeOfDeath }