Skip to content
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ This page lists all the individual contributions to the project by their author.
- Vehicle Deployment Enhancement
- Fixed an issue where miners affected by `Passengers/DeployFire` were unable to unload minerals
- Fixed an issue where mining vehicles could not move after leaving a tank bunker
- Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`
- **NetsuNegi**:
- Forbidding parallel AI queues by type
- Jumpjet crash speed fix when crashing onto building
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ New:
- Option to scale `PowerSurplus` setting if enabled to current power drain with `PowerSurplus.ScaleToDrainAmount` (by Starkku)
- Global default value for `DefaultToGuardArea` (by TaranDahl)
- [Weapon range finding in cylinder](New-or-Enhanced-Logics.md#range-finding-in-cylinder) (by TaranDahl)
- Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` (by FlyStar)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
10 changes: 10 additions & 0 deletions src/Ext/Infantry/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ DEFINE_HOOK(0x51EE6B, InfantryClass_WhatAction_ObjectClass_InfiltrateForceAttack
return WhatActionObjectTemp::Fire ? 0x51F05E : 0;
}

// Setting Ares' NoSelfGuardArea to yes will also disable this feature. I'm not sure if it should be removed.
DEFINE_HOOK(0x51E748, InfantryClass_WhatAction_ObjectClass_SkipGuardArea, 0x8)
{
GET(InfantryClass* const, pThis, EDI);
GET(const Action, action, EBP);
enum { SkipGameCode = 0x51E7A6 };

return (action == Action::Self_Deploy || pThis->IsDeployed()) ? SkipGameCode : 0;
}

DEFINE_HOOK(0x51ECC0, InfantryClass_WhatAction_ObjectClass_IsAreaFire, 0xA)
{
enum { IsAreaFire = 0x51ECE5, NotAreaFire = 0x51ECEC };
Expand Down
28 changes: 11 additions & 17 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,33 +452,27 @@ void TechnoTypeExt::ExtData::UpdateAdditionalAttributes()
if (!pWeapon)
return;

const int combatDamage = (pWeapon->Damage + pWeapon->AmbientDamage);
const ThreatType threats = pWeapon->Projectile ? pWeapon->AllowedThreats() : ThreatType::Normal;
const bool attackFriendlies = WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false);

if (isElite)
{
if (pWeapon->Projectile)
this->ThreatTypes.Y |= pWeapon->AllowedThreats();

this->CombatDamages.Y += (pWeapon->Damage + pWeapon->AmbientDamage);
this->ThreatTypes.Y |= threats;
this->CombatDamages.Y += combatDamage;
eliteNum++;

if (!this->AttackFriendlies.Y
&& WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false))
{
if (!this->AttackFriendlies.Y && attackFriendlies)
this->AttackFriendlies.Y = true;
}
}
else
{
if (pWeapon->Projectile)
this->ThreatTypes.X |= pWeapon->AllowedThreats();

this->CombatDamages.X += (pWeapon->Damage + pWeapon->AmbientDamage);
this->ThreatTypes.X |= threats;
this->CombatDamages.X += combatDamage;
num++;

if (!this->AttackFriendlies.X
&& WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false))
{
if (!this->AttackFriendlies.X && attackFriendlies)
this->AttackFriendlies.X = true;
}
}
};

Expand Down Expand Up @@ -1149,7 +1143,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

this->ParadropMission.Read(exINI, pSection, "ParadropMission");
this->AIParadropMission.Read(exINI, pSection, "AIParadropMission");

// Ares 0.2
this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius");

Expand Down
2 changes: 1 addition & 1 deletion src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ class TechnoTypeExt

Nullable<Mission> ParadropMission;
Nullable<Mission> AIParadropMission;

ExtData(TechnoTypeClass* OwnerObject) : Extension<TechnoTypeClass>(OwnerObject)
, HealthBar_Hide { false }
, HealthBar_HidePips { false }
Expand Down
148 changes: 145 additions & 3 deletions src/Ext/TechnoType/Hooks.MultiWeapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,24 @@ DEFINE_HOOK(0x7090A0, TechnoClass_VoiceAttack, 0x7)
return 0x7091C7;
}

bool __forceinline IsDeployed(TechnoClass* const pThis, const AbstractType rtti)
{
switch (rtti)
{
case AbstractType::Infantry:
return static_cast<InfantryClass*>(pThis)->IsDeployed();
case AbstractType::Unit:
{
auto const pUnit = static_cast<UnitClass*>(pThis);

return pUnit->Deployed || (pUnit->Type->DeployFire &&
pThis->CurrentMission == Mission::Unload);
}
default:
return false;
}
}

