Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/game/client/neo/c_neo_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_NEO_Player, DT_NEO_Player, CNEO_Player)
RecvPropInt(RECVINFO(m_iNextSpawnClassChoice)),
RecvPropInt(RECVINFO(m_bInLean)),
RecvPropEHandle(RECVINFO(m_hServerRagdoll)),
RecvPropEHandle(RECVINFO(m_hCommandingPlayer)),

RecvPropBool(RECVINFO(m_bInThermOpticCamo)),
RecvPropBool(RECVINFO(m_bLastTickInThermOpticCamo)),
Expand All @@ -100,6 +101,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_NEO_Player, DT_NEO_Player, CNEO_Player)
RecvPropArray(RecvPropInt(RECVINFO(m_rfAttackersScores[0])), m_rfAttackersScores),
RecvPropArray(RecvPropFloat(RECVINFO(m_rfAttackersAccumlator[0])), m_rfAttackersAccumlator),
RecvPropArray(RecvPropInt(RECVINFO(m_rfAttackersHits[0])), m_rfAttackersHits),
RecvPropArray(RecvPropVector(RECVINFO(m_vLastPingByStar[0])), m_vLastPingByStar),

RecvPropInt(RECVINFO(m_NeoFlags)),
RecvPropString(RECVINFO(m_szNeoName)),
Expand Down
3 changes: 3 additions & 0 deletions src/game/client/neo/c_neo_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ class C_NEO_Player : public C_HL2MP_Player

CNetworkVar(float, m_flNextPingTime);

CNetworkArray(Vector, m_vLastPingByStar, STAR__TOTAL);

CNetworkVar(bool, m_bInThermOpticCamo);
CNetworkVar(bool, m_bLastTickInThermOpticCamo);
CNetworkVar(bool, m_bInVision);
Expand All @@ -225,6 +227,7 @@ class C_NEO_Player : public C_HL2MP_Player
CNetworkVar(bool, m_bCarryingGhost);
CNetworkVar(bool, m_bIneligibleForLoadoutPick);
CNetworkHandle(CBaseEntity, m_hServerRagdoll);
CNetworkHandle(CBasePlayer, m_hCommandingPlayer);

