From 2e0f46beb1993dd91c3119932582db96cdaf7122 Mon Sep 17 00:00:00 2001 From: ricardoofnl Date: Thu, 3 Sep 2026 01:59:44 +0700 Subject: [PATCH] [saco] Implement `CScoreBoard::FUNC_1006ED30`; `Show` and six small helpers match, the refresh is 444/892 off --- saco/d3d9/common/DXUTgui.h | 1 + saco/net/netplayer.h | 2 + saco/net/playerpool.h | 20 +++++++++ saco/scoreboard.cpp | 84 +++++++++++++++++++++++++++++++++++++- saco/scoreboard.h | 9 ++++ 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/saco/d3d9/common/DXUTgui.h b/saco/d3d9/common/DXUTgui.h index 7a16dbc..c803498 100644 --- a/saco/d3d9/common/DXUTgui.h +++ b/saco/d3d9/common/DXUTgui.h @@ -637,6 +637,7 @@ public: int GetSelectedIndex( int nPreviousSelected = -1 ); DXUTListBoxItem *GetSelectedItem( int nPreviousSelected = -1 ) { return GetItem( GetSelectedIndex( nPreviousSelected ) ); } void SelectItem( int nNewIndex ); + CDXUTScrollBar *GetScrollBar() { return &m_ScrollBar; } enum STYLE { MULTISELECTION = 1 }; diff --git a/saco/net/netplayer.h b/saco/net/netplayer.h index f7c3702..27391b0 100644 --- a/saco/net/netplayer.h +++ b/saco/net/netplayer.h @@ -17,6 +17,8 @@ public: std::string m_PlayerName; void SetPlayerName(PCHAR szName) { m_PlayerName = szName; }; + int GetScore() { return field_4; }; + int GetPing() { return field_C; }; CNetPlayer(PCHAR szPlayerName, BOOL bIsNPC); ~CNetPlayer(); diff --git a/saco/net/playerpool.h b/saco/net/playerpool.h index 12d9771..9b966bb 100644 --- a/saco/net/playerpool.h +++ b/saco/net/playerpool.h @@ -56,6 +56,26 @@ public: PCHAR FUNC_100175C0(int iPlayerId); // .text:100175C0 + BOOL IsPlayerNPC(PLAYERID playerId) { + if(playerId > MAX_PLAYERS) return FALSE; + CNetPlayer *pPlayer = m_pPlayers[playerId]; + if(!pPlayer) return FALSE; + return pPlayer->m_bIsNPC; + } + int GetPlayerScore(PLAYERID playerId) { + if(playerId > MAX_PLAYERS) return 0; + CNetPlayer *pPlayer = m_pPlayers[playerId]; + if(!pPlayer) return 0; + return pPlayer->GetScore(); + } + int GetPlayerPing(PLAYERID playerId) { + if(playerId > MAX_PLAYERS) return 0; + CNetPlayer *pPlayer = m_pPlayers[playerId]; + if(!pPlayer) return 0; + return pPlayer->GetPing(); + } + int GetPlayerCount(BOOL bIncludeNPCs); // .text:100139F0, todo: implement + class CObject *FUNC_10013B70(ENTITY_TYPE *pEntity); // todo: implement void sub_10013C90(); // todo: implement diff --git a/saco/scoreboard.cpp b/saco/scoreboard.cpp index 680f891..7fd406b 100644 --- a/saco/scoreboard.cpp +++ b/saco/scoreboard.cpp @@ -92,9 +92,91 @@ void CScoreBoard::Hide(bool bResetInput) field_0 = 0; } -// stub: rebuilds the three player columns from the pool, not reconstructed yet +// swapping rows through a temp is what retail inlines at both sort sites +inline void SwapScoreboardRows(SCOREBOARD_ROW *pA, SCOREBOARD_ROW *pB) +{ + SCOREBOARD_ROW tmp = *pA; + *pA = *pB; + *pB = tmp; +} + void CScoreBoard::FUNC_1006ED30() { + if(!pNetGame) return; + if(!pNetGame->GetPlayerPool()) return; + if(!field_0) return; + if(!m_pDialog) return; + + int nSelected = m_pListBox->GetSelectedIndex(); + CDXUTScrollBar *pScrollBar = m_pListBox->GetScrollBar(); + int nTrackPos = pScrollBar->GetTrackPos(); + m_pListBox->RemoveAllItems(); + + CPlayerPool *pPlayerPool = pNetGame->GetPlayerPool(); + int nRows = pPlayerPool->GetPlayerCount(0) + 1; + int localPlayerId = pPlayerPool->GetLocalPlayerID(); + SCOREBOARD_ROW *pRows = (SCOREBOARD_ROW *)calloc(nRows, sizeof(SCOREBOARD_ROW)); + + strcpy(pRows->szName, pPlayerPool->GetLocalPlayerName()); + pRows->Color = pPlayerPool->GetLocalPlayer()->GetPlayerColorAsARGB(); + pRows->iScore = pPlayerPool->field_0; + pRows->iPing = pPlayerPool->field_22; + pRows->iPlayerId = pPlayerPool->GetLocalPlayerID(); + + SCOREBOARD_ROW *pRow = pRows + 1; + for(int playerId = 0; playerId < MAX_PLAYERS; playerId++) + { + if(pPlayerPool->GetSlotState((PLAYERID)playerId) != 1) continue; + if(playerId == localPlayerId) continue; + if(pPlayerPool->IsPlayerNPC((PLAYERID)playerId)) continue; + + pRow->iPing = pPlayerPool->GetPlayerPing((PLAYERID)playerId); + strcpy(pRow->szName, pPlayerPool->FUNC_100175C0(playerId)); + pRow->iScore = pPlayerPool->GetPlayerScore((PLAYERID)playerId); + pRow->Color = pPlayerPool->GetAt((PLAYERID)playerId)->GetPlayerColorAsARGB(); + pRow->iPlayerId = playerId; + pRow++; + } + + if(field_40 == 1) + { + for(int i = nRows - 1; i > 0; i--) + for(int j = 0; j < i; j++) + if(strcmp(pRows[j + 1].szName, pRows[j].szName) < 0) + SwapScoreboardRows(&pRows[j], &pRows[j + 1]); + } + else if(field_40 == 2) + { + for(int i = nRows - 1; i > 0; i--) + for(int j = 0; j < i; j++) + if(pRows[j + 1].iScore > pRows[j].iScore) + SwapScoreboardRows(&pRows[j], &pRows[j + 1]); + } + + char szText[260]; + for(int i = 0; i < nRows; i++) + { + sprintf(szText, "%u", pRows[i].iPlayerId); + m_pListBox->AddItem(szText, (void *)pRows[i].iPlayerId, pRows[i].Color); + + if(m_pListBox->GetItem(i) && pRows[i].szName[0]) + { + m_pListBox->SetItemColumnText(i, 0, pRows[i].szName); + sprintf(szText, "%d", pRows[i].iScore); + m_pListBox->SetItemColumnText(i, 1, szText); + sprintf(szText, "%u", pRows[i].iPing); + m_pListBox->SetItemColumnText(i, 2, szText); + } + } + + if(nSelected < 0) + m_pListBox->SelectItem(-1); + else + m_pListBox->SelectItem(nSelected); + + free(pRows); + + pScrollBar->SetTrackPos(nTrackPos); } void CScoreBoard::Show() diff --git a/saco/scoreboard.h b/saco/scoreboard.h index 268255f..1dcd925 100644 --- a/saco/scoreboard.h +++ b/saco/scoreboard.h @@ -1,6 +1,15 @@ #pragma once +struct SCOREBOARD_ROW +{ + D3DCOLOR Color; + char szName[29]; + int iPlayerId; + int iScore; + int iPing; +}; + class CScoreBoard { private: