Skip to content

Commit cf714e5

Browse files
committed
AuxWeapon
1 parent 7355c24 commit cf714e5

File tree

13 files changed

+265
-62
lines changed

13 files changed

+265
-62
lines changed

docs/New-or-Enhanced-Logics.md

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ This page describes all the engine features that are either new and introduced b
4141
- `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.
4242
- `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.
4343
- Note that the listed Warheads must be listed in `[Warheads]` for them to work.
44-
- `FeedbackWeapon` can specify an auxiliary weapon to be fired on the firer itself when a weapon is fired.
44+
- You can now specify an auxiliary weapon to be fired when a weapon is fired.
45+
- `FireInTransport` setting of the auxiliary weapons are respected to determine if it can be fired when the original weapon is fired from inside `OpenTopped=true` transport. If auxiliary weapons are fired, it is fired on the transport. `OpenToppedDamageMultiplier` is not applied on auxiliary weapons.
46+
- `AuxWeapon` is fired at the original target, or another nearby target if `AuxWeapon.Retarget` set to true.
47+
- `AuxWeapon.Offset` defines the relative position to the firer that the auxiliary weapon will be fired from. `AuxWeapon.FireOnTurret` defines if the FLH is relative to the turret rather than the body.
48+
- If `AuxWeapon.AllowZeroDamage` set to true, the auxiliary weapon will be fired even if its damage on the set target is 0.
49+
- `AuxWeapon.ApplyFirepowerMult` determines whether or not the auxiliary weapon's damage should multiply the firer's firepower multipliers.
50+
- `AuxWeapon.Retarget.AroundFirer` determines whether the original target or the firer will be the center of the retargeting. `AuxWeapon.Retarget.Range` determines the radius of the retargeting, default to the auxiliary weapon's `Range` if the center is the firer, and 0 if the center is the original target.
51+
- `AuxWeapon.Retarget.Accuracy` defines the probability that the auxiliary weapon is fired to the original target.
52+
- `FeedbackWeapon` is fired at the firer.
4553
- `FireInTransport` setting of the feedback weapon is respected to determine if it can be fired when the original weapon is fired from inside `OpenTopped=true` transport. If feedback weapon is fired, it is fired on the transport. `OpenToppedDamageMultiplier` is not applied on feedback weapons.
4654
- `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.
4755
- `Tint.VisibleToHouses` can be used to control which houses can see the tint effect.
@@ -124,6 +132,15 @@ ExtraWarheads= ; List of WarheadTypes
124132
ExtraWarheads.DamageOverrides= ; List of integers
125133
ExtraWarheads.DetonationChances= ; List of floating-point values (percentage or absolute)
126134
ExtraWarheads.FullDetonation= ; List of booleans
135+
AuxWeapon= ; WeaponType
136+
AuxWeapon.Offset=0,0,0 ; integer - Forward,Lateral,Height
137+
AuxWeapon.FireOnTurret=false ; boolean
138+
AuxWeapon.AllowZeroDamage=true ; boolean
139+
AuxWeapon.ApplyFirepowerMult=false ; boolean
140+
AuxWeapon.Retarget=false ; boolean
141+
AuxWeapon.Retarget.Range= ; floating point value
142+
AuxWeapon.Retarget.Accuracy= ; floating point value, percents or absolute (0.0-1.0)
143+
AuxWeapon.Retarget.AroundFirer=false ; boolean
127144
FeedbackWeapon= ; WeaponType
128145
Tint.Color= ; integer - R,G,B
129146
Tint.Intensity= ; floating point value
@@ -966,11 +983,13 @@ SubjectToGround=false ; boolean
966983
### Return weapon
967984

968985
- It is now possible to make another weapon & projectile go off from a detonated projectile (in somewhat similar manner to `AirburstWeapon` or `ShrapnelWeapon`) straight back to the firer by setting `ReturnWeapon`. If the firer perishes before the initial projectile detonates, `ReturnWeapon` is not fired off.
986+
- `ReturnWeapon.ApplyFirepowerMult` determines whether or not the auxiliary weapon's damage should multiply the firer's firepower multipliers.
969987

970988
In `rulesmd.ini`:
971989
```ini
972-
[SOMEPROJECTILE] ; Projectile
973-
ReturnWeapon= ; WeaponType
990+
[SOMEPROJECTILE] ; Projectile
991+
ReturnWeapon= ; WeaponType
992+
ReturnWeapon.ApplyFirepowerMult=false ; boolean
974993
```
975994

976995
```{note}
@@ -2241,18 +2260,34 @@ ExtraWarheads.DetonationChances= ; List of floating-point values (percentage or
22412260
ExtraWarheads.FullDetonation= ; List of booleans
22422261
```
22432262

2244-
### Feedback weapon
2263+
### Auxiliary weapon
22452264

22462265
![image](_static/images/feedbackweapon.gif)
22472266
*`FeedbackWeapon` used to apply healing aura upon firing a weapon in [Project Phantom](https://www.moddb.com/mods/project-phantom)*
22482267

2249-
- You can now specify an auxiliary weapon to be fired on the firer itself when a weapon is fired.
2250-
- `FireInTransport` setting of the feedback weapon is respected to determine if it can be fired when the original weapon is fired from inside `OpenTopped=true` transport. If feedback weapon is fired, it is fired on the transport. `OpenToppedDamageMultiplier` is not applied on feedback weapons.
2251-
2252-
In `rulesmd.ini`:
2253-
```ini
2254-
[SOMEWEAPON] ; WeaponType
2255-
FeedbackWeapon= ; WeaponType
2268+
- You can now specify an auxiliary weapon to be fired when a weapon is fired.
2269+
- `FireInTransport` setting of the auxiliary weapons are respected to determine if it can be fired when the original weapon is fired from inside `OpenTopped=true` transport. If auxiliary weapons are fired, it is fired on the transport. `OpenToppedDamageMultiplier` is not applied on auxiliary weapons.
2270+
- `AuxWeapon` is fired at the original target, or another nearby target if `AuxWeapon.Retarget` set to true.
2271+
- `AuxWeapon.Offset` defines the relative position to the firer that the auxiliary weapon will be fired from. `AuxWeapon.FireOnTurret` defines if the FLH is relative to the turret rather than the body.
2272+
- If `AuxWeapon.AllowZeroDamage` set to true, the auxiliary weapon will be fired even if its damage on the set target is 0.
2273+
- `AuxWeapon.ApplyFirepowerMult` determines whether or not the auxiliary weapon's damage should multiply the firer's firepower multipliers.
2274+
- `AuxWeapon.Retarget.AroundFirer` determines whether the original target or the firer will be the center of the retargeting. `AuxWeapon.Retarget.Range` determines the radius of the retargeting, default to the auxiliary weapon's `Range` if the center is the firer, and 0 if the center is the original target.
2275+
- `AuxWeapon.Retarget.Accuracy` defines the probability that the auxiliary weapon is fired to the original target.
2276+
- `FeedbackWeapon` is fired at the firer.
2277+
2278+
In `rulesmd.ini`:
2279+
```ini
2280+
[SOMEWEAPON] ; WeaponType
2281+
AuxWeapon= ; WeaponType
2282+
AuxWeapon.Offset=0,0,0 ; integer - Forward,Lateral,Height
2283+
AuxWeapon.FireOnTurret=false ; boolean
2284+
AuxWeapon.AllowZeroDamage=true ; boolean
2285+
AuxWeapon.ApplyFirepowerMult=false ; boolean
2286+
AuxWeapon.Retarget=false ; boolean
2287+
AuxWeapon.Retarget.Range= ; floating point value
2288+
AuxWeapon.Retarget.Accuracy= ; floating point value, percents or absolute (0.0-1.0)
2289+
AuxWeapon.Retarget.AroundFirer=false ; boolean
2290+
FeedbackWeapon= ; WeaponType
22562291
```
22572292

22582293
### Keep Range After Firing

src/Ext/Bullet/Hooks.DetonateLogics.cpp

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,13 @@ DEFINE_HOOK(0x469AA4, BulletClass_Logics_Extras, 0x5)
330330

331331
if (auto const pWeapon = pTypeExt->ReturnWeapon)
332332
{
333+
auto damage = pWeapon->Damage;
334+
335+
if (pTypeExt->ReturnWeapon_ApplyFirepowerMult)
336+
damage = static_cast<int>(damage * pThis->Owner->FirepowerMultiplier * TechnoExt::ExtMap.Find(pThis->Owner)->AE.FirepowerMultiplier);
337+
333338
if (BulletClass* pBullet = pWeapon->Projectile->CreateBullet(pThis->Owner, pThis->Owner,
334-
pWeapon->Damage, pWeapon->Warhead, pWeapon->Speed, pWeapon->Bright))
339+
damage, pWeapon->Warhead, pWeapon->Speed, pWeapon->Bright))
335340
{
336341
pBullet->WeaponType = pWeapon;
337342
pBullet->MoveTo(pThis->Location, BulletVelocity::Empty);
@@ -347,38 +352,6 @@ DEFINE_HOOK(0x469AA4, BulletClass_Logics_Extras, 0x5)
347352

348353
#pragma region Airburst
349354

350-
static bool IsAllowedSplitsTarget(TechnoClass* pSource, HouseClass* pOwner, WeaponTypeClass* pWeapon, TechnoClass* pTarget, bool useWeaponTargeting)
351-
{
352-
auto const pWH = pWeapon->Warhead;
353-
354-
if (useWeaponTargeting)
355-
{
356-
auto const pType = pTarget->GetTechnoType();
357-
358-
if (!pType->LegalTarget || GeneralUtils::GetWarheadVersusArmor(pWH, pType->Armor) == 0.0)
359-
return false;
360-
361-
auto const pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon);
362-
363-
if (!EnumFunctions::CanTargetHouse(pWeaponExt->CanTargetHouses, pOwner, pTarget->Owner)
364-
|| !EnumFunctions::IsCellEligible(pTarget->GetCell(), pWeaponExt->CanTarget, true, true)
365-
|| !EnumFunctions::IsTechnoEligible(pTarget, pWeaponExt->CanTarget))
366-
{
367-
return false;
368-
}
369-
370-
if (!pWeaponExt->HasRequiredAttachedEffects(pTarget, pSource))
371-
return false;
372-
}
373-
else
374-
{
375-
if (!WarheadTypeExt::ExtMap.Find(pWH)->CanTargetHouse(pOwner, pTarget))
376-
return false;
377-
}
378-
379-
return true;
380-
}
381-
382355
// Disable Ares' Airburst implementation.
383356
DEFINE_PATCH(0x469EBA, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90);
384357

