Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ This page lists all the individual contributions to the project by their author.
- Health bar permanently displayed
- Unlimbo Detonate warhead
- Fast access structure
- Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies`
- **NetsuNegi**:
- Forbidding parallel AI queues by type
- Jumpjet crash speed fix when crashing onto building
Expand Down
11 changes: 11 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,17 @@ In `rulesmd.ini`:
AreaFire.Target=base ; AreaFire Target Enumeration (base|self|random)
```

### Can attack allies

- Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies`, They override the firer's `AttackFriendlies` and `AttackCursorOnFriendlies`.

In `rulesmd.ini`:
```ini
[SOMEWEAPON] ; WeaponType
AttackFriendlies= ; boolean
AttackCursorOnFriendlies= ; boolean
```

### Burst delay customizations

- `Burst.Delays` allows specifying weapon-specific burst shot delays. Takes precedence over the old `BurstDelayX` logic available on VehicleTypes, functions with Infantry & BuildingType weapons (AircraftTypes are not supported due to their weapon firing system being completely different) and allows every shot of `Burst` to have a separate delay instead of only first four shots.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ New:
- [Unlimbo Detonate warhead](New-or-Enhanced-Logics.md#unlimbo-detonate-warhead) (by FlyStar)
- Attack and damage technos underground (by TaranDahl)
- Fast access structure (by FlyStar)
- Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies` (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
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ void RulesExt::LoadAfterTypeData(RulesClass* pThis, CCINIClass* pINI)
// Spawner range
if (pTechnoTypeExt->Spawner_LimitRange)
pTechnoTypeExt->CalculateSpawnerRange();

pTechnoTypeExt->UpdateAdditionalAttributes();
}
}

Expand Down
65 changes: 65 additions & 0 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1459,3 +1459,68 @@ DEFINE_HOOK(0x6F7E1E, TechnoClass_CanAutoTargetObject_AU, 0x6)
}

#pragma endregion

#pragma region AutoTargetExtension

DEFINE_JUMP(LJMP, 0x700387, 0x7003BD)

DEFINE_HOOK(0x700358, TechnoClass_MouseOverObject_AttackFriendlies, 0x6)
{
enum { CanAttack = 0x700381, Continue = 0x700385 };

GET(TechnoClass*, pThis, ESI);
GET(WeaponTypeClass*, pWeapon, EBP);
GET_STACK(const bool, IvanBomb, STACK_OFFSET(0x1C, -0xC));

const auto pType = pThis->GetTechnoType();
const auto pWeaponTypeExt = WeaponTypeExt::ExtMap.Find(pWeapon);

if (pWeaponTypeExt->AttackFriendlies.Get(pType->AttackFriendlies) ||
(pWeaponTypeExt->AttackCursorOnFriendlies.Get(pType->AttackCursorOnFriendlies) && !IvanBomb))
{
return CanAttack;
}

return Continue;
}

DEFINE_HOOK_AGAIN(0x6F9CE9, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA) // TechnoClass::SelectAutoTarget
DEFINE_HOOK_AGAIN(0x6F9BAE, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA)
DEFINE_HOOK_AGAIN(0x6F9204, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA)
DEFINE_HOOK_AGAIN(0x6F8BBC, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA) // TechnoClass::TryAutoTargetObject
DEFINE_HOOK(0x6F8A92, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA)
{
GET(TechnoClass*, pThis, ESI);

R->CL(TechnoExt::ExtMap.Find(pThis)->TypeExtData->AttackFriendlies);
return R->Origin() + 0x10;
}

namespace CanAutoTargetTemp
{
TechnoTypeExt::ExtData* TypeExtData;
WeaponTypeExt::ExtData* WeaponExt;
}

DEFINE_HOOK(0x6F7E30, TechnoClass_CanAutoTarget_SetContent, 0x6)
{
GET(TechnoClass*, pThis, EDI);
GET(WeaponTypeClass*, pWeapon, EBP);

CanAutoTargetTemp::TypeExtData = TechnoExt::ExtMap.Find(pThis)->TypeExtData;
CanAutoTargetTemp::WeaponExt = WeaponTypeExt::ExtMap.Find(pWeapon);

return 0;
}

DEFINE_HOOK(0x6F7EF4, TechnoClass_CanAutoTarget_AttackFriendlies, 0xA)
{
enum { SkipGameCode = 0x6F7F04 };

R->CL(CanAutoTargetTemp::WeaponExt->AttackFriendlies.Get(
CanAutoTargetTemp::TypeExtData->OwnerObject()->AttackFriendlies));

return SkipGameCode;
}

