Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class ContainModuleInterface
// Player Occupancy.
virtual PlayerMaskType getPlayerWhoEntered(void) const = 0;

virtual void processDamageToContained() = 0; ///< Do our % damage to units now.
virtual void processDamageToContained(Real percentDamage) = 0; ///< Do our % damage to units now.

virtual void enableLoadSounds( Bool enable ) = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class OpenContain : public UpdateModule,
// returns true iff there are objects currently waiting to enter.
virtual Bool hasObjectsWantingToEnterOrExit() const;

virtual void processDamageToContained(); ///< Do our % damage to units now.
virtual void processDamageToContained(Real percentDamage); ///< Do our % damage to units now.

virtual void enableLoadSounds( Bool enable ) { m_loadSoundsEnabled = enable; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -755,14 +755,20 @@ void OpenContain::onDie( const DamageInfo * damageInfo )
if (!getOpenContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo))
return;

#if !RETAIL_COMPATIBLE_CRC
killRidersWhoAreNotFreeToExit();
#endif

//Check to see if we are going to inflict damage on contained units.
if( getOpenContainModuleData()->m_damagePercentageToUnits > 0 )
{
//Cycle through the units and apply damage to them!
processDamageToContained();
processDamageToContained(getOpenContainModuleData()->m_damagePercentageToUnits);
}

#if RETAIL_COMPATIBLE_CRC
killRidersWhoAreNotFreeToExit();
#endif

// Leaving this commented out to show it can't work. We are about to die, so they will have zero
// chance to hit an exitState::Update. At least we would clean them up in onDelete.
Expand Down Expand Up @@ -1286,9 +1292,9 @@ void OpenContain::orderAllPassengersToExit( CommandSourceType commandSource )
}

