From 4a9c2668abd888f0524b63a3272b4c91ea1ff436 Mon Sep 17 00:00:00 2001 From: terencehill Date: Sun, 1 Sep 2024 14:12:09 +0200 Subject: [PATCH] Don't allow StatusEffects_gettime to return a time in the past By not doing so the effect would be still active in the last frame even if end time has passed. It prevents wrong usage of the returned value, for example in Fire_AddDamage where mintime can be set to a negative value and used to apply a negative damage to the player Removed now redundant max operations at StatusEffects_gettime call sites --- .gitlab-ci.yml | 2 +- qcsrc/common/mutators/mutator/buffs/sv_buffs.qc | 2 +- .../mutators/mutator/status_effects/status_effects.qc | 5 ++++- qcsrc/server/client.qc | 2 +- qcsrc/server/items/items.qc | 11 ++++++----- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 55eb8a1bb..d96b58c55 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,7 +36,7 @@ test_compilation_units: test_sv_game: stage: test script: - - export EXPECT=e67187c8446f97a8b062a431dccb89e0 + - export EXPECT=28a49dd762a7a794f210eeadbbc37a8e - qcsrc/tools/sv_game-hashtest.sh - exit $? diff --git a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc index e51c7cc9d..4c6db060a 100644 --- a/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc +++ b/qcsrc/common/mutators/mutator/buffs/sv_buffs.qc @@ -247,7 +247,7 @@ void buff_Touch(entity this, entity toucher) buff_RemoveAll(toucher, STATUSEFFECT_REMOVE_NORMAL); // remove previous buffs so that a new one may be added if(bufftime) - StatusEffects_apply(thebuff, toucher, min(time + bufftime, max(oldtime, time) + bufftime), 0); + StatusEffects_apply(thebuff, toucher, min(time + bufftime, oldtime + bufftime), 0); else StatusEffects_apply(thebuff, toucher, time + 999, 0); // HACK: zero timer means "infinite"! diff --git a/qcsrc/common/mutators/mutator/status_effects/status_effects.qc b/qcsrc/common/mutators/mutator/status_effects/status_effects.qc index 577503244..e4301d3c5 100644 --- a/qcsrc/common/mutators/mutator/status_effects/status_effects.qc +++ b/qcsrc/common/mutators/mutator/status_effects/status_effects.qc @@ -21,7 +21,10 @@ float StatusEffects_gettime(StatusEffects this, entity actor) store = actor.statuseffects; #endif if(!store) return 0; - return store.statuseffect_time[this.m_id]; + float eff_time = store.statuseffect_time[this.m_id]; + // if effect end time has passed and m_tick hasn't removed the effect yet + // return current time since the effect is actually still active in this frame + return (eff_time < time ? time : eff_time); } #endif #ifdef SVQC diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index c5dd18268..355c134d8 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -1557,7 +1557,7 @@ void player_powerups(entity this) else { play_countdown(this, StatusEffects_gettime(STATUSEFFECT_Superweapons, this), SND_POWEROFF); - if (time > StatusEffects_gettime(STATUSEFFECT_Superweapons, this)) + if (time >= StatusEffects_gettime(STATUSEFFECT_Superweapons, this)) { this.items = this.items - (this.items & IT_SUPERWEAPON); STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS; diff --git a/qcsrc/server/items/items.qc b/qcsrc/server/items/items.qc index 6fc66efbd..7ceb2b62f 100644 --- a/qcsrc/server/items/items.qc +++ b/qcsrc/server/items/items.qc @@ -604,7 +604,7 @@ bool Item_GiveTo(entity item, entity player) if (item.strength_finished) { pickedup = true; - float t = max(StatusEffects_gettime(STATUSEFFECT_Strength, player), time); + float t = StatusEffects_gettime(STATUSEFFECT_Strength, player); if (autocvar_g_powerups_stack) t += item.strength_finished; else @@ -614,7 +614,7 @@ bool Item_GiveTo(entity item, entity player) if (item.invincible_finished) { pickedup = true; - float t = max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time); + float t = StatusEffects_gettime(STATUSEFFECT_Shield, player); if (autocvar_g_powerups_stack) t += item.invincible_finished; else @@ -624,7 +624,7 @@ bool Item_GiveTo(entity item, entity player) if (item.speed_finished) { pickedup = true; - float t = max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time); + float t = StatusEffects_gettime(STATUSEFFECT_Speed, player); if (autocvar_g_powerups_stack) t += item.speed_finished; else @@ -634,7 +634,7 @@ bool Item_GiveTo(entity item, entity player) if (item.invisibility_finished) { pickedup = true; - float t = max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time); + float t = StatusEffects_gettime(STATUSEFFECT_Invisibility, player); if (autocvar_g_powerups_stack) t += item.invisibility_finished; else @@ -644,7 +644,8 @@ bool Item_GiveTo(entity item, entity player) if (item.superweapons_finished) { pickedup = true; - StatusEffects_apply(STATUSEFFECT_Superweapons, player, max(StatusEffects_gettime(STATUSEFFECT_Superweapons, player), time) + item.superweapons_finished, 0); + float t = StatusEffects_gettime(STATUSEFFECT_Superweapons, player); + StatusEffects_apply(STATUSEFFECT_Superweapons, player, t + item.superweapons_finished, 0); } // always eat teamed entities -- 2.39.2