Skip to content

Commit 14f124f

Browse files
committed
ExtraWarheads AE
1 parent efe8f20 commit 14f124f

File tree

12 files changed

+124
-46
lines changed

12 files changed

+124
-46
lines changed

CREDITS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ This page lists all the individual contributions to the project by their author.
468468
- Fire weapon when Warhead kills something
469469
- Promotion animation deglobalization
470470
- Forcing specific weapon by range
471+
- Attached effect attach/discard by health
472+
- Attached effect with `ExtraWarheads`
471473
- **NaotoYuuki** - Vertical & meteor trajectory projectile prototypes
472474
- **handama** - AI script action to `16005 Jump Back To Previous Script`
473475
- **TaranDahl (航味麻酱)**:

docs/New-or-Enhanced-Logics.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This page describes all the engine features that are either new and introduced b
88

99
- Similar (but not identical) to [Ares' AttachEffect](https://ares-developers.github.io/Ares-docs/new/attacheffect.html), but with some differences and new features. The largest difference is that here attached effects are explicitly defined types.
1010
- `Duration` determines how long the effect lasts for. It can be overriden by `DurationOverrides` on TechnoTypes and Warheads.
11-
- `Duration.ApplyVersus.Warhead` can multiply the duration by the set warhead's versus against the target's armor type if it's not negative. Can't reduce duration to below 0 by a negative versus.
11+
- If `Duration.ApplyVersus.Warhead` is set, it can multiply the duration by the set warhead's versus against the target's armor type if it's not negative. Can't reduce duration to below 0 by a negative versus.
1212
- If `Duration.ApplyFirepowerMult` set to true, the duration will multiply the invoker's firepower multipliers if it's not negative. Can't reduce duration to below 0 by a negative firepower multiplier.
1313
- If `Duration.ApplyArmorMultOnTarget` set to true, the duration will divide the target's armor multipliers if it's not negative. This'll also include `ArmorMultiplier` from its own and ignore `ArmorMultiplier.Allow/DisallowWarheads`. Can't reduce duration to below 0 by a negative armor multiplier.
1414
- `Cumulative`, if set to true, allows the same type of effect to be applied on same object multiple times, up to `Cumulative.MaxCount` number or with no limit if `Cumulative.MaxCount` is a negative number. If the target already has `Cumulative.MaxCount` number of the same effect applied on it, trying to attach another will refresh duration of the attached instance with shortest remaining duration.
@@ -36,6 +36,11 @@ This page describes all the engine features that are either new and introduced b
3636
- Attached effect can fire off a weapon when expired / removed / object dies by setting `ExpireWeapon`.
3737
- `ExpireWeapon.TriggerOn` determines the exact conditions upon which the weapon is fired, defaults to `expire` which means only if the effect naturally expires.
3838
- `ExpireWeapon.CumulativeOnlyOnce`, if set to true, makes it so that `Cumulative=true` attached effects only detonate the weapon once period, instead of once per active instance. On `remove` and `expire` condition this means it will only detonate after last instance has expired or been removed.
39+
- Attached effect can allow the TechnoType's weapon to detonate multiple Warheads on impact by listing `ExtraWarheads`. The warheads are detonated at same location as the main one, after it in listed order. This only works in cases where a projectile has been fired by a weapon and still remembers it when it is detonated (due to currently existing technical limitations, this excludes `AirburstWeapon`).
40+
- `ExtraWarheads.DamageOverrides` can be used to override the weapon's `Damage` for the extra Warhead detonations. Value from position matching the position from `ExtraWarheads` is used if found, or last listed value if not found. If list is empty, WeaponType `Damage` is used.
41+
- `ExtraWarheads.DetonationChances` can be used to customize the chance of each extra Warhead detonation occuring. Value from position matching the position from `ExtraWarheads` is used if found, or last listed value if not found. If list is empty, every extra Warhead detonation is guaranteed to occur.
42+
- `ExtraWarheads.FullDetonation` can be used to customize whether or not each individual Warhead is detonated fully (as part of a dummy weapon) or simply deals area damage and applies Phobos' Warhead effects. Value from position matching the position from `ExtraWarheads` is used if found, or last listed value if not found. If list is empty, defaults to true.
43+
- Note that the listed Warheads must be listed in `[Warheads]` for them to work.
3944
- `Tint.Color` & `Tint.Intensity` can be used to set a color tint effect and additive lighting increase/decrease on the object the effect is attached to, respectively.
4045
- `Tint.VisibleToHouses` can be used to control which houses can see the tint effect.
4146
- `FirepowerMultiplier`, `ArmorMultiplier`, `SpeedMultiplier` and `ROFMultiplier` can be used to modify the object's firepower, armor strength, movement speed and weapon reload rate, respectively.
@@ -112,6 +117,10 @@ CumulativeAnimations.RestartOnChange=true ; boolean
112117
ExpireWeapon= ; WeaponType
113118
ExpireWeapon.TriggerOn=expire ; List of expire weapon trigger condition enumeration (none|expire|remove|death|discard|all)
114119
ExpireWeapon.CumulativeOnlyOnce=false ; boolean
120+
ExtraWarheads= ; List of WarheadTypes
121+
ExtraWarheads.DamageOverrides= ; List of integers
122+
ExtraWarheads.DetonationChances= ; List of floating-point values (percentage or absolute)
123+
ExtraWarheads.FullDetonation= ; List of booleans
115124
Tint.Color= ; integer - R,G,B
116125
Tint.Intensity= ; floating point value
117126
Tint.VisibleToHouses=all ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)