#pragma endregion
47 changes: 47 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <Ext/BuildingType/Body.h>
#include <Ext/BulletType/Body.h>
#include <Ext/Techno/Body.h>
#include <Ext/WeaponType/Body.h>
#include <New/Type/InsigniaTypeClass.h>

#include <Utilities/GeneralUtils.h>
Expand Down Expand Up @@ -259,6 +260,50 @@ int TechnoTypeExt::ExtData::SelectMultiWeapon(TechnoClass* const pThis, Abstract
return 0;
}

void TechnoTypeExt::ExtData::UpdateAdditionalAttributes()
{
const auto pThis = this->OwnerObject();
this->AttackFriendlies = pThis->AttackFriendlies;

if (!AttackFriendlies)
{
int Count = 2;

if (this->MultiWeapon
&& (!pThis->IsGattling && (!pThis->HasMultipleTurrets() || !pThis->Gunner)))
{
Count = pThis->WeaponCount;
}

for (int index = 0; index < Count; index++)
{
const auto pWeapon = pThis->GetWeapon(index)->WeaponType;
auto pEliteWeapon = pThis->GetEliteWeapon(index)->WeaponType;

if (!pEliteWeapon)
pEliteWeapon = pWeapon;

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

if (pEliteWeapon)
{
if (WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false))
{
this->AttackFriendlies = true;
return;
}
}
}
}
}

// Ares 0.A source
const char* TechnoTypeExt::ExtData::GetSelectionGroupID() const
{
Expand Down Expand Up @@ -1609,6 +1654,8 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->InfantryAutoDeploy)

.Process(this->TurretResponse)

.Process(this->AttackFriendlies)
;
}
void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)
Expand Down
6 changes: 6 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ class TechnoTypeExt

Nullable<bool> TurretResponse;

bool AttackFriendlies;

ExtData(TechnoTypeClass* OwnerObject) : Extension<TechnoTypeClass>(OwnerObject)
, HealthBar_Hide { false }
, HealthBar_HidePips { false }
Expand Down Expand Up @@ -812,6 +814,8 @@ class TechnoTypeExt
, InfantryAutoDeploy {}

, TurretResponse {}

, AttackFriendlies { false }
{ }

virtual ~ExtData() = default;
Expand All @@ -832,6 +836,8 @@ class TechnoTypeExt
int SelectForceWeapon(TechnoClass* pThis, AbstractClass* pTarget);
int SelectMultiWeapon(TechnoClass* const pThis, AbstractClass* const pTarget);

void UpdateAdditionalAttributes();

// Ares 0.A
const char* GetSelectionGroupID() const;

Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WeaponType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->DelayedFire_OnlyOnInitialBurst.Read(exINI, pSection, "DelayedFire.OnlyOnInitialBurst");
this->DelayedFire_AnimOffset.Read(exINI, pSection, "DelayedFire.AnimOffset");
this->DelayedFire_AnimOnTurret.Read(exINI, pSection, "DelayedFire.AnimOnTurret");
this->AttackFriendlies.Read(exINI, pSection, "AttackFriendlies");
this->AttackCursorOnFriendlies.Read(exINI, pSection, "AttackCursorOnFriendlies");

// handle SkipWeaponPicking
if (this->CanTarget != AffectedTarget::All || this->CanTargetHouses != AffectedHouse::All
Expand Down Expand Up @@ -237,6 +239,8 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm)
.Process(this->DelayedFire_OnlyOnInitialBurst)
.Process(this->DelayedFire_AnimOffset)
.Process(this->DelayedFire_AnimOnTurret)
.Process(this->AttackFriendlies)
.Process(this->AttackCursorOnFriendlies)
;
};

Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WeaponType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class WeaponTypeExt
Valueable<bool> DelayedFire_OnlyOnInitialBurst;
Nullable<CoordStruct> DelayedFire_AnimOffset;
Valueable<bool> DelayedFire_AnimOnTurret;
Nullable<bool> AttackFriendlies;
Nullable<bool> AttackCursorOnFriendlies;

bool SkipWeaponPicking;

Expand Down Expand Up @@ -164,6 +166,8 @@ class WeaponTypeExt
, DelayedFire_OnlyOnInitialBurst { false }
, DelayedFire_AnimOffset {}
, DelayedFire_AnimOnTurret { true }
, AttackFriendlies {}
, AttackCursorOnFriendlies {}
{ }

int GetBurstDelay(int burstIndex) const;
Expand Down