static __forceinline ThreatType GetThreatType(TechnoClass* pThis, TechnoTypeExt::ExtData* pTypeExt, ThreatType result)
{
const ThreatType flags = pThis->Veterancy.IsElite() ? pTypeExt->ThreatTypes.Y : pTypeExt->ThreatTypes.X;
Expand All @@ -157,9 +175,9 @@ DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClas
GET(FootClass*, pThis, ESI);
GET(const ThreatType, result, EDI);

const bool isUnit = R->Origin() == 0x7431C9;
const auto pTypeExt = TechnoExt::ExtMap.Find(pThis)->TypeExtData;
const auto pType = pTypeExt->OwnerObject();
const bool isUnit = R->Origin() == 0x7431C9;

if (isUnit
&& !pType->IsGattling && pType->TurretCount > 0
Expand All @@ -168,6 +186,46 @@ DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClas
return UnitGunner;
}

const AbstractType rtti = isUnit ? AbstractType::Unit : AbstractType::Infantry;
const int deployFireWeapon = pType->DeployFireWeapon;

if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0)
{
ThreatType flags = result;

if (const auto pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType)
flags |= pWeapon->AllowedThreats();

R->EDI(flags);
return isUnit ? UnitReturn : InfantryReturn;
}

const int openTransportWeapon = pType->OpenTransportWeapon;

if (pThis->InOpenToppedTransport && openTransportWeapon >= 0)
{
ThreatType flags = result;

if (const auto pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType)
flags |= pWeapon->AllowedThreats();

R->EDI(flags);
return isUnit ? UnitReturn : InfantryReturn;
}

const int noAmmoWeapon = pTypeExt->NoAmmoWeapon;

if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount)
{
ThreatType flags = result;

if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType)
flags |= pWeapon->AllowedThreats();

R->EDI(flags);
return isUnit ? UnitReturn : InfantryReturn;
}

R->EDI(GetThreatType(pThis, pTypeExt, result));
return isUnit ? UnitReturn : InfantryReturn;
}
Expand All @@ -185,7 +243,22 @@ DEFINE_HOOK(0x445F04, BuildingClass_SelectAutoTarget_MultiWeapon, 0xA)
return Continue;
}

R->EDI(GetThreatType(pThis, TechnoTypeExt::ExtMap.Find(pThis->Type), result));
const auto pType = pThis->Type;
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
const int noAmmoWeapon = pTypeExt->NoAmmoWeapon;

if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount)
{
ThreatType flags = result;

if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType)
flags |= pWeapon->AllowedThreats();

R->EDI(flags);
return ReturnThreatType;
}

R->EDI(GetThreatType(pThis, pTypeExt, result));
return ReturnThreatType;
}

Expand Down Expand Up @@ -215,6 +288,45 @@ DEFINE_HOOK(0x6F398E, TechnoClass_CombatDamage_MultiWeapon, 0x7)
return GunnerDamage;
}

const int deployFireWeapon = pType->DeployFireWeapon;

if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0)
{
int damage = 0;

if (auto const pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType)
damage = (pWeapon->Damage + pWeapon->AmbientDamage);

R->EAX(damage);
return ReturnDamage;
}

const int openTransportWeapon = pType->OpenTransportWeapon;

if (pThis->InOpenToppedTransport && openTransportWeapon >= 0)
{
int damage = 0;

if (auto const pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType)
damage = (pWeapon->Damage + pWeapon->AmbientDamage);

R->EAX(damage);
return ReturnDamage;
}

const int noAmmoWeapon = pTypeExt->NoAmmoWeapon;

if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount)
{
int damage = 0;

if (auto const pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType)
damage = (pWeapon->Damage + pWeapon->AmbientDamage);

R->EAX(damage);
return ReturnDamage;
}

R->EAX(pThis->Veterancy.IsElite() ? pTypeExt->CombatDamages.Y : pTypeExt->CombatDamages.X);
return ReturnDamage;
}
Expand All @@ -227,16 +339,46 @@ DEFINE_HOOK(0x707ED0, TechnoClass_GetGuardRange_MultiWeapon, 0x6)

const auto pType = pThis->GetTechnoType();
const bool specialWeapon = !pType->IsGattling && (!pType->HasMultipleTurrets() || !pType->Gunner);
const AbstractType rtti = pThis->WhatAmI();

if (!pType->IsGattling && pType->TurretCount > 0
&& (pType->Gunner || !specialWeapon)
&& pThis->WhatAmI() == AbstractType::Unit)
&& rtti == AbstractType::Unit)
{
R->EAX(pThis->GetWeaponRange(pThis->CurrentWeaponNumber));
return ReturnRange;
}

const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
const int deployFireWeapon = pType->DeployFireWeapon;

if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0)
{
int range = pThis->GetWeaponRange(deployFireWeapon);

R->EAX(range);
return ReturnRange;
}

const int openTransportWeapon = pType->OpenTransportWeapon;

if (pThis->InOpenToppedTransport && openTransportWeapon >= 0)
{
int range = pThis->GetWeaponRange(openTransportWeapon);

R->EAX(range);
return ReturnRange;
}

const int noAmmoWeapon = pTypeExt->NoAmmoWeapon;

if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount)
{
int range = pThis->GetWeaponRange(noAmmoWeapon);

R->EAX(range);
return ReturnRange;
}

if (pTypeExt->MultiWeapon && specialWeapon)
{
Expand Down
Loading