From 2337f6afcaf40c22a5680b1886430e15c0bbd1ff Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:20:38 +0000 Subject: [PATCH] Fix SpecialPowerModule null controlling player crash --- .../SpecialPower/SpecialPowerModule.cpp | 16 +++++++++--- .../SpecialPower/SpecialPowerModule.cpp | 26 +++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp index 1902010dda7..ce90b003594 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp @@ -454,7 +454,12 @@ void SpecialPowerModule::createViewObject( const Coord3D *location ) if( viewObjectTemplate == nullptr ) return; - Object *viewObject = TheThingFactory->newObject( viewObjectTemplate, getObject()->getControllingPlayer()->getDefaultTeam() ); + // Get the team to use for the view object - use controlling player's default team if available, + // otherwise fall back to the object's team + Player *controllingPlayer = getObject()->getControllingPlayer(); + Team *team = controllingPlayer ? controllingPlayer->getDefaultTeam() : getObject()->getTeam(); + + Object *viewObject = TheThingFactory->newObject( viewObjectTemplate, team ); if( viewObject == nullptr ) return; @@ -482,9 +487,14 @@ void SpecialPowerModule::markSpecialPowerTriggered( const Coord3D *location ) //------------------------------------------------------------------------------------------------- void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) { + // Check if controlling player is null - if so, we can't proceed with some operations + Player *controllingPlayer = getObject()->getControllingPlayer(); + if (!controllingPlayer) + return; + // Tell the scripting engine! TheScriptEngine->notifyOfTriggeredSpecialPower( - getObject()->getControllingPlayer()->getPlayerIndex(), + controllingPlayer->getPlayerIndex(), getSpecialPowerModuleData()->m_specialPowerTemplate->getName(), getObject()->getID()); @@ -518,7 +528,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) AudioEventRTS soundAtLocation = *modData->m_specialPowerTemplate->getInitiateAtTargetSound(); soundAtLocation.setPosition( location ); - soundAtLocation.setPlayerIndex(getObject()->getControllingPlayer()->getPlayerIndex()); + soundAtLocation.setPlayerIndex(controllingPlayer->getPlayerIndex()); TheAudio->addAudioEvent( &soundAtLocation ); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp index ec121ac8caf..72c006d0da0 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/SpecialPower/SpecialPowerModule.cpp @@ -514,7 +514,12 @@ void SpecialPowerModule::createViewObject( const Coord3D *location ) if( viewObjectTemplate == nullptr ) return; - Object *viewObject = TheThingFactory->newObject( viewObjectTemplate, getObject()->getControllingPlayer()->getDefaultTeam() ); + // Get the team to use for the view object - use controlling player's default team if available, + // otherwise fall back to the object's team + Player *controllingPlayer = getObject()->getControllingPlayer(); + Team *team = controllingPlayer ? controllingPlayer->getDefaultTeam() : getObject()->getTeam(); + + Object *viewObject = TheThingFactory->newObject( viewObjectTemplate, team ); if( viewObject == nullptr ) return; @@ -542,9 +547,14 @@ void SpecialPowerModule::markSpecialPowerTriggered( const Coord3D *location ) //------------------------------------------------------------------------------------------------- void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) { + // Check if controlling player is null - if so, we can't proceed with some operations + Player *controllingPlayer = getObject()->getControllingPlayer(); + if (!controllingPlayer) + return; + // Tell the scripting engine! TheScriptEngine->notifyOfTriggeredSpecialPower( - getObject()->getControllingPlayer()->getPlayerIndex(), + controllingPlayer->getPlayerIndex(), getSpecialPowerModuleData()->m_specialPowerTemplate->getName(), getObject()->getID()); @@ -562,7 +572,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) { if( type == SPECIAL_PARTICLE_UPLINK_CANNON || type == SUPW_SPECIAL_PARTICLE_UPLINK_CANNON || type == LAZR_SPECIAL_PARTICLE_UPLINK_CANNON ) { - if ( localPlayer == getObject()->getControllingPlayer() ) + if ( localPlayer == controllingPlayer ) { TheEva->setShouldPlay(EVA_SuperweaponLaunched_Own_ParticleCannon); } @@ -578,7 +588,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) } else if( type == SPECIAL_NEUTRON_MISSILE || type == NUKE_SPECIAL_NEUTRON_MISSILE || type == SUPW_SPECIAL_NEUTRON_MISSILE ) { - if ( localPlayer == getObject()->getControllingPlayer() ) + if ( localPlayer == controllingPlayer ) { TheEva->setShouldPlay(EVA_SuperweaponLaunched_Own_Nuke); } @@ -594,7 +604,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) } else if (type == SPECIAL_SCUD_STORM) { - if ( localPlayer == getObject()->getControllingPlayer() ) + if ( localPlayer == controllingPlayer ) { TheEva->setShouldPlay(EVA_SuperweaponLaunched_Own_ScudStorm); } @@ -612,7 +622,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) { // This is Ghetto. Voices should be ini lines in the special power entry. You shouldn't have to // add to an enum to get a new voice - if ( localPlayer == getObject()->getControllingPlayer() ) + if ( localPlayer == controllingPlayer ) { TheEva->setShouldPlay(EVA_SuperweaponLaunched_Own_GPS_Scrambler); } @@ -628,7 +638,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) } else if (type == SPECIAL_SNEAK_ATTACK) { - if ( localPlayer == getObject()->getControllingPlayer() ) + if ( localPlayer == controllingPlayer ) { TheEva->setShouldPlay(EVA_SuperweaponLaunched_Own_Sneak_Attack); } @@ -658,7 +668,7 @@ void SpecialPowerModule::aboutToDoSpecialPower( const Coord3D *location ) AudioEventRTS soundAtLocation = *modData->m_specialPowerTemplate->getInitiateAtTargetSound(); soundAtLocation.setPosition( location ); - soundAtLocation.setPlayerIndex(getObject()->getControllingPlayer()->getPlayerIndex()); + soundAtLocation.setPlayerIndex(controllingPlayer->getPlayerIndex()); TheAudio->addAudioEvent( &soundAtLocation ); }