CNetworkVar(int, m_iNeoClass);
CNetworkVar(int, m_iNeoSkin);
Expand Down
208 changes: 204 additions & 4 deletions src/game/client/neo/ui/neo_hud_round_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ void CNEOHud_RoundState::DrawNeoHudElement()
bool bDMRightSide = false;
if (NEORules()->IsTeamplay())
{
for (int i = 0; i < (MAX_PLAYERS + 1); i++)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
if (g_PR->IsConnected(i))
{
Expand Down Expand Up @@ -615,6 +615,14 @@ void CNEOHud_RoundState::DrawNeoHudElement()

void CNEOHud_RoundState::DrawPlayerList()
{
ConVarRef cl_neo_bot_cmdr_enable_ref("sv_neo_bot_cmdr_enable");
Assert(cl_neo_bot_cmdr_enable_ref.IsValid());
if (cl_neo_bot_cmdr_enable_ref.IsValid() && cl_neo_bot_cmdr_enable_ref.GetBool())
{
DrawPlayerList_BotCmdr();
return;
}

if (g_PR)
{
// Draw members of players squad in an old style list
Expand All @@ -638,7 +646,7 @@ void CNEOHud_RoundState::DrawPlayerList()
{
bool squadMateFound = false;

for (int i = 0; i < (MAX_PLAYERS + 1); i++)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
if (i == localPlayerIndex)
{
Expand Down Expand Up @@ -673,7 +681,7 @@ void CNEOHud_RoundState::DrawPlayerList()
m_iRightPlayersAlive = 0;

// Draw other team mates
for (int i = 0; i < (MAX_PLAYERS + 1); i++)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
if (!g_PR->IsConnected(i))
{
Expand Down Expand Up @@ -712,8 +720,127 @@ void CNEOHud_RoundState::DrawPlayerList()
}
}

void CNEOHud_RoundState::DrawPlayerList_BotCmdr()
{
if (!g_PR)
{
return;
}

// Draw members of players squad in an old style list
const int localPlayerTeam = GetLocalPlayerTeam();
const int localPlayerIndex = GetLocalPlayerIndex();
const bool localPlayerSpec = !(localPlayerTeam == TEAM_JINRAI || localPlayerTeam == TEAM_NSF);
const int leftTeam = cl_neo_hud_team_swap_sides.GetBool() ? (localPlayerSpec ? TEAM_JINRAI : localPlayerTeam) : TEAM_JINRAI;

int offset = 52;
if (cl_neo_squad_hud_star_scale.GetFloat() > 0)
{
IntDim res = {};
surface()->GetScreenSize(res.w, res.h);
offset *= cl_neo_squad_hud_star_scale.GetFloat() * res.h / 1080.0f;
}

const bool hideDueToScoreboard = cl_neo_hud_scoreboard_hide_others.GetBool() && g_pNeoScoreBoard->IsVisible();

// Draw squad mates
m_commandedList.RemoveAll();
m_nonCommandedList.RemoveAll();
m_nonSquadList.RemoveAll();

bool squadMateFound = false;
m_iLeftPlayersAlive = 0;
m_iRightPlayersAlive = 0;
const int localStar = g_PR->GetStar(localPlayerIndex);

// Single pass to collect and categorize players
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
if (!g_PR->IsConnected(i))
{
continue;
}
const int playerTeam = g_PR->GetTeam(i);
if (playerTeam != leftTeam)
{
if (g_PR->IsAlive(i))
{
m_iRightPlayersAlive++;
}
}
else {
if (g_PR->IsAlive(i))
{
m_iLeftPlayersAlive++;
}
}
if (playerTeam != localPlayerTeam)
{
continue;
}
if (i == localPlayerIndex || localPlayerSpec || hideDueToScoreboard || !ArePlayersOnSameTeam(i, localPlayerIndex))
{
continue;
}

// Only consider players in the same squad star as the local player
const bool isSameSquadStar = (localStar != STAR_NONE) && (g_PR->GetStar(i) == localStar);
if (isSameSquadStar)
{
C_NEO_Player* pPlayer = ToNEOPlayer(UTIL_PlayerByIndex(i));
bool isCommanded = (pPlayer && pPlayer->m_hCommandingPlayer.Get() == C_NEO_Player::GetLocalNEOPlayer());
if (isCommanded)
{
m_commandedList.AddToTail(i);
}
else
{
m_nonCommandedList.AddToTail(i);
}
squadMateFound = true;
}
else
{
m_nonSquadList.AddToTail(i);
}
}

// Draw commanded players first
const auto player = C_NEO_Player::GetLocalNEOPlayer();
TeamLogoColor* pTeamLogoColor = player ? &m_teamLogoColors[player->GetTeamNumber()] : nullptr;
const Color* colorOverride = pTeamLogoColor ? &pTeamLogoColor->color : nullptr;
for (int i = 0; i < m_commandedList.Count(); ++i)
{
offset = DrawPlayerRow_BotCmdr(m_commandedList[i], offset, false, colorOverride);
}

// Draw non-commanded players (who are also in the same squad star)
for (int i = 0; i < m_nonCommandedList.Count(); ++i)
{
offset = DrawPlayerRow_BotCmdr(m_nonCommandedList[i], offset, false);
}

if (squadMateFound)
{
offset += 12;
}

// Draw other team mates
for (int i = 0; i < m_nonSquadList.Count(); ++i)
{
offset = DrawPlayerRow_BotCmdr(m_nonSquadList[i], offset, true);
}
}

int CNEOHud_RoundState::DrawPlayerRow(int playerIndex, const int yOffset, bool small)
{
ConVarRef cl_neo_bot_cmdr_enable_ref("sv_neo_bot_cmdr_enable");
Assert(cl_neo_bot_cmdr_enable_ref.IsValid());
if (cl_neo_bot_cmdr_enable_ref.IsValid() && cl_neo_bot_cmdr_enable_ref.GetBool())
{
return DrawPlayerRow_BotCmdr(playerIndex, yOffset, small);
}

// Draw player
static constexpr int SQUAD_MATE_TEXT_LENGTH = 62; // 31 characters in name without end character max plus 3 in short rank name plus 7 max in class name plus 3 max in health plus other characters
char squadMateText[SQUAD_MATE_TEXT_LENGTH];
Expand Down Expand Up @@ -749,7 +876,7 @@ int CNEOHud_RoundState::DrawPlayerRow(int playerIndex, const int yOffset, bool s
auto* pImpersonator = pNeoPlayer ? pNeoPlayer->m_hSpectatorTakeoverPlayerImpersonatingMe.Get() : nullptr;

const char* pPlayerDisplayName = pImpersonator ?
pImpersonator->GetPlayerName()
pImpersonator->GetPlayerName()
: g_PR->GetPlayerName(playerIndex);

const char* displayClass = pImpersonator ? GetNeoClassName(pImpersonator->m_iClassBeforeTakeover) : squadMateClass;
Expand All @@ -767,6 +894,62 @@ int CNEOHud_RoundState::DrawPlayerRow(int playerIndex, const int yOffset, bool s
return yOffset + fontHeight;
}

int CNEOHud_RoundState::DrawPlayerRow_BotCmdr(int playerIndex, const int yOffset, bool small, const Color* colorOverride)
{
// Draw player
static constexpr int SQUAD_MATE_TEXT_LENGTH = 62; // 31 characters in name without end character max plus 3 in short rank name plus 7 max in class name plus 3 max in health plus other characters
char squadMateText[SQUAD_MATE_TEXT_LENGTH];
wchar_t wSquadMateText[SQUAD_MATE_TEXT_LENGTH];
const char* squadMateRankName = GetRankName(g_PR->GetXP(playerIndex), true);
const char* squadMateClass = GetNeoClassName(g_PR->GetClass(playerIndex));
const bool isAlive = g_PR->IsAlive(playerIndex);

C_NEO_Player* pNeoPlayer = ToNEOPlayer(UTIL_PlayerByIndex(playerIndex));
if (isAlive)
{
const char* pPlayerDisplayName = pNeoPlayer ?
pNeoPlayer->GetPlayerNameWithTakeoverContext(playerIndex)
: g_PR->GetPlayerName(playerIndex);

const char* displayRankName = squadMateRankName;
if (pNeoPlayer)
{
C_NEO_Player* pTakeoverTarget = ToNEOPlayer(pNeoPlayer->m_hSpectatorTakeoverPlayerTarget.Get());
if (pTakeoverTarget)
{
displayRankName = GetRankName(g_PR->GetXP(pTakeoverTarget->entindex()), true);
}
}

const int healthMode = cl_neo_hud_health_mode.GetInt();
char playerHealth[7]; // 4 digits + 2 letters
V_snprintf(playerHealth, sizeof(playerHealth), healthMode ? "%dhp" : "%d%%", g_PR->GetDisplayedHealth(playerIndex, healthMode));
V_snprintf(squadMateText, SQUAD_MATE_TEXT_LENGTH, "%s %s [%s] %s", pPlayerDisplayName, squadMateRankName, squadMateClass, playerHealth);
}
else
{
auto* pImpersonator = pNeoPlayer ? pNeoPlayer->m_hSpectatorTakeoverPlayerImpersonatingMe.Get() : nullptr;

const char* pPlayerDisplayName = pImpersonator ?
pImpersonator->GetPlayerName()
: g_PR->GetPlayerName(playerIndex);

const char* displayClass = pImpersonator ? GetNeoClassName(pImpersonator->m_iClassBeforeTakeover) : squadMateClass;
V_snprintf(squadMateText, SQUAD_MATE_TEXT_LENGTH, "%s [%s] DEAD", pPlayerDisplayName, displayClass);
}
int wSquadMateTextLen = g_pVGuiLocalize->ConvertANSIToUnicode(squadMateText, wSquadMateText, sizeof(wSquadMateText));

int fontWidth, fontHeight;
surface()->DrawSetTextFont(small ? m_hOCRSmallerFont : m_hOCRSmallFont);
surface()->GetTextSize(m_hOCRSmallFont, m_wszPlayersAliveUnicode, fontWidth, fontHeight);

surface()->DrawSetTextColor(colorOverride ? *colorOverride : (isAlive ? COLOR_FADED_WHITE : COLOR_DARK_FADED_WHITE));
surface()->DrawSetTextPos(8, yOffset);
surface()->DrawPrintText(wSquadMateText, wSquadMateTextLen - 1);

return yOffset + fontHeight;
}

void CNEOHud_RoundState::DrawPlayer(int playerIndex, int teamIndex, const TeamLogoColor &teamLogoColor,
const int xOffset, const bool drawHealthClass)
{
Expand All @@ -792,6 +975,23 @@ void CNEOHud_RoundState::DrawPlayer(int playerIndex, int teamIndex, const TeamLo
surface()->DrawSetColor(COLOR_DARK);
surface()->DrawTexturedRect(xOffset, Y_POS + 1, xOffset + m_ilogoSize, Y_POS + m_ilogoSize + 1);

ConVarRef cl_neo_bot_cmdr_enable_ref("sv_neo_bot_cmdr_enable");
Assert(cl_neo_bot_cmdr_enable_ref.IsValid());
if (cl_neo_bot_cmdr_enable_ref.IsValid() && cl_neo_bot_cmdr_enable_ref.GetBool())
{
// Draw Command Highlight Border on top of the avatar image
C_NEO_Player* pPlayer = static_cast<C_NEO_Player*>(UTIL_PlayerByIndex(playerIndex));
if (pPlayer && pPlayer->m_hCommandingPlayer.Get() == C_NEO_Player::GetLocalNEOPlayer())
{
surface()->DrawSetColor(COLOR_WHITE);
// Draw a thicker border inwards
for (int borderIndex = 0; borderIndex < 3; ++borderIndex)
{
surface()->DrawOutlinedRect(xOffset + borderIndex, Y_POS + borderIndex, xOffset + m_ilogoSize - borderIndex, Y_POS + m_ilogoSize - borderIndex);
}
}
}

// Deathmatch only: Draw XP on everyone
if (!NEORules()->IsTeamplay())
{
Expand Down
7 changes: 7 additions & 0 deletions src/game/client/neo/ui/neo_hud_round_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class CNEOHud_RoundState : public CNEOHud_ChildElement, public CHudElement, publ

void CheckActiveStar();
void DrawPlayerList();
void DrawPlayerList_BotCmdr();
int DrawPlayerRow(int playerIndex, int yOffset, bool small = false);
int DrawPlayerRow_BotCmdr(int playerIndex, int yOffset, bool small = false, const Color* highlightColor = nullptr);
void DrawPlayer(int playerIndex, int teamIndex, const TeamLogoColor &teamLogoColor,
const int xOffset, const bool drawHealthClass);
void SetTextureToAvatar(int playerIndex);
Expand Down Expand Up @@ -98,6 +100,11 @@ class CNEOHud_RoundState : public CNEOHud_ChildElement, public CHudElement, publ
int m_iBeepSecsTotal = 0;
NeoRoundStatus m_ePrevRoundStatus = NeoRoundStatus::Idle;

// Bot Commander Lists
CUtlVector<int> m_commandedList;
CUtlVector<int> m_nonCommandedList;
CUtlVector<int> m_nonSquadList;

CPanelAnimationVar(Color, box_color, "box_color", "200 200 200 40");
CPanelAnimationVarAliasType(bool, health_monochrome, "health_monochrome", "1", "bool");
CPanelAnimationVarAliasType(bool, top_left_corner, "top_left_corner", "0", "bool");
Expand Down
4 changes: 4 additions & 0 deletions src/game/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,8 @@ target_sources_grouped(
neo/bot/behavior/neo_bot_attack.h
neo/bot/behavior/neo_bot_behavior.cpp
neo/bot/behavior/neo_bot_behavior.h
neo/bot/behavior/neo_bot_command_follow.cpp
neo/bot/behavior/neo_bot_command_follow.h
neo/bot/behavior/neo_bot_dead.cpp
neo/bot/behavior/neo_bot_dead.h
neo/bot/behavior/neo_bot_jgr_capture.cpp
Expand All @@ -1452,6 +1454,8 @@ target_sources_grouped(
neo/bot/behavior/neo_bot_melee_attack.h
neo/bot/behavior/neo_bot_move_to_vantage_point.cpp
neo/bot/behavior/neo_bot_move_to_vantage_point.h
neo/bot/behavior/neo_bot_pause.cpp
neo/bot/behavior/neo_bot_pause.h
neo/bot/behavior/neo_bot_retreat_to_cover.cpp
neo/bot/behavior/neo_bot_retreat_to_cover.h
neo/bot/behavior/neo_bot_retreat_from_grenade.cpp
Expand Down
Loading