Skip to content

[Highly Customized] Directional armor #1623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ This page lists all the individual contributions to the project by their author.
- Fix an issue that teleport units board transport vehicles on the bridge will create an impassable invisible barrier, which may cause the game to freeze or even crash
- Fix wrong shadow when a vehicle has hover locomotor and is being lifted by `IsLocomotor=yes` warhead
- Fix the bug that a unit can overlap with `Teleport` units after it's been damaged by a fallen unit lifted by `IsLocomotor=yes` warheads
- Directional armor
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
Expand Down
32 changes: 32 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,38 @@ JumpjetTilt.SidewaysRotationFactor=1.0 ; floating point value
JumpjetTilt.SidewaysSpeedFactor=1.0 ; floating point value
```

### Directional armor

- The damage suffered by the vehicle can now be affected by the hit direction.
- The front and rear judgment ranges are always symmetrical. A front angle of 0.5 indicates that the front direction is the axis, and the 45 degree angle range on both sides belongs to the front judgment range.
A front angle of 1.0 indicates that the 90 degree angle range on both sides belongs to the front judgment range;
- The lateral range refers to the remaining angle range after excluding the front and back sides.
- The warhead needs to have `Directional=true` to enable this effect.
- `Directional.Multiplier` is an additional multiplier used to control the intensity of the effect.

In `rulesmd.ini`
```ini
[CombatDamage]
DirectionalArmor=false ; boolean
DirectionalArmor.FrontMultiplier=1.0 ; float
DirectionalArmor.SideMultiplier=1.0 ; float
DirectionalArmor.BackMultiplier=1.0 ; float
DirectionalArmor.FrontField=0.5 ; float
DirectionalArmor.BackField=0.5 ; float

[SOMEVEHICLE] ; VehicleType
DirectionalArmor= ; boolean
DirectionalArmor.FrontMultiplier= ; float
DirectionalArmor.SideMultiplier= ; float
DirectionalArmor.BackMultiplier= ; float
DirectionalArmor.FrontField= ; float
DirectionalArmor.BackField= ; float

