From 581ad511e74f831c376ac43b1b6592c0bfcea1b6 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Sat, 4 Apr 2026 14:46:49 +0200 Subject: [PATCH 1/6] fix(logic): Use const builderObject in BuildAssistant::isLocationLegalToBuild --- GeneralsMD/Code/GameEngine/Include/Common/BuildAssistant.h | 4 ++-- .../Code/GameEngine/Source/Common/System/BuildAssistant.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/BuildAssistant.h b/GeneralsMD/Code/GameEngine/Include/Common/BuildAssistant.h index 2097e8c12d0..fca2b85229a 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/BuildAssistant.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/BuildAssistant.h @@ -151,14 +151,14 @@ class BuildAssistant : public SubsystemInterface const ThingTemplate *build, Real angle, // angle to construct 'build' at UnsignedInt options, // use LocationLegalToBuildOptions - Object *builderObject, + const Object *builderObject, Player *player); /// query if we can build at this location virtual LegalBuildCode isLocationClearOfObjects( const Coord3D *worldPos, const ThingTemplate *build, Real angle, // angle to construct 'build' a - Object *builderObject, + const Object *builderObject, UnsignedInt options, Player *thePlayer); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp index ebc5746d69e..725e921edda 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp @@ -656,7 +656,7 @@ void BuildAssistant::iterateFootprint( const ThingTemplate *build, LegalBuildCode BuildAssistant::isLocationClearOfObjects( const Coord3D *worldPos, const ThingTemplate *build, Real angle, - Object *builderObject, + const Object *builderObject, UnsignedInt options, Player *thePlayer) { @@ -915,7 +915,7 @@ LegalBuildCode BuildAssistant::isLocationLegalToBuild( const Coord3D *worldPos, const ThingTemplate *build, Real angle, UnsignedInt options, - Object *builderObject, + const Object *builderObject, Player *player) { @@ -1002,7 +1002,7 @@ LegalBuildCode BuildAssistant::isLocationLegalToBuild( const Coord3D *worldPos, // if clear path is requested check to see if the builder object can get there (unless it's a structure) if( BitIsSet( options, CLEAR_PATH ) && builderObject && !builderObject->isKindOf( KINDOF_IMMOBILE ) ) { - AIUpdateInterface *ai = builderObject->getAIUpdateInterface(); + const AIUpdateInterface *ai = builderObject->getAIUpdateInterface(); // // if there is no AI interface for this object, it cannot possible pass a clear path From fc1aa4ef646e592ef4cfd94802d2b6cdb7236ebf Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Wed, 1 Apr 2026 19:33:43 +0200 Subject: [PATCH 2/6] fix(logic): Improve validation of building placement for Sneak Attack --- .../Source/Common/RTS/ActionManager.cpp | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index f7522fe7bfa..1549be67b88 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -36,6 +36,7 @@ #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine #include "Common/ActionManager.h" +#include "Common/BuildAssistant.h" #include "Common/GlobalData.h" #include "Common/Player.h" #include "Common/PlayerList.h" @@ -1506,7 +1507,7 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 } } - // Last check is shroudedness, if it is cared about + // Second check is shroudedness, if it is cared about switch( spTemplate->getSpecialPowerType() ) { case SPECIAL_DAISY_CUTTER: @@ -1552,7 +1553,6 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 case SUPW_SPECIAL_PARTICLE_UPLINK_CANNON: case LAZR_SPECIAL_PARTICLE_UPLINK_CANNON: case SPECIAL_CLEANUP_AREA: - case SPECIAL_SNEAK_ATTACK: case SPECIAL_BATTLESHIP_BOMBARDMENT: //Don't allow "damaging" special powers in shrouded areas, but Fogged are okay. return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED; @@ -1586,6 +1586,35 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 case SPECIAL_CHANGE_BATTLE_PLANS: return false; } + + // TheSuperHackers @fix stephanmeesters 04/04/2026 Some special powers can spawn a building. To avoid cheating + // we must verify that it is legal to place this building. + switch( spTemplate->getSpecialPowerType() ) + { + case SPECIAL_SNEAK_ATTACK: + { +#if RETAIL_COMPATIBLE_CRC + return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED; +#elif + const ThingTemplate* referenceThing = mod->getReferenceThingTemplate(); + DEBUG_ASSERTCRASH(referenceThing, ("canDoSpecialPowerAtLocation: SpecialPowerTemplate has a null ThingTemplate") ); + if (!referenceThing) + return FALSE; + + return TheBuildAssistant->isLocationLegalToBuild(loc, + referenceThing, + referenceThing->getPlacementViewAngle(), + BuildAssistant::USE_QUICK_PATHFIND | + BuildAssistant::TERRAIN_RESTRICTIONS | + BuildAssistant::CLEAR_PATH | + BuildAssistant::NO_OBJECT_OVERLAP | + BuildAssistant::SHROUD_REVEALED | + BuildAssistant::IGNORE_STEALTHED, + obj, + nullptr) == LBC_OK; +#endif + } + } } return false; } From 348f7cab98dd2818669be6083467736d3b18758e Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Sat, 4 Apr 2026 15:06:24 +0200 Subject: [PATCH 3/6] Replace elif with else --- GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index 1549be67b88..a4fa2be46ba 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -1595,7 +1595,7 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 { #if RETAIL_COMPATIBLE_CRC return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED; -#elif +#else const ThingTemplate* referenceThing = mod->getReferenceThingTemplate(); DEBUG_ASSERTCRASH(referenceThing, ("canDoSpecialPowerAtLocation: SpecialPowerTemplate has a null ThingTemplate") ); if (!referenceThing) From 9d50bc013f05123dc9c951ec440f90879f68d406 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:57:27 +0200 Subject: [PATCH 4/6] Process review comments --- .../Source/Common/RTS/ActionManager.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index a4fa2be46ba..b944b0c8903 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -1588,7 +1588,7 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 } // TheSuperHackers @fix stephanmeesters 04/04/2026 Some special powers can spawn a building. To avoid cheating - // we must verify that it is legal to place this building. + // verify that it is legal to place this building. switch( spTemplate->getSpecialPowerType() ) { case SPECIAL_SNEAK_ATTACK: @@ -1597,21 +1597,21 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED; #else const ThingTemplate* referenceThing = mod->getReferenceThingTemplate(); - DEBUG_ASSERTCRASH(referenceThing, ("canDoSpecialPowerAtLocation: SpecialPowerTemplate has a null ThingTemplate") ); if (!referenceThing) return FALSE; - return TheBuildAssistant->isLocationLegalToBuild(loc, - referenceThing, - referenceThing->getPlacementViewAngle(), - BuildAssistant::USE_QUICK_PATHFIND | - BuildAssistant::TERRAIN_RESTRICTIONS | - BuildAssistant::CLEAR_PATH | - BuildAssistant::NO_OBJECT_OVERLAP | - BuildAssistant::SHROUD_REVEALED | - BuildAssistant::IGNORE_STEALTHED, - obj, - nullptr) == LBC_OK; + return TheBuildAssistant->isLocationLegalToBuild( + loc, + referenceThing, + referenceThing->getPlacementViewAngle(), + BuildAssistant::USE_QUICK_PATHFIND | + BuildAssistant::TERRAIN_RESTRICTIONS | + BuildAssistant::CLEAR_PATH | + BuildAssistant::NO_OBJECT_OVERLAP | + BuildAssistant::SHROUD_REVEALED | + BuildAssistant::IGNORE_STEALTHED, + obj, + nullptr) == LBC_OK; #endif } } From 5e8717c9c2f51bb3dd96691ddb61f3528cc241e2 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 6 Apr 2026 11:44:24 +0200 Subject: [PATCH 5/6] Process review comments 2 --- .../GameEngine/Source/Common/RTS/ActionManager.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index b944b0c8903..71faac30efa 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp @@ -1587,8 +1587,8 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 return false; } - // TheSuperHackers @fix stephanmeesters 04/04/2026 Some special powers can spawn a building. To avoid cheating - // verify that it is legal to place this building. + // TheSuperHackers @fix stephanmeesters 04/04/2026 Some special powers can spawn a building. + // To avoid cheating, verify that it is legal to place this building. switch( spTemplate->getSpecialPowerType() ) { case SPECIAL_SNEAK_ATTACK: @@ -1600,18 +1600,17 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3 if (!referenceThing) return FALSE; + const Real angle = referenceThing->getPlacementViewAngle(); + return TheBuildAssistant->isLocationLegalToBuild( - loc, - referenceThing, - referenceThing->getPlacementViewAngle(), + loc, referenceThing, angle, BuildAssistant::USE_QUICK_PATHFIND | BuildAssistant::TERRAIN_RESTRICTIONS | BuildAssistant::CLEAR_PATH | BuildAssistant::NO_OBJECT_OVERLAP | BuildAssistant::SHROUD_REVEALED | BuildAssistant::IGNORE_STEALTHED, - obj, - nullptr) == LBC_OK; + obj, nullptr) == LBC_OK; #endif } } From 8e5fd246137a396779bec47ad2ac45b695906c00 Mon Sep 17 00:00:00 2001 From: stm <14291421+stephanmeesters@users.noreply.github.com> Date: Mon, 6 Apr 2026 11:46:04 +0200 Subject: [PATCH 6/6] Replicate to Generals --- Generals/Code/GameEngine/Include/Common/BuildAssistant.h | 4 ++-- .../Code/GameEngine/Source/Common/System/BuildAssistant.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Generals/Code/GameEngine/Include/Common/BuildAssistant.h b/Generals/Code/GameEngine/Include/Common/BuildAssistant.h index f4085fd6cb2..b9f49b03470 100644 --- a/Generals/Code/GameEngine/Include/Common/BuildAssistant.h +++ b/Generals/Code/GameEngine/Include/Common/BuildAssistant.h @@ -148,14 +148,14 @@ class BuildAssistant : public SubsystemInterface const ThingTemplate *build, Real angle, // angle to construct 'build' at UnsignedInt options, // use LocationLegalToBuildOptions - Object *builderObject, + const Object *builderObject, Player *player); /// query if we can build at this location virtual Bool isLocationClearOfObjects( const Coord3D *worldPos, const ThingTemplate *build, Real angle, // angle to construct 'build' a - Object *builderObject, + const Object *builderObject, UnsignedInt options, Player *thePlayer); diff --git a/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp b/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp index d752afedeaa..ccb32fa1bf6 100644 --- a/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp @@ -656,7 +656,7 @@ void BuildAssistant::iterateFootprint( const ThingTemplate *build, Bool BuildAssistant::isLocationClearOfObjects( const Coord3D *worldPos, const ThingTemplate *build, Real angle, - Object *builderObject, + const Object *builderObject, UnsignedInt options, Player *thePlayer) { @@ -842,7 +842,7 @@ LegalBuildCode BuildAssistant::isLocationLegalToBuild( const Coord3D *worldPos, const ThingTemplate *build, Real angle, UnsignedInt options, - Object *builderObject, + const Object *builderObject, Player *player) { @@ -928,7 +928,7 @@ LegalBuildCode BuildAssistant::isLocationLegalToBuild( const Coord3D *worldPos, // if clear path is requested check to see if the builder object can get there if( BitIsSet( options, CLEAR_PATH ) && builderObject ) { - AIUpdateInterface *ai = builderObject->getAIUpdateInterface(); + const AIUpdateInterface *ai = builderObject->getAIUpdateInterface(); // // if there is no AI interface for this object, it cannot possible pass a clear path