@@ -494,7 +467,7 @@ DEFINE_HOOK(0x469EC0, BulletClass_Logics_AirburstWeapon, 0x6)
494467

495468
if (coordsTarget.DistanceFrom(coords) < pTypeExt->Splits_TargetingDistance.Get()
496469
&& (pType->AA || !pTechno->IsInAir())
497-
&& IsAllowedSplitsTarget(pSource, pOwner, pWeapon, pTechno, pTypeExt->Splits_UseWeaponTargeting))
470+
&& TechnoExt::IsAllowedSplitsTarget(pSource, pOwner, pWeapon, pTechno, pTypeExt->Splits_UseWeaponTargeting))
498471
{
499472
targets.AddItem(pTechno);
500473
}

src/Ext/BulletType/Body.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void BulletTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
5252
this->AAOnly.Read(exINI, pSection, "AAOnly");
5353
this->Arcing_AllowElevationInaccuracy.Read(exINI, pSection, "Arcing.AllowElevationInaccuracy");
5454
this->ReturnWeapon.Read<true>(exINI, pSection, "ReturnWeapon");
55+
this->ReturnWeapon_ApplyFirepowerMult.Read(exINI, pSection, "ReturnWeapon.ApplyFirepowerMult");
5556
this->SubjectToGround.Read(exINI, pSection, "SubjectToGround");
5657

