Skip to content
Merged
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
4 changes: 4 additions & 0 deletions Generals/Code/GameEngine/Include/GameLogic/GameLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ class GameLogic : public SubsystemInterface, public Snapshot

Bool isQuitToDesktopRequested() const { return m_quitToDesktopAfterMatch; }

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
void friend_destroyInTunnelContain(const Object* strandedObject);
#endif

protected:

// snapshot methods
Expand Down
21 changes: 20 additions & 1 deletion Generals/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4829,9 +4829,28 @@ StateReturnType AIAttackAimAtTargetState::onEnter()
//to move to the best fire point, check if it's in firing range, and if not
//move it back so another unit with longer range can!
Object *containedBy = source->getContainedBy();
ContainModuleInterface *contain = containedBy ? containedBy->getContain() : nullptr;

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
if( containedBy && weapon )
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Outdated
#else
if( containedBy && weapon && contain && contain->isEnclosingContainerFor( source ) )
#endif
{
ContainModuleInterface *contain = containedBy->getContain();
#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Caball009 22/09/2026 Return early to prevent a crash.
// This is needed when a Tunnel Network with units is transferred to another player and then sold or destroyed.
// The units are not properly transferred and are left in an invalid state.
if (!contain)
{
// remove all such units from the tunnel tracker and destroy them
TheGameLogic->friend_destroyInTunnelContain(source);

return STATE_FAILURE;
}
#endif

// non enclosing garrison containers do not use firepoints. Lorenzen, 6/11/03
Comment thread
Caball009 marked this conversation as resolved.
if (victim)
{
inFiringRange = contain->attemptBestFirePointPosition( source, weapon, victim );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4318,9 +4318,24 @@ Object* AIUpdateInterface::getNextMoodTarget( Bool calledByAI, Bool calledDuring
//Not contained
return nullptr;
}

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Caball009 22/09/2026 Return early to prevent a crash.
// This is needed when a Tunnel Network with units is transferred to another player and then sold or destroyed.
// The units are not properly transferred and are left in an invalid state.
if (!container->getContain())
{
// remove all such units from the tunnel tracker and destroy them
TheGameLogic->friend_destroyInTunnelContain(obj);

return nullptr;
}
#endif

if( !container->getContain()->isPassengerAllowedToFire() )
{
//Container doesn't allow for passenger to shoot.
// Sorry, stealthed and not allowed to idle fire when stealthed.
// Being in a firing container is an exception to this veto.
return nullptr;
}
}
Expand Down
39 changes: 38 additions & 1 deletion Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
#include "Common/ThingFactory.h"
#include "Common/Team.h"
#include "Common/ThingTemplate.h"
#include "GameClient/Water.h"
#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
#include "Common/TunnelTracker.h"
#endif
#include "Common/WellKnownKeys.h"
#include "Common/Xfer.h"
#include "Common/XferCRC.h"
Expand All @@ -73,6 +75,7 @@
#include "GameClient/View.h"
#include "GameClient/CampaignManager.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameClient/Water.h"

#include "GameLogic/AI.h"
#include "GameLogic/AIPathfind.h"
Expand Down Expand Up @@ -2829,6 +2832,40 @@ void GameLogic::friend_awakenUpdateModule(Object* obj, UpdateModulePtr u, Unsign
}
}

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// ------------------------------------------------------------------------------------------------
// Find the tunnel tracker that contains the object and destroy all objects in the contain list
// ------------------------------------------------------------------------------------------------
void GameLogic::friend_destroyInTunnelContain(const Object* strandedObject)
{
for (Int i = 0; i < ThePlayerList->getPlayerCount(); ++i)
{
TunnelTracker* tracker = ThePlayerList->getNthPlayer(i)->getTunnelSystem();
if (!tracker)
continue;

const ContainedItemsList& list = *tracker->getContainedItemsList();

const ContainedItemsList::const_iterator it = std::find(list.begin(), list.end(), strandedObject);
if (it == list.end())
continue;

while (!list.empty())
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
Object* obj = list.front();

tracker->removeFromContain(obj);

obj->onRemovedFrom(nullptr);

destroyObject(obj);
Comment thread
Caball009 marked this conversation as resolved.
}

break;
}
}
#endif

// ------------------------------------------------------------------------------------------------
#ifdef DO_UNIT_TIMINGS
enum {TIME_FRAMES=100};
Expand Down
4 changes: 4 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ class GameLogic : public SubsystemInterface, public Snapshot