[SOMEWARHEAD]
Directional=false ; boolean
Directional.Multiplier=1.0 ; float
```

## Warheads

```{hint}
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ New:
- [Jumpjet Tilts While Moving](New-or-Enhanced-Logics.md#jumpjet-tilts-while-moving) (by CrimRecya)
- [Spawned aircraft facing to match turret toggle](New-or-Enhanced-Logics.md#aircraft-spawner-customizations) (by Starkku)
- [Removed dependency on `blowfish.dll`](Miscellanous.md#blowfish-dependency) (by ZivDero)
- Directional armor (by NetsuNegi)

Vanilla fixes:
- Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl)
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Bullet/Trajectories/PhobosTrajectory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Ext/BulletType/Body.h>
#include <Ext/Bullet/Body.h>
#include <Ext/WeaponType/Body.h>
#include <Ext/WarheadType/Body.h>

#include <BulletClass.h>
#include <Helpers/Macro.h>
Expand Down
13 changes: 13 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->DamageAlliesMultiplier.Read(exINI, GameStrings::CombatDamage, "DamageAlliesMultiplier");
this->DamageEnemiesMultiplier.Read(exINI, GameStrings::CombatDamage, "DamageEnemiesMultiplier");

this->DirectionalArmor.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor");
this->DirectionalArmor_FrontMultiplier.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor.FrontMultiplier");
this->DirectionalArmor_SideMultiplier.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor.SideMultiplier");
this->DirectionalArmor_BackMultiplier.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor.BackMultiplier");
this->DirectionalArmor_FrontField.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor.FrontField");
this->DirectionalArmor_BackField.Read(exINI, GameStrings::CombatDamage, "DirectionalArmor.BackField");

this->AircraftLevelLightMultiplier.Read(exINI, GameStrings::AudioVisual, "AircraftLevelLightMultiplier");
this->JumpjetLevelLightMultiplier.Read(exINI, GameStrings::AudioVisual, "JumpjetLevelLightMultiplier");

Expand Down Expand Up @@ -429,6 +436,12 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->DamageOwnerMultiplier)
.Process(this->DamageAlliesMultiplier)
.Process(this->DamageEnemiesMultiplier)
.Process(this->DirectionalArmor)
.Process(this->DirectionalArmor_FrontMultiplier)
.Process(this->DirectionalArmor_SideMultiplier)
.Process(this->DirectionalArmor_BackMultiplier)
.Process(this->DirectionalArmor_FrontField)
.Process(this->DirectionalArmor_BackField)
.Process(this->AircraftLevelLightMultiplier)
.Process(this->JumpjetLevelLightMultiplier)
.Process(this->VoxelLightSource)
Expand Down
15 changes: 15 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@ class RulesExt
Valueable<double> DamageAlliesMultiplier;
Valueable<double> DamageEnemiesMultiplier;

Valueable<bool> DirectionalArmor;
Valueable<double> DirectionalArmor_FrontMultiplier;
Valueable<double> DirectionalArmor_SideMultiplier;
Valueable<double> DirectionalArmor_BackMultiplier;
Valueable<double> DirectionalArmor_FrontField;
Valueable<double> DirectionalArmor_BackField;

Valueable<double> AircraftLevelLightMultiplier;
Valueable<double> JumpjetLevelLightMultiplier;

Expand Down Expand Up @@ -325,6 +332,14 @@ class RulesExt
, DamageOwnerMultiplier { 1.0 }
, DamageAlliesMultiplier { 1.0 }
, DamageEnemiesMultiplier { 1.0 }

, DirectionalArmor { false }
, DirectionalArmor_FrontMultiplier { 1.0 }
, DirectionalArmor_SideMultiplier { 1.0 }
, DirectionalArmor_BackMultiplier { 1.0 }
, DirectionalArmor_FrontField { 0.5 }
, DirectionalArmor_BackField { 0.5 }

, AircraftLevelLightMultiplier { 1.0 }
, JumpjetLevelLightMultiplier { 0.0 }
, VoxelLightSource { }
Expand Down
15 changes: 15 additions & 0 deletions src/Ext/Techno/Hooks.ReceiveDamage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ DEFINE_HOOK(0x701900, TechnoClass_ReceiveDamage_Shield, 0x6)
else
multiplier = pWHExt->DamageOwnerMultiplier.Get(pRules->DamageOwnerMultiplier);

if (pTypeExt->DirectionalArmor.Get(RulesExt::Global()->DirectionalArmor) && pThis->WhatAmI() == AbstractType::Unit && WarheadTypeExt::HitDirection >= 0 && args->DistanceToEpicenter <= 64)
{
const int tarFacing = pThis->PrimaryFacing.Current().GetValue<16>();
const int angle = abs(WarheadTypeExt::HitDirection - tarFacing);
const int frontField = static_cast<int>(16384 * pTypeExt->DirectionalArmor_FrontField.Get(RulesExt::Global()->DirectionalArmor_FrontField));
const int backField = static_cast<int>(16384 * pTypeExt->DirectionalArmor_BackField.Get(RulesExt::Global()->DirectionalArmor_BackField));

if (angle >= 32768 - frontField && angle <= 32768 + frontField)
multiplier *= pTypeExt->DirectionalArmor_FrontMultiplier.Get(RulesExt::Global()->DirectionalArmor_FrontMultiplier) * pWHExt->Directional_Multiplier;
else if ((angle < backField && angle >= 0) || (angle > 49152 + backField && angle <= 65536))
multiplier *= pTypeExt->DirectionalArmor_BackMultiplier.Get(RulesExt::Global()->DirectionalArmor_BackMultiplier) * pWHExt->Directional_Multiplier;
else
multiplier *= pTypeExt->DirectionalArmor_SideMultiplier.Get(RulesExt::Global()->DirectionalArmor_SideMultiplier) * pWHExt->Directional_Multiplier;
}

if (multiplier != 1.0)
{
const auto sgnDamage = *args->Damage > 0 ? 1 : -1;
Expand Down
14 changes: 14 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->KeepTargetOnMove.Read(exINI, pSection, "KeepTargetOnMove");
this->KeepTargetOnMove_ExtraDistance.Read(exINI, pSection, "KeepTargetOnMove.ExtraDistance");

this->DirectionalArmor.Read(exINI, pSection, "DirectionalArmor");
this->DirectionalArmor_FrontMultiplier.Read(exINI, pSection, "DirectionalArmor.FrontMultiplier");
this->DirectionalArmor_SideMultiplier.Read(exINI, pSection, "DirectionalArmor.SideMultiplier");
this->DirectionalArmor_BackMultiplier.Read(exINI, pSection, "DirectionalArmor.BackMultiplier");
this->DirectionalArmor_FrontField.Read(exINI, pSection, "DirectionalArmor.FrontField");
this->DirectionalArmor_BackField.Read(exINI, pSection, "DirectionalArmor.BackField");

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

this->Image_ConditionYellow.Read(exINI, pSection, "Image.ConditionYellow");
Expand Down Expand Up @@ -943,6 +950,13 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->KeepTargetOnMove)
.Process(this->KeepTargetOnMove_ExtraDistance)

.Process(this->DirectionalArmor)
.Process(this->DirectionalArmor_FrontMultiplier)
.Process(this->DirectionalArmor_SideMultiplier)
.Process(this->DirectionalArmor_BackMultiplier)
.Process(this->DirectionalArmor_FrontField)
.Process(this->DirectionalArmor_BackField)

.Process(this->Power)

.Process(this->Image_ConditionYellow)
Expand Down
14 changes: 14 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ class TechnoTypeExt
Valueable<bool> KeepTargetOnMove;
Valueable<Leptons> KeepTargetOnMove_ExtraDistance;

Nullable<bool> DirectionalArmor;
Nullable<double> DirectionalArmor_FrontMultiplier;
Nullable<double> DirectionalArmor_SideMultiplier;
Nullable<double> DirectionalArmor_BackMultiplier;
Nullable<double> DirectionalArmor_FrontField;
Nullable<double> DirectionalArmor_BackField;

Valueable<int> Power;

Nullable<UnitTypeClass*> Image_ConditionYellow;
Expand Down Expand Up @@ -568,6 +575,13 @@ class TechnoTypeExt
, KeepTargetOnMove { false }
, KeepTargetOnMove_ExtraDistance { Leptons(0) }

, DirectionalArmor {}
, DirectionalArmor_FrontMultiplier {}
, DirectionalArmor_SideMultiplier {}
, DirectionalArmor_BackMultiplier {}
, DirectionalArmor_FrontField {}
, DirectionalArmor_BackField {}

, Power { }

, Image_ConditionYellow { }
Expand Down
6 changes: 6 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->Shield_Respawn_Types.Read(exINI, pSection, "Shield.Respawn.Types");
this->Shield_SelfHealing_Types.Read(exINI, pSection, "Shield.SelfHealing.Types");

this->Directional.Read(exINI, pSection, "Directional");
this->Directional_Multiplier.Read(exINI, pSection, "Directional.Multiplier");

this->NotHuman_DeathSequence.Read(exINI, pSection, "NotHuman.DeathSequence");
this->LaunchSW.Read(exINI, pSection, "LaunchSW");
this->LaunchSW_RealLaunch.Read(exINI, pSection, "LaunchSW.RealLaunch");
Expand Down Expand Up @@ -475,6 +478,9 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)
.Process(this->Shield_Respawn_Types)
.Process(this->Shield_SelfHealing_Types)

