From d11599b4c85bbd41163ebd3308642f9c491b4a3c Mon Sep 17 00:00:00 2001 From: terencehill Date: Sun, 11 Jun 2023 12:16:52 +0000 Subject: [PATCH] Survival: show hunters to other hunters in the scoreboard. It fixes #2844 --- qcsrc/client/hud/panel/scoreboard.qc | 8 +++- .../gamemode/survival/cl_survival.qc | 34 +++++++++----- .../gamemode/survival/sv_survival.qc | 44 +++++++++---------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index b04600dcf..adcadb00d 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -973,7 +973,13 @@ string Scoreboard_GetName(entity pl) } else if(!teamplay) { - int f = entcs_GetClientColors(pl.sv_entnum); + int f; + // NOTE: always adding 1024 allows saving the colormap 0 as a value != 0 + if (playerslots[pl.sv_entnum].colormap >= 1024) + f = playerslots[pl.sv_entnum].colormap - 1024; // override server-side player colors + else + f = entcs_GetClientColors(pl.sv_entnum); + { sbt_field_icon0 = "gfx/scoreboard/playercolor_base"; sbt_field_icon1 = "gfx/scoreboard/playercolor_shirt"; diff --git a/qcsrc/common/gamemodes/gamemode/survival/cl_survival.qc b/qcsrc/common/gamemodes/gamemode/survival/cl_survival.qc index 72f4b83e0..01e6a6006 100644 --- a/qcsrc/common/gamemodes/gamemode/survival/cl_survival.qc +++ b/qcsrc/common/gamemodes/gamemode/survival/cl_survival.qc @@ -8,13 +8,13 @@ NET_HANDLE(ENT_CLIENT_SURVIVALSTATUSES, bool isnew) make_pure(this); int sf = 0; serialize(byte, 0, sf); - if (sf & BIT(1)) + if (sf & BIT(1)) // make all players survivors { for (int j = 0; j < maxclients; ++j) if (playerslots[j]) playerslots[j].survival_status = SURV_STATUS_PREY; } - if (sf & BIT(0)) + if (sf & BIT(0)) // reveal hunters (to hunters) { for (int i = 1; i <= maxclients; i += 8) { @@ -29,6 +29,24 @@ NET_HANDLE(ENT_CLIENT_SURVIVALSTATUSES, bool isnew) } } } + + // we could check STAT(GAME_STOPPED) instead of this dedicated flag, + // unfortunately STAT(GAME_STOPPED) is still false right when we receive this + bool reveal_hunters_to_survivors = (sf & BIT(2)); // when a round ends + + int mystatus = playerslots[player_localnum].survival_status; + for (int i = 1; i <= maxclients; ++i) + { + entity e = playerslots[i - 1]; + if (!e) continue; + + int plcolor = SURV_COLOR_PREY; + if(e.survival_status == SURV_STATUS_HUNTER && (mystatus == SURV_STATUS_HUNTER || reveal_hunters_to_survivors)) + plcolor = SURV_COLOR_HUNTER; + + e.colormap = 1024 + plcolor; // override scoreboard and player model colors + } + return true; } @@ -69,14 +87,10 @@ MUTATOR_HOOKFUNCTION(cl_surv, ForcePlayercolors_Skip, CBC_ORDER_LAST) entity player = M_ARGV(0, entity); entity e = playerslots[player.entnum - 1]; - int surv_status = ((e) ? e.survival_status : SURV_COLOR_PREY); - int mystatus = playerslots[player_localnum].survival_status; - - int plcolor = SURV_COLOR_PREY; // default to survivor - if((mystatus == SURV_STATUS_HUNTER || intermission || STAT(GAME_STOPPED)) && surv_status == SURV_STATUS_HUNTER) - plcolor = SURV_COLOR_HUNTER; - - player.colormap = 1024 + plcolor; + if (e && e.colormap) + player.colormap = e.colormap; + else + player.colormap = 1024 + SURV_COLOR_PREY; return true; } diff --git a/qcsrc/common/gamemodes/gamemode/survival/sv_survival.qc b/qcsrc/common/gamemodes/gamemode/survival/sv_survival.qc index 83817ac8e..dea924772 100644 --- a/qcsrc/common/gamemodes/gamemode/survival/sv_survival.qc +++ b/qcsrc/common/gamemodes/gamemode/survival/sv_survival.qc @@ -15,6 +15,13 @@ void SurvivalStatuses_Send() { // SendFlags can be set to anything != 0, SurvivalStatuses_SendEntity won't use its value survivalStatuses.SendFlags = 1; + survivalStatuses.nextthink = 0; // clear delayed send +} + +void SurvivalStatuses_Send_Delayed() +{ + survivalStatuses.think = SurvivalStatuses_Send; + survivalStatuses.nextthink = time + 0.2; } bool SurvivalStatuses_SendEntity(entity this, entity dest, float sendflags) @@ -22,12 +29,13 @@ bool SurvivalStatuses_SendEntity(entity this, entity dest, float sendflags) Stream out = MSG_ENTITY; WriteHeader(out, ENT_CLIENT_SURVIVALSTATUSES); - sendflags = BIT(0) | BIT(1); + sendflags |= BIT(1); // make all players survivors - // send hunter statuses only to hunters - bool send_hunter_statuses = (dest.survival_status == SURV_STATUS_HUNTER || STAT(GAME_STOPPED)); - if (!send_hunter_statuses) - sendflags &= !BIT(0); + if (dest.survival_status == SURV_STATUS_HUNTER); + sendflags |= BIT(0); // send hunter statuses + + if (round_handler_AwaitingNextRound()) + sendflags |= (BIT(0) | BIT(2)); // send hunter statuses and reveal hunters to survivors serialize(byte, out, sendflags); if (sendflags & BIT(0)) { @@ -35,7 +43,7 @@ bool SurvivalStatuses_SendEntity(entity this, entity dest, float sendflags) int f = 0; entity e = edict_num(i); for (int b = 0; b < 8; ++b, e = nextent(e)) { - bool is_hunter = (IS_PLAYER(e) && e.survival_status == SURV_STATUS_HUNTER); + bool is_hunter = (INGAME(e) && e.survival_status == SURV_STATUS_HUNTER); if (is_hunter) f |= BIT(b); } @@ -95,6 +103,7 @@ float Surv_CheckWinner() allowed_to_spawn = false; game_stopped = true; round_handler_Init(5, autocvar_g_survival_warmup, autocvar_g_survival_round_timelimit); + SurvivalStatuses_Send(); return 1; } @@ -132,6 +141,7 @@ float Surv_CheckWinner() allowed_to_spawn = false; game_stopped = true; round_handler_Init(5, autocvar_g_survival_warmup, autocvar_g_survival_round_timelimit); + SurvivalStatuses_Send(); FOREACH_CLIENT(true, { @@ -256,21 +266,6 @@ MUTATOR_HOOKFUNCTION(surv, ClientObituary) M_ARGV(5, bool) = true; // anonymous attacker } -MUTATOR_HOOKFUNCTION(surv, PlayerPreThink) -{ - entity player = M_ARGV(0, entity); - - if(IS_PLAYER(player) || INGAME(player)) - { - // update the scoreboard colour display to out the real killer at the end of the round - // running this every frame to avoid cheats - int plcolor = SURV_COLOR_PREY; - if(player.survival_status == SURV_STATUS_HUNTER && game_stopped) - plcolor = SURV_COLOR_HUNTER; - setcolor(player, plcolor); - } -} - MUTATOR_HOOKFUNCTION(surv, PlayerSpawn) { entity player = M_ARGV(0, entity); @@ -310,6 +305,10 @@ MUTATOR_HOOKFUNCTION(surv, PutClientInServer) if (!warmup_stage) eliminatedPlayers.SendFlags |= 1; + // send statuses with a small delay to make sure a playerslot exists, otherwise + // personal colors for this player won't be overriden + // it also reduces network traffic when multiple clients join the server at once (at map start) + SurvivalStatuses_Send_Delayed(); } MUTATOR_HOOKFUNCTION(surv, reset_map_players) @@ -325,6 +324,7 @@ MUTATOR_HOOKFUNCTION(surv, reset_map_players) } }); bot_relinkplayerlist(); + // this will also clear scheduled SurvivalStatuses_Send set by PutClientInServer SurvivalStatuses_Send(); return true; } @@ -383,7 +383,7 @@ MUTATOR_HOOKFUNCTION(surv, PlayerDies) // killed an ally! punishment is death if(autocvar_g_survival_punish_teamkill && frag_attacker != frag_target && IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target) && frag_attacker.survival_status == frag_target.survival_status && !ITEM_DAMAGE_NEEDKILL(frag_deathtype)) - if(!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted()) // don't autokill if the round hasn't + if(!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted()) // don't autokill if the round hasn't started yet Damage(frag_attacker, frag_attacker, frag_attacker, 100000, DEATH_MIRRORDAMAGE.m_id, DMG_NOWEP, frag_attacker.origin, '0 0 0'); return true; } -- 2.39.2