/* =========================================================================== Copyright (C) 2023 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // DESCRIPTION: // Scoreboard #include "cg_local.h" void CG_GetScoreBoardColor(float *fR, float *fG, float *fB, float *fA) { *fR = 0.0f; *fG = 0.0f; *fB = 0.0f; *fA = 0.7f; } void CG_GetScoreBoardFontColor(float *fR, float *fG, float *fB, float *fA) { *fR = 1.0f; *fG = 1.0f; *fB = 1.0f; *fA = 1.0f; } void CG_GetScoreBoardPosition(float *fX, float *fY, float *fW, float *fH) { *fX = 32.0; *fY = 56.0; *fW = 384.0; *fH = 392.0; } int CG_GetScoreBoardDrawHeader() { return 0; } void CG_PrepScoreBoardInfo() { switch (cgs.gametype) { case GT_TEAM_ROUNDS: Q_strncpyz(cg.scoresMenuName, "DM_Round_Scoreboard", sizeof(cg.scoresMenuName)); break; case GT_OBJECTIVE: Q_strncpyz(cg.scoresMenuName, "Obj_Scoreboard", sizeof(cg.scoresMenuName)); break; case GT_TOW: Q_strncpyz(cg.scoresMenuName, "Tow_Scoreboard", sizeof(cg.scoresMenuName)); break; case GT_LIBERATION: Q_strncpyz(cg.scoresMenuName, "Lib_Scoreboard", sizeof(cg.scoresMenuName)); break; default: Q_strncpyz(cg.scoresMenuName, "DM_Scoreboard", sizeof(cg.scoresMenuName)); break; } } const char *CG_GetColumnName_ver_15(int iColumnNum, int *iColumnWidth) { int iReturnWidth; const char *pszReturnString; switch (iColumnNum) { case 0: iReturnWidth = 24; pszReturnString = "#"; break; case 1: iReturnWidth = 128; pszReturnString = "Name"; break; case 2: iReturnWidth = 64; pszReturnString = "Kills"; break; case 3: iReturnWidth = 64; pszReturnString = "Deaths"; if (cgs.gametype > GT_TEAM) { pszReturnString = "Total"; } break; case 4: iReturnWidth = 64; pszReturnString = "Time"; break; case 5: iReturnWidth = 64; pszReturnString = "Ping"; break; default: iReturnWidth = 0; pszReturnString = 0; break; } if (iColumnWidth) { *iColumnWidth = iReturnWidth; } return pszReturnString; } const char *CG_GetColumnName_ver_6(int iColumnNum, int *iColumnWidth) { int iReturnWidth; const char *pszReturnString; switch (iColumnNum) { case 0: iReturnWidth = 128; pszReturnString = "Name"; break; case 1: iReturnWidth = 64; pszReturnString = "Kills"; break; case 2: iReturnWidth = 64; pszReturnString = "Deaths"; if (cgs.gametype > GT_TEAM) { pszReturnString = "Total"; } break; case 3: iReturnWidth = 64; pszReturnString = "Time"; break; case 4: iReturnWidth = 64; pszReturnString = "Ping"; break; default: iReturnWidth = 0; pszReturnString = 0; break; } if (iColumnWidth) { *iColumnWidth = iReturnWidth; } return pszReturnString; } void CG_ParseScores_ver_15() { int i; int iEntryCount; int iClientTeam, iClientNum; int iDatumCount; int iMatchTeam; int iCurrentEntry; qboolean bIsDead, bIsHeader; char szString2[MAX_STRING_TOKENS]; char szString3[MAX_STRING_TOKENS]; char szString4[MAX_STRING_TOKENS]; char szString5[MAX_STRING_TOKENS]; char szString6[MAX_STRING_TOKENS]; char szString7[MAX_STRING_TOKENS]; float vSameTeamTextColor[4]; float vSameTeamBackColor[4]; float vOtherTeamTextColor[4]; float vOtherTeamBackColor[4]; float vNoTeamTextColor[4]; float vNoTeamBackColor[4]; float vThisClientTextColor[4]; float vThisClientBackColor[4]; float vDeadTextColorDead[4]; float *pItemTextColor; float *pItemBackColor; iMatchTeam = -1; vSameTeamTextColor[0] = 1.0f; vSameTeamTextColor[1] = 1.0f; vSameTeamTextColor[2] = 1.0f; vSameTeamTextColor[3] = 1.0f; vSameTeamBackColor[0] = 0.1f; vSameTeamBackColor[1] = 0.5f; vSameTeamBackColor[2] = 0.1f; vSameTeamBackColor[3] = 0.4f; vOtherTeamTextColor[0] = 1.0f; vOtherTeamTextColor[1] = 1.0f; vOtherTeamTextColor[2] = 1.0f; vOtherTeamTextColor[3] = 1.0f; vOtherTeamBackColor[0] = 0.5f; vOtherTeamBackColor[1] = 0.1f; vOtherTeamBackColor[2] = 0.1f; vOtherTeamBackColor[3] = 0.4f; vNoTeamTextColor[0] = 1.0f; vNoTeamTextColor[1] = 1.0f; vNoTeamTextColor[2] = 1.0f; vNoTeamTextColor[3] = 1.0f; vNoTeamBackColor[0] = 0.1f; vNoTeamBackColor[1] = 0.1f; vNoTeamBackColor[2] = 0.1f; vNoTeamBackColor[3] = 0.4f; vDeadTextColorDead[0] = 1.0f; vDeadTextColorDead[1] = 0.1f; vDeadTextColorDead[2] = 0.1f; vDeadTextColorDead[3] = 1.0f; vThisClientTextColor[0] = 0.0f; vThisClientTextColor[1] = 0.0f; vThisClientTextColor[2] = 0.0f; vThisClientTextColor[3] = 1.0f; if (cgs.gametype > GT_FFA) { vThisClientBackColor[0] = 0.5f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.5f; } else { vThisClientBackColor[0] = 0.75f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.75f; } vThisClientBackColor[3] = 0.8f; iCurrentEntry = 1; if (cgs.gametype > GT_FFA) { iDatumCount = 6; iMatchTeam = cg.snap->ps.stats[STAT_TEAM]; if (iMatchTeam != TEAM_ALLIES && iMatchTeam != TEAM_AXIS) { iMatchTeam = TEAM_ALLIES; vThisClientTextColor[0] = 0.0f; vThisClientTextColor[1] = 0.0f; vThisClientTextColor[2] = 0.0f; vThisClientBackColor[0] = 0.75f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.75f; } } else { // free-for-all iDatumCount = 5; } iEntryCount = atoi(cgi.Argv(iCurrentEntry++)); if (iEntryCount > MAX_CLIENTS) { iEntryCount = MAX_CLIENTS; } if (cgs.gametype == GT_TOW) { cgi.Cvar_Set("tow_allied_obj1", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_allied_obj2", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_allied_obj3", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_allied_obj4", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_allied_obj5", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_axis_obj1", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_axis_obj2", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_axis_obj3", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_axis_obj4", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("tow_axis_obj5", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); } if (cgs.gametype == GT_LIBERATION) { cgi.Cvar_Set("scoreboard_toggle1", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); cgi.Cvar_Set("scoreboard_toggle2", va("%i", (int)atof(cgi.Argv(iCurrentEntry++)))); } for (i = 0; i < iEntryCount; ++i) { bIsHeader = qfalse; if (cgs.gametype > GT_FFA) { iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i)); iClientTeam = atoi(cgi.Argv(1 + iCurrentEntry + iDatumCount * i)); if (iClientTeam >= 0) { bIsDead = qfalse; } else { bIsDead = qtrue; iClientTeam = -iClientTeam; } if (iClientNum == -1) { szString2[0] = 0; bIsHeader = qtrue; switch (iClientTeam) { case 1: Q_strncpyz(szString3, cgi.LV_ConvertString("Spectators"), sizeof(szString3)); break; case 2: Q_strncpyz(szString3, cgi.LV_ConvertString("Free-For-Allers"), sizeof(szString3)); break; case 3: Com_sprintf( szString3, sizeof(szString3), "%s - %d %s", cgi.LV_ConvertString("Allies"), atoi(cgi.Argv(2 + iCurrentEntry + iDatumCount * i)), cgi.LV_ConvertString("Players") ); iCurrentEntry++; break; case 4: Com_sprintf( szString3, sizeof(szString3), "%s - %d %s", cgi.LV_ConvertString("Axis"), atoi(cgi.Argv(2 + iCurrentEntry + iDatumCount * i)), cgi.LV_ConvertString("Players") ); iCurrentEntry++; break; default: Q_strncpyz(szString3, cgi.LV_ConvertString("No Team"), sizeof(szString3)); break; } } else if (iClientNum == -2) { // spectating szString2[0] = 0; szString3[0] = 0; } else { Q_strncpyz(szString2, va("%i", iClientNum), sizeof(szString2)); Q_strncpyz(szString3, cg.clientinfo[iClientNum].name, sizeof(szString3)); } Q_strncpyz(szString4, cgi.Argv(2 + iCurrentEntry + iDatumCount * i), sizeof(szString4)); Q_strncpyz(szString5, cgi.Argv(3 + iCurrentEntry + iDatumCount * i), sizeof(szString5)); Q_strncpyz(szString6, cgi.Argv(4 + iCurrentEntry + iDatumCount * i), sizeof(szString6)); Q_strncpyz(szString7, cgi.Argv(5 + iCurrentEntry + iDatumCount * i), sizeof(szString7)); if (cgs.gametype >= GT_TEAM_ROUNDS && iClientNum == -1 && (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS)) { strcat(szString4, va(" %s", cgi.LV_ConvertString("Wins"))); szString5[0] = 0; } if (iClientNum == cg.snap->ps.clientNum) { pItemTextColor = vThisClientTextColor; pItemBackColor = vThisClientBackColor; } else if (iClientNum == -2) { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } else if (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS) { if (iClientTeam == iMatchTeam) { pItemTextColor = vSameTeamTextColor; pItemBackColor = vSameTeamBackColor; } else { pItemTextColor = vOtherTeamTextColor; pItemBackColor = vOtherTeamBackColor; } } else { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } if (bIsDead) { pItemTextColor = vDeadTextColorDead; } } else { iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i)); if (iClientNum >= 0) { Q_strncpyz(szString2, va("%i", iClientNum), sizeof(szString2)); Q_strncpyz(szString3, cg.clientinfo[iClientNum].name, sizeof(szString3)); Q_strncpyz(szString4, cgi.Argv(1 + iCurrentEntry + iDatumCount * i), sizeof(szString4)); Q_strncpyz(szString5, cgi.Argv(2 + iCurrentEntry + iDatumCount * i), sizeof(szString5)); Q_strncpyz(szString6, cgi.Argv(3 + iCurrentEntry + iDatumCount * i), sizeof(szString6)); Q_strncpyz(szString7, cgi.Argv(4 + iCurrentEntry + iDatumCount * i), sizeof(szString7)); } else { szString2[0] = 0; if (iClientNum == -3) { Q_strncpyz(szString2, cgi.LV_ConvertString("Players"), sizeof(szString2)); bIsHeader = qtrue; } else if (iClientNum == -2) { Q_strncpyz(szString2, cgi.LV_ConvertString("Spectators"), sizeof(szString2)); bIsHeader = qtrue; } else { // unknown szString3[0] = 0; } szString4[0] = 0; szString5[0] = 0; szString6[0] = 0; szString7[0] = 0; } if (iClientNum == cg.snap->ps.clientNum) { pItemTextColor = vThisClientTextColor; pItemBackColor = vThisClientBackColor; } else { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } } cgi.UI_SetScoreBoardItem( i, szString2, szString3, szString4, szString5, szString6, szString7, NULL, NULL, pItemTextColor, pItemBackColor, bIsHeader ); } cgi.UI_DeleteScoreBoardItems(iEntryCount); } void CG_ParseScores_ver_6() { int i; int iEntryCount; int iClientTeam, iClientNum; int iDatumCount; int iMatchTeam; int iCurrentEntry; qboolean bIsDead, bIsHeader; char szString2[MAX_STRING_TOKENS]; char szString3[MAX_STRING_TOKENS]; char szString4[MAX_STRING_TOKENS]; char szString5[MAX_STRING_TOKENS]; char szString6[MAX_STRING_TOKENS]; float vSameTeamTextColor[4]; float vSameTeamBackColor[4]; float vOtherTeamTextColor[4]; float vOtherTeamBackColor[4]; float vNoTeamTextColor[4]; float vNoTeamBackColor[4]; float vThisClientTextColor[4]; float vThisClientBackColor[4]; float vDeadTextColorDead[4]; float *pItemTextColor; float *pItemBackColor; iMatchTeam = -1; vSameTeamTextColor[0] = 1.0f; vSameTeamTextColor[1] = 1.0f; vSameTeamTextColor[2] = 1.0f; vSameTeamTextColor[3] = 1.0f; vSameTeamBackColor[0] = 0.1f; vSameTeamBackColor[1] = 0.5f; vSameTeamBackColor[2] = 0.1f; vSameTeamBackColor[3] = 0.4f; vOtherTeamTextColor[0] = 1.0f; vOtherTeamTextColor[1] = 1.0f; vOtherTeamTextColor[2] = 1.0f; vOtherTeamTextColor[3] = 1.0f; vOtherTeamBackColor[0] = 0.5f; vOtherTeamBackColor[1] = 0.1f; vOtherTeamBackColor[2] = 0.1f; vOtherTeamBackColor[3] = 0.4f; vNoTeamTextColor[0] = 1.0f; vNoTeamTextColor[1] = 1.0f; vNoTeamTextColor[2] = 1.0f; vNoTeamTextColor[3] = 1.0f; vNoTeamBackColor[0] = 0.1f; vNoTeamBackColor[1] = 0.1f; vNoTeamBackColor[2] = 0.1f; vNoTeamBackColor[3] = 0.4f; vDeadTextColorDead[0] = 1.0f; vDeadTextColorDead[1] = 0.1f; vDeadTextColorDead[2] = 0.1f; vDeadTextColorDead[3] = 1.0f; vThisClientTextColor[0] = 0.0f; vThisClientTextColor[1] = 0.0f; vThisClientTextColor[2] = 0.0f; vThisClientTextColor[3] = 1.0f; if (cgs.gametype > GT_FFA) { vThisClientBackColor[0] = 0.5f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.5f; } else { vThisClientBackColor[0] = 0.75f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.75f; } vThisClientBackColor[3] = 0.8f; iCurrentEntry = 1; if (cgs.gametype > GT_FFA) { iDatumCount = 6; iMatchTeam = cg.snap->ps.stats[STAT_TEAM]; if (iMatchTeam != TEAM_ALLIES && iMatchTeam != TEAM_AXIS) { iMatchTeam = TEAM_ALLIES; vThisClientTextColor[0] = 0.0f; vThisClientTextColor[1] = 0.0f; vThisClientTextColor[2] = 0.0f; vThisClientBackColor[0] = 0.75f; vThisClientBackColor[1] = 0.75f; vThisClientBackColor[2] = 0.75f; } } else { // free-for-all iDatumCount = 5; } iEntryCount = atoi(cgi.Argv(iCurrentEntry++)); if (iEntryCount > MAX_CLIENTS) { iEntryCount = MAX_CLIENTS; } for (i = 0; i < iEntryCount; ++i) { bIsHeader = qfalse; if (cgs.gametype > GT_FFA) { iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i)); iClientTeam = atoi(cgi.Argv(1 + iCurrentEntry + iDatumCount * i)); if (iClientTeam >= 0) { bIsDead = qfalse; } else { bIsDead = qtrue; iClientTeam = -iClientTeam; } if (iClientNum == -1) { bIsHeader = qtrue; switch (iClientTeam) { case 1: Q_strncpyz(szString2, cgi.LV_ConvertString("Spectators"), sizeof(szString2)); break; case 2: Q_strncpyz(szString2, cgi.LV_ConvertString("Free-For-Allers"), sizeof(szString2)); break; case 3: Q_strncpyz(szString2, cgi.LV_ConvertString("Allies"), sizeof(szString2)); break; case 4: Q_strncpyz(szString2, cgi.LV_ConvertString("Axis"), sizeof(szString2)); break; default: Q_strncpyz(szString2, cgi.LV_ConvertString("No Team"), sizeof(szString2)); break; } } else if (iClientNum == -2) { // spectating szString2[0] = 0; } else { Q_strncpyz(szString2, cg.clientinfo[iClientNum].name, sizeof(szString2)); } Q_strncpyz(szString3, cgi.Argv(2 + iCurrentEntry + iDatumCount * i), sizeof(szString3)); Q_strncpyz(szString4, cgi.Argv(3 + iCurrentEntry + iDatumCount * i), sizeof(szString4)); Q_strncpyz(szString5, cgi.Argv(4 + iCurrentEntry + iDatumCount * i), sizeof(szString5)); Q_strncpyz(szString6, cgi.Argv(5 + iCurrentEntry + iDatumCount * i), sizeof(szString6)); if (iClientNum == cg.snap->ps.clientNum) { pItemTextColor = vThisClientTextColor; pItemBackColor = vThisClientBackColor; } else if (iClientNum == -2) { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } else if (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS) { if (iClientTeam == iMatchTeam) { pItemTextColor = vSameTeamTextColor; pItemBackColor = vSameTeamBackColor; } else { pItemTextColor = vOtherTeamTextColor; pItemBackColor = vOtherTeamBackColor; } } else { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } if (bIsDead) { pItemTextColor = vDeadTextColorDead; } } else { iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i)); if (iClientNum >= 0) { Q_strncpyz(szString2, cg.clientinfo[iClientNum].name, sizeof(szString2)); Q_strncpyz(szString3, cgi.Argv(1 + iCurrentEntry + iDatumCount * i), sizeof(szString3)); Q_strncpyz(szString4, cgi.Argv(2 + iCurrentEntry + iDatumCount * i), sizeof(szString4)); Q_strncpyz(szString5, cgi.Argv(3 + iCurrentEntry + iDatumCount * i), sizeof(szString5)); Q_strncpyz(szString6, cgi.Argv(4 + iCurrentEntry + iDatumCount * i), sizeof(szString6)); } else { if (iClientNum == -3) { Q_strncpyz(szString2, cgi.LV_ConvertString("Players"), sizeof(szString2)); bIsHeader = qtrue; } else if (iClientNum == -2) { Q_strncpyz(szString2, cgi.LV_ConvertString("Spectators"), sizeof(szString2)); bIsHeader = qtrue; } else { // unknown szString2[0] = 0; } szString3[0] = 0; szString4[0] = 0; szString5[0] = 0; szString6[0] = 0; } if (iClientNum == cg.snap->ps.clientNum) { pItemTextColor = vThisClientTextColor; pItemBackColor = vThisClientBackColor; } else { pItemTextColor = vNoTeamTextColor; pItemBackColor = vNoTeamBackColor; } } cgi.UI_SetScoreBoardItem( i, szString2, szString3, szString4, szString5, szString6, NULL, NULL, NULL, pItemTextColor, pItemBackColor, bIsHeader ); } cgi.UI_DeleteScoreBoardItems(iEntryCount); } void CG_ParseScores() { if (cg_protocol >= PROTOCOL_MOHTA_MIN) { CG_ParseScores_ver_15(); } else { CG_ParseScores_ver_6(); } } void CG_InitScoresAPI(clientGameExport_t *cge) { cge->CG_GetScoreBoardColor = CG_GetScoreBoardColor; cge->CG_GetScoreBoardFontColor = CG_GetScoreBoardFontColor; cge->CG_GetScoreBoardPosition = CG_GetScoreBoardPosition; cge->CG_GetScoreBoardDrawHeader = CG_GetScoreBoardDrawHeader; if (cg_protocol >= PROTOCOL_MOHTA_MIN) { cge->CG_GetColumnName = &CG_GetColumnName_ver_15; } else { cge->CG_GetColumnName = &CG_GetColumnName_ver_6; } }