.Process(this->Directional)
.Process(this->Directional_Multiplier)

.Process(this->SpawnsCrate_Types)
.Process(this->SpawnsCrate_Weights)

Expand Down
8 changes: 8 additions & 0 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ class WarheadTypeExt
NullableVector<ShieldTypeClass*> Shield_Respawn_Types;
NullableVector<ShieldTypeClass*> Shield_SelfHealing_Types;

Valueable<bool> Directional;
Valueable<double> Directional_Multiplier;

Valueable<int> NotHuman_DeathSequence;
ValueableIdxVector<SuperWeaponTypeClass> LaunchSW;
Valueable<bool> LaunchSW_RealLaunch;
Expand Down Expand Up @@ -286,6 +289,9 @@ class WarheadTypeExt
, Shield_Respawn_Types {}
, Shield_SelfHealing_Types {}

, Directional { false}
, Directional_Multiplier { 1.0 }

, SpawnsCrate_Types {}
, SpawnsCrate_Weights {}

Expand Down Expand Up @@ -409,6 +415,8 @@ class WarheadTypeExt
};

static ExtContainer ExtMap;
static int HitDirection;

static bool LoadGlobals(PhobosStreamReader& Stm);
static bool SaveGlobals(PhobosStreamWriter& Stm);

Expand Down
47 changes: 47 additions & 0 deletions src/Ext/WarheadType/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <Utilities/EnumFunctions.h>

