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
Original file line number Diff line number Diff line change
Expand Up @@ -1592,36 +1592,7 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
if (TheNetwork->sawCRCMismatch())
{
++stats.desyncs[ptIdx];
}
else if (gameEndedInDisconnect)
{
++stats.discons[ptIdx];
}
else if (TheVictoryConditions->isLocalAlliedDefeat() || !TheVictoryConditions->getEndFrame())
{
++stats.losses[ptIdx];
}
else
{
++stats.wins[ptIdx];
}

ScoreKeeper *s = player->getScoreKeeper();
stats.buildingsBuilt[ptIdx] += s->getTotalBuildingsBuilt();
stats.buildingsKilled[ptIdx] += s->getTotalBuildingsDestroyed();
stats.buildingsLost[ptIdx] += s->getTotalBuildingsLost();

if (TheGameSpyGame->isQMGame())
{
stats.QMGames[ptIdx]++;
}
else
{
stats.customGames[ptIdx]++;
}

if (TheNetwork->sawCRCMismatch())
{
stats.lossesInARow = 0;
stats.desyncsInARow++;
stats.disconsInARow = 0;
Expand All @@ -1630,6 +1601,8 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else if (gameEndedInDisconnect)
{
++stats.discons[ptIdx];

stats.lossesInARow = 0;
stats.desyncsInARow = 0;
stats.disconsInARow++;
Expand All @@ -1638,6 +1611,8 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else if (TheVictoryConditions->isLocalAlliedVictory())
{
++stats.wins[ptIdx];

stats.lossesInARow = 0;
stats.desyncsInARow = 0;
stats.disconsInARow = 0;
Expand All @@ -1646,13 +1621,29 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else
{
++stats.losses[ptIdx];

stats.lossesInARow++;
stats.desyncsInARow = 0;
stats.disconsInARow = 0;
stats.winsInARow = 0;
stats.maxLossesInARow = max(stats.lossesInARow, stats.maxLossesInARow);
}

ScoreKeeper *s = player->getScoreKeeper();
stats.buildingsBuilt[ptIdx] += s->getTotalBuildingsBuilt();
stats.buildingsKilled[ptIdx] += s->getTotalBuildingsDestroyed();
stats.buildingsLost[ptIdx] += s->getTotalBuildingsLost();

if (TheGameSpyGame->isQMGame())
{
stats.QMGames[ptIdx]++;
}
else
{
stats.customGames[ptIdx]++;
}

stats.earnings[ptIdx] += s->getTotalMoneyEarned();
stats.duration[ptIdx] += TheGameLogic->getFrame() / LOGICFRAMES_PER_SECOND / 60; // in minutes
stats.games[ptIdx]++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,15 @@ class VictoryConditions : public VictoryConditionsInterface
Bool amIObserver( void ) { return m_isObserver;} ///< Am I an observer?( need this for scripts )
virtual UnsignedInt getEndFrame( void ) { return m_endFrame; } ///< on which frame was the game effectively over?
private:
Player* findFirstVictoriousPlayer(); ///< Find the first player that has achieved victory.
void markAllianceVictorious(Player* victoriousPlayer); ///< Mark the victorious player and his allies as victorious.
Bool multipleAlliancesExist(void); ///< Are there multiple alliances still alive?

Player* m_players[MAX_PLAYER_COUNT];
Int m_localSlotNum;
UnsignedInt m_endFrame;
Bool m_isDefeated[MAX_PLAYER_COUNT];
Bool m_isVictorious[MAX_PLAYER_COUNT];
Bool m_localPlayerDefeated; ///< prevents condition from being signaled each frame
Bool m_singleAllianceRemaining; ///< prevents condition from being signaled each frame
Bool m_isObserver;
Expand Down Expand Up @@ -127,6 +132,7 @@ void VictoryConditions::reset( void )
{
m_players[i] = nullptr;
m_isDefeated[i] = false;
m_isVictorious[i] = false;
}
m_localSlotNum = -1;

Expand All @@ -139,42 +145,54 @@ void VictoryConditions::reset( void )
}

//-------------------------------------------------------------------------------------------------
void VictoryConditions::update( void )
Bool VictoryConditions::multipleAlliancesExist()
{
if (!TheRecorder->isMultiplayer() || (m_localSlotNum < 0 && !m_isObserver))
return;
Player* alive = nullptr;

// Check for a single winning alliance
if (!m_singleAllianceRemaining)
for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
{
Bool multipleAlliances = false;
Player *alive = nullptr;
Player *player;
for (Int i=0; i<MAX_PLAYER_COUNT; ++i)
Player* player = m_players[i];

if (player && !hasSinglePlayerBeenDefeated(player))
{
player = m_players[i];
if (player && !hasSinglePlayerBeenDefeated(player))
if (alive)
{
if (alive)
// check to verify they are on the same team
if (!areAllies(alive, player))
{
// check to verify they are on the same team
if (!areAllies(alive, player))
{
multipleAlliances = true;
break;
}
}
else
{
alive = player; // save this pointer to check against
return true;
}
}
else
{
alive = player; // save this pointer to check against
}
}
}

if (!multipleAlliances)
return false;
}

//-------------------------------------------------------------------------------------------------
void VictoryConditions::update( void )
{
if (!TheRecorder->isMultiplayer() || (m_localSlotNum < 0 && !m_isObserver))
return;

// Check for a single winning alliance
if (!m_singleAllianceRemaining)
{
if (!multipleAlliancesExist())
{
m_singleAllianceRemaining = true; // don't check again
m_endFrame = TheGameLogic->getFrame();

// TheSuperHackers @bugfix Stubbjax 11/02/2026 Cache victory status so that premature exits don't void the victory.

Player* victoriousPlayer = findFirstVictoriousPlayer();

if (victoriousPlayer)
markAllianceVictorious(victoriousPlayer);
}
}

Expand Down Expand Up @@ -233,19 +251,51 @@ void VictoryConditions::update( void )
}
}

//-------------------------------------------------------------------------------------------------
Player* VictoryConditions::findFirstVictoriousPlayer()
{
for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
{
Player* player = m_players[i];
if (player && !hasSinglePlayerBeenDefeated(player))
return player;
}

return nullptr;
}

//-------------------------------------------------------------------------------------------------
void VictoryConditions::markAllianceVictorious(Player* victoriousPlayer)
{
// This marks the player and any allies as victorious, including defeated allies.
// This also ensures players retain their victorious status if their assets are destroyed after
// the victory conditions are met (e.g. when quitting the game prior to the victory screen).

for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
{
Player* player = m_players[i];
if (player == victoriousPlayer || (player && areAllies(player, victoriousPlayer)))
m_isVictorious[i] = true;
}
}

//-------------------------------------------------------------------------------------------------
Bool VictoryConditions::hasAchievedVictory(Player *player)
{
if (!player)
return false;

if (m_singleAllianceRemaining)
if (!m_singleAllianceRemaining)
return false;

for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
{
for (Int i=0; i<MAX_PLAYER_COUNT; ++i)
if (player == m_players[i])
{
if ( m_players[i] && !hasSinglePlayerBeenDefeated(m_players[i]) &&
(player == m_players[i] || areAllies(m_players[i], player)) )
if (m_isVictorious[i])
return true;

break;
}
}

Expand All @@ -258,8 +308,19 @@ Bool VictoryConditions::hasBeenDefeated(Player *player)
if (!player)
return false;

if (m_singleAllianceRemaining && !hasAchievedVictory(player))
return true;
if (!m_singleAllianceRemaining)
return false;

for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
{
if (player == m_players[i])
{
if (m_isDefeated[i])
return true;

break;
}
}

return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1859,36 +1859,7 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
if (TheNetwork->sawCRCMismatch())
{
++stats.desyncs[ptIdx];
}
else if (gameEndedInDisconnect)
{
++stats.discons[ptIdx];
}
else if (TheVictoryConditions->isLocalAlliedDefeat() || !TheVictoryConditions->getEndFrame())
{
++stats.losses[ptIdx];
}
else
{
++stats.wins[ptIdx];
}

ScoreKeeper *s = player->getScoreKeeper();
stats.buildingsBuilt[ptIdx] += s->getTotalBuildingsBuilt();
stats.buildingsKilled[ptIdx] += s->getTotalBuildingsDestroyed();
stats.buildingsLost[ptIdx] += s->getTotalBuildingsLost();

if (TheGameSpyGame->isQMGame())
{
stats.QMGames[ptIdx]++;
}
else
{
stats.customGames[ptIdx]++;
}

if (TheNetwork->sawCRCMismatch())
{
stats.lossesInARow = 0;
stats.desyncsInARow++;
stats.disconsInARow = 0;
Expand All @@ -1897,6 +1868,8 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else if (gameEndedInDisconnect)
{
++stats.discons[ptIdx];

stats.lossesInARow = 0;
stats.desyncsInARow = 0;
stats.disconsInARow++;
Expand All @@ -1905,6 +1878,8 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else if (TheVictoryConditions->isLocalAlliedVictory())
{
++stats.wins[ptIdx];

stats.lossesInARow = 0;
stats.desyncsInARow = 0;
stats.disconsInARow = 0;
Expand All @@ -1913,13 +1888,29 @@ winName.format("ScoreScreen.wnd:StaticTextScore%d", pos);
}
else
{
++stats.losses[ptIdx];

stats.lossesInARow++;
stats.desyncsInARow = 0;
stats.disconsInARow = 0;
stats.winsInARow = 0;
stats.maxLossesInARow = max(stats.lossesInARow, stats.maxLossesInARow);
}

ScoreKeeper *s = player->getScoreKeeper();
stats.buildingsBuilt[ptIdx] += s->getTotalBuildingsBuilt();
stats.buildingsKilled[ptIdx] += s->getTotalBuildingsDestroyed();
stats.buildingsLost[ptIdx] += s->getTotalBuildingsLost();

if (TheGameSpyGame->isQMGame())
{
stats.QMGames[ptIdx]++;
}
else
{
stats.customGames[ptIdx]++;
}

stats.earnings[ptIdx] += s->getTotalMoneyEarned();
stats.duration[ptIdx] += TheGameLogic->getFrame() / LOGICFRAMES_PER_SECOND / 60; // in minutes
stats.games[ptIdx]++;
Expand Down
Loading
Loading