From 718f144ab8fdf50d99aa10ad16082c856878790f Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Fri, 28 Feb 2025 02:50:57 +1000 Subject: [PATCH] ka, tka: refactor/fix ball carrier time scoring ka: runs the ball carried think func every frame to facilitate other features, which also allows the code to be simplified somewhat and makes cvar g_keepaway_score_timeinterval redundant. See subsequent commits. tka: as above, also implements fractional timepoints accumulation, making g_tka_score_timepoints behaviour consistent with g_keepaway_score_timepoints. --- .../gamemode/keepaway/sv_keepaway.qc | 26 ++++++++--------- qcsrc/common/gamemodes/gamemode/tka/sv_tka.qc | 28 +++++++++++++------ qcsrc/common/gamemodes/sv_rules.qc | 14 +++++----- qcsrc/common/gamemodes/sv_rules.qh | 6 ++-- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/qcsrc/common/gamemodes/gamemode/keepaway/sv_keepaway.qc b/qcsrc/common/gamemodes/gamemode/keepaway/sv_keepaway.qc index 648d05c3f..b07e43273 100644 --- a/qcsrc/common/gamemodes/gamemode/keepaway/sv_keepaway.qc +++ b/qcsrc/common/gamemodes/gamemode/keepaway/sv_keepaway.qc @@ -79,30 +79,28 @@ void ka_RespawnBall(entity this) // runs whenever the ball needs to be relocated sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere) } -.float timepoints_counter; +/// accumulates points precisely while main points value remains an integer, shared with tka +.float timepoints_accum; MUTATOR_HOOKFUNCTION(ka, reset_map_global) { FOREACH_CLIENT(true, { - it.timepoints_counter = 0; + it.timepoints_accum = 0; }); return true; } +/// runs (only) while a player is carrying the ball void ka_TimeScoring(entity this) { - if(this.owner.ballcarried) - { // add points for holding the ball after a certain amount of time - float timescore = 0; - if(autocvar_g_keepaway_score_timepoints) - timescore = autocvar_g_keepaway_score_timepoints / max(0.001, autocvar_g_keepaway_score_timeinterval); - - if (timescore) - GameRules_scoring_add_float2int(this.owner, SCORE, timescore, timepoints_counter, 1); - - GameRules_scoring_add(this.owner, KEEPAWAY_BCTIME, 1); - this.nextthink = time + 1; + if (autocvar_g_keepaway_score_timepoints && autocvar_g_keepaway_score_timeinterval) + { + float timescore = autocvar_g_keepaway_score_timepoints / autocvar_g_keepaway_score_timeinterval; + GameRules_scoring_add_float2int(this.owner, SCORE, timescore * frametime, timepoints_accum, 1); } + GameRules_scoring_add(this.owner, KEEPAWAY_BCTIME, frametime); + + this.nextthink = time; } void ka_DamageEvent(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) @@ -147,7 +145,7 @@ void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball c this.effects |= EF_NODRAW; settouch(this, func_null); setthink(this, ka_TimeScoring); - this.nextthink = time + 1; + this.nextthink = time; this.takedamage = DAMAGE_NO; this.event_damage = func_null; this.damagedbycontents = false; diff --git a/qcsrc/common/gamemodes/gamemode/tka/sv_tka.qc b/qcsrc/common/gamemodes/gamemode/tka/sv_tka.qc index f6835cee2..04f686ca7 100644 --- a/qcsrc/common/gamemodes/gamemode/tka/sv_tka.qc +++ b/qcsrc/common/gamemodes/gamemode/tka/sv_tka.qc @@ -76,16 +76,28 @@ void tka_RespawnBall(entity this) // runs whenever the ball needs to be relocate sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere) } -void tka_TimeScoring(entity this) +/// accumulates points precisely while main points value remains an integer, shared with ka +.float timepoints_accum; +MUTATOR_HOOKFUNCTION(tka, reset_map_global) { - if(this.owner.ballcarried) - { // add points for holding the ball after a certain amount of time - if(autocvar_g_tka_score_timepoints) - GameRules_scoring_add_team(this.owner, SCORE, autocvar_g_tka_score_timepoints); + FOREACH_CLIENT(true, + { + it.timepoints_accum = 0; + }); + return true; +} - GameRules_scoring_add(this.owner, TKA_BCTIME, (autocvar_g_tka_score_timeinterval / 1)); // interval is divided by 1 so that time always shows "seconds" - this.nextthink = time + autocvar_g_tka_score_timeinterval; +/// runs (only) while a player is carrying the ball +void tka_TimeScoring(entity this) +{ + if (autocvar_g_tka_score_timepoints && autocvar_g_tka_score_timeinterval) + { + float timescore = autocvar_g_tka_score_timepoints / autocvar_g_tka_score_timeinterval; + GameRules_scoring_add_team_float2int(this.owner, SCORE, timescore * frametime, timepoints_accum, 1); } + GameRules_scoring_add(this.owner, TKA_BCTIME, frametime); + + this.nextthink = time; } void tka_TouchEvent(entity this, entity toucher) // runs any time that the ball comes in contact with something @@ -124,7 +136,7 @@ void tka_TouchEvent(entity this, entity toucher) // runs any time that the ball this.effects |= EF_NODRAW; settouch(this, func_null); setthink(this, tka_TimeScoring); - this.nextthink = time + autocvar_g_tka_score_timeinterval; + this.nextthink = time; this.takedamage = DAMAGE_NO; navigation_dynamicgoal_unset(this); diff --git a/qcsrc/common/gamemodes/sv_rules.qc b/qcsrc/common/gamemodes/sv_rules.qc index 03b6ce1a4..f582f82cb 100644 --- a/qcsrc/common/gamemodes/sv_rules.qc +++ b/qcsrc/common/gamemodes/sv_rules.qc @@ -107,11 +107,11 @@ bool GameRules_scoring_is_vip(entity player) return player.m_GameRules_scoring_vip; } -// Uses client.float_field to accumulate and consume float score and adds score to the player as int (rounded) -// only when at least one unit of score has been accumulated. It works with negative score too -// Float scores can't be used as score because they aren't supported by the QC score networking system -// and online server browsers (e.g. qstat) -float _GameRules_scoring_add_float2int(entity client, entity sp, float value, .float float_field, float score_factor) +/// Uses client.(float_field) to accumulate and consume float score and adds score to the player as int (rounded) +/// only when at least one unit of score has been accumulated. It works with negative score too +/// Float scores can't be used as score because they aren't supported by the QC score networking system +/// and online server browsers (e.g. qstat) +float _GameRules_scoring_add_float2int(entity client, entity sp, int st, float value, .float float_field, float score_factor, bool team) { client.(float_field) += value; float score_counter = client.(float_field) / score_factor; @@ -120,10 +120,10 @@ float _GameRules_scoring_add_float2int(entity client, entity sp, float value, .f // NOTE: this code works for subtracting score too int points = floor(score_counter + 0.5); - client.(float_field) -= points * score_factor; if (!points) return 0; - return PlayerScore_Add(client, sp, points); + client.(float_field) -= points * score_factor; + return team ? PlayerTeamScore_Add(client, sp, st, points) : PlayerScore_Add(client, sp, points); } float _GameRules_scoring_add(entity client, entity sp, float value) diff --git a/qcsrc/common/gamemodes/sv_rules.qh b/qcsrc/common/gamemodes/sv_rules.qh index 6078428b6..1cb6a8390 100644 --- a/qcsrc/common/gamemodes/sv_rules.qh +++ b/qcsrc/common/gamemodes/sv_rules.qh @@ -73,9 +73,11 @@ void GameRules_scoring_vip(entity player, bool value); bool GameRules_scoring_is_vip(entity player); #define GameRules_scoring_add_float2int(client, fld, value, float_field, score_factor) \ - _GameRules_scoring_add_float2int(client, SP_##fld, value, float_field, score_factor) -float _GameRules_scoring_add_float2int(entity client, entity sp, float value, .float field, float score_factor); + _GameRules_scoring_add_float2int(client, SP_##fld, 0, value, float_field, score_factor, false) +float _GameRules_scoring_add_float2int(entity client, entity sp, int st, float value, .float float_field, float score_factor, bool team); #define GameRules_scoring_add(client, fld, value) _GameRules_scoring_add(client, SP_##fld, value) float _GameRules_scoring_add(entity client, entity sp, float value); +#define GameRules_scoring_add_team_float2int(client, fld, value, float_field, score_factor) \ + _GameRules_scoring_add_float2int(client, SP_##fld, ST_##fld, value, float_field, score_factor, true) #define GameRules_scoring_add_team(client, fld, value) _GameRules_scoring_add_team(client, SP_##fld, ST_##fld, value) float _GameRules_scoring_add_team(entity client, entity sp, int st, float value); -- 2.39.5