5758
this->Splits.Read(exINI, pSection, "Splits");
@@ -144,6 +145,7 @@ void BulletTypeExt::ExtData::Serialize(T& Stm)
144145
.Process(this->AAOnly)
145146
.Process(this->Arcing_AllowElevationInaccuracy)
146147
.Process(this->ReturnWeapon)
148+
.Process(this->ReturnWeapon_ApplyFirepowerMult)
147149
.Process(this->SubjectToGround)
148150
.Process(this->Splits)
149151
.Process(this->AirburstSpread)

src/Ext/BulletType/Body.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class BulletTypeExt
4444
Valueable<bool> AAOnly;
4545
Valueable<bool> Arcing_AllowElevationInaccuracy;
4646
Valueable<WeaponTypeClass*> ReturnWeapon;
47+
Valueable<bool> ReturnWeapon_ApplyFirepowerMult;
4748

4849
Valueable<bool> SubjectToGround;
4950

@@ -92,6 +93,7 @@ class BulletTypeExt
9293
, AAOnly { false }
9394
, Arcing_AllowElevationInaccuracy { true }
9495
, ReturnWeapon {}
96+
, ReturnWeapon_ApplyFirepowerMult { false }
9597
, SubjectToGround { false }
9698
, Splits { false }
9799
, AirburstSpread { 1.5 }

