Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Credits
- **ChrisLv_CN** - interceptor logic, LaserTrails, laser fixes, general assistance (work relicensed under [following permission](images/ChrisLv-relicense.png))
- **Xkein** - general assistance, YRpp edits
- **thomassneddon** - general assistance
- **Starkku** - Warhead shield penetration & breaking, strafing aircraft weapon customization, vehicle DeployFire fixes/improvements, stationary VehicleTypes, Burst logic improvements, TechnoType auto-firing weapons, Secondary weapon fallback customization, weapon target type filtering, AreaFire targeting customization, CreateUnit improvements, Attached animation & jumpjet unit layer customization, IsSimpleDeployer improvements, Shield modification warheads
- **Starkku** - Warhead shield penetration & breaking, strafing aircraft weapon customization, vehicle DeployFire fixes/improvements, stationary VehicleTypes, Burst logic improvements, TechnoType auto-firing weapons, Secondary weapon fallback customization, weapon target type filtering, AreaFire targeting customization, CreateUnit improvements, Attached animation & jumpjet unit layer customization, IsSimpleDeployer improvements, Shield modification warheads, Warhead decloaking toggle
- **SukaHati (Erzoid)** - Minimum interceptor guard range
- **Morton (MortonPL)** - XDrawOffset, Shield passthrough & absorption, building LimboDelivery, fix for Image in art rules
- **mevitar** - honorary shield tester *triple* award
Expand Down
12 changes: 12 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,16 @@ In `rulesmd.ini`:
[SOMEPROJECTILE] ; Projectile
Gravity=6.0 ; double
Gravity.HeightFix=false ; boolean
```

## Warheads

### Customizing decloak on damaging targets

- You can now specify whether or not the warhead decloaks objects that are damaged by the warhead.

In `rulesmd.ini`:
```ini
[SOMEWARHEAD] ; WarheadType
DecloakDamagedTargets=true ; boolean
```
4 changes: 3 additions & 1 deletion docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ HitAnim= ; animation
BreakWeapon= ; WeaponType
AbsorbPercent=1.0 ; double, percents
PassPercent=0.0 ; double, percents

AllowTransfer= ; boolean

[SOMETECHNO] ; TechnoType
ShieldType=SOMESHIELDTYPE ; ShieldType; none by default

Expand Down Expand Up @@ -85,6 +86,7 @@ Shield.InheritStateOnReplace=false ; boolean
- `BreakWeapon`, if set, will be fired at the TechnoType once the shield breaks.
- `AbsorbPercent` controls the percentage of damage that will be absorbed by the shield. Defaults to 1.0, meaning full damage absorption.
- `PassPercent` controls the percentage of damage that will *not* be absorbed by the shield, and will be dealt to the unit directly even if the shield is active. Defaults to 0.0 - no penetration.
- `AllowTransfer` controls whether or not the shield can be transferred if the TechnoType changes (such as `(Un)DeploysInto` or Ares type conversion). If not set, defaults to true if shield was attached via `Shield.AttachTypes`, otherwise false.
- A TechnoType with a shield will show its shield Strength. An empty shield strength bar will be left after destroyed if it is respawnable.
- Buildings now use the 5th frame of `pips.shp` to display the shield strength while other units uses the 16th frame by default.
- `Pips.Shield` can be used to specify which pip frame should be used as shield strength. If only 1 digit set, then it will always display it, or if 3 digits set, it will respect `ConditionYellow` and `ConditionRed`. `Pips.Shield.Building` is used for BuildingTypes.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ New:
- IsSimpleDeployer deploy direction & animation customizations (by Starkku)
- Customizable projectile gravity (by secsome)
- Gates can now link with walls correctly via `NSGates` or `EWGates` (by Uranusian)
- Per-warhead toggle for decloak of damaged targets (by Starkku)

Vanilla fixes:
- Fixed laser drawing code to allow for thicker lasers in house color draw mode (by Kerbiter, ChrisLv_CN)
Expand Down
6 changes: 6 additions & 0 deletions src/Ext/Techno/Hooks.Shield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ DEFINE_HOOK(0x6F9E50, TechnoClass_AI_Shield, 0x5)
{
GET(TechnoClass*, pThis, ECX);
const auto pExt = TechnoExt::ExtMap.Find(pThis);
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());

// Set current shield type if it is not set.
if (!pExt->CurrentShieldType->Strength && pTypeExt->ShieldType->Strength)
pExt->CurrentShieldType = pTypeExt->ShieldType;

// Create shield class instance if it does not exist.
if (pExt->CurrentShieldType && pExt->CurrentShieldType->Strength && !pExt->Shield)
pExt->Shield = std::make_unique<ShieldClass>(pThis);

Expand Down
14 changes: 14 additions & 0 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,18 @@ DEFINE_HOOK(0x6FE19A, TechnoClass_FireAt_AreaFire, 0x6)
}

return 0;
}

DEFINE_HOOK(0x702819, TechnoClass_ReceiveDamage_Decloak, 0xA)
{
GET(TechnoClass* const, pThis, ESI);
GET_STACK(WarheadTypeClass*, pWarhead, STACK_OFFS(0xC4, -0xC));

if (auto pExt = WarheadTypeExt::ExtMap.Find(pWarhead))
{
if (pExt->DecloakDamagedTargets)
pThis->Uncloak(false);
}

return 0x702823;
}
3 changes: 3 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->RemoveDisguise.Read(exINI, pSection, "RemoveDisguise");
this->RemoveMindControl.Read(exINI, pSection, "RemoveMindControl");
this->AnimList_PickRandom.Read(exINI, pSection, "AnimList.PickRandom");
this->DecloakDamagedTargets.Read(exINI, pSection, "DecloakDamagedTargets");

// Crits
this->Crit_Chance.Read(exINI, pSection, "Crit.Chance");
Expand Down Expand Up @@ -106,6 +107,8 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)

.Process(this->AnimList_PickRandom)

.Process(this->DecloakDamagedTargets)

.Process(this->Crit_Chance)
.Process(this->Crit_ExtraDamage)
.Process(this->Crit_Affects)
Expand Down
6 changes: 4 additions & 2 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class WarheadTypeExt
Valueable<bool> RemoveDisguise;
Valueable<bool> RemoveMindControl;
Valueable<bool> AnimList_PickRandom;
Valueable<bool> DecloakDamagedTargets;

Valueable<int> Crit_ExtraDamage;
Valueable<double> Crit_Chance;
Expand Down Expand Up @@ -54,7 +55,7 @@ class WarheadTypeExt
Valueable<int> Shield_Respawn_Rate;
Valueable<bool> Shield_Respawn_ResetTimer;
Valueable<int> Shield_SelfHealing_Duration;
Valueable<double> Shield_SelfHealing_Amount;
Nullable<double> Shield_SelfHealing_Amount;
Valueable<int> Shield_SelfHealing_Rate;
Valueable<bool> Shield_SelfHealing_ResetTimer;

Expand All @@ -79,6 +80,7 @@ class WarheadTypeExt
, RemoveDisguise { false }
, RemoveMindControl { false }
, AnimList_PickRandom { false }
, DecloakDamagedTargets { true }

, Crit_Chance { 0.0 }
, Crit_ExtraDamage { 0 }
Expand All @@ -105,7 +107,7 @@ class WarheadTypeExt
, Shield_Respawn_Rate_InMinutes { -1.0 }
, Shield_Respawn_ResetTimer { false }
, Shield_SelfHealing_Duration { 0 }
, Shield_SelfHealing_Amount { 0.0 }
, Shield_SelfHealing_Amount { }
, Shield_SelfHealing_Rate { -1 }
, Shield_SelfHealing_Rate_InMinutes { -1.0 }
, Shield_SelfHealing_ResetTimer { false }
Expand Down
9 changes: 6 additions & 3 deletions src/Ext/WarheadType/Detonate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ void WarheadTypeExt::ExtData::ApplyShieldModifiers(TechnoClass* pTarget)
if (shieldIndex >= 0)
{
ratio = pExt->Shield->GetHealthRatio();
pExt->CurrentShieldType = ShieldTypeClass::FindOrAllocate(NONE_STR);
pExt->Shield->KillAnim();
pExt->Shield = nullptr;
pExt->CurrentShieldType = nullptr;
}
}

Expand All @@ -128,7 +128,7 @@ void WarheadTypeExt::ExtData::ApplyShieldModifiers(TechnoClass* pTarget)
if (shieldType->Strength && (!pExt->Shield || (this->Shield_ReplaceNonRespawning && pExt->Shield->IsBrokenAndNonRespawning())))
{
pExt->CurrentShieldType = shieldType;
pExt->Shield = std::make_unique<ShieldClass>(pTarget);
pExt->Shield = std::make_unique<ShieldClass>(pTarget, true);

if (this->Shield_ReplaceOnly && this->Shield_InheritStateOnReplace)
{
Expand All @@ -154,7 +154,10 @@ void WarheadTypeExt::ExtData::ApplyShieldModifiers(TechnoClass* pTarget)
pExt->Shield->SetRespawn(this->Shield_Respawn_Duration, this->Shield_Respawn_Amount, this->Shield_Respawn_Rate, this->Shield_Respawn_ResetTimer);

if (this->Shield_SelfHealing_Duration > 0)
pExt->Shield->SetSelfHealing(this->Shield_SelfHealing_Duration, this->Shield_SelfHealing_Amount, this->Shield_SelfHealing_Rate, this->Shield_SelfHealing_ResetTimer);
{
double amount = this->Shield_SelfHealing_Amount.Get(pExt->Shield->GetType()->SelfHealing);
pExt->Shield->SetSelfHealing(this->Shield_SelfHealing_Duration, amount, this->Shield_SelfHealing_Rate, this->Shield_SelfHealing_ResetTimer);
}
}
}
}
Expand Down
67 changes: 49 additions & 18 deletions src/New/Entity/ShieldClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ ShieldClass::ShieldClass() : Techno { nullptr }
, Timers { }
{ }

ShieldClass::ShieldClass(TechnoClass* pTechno) : Techno { pTechno }
ShieldClass::ShieldClass(TechnoClass* pTechno, bool isAttached) : Techno { pTechno }
, IdleAnim { nullptr }
, Timers { }
, Cloak { false }
, Online { true }
, Temporal { false }
, Available { true }
, Attached { isAttached }
, SelfHealing_Rate_Warhead { -1 }
, Respawn_Rate_Warhead { -1 }
{
Expand Down Expand Up @@ -52,6 +53,7 @@ bool ShieldClass::Serialize(T& Stm)
.Process(this->Online)
.Process(this->Temporal)
.Process(this->Available)
.Process(this->Attached)
.Process(this->Type)
.Process(this->SelfHealing_Warhead)
.Process(this->SelfHealing_Rate_Warhead)
Expand All @@ -78,6 +80,7 @@ void ShieldClass::SyncShieldToAnother(TechnoClass* pFrom, TechnoClass* pTo)

if (pFromExt->Shield)
{
pToExt->CurrentShieldType = pFromExt->CurrentShieldType;
pToExt->Shield = std::make_unique<ShieldClass>(pTo);
strcpy(pToExt->Shield->TechnoID, pFromExt->Shield->TechnoID);
pToExt->Shield->Available = pFromExt->Shield->Available;
Expand Down Expand Up @@ -125,6 +128,9 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args)
this->Timers.SelfHealing.Start(rate); // when attacked, restart the timer
this->ResponseAttack();

if (pWHExt->DecloakDamagedTargets)
this->Techno->Uncloak(false);

int residueDamage = shieldDamage - this->HP;
if (residueDamage >= 0)
{
Expand Down Expand Up @@ -260,9 +266,11 @@ void ShieldClass::AI()
}
}

if (this->ConvertCheck())
return;

this->UpdateType();
this->CloakCheck();
this->ConvertCheck();

if (!this->Available)
return;
Expand Down Expand Up @@ -365,33 +373,50 @@ void ShieldClass::TemporalCheck()
}

// Is used for DeploysInto/UndeploysInto and DeploysInto/UndeploysInto
void ShieldClass::ConvertCheck()
bool ShieldClass::ConvertCheck()
{
const auto newID = this->Techno->get_ID();

if (strcmp(this->TechnoID, newID) == 0)
return;
return false;

const auto pType = this->Type;
const auto pTechnoExt = TechnoExt::ExtMap.Find(this->Techno);
const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(this->Techno->GetTechnoType());
const auto pOldType = this->Type;
bool allowTransfer = this->Type->AllowTransfer.Get(Attached);

if (pType->Strength && this->Available)
{ // Update this shield for the new owner
const auto pFrom_TechnoType = TechnoTypeClass::Find(this->TechnoID);
const auto pFromType = TechnoTypeExt::ExtMap.Find(pFrom_TechnoType)->ShieldType;
// Update shield type.
if (!allowTransfer && !pTechnoTypeExt->ShieldType->Strength)
{
this->KillAnim();
pTechnoExt->CurrentShieldType = ShieldTypeClass::FindOrAllocate(NONE_STR);
pTechnoExt->Shield = nullptr;

if (pFromType->IdleAnim.Get() != pType->IdleAnim.Get())
return true;
}
else if (pTechnoTypeExt->ShieldType->Strength)
{
pTechnoExt->CurrentShieldType = pTechnoTypeExt->ShieldType;
}

const auto pNewType = pTechnoExt->CurrentShieldType;

// Update shield properties.
if (pNewType->Strength && this->Available)
{
if (pOldType->IdleAnim.Get() != pNewType->IdleAnim.Get())
this->KillAnim();

this->HP = (int)round(
(double)this->HP /
(double)pFromType->Strength *
(double)pType->Strength
(double)pOldType->Strength *
(double)pNewType->Strength
);
}
else
{
const auto timer = (this->HP <= 0) ? &this->Timers.Respawn : &this->Timers.SelfHealing;
if (pType->Strength && !this->Available)
if (pNewType->Strength && !this->Available)
{ // Resume this shield when became Available
timer->Resume();
this->Available = true;
Expand All @@ -405,6 +430,8 @@ void ShieldClass::ConvertCheck()
}

strcpy(this->TechnoID, newID);

return false;
}

void ShieldClass::SelfHealing()
Expand All @@ -424,7 +451,7 @@ void ShieldClass::SelfHealing()
const int rate = timerWH->InProgress() ? this->SelfHealing_Rate_Warhead : pType->SelfHealing_Rate;
const auto percentageAmount = this->GetPercentageAmount(amount);

if (percentageAmount > 0)
if (percentageAmount != 0)
{
if (this->HP < this->Type->Strength && timer->StartTime == -1)
timer->Start(rate);
Expand All @@ -439,6 +466,10 @@ void ShieldClass::SelfHealing()
this->HP = pType->Strength;
timer->Stop();
}
else if (this->HP <= 0)
{
BreakShield();
}
}
}
}
Expand Down Expand Up @@ -514,11 +545,11 @@ void ShieldClass::SetRespawn(int duration, double amount, int rate, bool resetTi

this->Respawn_Warhead = amount > 0 ? amount : Type->Respawn;
this->Respawn_Rate_Warhead = rate >= 0 ? rate : Type->Respawn_Rate;

timerWH->Start(duration);

if (this->HP <= 0 && Respawn_Rate_Warhead >= 0 && (resetTimer || timer->Expired()))
{
if (this->HP <= 0 && Respawn_Rate_Warhead >= 0 && (resetTimer || timer->Expired()))
{
timer->Start(Respawn_Rate_Warhead);
}
else if (timer->InProgress())
Expand All @@ -534,7 +565,7 @@ void ShieldClass::SetSelfHealing(int duration, double amount, int rate, bool res
auto timer = &this->Timers.SelfHealing;
auto timerWH = &this->Timers.SelfHealing_Warhead;

this->SelfHealing_Warhead = amount > 0 ? amount : Type->SelfHealing;
this->SelfHealing_Warhead = amount;
this->SelfHealing_Rate_Warhead = rate >= 0 ? rate : Type->SelfHealing_Rate;

timerWH->Start(duration);
Expand Down
6 changes: 4 additions & 2 deletions src/New/Entity/ShieldClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class ShieldClass
{
public:
ShieldClass();
ShieldClass(TechnoClass* pTechno);
ShieldClass(TechnoClass* pTechno, bool isAttached);
ShieldClass(TechnoClass* pTechno) : ShieldClass(pTechno, false) {};
~ShieldClass() = default;

int ReceiveDamage(args_ReceiveDamage* args);
Expand Down Expand Up @@ -61,7 +62,7 @@ class ShieldClass
void CloakCheck();
void OnlineCheck();
void TemporalCheck();
void ConvertCheck();
bool ConvertCheck();

void DrawShieldBar_Building(int iLength, Point2D* pLocation, RectangleStruct* pBound);
void DrawShieldBar_Other(int iLength, Point2D* pLocation, RectangleStruct* pBound);
Expand All @@ -77,6 +78,7 @@ class ShieldClass
bool Online;
bool Temporal;
bool Available;
bool Attached;

double SelfHealing_Warhead;
int SelfHealing_Rate_Warhead;
Expand Down
3 changes: 3 additions & 0 deletions src/New/Type/ShieldTypeClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ void ShieldTypeClass::LoadFromINI(CCINIClass* pINI)

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

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

template <typename T>
Expand All @@ -71,6 +73,7 @@ void ShieldTypeClass::Serialize(T& Stm)
.Process(this->BreakWeapon)
.Process(this->AbsorbPercent)
.Process(this->PassPercent)
.Process(this->AllowTransfer)
;
}

Expand Down
2 changes: 2 additions & 0 deletions src/New/Type/ShieldTypeClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
Valueable<double> AbsorbPercent;
Valueable<double> PassPercent;

Nullable<bool> AllowTransfer;
private:
Valueable<double> Respawn_Rate__InMinutes;
Valueable<double> SelfHealing_Rate__InMinutes;
Expand All @@ -55,6 +56,7 @@ class ShieldTypeClass final : public Enumerable<ShieldTypeClass>
, PassPercent(0.0)
, Respawn_Rate__InMinutes(0.0)
, SelfHealing_Rate__InMinutes(0.0)
, AllowTransfer()
{};

virtual ~ShieldTypeClass() override = default;
Expand Down