diff --git a/src/Ext/Infantry/Hooks.Firing.cpp b/src/Ext/Infantry/Hooks.Firing.cpp index 16b248b10d..39d7c442d9 100644 --- a/src/Ext/Infantry/Hooks.Firing.cpp +++ b/src/Ext/Infantry/Hooks.Firing.cpp @@ -87,8 +87,8 @@ DEFINE_HOOK(0x5209AF, InfantryClass_FiringAI, 0x6) { enum { Continue = 0x5209CD, ReturnFromFunction = 0x520AD9 }; - GET(InfantryClass*, pThis, EBP); - GET(int, firingFrame, EDX); + GET(InfantryClass* const, pThis, EBP); + GET(const int, fireUp, EDX); int cumulativeDelay = 0; int projectedDelay = 0; @@ -115,17 +115,20 @@ DEFINE_HOOK(0x5209AF, InfantryClass_FiringAI, 0x6) } } - if (TechnoExt::HandleDelayedFireWithPauseSequence(pThis, weaponIndex, firingFrame + cumulativeDelay)) + const int frame = pThis->Animation.Value; + const int firingFrame = fireUp + cumulativeDelay; + + if (TechnoExt::HandleDelayedFireWithPauseSequence(pThis, FiringAITemp::WeaponType, weaponIndex, frame, firingFrame)) return ReturnFromFunction; - if (pThis->Animation.Value == firingFrame + cumulativeDelay) + if (frame == firingFrame) { if (allowBurst) { - int frameCount = pThis->Type->Sequence->GetSequence(pThis->SequenceAnim).CountFrames; + const int frameCount = pThis->Type->Sequence->GetSequence(pThis->SequenceAnim).CountFrames; // If projected frame for firing next shot goes beyond the sequence frame count, cease firing after this shot and start rearm timer. - if (firingFrame + projectedDelay > frameCount) + if (fireUp + projectedDelay > frameCount) TechnoExt::ExtMap.Find(pThis)->ForceFullRearmDelay = true; } @@ -177,26 +180,26 @@ DEFINE_HOOK(0x5209EE, InfantryClass_UpdateFiring_BurstNoDelay, 0x5) enum { SkipVanillaFire = 0x520A57 }; GET(InfantryClass* const, pThis, EBP); - GET(const int, wpIdx, ESI); + GET(const int, weaponIndex, ESI); GET(AbstractClass* const, pTarget, EAX); - if (const auto pWeapon = pThis->GetWeapon(wpIdx)->WeaponType) + if (const auto pWeapon = pThis->GetWeapon(weaponIndex)->WeaponType) { if (pWeapon->Burst > 1) { - const auto pExt = WeaponTypeExt::ExtMap.Find(pWeapon); + const auto pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon); - if (pExt->Burst_NoDelay && (!pExt->DelayedFire_Duration.isset() || pExt->DelayedFire_OnlyOnInitialBurst)) + if (pWeaponExt->Burst_NoDelay && (!pWeaponExt->DelayedFire_Duration.isset() || pWeaponExt->DelayedFire_OnlyOnInitialBurst)) { - if (pThis->Fire(pTarget, wpIdx)) + if (pThis->Fire(pTarget, weaponIndex)) { if (!pThis->CurrentBurstIndex) return SkipVanillaFire; - auto rof = pThis->RearmTimer.TimeLeft; + int rof = pThis->RearmTimer.TimeLeft; pThis->RearmTimer.Start(0); - for (auto i = pThis->CurrentBurstIndex; i < pWeapon->Burst && pThis->GetFireError(pTarget, wpIdx, true) == FireError::OK && pThis->Fire(pTarget, wpIdx); ++i) + for (int i = pThis->CurrentBurstIndex; i < pWeapon->Burst && pThis->GetFireError(pTarget, weaponIndex, true) == FireError::OK && pThis->Fire(pTarget, weaponIndex); ++i) { rof = pThis->RearmTimer.TimeLeft; pThis->RearmTimer.Start(0); diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 421fc8c6f3..b70ae4b52e 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -689,11 +689,10 @@ void TechnoExt::CreateDelayedFireAnim(TechnoClass* pThis, AnimTypeClass* pAnimTy } } -bool TechnoExt::HandleDelayedFireWithPauseSequence(TechnoClass* pThis, int weaponIndex, int firingFrame) +bool TechnoExt::HandleDelayedFireWithPauseSequence(TechnoClass* pThis, WeaponTypeClass* pWeapon, int weaponIndex, int frame, int firingFrame) { auto const pExt = TechnoExt::ExtMap.Find(pThis); auto& timer = pExt->DelayedFireTimer; - auto const pWeapon = pThis->GetWeapon(weaponIndex)->WeaponType; auto const pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon); if (pExt->DelayedFireWeaponIndex >= 0 && pExt->DelayedFireWeaponIndex != weaponIndex) @@ -706,7 +705,7 @@ bool TechnoExt::HandleDelayedFireWithPauseSequence(TechnoClass* pThis, int weapo { if (pWeapon->Burst <= 1 || !pWeaponExt->DelayedFire_OnlyOnInitialBurst || pThis->CurrentBurstIndex == 0) { - if (pThis->Animation.Value == firingFrame) + if (frame == firingFrame) pExt->DelayedFireSequencePaused = true; if (!timer.HasStarted()) @@ -925,7 +924,6 @@ void TechnoExt::ExtData::Serialize(T& Stm) .Process(this->LastSensorsMapCoords) .Process(this->TiberiumEater_Timer) .Process(this->AirstrikeTargetingMe) - .Process(this->FiringAnimationTimer) .Process(this->SimpleDeployerAnimationTimer) .Process(this->DelayedFireSequencePaused) .Process(this->DelayedFireTimer) diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 3efd6663bb..adf1ad6516 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -78,8 +78,6 @@ class TechnoExt AirstrikeClass* AirstrikeTargetingMe; - CDTimerClass FiringAnimationTimer; - bool IsSelected; bool ResetLocomotor; @@ -146,7 +144,6 @@ class TechnoExt , LastSensorsMapCoords { CellStruct::Empty } , TiberiumEater_Timer {} , AirstrikeTargetingMe { nullptr } - , FiringAnimationTimer {} , SimpleDeployerAnimationTimer {} , DelayedFireSequencePaused { false } , DelayedFireWeaponIndex { -1 } @@ -280,7 +277,7 @@ class TechnoExt static void GetValuesForDisplay(TechnoClass* pThis, DisplayInfoType infoType, int& value, int& maxValue, int infoIndex); static void GetDigitalDisplayFakeHealth(TechnoClass* pThis, int& value, int& maxValue); static void CreateDelayedFireAnim(TechnoClass* pThis, AnimTypeClass* pAnimType, int weaponIndex, bool attach, bool center, bool removeOnNoDelay, bool onTurret, CoordStruct firingCoords); - static bool HandleDelayedFireWithPauseSequence(TechnoClass* pThis, int weaponIndex, int firingFrame); + static bool HandleDelayedFireWithPauseSequence(TechnoClass* pThis, WeaponTypeClass* pWeapon, int weaponIndex, int frame, int firingFrame); static bool IsHealthInThreshold(TechnoClass* pObject, double min, double max); static UnitTypeClass* GetUnitTypeExtra(UnitClass* pUnit); static AircraftTypeClass* GetAircraftTypeExtra(AircraftClass* pAircraft); diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 40f985832a..7ddd10463b 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -32,6 +32,18 @@ DEFINE_JUMP(VTABLE, 0x7F5CF4, 0x741490) // UnitClass_GetTechnoType -> UnitClass_ #pragma region Update +DEFINE_HOOK(0x7363C9, UnitClass_AI_AnimationPaused, 0x6) +{ + enum { SkipGameCode = 0x7363DE }; + + GET(UnitClass*, pThis, ESI); + + if (TechnoExt::ExtMap.Find(pThis)->DelayedFireSequencePaused) + return SkipGameCode; + + return 0; +} + // Early, before ObjectClass_AI DEFINE_HOOK(0x6F9E50, TechnoClass_AI, 0x5) { @@ -983,7 +995,7 @@ DEFINE_HOOK(0x6FCF3E, TechnoClass_SetTarget_After, 0x6) || !pThis->IsCloseEnough(pTarget, pThis->SelectWeapon(pTarget))) { pUnit->CurrentFiringFrame = -1; - pExt->FiringAnimationTimer.Stop(); + pExt->ResetDelayedFireTimer(); } } } diff --git a/src/Ext/Unit/Hooks.Firing.cpp b/src/Ext/Unit/Hooks.Firing.cpp index 9e3bf78cd3..7e861e2780 100644 --- a/src/Ext/Unit/Hooks.Firing.cpp +++ b/src/Ext/Unit/Hooks.Firing.cpp @@ -7,43 +7,41 @@ DEFINE_HOOK(0x736F61, UnitClass_UpdateFiring_FireUp, 0x6) { enum { SkipFiring = 0x737063 }; - GET(UnitClass*, pThis, ESI); - GET(int, weaponIndex, EDI); + GET(UnitClass* const, pThis, ESI); + GET(const int, weaponIndex, EDI); const auto pType = pThis->Type; - if (pType->Turret || pType->Voxel) + if (pType->Turret || pType->Voxel || pThis->InLimbo) return 0; const auto pExt = TechnoExt::ExtMap.Find(pThis); // SHP vehicles have no secondary action frames, so it does not need SecondaryFire. - const auto pTypeExt = pExt->TypeExtData; - const int fireUp = pTypeExt->FireUp; - CDTimerClass& timer = pExt->FiringAnimationTimer; + const int fireUp = pExt->TypeExtData->FireUp; if (fireUp >= 0 && !pType->OpportunityFire && pThis->Locomotor->Is_Really_Moving_Now()) { - if (timer.InProgress()) - timer.Stop(); + if (pThis->CurrentFiringFrame != -1) + pThis->CurrentFiringFrame = -1; return SkipFiring; } - const int frames = pType->FiringFrames; + const int firingFrames = pType->FiringFrames; + const int frames = 2 * firingFrames - 1; - if (!timer.InProgress() && frames >= 1) - { - pThis->CurrentFiringFrame = 2 * frames - 1; - timer.Start(pThis->CurrentFiringFrame); - } + if (frames >= 0 && pThis->CurrentFiringFrame == -1) + pThis->CurrentFiringFrame = frames; - if (fireUp >= 0 && frames >= 1) + auto const pWeapon = pThis->GetWeapon(weaponIndex)->WeaponType; + + if (fireUp >= 0) { int cumulativeDelay = 0; int projectedDelay = 0; - auto const pWeaponExt = WeaponTypeExt::ExtMap.TryFind(pThis->GetWeapon(weaponIndex)->WeaponType); - const bool allowBurst = pWeaponExt && pWeaponExt->Burst_FireWithinSequence; + auto const pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon); + const bool allowBurst = pWeaponExt->Burst_FireWithinSequence; const int currentBurstIndex = pThis->CurrentBurstIndex; auto& random = ScenarioClass::Instance->Random; @@ -66,15 +64,13 @@ DEFINE_HOOK(0x736F61, UnitClass_UpdateFiring_FireUp, 0x6) } } - if (TechnoExt::HandleDelayedFireWithPauseSequence(pThis, weaponIndex, fireUp + cumulativeDelay)) - return SkipFiring; + const int frame = (frames - pThis->CurrentFiringFrame) / 2; + const int firingFrame = fireUp + cumulativeDelay; - int frame = (timer.TimeLeft - timer.GetTimeLeft()); - - if (frame % 2 != 0) + if (TechnoExt::HandleDelayedFireWithPauseSequence(pThis, pWeapon, weaponIndex, frame, firingFrame)) return SkipFiring; - if (frame / 2 != fireUp + cumulativeDelay) + if (frame != firingFrame) { return SkipFiring; } @@ -85,6 +81,10 @@ DEFINE_HOOK(0x736F61, UnitClass_UpdateFiring_FireUp, 0x6) pExt->ForceFullRearmDelay = true; } } + else if (TechnoExt::HandleDelayedFireWithPauseSequence(pThis, pWeapon, weaponIndex, 0, -1)) + { + return SkipFiring; + } return 0; } @@ -94,26 +94,26 @@ DEFINE_HOOK(0x736F67, UnitClass_UpdateFiring_BurstNoDelay, 0x6) enum { SkipVanillaFire = 0x737063 }; GET(UnitClass* const, pThis, ESI); - GET(const int, wpIdx, EDI); + GET(const int, weaponIndex, EDI); GET(AbstractClass* const, pTarget, EAX); - if (const auto pWeapon = pThis->GetWeapon(wpIdx)->WeaponType) + if (const auto pWeapon = pThis->GetWeapon(weaponIndex)->WeaponType) { if (pWeapon->Burst > 1) { - const auto pExt = WeaponTypeExt::ExtMap.Find(pWeapon); + const auto pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon); - if (pExt->Burst_NoDelay && (!pExt->DelayedFire_Duration.isset() || pExt->DelayedFire_OnlyOnInitialBurst)) + if (pWeaponExt->Burst_NoDelay && (!pWeaponExt->DelayedFire_Duration.isset() || pWeaponExt->DelayedFire_OnlyOnInitialBurst)) { - if (pThis->Fire(pTarget, wpIdx)) + if (pThis->Fire(pTarget, weaponIndex)) { if (!pThis->CurrentBurstIndex) return SkipVanillaFire; - auto rof = pThis->RearmTimer.TimeLeft; + int rof = pThis->RearmTimer.TimeLeft; pThis->RearmTimer.Start(0); - for (auto i = pThis->CurrentBurstIndex; i < pWeapon->Burst && pThis->GetFireError(pTarget, wpIdx, true) == FireError::OK && pThis->Fire(pTarget, wpIdx); ++i) + for (int i = pThis->CurrentBurstIndex; i < pWeapon->Burst && pThis->GetFireError(pTarget, weaponIndex, true) == FireError::OK && pThis->Fire(pTarget, weaponIndex); ++i) { rof = pThis->RearmTimer.TimeLeft; pThis->RearmTimer.Start(0); diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index be24ebc24f..7f2037c577 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -127,7 +127,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) exINI.ParseStringList(this->AttachEffect_RequiredGroups, pSection, "AttachEffect.RequiredGroups"); exINI.ParseStringList(this->AttachEffect_DisallowedGroups, pSection, "AttachEffect.DisallowedGroups"); this->AttachEffect_RequiredMinCounts.Read(exINI, pSection, "AttachEffect.RequiredMinCounts"); - this->AttachEffect_RequiredMaxCounts.Read(exINI, pSection, "AttachEffect.RequiredMaxCounts");this->DelayedFire_Duration.Read(exINI, pSection, "DelayedFire.Duration"); + this->AttachEffect_RequiredMaxCounts.Read(exINI, pSection, "AttachEffect.RequiredMaxCounts"); this->AttachEffect_DisallowedMinCounts.Read(exINI, pSection, "AttachEffect.DisallowedMinCounts"); this->AttachEffect_DisallowedMaxCounts.Read(exINI, pSection, "AttachEffect.DisallowedMaxCounts"); this->AttachEffect_CheckOnFirer.Read(exINI, pSection, "AttachEffect.CheckOnFirer");