bugfix: Prevent dead units from repeatedly dealing crash damage on collision with non-buildings#2204
bugfix: Prevent dead units from repeatedly dealing crash damage on collision with non-buildings#2204Stubbjax wants to merge 5 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Generals/Code/GameEngine/Source/GameLogic/Object/Update/PhysicsUpdate.cpp | Replaces createAndFireTempWeapon (AoE) with a targeted attemptDamage call for non-building vehicle crashes; null-checked, properly populates DamageInfo fields including m_sourcePlayerMask, and adds FX via the null-safe FXList::doFXObj helper. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/PhysicsUpdate.cpp | Identical fix applied to the Zero Hour copy of PhysicsUpdate.cpp; change is a character-for-character mirror of the Generals/ version. |
Reviews (5): Last reviewed commit: "tweak: Assign source player mask" | Re-trigger Greptile
|
This doesn't properly resolve #2015, the issue with aircraft landing on mines is that the The issue is that the mines block the slow death code from detecting when the chinook hits the ground properly and prevents the carcus from ever clearing itself. |
That sounds like a separate issue? This fix targets the issue as described; "GLA Technical kills/damages building when dying by China Mines". |
Ah yeah, i glanced over it and read the bit about migs and chinooks in the issue as well. The other week Fish and i were looking into the same issue but with aircraft and it is a problem with the death behaviour modules. I don't think your change here will fix their behaviour since they are never properly set to being effectively dead since they remain stuck in their death crash handling. |
Is effectively dead not exactly the status that should apply here? As far as I'm aware that status is applied as soon as health becomes depleted. |
I would need to check again, have you seen if this also prevents falling planes and helicopters applying continuous damage when they land on mines? Or checked if falling planes and helicopters apply any damage when landing on things? |
This will affect anything that would have previously repeatedly applied |
| if (obj->isKindOf(KINDOF_VEHICLE)) | ||
| #else | ||
| // TheSuperHackers @bugfix Stubbjax 28/01/2026 Prevent dead units from repeatedly dealing damage. | ||
| if (obj->isKindOf(KINDOF_VEHICLE) && !obj->isEffectivelyDead()) |
There was a problem hiding this comment.
Can you clarify what you mean? You have described the fix as intended, which is to prevent crash damage from triggering if the object is effectively dead.
There was a problem hiding this comment.
Ok how do we know the intent is to not apply damage once when dead technical crashes?
There was a problem hiding this comment.
We do not. We can only say the new intent is to not have it deal any damage in order to improve gameplay.
There was a problem hiding this comment.
I expect that a dead vehicle crashing into something can apply damage once. For example if a plane is shot and its rubble hits the ground, then it applies collision damage once. Otherwise only alive vehicles would cause crash damage, which may not be intuitive for players. This is also more in line with what the original code did (incorrectly).
There was a problem hiding this comment.
I suggest add 1 new bit flag to PhysicsBehavior, default it to 1, check if it is 1 before one of the createAndFireTempWeapon, and then set it to 0 afterwards.
This way, this physics weapon can only ever fire once.
There was a problem hiding this comment.
Check if there is a way to determine if a collision event is "new". I suspect PhysicsBehavior::onCollide keeps being called every frame because the object is not pushed away from the collider, but keeps intersecting while flying through it.
There was a problem hiding this comment.
I'm still struggling to understand why such behaviour is desirable. Currently, if a dead unit falls on a non-building obstacle (e.g. rocks, mines, shipping containers, etc.), then it deals crush damage in a radius while in contact. Even if we reduce this to a single damage instance per obstacle, the behaviour is still effectively arbitrary and can yield confusing and unexpected results.
THE_ROCKS.mp4
There was a problem hiding this comment.
So instead perhaps disable the crash damages entirely?
There was a problem hiding this comment.
Should the same test exist for this damage?
There was a problem hiding this comment.
I think it would probably be better. But as a separate change?
There was a problem hiding this comment.
If the repro is unknown or very different for the other, then maybe make separate change.
|
Needs a decision. Current fix does not appear to be satisfying. |
I think the ideal solution would be to forgo the So instead of: TheWeaponStore->createAndFireTempWeapon(getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate, obj, obj->getPosition());We would have: const WeaponTemplate* weaponTemplate = getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate;
DamageInfo damageInfo;
damageInfo.in.m_damageType = weaponTemplate->getDamageType();
damageInfo.in.m_deathType = weaponTemplate->getDeathType();
damageInfo.in.m_sourceID = obj->getID();
damageInfo.in.m_amount = weaponTemplate->m_primaryDamage;
other->attemptDamage(&damageInfo);This would mean only rocks or mines or whatever other prop objects would receive the damage directly, while nearby units and buildings remain unaffected. We could think about doing this for the building crash too, to avoid the inconsistent damage application entirely. We can then look at implementing dedicated death weapons for crashed aircraft further down the track. Thoughts? |
|
Can crashed units collide with multiple units or just ever one? |
Well it wouldn't be units, but yes, I imagine any applicable obstacles within the geometry bounds would run through |
|
It appears logical to only apply damage to directly collided things. It just needs to make sure to not re-apply the damage on every repeated collision event. |
Does it matter if it does? We don't know what object(s) might be in the way. If we only apply e.g. 30 damage once to a 100-HP object, then the object will remain and potentially block the dead object. |
|
But isn't the repeated damage exactly the problem here? A dead vehicle falling onto a building will not be pushed off the building. It will continueosly collide and spam damage events every logic frame. |
If the object collides with a building, the object is destroyed. The problem occurs when the object collides with non-building obstacles and spawns damage instances during those collisions which affect other nearby objects. |
|
Ok. You can make a POC for this and then we see how that looks. |
Pushed an update. This essentially yields the same benefits as the original fix, with the added bonus that falling dead objects don't get stuck above destructible non-building obstacles. BeforeColliding with an obstacle deals damage to nearby objects LIX_CRASH_BEFORE.mp4AfterColliding with an obstacle only deals damage to collided objects LIX_CRASH_AFTER.mp4 |
xezon
left a comment
There was a problem hiding this comment.
Can you also prepare a change for the crash damage on buildings?
As part of this change or separately? |
Can be separate if it requires seperate description. |
|
I see green ticks everywhere. Is there anything else needed for this to be merged into main? |
|
I was waiting for the partner fix to merge them together |
426f7ef to
bbd73fd
Compare
| // TheSuperHackers @bugfix Stubbjax 19/04/2026 Prevent non-building collisions from repeatedly dealing collateral damage to other objects. | ||
| const WeaponTemplate* weaponTemplate = getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate; | ||
| if (weaponTemplate != nullptr) | ||
| { | ||
| WeaponBonus nullBonus; | ||
|
|
||
| DamageInfo damageInfo; | ||
| damageInfo.in.m_damageType = weaponTemplate->getDamageType(); | ||
| damageInfo.in.m_deathType = weaponTemplate->getDeathType(); | ||
| damageInfo.in.m_sourceID = obj->getID(); | ||
| damageInfo.in.m_amount = weaponTemplate->getPrimaryDamage(nullBonus); |
There was a problem hiding this comment.
The
DamageInfo is populated without setting m_sourcePlayerMask. In the standard weapon path (dealDamageInternal), this field is populated from the source object's controlling player. Object.cpp reads it to decide whether to trigger a radar alert for the locally-controlled owner, and ScriptConditions.cpp uses it to resolve which player last damaged a unit. With the field left at its default of 0, crash-damage hits will skip radar warnings on the victim's side and any script trigger keyed on "attacked by player X" will fail to identify the attacker.
| // TheSuperHackers @bugfix Stubbjax 19/04/2026 Prevent non-building collisions from repeatedly dealing collateral damage to other objects. | |
| const WeaponTemplate* weaponTemplate = getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate; | |
| if (weaponTemplate != nullptr) | |
| { | |
| WeaponBonus nullBonus; | |
| DamageInfo damageInfo; | |
| damageInfo.in.m_damageType = weaponTemplate->getDamageType(); | |
| damageInfo.in.m_deathType = weaponTemplate->getDeathType(); | |
| damageInfo.in.m_sourceID = obj->getID(); | |
| damageInfo.in.m_amount = weaponTemplate->getPrimaryDamage(nullBonus); | |
| // TheSuperHackers @bugfix Stubbjax 19/04/2026 Prevent non-building collisions from repeatedly dealing collateral damage to other objects. | |
| const WeaponTemplate* weaponTemplate = getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate; | |
| if (weaponTemplate != nullptr) | |
| { | |
| WeaponBonus nullBonus; | |
| DamageInfo damageInfo; | |
| damageInfo.in.m_damageType = weaponTemplate->getDamageType(); | |
| damageInfo.in.m_deathType = weaponTemplate->getDeathType(); | |
| damageInfo.in.m_sourceID = obj->getID(); | |
| damageInfo.in.m_sourcePlayerMask = obj->getControllingPlayer() ? obj->getControllingPlayer()->getPlayerMask() : 0; | |
| damageInfo.in.m_amount = weaponTemplate->getPrimaryDamage(nullBonus); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameLogic/Object/Update/PhysicsUpdate.cpp
Line: 1269-1279
Comment:
The `DamageInfo` is populated without setting `m_sourcePlayerMask`. In the standard weapon path (`dealDamageInternal`), this field is populated from the source object's controlling player. `Object.cpp` reads it to decide whether to trigger a radar alert for the locally-controlled owner, and `ScriptConditions.cpp` uses it to resolve which player last damaged a unit. With the field left at its default of 0, crash-damage hits will skip radar warnings on the victim's side and any script trigger keyed on "attacked by player X" will fail to identify the attacker.
```suggestion
// TheSuperHackers @bugfix Stubbjax 19/04/2026 Prevent non-building collisions from repeatedly dealing collateral damage to other objects.
const WeaponTemplate* weaponTemplate = getPhysicsBehaviorModuleData()->m_vehicleCrashesIntoNonBuildingWeaponTemplate;
if (weaponTemplate != nullptr)
{
WeaponBonus nullBonus;
DamageInfo damageInfo;
damageInfo.in.m_damageType = weaponTemplate->getDamageType();
damageInfo.in.m_deathType = weaponTemplate->getDeathType();
damageInfo.in.m_sourceID = obj->getID();
damageInfo.in.m_sourcePlayerMask = obj->getControllingPlayer() ? obj->getControllingPlayer()->getPlayerMask() : 0;
damageInfo.in.m_amount = weaponTemplate->getPrimaryDamage(nullBonus);
```
How can I resolve this? If you propose a fix, please make it concise.4e17363 to
fd6d974
Compare




Closes #2015
This change fixes an issue where dead vehicles repeatedly trigger
VehicleCrashesIntoNonBuildingWeaponwhen colliding with mines, causing continuous damage to nearby units and structures.This weapon is hardcoded into the physics update, and is fired when a vehicle falls onto a non-building object - the intent being that a vehicle deals some 'crush' damage to a victim it lands on. It is especially problematic in the case of mines as the mines cannot destroy the already-dead vehicle. The issue is most apparent with Technicals due to their frequent involvement in bombing runs and their tendency to fling themselves forwards upon death.
The fix makes the weapon only deal damage to the collided target.
There is also a building-specific crash block that fires
VehicleCrashesIntoBuildingWeaponwhen a vehicle crashes into a building, however this results in the immediate destruction of the crashing vehicle, and so is not as problematic.Before
The Propaganda Center dies due to dead Technicals firing
VehicleCrashesIntoNonBuildingWeaponevery frameYES_DAMAGE.mp4
After
The Propaganda Center survives unscathed as
VehicleCrashesIntoNonBuildingWeapononly targets the minesNO_DAMAGE.mp4