//-------------------------------------------------------------------------------------------------
void OpenContain::processDamageToContained()
void OpenContain::processDamageToContained(Real percentDamage)
{
const OpenContainModuleData* data = getOpenContainModuleData();
const bool killContained = percentDamage == 1.0f;

#if RETAIL_COMPATIBLE_CRC

Expand All @@ -1303,7 +1309,7 @@ void OpenContain::processDamageToContained()
Object *object = *it++;

//Calculate the damage to be inflicted on each unit.
Real damage = object->getBodyModule()->getMaxHealth() * data->m_damagePercentageToUnits;
Real damage = object->getBodyModule()->getMaxHealth() * percentDamage;

DamageInfo damageInfo;
damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE;
Expand All @@ -1312,7 +1318,7 @@ void OpenContain::processDamageToContained()
damageInfo.in.m_amount = damage;
object->attemptDamage( &damageInfo );

if( !object->isEffectivelyDead() && data->m_damagePercentageToUnits == 1.0f )
if( !object->isEffectivelyDead() && killContained )
object->kill(); // in case we are carrying flame proof troops we have been asked to kill

// TheSuperHackers @info Calls to Object::attemptDamage and Object::kill will not remove
Expand Down Expand Up @@ -1360,7 +1366,7 @@ void OpenContain::processDamageToContained()
DEBUG_ASSERTCRASH( object, ("Contain list must not contain null element") );

// Calculate the damage to be inflicted on each unit.
Real damage = object->getBodyModule()->getMaxHealth() * data->m_damagePercentageToUnits;
Real damage = object->getBodyModule()->getMaxHealth() * percentDamage;

DamageInfo damageInfo;
damageInfo.in.m_damageType = DAMAGE_UNRESISTABLE;
Expand All @@ -1369,7 +1375,7 @@ void OpenContain::processDamageToContained()
damageInfo.in.m_amount = damage;
object->attemptDamage( &damageInfo );

if( !object->isEffectivelyDead() && data->m_damagePercentageToUnits == 1.0f )
if( !object->isEffectivelyDead() && killContained )
object->kill(); // in case we are carrying flame proof troops we have been asked to kill

if ( object->isEffectivelyDead() )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,13 @@ Bool TransportContain::isSpecificRiderFreeToExit(Object* specificObject)
if (ai && ai->getAiFreeToExit(specificObject) != FREE_TO_EXIT)
return FALSE;

#if !RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Stubbjax 02/03/2026 If our parent container is held, then we
// are not free to exit.
if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing null check before dereferencing getContainedBy(). While objects in the contain list should have a valid container, defensive programming suggests checking for nullptr to prevent potential crashes.

Suggested change
if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
if (specificObject->getContainedBy() && specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp
Line: 462

Comment:
Missing null check before dereferencing `getContainedBy()`. While objects in the contain list should have a valid container, defensive programming suggests checking for nullptr to prevent potential crashes.

```suggestion
	if (specificObject->getContainedBy() && specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
```

How can I resolve this? If you propose a fix, please make it concise.

return FALSE;
#endif

// I can always kick people out if I am in the air, I know what I'm doing
if (me->isUsingAirborneLocomotor())
return TRUE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -875,14 +875,20 @@ void OpenContain::onDie( const DamageInfo * damageInfo )
if (!getOpenContainModuleData()->m_dieMuxData.isDieApplicable(getObject(), damageInfo))
return;

#if !RETAIL_COMPATIBLE_CRC
killRidersWhoAreNotFreeToExit();
#endif

//Check to see if we are going to inflict damage on contained units.
if( getDamagePercentageToUnits() > 0 )
{
//Cycle through the units and apply damage to them!
processDamageToContained(getDamagePercentageToUnits());
}

#if RETAIL_COMPATIBLE_CRC
killRidersWhoAreNotFreeToExit();
#endif

// Leaving this commented out to show it can't work. We are about to die, so they will have zero
// chance to hit an exitState::Update. At least we would clean them up in onDelete.
Expand Down Expand Up @@ -1457,6 +1463,7 @@ void OpenContain::orderAllPassengersToHackInternet( CommandSourceType commandSou
void OpenContain::processDamageToContained(Real percentDamage)
{
const OpenContainModuleData *data = getOpenContainModuleData();
const bool killContained = percentDamage == 1.0f;

#if RETAIL_COMPATIBLE_CRC

Expand All @@ -1480,7 +1487,7 @@ void OpenContain::processDamageToContained(Real percentDamage)
damageInfo.in.m_amount = damage;
object->attemptDamage( &damageInfo );

if( !object->isEffectivelyDead() && percentDamage == 1.0f )
if( !object->isEffectivelyDead() && killContained )
object->kill(); // in case we are carrying flame proof troops we have been asked to kill

// TheSuperHackers @info Calls to Object::attemptDamage and Object::kill will not remove
Expand Down Expand Up @@ -1537,7 +1544,7 @@ void OpenContain::processDamageToContained(Real percentDamage)
damageInfo.in.m_amount = damage;
object->attemptDamage( &damageInfo );

if( !object->isEffectivelyDead() && percentDamage == 1.0f )
if( !object->isEffectivelyDead() && killContained )
object->kill(); // in case we are carrying flame proof troops we have been asked to kill

if ( object->isEffectivelyDead() )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,12 @@ void TransportContain::killRidersWhoAreNotFreeToExit()
if (d->m_destroyRidersWhoAreNotFreeToExit)
TheGameLogic->destroyObject(obj);
else
#if RETAIL_COMPATIBLE_CRC
obj->kill();
#else
// TheSuperHackers @info Burned death prevents infantry corpses dropping out of the container.
obj->kill(DAMAGE_UNRESISTABLE, d->m_isBurnedDeathToUnits ? DEATH_BURNED : DEATH_NORMAL);
#endif
}
}
}
Expand All @@ -562,6 +567,13 @@ Bool TransportContain::isSpecificRiderFreeToExit(Object* specificObject)
if (ai && ai->getAiFreeToExit(specificObject) != FREE_TO_EXIT)
return FALSE;

#if !RETAIL_COMPATIBLE_CRC
// TheSuperHackers @bugfix Stubbjax 02/03/2026 If our parent container is held, then we
// are not free to exit.
if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing null check before dereferencing getContainedBy(). While objects in the contain list should have a valid container, defensive programming suggests checking for nullptr to prevent potential crashes.

Suggested change
if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
if (specificObject->getContainedBy() && specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
Prompt To Fix With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp
Line: 573

Comment:
Missing null check before dereferencing `getContainedBy()`. While objects in the contain list should have a valid container, defensive programming suggests checking for nullptr to prevent potential crashes.

```suggestion
	if (specificObject->getContainedBy() && specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD))
```

How can I resolve this? If you propose a fix, please make it concise.

return FALSE;
#endif

// I can always kick people out if I am in the air, I know what I'm doing
if (me->isUsingAirborneLocomotor())
return TRUE;
Expand Down
Loading