src/Ext/Techno/Body.Update.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
11711171
bool hasRestrictedArmorMultipliers = false;
11721172
bool hasCritModifiers = false;
11731173
bool hasExtraWarheads = false;
1174-
bool hasFeedbackWeapon = false;
1174+
bool hasFeedbackOrAuxWeapon = false;
11751175

11761176
for (const auto& attachEffect : this->AttachedEffects)
11771177
{
@@ -1194,7 +1194,7 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
11941194
hasRestrictedArmorMultipliers |= (type->ArmorMultiplier != 1.0 && (type->ArmorMultiplier_AllowWarheads.size() > 0 || type->ArmorMultiplier_DisallowWarheads.size() > 0));
11951195
hasCritModifiers |= (type->Crit_Multiplier != 1.0 || type->Crit_ExtraChance != 0.0);
11961196
hasExtraWarheads |= type->ExtraWarheads.size() > 0;
1197-
hasFeedbackWeapon |= type->FeedbackWeapon != nullptr;
1197+
hasFeedbackOrAuxWeapon |= type->FeedbackWeapon != nullptr || type->AuxWeapon != nullptr;
11981198
}
11991199

12001200
this->AE.FirepowerMultiplier = firepower;
@@ -1212,7 +1212,7 @@ void TechnoExt::ExtData::RecalculateStatMultipliers()
12121212
this->AE.HasRestrictedArmorMultipliers = hasRestrictedArmorMultipliers;
12131213
this->AE.HasCritModifiers = hasCritModifiers;
12141214
this->AE.HasExtraWarheads = hasExtraWarheads;
1215-
this->AE.HasFeedbackWeapon = hasFeedbackWeapon;
1215+
this->AE.HasFeedbackOrAuxWeapon = hasFeedbackOrAuxWeapon;
12161216

12171217
if (forceDecloak && pThis->CloakState == CloakState::Cloaked)
12181218
pThis->Uncloak(true);

src/Ext/Techno/Body.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class TechnoExt
146146
int GetAttachedEffectCumulativeCount(AttachEffectTypeClass* pAttachEffectType, bool ignoreSameSource = false, TechnoClass* pInvoker = nullptr, AbstractClass* pSource = nullptr) const;
147147
void ApplyMindControlRangeLimit();
148148
int ApplyForceWeaponInRange(TechnoClass* pTarget);
149+
void ApplyAuxWeapon(WeaponTypeClass* pAuxWeapon, AbstractClass* pTarget, CoordStruct offset, double accuracy, bool onTurret, bool retarget, bool aroundFirer, bool zeroDamage, bool firepowerMult);
149150

