Skip to content

Commit 4d23c78

Browse files
authored
bugfix(player): Fix transferred in-progress upgrades (#2396)
1 parent adc77cc commit 4d23c78

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

  • GeneralsMD/Code/GameEngine/Source/Common/RTS
  • Generals/Code/GameEngine/Source/Common/RTS

Generals/Code/GameEngine/Source/Common/RTS/Player.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
#include "GameLogic/Module/SpecialPowerModule.h"
9797
#include "GameLogic/Module/SupplyTruckAIUpdate.h"
9898
#include "GameLogic/Module/BattlePlanUpdate.h"
99+
#include "GameLogic/Module/ProductionUpdate.h"
99100
#include "GameLogic/VictoryConditions.h"
100101

101102
#include "GameNetwork/GameInfo.h"
@@ -2023,6 +2024,18 @@ void Player::setObjectsEnabled(AsciiString templateTypeToAffect, Bool enable)
20232024
}
20242025
}
20252026

2027+
//=============================================================================
2028+
static void cancelUpgradeInProduction(Object* obj, void* userData)
2029+
{
2030+
const UpgradeTemplate* upgradeTemplate = static_cast<const UpgradeTemplate*>(userData);
2031+
ProductionUpdateInterface* pui = ProductionUpdate::getProductionUpdateInterfaceFromObject(obj);
2032+
2033+
if (pui && pui->isUpgradeInQueue(upgradeTemplate))
2034+
{
2035+
pui->cancelUpgrade(upgradeTemplate);
2036+
}
2037+
}
2038+
20262039
//=============================================================================
20272040
void Player::transferAssetsFromThat(Player *that)
20282041
{
@@ -2031,6 +2044,33 @@ void Player::transferAssetsFromThat(Player *that)
20312044
return;
20322045
}
20332046

2047+
#if !RETAIL_COMPATIBLE_CRC
2048+
// TheSuperHackers @bugfix Stubbjax 03/02/2026 Cancel any in-progress player upgrades 'that'
2049+
// player currently has in progress that 'this' player already has in progress or completed.
2050+
std::vector<const UpgradeTemplate*> upgradesToCancel;
2051+
for (Upgrade* upgrade = that->m_upgradeList; upgrade; upgrade = upgrade->friend_getNext())
2052+
{
2053+
const UpgradeTemplate* upgradeTemplate = upgrade->getTemplate();
2054+
2055+
if (upgrade->getStatus() == UPGRADE_STATUS_IN_PRODUCTION
2056+
&& upgradeTemplate->getUpgradeType() == UPGRADE_TYPE_PLAYER
2057+
&& (hasUpgradeComplete(upgradeTemplate) || hasUpgradeInProduction(upgradeTemplate)))
2058+
{
2059+
upgradesToCancel.push_back(upgradeTemplate);
2060+
}
2061+
}
2062+
2063+
for (std::vector<const UpgradeTemplate*>::iterator cancelIt = upgradesToCancel.begin(); cancelIt != upgradesToCancel.end(); ++cancelIt)
2064+
{
2065+
const UpgradeTemplate* upgradeTemplate = *cancelIt;
2066+
that->iterateObjects(cancelUpgradeInProduction, const_cast<UpgradeTemplate*>(upgradeTemplate));
2067+
}
2068+
2069+
// TheSuperHackers @bugfix Stubbjax 03/02/2026 Ensure the in-progress upgrade mask is copied from 'that'
2070+
// player to 'this' player to prevent duplicate player upgrades being purchased.
2071+
m_upgradesInProgress.set(that->m_upgradesInProgress);
2072+
#endif
2073+
20342074
std::list<Object *> objsToTransfer;
20352075

20362076
// let's not transfer beacons

GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,18 @@ void Player::setObjectsEnabled(AsciiString templateTypeToAffect, Bool enable)
21152115
}
21162116
}
21172117

2118+
//=============================================================================
2119+
static void cancelUpgradeInProduction(Object* obj, void* userData)
2120+
{
2121+
const UpgradeTemplate* upgradeTemplate = static_cast<const UpgradeTemplate*>(userData);
2122+
ProductionUpdateInterface* pui = ProductionUpdate::getProductionUpdateInterfaceFromObject(obj);
2123+
2124+
if (pui && pui->isUpgradeInQueue(upgradeTemplate))
2125+
{
2126+
pui->cancelUpgrade(upgradeTemplate);
2127+
}
2128+
}
2129+
21182130
//=============================================================================
21192131
void Player::transferAssetsFromThat(Player *that)
21202132
{
@@ -2123,6 +2135,33 @@ void Player::transferAssetsFromThat(Player *that)
21232135
return;
21242136
}
21252137

2138+
#if !RETAIL_COMPATIBLE_CRC
2139+
// TheSuperHackers @bugfix Stubbjax 03/02/2026 Cancel any in-progress player upgrades 'that'
2140+
// player currently has in progress that 'this' player already has in progress or completed.
2141+
std::vector<const UpgradeTemplate*> upgradesToCancel;
2142+
for (Upgrade* upgrade = that->m_upgradeList; upgrade; upgrade = upgrade->friend_getNext())
2143+
{
2144+
const UpgradeTemplate* upgradeTemplate = upgrade->getTemplate();
2145+
2146+
if (upgrade->getStatus() == UPGRADE_STATUS_IN_PRODUCTION
2147+
&& upgradeTemplate->getUpgradeType() == UPGRADE_TYPE_PLAYER
2148+
&& (hasUpgradeComplete(upgradeTemplate) || hasUpgradeInProduction(upgradeTemplate)))
2149+
{
2150+
upgradesToCancel.push_back(upgradeTemplate);
2151+
}
2152+
}
2153+
2154+
for (std::vector<const UpgradeTemplate*>::iterator cancelIt = upgradesToCancel.begin(); cancelIt != upgradesToCancel.end(); ++cancelIt)
2155+
{
2156+
const UpgradeTemplate* upgradeTemplate = *cancelIt;
2157+
that->iterateObjects(cancelUpgradeInProduction, const_cast<UpgradeTemplate*>(upgradeTemplate));
2158+
}
2159+
2160+
// TheSuperHackers @bugfix Stubbjax 03/02/2026 Ensure the in-progress upgrade mask is copied from 'that'
2161+
// player to 'this' player to prevent duplicate player upgrades being purchased.
2162+
m_upgradesInProgress.set(that->m_upgradesInProgress);
2163+
#endif
2164+
21262165
std::list<Object *> objsToTransfer;
21272166

21282167
// let's not transfer beacons

0 commit comments

Comments
 (0)