diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f42cf5bb76..7d2c07b1f5 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -289,8 +289,10 @@ IdleAnimDamaged.ConditionYellow= ; Animation IdleAnimDamaged.ConditionRed= ; Animation IdleAnim.OfflineAction=Hides ; AttachedAnimFlag (None, Hides, Temporal, Paused or PausedTemporal) IdleAnim.TemporalAction=Hides ; AttachedAnimFlag (None, Hides, Temporal, Paused or PausedTemporal) -BreakAnim= ; Animation -HitAnim= ; Animation +BreakAnim= ; list of Animation +BreakAnims= ; list of Animation, overrides BreakAnim +HitAnim= ; list of Animation +HitAnims= ; list of Animation, overrides HitAnim HitFlash=false ; boolean HitFlash.FixedSize= ; integer HitFlash.Red=true ; boolean @@ -315,8 +317,10 @@ ShieldType=SOMESHIELDTYPE ; ShieldType; none by default [SOMEWARHEAD] ; WarheadType Shield.Penetrate=false ; boolean Shield.Break=false ; boolean -Shield.BreakAnim= ; Animation -Shield.HitAnim= ; Animation +Shield.BreakAnim= ; list of Animation +Shield.BreakAnims= ; list of Animation, overrides Shield.BreakAnim +Shield.HitAnim= ; list of Animation +Shield.HitAnims= ; list of Animation, overrides Shield.HitAnim Shield.SkipHitAnim=false ; boolean Shield.HitFlash=true ; boolean Shield.BreakWeapon= ; WeaponType @@ -372,8 +376,8 @@ Shield.InheritStateOnReplace=false ; boolean - `Bouncer=true` and `IsMeteor=true` animations can exhibit irregular behaviour when used as `IdleAnim` and should be avoided. - `IdleAnim.OfflineAction` indicates what happens to the animation when the shield is in a low power state. - `IdleAnim.TemporalAction` indicates what happens to the animation when the shield is attacked by temporal weapons. -- `BreakAnim`, if set, will be played when the shield has been broken. -- `HitAnim`, if set, will be played when the shield is attacked, similar to `WeaponNullifyAnim` for Iron Curtain. +- `BreakAnim(s)`, if set, will be played when the shield has been broken. If more than one animation is listed, a random one is selected. If both are set, `BreakAnims` will override `BreakAnim`. +- `HitAnim(s)`, if set, will be played when the shield is attacked, similar to `WeaponNullifyAnim` for Iron Curtain. If more than one animation is listed, a random one is selected. If both are set, `HitAnims` will override `HitAnim`. - `HitFlash`, if set to true, makes it so that a light flash is generated when the shield is attacked by a Warhead unless it has `Shield.HitFlash=false`. Size of the flash is determined by damage dealt, unless `HitFlash.FixedSize` is set to a number, in which case that value is used instead (range of values that produces visible effect are increments of 4 from 81 to 252, anything higher or below does not have effect). Color can be customized via `HitFlash.Red/Green/Blue`. If `HitFlash.Black` is set to true, the generated flash will be black regardless of other color settings. - `BreakWeapon`, if set, will be fired at the TechnoType once the shield breaks. - `AbsorbPercent` controls the percentage of damage that will be absorbed by the shield. Defaults to 1.0, meaning full damage absorption. @@ -394,8 +398,8 @@ Shield.InheritStateOnReplace=false ; boolean - Warheads have new options that interact with shields. Note that all of these that do not by their very nature require ability to target the shield (such as modifiers like `Shield.Break` or removing / attaching) still require Warhead `Verses` to affect the target unless `EffectsRequireVerses` is set to false on the Warhead. - `Shield.Penetrate` allows the warhead ignore the shield and always deal full damage to the TechnoType itself. It also allows targeting the TechnoType as if shield doesn't exist. - `Shield.Break` allows the warhead to always break shields of TechnoTypes. This is done before damage is dealt. - - `Shield.BreakAnim` will be displayed instead of ShieldType `BreakAnim` if the shield is broken by the Warhead, either through damage or `Shield.Break`. - - `Shield.HitAnim` will be displayed instead of ShieldType `HitAnim` if set when Warhead hits the shield. + - `Shield.BreakAnim(s)` will be displayed instead of ShieldType `BreakAnim(s)` if the shield is broken by the Warhead, either through damage or `Shield.Break`. If more than one animation is listed, a random one is selected. If both are set, `Shield.BreakAnims` will override `Shield.BreakAnim`. + - `Shield.HitAnim(s)` will be displayed instead of ShieldType `HitAnim(s)` if set when Warhead hits the shield. If more than one animation is listed, a random one is selected. If both are set, `Shield.HitAnims` will override `Shield.HitAnim`. - If `Shield.SkipHitAnim` is set to true, no hit anim is shown when the Warhead damages the shield whatsoever. - `Shield.BreakWeapon` will be fired instead of ShieldType `BreakWeapon` if the shield is broken by the Warhead, either through damage or `Shield.Break`. - `Shield.AbsorbPercent` overrides the `AbsorbPercent` value set in the ShieldType that is being damaged. @@ -431,7 +435,7 @@ Shield.InheritStateOnReplace=false ; boolean - `CreateUnit.AlwaysSpawnOnGround`, if set to true, ensures the vehicle will be created on the cell at ground level even if animation is in air. If set to false, jumpjet units spawned on ground will take off automatically after being spawned regardless. - `CreateUnit.SpawnParachutedInAir`, if set to true, makes it so that the vehicle is created with a parachute if it is spawned in air. Has no effect if `CreateUnit.AlwaysSpawnOnGround` is set to true. - `CreateUnit.ConsiderPathfinding`, if set to true, will consider whether or not the cell where the animation is located is occupied by other objects or impassable to the vehicle being created and will attempt to find a nearby cell that is not. Otherwise the vehicle will be created at the animation's location despite these obstacles if possible. - - `CreateUnit.SpawnAnim` can be used to play another animation at created unit's location after it has appeared. This animation has same owner and invoker as the parent animation. + - `CreateUnit.SpawnAnim(s)` can be used to play another animation at created unit's location after it has appeared. This animation has same owner and invoker as the parent animation. If more than one animation is listed, a random one is selected. If both are set, `CreateUnit.SpawnAnims` will override `CreateUnit.SpawnAnim`. - `CreateUnit.SpawnHeight` can be set to override the animation's height when determining where to spawn the created unit. Has no effect if `CreateUnit.AlwaysSpawnOnGround` is set to true. In `artmd.ini`: @@ -449,7 +453,8 @@ CreateUnit.InheritTurretFacings=false ; boolean CreateUnit.AlwaysSpawnOnGround=false ; boolean CreateUnit.SpawnParachutedInAir=false ; boolean CreateUnit.ConsiderPathfinding=false ; boolean -CreateUnit.SpawnAnim= ; Animation +CreateUnit.SpawnAnim= ; list of Animation +CreateUnit.SpawnAnims= ; list of Animation, overrides CreateUnit.SpawnAnim CreareUnit.SpawnHeight= ; integer, height in leptons ``` @@ -907,7 +912,7 @@ Spawner.AttackImmediately=false ; boolean - `PassengerDeletion.SoylentMultiplier` is a direct multiplier applied to the refunded amount of credits. - `PassengerDeletion.SoylentAllowedHouses` determines which houses passengers can belong to be eligible for refunding. - `PassengerDeletion.DisplaySoylent` can be set to true to display the amount of credits refunded on the transport. `PassengerDeletion.DisplaySoylentToHouses` determines which houses can see this and `PassengerDeletion.DisplaySoylentOffset` can be used to adjust the display offset. - - `PassengerDeletion.ReportSound` and `PassengerDeletion.Anim` can be used to specify a sound and animation to play when a passenger is erased, respectively. + - `PassengerDeletion.ReportSound` and `PassengerDeletion.Anim(s)` can be used to specify a sound and animation to play when a passenger is erased, respectively. If more than one animation is listed, a random one is selected. If both are set, `PassengerDeletion.Anims` will override `PassengerDeletion.Anim`. In `rulesmd.ini`: ```ini @@ -926,7 +931,8 @@ PassengerDeletion.DisplaySoylent=false ; boolean PassengerDeletion.DisplaySoylentToHouses=All ; Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) PassengerDeletion.DisplaySoylentOffset=0,0 ; X,Y, pixels relative to default PassengerDeletion.ReportSound= ; Sound -PassengerDeletion.Anim= ; Animation +PassengerDeletion.Anim= ; list of Animation +PassengerDeletion.Anims= ; list of Animation, overrides PassengerDeletion.Anim ``` ### Automatic passenger owner change to match transport owner @@ -1109,7 +1115,7 @@ Both `InitialStrength` and `InitialStrength.Cloning` never surpass the type's `S - `vanish`: The object will be directly removed from the game peacefully instead of actually getting killed. - `sell`: If the object is a **building** with buildup, it will be sold instead of destroyed. -If this option is not set, the self-destruction logic will not be enabled. `AutoDeath.VanishAnimation` can be set to animation to play at object's location if `vanish` behaviour is chosen. +If this option is not set, the self-destruction logic will not be enabled. `AutoDeath.VanishAnimation(s)` can be set to animation to play at object's location if `vanish` behaviour is chosen. If more than one animation is listed, a random one is selected. If both are set, `AutoDeath.VanishAnimations` will override `AutoDeath.VanishAnimation`. ```{note} Please notice that if the object is a unit which carries passengers, they will not be released even with the `kill` option **if you are not using Ares 3.0+**. @@ -1121,7 +1127,8 @@ In `rulesmd.ini`: ```ini [SOMETECHNO] ; TechnoType AutoDeath.Behavior= ; enumeration (kill | vanish | sell), default not set -AutoDeath.VanishAnimation ; Animation +AutoDeath.VanishAnimation= ; list of Animation +AutoDeath.VanishAnimations= ; list of Animation, overrides AutoDeath.VanishAnimation AutoDeath.OnAmmoDepletion=no ; boolean AutoDeath.AfterDelay=0 ; positive integer AutoDeath.TechnosDontExist= ; list of TechnoType names @@ -1279,11 +1286,13 @@ Convert.ComputerToHuman = ; TechnoType ### Destroy animation & sound - You can now specify a destroy animation and sound for a TerrainType that are played when it is destroyed. + - If more than one animation is listed in `DestroyAnim(s)`, a random one is selected. If both are set, `DestroyAnims` will override `DestroyAnim`. In `rulesmd.ini`: ```ini [SOMETERRAINTYPE] ; TerrainType -DestroyAnim= ; Animation +DestroyAnim= ; list of Animation +DestroyAnims= ; list of Animation, overrides DestroyAnim DestroySound= ; Sound ``` diff --git a/src/Ext/Anim/Hooks.AnimCreateUnit.cpp b/src/Ext/Anim/Hooks.AnimCreateUnit.cpp index 8a2fc3d2d0..3621b45a21 100644 --- a/src/Ext/Anim/Hooks.AnimCreateUnit.cpp +++ b/src/Ext/Anim/Hooks.AnimCreateUnit.cpp @@ -144,14 +144,17 @@ DEFINE_HOOK(0x424932, AnimClass_AI_CreateUnit_ActualAffects, 0x6) if (success) { - if (auto const pAnimType = pTypeExt->CreateUnit_SpawnAnim) + if (!pTypeExt->CreateUnit_SpawnAnim.empty()) { - if (auto const pAnim = GameCreate(pAnimType, location)) + if (auto const pAnimType = pTypeExt->CreateUnit_SpawnAnim[ScenarioClass::Instance->Random.RandomRanged(0, pTypeExt->CreateUnit_SpawnAnim.size() - 1)]) { - AnimExt::SetAnimOwnerHouseKind(pAnim, pInvokerHouse, nullptr, false, true); + if (auto const pAnim = GameCreate(pAnimType, location)) + { + AnimExt::SetAnimOwnerHouseKind(pAnim, pInvokerHouse, nullptr, false, true); - if (auto const pAnimExt = AnimExt::ExtMap.Find(pAnim)) - pAnimExt->SetInvoker(pInvoker, pInvokerHouse); + if (auto const pAnimExt = AnimExt::ExtMap.Find(pAnim)) + pAnimExt->SetInvoker(pInvoker, pInvokerHouse); + } } } diff --git a/src/Ext/AnimType/Body.cpp b/src/Ext/AnimType/Body.cpp index 71a4c7d95d..a250494931 100644 --- a/src/Ext/AnimType/Body.cpp +++ b/src/Ext/AnimType/Body.cpp @@ -97,6 +97,7 @@ void AnimTypeExt::ExtData::LoadFromINIFile(CCINIClass* pINI) this->CreateUnit_SpawnParachutedInAir.Read(exINI, pID, "CreateUnit.SpawnParachutedInAir"); this->CreateUnit_ConsiderPathfinding.Read(exINI, pID, "CreateUnit.ConsiderPathfinding"); this->CreateUnit_SpawnAnim.Read(exINI, pID, "CreateUnit.SpawnAnim"); + this->CreateUnit_SpawnAnim.Read(exINI, pID, "CreateUnit.SpawnAnims"); this->CreateUnit_SpawnHeight.Read(exINI, pID, "CreateUnit.SpawnHeight"); this->XDrawOffset.Read(exINI, pID, "XDrawOffset"); this->HideIfNoOre_Threshold.Read(exINI, pID, "HideIfNoOre.Threshold"); diff --git a/src/Ext/AnimType/Body.h b/src/Ext/AnimType/Body.h index ad5047ec48..315eae2ae9 100644 --- a/src/Ext/AnimType/Body.h +++ b/src/Ext/AnimType/Body.h @@ -30,7 +30,7 @@ class AnimTypeExt Valueable CreateUnit_AlwaysSpawnOnGround; Valueable CreateUnit_SpawnParachutedInAir; Valueable CreateUnit_ConsiderPathfinding; - Valueable CreateUnit_SpawnAnim; + ValueableVector CreateUnit_SpawnAnim; Nullable CreateUnit_SpawnHeight; Valueable XDrawOffset; Valueable HideIfNoOre_Threshold; diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 4adfa8df6b..3af7a942d4 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -136,7 +136,10 @@ bool TechnoExt::ExtData::CheckDeathConditions(bool isInLimbo) // Self-destruction must be enabled const auto howToDie = pTypeExt->AutoDeath_Behavior.Get(); - const auto pVanishAnim = pTypeExt->AutoDeath_VanishAnimation; + AnimTypeClass* pVanishAnim = nullptr; + + if (!pTypeExt->AutoDeath_VanishAnimation.empty()) + pVanishAnim = pTypeExt->AutoDeath_VanishAnimation[ScenarioClass::Instance->Random.RandomRanged(0, pTypeExt->AutoDeath_VanishAnimation.size() - 1)]; // Death if no ammo if (pType->Ammo > 0 && pThis->Ammo <= 0 && pTypeExt->AutoDeath_OnAmmoDepletion) @@ -283,11 +286,16 @@ void TechnoExt::ExtData::EatPassengers() if (pDelType->ReportSound >= 0) VocClass::PlayAt(pDelType->ReportSound.Get(), pThis->GetCoords(), nullptr); - if (const auto pAnimType = pDelType->Anim.Get()) + if (!pDelType->Anim.empty()) { - auto const pAnim = GameCreate(pAnimType, pThis->Location); - pAnim->SetOwnerObject(pThis); - pAnim->Owner = pThis->Owner; + if (auto const pAnimType = pDelType->Anim[ScenarioClass::Instance->Random.RandomRanged(0, pDelType->Anim.size() - 1)]) + { + if (auto const pAnim = GameCreate(pAnimType, pThis->Location)) + { + pAnim->SetOwnerObject(pThis); + pAnim->Owner = pThis->Owner; + } + } } // Check if there is money refund diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index aef8425b07..483d9822c5 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -164,6 +164,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->AutoDeath_Behavior.Read(exINI, pSection, "AutoDeath.Behavior"); this->AutoDeath_VanishAnimation.Read(exINI, pSection, "AutoDeath.VanishAnimation"); + this->AutoDeath_VanishAnimation.Read(exINI, pSection, "AutoDeath.VanishAnimations"); this->AutoDeath_OnAmmoDepletion.Read(exINI, pSection, "AutoDeath.OnAmmoDepletion"); this->AutoDeath_AfterDelay.Read(exINI, pSection, "AutoDeath.AfterDelay"); this->AutoDeath_TechnosDontExist.Read(exINI, pSection, "AutoDeath.TechnosDontExist"); diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index b390188549..b341c502ae 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -67,7 +67,7 @@ class TechnoTypeExt Valueable Ammo_DeployUnlockMaximumAmount; Nullable AutoDeath_Behavior; - Valueable AutoDeath_VanishAnimation; + ValueableVector AutoDeath_VanishAnimation; Valueable AutoDeath_OnAmmoDepletion; Valueable AutoDeath_AfterDelay; ValueableVector AutoDeath_TechnosDontExist; diff --git a/src/Ext/TerrainType/Body.cpp b/src/Ext/TerrainType/Body.cpp index c0a655f609..077259c65b 100644 --- a/src/Ext/TerrainType/Body.cpp +++ b/src/Ext/TerrainType/Body.cpp @@ -5,6 +5,7 @@ #include #include +#include #include TerrainTypeExt::ExtContainer TerrainTypeExt::ExtMap; @@ -23,8 +24,11 @@ void TerrainTypeExt::ExtData::PlayDestroyEffects(const CoordStruct& coords) { VocClass::PlayIndexAtPos(this->DestroySound, coords); - if (auto const pAnimType = this->DestroyAnim) - GameCreate(pAnimType, coords); + if (!this->DestroyAnim.empty()) + { + if (auto const pAnimType = this->DestroyAnim[ScenarioClass::Instance->Random.RandomRanged(0, this->DestroyAnim.size() - 1)]) + GameCreate(pAnimType, coords); + } } void TerrainTypeExt::Remove(TerrainClass* pTerrain) @@ -78,6 +82,7 @@ void TerrainTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->SpawnsTiberium_CellsPerAnim.Read(exINI, pSection, "SpawnsTiberium.CellsPerAnim"); this->DestroyAnim.Read(exINI, pSection, "DestroyAnim"); + this->DestroyAnim.Read(exINI, pSection, "DestroyAnims"); this->DestroySound.Read(exINI, pSection, "DestroySound"); this->MinimapColor.Read(exINI, pSection, "MinimapColor"); diff --git a/src/Ext/TerrainType/Body.h b/src/Ext/TerrainType/Body.h index 560b603549..8951d69838 100644 --- a/src/Ext/TerrainType/Body.h +++ b/src/Ext/TerrainType/Body.h @@ -21,7 +21,7 @@ class TerrainTypeExt Valueable SpawnsTiberium_Range; Valueable> SpawnsTiberium_GrowthStage; Valueable> SpawnsTiberium_CellsPerAnim; - Valueable DestroyAnim; + ValueableVector DestroyAnim; ValueableIdx DestroySound; Nullable MinimapColor; Valueable IsPassable; diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 281a42af65..f4831f1fb3 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -196,7 +196,9 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Shield_Penetrate.Read(exINI, pSection, "Shield.Penetrate"); this->Shield_Break.Read(exINI, pSection, "Shield.Break"); this->Shield_BreakAnim.Read(exINI, pSection, "Shield.BreakAnim"); + this->Shield_BreakAnim.Read(exINI, pSection, "Shield.BreakAnims"); this->Shield_HitAnim.Read(exINI, pSection, "Shield.HitAnim"); + this->Shield_HitAnim.Read(exINI, pSection, "Shield.HitAnims"); this->Shield_SkipHitAnim.Read(exINI, pSection, "Shield.SkipHitAnim"); this->Shield_HitFlash.Read(exINI, pSection, "Shield.HitFlash"); this->Shield_BreakWeapon.Read(exINI, pSection, "Shield.BreakWeapon"); diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index 90b9968f7d..a6ec9e7e9b 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -69,8 +69,8 @@ class WarheadTypeExt Valueable Shield_Penetrate; Valueable Shield_Break; - Valueable Shield_BreakAnim; - Valueable Shield_HitAnim; + ValueableVector Shield_BreakAnim; + ValueableVector Shield_HitAnim; Valueable Shield_SkipHitAnim; Valueable Shield_HitFlash; Nullable Shield_BreakWeapon; diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index 356e1426a1..00f57ceab9 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -253,7 +253,14 @@ void WarheadTypeExt::ExtData::ApplyShieldModifiers(TechnoClass* pTarget, TechnoE }; if (this->Shield_Break && pTargetExt->Shield->IsActive() && isShieldTypeEligible(this->Shield_Break_Types.GetElements(this->Shield_AffectTypes))) - pTargetExt->Shield->BreakShield(this->Shield_BreakAnim, this->Shield_BreakWeapon); + { + AnimTypeClass* pAnimType = nullptr; + + if (!this->Shield_BreakAnim.empty()) + pAnimType = this->Shield_BreakAnim[ScenarioClass::Instance->Random.RandomRanged(0, this->Shield_BreakAnim.size() - 1)]; + + pTargetExt->Shield->BreakShield(pAnimType, this->Shield_BreakWeapon); + } if (this->Shield_Respawn_Duration > 0 && isShieldTypeEligible(this->Shield_Respawn_Types.GetElements(this->Shield_AffectTypes))) { diff --git a/src/New/Entity/ShieldClass.cpp b/src/New/Entity/ShieldClass.cpp index 4d105f7809..13be87dc94 100644 --- a/src/New/Entity/ShieldClass.cpp +++ b/src/New/Entity/ShieldClass.cpp @@ -231,7 +231,12 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) int actualResidueDamage = Math::max(0, int((double)(originalShieldDamage - this->HP) / GeneralUtils::GetWarheadVersusArmor(args->WH, this->GetArmorType()))); //only absord percentage damage - this->BreakShield(pWHExt->Shield_BreakAnim, pWHExt->Shield_BreakWeapon.Get(nullptr)); + AnimTypeClass* pAnimType = nullptr; + + if (!pWHExt->Shield_BreakAnim.empty()) + pAnimType = pWHExt->Shield_BreakAnim[ScenarioClass::Instance->Random.RandomRanged(0, pWHExt->Shield_BreakAnim.size() - 1)]; + + this->BreakShield(pAnimType, pWHExt->Shield_BreakWeapon.Get(nullptr)); return this->Type->AbsorbOverDamage ? healthDamage : actualResidueDamage + healthDamage; } @@ -260,7 +265,14 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) } if (!pWHExt->Shield_SkipHitAnim) - this->WeaponNullifyAnim(pWHExt->Shield_HitAnim); + { + AnimTypeClass* pAnimType = nullptr; + + if (!pWHExt->Shield_HitAnim.empty()) + pAnimType = pWHExt->Shield_HitAnim[ScenarioClass::Instance->Random.RandomRanged(0, pWHExt->Shield_HitAnim.size() - 1)]; + + this->WeaponNullifyAnim(pAnimType); + } this->HP = -residueDamage; @@ -324,10 +336,11 @@ void ShieldClass::WeaponNullifyAnim(AnimTypeClass* pHitAnim) if (this->AreAnimsHidden) return; - const auto pAnimType = pHitAnim ? pHitAnim : this->Type->HitAnim; + if (!pHitAnim && !this->Type->HitAnim.empty()) + pHitAnim = this->Type->HitAnim[ScenarioClass::Instance->Random.RandomRanged(0, this->Type->HitAnim.size() - 1)]; - if (pAnimType) - GameCreate(pAnimType, this->Techno->GetCoords()); + if (pHitAnim) + GameCreate(pHitAnim, this->Techno->GetCoords()); } bool ShieldClass::CanBeTargeted(WeaponTypeClass* pWeapon) const @@ -680,11 +693,12 @@ void ShieldClass::BreakShield(AnimTypeClass* pBreakAnim, WeaponTypeClass* pBreak if (!this->AreAnimsHidden) { - const auto pAnimType = pBreakAnim ? pBreakAnim : this->Type->BreakAnim; + if (!pBreakAnim && !this->Type->BreakAnim.empty()) + pBreakAnim = this->Type->BreakAnim[ScenarioClass::Instance->Random.RandomRanged(0, this->Type->BreakAnim.size() - 1)]; - if (pAnimType) + if (pBreakAnim) { - if (auto const pAnim = GameCreate(pAnimType, this->Techno->Location)) + if (auto const pAnim = GameCreate(pBreakAnim, this->Techno->Location)) { pAnim->SetOwnerObject(this->Techno); pAnim->Owner = this->Techno->Owner; diff --git a/src/New/Type/Affiliated/PassengerDeletionTypeClass.cpp b/src/New/Type/Affiliated/PassengerDeletionTypeClass.cpp index 0493a427fb..30a8400865 100644 --- a/src/New/Type/Affiliated/PassengerDeletionTypeClass.cpp +++ b/src/New/Type/Affiliated/PassengerDeletionTypeClass.cpp @@ -53,6 +53,7 @@ void PassengerDeletionTypeClass::LoadFromINI(CCINIClass* pINI, const char* pSect this->DisplaySoylentOffset.Read(exINI, pSection, "PassengerDeletion.DisplaySoylentOffset"); this->ReportSound.Read(exINI, pSection, "PassengerDeletion.ReportSound"); this->Anim.Read(exINI, pSection, "PassengerDeletion.Anim"); + this->Anim.Read(exINI, pSection, "PassengerDeletion.Anims"); } #pragma region(save/load) diff --git a/src/New/Type/Affiliated/PassengerDeletionTypeClass.h b/src/New/Type/Affiliated/PassengerDeletionTypeClass.h index ee2aded116..1c79a9a702 100644 --- a/src/New/Type/Affiliated/PassengerDeletionTypeClass.h +++ b/src/New/Type/Affiliated/PassengerDeletionTypeClass.h @@ -28,7 +28,7 @@ class PassengerDeletionTypeClass Valueable DisplaySoylentToHouses; Valueable DisplaySoylentOffset; ValueableIdx ReportSound; - Valueable Anim; + ValueableVector Anim; void LoadFromINI(CCINIClass* pINI, const char* pSection); bool Load(PhobosStreamReader& stm, bool registerForChange); diff --git a/src/New/Type/ShieldTypeClass.cpp b/src/New/Type/ShieldTypeClass.cpp index f913e64476..7e935aaf8b 100644 --- a/src/New/Type/ShieldTypeClass.cpp +++ b/src/New/Type/ShieldTypeClass.cpp @@ -69,7 +69,9 @@ void ShieldTypeClass::LoadFromINI(CCINIClass* pINI) this->IdleAnimDamaged.Read(exINI, pSection, "IdleAnimDamaged.%s"); this->BreakAnim.Read(exINI, pSection, "BreakAnim"); + this->BreakAnim.Read(exINI, pSection, "BreakAnims"); this->HitAnim.Read(exINI, pSection, "HitAnim"); + this->HitAnim.Read(exINI, pSection, "HitAnims"); this->HitFlash.Read(exINI, pSection, "HitFlash"); this->HitFlash_FixedSize.Read(exINI, pSection, "HitFlash.FixedSize"); this->HitFlash_Red.Read(exINI, pSection, "HitFlash.Red"); diff --git a/src/New/Type/ShieldTypeClass.h b/src/New/Type/ShieldTypeClass.h index 2dfc4d5e59..f3df109e2d 100644 --- a/src/New/Type/ShieldTypeClass.h +++ b/src/New/Type/ShieldTypeClass.h @@ -29,8 +29,8 @@ class ShieldTypeClass final : public Enumerable Valueable IdleAnim_TemporalAction; Damageable IdleAnim; Damageable IdleAnimDamaged; - Valueable BreakAnim; - Valueable HitAnim; + ValueableVector BreakAnim; + ValueableVector HitAnim; Valueable HitFlash; Nullable HitFlash_FixedSize; Valueable HitFlash_Red;