Skip to content

Commit 67c83bd

Browse files
authored
Forcing specific weapon by range (#1407)
- `ForceWeapon.InRange` forces specified a list of weapons to be used once the target is within their `Range`. The first weapon in the listed order satisfied will be selected. Can be applied to both ground and air target if `ForceAAWeapon.InRange` is not set. - `ForceAAWeapon.InRange` does the same thing but only for air target. Taking priority to `ForceWeapon.InRange`, which means that it can only be applied to ground target when they're both set. - `Force(AA)Weapon.InRange.Overrides` overrides the range when decides which weapon to use. Value from position matching the position from `Force(AA)Weapon.InRange` is used if found, or the weapon's own `Range` if not found or set to a value below 0. Specifically, if a position has `Force(AA)Weapon.InRange` set to -1 and `Force(AA)Weapon.InRange.Overrides` set to a positive value, it'll use default weapon selection logic once satisfied. - If `Force(AA)Weapon.InRange.ApplyRangeModifiers` is set to true, any applicable weapon range modifiers from the firer are applied to the decision range. In `rulesmd.ini`: ```ini [SOMETECHNO] ; TechnoType ForceWeapon.InRange= ; list of integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable ForceWeapon.InRange.Overrides= ; list of floating point value ForceWeapon.InRange.ApplyRangeModifiers=false ; boolean ForceAAWeapon.InRange= ; list of integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable ForceAAWeapon.InRange.Overrides= ; list of floating point value ForceAAWeapon.InRange.ApplyRangeModifiers=false ; boolean ``` An example: ```ini [SOMETECHNO] ForceWeapon.InRange=0,1,0,-1,1 ForceWeapon.InRange.Overrides=1,2,3,4,0 ``` when the target distance is less than 1: use primary. when the target distance is between 1 and 2: use secondary. when the target distance is between 2 and 3: use primary. when the target distance is between 3 and 4: use default weapon selection rule. when the target distance is between 4 and secondary's range: use secondary. when the target distance is greater than secondary's range: use default weapon selection rule. This pattern can natually support WeaponX as well.
1 parent c86b162 commit 67c83bd

File tree

8 files changed

+119
-7
lines changed

8 files changed

+119
-7
lines changed

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ This page lists all the individual contributions to the project by their author.
444444
- Fix `DefaultDisguise` showing wrong house colors for different players
445445
- Fire weapon when kill
446446
- Promotion animation deglobalization
447+
- Forcing specific weapon by range
447448
- **NaotoYuuki** - Vertical & meteor trajectory projectile prototypes
448449
- **handama** - AI script action to `16005 Jump Back To Previous Script`
449450
- **TaranDahl (航味麻酱)**:

docs/New-or-Enhanced-Logics.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,14 +1398,24 @@ FLHKEY.BurstN= ; integer - Forward,Lateral,Height. FLHKey refers to weapon-spec
13981398
- `ForceWeapon.Cloaked` forces specified weapon to be used against any cloaked targets.
13991399
- `ForceWeapon.Disguised` forces specified weapon to be used against any disguised targets.
14001400
- `ForceWeapon.UnderEMP` forces specified weapon to be used if the target is under EMP effect.
1401+
- `ForceWeapon.InRange` forces specified a list of weapons to be used once the target is within their `Range`. The first weapon in the listed order satisfied will be selected. Can be applied to both ground and air target if `ForceAAWeapon.InRange` is not set.
1402+
- `ForceAAWeapon.InRange` does the same thing but only for air target. Taking priority to `ForceWeapon.InRange`, which means that it can only be applied to ground target when they're both set.
1403+
- `Force(AA)Weapon.InRange.Overrides` overrides the range when decides which weapon to use. Value from position matching the position from `Force(AA)Weapon.InRange` is used if found, or the weapon's own `Range` if not found or set to a value below 0. Specifically, if a position has `Force(AA)Weapon.InRange` set to -1 and `Force(AA)Weapon.InRange.Overrides` set to a positive value, it'll use default weapon selection logic once satisfied.
1404+
- If `Force(AA)Weapon.InRange.ApplyRangeModifiers` is set to true, any applicable weapon range modifiers from the firer are applied to the decision range.
14011405

14021406
In `rulesmd.ini`:
14031407
```ini
1404-
[SOMETECHNO] ; TechnoType
1405-
ForceWeapon.Naval.Decloaked=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1406-
ForceWeapon.Cloaked=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1407-
ForceWeapon.Disguised=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1408-
ForceWeapon.UnderEMP=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1408+
[SOMETECHNO] ; TechnoType
1409+
ForceWeapon.Naval.Decloaked=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1410+
ForceWeapon.Cloaked=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1411+
ForceWeapon.Disguised=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1412+
ForceWeapon.UnderEMP=-1 ; integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1413+
ForceWeapon.InRange= ; list of integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1414+
ForceWeapon.InRange.Overrides= ; list of floating point value
1415+
ForceWeapon.InRange.ApplyRangeModifiers=false ; boolean
1416+
ForceAAWeapon.InRange= ; list of integer. 0 for primary weapon, 1 for secondary weapon, -1 to disable
1417+
ForceAAWeapon.InRange.Overrides= ; list of floating point value
1418+
ForceAAWeapon.InRange.ApplyRangeModifiers=false ; boolean
14091419
```
14101420

14111421
### Initial spawns number

docs/Whats-New.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ New:
357357
- [Customize overpower logic](Fixed-or-Improved-Logics.md#customize-overpower-logic) (by NetsuNegi)
358358
- Promotion animation deglobalization (by Ollerus)
359359
- Enhanced reveal & gap warhead (by NetsuNegi)
360+
- Forcing specific weapon by range (by Ollerus)
360361
361362
Vanilla fixes:
362363
- Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl)

src/Ext/Techno/Body.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class TechnoExt
144144
bool HasAttachedEffects(std::vector<AttachEffectTypeClass*> attachEffectTypes, bool requireAll, bool ignoreSameSource, TechnoClass* pInvoker, AbstractClass* pSource, std::vector<int> const* minCounts, std::vector<int> const* maxCounts) const;
145145
int GetAttachedEffectCumulativeCount(AttachEffectTypeClass* pAttachEffectType, bool ignoreSameSource = false, TechnoClass* pInvoker = nullptr, AbstractClass* pSource = nullptr) const;
146146
void ApplyMindControlRangeLimit();
147+
int ApplyForceWeaponInRange();
147148

148149
UnitTypeClass* GetUnitTypeExtra() const;
149150

src/Ext/Techno/Hooks.Firing.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
#include <Utilities/EnumFunctions.h>
1212

1313
#pragma region TechnoClass_SelectWeapon
14+
15+
namespace ForceWeaponInRangeTemp
16+
{
17+
bool SelectWeaponByRange = false;
18+
}
19+
1420
DEFINE_HOOK(0x6F3339, TechnoClass_WhatWeaponShouldIUse_Interceptor, 0x8)
1521
{
1622
enum { SkipGameCode = 0x6F3341, ReturnValue = 0x6F3406 };
@@ -75,16 +81,19 @@ DEFINE_HOOK(0x6F3428, TechnoClass_WhatWeaponShouldIUse_ForceWeapon, 0x6)
7581

7682
GET(TechnoClass*, pThis, ECX);
7783

78-
if (pThis && pThis->Target)
84+
if (ForceWeaponInRangeTemp::SelectWeaponByRange || !pThis)
85+
return 0;
86+
87+
if (pThis->Target)
7988
{
8089
auto const pTarget = abstract_cast<TechnoClass*>(pThis->Target);
8190

8291
if (!pTarget)
8392
return 0;
8493

8594
int forceWeaponIndex = -1;
86-
auto const pTargetType = pTarget->GetTechnoType();
8795
auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());
96+
auto const pTargetType = pTarget->GetTechnoType();
8897

8998
if (pTypeExt->ForceWeapon_Naval_Decloaked >= 0 &&
9099
pTargetType->Cloakable && pTargetType->Naval &&
@@ -107,6 +116,12 @@ DEFINE_HOOK(0x6F3428, TechnoClass_WhatWeaponShouldIUse_ForceWeapon, 0x6)
107116
{
108117
forceWeaponIndex = pTypeExt->ForceWeapon_UnderEMP;
109118
}
119+
else if (!pTypeExt->ForceWeapon_InRange.empty() || !pTypeExt->ForceAAWeapon_InRange.empty())
120+
{
121+
ForceWeaponInRangeTemp::SelectWeaponByRange = true;
122+
forceWeaponIndex = TechnoExt::ExtMap.Find(pThis)->ApplyForceWeaponInRange();
123+
ForceWeaponInRangeTemp::SelectWeaponByRange = false;
124+
}
110125

111126
if (forceWeaponIndex >= 0)
112127
{

src/Ext/Techno/WeaponHelpers.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,63 @@ void TechnoExt::ApplyRevengeWeapon(TechnoClass* pThis, TechnoClass* pSource, War
251251
WeaponTypeExt::DetonateAt(pType->RevengeWeapon, pSource, pThis);
252252
}
253253
}
254+
255+
int TechnoExt::ExtData::ApplyForceWeaponInRange()
256+
{
257+
int forceWeaponIndex = -1;
258+
auto const pThis = this->OwnerObject();
259+
auto const pTypeExt = this->TypeExtData;
260+
auto const pTarget = pThis->Target;
261+
262+
const bool useAASetting = !pTypeExt->ForceAAWeapon_InRange.empty() && pTarget->IsInAir();
263+
auto const& weaponIndices = useAASetting ? pTypeExt->ForceAAWeapon_InRange : pTypeExt->ForceWeapon_InRange;
264+
auto const& rangeOverrides = useAASetting ? pTypeExt->ForceAAWeapon_InRange_Overrides : pTypeExt->ForceWeapon_InRange_Overrides;
265+
const bool applyRangeModifiers = useAASetting ? pTypeExt->ForceAAWeapon_InRange_ApplyRangeModifiers : pTypeExt->ForceWeapon_InRange_ApplyRangeModifiers;
266+
267+
const int defaultWeaponIndex = pThis->SelectWeapon(pTarget);
268+
const int currentDistance = pThis->DistanceFrom(pTarget);
269+
auto const pDefaultWeapon = pThis->GetWeapon(defaultWeaponIndex)->WeaponType;
270+
271+
for (size_t i = 0; i < weaponIndices.size(); i++)
272+
{
273+
int range = 0;
274+
275+
// Value below 0 means Range won't be overriden
276+
if (i < rangeOverrides.size() && rangeOverrides[i] > 0)
277+
range = static_cast<int>(rangeOverrides[i] * Unsorted::LeptonsPerCell);
278+
279+
if (weaponIndices[i] >= 0)
280+
{
281+
if (range > 0 || applyRangeModifiers)
282+
{
283+
auto const pWeapon = weaponIndices[i] == defaultWeaponIndex ? pDefaultWeapon : pThis->GetWeapon(weaponIndices[i])->WeaponType;
284+
range = range > 0 ? range : pWeapon->Range;
285+
286+
if (applyRangeModifiers)
287+
range = WeaponTypeExt::GetRangeWithModifiers(pWeapon, pThis, range);
288+
}
289+
290+
if (currentDistance <= range)
291+
{
292+
forceWeaponIndex = weaponIndices[i];
293+
break;
294+
}
295+
}
296+
else
297+
{
298+
if (range > 0 || applyRangeModifiers)
299+
{
300+
range = range > 0 ? range : pDefaultWeapon->Range;
301+
302+
if (applyRangeModifiers)
303+
range = WeaponTypeExt::GetRangeWithModifiers(pDefaultWeapon, pThis, range);
304+
}
305+
306+
// Don't force weapon if range satisfied
307+
if (currentDistance <= range)
308+
break;
309+
}
310+
}
311+
312+
return forceWeaponIndex;
313+
}

src/Ext/TechnoType/Body.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,12 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
391391
this->ForceWeapon_Cloaked.Read(exINI, pSection, "ForceWeapon.Cloaked");
392392
this->ForceWeapon_Disguised.Read(exINI, pSection, "ForceWeapon.Disguised");
393393
this->ForceWeapon_UnderEMP.Read(exINI, pSection, "ForceWeapon.UnderEMP");
394+
this->ForceWeapon_InRange.Read(exINI, pSection, "ForceWeapon.InRange");
395+
this->ForceWeapon_InRange_Overrides.Read(exINI, pSection, "ForceWeapon.InRange.Overrides");
396+
this->ForceWeapon_InRange_ApplyRangeModifiers.Read(exINI, pSection, "ForceWeapon.InRange.ApplyRangeModifiers");
397+
this->ForceAAWeapon_InRange.Read(exINI, pSection, "ForceAAWeapon.InRange");
398+
this->ForceAAWeapon_InRange_Overrides.Read(exINI, pSection, "ForceAAWeapon.InRange.Overrides");
399+
this->ForceAAWeapon_InRange_ApplyRangeModifiers.Read(exINI, pSection, "ForceAAWeapon.InRange.ApplyRangeModifiers");
394400
this->Ammo_Shared.Read(exINI, pSection, "Ammo.Shared");
395401
this->Ammo_Shared_Group.Read(exINI, pSection, "Ammo.Shared.Group");
396402
this->SelfHealGainType.Read(exINI, pSection, "SelfHealGainType");
@@ -805,6 +811,12 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
805811
.Process(this->ForceWeapon_Cloaked)
806812
.Process(this->ForceWeapon_Disguised)
807813
.Process(this->ForceWeapon_UnderEMP)
814+
.Process(this->ForceWeapon_InRange)
815+
.Process(this->ForceWeapon_InRange_Overrides)
816+
.Process(this->ForceWeapon_InRange_ApplyRangeModifiers)
817+
.Process(this->ForceAAWeapon_InRange)
818+
.Process(this->ForceAAWeapon_InRange_Overrides)
819+
.Process(this->ForceAAWeapon_InRange_ApplyRangeModifiers)
808820
.Process(this->Ammo_Shared)
809821
.Process(this->Ammo_Shared_Group)
810822
.Process(this->SelfHealGainType)

src/Ext/TechnoType/Body.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ class TechnoTypeExt
159159
Valueable<int> ForceWeapon_Cloaked;
160160
Valueable<int> ForceWeapon_Disguised;
161161
Valueable<int> ForceWeapon_UnderEMP;
162+
ValueableVector<int> ForceWeapon_InRange;
163+
ValueableVector<double> ForceWeapon_InRange_Overrides;
164+
Valueable<bool> ForceWeapon_InRange_ApplyRangeModifiers;
165+
ValueableVector<int> ForceAAWeapon_InRange;
166+
ValueableVector<double> ForceAAWeapon_InRange_Overrides;
167+
Valueable<bool> ForceAAWeapon_InRange_ApplyRangeModifiers;
162168

163169
Valueable<bool> Ammo_Shared;
164170
Valueable<int> Ammo_Shared_Group;
@@ -432,6 +438,12 @@ class TechnoTypeExt
432438
, ForceWeapon_Cloaked { -1 }
433439
, ForceWeapon_Disguised { -1 }
434440
, ForceWeapon_UnderEMP { -1 }
441+
, ForceWeapon_InRange {}
442+
, ForceWeapon_InRange_Overrides {}
443+
, ForceWeapon_InRange_ApplyRangeModifiers { false }
444+
, ForceAAWeapon_InRange {}
445+
, ForceAAWeapon_InRange_Overrides {}
446+
, ForceAAWeapon_InRange_ApplyRangeModifiers { false }
435447

436448
, Ammo_Shared { false }
437449
, Ammo_Shared_Group { -1 }

0 commit comments

Comments
 (0)