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

Draft
wants to merge 17 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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 @@ -408,6 +408,7 @@ This page lists all the individual contributions to the project by their author.
- Exclusive SuperWeapon Sidebar
- Fix the bug that AlphaImage remained after unit entered tunnel
- Weapon target filtering by health percentage
- 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 @@ -1861,6 +1861,38 @@ FireUp= ; integer
FireUp.ResetInRetarget=true ; boolean
```

### 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use case of this flag?

```

## 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 @@ -391,6 +391,7 @@ New:
- [Turretless vehicles with `Voxel=no` support use `FireUp` like infantry](New-or-Enhanced-Logics.md#turretless-shape-vehicle-fireup) (by FlyStar)
- Infantry support `IsGattling=yes` (by FlyStar)
- [Several new Infotypes, no display in specific status and a new single frame display method](User-Interface.md#digital-display) (by CrimRecya)
- Directional armor (by NetsuNegi)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
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 @@ -219,6 +219,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 @@ -462,6 +469,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 @@ -176,6 +176,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 @@ -358,6 +365,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
16 changes: 16 additions & 0 deletions src/Ext/Techno/Hooks.ReceiveDamage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ DEFINE_HOOK(0x701900, TechnoClass_ReceiveDamage_Shield, 0x6)
// Calculate Damage Multiplier
if (!args->IgnoreDefenses && *args->Damage)
{
const auto pTypeExt = pExt->TypeExtData;
double multiplier = 1.0;

if (!pSourceHouse || !pTargetHouse || !pSourceHouse->IsAlliedWith(pTargetHouse))
Expand All @@ -38,6 +39,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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why UnitClass only?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

becase only unit can move by reverse direction (need #1622)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe required distance could be made customisable?

{
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 @@ -609,6 +609,13 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->KeepTargetOnMove_NoMorePursuit.Read(exINI, pSection, "KeepTargetOnMove.NoMorePursuit");
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->AllowAirstrike.Read(exINI, pSection, "AllowAirstrike");
Expand Down Expand Up @@ -1187,6 +1194,13 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->KeepTargetOnMove_NoMorePursuit)
.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->AllowAirstrike)
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 @@ -298,6 +298,13 @@ class TechnoTypeExt
Valueable<bool> KeepTargetOnMove_NoMorePursuit;
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<bool> AllowAirstrike;
Expand Down Expand Up @@ -640,6 +647,13 @@ class TechnoTypeExt
, KeepTargetOnMove_NoMorePursuit { true }
, KeepTargetOnMove_ExtraDistance { Leptons(0) }

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

, Power { }

, AllowAirstrike { }
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 @@ -214,6 +214,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 @@ -460,6 +463,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 @@ -292,6 +295,9 @@ class WarheadTypeExt
, Shield_Respawn_Types {}
, Shield_SelfHealing_Types {}

, Directional { false}
, Directional_Multiplier { 1.0 }

, SpawnsCrate_Types {}
, SpawnsCrate_Weights {}

Expand Down Expand Up @@ -421,6 +427,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