diff --git a/CREDITS.md b/CREDITS.md index ba520cae5f..a30c9f2b08 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -494,6 +494,7 @@ This page lists all the individual contributions to the project by their author. - Damaged unit image changes - `VoiceDeploy` through hot-key/command bar fix - Damaged aircraft image changes + - Delayed fire additional initial animations count - **ZivDero**: - Re-enable the Veinhole Monster and Weeds from TS - Recreate the weed-charging of SWs like the TS Chemical Missile diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f658e71646..c276499ed3 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2669,21 +2669,23 @@ Burst.NoDelay=false ; boolean - If `DelayedFire.CenterAnimOnFirer` is set the animation is created at the firer's center rather than at the firing coordinates. - If the weapon was fired by InfantryType and `DelayedFire.PauseFiringSequence` is set to true, the infantry's firing sequence animation is paused when it hits the firing frame defined by `FireUp/Prone` or `SecondaryFire/Prone` in its `artmd.ini` entry until the delay timer has expired. - If the weapon has `Burst` > 1 and `DelayedFire.OnlyOnInitialBurst` set to true, the delay occurs only before the initial burst shot. Note that if using Ares, `Burst` index does not reset if firing is interrupted or the firer loses target, meaning it will be able to resume firing without waiting for the delay. - -In `rulesmd.ini`: -```ini -[SOMEWEAPON] ; WeaponType -DelayedFire.Duration= ; integer - single or comma-sep. range (game frames) -DelayedFire.SkipInTransport=false ; boolean -DelayedFire.Animation= ; Animation -DelayedFire.OpenToppedAnimation= ; Animation -DelayedFire.AnimIsAttached=true ; boolean -DelayedFire.AnimOffset= ; integer - Forward,Lateral,Height -DelayedFire.AnimOnTurret=true ; boolean -DelayedFire.CenterAnimOnFirer=false ; boolean -DelayedFire.RemoveAnimOnNoDelay=false ; boolean -DelayedFire.PauseFiringSequence=false ; boolean -DelayedFire.OnlyOnInitialBurst=false ; boolean + - If the weapon has `DelayedFire.OnlyOnInitialBurst` set to true and `DelayedFire.InitialBurstAnimCount` set higher than 1, then there will be created additional `DelayedFire.Animation`-s at the same time as the first one. + +In `rulesmd.ini`: +```ini +[SOMEWEAPON] ; WeaponType +DelayedFire.Duration= ; integer - single or comma-sep. range (game frames) +DelayedFire.SkipInTransport=false ; boolean +DelayedFire.Animation= ; Animation +DelayedFire.OpenToppedAnimation= ; Animation +DelayedFire.AnimIsAttached=true ; boolean +DelayedFire.AnimOffset= ; integer - Forward,Lateral,Height +DelayedFire.AnimOnTurret=true ; boolean +DelayedFire.CenterAnimOnFirer=false ; boolean +DelayedFire.RemoveAnimOnNoDelay=false ; boolean +DelayedFire.PauseFiringSequence=false ; boolean +DelayedFire.OnlyOnInitialBurst=false ; boolean +DelayedFire.InitialBurstAnimCount=1 ; integer ``` ```{note} diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 7765e7bdb1..8fba90bafc 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -464,6 +464,7 @@ New: - [Customize if cloning need power](Fixed-or-Improved-Logics.md#customize-if-cloning-need-power) (by NetsuNegi) - [Added Target Filtering Options to AttachEffect System](New-or-Enhanced-Logics.md#attached-effects) (by Flactine) - [Customize type selection for IFV](Fixed-or-Improved-Logics.md#customize-type-selection-for-ifv) (by NetsuNegi) +- Delayed fire additional initial animations count Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/src/Ext/Techno/Body.Internal.cpp b/src/Ext/Techno/Body.Internal.cpp index 9a6a420049..37292e54c5 100644 --- a/src/Ext/Techno/Body.Internal.cpp +++ b/src/Ext/Techno/Body.Internal.cpp @@ -148,6 +148,25 @@ CoordStruct TechnoExt::GetSimpleFLH(InfantryClass* pThis, int weaponIndex, bool& return FLH; } +CoordStruct TechnoExt::GetCompleteFLH(TechnoClass* pThis, int weaponIndex) +{ + bool found = false; + auto FLH = TechnoExt::GetBurstFLH(pThis, weaponIndex, found); + + if (!found) + { + if (auto const pInf = abstract_cast(pThis)) + FLH = TechnoExt::GetSimpleFLH(pInf, weaponIndex, found); + + if (!found) + FLH = pThis->GetWeapon(weaponIndex)->FLH; + + if (pThis->CurrentBurstIndex % 2 != 0) + FLH.Y = -FLH.Y; + } + return FLH; +} + void TechnoExt::ExtData::InitializeDisplayInfo() { const auto pThis = this->OwnerObject(); diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 121ece2f9a..73c64a389e 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -713,6 +713,21 @@ bool TechnoExt::HandleDelayedFireWithPauseSequence(TechnoClass* pThis, WeaponTyp if (pWeaponExt->DelayedFire_AnimOffset.isset()) firingCoords = pWeaponExt->DelayedFire_AnimOffset; + else + firingCoords = TechnoExt::GetCompleteFLH(pThis, weaponIndex); + + if(pWeaponExt->DelayedFire_InitialBurstAnimCount > 1 && pThis->CurrentBurstIndex == 0) + { + for (int i = 1; i < pWeaponExt->DelayedFire_InitialBurstAnimCount; i++) + { + TechnoExt::CreateDelayedFireAnim(pThis, pAnimType, weaponIndex, pWeaponExt->DelayedFire_AnimIsAttached, pWeaponExt->DelayedFire_CenterAnimOnFirer, + pWeaponExt->DelayedFire_RemoveAnimOnNoDelay, pWeaponExt->DelayedFire_AnimOnTurret, firingCoords); + pThis->CurrentBurstIndex = i; + firingCoords = TechnoExt::GetCompleteFLH(pThis, weaponIndex); + } + + pThis->CurrentBurstIndex = 0; + } TechnoExt::CreateDelayedFireAnim(pThis, pAnimType, weaponIndex, pWeaponExt->DelayedFire_AnimIsAttached, pWeaponExt->DelayedFire_CenterAnimOnFirer, pWeaponExt->DelayedFire_RemoveAnimOnNoDelay, pWeaponExt->DelayedFire_AnimOnTurret, firingCoords); diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 89ed549edf..c29a2fc2d1 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -258,6 +258,7 @@ class TechnoExt static CoordStruct GetBurstFLH(TechnoClass* pThis, int weaponIndex, bool& FLHFound); static CoordStruct GetSimpleFLH(InfantryClass* pThis, int weaponIndex, bool& FLHFound); + static CoordStruct GetCompleteFLH(TechnoClass* pThis, int weaponIndex); static void ChangeOwnerMissionFix(FootClass* pThis); static void KillSelf(TechnoClass* pThis, AutoDeathBehavior deathOption, const std::vector& pVanishAnimation, bool isInLimbo = false); diff --git a/src/Ext/Techno/Hooks.Firing.cpp b/src/Ext/Techno/Hooks.Firing.cpp index 9f38a1b6e8..d479bc70dc 100644 --- a/src/Ext/Techno/Hooks.Firing.cpp +++ b/src/Ext/Techno/Hooks.Firing.cpp @@ -572,7 +572,6 @@ DEFINE_HOOK(0x6FDDC0, TechnoClass_FireAt_BeforeTruelyFire, 0x6) pExt->DelayedFireWeaponIndex = weaponIndex; timer.Start(Math::max(GeneralUtils::GetRangedRandomOrSingleValue(pWeaponExt->DelayedFire_Duration), 0)); auto pAnimType = pWeaponExt->DelayedFire_Animation; - if (pThis->Transporter && pWeaponExt->DelayedFire_OpenToppedAnimation.isset()) pAnimType = pWeaponExt->DelayedFire_OpenToppedAnimation; @@ -580,10 +579,24 @@ DEFINE_HOOK(0x6FDDC0, TechnoClass_FireAt_BeforeTruelyFire, 0x6) if (pWeaponExt->DelayedFire_AnimOffset.isset()) firingCoords = pWeaponExt->DelayedFire_AnimOffset; + else + firingCoords = TechnoExt::GetCompleteFLH(pThis, weaponIndex); + + if(pWeaponExt->DelayedFire_InitialBurstAnimCount > 1 && pThis->CurrentBurstIndex == 0) + { + for (int i = 1; i < pWeaponExt->DelayedFire_InitialBurstAnimCount; i++) + { + TechnoExt::CreateDelayedFireAnim(pThis, pAnimType, weaponIndex, pWeaponExt->DelayedFire_AnimIsAttached, pWeaponExt->DelayedFire_CenterAnimOnFirer, + pWeaponExt->DelayedFire_RemoveAnimOnNoDelay, pWeaponExt->DelayedFire_AnimOnTurret, firingCoords); + pThis->CurrentBurstIndex = i; + firingCoords = TechnoExt::GetCompleteFLH(pThis, weaponIndex); + } + + pThis->CurrentBurstIndex = 0; + } TechnoExt::CreateDelayedFireAnim(pThis, pAnimType, weaponIndex, pWeaponExt->DelayedFire_AnimIsAttached, pWeaponExt->DelayedFire_CenterAnimOnFirer, pWeaponExt->DelayedFire_RemoveAnimOnNoDelay, pWeaponExt->DelayedFire_AnimOnTurret, firingCoords); - return SkipFiring; } else @@ -915,20 +928,7 @@ DEFINE_HOOK(0x6F3AEB, TechnoClass_GetFLH, 0x6) if (weaponIndex >= 0) { - bool found = false; - flh = TechnoExt::GetBurstFLH(pThis, weaponIndex, found); - - if (!found) - { - if (auto const pInf = abstract_cast(pThis)) - flh = TechnoExt::GetSimpleFLH(pInf, weaponIndex, found); - - if (!found) - flh = pThis->GetWeapon(weaponIndex)->FLH; - - if (pThis->CurrentBurstIndex % 2 != 0) - flh.Y = -flh.Y; - } + flh = TechnoExt::GetCompleteFLH(pThis, weaponIndex); } else { diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index e3cd9c1d5c..217606ac50 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -151,6 +151,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->DelayedFire_RemoveAnimOnNoDelay.Read(exINI, pSection, "DelayedFire.RemoveAnimOnNoDelay"); this->DelayedFire_PauseFiringSequence.Read(exINI, pSection, "DelayedFire.PauseFiringSequence"); this->DelayedFire_OnlyOnInitialBurst.Read(exINI, pSection, "DelayedFire.OnlyOnInitialBurst"); + this->DelayedFire_InitialBurstAnimCount.Read(exINI, pSection, "DelayedFire.InitialBurstAnimCount"); this->DelayedFire_AnimOffset.Read(exINI, pSection, "DelayedFire.AnimOffset"); this->DelayedFire_AnimOnTurret.Read(exINI, pSection, "DelayedFire.AnimOnTurret"); @@ -235,6 +236,7 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm) .Process(this->DelayedFire_RemoveAnimOnNoDelay) .Process(this->DelayedFire_PauseFiringSequence) .Process(this->DelayedFire_OnlyOnInitialBurst) + .Process(this->DelayedFire_InitialBurstAnimCount) .Process(this->DelayedFire_AnimOffset) .Process(this->DelayedFire_AnimOnTurret) ; diff --git a/src/Ext/WeaponType/Body.h b/src/Ext/WeaponType/Body.h index 03d6fe37e0..61f8722a7f 100644 --- a/src/Ext/WeaponType/Body.h +++ b/src/Ext/WeaponType/Body.h @@ -89,6 +89,7 @@ class WeaponTypeExt Valueable DelayedFire_RemoveAnimOnNoDelay; Valueable DelayedFire_PauseFiringSequence; Valueable DelayedFire_OnlyOnInitialBurst; + Valueable DelayedFire_InitialBurstAnimCount; Nullable DelayedFire_AnimOffset; Valueable DelayedFire_AnimOnTurret; @@ -162,6 +163,7 @@ class WeaponTypeExt , DelayedFire_RemoveAnimOnNoDelay { false } , DelayedFire_PauseFiringSequence { false } , DelayedFire_OnlyOnInitialBurst { false } + , DelayedFire_InitialBurstAnimCount { 1 } , DelayedFire_AnimOffset {} , DelayedFire_AnimOnTurret { true } { }