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 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/RTS/ActionManager.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp index f7522fe7bfa..71faac30efa 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,34 @@ 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, 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; +#else + const ThingTemplate* referenceThing = mod->getReferenceThingTemplate(); + if (!referenceThing) + return FALSE; + + const Real angle = referenceThing->getPlacementViewAngle(); + + return TheBuildAssistant->isLocationLegalToBuild( + 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; +#endif + } + } } return false; } 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