Bool isQuitToDesktopRequested() const { return m_quitToDesktopAfterMatch; }

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
void friend_destroyInTunnelContain(const Object* strandedObject);
#endif

protected:

// snapshot methods
Expand Down
17 changes: 17 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4953,8 +4953,25 @@ StateReturnType AIAttackAimAtTargetState::onEnter()
Object *containedBy = source->getContainedBy();
ContainModuleInterface *contain = containedBy ? containedBy->getContain() : nullptr;

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
if( containedBy && weapon )
#else
if( containedBy && weapon && contain && contain->isEnclosingContainerFor( source ) )
#endif
{
#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Caball009 22/09/2026 Return early to prevent a crash.
// This is needed when a Tunnel Network with units is transferred to another player and then sold or destroyed.
// The units are not properly transferred and are left in an invalid state.
if (!contain)
{
// remove all such units from the tunnel tracker and destroy them
TheGameLogic->friend_destroyInTunnelContain(source);

return STATE_FAILURE;
}
#endif

// non enclosing garrison containers do not use firepoints. Lorenzen, 6/11/03
if (victim)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4559,13 +4559,33 @@ Object* AIUpdateInterface::getNextMoodTarget( Bool calledByAI, Bool calledDuring
{
if( !canAutoAcquireWhileStealthed() )
{
const Object *container = obj->getContainedBy();
if( ! (container && container->getContain()->isPassengerAllowedToFire()) )
{
//He's stealthed and idle, but if he's garrisoned, then that's a whole different matter....
const Object *container = obj->getContainedBy();
if( !container )
{
//Not contained
return nullptr;
}

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Caball009 22/09/2026 Return early to prevent a crash.
// This is needed when a Tunnel Network with units is transferred to another player and then sold or destroyed.
// The units are not properly transferred and are left in an invalid state.
if (!container->getContain())
{
// remove all such units from the tunnel tracker and destroy them
TheGameLogic->friend_destroyInTunnelContain(obj);

return nullptr;
}
#endif

if( !container->getContain()->isPassengerAllowedToFire() )
{
// Sorry, stealthed and not allowed to idle fire when stealthed.
// Being in a firing container is an exception to this veto.
return nullptr;
}
return nullptr;
}
}
}
}
Expand Down
35 changes: 33 additions & 2 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
#include "Common/ThingFactory.h"
#include "Common/Team.h"
#include "Common/ThingTemplate.h"
#include "GameClient/Water.h"
#include "GameClient/Snow.h"
#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
#include "Common/TunnelTracker.h"
#endif
#include "Common/WellKnownKeys.h"
#include "Common/Xfer.h"
#include "Common/XferCRC.h"
Expand All @@ -73,8 +74,10 @@
#include "GameClient/MapUtil.h"
#include "GameClient/Mouse.h"
#include "GameClient/ParticleSys.h"
#include "GameClient/Snow.h"
#include "GameClient/TerrainVisual.h"
#include "GameClient/View.h"
#include "GameClient/Water.h"
#include "GameClient/CampaignManager.h"
#include "GameClient/GameWindowTransitions.h"

Expand Down Expand Up @@ -3154,11 +3157,39 @@ void GameLogic::friend_awakenUpdateModule(Object* obj, UpdateModulePtr u, Unsign
}
}

#if RTS_GENERALS && RETAIL_COMPATIBLE_CRC
// ------------------------------------------------------------------------------------------------
// Find the tunnel tracker that contains the object and destroy all objects in the contain list
// ------------------------------------------------------------------------------------------------
void GameLogic::friend_destroyInTunnelContain(const Object* strandedObject)
{
for (Int i = 0; i < ThePlayerList->getPlayerCount(); ++i)
{
TunnelTracker* tracker = ThePlayerList->getNthPlayer(i)->getTunnelSystem();
if (!tracker)
continue;

const ContainedItemsList& list = *tracker->getContainedItemsList();

const ContainedItemsList::const_iterator it = std::find(list.begin(), list.end(), strandedObject);
if (it == list.end())
continue;

while (!list.empty())
{
Object* obj = list.front();

tracker->removeFromContain(obj);

obj->onRemovedFrom(nullptr);

destroyObject(obj);
}

break;
}
}
#endif

// ------------------------------------------------------------------------------------------------
#ifdef DO_UNIT_TIMINGS
Expand Down
Loading