Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -775,3 +775,4 @@ This page lists all the individual contributions to the project by their author.
- Wall overlay unit sell exploit fix
- Multiplayer gamespeed fix for RealTimeTimers
- Revert Ares patch to allow OpenTopped transport customization
- Fix for units with Fly, Jumpjet or Rocket locomotors crashing off-map not being cleaned up
1 change: 1 addition & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho
- Fixed the bug that vehicle fall on infantry will make all cell content has been removed.
- Fixed buildings that have their owner changed during buildup skipping buildup and sometimes not correctly clearing the state.
- Fixed preplaced aircraft outside visible map being incorrectly flagged as crashing under certain conditions.
- Fixed units with Fly, Jumpjet or Rocket locomotors destroyed while crashing off-map never being fully cleaned up, permanently blocking production slots and counting towards unit limits.
- Fixed `MovementZone=Subterannean` harvesters being unable to find docks if in area enclosed by water, cliffs etc.
- Fixed an issue where some effects pointing to a unit were not properly cleared when the unit changed its owner.
- Allow Reveal Crate to take effect when picking up by another player controlled house in campaign.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ Phobos fixes:
- Fixed the bug that the upgrade building's power-enhancing effect depends only on its parent building and is not related to the upgrade building itself (by NetsuNegi)
- Fixed an issue where hover vehicles could not be destroyed after malfunctioning on water surfaces (by FlyStar)
- Fixed an issue where shadow matrix scaling was incorrectly applied to `TurretOffset` causing turret shadow misplacement (by Noble_Fish)
- Fixed units with Fly, Jumpjet or Rocket locomotors destroyed while crashing off-map never being fully cleaned up, permanently blocking production slots and counting towards unit limits (by RAZER)
Fixes / interactions with other extensions:
<!-- - Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades (by Ollerus) -->
Expand Down
57 changes: 57 additions & 0 deletions src/Misc/Hooks.BugFixes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2874,6 +2874,63 @@ DEFINE_HOOK(0x4DB874, FootClass_SetLocation_Extra, 0xA)
return SkipGameCode;
}

// Fix crash descent for aircraft/units off-map.
// In all three locomotors below, MapClass::In_Radar blocks position/coordinate updates
// when outside the map. This means crashing units off-map never descend to ground level
// (or reach their destination), so the cleanup code (fire death weapon, UnInit) never runs.
// The fix: at each locomotor's height/health check, treat off-map as ground-touch.
// FlyLocomotionClass::Process - height check after crash descent calculation.
// If off-map and crashing, skip the height > 0 check and go straight to ground-touch cleanup.
// The IsCrashing guard is needed because healthy non-moving airborne aircraft also reach this
// code path (Is_Moving()==false && Height>0) and must not be sent to cleanup.
DEFINE_HOOK(0x4CD797, FlyLocomotionClass_CrashDescent_OffMap, 0x5)
{
enum { GroundTouchCleanup = 0x4CD7AA };

GET(FlyLocomotionClass*, pThis, ESI);

const auto pLinkedTo = pThis->LinkedTo;

if (pLinkedTo->IsCrashing && !MapClass::Instance.IsWithinUsableArea(pLinkedTo->GetCoords()))
return GroundTouchCleanup;

return 0;
}

// JumpjetLocomotionClass::Process - height check before IsCrashing gate.
// If off-map, skip height check and go to the IsCrashing check directly.
DEFINE_HOOK(0x54CC16, JumpjetLocomotionClass_CrashDescent_OffMap, 0x8)
{
enum { IsCrashingCheck = 0x54CC36 };

GET(JumpjetLocomotionClass*, pThis, EDI);

if (!MapClass::Instance.IsWithinUsableArea(pThis->LinkedTo->GetCoords()))
{
// Replicate the stack init from the stolen bytes (mov byte ptr [esp+11h], 0)
// so the "fell on something" flag is properly zeroed for the crash path.
REF_STACK(BYTE, fellOnSomething, STACK_OFFSET(0x34, -0x23));
fellOnSomething = 0;
return IsCrashingCheck;
}

return 0;
}

// RocketLocomotionClass::Process - health check after position update.
// If off-map, bypass the Health > 0 skip and force detonation/cleanup.
DEFINE_HOOK(0x662FD5, RocketLocomotionClass_Process_OffMap, 0x6)
{
enum { ForceCleanup = 0x662FDF };

GET(RocketLocomotionClass*, pThis, EDI);

if (!MapClass::Instance.IsWithinUsableArea(pThis->LinkedTo->GetCoords()))
return ForceCleanup;

return 0;
}

DEFINE_HOOK(0x4DEC7F, FootClass_Crash_FallingDownFix, 0x7)
{
GET(FootClass*, pThis, ESI);
Expand Down
Loading