#pragma region Detonation
int WarheadTypeExt::HitDirection = -1;

DEFINE_HOOK(0x46920B, BulletClass_Detonate, 0x6)
{
Expand All @@ -21,12 +22,58 @@ DEFINE_HOOK(0x46920B, BulletClass_Detonate, 0x6)
auto const pOwner = pBullet->Owner;
auto const pHouse = pOwner ? pOwner->Owner : nullptr;
auto const pDecidedHouse = pHouse ? pHouse : pBulletExt->FirerHouse;

pWHExt->Detonate(pOwner, pDecidedHouse, pBulletExt, *pCoords);
pWHExt->InDamageArea = false;

return 0;
}

DEFINE_HOOK(0x469A69, BulletClass_Detonate_DamageArea, 0x6)
{
enum { SkipGameCode = 0x469A88 };

GET(BulletClass*, pBullet, ESI);
GET(TechnoClass*, pSourceTechno, EAX);
GET(int, damage, EDX);
GET_BASE(CoordStruct*, coords, 0x8);
const auto pBulletExt = BulletExt::ExtMap.Find(pBullet);
const auto pSourceHouse = pSourceTechno ? pSourceTechno->Owner : pBulletExt->FirerHouse;
const auto pWH = pBullet->WH;
const auto pWHExt = WarheadTypeExt::ExtMap.Find(pWH);

do
{
if (pWHExt->Directional)
{
if (pBullet->Type->Inviso)
{
if (pBullet->SourceCoords.X != pBullet->TargetCoords.X || pBullet->SourceCoords.Y != pBullet->TargetCoords.Y)
{
WarheadTypeExt::HitDirection = DirStruct(Math::atan2(static_cast<double>(pBullet->SourceCoords.Y - pBullet->TargetCoords.Y), static_cast<double>(pBullet->TargetCoords.X - pBullet->SourceCoords.X))).GetValue<16>();
break;
}
}
else
{
if (pBullet->Velocity.X != 0.0 || pBullet->Velocity.Y != 0.0)
{
WarheadTypeExt::HitDirection = DirStruct((-1) * Math::atan2(pBullet->Velocity.Y, pBullet->Velocity.X)).GetValue<16>();
break;
}
}
}

WarheadTypeExt::HitDirection = -1;
}
while (false);

R->EAX(MapClass::Instance.DamageArea(*coords, damage, pSourceTechno, pWH, true, pSourceHouse));
WarheadTypeExt::HitDirection = -1;

return SkipGameCode;
}

DEFINE_HOOK(0x489286, MapClass_DamageArea, 0x6)
{
GET_BASE(const WarheadTypeClass*, pWH, 0x0C);
Expand Down