150151
UnitTypeClass* GetUnitTypeExtra() const;
151152

@@ -222,4 +223,5 @@ class TechnoExt
222223
static int GetWeaponIndexAgainstWall(TechnoClass* pThis, OverlayTypeClass* pWallOverlayType);
223224
static void ApplyKillWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH);
224225
static void ApplyRevengeWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH);
226+
static bool IsAllowedSplitsTarget(TechnoClass* pSource, HouseClass* pOwner, WeaponTypeClass* pWeapon, TechnoClass* pTarget, bool useWeaponTargeting = true, bool allowZeroDamage = false);
225227
};

src/Ext/Techno/Hooks.Firing.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -574,31 +574,40 @@ DEFINE_HOOK(0x6FF43F, TechnoClass_FireAt_FeedbackWeapon, 0x6)
574574
{
575575
GET(TechnoClass*, pThis, ESI);
576576
GET(WeaponTypeClass*, pWeapon, EBX);
577+
GET_BASE(AbstractClass*, pTarget, 0x8);
578+
579+
auto const pExt = TechnoExt::ExtMap.Find(pThis);
577580

578581
if (auto const pWeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon))
579582
{
580583
if (auto const pWeaponFeedback = pWeaponExt->FeedbackWeapon)
581584
{
582-
if (pThis->InOpenToppedTransport && !pWeaponFeedback->FireInTransport)
583-
return 0;
584-
585-
WeaponTypeExt::DetonateAt(pWeaponFeedback, pThis, pThis);
585+
if (!pThis->InOpenToppedTransport || pWeaponFeedback->FireInTransport)
586+
WeaponTypeExt::DetonateAt(pWeaponFeedback, pThis, pThis);
586587
}
587-
}
588588

589-
auto const pExt = TechnoExt::ExtMap.Find(pThis);
589+
if (auto const pAuxWeapon = pWeaponExt->AuxWeapon)
590+
pExt->ApplyAuxWeapon(pThis, pAuxWeapon, pTarget, pWeaponExt->AuxWeapon_Offset, pWeaponExt->AuxWeapon_Retarget_Accuracy, pWeaponExt->AuxWeapon_FireOnTurret,
591+
pWeaponExt->AuxWeapon_Retarget, pWeaponExt->AuxWeapon_Retarget_AroundFirer, pWeaponExt->AuxWeapon_AllowZeroDamage, pWeaponExt->AuxWeapon_ApplyFirepowerMult);
592+
}
590593

591-
if (pExt->AE.HasFeedbackWeapon)
594+
if (pExt->AE.HasFeedbackOrAuxWeapon)
592595
{
593596
for (auto const& pAE : pExt->AttachedEffects)
594597
{
595-
if (auto const pWeaponFeedback = pAE->GetType()->FeedbackWeapon)
598+
auto const pAEType = pAE->GetType();
599+
600+
if (auto const pWeaponFeedback = pAEType->FeedbackWeapon)
596601
{
597602
if (pThis->InOpenToppedTransport && !pWeaponFeedback->FireInTransport)
598-
return 0;
603+
continue;
599604

600605
WeaponTypeExt::DetonateAt(pWeaponFeedback, pThis, pThis);
601606
}
607+
608+
if (auto const pAuxWeapon = pAEType->AuxWeapon)
609+
pExt->ApplyAuxWeapon(pAuxWeapon, pTarget, pAEType->AuxWeapon_Offset, pAEType->AuxWeapon_Retarget_Accuracy, pAEType->AuxWeapon_FireOnTurret,
610+
pAEType->AuxWeapon_Retarget, pAEType->AuxWeapon_Retarget_AroundFirer, pAEType->AuxWeapon_AllowZeroDamage, pAEType->AuxWeapon_ApplyFirepowerMult);
602611
}
603612
}
604613

0 commit comments

Comments
 (0)