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
2 changes: 2 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2618,6 +2618,7 @@ OmniFire.TurnToTarget=no ; boolean
- `Strafing.Shots` controls the number of times the weapon is fired during a single strafe run, defaults to 5 if not set. `Ammo` is only deducted at the end of the strafe run, regardless of the number of shots fired.
- `Strafing.SimulateBurst` controls whether or not the shots fired during strafing simulate behavior of `Burst`, allowing for alternating firing offset. Only takes effect if weapon has `Burst` set to 1 or undefined.
- `Strafing.UseAmmoPerShot`, if set to `true` overrides the usual behaviour of only deducting ammo after a strafing run and instead doing it after each individual shot.
- `Strafing.TargetCell` controls whether the aircraft will change the target of this round to the ground after firing the first shot, to ensure that all `Strafing.Shots` can be dropped. That is, the `Strafing` will not be interrupted by the premature death of the target.
- `Strafing.EndDelay` can be used to override the delay after firing last shot in strafing run before aircraft resumes another strafing run or returns to base. Defaults to (Weapon `Range` * 256 + 1024) / Aircraft `Speed`. Note that using a short delay with aircraft that can do multiple strafing runs with their ammo can cause undesired behaviour like dancing around or facing weird way depending on other factors like ROF and/or movement speed.
- There is a special case for aircraft spawned by `Type=SpyPlane` superweapons on `SpyPlane Approach` or `SpyPlane Overfly` mission where `Strafing.Shots` only if explicitly set on its primary weapon, determines the maximum number of times the map revealing effect can activate irregardless of other factors.