docs/Whats-New.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ New:
370370
- Customize airstrike targets (by NetsuNegi)
371371
- Aggressive attack move mission (by CrimRecya)
372372
- Amphibious access vehicle (by CrimRecya)
373+
- Attached effect attach/discard by health (by Ollerus)
374+
- Attached effect with `ExtraWarheads` (by Ollerus)
373375
374376
Vanilla fixes:
375377
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)

src/Ext/Bullet/Body.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,47 @@ void BulletExt::ExtData::InitializeLaserTrails()
154154
}
155155
}
156156

157+
void BulletExt::ExtData::ApplyExtraWarheads(std::vector<WarheadTypeClass*> exWH, std::vector<int> exWHDamageOverrides, std::vector<double> exWHChances, std::vector<bool> exWHFull, CoordStruct* coords, HouseClass* pOwner)
158+
{
159+
auto const pThis = this->OwnerObject();
160+
int damage = pThis->WeaponType ? pThis->WeaponType->Damage : 0;
161+
162+
for (size_t i = 0; i < exWH.size(); i++)
163+
{
164+
auto const pWH = exWH[i];
165+
size_t size = exWHDamageOverrides.size();
166+
167+
if (size > i)
168+
damage = exWHDamageOverrides[i];
169+
else if (size > 0)
170+
damage = exWHDamageOverrides[size - 1];
171+
172+
bool detonate = true;
173+
size = exWHChances.size();
174+
175+
if (size > i)
176+
detonate = exWHChances[i] >= ScenarioClass::Instance->Random.RandomDouble();
177+
else if (size > 0)
178+
detonate = exWHChances[size - 1] >= ScenarioClass::Instance->Random.RandomDouble();
179+
180+
bool isFull = true;
181+
size = exWHFull.size();
182+
183+
if (size > i)
184+
isFull = exWHFull[i];
185+
else if (size > 0)
186+
isFull = exWHFull[size - 1];
187+
188+
if (!detonate)
189+
continue;
190+
191+
if (isFull)
192+
WarheadTypeExt::DetonateAt(pWH, *coords, pThis->Owner, damage, pOwner, pThis->Target);
193+
else
194+
WarheadTypeExt::ExtMap.Find(pWH)->DamageAreaWithTarget(*coords, damage, pThis->Owner, pWH, true, pOwner, abstract_cast<TechnoClass*>(pThis->Target));
195+
}
196+
}
197+
157198
static inline int SetBuildingFireAnimZAdjust(BuildingClass* pBuilding, int animY)
158199
{
159200
if (pBuilding->GetOccupantCount() > 0)

src/Ext/Bullet/Body.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class BulletExt
5454
void InterceptBullet(TechnoClass* pSource, WeaponTypeClass* pWeapon);
5555
void ApplyRadiationToCell(CellStruct Cell, int Spread, int RadLevel);
5656
void InitializeLaserTrails();
57+
void ApplyExtraWarheads(std::vector<WarheadTypeClass*> exWH, std::vector<int> exWHDamageOverrides, std::vector<double> exWHChances, std::vector<bool> exWHFull, CoordStruct* coords, HouseClass* pOwner);
5758

5859
private:
5960
template <typename T>

src/Ext/Bullet/Hooks.DetonateLogics.cpp

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -297,48 +297,29 @@ DEFINE_HOOK(0x469AA4, BulletClass_Logics_Extras, 0x5)
297297
GET(BulletClass*, pThis, ESI);
298298
GET_BASE(CoordStruct*, coords, 0x8);
299299

300-
auto const pOwner = pThis->Owner ? pThis->Owner->Owner : BulletExt::ExtMap.Find(pThis)->FirerHouse;
300+
auto const pBulletExt = BulletExt::ExtMap.Find(pThis);
301+
auto const pOwner = pThis->Owner ? pThis->Owner->Owner : pBulletExt->FirerHouse;
301302

302303
// Extra warheads
303304
if (pThis->WeaponType)
304305
{
305306
auto const pWeaponExt = WeaponTypeExt::ExtMap.Find(pThis->WeaponType);
306-
int defaultDamage = pThis->WeaponType->Damage;
307-
308-
for (size_t i = 0; i < pWeaponExt->ExtraWarheads.size(); i++)
309-
{
310-
auto const pWH = pWeaponExt->ExtraWarheads[i];
311-
int damage = defaultDamage;
312-
size_t size = pWeaponExt->ExtraWarheads_DamageOverrides.size();
313-
314-
if (size > i)
315-
damage = pWeaponExt->ExtraWarheads_DamageOverrides[i];
316-
else if (size > 0)
317-
damage = pWeaponExt->ExtraWarheads_DamageOverrides[size - 1];
318-
319-
bool detonate = true;
320-
size = pWeaponExt->ExtraWarheads_DetonationChances.size();
321-
322-
if (size > i)
323-
detonate = pWeaponExt->ExtraWarheads_DetonationChances[i] >= ScenarioClass::Instance->Random.RandomDouble();
324-
else if (size > 0)
325-
detonate = pWeaponExt->ExtraWarheads_DetonationChances[size - 1] >= ScenarioClass::Instance->Random.RandomDouble();
326-
327-
bool isFull = true;
328-
size = pWeaponExt->ExtraWarheads_FullDetonation.size();
307+
pBulletExt->ApplyExtraWarheads(pWeaponExt->ExtraWarheads, pWeaponExt->ExtraWarheads_DamageOverrides, pWeaponExt->ExtraWarheads_DetonationChances, pWeaponExt->ExtraWarheads_FullDetonation, coords, pOwner);
308+
}
329309

330-
if (size > i)
331-
isFull = pWeaponExt->ExtraWarheads_FullDetonation[i];
332-
else if (size > 0)
333-
isFull = pWeaponExt->ExtraWarheads_FullDetonation[size - 1];
310+
if (pThis->Owner)
311+
{
312+
auto const pExt = TechnoExt::ExtMap.Find(pThis->Owner);
334313

335-
if (!detonate)
336-
continue;
314+
if (pExt->AE.HasExtraWarheads)
315+
{
316+
for (auto const& pAE : pExt->AttachedEffects)
317+
{
318+
auto const pType = pAE->GetType();
337319

338-
if (isFull)
339-
WarheadTypeExt::DetonateAt(pWH, *coords, pThis->Owner, damage, pOwner, pThis->Target);
340-
else
341-
WarheadTypeExt::ExtMap.Find(pWH)->DamageAreaWithTarget(*coords, damage, pThis->Owner, pWH, true, pOwner, abstract_cast<TechnoClass*>(pThis->Target));
320+
if (pType->ExtraWarheads.size() > 0)
321+
pBulletExt->ApplyExtraWarheads(pType->ExtraWarheads, pType->ExtraWarheads_DamageOverrides, pType->ExtraWarheads_DetonationChances, pType->ExtraWarheads_FullDetonation, coords, pOwner);
322+
}
342323
}
343324
}
344325

src/Ext/Techno/Body.Update.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
11691169
bool reflectsDamage = false;
11701170
bool hasOnFireDiscardables = false;
11711171
bool hasRestrictedArmorMultipliers = false;
1172+
bool hasCritModifiers = false;
1173+
bool hasExtraWarheads = false;
11721174

11731175
for (const auto& attachEffect : this->AttachedEffects)
11741176
{
@@ -1189,6 +1191,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
11891191
reflectsDamage |= type->ReflectDamage;
11901192
hasOnFireDiscardables |= (type->DiscardOn & DiscardCondition::Firing) != DiscardCondition::None;
11911193
hasRestrictedArmorMultipliers |= (type->ArmorMultiplier != 1.0 && (type->ArmorMultiplier_AllowWarheads.size() > 0 || type->ArmorMultiplier_DisallowWarheads.size() > 0));
1194+
hasCritModifiers |= (type->Crit_Multiplier != 1.0 || type->Crit_ExtraChance != 0.0);
1195+
hasExtraWarheads |= type->ExtraWarheads.size() > 0;
11921196
}
11931197

11941198
this->AE.FirepowerMultiplier = firepower;
@@ -1204,6 +1208,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
12041208
this->AE.ReflectDamage = reflectsDamage;
12051209
this->AE.HasOnFireDiscardables = hasOnFireDiscardables;
12061210
this->AE.HasRestrictedArmorMultipliers = hasRestrictedArmorMultipliers;
1211+
this->AE.HasCritModifiers = hasCritModifiers;
1212+
this->AE.HasExtraWarheads = hasExtraWarheads;
12071213

12081214
if (forceDecloak && pThis->CloakState == CloakState::Cloaked)
12091215
pThis->Uncloak(true);

src/Ext/WarheadType/Detonate.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,10 @@ double WarheadTypeExt::ExtData::GetCritChance(TechnoClass* pFirer) const
634634
return critChance;
635635

636636
auto const pExt = TechnoExt::ExtMap.Find(pFirer);
637+
638+
if (!pExt->AE.HasCritModifiers)
639+
return critChance;
640+
637641
double extraChance = 0.0;
638642

639643
for (auto& attachEffect : pExt->AttachedEffects)

src/New/Entity/AttachEffectClass.cpp

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,26 @@ AttachEffectClass::AttachEffectClass(AttachEffectTypeClass* pType, TechnoClass*
4646

4747
this->Duration = this->DurationOverride != 0 ? this->DurationOverride : this->Type->Duration;
4848

49-
if (this->Duration > 0)
49+
if (this->Type->Duration_ApplyVersus_Warhead && this->Duration > 0)
5050
{
51-
if (this->Type->Duration_ApplyVersus_Warhead)
51+
auto const pTechnoExt = TechnoExt::ExtMap.Find(pTechno);
52+
auto pArmor = pTechno->GetTechnoType()->Armor;
53+
54+
if (auto const pShieldData = pTechnoExt->Shield.get())
5255
{
53-
auto const pArmor = pTechno->Shield && pTechno->Shield->IsActive() ? pTechno->Shield->GetArmor() : pTechno->GetTechnoType()->Armor;
54-
this->Duration = Math::max(static_cast<int>(this->Duration * GeneralUtils::GetWarheadVersusArmor(this->Type->Duration_ApplyVersus_Warhead, pArmor), 0));
56+
if (pShieldData->IsActive())
57+
pArmor = pShieldData->GetArmorType();
5558
}
5659

57-
if (this->Type->Duration_ApplyFirepowerMult && pInvoker)
58-
this->Duration = Math::max(static_cast<int>(this->Duration * pInvoker->FirepowerMultiplier * TechnoExt::ExtMap.Find(pInvoker)->AE.FirepowerMultiplier), 0);
59-
60-
if (this->Type->Duration_ApplyArmorMultOnTarget) // count its own ArmorMultiplier as well
61-
this->Duration = Math::max(static_cast<int>(this->Duration / pTechno->ArmorMultiplier / TechnoExt::ExtMap.Find(pTechno)->AE.ArmorMultiplier / this->Type->ArmorMultiplier), 0);
60+
this->Duration = Math::max(static_cast<int>(this->Duration * GeneralUtils::GetWarheadVersusArmor(this->Type->Duration_ApplyVersus_Warhead, pArmor)), 0);
6261
}
6362

63+
if (this->Type->Duration_ApplyFirepowerMult && this->Duration > 0 && pInvoker)
64+
this->Duration = Math::max(static_cast<int>(this->Duration * pInvoker->FirepowerMultiplier * TechnoExt::ExtMap.Find(pInvoker)->AE.FirepowerMultiplier), 0);
65+
66+
if (this->Type->Duration_ApplyArmorMultOnTarget && this->Duration > 0) // count its own ArmorMultiplier as well
67+
this->Duration = Math::max(static_cast<int>(this->Duration / pTechno->ArmorMultiplier / TechnoExt::ExtMap.Find(pTechno)->AE.ArmorMultiplier / this->Type->ArmorMultiplier), 0);
68+
6469
AttachEffectClass::Array.emplace_back(this);
6570
}
6671

@@ -399,8 +404,16 @@ void AttachEffectClass::RefreshDuration(int durationOverride)
399404

400405
if (this->Type->Duration_ApplyVersus_Warhead)
401406
{
402-
auto const pArmor = this->Techno->Shield && this->Techno->Shield->IsActive() ? this->Techno->Shield->GetArmor() : this->Techno->GetTechnoType()->Armor;
403-
this->Duration = Math::max(static_cast<int>(this->Duration * GeneralUtils::GetWarheadVersusArmor(this->Type->Duration_ApplyVersus_Warhead, pArmor), 0));
407+
auto const pTechnoExt = TechnoExt::ExtMap.Find(this->Techno);
408+
auto pArmor = this->Techno->GetTechnoType()->Armor;
409+
410+
if (auto const pShieldData = pTechnoExt->Shield.get())
411+
{
412+
if (pShieldData->IsActive())
413+
pArmor = pShieldData->GetArmorType();
414+
}
415+
416+
this->Duration = Math::max(static_cast<int>(this->Duration * GeneralUtils::GetWarheadVersusArmor(this->Type->Duration_ApplyVersus_Warhead, pArmor)), 0);
404417
}
405418

406419
if (this->Type->Duration_ApplyFirepowerMult && this->Duration > 0 && this->Invoker)

src/New/Entity/AttachEffectClass.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ struct AttachEffectTechnoProperties
9696
bool ReflectDamage;
9797
bool HasOnFireDiscardables;
9898
bool HasRestrictedArmorMultipliers;
99+
bool HasCritModifiers;
100+
bool HasExtraWarheads;
99101

100102
AttachEffectTechnoProperties() :
101103
FirepowerMultiplier { 1.0 }

src/New/Type/AttachEffectTypeClass.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ void AttachEffectTypeClass::LoadFromINI(CCINIClass* pINI)
124124
this->ExpireWeapon_TriggerOn.Read(exINI, pSection, "ExpireWeapon.TriggerOn");
125125
this->ExpireWeapon_CumulativeOnlyOnce.Read(exINI, pSection, "ExpireWeapon.CumulativeOnlyOnce");
126126

127+
this->ExtraWarheads.Read(exINI, pSection, "ExtraWarheads");
128+
this->ExtraWarheads_DamageOverrides.Read(exINI, pSection, "ExtraWarheads.DamageOverrides");
129+
this->ExtraWarheads_DetonationChances.Read(exINI, pSection, "ExtraWarheads.DetonationChances");
130+
this->ExtraWarheads_FullDetonation.Read(exINI, pSection, "ExtraWarheads.FullDetonation");
131+
127132
this->Tint_Color.Read(exINI, pSection, "Tint.Color");
128133
this->Tint_Intensity.Read(exINI, pSection, "Tint.Intensity");
129134
this->Tint_VisibleToHouses.Read(exINI, pSection, "Tint.VisibleToHouses");
@@ -198,6 +203,10 @@ void AttachEffectTypeClass::Serialize(T& Stm)
198203
.Process(this->ExpireWeapon)
199204
.Process(this->ExpireWeapon_TriggerOn)
200205
.Process(this->ExpireWeapon_CumulativeOnlyOnce)
206+
.Process(this->ExtraWarheads)
207+
.Process(this->ExtraWarheads_DamageOverrides)
208+
.Process(this->ExtraWarheads_DetonationChances)
209+
.Process(this->ExtraWarheads_FullDetonation)
201210
.Process(this->Tint_Color)
202211
.Process(this->Tint_Intensity)
203212
.Process(this->Tint_VisibleToHouses)

src/New/Type/AttachEffectTypeClass.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ class AttachEffectTypeClass final : public Enumerable<AttachEffectTypeClass>
6666
Valueable<WeaponTypeClass*> ExpireWeapon;
6767
Valueable<ExpireWeaponCondition> ExpireWeapon_TriggerOn;
6868
Valueable<bool> ExpireWeapon_CumulativeOnlyOnce;
69+
ValueableVector<WarheadTypeClass*> ExtraWarheads;
70+
ValueableVector<int> ExtraWarheads_DamageOverrides;
71+
ValueableVector<double> ExtraWarheads_DetonationChances;
72+
ValueableVector<bool> ExtraWarheads_FullDetonation;
6973
Nullable<ColorStruct> Tint_Color;
7074
Valueable<double> Tint_Intensity;
7175
Valueable<AffectedHouse> Tint_VisibleToHouses;
@@ -127,6 +131,10 @@ class AttachEffectTypeClass final : public Enumerable<AttachEffectTypeClass>
127131
, ExpireWeapon {}
128132
, ExpireWeapon_TriggerOn { ExpireWeaponCondition::Expire }
129133
, ExpireWeapon_CumulativeOnlyOnce { false }
134+
, ExtraWarheads {}
135+
, ExtraWarheads_DamageOverrides {}
136+
, ExtraWarheads_DetonationChances {}
137+
, ExtraWarheads_FullDetonation {}
130138
, Tint_Color {}
131139
, Tint_Intensity { 0.0 }
132140
, Tint_VisibleToHouses { AffectedHouse::All }

0 commit comments

Comments
 (0)