Skip to content

Commit 90a19c6

Browse files
authored
MultiWeapon Auto-Target Selection Fix (#1904)
Fixed an issue where the game would only use `Weapon1` and `Weapon2` for auto-targeting even when `MultiWeapon=yes` was set. 修复`MultiWeapon`启用后仍然只使用`Weapon1`、`Weapon2`进行自动索敌的问题。 --------- Co-authored-by: Fly-Star <100747645+a851903106@users.noreply.github.com>
1 parent f047fd9 commit 90a19c6

File tree

6 files changed

+178
-4
lines changed

6 files changed

+178
-4
lines changed

docs/Fixed-or-Improved-Logics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho
302302
- Fixed an issue that technos head to building's dock even they are not going to dock.
303303
- Fixed an issue that the jumpjet vehicles cannot stop correctly after going berserk.
304304
- Fixed the issue where Ares' `Flash.Duration` cannot override the weapon's repair flash effect.
305+
- Fixed an issue where the game would only use `Weapon1` and `Weapon2` for auto-targeting even when `MultiWeapon=yes` was set.
305306

306307
```{note}
307308
The described behavior is a replica of and is compliant with XNA CnCNet Client's multiplayer save game support.

docs/Whats-New.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ Phobos fixes:
501501
- Fixed an issue where the 77 trigger event in Ares was not functioning properly (by NetsuNegi)
502502
- Fixed an interaction error between the engineer and the Ares rubble (by FlyStar)
503503
- Fixed the projection location of selectbox when over elevated bridge (by NetsuNegi)
504+
- Fixed an issue where the game would only use `Weapon1` and `Weapon2` for auto-targeting even when `MultiWeapon=yes` was set (by FlyStar)
504505
505506
Fixes / interactions with other extensions:
506507
- Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades (by Ollerus)

src/Ext/Rules/Body.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ void RulesExt::LoadAfterTypeData(RulesClass* pThis, CCINIClass* pINI)
5757
// Spawner range
5858
if (pTechnoTypeExt->Spawner_LimitRange)
5959
pTechnoTypeExt->CalculateSpawnerRange();
60+
61+
pTechnoTypeExt->UpdateAdditionalAttributes();
6062
}
6163
}
6264

src/Ext/TechnoType/Body.cpp

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,26 +139,26 @@ bool TechnoTypeExt::ExtData::IsSecondary(int nWeaponIndex)
139139

140140
int TechnoTypeExt::ExtData::SelectMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget)
141141
{
142-
if (!pTarget || !this->MultiWeapon.Get())
142+
if (!pTarget || !this->MultiWeapon)
143143
return -1;
144144

145145
const auto pType = this->OwnerObject();
146146

147147
if (pType->IsGattling || (pType->HasMultipleTurrets() && pType->Gunner))
148148
return -1;
149149

150-
const int weaponCount = Math::min(pType->WeaponCount, this->MultiWeapon_SelectCount.Get());
150+
const int weaponCount = Math::min(pType->WeaponCount, this->MultiWeapon_SelectCount);
151+
const bool noSecondary = this->NoSecondaryWeaponFallback;
151152

152153
if (weaponCount < 2)
153154
return 0;
154-
else if (weaponCount == 2)
155+
else if (weaponCount == 2 && !noSecondary)
155156
return -1;
156157

157158
std::vector<bool> secondaryCanTargets {};
158159
secondaryCanTargets.resize(weaponCount, false);
159160

160161
const bool isElite = pThis->Veterancy.IsElite();
161-
const bool noSecondary = this->NoSecondaryWeaponFallback.Get();
162162

163163
if (const auto pTargetTechno = abstract_cast<TechnoClass*, true>(pTarget))
164164
{
@@ -362,6 +362,53 @@ void TechnoTypeExt::ExtData::ParseVoiceWeaponAttacks(INI_EX& exINI, const char*
362362
}
363363
}
364364

365+
void TechnoTypeExt::ExtData::UpdateAdditionalAttributes()
366+
{
367+
int num = 0;
368+
int eliteNum = 0;
369+
370+
this->ThreatTypes = { ThreatType::Normal,ThreatType::Normal };
371+
this->CombatDamages = { 0,0 };
372+
373+
const auto pThis = this->OwnerObject();
374+
int count = 2;
375+
376+
if (this->MultiWeapon
377+
&& (!pThis->IsGattling && (!pThis->HasMultipleTurrets() || !pThis->Gunner)))
378+
{
379+
count = pThis->WeaponCount;
380+
}
381+
382+
for (int index = 0; index < count; index++)
383+
{
384+
const auto pWeapon = pThis->GetWeapon(index)->WeaponType;
385+
auto pEliteWeapon = pThis->GetEliteWeapon(index)->WeaponType;
386+
387+
if (!pEliteWeapon)
388+
pEliteWeapon = pWeapon;
389+
390+
if (pWeapon)
391+
{
392+
this->ThreatTypes.X |= pWeapon->AllowedThreats();
393+
this->CombatDamages.X += (pWeapon->Damage + pWeapon->AmbientDamage);
394+
num++;
395+
}
396+
397+
if (pEliteWeapon)
398+
{
399+
this->ThreatTypes.Y |= pEliteWeapon->AllowedThreats();
400+
this->CombatDamages.Y += (pEliteWeapon->Damage + pEliteWeapon->AmbientDamage);
401+
eliteNum++;
402+
}
403+
}
404+
405+
if (num > 0)
406+
this->CombatDamages.X /= num;
407+
408+
if (eliteNum > 0)
409+
this->CombatDamages.Y /= eliteNum;
410+
}
411+
365412
void TechnoTypeExt::ExtData::CalculateSpawnerRange()
366413
{
367414
const auto pThis = this->OwnerObject();

src/Ext/TechnoType/Body.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ class TechnoTypeExt
422422
ValueableVector<bool> MultiWeapon_IsSecondary;
423423
Valueable<int> MultiWeapon_SelectCount;
424424
bool ReadMultiWeapon;
425+
Vector2D<ThreatType> ThreatTypes;
426+
Vector2D<int> CombatDamages;
425427

426428
ValueableIdx<VocClass> VoiceIFVRepair;
427429
ValueableVector<int> VoiceWeaponAttacks;
@@ -804,6 +806,8 @@ class TechnoTypeExt
804806
, MultiWeapon_IsSecondary {}
805807
, MultiWeapon_SelectCount { 2 }
806808
, ReadMultiWeapon { false }
809+
, ThreatTypes { ThreatType::Normal,ThreatType::Normal }
810+
, CombatDamages { 0,0 }
807811

808812
, VoiceIFVRepair { -1 }
809813
, VoiceWeaponAttacks {}
@@ -832,6 +836,8 @@ class TechnoTypeExt
832836
int SelectForceWeapon(TechnoClass* pThis, AbstractClass* pTarget);
833837
int SelectMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget);
834838

839+
void UpdateAdditionalAttributes();
840+
835841
// Ares 0.A
836842
const char* GetSelectionGroupID() const;
837843

src/Ext/TechnoType/Hooks.MultiWeapon.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "Body.h"
22
#include <Randomizer.h>
33

4+
#include <Ext/Techno/Body.h>
5+
46
DEFINE_HOOK(0x7128B2, TechnoTypeClass_ReadINI_MultiWeapon, 0x6)
57
{
68
GET(TechnoTypeClass*, pThis, EBP);
@@ -141,3 +143,118 @@ DEFINE_HOOK(0x7090A0, TechnoClass_VoiceAttack, 0x7)
141143

142144
return 0x7091C7;
143145
}
146+
147+
ThreatType __forceinline GetThreatType(TechnoClass* pThis, TechnoTypeExt::ExtData* pTypeExt, ThreatType result)
148+
{
149+
const ThreatType flags = pThis->Veterancy.IsElite() ? pTypeExt->ThreatTypes.Y : pTypeExt->ThreatTypes.X;
150+
return result | flags;
151+
}
152+
153+
DEFINE_HOOK_AGAIN(0x51E2CF, FootClass_SelectAutoTarget_MultiWeapon, 0x6) // InfantryClass_SelectAutoTarget
154+
DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClass_SelectAutoTarget
155+
{
156+
enum { InfantryReturn = 0x51E31B, UnitReturn = 0x74324F, UnitGunner = 0x7431E4 };
157+
158+
GET(FootClass*, pThis, ESI);
159+
GET(const ThreatType, result, EDI);
160+
161+
const bool isUnit = R->Origin() == 0x7431C9;
162+
const auto pType = pThis->GetTechnoType();
163+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
164+
165+
if (isUnit
166+
&& !pType->IsGattling && pType->TurretCount > 0
167+
&& (pType->Gunner || !pTypeExt->MultiWeapon))
168+
{
169+
return UnitGunner;
170+
}
171+
172+
R->EDI(GetThreatType(pThis, pTypeExt, result));
173+
return isUnit ? UnitReturn : InfantryReturn;
174+
}
175+
176+
DEFINE_HOOK(0x445F04, BuildingClass_SelectAutoTarget_MultiWeapon, 0xA)
177+
{
178+
enum { ReturnThreatType = 0x445F58, Continue = 0x445F0E };
179+
180+
GET(BuildingClass*, pThis, ESI);
181+
GET_STACK(const ThreatType, result, STACK_OFFSET(0x8, 0x4));
182+
183+
if (pThis->UpgradeLevel > 0 || pThis->CanOccupyFire())
184+
{
185+
R->EAX(pThis->GetWeapon(0));
186+
return Continue;
187+
}
188+
189+
R->EDI(GetThreatType(pThis, TechnoTypeExt::ExtMap.Find(pThis->Type), result));
190+
return ReturnThreatType;
191+
}
192+
193+
DEFINE_HOOK(0x6F398E, TechnoClass_CombatDamage_MultiWeapon, 0x7)
194+
{
195+
enum { ReturnDamage = 0x6F3ABB, GunnerDamage = 0x6F39AD, Continue = 0x6F39F4 };
196+
197+
GET(TechnoClass*, pThis, ESI);
198+
199+
const AbstractType rtti = pThis->WhatAmI();
200+
201+
if (rtti == AbstractType::Building)
202+
{
203+
const auto pBuilding = static_cast<BuildingClass*>(pThis);
204+
205+
if (pBuilding->UpgradeLevel > 0 || pBuilding->CanOccupyFire())
206+
return Continue;
207+
}
208+
209+
const auto pType = pThis->GetTechnoType();
210+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
211+
212+
if (rtti == AbstractType::Unit
213+
&& !pType->IsGattling && pType->TurretCount > 0
214+
&& (pType->Gunner || !pTypeExt->MultiWeapon))
215+
{
216+
return GunnerDamage;
217+
}
218+
219+
R->EAX(pThis->Veterancy.IsElite() ? pTypeExt->CombatDamages.Y : pTypeExt->CombatDamages.X);
220+
return ReturnDamage;
221+
}
222+
223+
DEFINE_HOOK(0x707ED0, TechnoClass_GetGuardRange_MultiWeapon, 0x6)
224+
{
225+
enum { ReturnRange = 0x707F08 };
226+
227+
GET(TechnoClass*, pThis, ESI);
228+
229+
const auto pType = pThis->GetTechnoType();
230+
const bool specialWeapon = !pType->IsGattling && (!pType->HasMultipleTurrets() || !pType->Gunner);
231+
232+
if (!pType->IsGattling && pType->TurretCount > 0
233+
&& (pType->Gunner || !specialWeapon)
234+
&& pThis->WhatAmI() == AbstractType::Unit)
235+
{
236+
R->EAX(pThis->GetWeaponRange(pThis->CurrentWeaponNumber));
237+
return ReturnRange;
238+
}
239+
240+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
241+
242+
if (pTypeExt->MultiWeapon && specialWeapon)
243+
{
244+
const int selectCount = Math::min(pType->WeaponCount, pTypeExt->MultiWeapon_SelectCount);
245+
int range = 0;
246+
247+
for (int index = selectCount - 1; index >= 0; --index)
248+
{
249+
const auto weaponRange = pThis->GetWeaponRange(index);
250+
251+
if (weaponRange > range)
252+
range = weaponRange;
253+
}
254+
255+
R->EAX(range);
256+
return ReturnRange;
257+
}
258+
259+
return 0;
260+
}

0 commit comments

Comments
 (0)