Expand All @@ -2628,6 +2629,7 @@ Strafing= ; boolean
Strafing.Shots= ; integer
Strafing.SimulateBurst=false ; boolean
Strafing.UseAmmoPerShot=false ; boolean
Strafing.TargetCell=false ; boolean
Strafing.EndDelay= ; integer, game frames
```

Expand Down
75 changes: 69 additions & 6 deletions src/Ext/Aircraft/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ DEFINE_FUNCTION_JUMP(CALL6, 0x4188D3, AircraftClass_SelectWeapon_Wrapper);
DEFINE_FUNCTION_JUMP(CALL6, 0x4189E2, AircraftClass_SelectWeapon_Wrapper);
DEFINE_FUNCTION_JUMP(CALL6, 0x418AF1, AircraftClass_SelectWeapon_Wrapper);

DEFINE_HOOK_AGAIN(0x41874E, AircraftClass_Mission_Attack_StrafingDestinationFix, 0x6)
DEFINE_HOOK(0x418544, AircraftClass_Mission_Attack_StrafingDestinationFix, 0x6)
{
GET(FireError, fireError, EAX);
GET(AircraftClass*, pThis, ESI);

// The aircraft managed by the spawn manager will not update destination after changing target
if (fireError == FireError::RANGE && pThis->Is_Strafe())
pThis->SetDestination(pThis->Target, true);

return 0;
}

#pragma region After_Shot_Delays

static int GetDelay(AircraftClass* pThis, bool isLastShot)
Expand All @@ -205,6 +218,7 @@ static int GetDelay(AircraftClass* pThis, bool isLastShot)

if (isLastShot || pExt->Strafe_BombsDroppedThisRound == pWeaponExt->Strafing_Shots.Get(5) || (pWeaponExt->Strafing_UseAmmoPerShot && !pThis->Ammo))
{
pExt->Strafe_TargetCell = nullptr;
pThis->MissionStatus = (int)AirAttackStatus::FlyToPosition;
delay = pWeaponExt->Strafing_EndDelay.Get((pWeapon->Range + (Unsorted::LeptonsPerCell * 4)) / pThis->Type->Speed);
}
Expand All @@ -216,6 +230,11 @@ DEFINE_HOOK(0x4184CC, AircraftClass_Mission_Attack_Delay1A, 0x6)
{
GET(AircraftClass*, pThis, ESI);

auto const pExt = TechnoExt::ExtMap.Find(pThis);

if (WeaponTypeExt::ExtMap.Find(pThis->GetWeapon(pExt->CurrentAircraftWeaponIndex)->WeaponType)->Strafing_TargetCell)
pExt->Strafe_TargetCell = MapClass::Instance.GetCellAt(pThis->Target->GetCoords());

pThis->IsLocked = true;
pThis->MissionStatus = (int)AirAttackStatus::FireAtTarget2_Strafe;
R->EAX(GetDelay(pThis, false));
Expand Down Expand Up @@ -275,10 +294,55 @@ DEFINE_HOOK(0x418B8A, AircraftClass_Mission_Attack_Delay5, 0x6)

#pragma endregion

DEFINE_HOOK_AGAIN(0x41882C, AircraftClass_MissionAttack_ScatterCell1, 0x6);
DEFINE_HOOK_AGAIN(0x41893B, AircraftClass_MissionAttack_ScatterCell1, 0x6);
DEFINE_HOOK_AGAIN(0x418A4A, AircraftClass_MissionAttack_ScatterCell1, 0x6);
DEFINE_HOOK_AGAIN(0x418B46, AircraftClass_MissionAttack_ScatterCell1, 0x6);
#pragma region StrafeCell

DEFINE_HOOK_AGAIN(0x4188AC, AircraftClass_Mission_Attack_StrafeCell, 0x6)
DEFINE_HOOK_AGAIN(0x4189BB, AircraftClass_Mission_Attack_StrafeCell, 0x6)
DEFINE_HOOK_AGAIN(0x418ACA, AircraftClass_Mission_Attack_StrafeCell, 0x6)
DEFINE_HOOK(0x41879D, AircraftClass_Mission_Attack_StrafeCell, 0x6)
{
enum { CannotFireNow = 0x418BC5, SkipGameCode = 0x418BBA };

GET(AircraftClass*, pThis, ESI);

const auto pExt = TechnoExt::ExtMap.Find(pThis);

if (const auto pTargetCell = pExt->Strafe_TargetCell)
{
switch (pThis->GetFireError(pTargetCell, pExt->CurrentAircraftWeaponIndex, true))
{
case FireError::OK:
case FireError::FACING:
case FireError::CLOAKED:
case FireError::RANGE:
break;
default:
return CannotFireNow;
}

AircraftExt::FireWeapon(pThis, pTargetCell);

if (pExt->TypeExtData->FiringForceScatter)
pTargetCell->ScatterContent(pThis->Location, true, false, false);

pThis->SetDestination(pTargetCell, true);
pThis->MissionStatus++;

R->EAX(GetDelay(pThis, pThis->MissionStatus > static_cast<int>(AirAttackStatus::FireAtTarget5_Strafe)));
return SkipGameCode;
}

return 0;
}

#pragma endregion

#pragma region ScatterCell

DEFINE_HOOK_AGAIN(0x41882C, AircraftClass_MissionAttack_ScatterCell1, 0x6)
DEFINE_HOOK_AGAIN(0x41893B, AircraftClass_MissionAttack_ScatterCell1, 0x6)
DEFINE_HOOK_AGAIN(0x418A4A, AircraftClass_MissionAttack_ScatterCell1, 0x6)
DEFINE_HOOK_AGAIN(0x418B46, AircraftClass_MissionAttack_ScatterCell1, 0x6)
DEFINE_HOOK(0x41847E, AircraftClass_MissionAttack_ScatterCell1, 0x6)
{
GET(AircraftClass*, pThis, ESI);
Expand Down Expand Up @@ -315,7 +379,6 @@ DEFINE_HOOK(0x414C0B, AircraftClass_ChronoSparkleDelay, 0x5)
return 0x414C10;
}


#pragma region LandingDir

DEFINE_HOOK(0x4CF31C, FlyLocomotionClass_FlightUpdate_LandingDir, 0x9)
Expand Down Expand Up @@ -545,7 +608,7 @@ DEFINE_HOOK(0x4CF190, FlyLocomotionClass_FlightUpdate_SetPrimaryFacing, 0x6) //
destination.Y += cellOffset.Y;
}

if (footCoords.Y != destination.Y && footCoords.X != destination.X)
if (footCoords.Y != destination.Y || footCoords.X != destination.X)
pAircraft->PrimaryFacing.SetDesired(DirStruct(Math::atan2(footCoords.Y - destination.Y, destination.X - footCoords.X)));
else
pAircraft->PrimaryFacing.SetDesired(landingDir);
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Techno/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ void TechnoExt::ExtData::Serialize(T& Stm)
.Process(this->MindControlRingAnimType)
.Process(this->DamageNumberOffset)
.Process(this->Strafe_BombsDroppedThisRound)
.Process(this->Strafe_TargetCell)
.Process(this->CurrentAircraftWeaponIndex)
.Process(this->IsInTunnel)
.Process(this->IsBurrowed)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class TechnoExt
AnimTypeClass* MindControlRingAnimType;
int DamageNumberOffset;
int Strafe_BombsDroppedThisRound;
CellClass* Strafe_TargetCell;
int CurrentAircraftWeaponIndex;
bool IsInTunnel;
bool IsBurrowed;
Expand Down Expand Up @@ -108,6 +109,7 @@ class TechnoExt
, MindControlRingAnimType { nullptr }
, DamageNumberOffset { INT32_MIN }
, Strafe_BombsDroppedThisRound { 0 }
, Strafe_TargetCell { nullptr }
, CurrentAircraftWeaponIndex {}
, IsInTunnel { false }
, IsBurrowed { false }
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/WeaponType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->Strafing_Shots.Read(exINI, pSection, "Strafing.Shots");
this->Strafing_SimulateBurst.Read(exINI, pSection, "Strafing.SimulateBurst");
this->Strafing_UseAmmoPerShot.Read(exINI, pSection, "Strafing.UseAmmoPerShot");
this->Strafing_TargetCell.Read(exINI, pSection, "Strafing.TargetCell");
this->Strafing_EndDelay.Read(exINI, pSection, "Strafing.EndDelay");
this->CanTarget.Read(exINI, pSection, "CanTarget");
this->CanTargetHouses.Read(exINI, pSection, "CanTargetHouses");
Expand Down Expand Up @@ -179,6 +180,7 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm)
.Process(this->Strafing_Shots)
.Process(this->Strafing_SimulateBurst)
.Process(this->Strafing_UseAmmoPerShot)
.Process(this->Strafing_TargetCell)
.Process(this->Strafing_EndDelay)
.Process(this->CanTarget)
.Process(this->CanTargetHouses)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/WeaponType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class WeaponTypeExt
Nullable<int> Strafing_Shots;
Valueable<bool> Strafing_SimulateBurst;
Valueable<bool> Strafing_UseAmmoPerShot;
Valueable<bool> Strafing_TargetCell;
Nullable<int> Strafing_EndDelay;
Valueable<AffectedTarget> CanTarget;
Valueable<AffectedHouse> CanTargetHouses;
Expand Down Expand Up @@ -107,6 +108,7 @@ class WeaponTypeExt
, Strafing_Shots {}
, Strafing_SimulateBurst { false }
, Strafing_UseAmmoPerShot { false }
, Strafing_TargetCell { false }
, Strafing_EndDelay {}
, CanTarget { AffectedTarget::All }
, CanTargetHouses { AffectedHouse::All }
Expand Down
Loading