From af4bc337006c83a11e91c629f80485d74c6d9143 Mon Sep 17 00:00:00 2001 From: Starkku Date: Wed, 19 Jan 2022 15:22:18 +0200 Subject: [PATCH 1/4] Critical damage chance additions - `Crit.AffectBelowPercent` can be used to set maximum percentage of hitpoints targets (if applicable) can have left to be affected. - `Crit.AnimList.PickRandom` determines if a random animation from `Crit.AnimList` is picked or not. Defaults to `AnimList.PickRandom`. - `Crit.AnimOnAffectedTargets`, if set, draws animation on every affected target (randomized separately every time if `Crit.AnimList.PickRandom` is in effect) instead of once at Warhead's impact location if critical damage chance roll was successful. --- README.md | 2 +- docs/New-or-Enhanced-Logics.md | 19 +++++++++++-------- docs/Whats-New.md | 1 + src/Ext/WarheadType/Body.cpp | 6 ++++++ src/Ext/WarheadType/Body.h | 6 ++++++ src/Ext/WarheadType/Detonate.cpp | 11 +++++++++++ src/Ext/WarheadType/Hooks.cpp | 4 ++-- 7 files changed, 38 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4e1c7ff8cf..88363c887e 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,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, Warhead decloaking toggle, Warp(In/Out)Weapon, Grinder improvements / additions, Attached animation position customization +- **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, Warp(In/Out)Weapon, Grinder improvements / additions, Attached animation position customization, Critical damage additions - **SukaHati (Erzoid)** - Minimum interceptor guard range - **Morton (MortonPL)** - XDrawOffset, Shield passthrough & absorption, building LimboDelivery, fix for Image in art rules, power delta counter - **mevitar** - honorary shield tester *triple* award diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 0359ced4ef..6b1bbaad3f 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -611,18 +611,21 @@ RemoveMindControl=no ; boolean ### Critical damage chance -- Warheads can now apply additional chance-based damage (known as "critical" damage) with the ability to customize chance, damage, affected targets, and animations of critical strike. +- Warheads can now apply additional chance-based damage (known as "critical" damage) with the ability to customize chance, damage, affected targets, affected target HP threshold and animations of critical strike. In `rulesmd.ini`: ```ini -[SOMEWARHEAD] ; Warhead -Crit.Chance=0.0 ; float, chance on [0.0-1.0] scale -Crit.ExtraDamage=0 ; integer, extra damage -Crit.Affects=all ; list of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all) -Crit.AnimList= ; list of animations +[SOMEWARHEAD] ; Warhead +Crit.Chance=0.0 ; float, chance on [0.0-1.0] scale +Crit.ExtraDamage=0 ; integer, extra damage +Crit.Affects=all ; list of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all) +Crit.AffectBelowPercent=1.0 ; float, maximum percentage of hitpoints targets (if applicable) can have left to be affected. +Crit.AnimList= ; list of animations +Crit.AnimList.PickRandom= ; boolean, pick animation from list by random, defaults to AnimList.PickRandom +Crit.AnimOnAffectedTargets=false ; boolean, if set plays animation on every affected target instead of once at primary target. -[SOMETECHNO] ; TechnoType -ImmuneToCrit=no ; boolean +[SOMETECHNO] ; TechnoType +ImmuneToCrit=no ; boolean ``` ### Custom 'SplashList' on Warheads diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 7205fc38f0..b2767e85c3 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -276,6 +276,7 @@ New: - New ways for self-killing objects under certaing cases (by FS-21) - `ForceWeapon.Naval.Decloacked` for overriding uncloaked underwater attack behavior (by FS-21) - Shared Ammo for transports to passengers (by FS-21) +- Critical damage target HP threshold & additional animation customizations (by Starkku) Vanilla fixes: - Fixed laser drawing code to allow for thicker lasers in house color draw mode (by Kerbiter, ChrisLv_CN) diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 5643af8934..7a408d2442 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -55,6 +55,9 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Crit_ExtraDamage.Read(exINI, pSection, "Crit.ExtraDamage"); this->Crit_Affects.Read(exINI, pSection, "Crit.Affects"); this->Crit_AnimList.Read(exINI, pSection, "Crit.AnimList"); + this->Crit_AnimList_PickRandom.Read(exINI, pSection, "Crit.AnimList.PickRandom"); + this->Crit_AnimOnAffectedTargets.Read(exINI, pSection, "Crit.AnimOnAffectedTargets"); + this->Crit_AffectBelowPercent.Read(exINI, pSection, "Crit.AffectBelowPercent"); this->MindControl_Anim.Read(exINI, pSection, "MindControl.Anim"); @@ -113,6 +116,9 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->Crit_ExtraDamage) .Process(this->Crit_Affects) .Process(this->Crit_AnimList) + .Process(this->Crit_AnimList_PickRandom) + .Process(this->Crit_AnimOnAffectedTargets) + .Process(this->Crit_AffectBelowPercent) .Process(this->MindControl_Anim) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index 720d82a0b1..051d32b632 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -29,6 +29,9 @@ class WarheadTypeExt Valueable Crit_Chance; Valueable Crit_Affects; ValueableVector Crit_AnimList; + Nullable Crit_AnimList_PickRandom; + Valueable Crit_AnimOnAffectedTargets; + Valueable Crit_AffectBelowPercent; Nullable MindControl_Anim; @@ -86,6 +89,9 @@ class WarheadTypeExt , Crit_ExtraDamage { 0 } , Crit_Affects { AffectedTarget::All } , Crit_AnimList {} + , Crit_AnimList_PickRandom {} + , Crit_AnimOnAffectedTargets { false } + , Crit_AffectBelowPercent { 1.0 } , RandomBuffer { 0.0 } , MindControl_Anim {} diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index 3d8a9aa359..67e2086cb6 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -190,6 +190,9 @@ void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget { if (pTypeExt->ImmuneToCrit) return; + + if (pTarget->GetHealthPercentage() > this->Crit_AffectBelowPercent) + return; } if (!EnumFunctions::IsCellEligible(pTarget->GetCell(), this->Crit_Affects)) @@ -198,6 +201,14 @@ void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget if (!EnumFunctions::IsTechnoEligible(pTarget, this->Crit_Affects)) return; + if (this->Crit_AnimOnAffectedTargets && this->Crit_AnimList.size()) + { + int idx = this->OwnerObject()->EMEffect || this->Crit_AnimList_PickRandom.Get(this->AnimList_PickRandom) ? + ScenarioClass::Instance->Random.RandomRanged(0, this->Crit_AnimList.size() - 1) : 0; + + GameCreate(this->Crit_AnimList[idx], pTarget->Location); + } + auto Damage = this->Crit_ExtraDamage.Get(); pTarget->ReceiveDamage(&Damage, 0, this->OwnerObject(), pOwner, false, false, pHouse); diff --git a/src/Ext/WarheadType/Hooks.cpp b/src/Ext/WarheadType/Hooks.cpp index 8a1db378e3..5ab01ba777 100644 --- a/src/Ext/WarheadType/Hooks.cpp +++ b/src/Ext/WarheadType/Hooks.cpp @@ -92,10 +92,10 @@ DEFINE_HOOK(0x48A5B3, WarheadTypeClass_AnimList_CritAnim, 0x6) GET(WarheadTypeClass* const, pThis, ESI); auto pWHExt = WarheadTypeExt::ExtMap.Find(pThis); - if (pWHExt && !(pWHExt->Crit_Chance < pWHExt->RandomBuffer) && pWHExt->Crit_AnimList.size()) + if (pWHExt && !(pWHExt->Crit_Chance < pWHExt->RandomBuffer) && pWHExt->Crit_AnimList.size() && !pWHExt->Crit_AnimOnAffectedTargets) { GET(int, nDamage, ECX); - int idx = pThis->EMEffect || pWHExt->AnimList_PickRandom ? + int idx = pThis->EMEffect || pWHExt->Crit_AnimList_PickRandom.Get(pWHExt->AnimList_PickRandom) ? ScenarioClass::Instance->Random.RandomRanged(0, pWHExt->Crit_AnimList.size() - 1) : std::min(pWHExt->Crit_AnimList.size() * 25 - 1, (size_t)nDamage) / 25; R->EAX(pWHExt->Crit_AnimList[idx]); From 7fc9050d26e4fe8e1245d763a9e53bec6eb673b7 Mon Sep 17 00:00:00 2001 From: Starkku Date: Sat, 29 Jan 2022 23:23:12 +0200 Subject: [PATCH 2/4] Add Crit.Warhead --- docs/New-or-Enhanced-Logics.md | 3 ++- src/Ext/WarheadType/Body.cpp | 2 ++ src/Ext/WarheadType/Body.h | 2 ++ src/Ext/WarheadType/Detonate.cpp | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 6b1bbaad3f..f465930ad0 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -611,13 +611,14 @@ RemoveMindControl=no ; boolean ### Critical damage chance -- Warheads can now apply additional chance-based damage (known as "critical" damage) with the ability to customize chance, damage, affected targets, affected target HP threshold and animations of critical strike. +- Warheads can now apply additional chance-based damage (known as "critical" damage) with the ability to customize chance, damage, warhead, affected targets, affected target HP threshold and animations of critical strike. In `rulesmd.ini`: ```ini [SOMEWARHEAD] ; Warhead Crit.Chance=0.0 ; float, chance on [0.0-1.0] scale Crit.ExtraDamage=0 ; integer, extra damage +Crit.Warhead= ; Warhead, used for applying the damage, current warhead is used if not set. Crit.Affects=all ; list of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all) Crit.AffectBelowPercent=1.0 ; float, maximum percentage of hitpoints targets (if applicable) can have left to be affected. Crit.AnimList= ; list of animations diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 7a408d2442..be494dcd00 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -53,6 +53,7 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) // Crits this->Crit_Chance.Read(exINI, pSection, "Crit.Chance"); this->Crit_ExtraDamage.Read(exINI, pSection, "Crit.ExtraDamage"); + this->Crit_Warhead.Read(exINI, pSection, "Crit.Warhead"); this->Crit_Affects.Read(exINI, pSection, "Crit.Affects"); this->Crit_AnimList.Read(exINI, pSection, "Crit.AnimList"); this->Crit_AnimList_PickRandom.Read(exINI, pSection, "Crit.AnimList.PickRandom"); @@ -114,6 +115,7 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->Crit_Chance) .Process(this->Crit_ExtraDamage) + .Process(this->Crit_Warhead) .Process(this->Crit_Affects) .Process(this->Crit_AnimList) .Process(this->Crit_AnimList_PickRandom) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index 051d32b632..72f5ddecec 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -26,6 +26,7 @@ class WarheadTypeExt Valueable DecloakDamagedTargets; Valueable Crit_ExtraDamage; + Nullable Crit_Warhead; Valueable Crit_Chance; Valueable Crit_Affects; ValueableVector Crit_AnimList; @@ -87,6 +88,7 @@ class WarheadTypeExt , Crit_Chance { 0.0 } , Crit_ExtraDamage { 0 } + , Crit_Warhead {} , Crit_Affects { AffectedTarget::All } , Crit_AnimList {} , Crit_AnimList_PickRandom {} diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index 67e2086cb6..dc3399a8c3 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -211,5 +211,5 @@ void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget auto Damage = this->Crit_ExtraDamage.Get(); - pTarget->ReceiveDamage(&Damage, 0, this->OwnerObject(), pOwner, false, false, pHouse); + pTarget->ReceiveDamage(&Damage, 0, this->Crit_Warhead.Get(this->OwnerObject()), pOwner, false, false, pHouse); } \ No newline at end of file From 45a2ec567ec0e40be3dd69658878782942642953 Mon Sep 17 00:00:00 2001 From: Starkku Date: Thu, 3 Mar 2022 23:40:29 +0200 Subject: [PATCH 3/4] Further changes / additions. - Add `Crit.ApplyChancePerTarget`, which if set makes critical hit chance determined individually for each target. - Changed behaviour for `Crit.Warhead` - if set it now fully detonates the warhead, if not then it only deals damage with current warhead like before. - Improved documentation. --- README.md | 4 ++-- docs/New-or-Enhanced-Logics.md | 21 +++++++++++-------- docs/Whats-New.md | 2 +- src/Ext/BulletType/Body.cpp | 10 +++++++++ src/Ext/BulletType/Body.h | 1 + src/Ext/WarheadType/Body.cpp | 35 ++++++++++++++++++++++++++++++++ src/Ext/WarheadType/Body.h | 9 +++++++- src/Ext/WarheadType/Detonate.cpp | 18 ++++++++++++---- src/Ext/WarheadType/Hooks.cpp | 2 +- src/Ext/WeaponType/Body.h | 1 - 10 files changed, 85 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 88363c887e..7e5ae8b2a8 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,11 @@ Credits - **Otamaa (Fahroni, BoredEXE)** - help with CellSpread, ported and fixed custom RadType code, togglable ElectricBolt bolts, customizable Chrono Locomotor properties per TechnoClass, DebrisMaximums fixes, Anim-to-Unit, NotHuman anim sequences improvements, Customizable OpenTopped Properties, hooks for ScriptType Actions 92 & 93, ore stage threshold for `HideIfNoOre`, occupied building `MuzzleFlashX` bugfix,`EnemyUIName=` for other TechnoTypes, TerrainType `DestroyAnim` & `DestroySound` - **E1 Elite** - TileSet 255 and above bridge repair fix - **FS-21** - Dump Object Info enhancements, Powered.KillSpawns, Spawner.LimitRange, ScriptType Actions 71 to 113, MC deployer fixes, help with docs, Automatic Passenger Deletion, Fire SW At Location Trigger Action, Fire SW At Waypoint Trigger Action, Kill Object Automatically, Customize resource storage, Override Uncloaked Underwater attack behavior, AI Aircraft docks fix, Shared Ammo -- **AutoGavy** - interceptor logic, warhead critical damage system, Customize resource storage +- **AutoGavy** - interceptor logic, Warhead critical hit logic, Customize resource storage - **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, Warhead decloaking toggle, Warp(In/Out)Weapon, Grinder improvements / additions, Attached animation position customization, Critical damage additions +- **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, Warp(In/Out)Weapon, Grinder improvements / additions, Attached animation position customization, Critical hit logic additions - **SukaHati (Erzoid)** - Minimum interceptor guard range - **Morton (MortonPL)** - XDrawOffset, Shield passthrough & absorption, building LimboDelivery, fix for Image in art rules, power delta counter - **mevitar** - honorary shield tester *triple* award diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f465930ad0..da0b999ccb 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -609,24 +609,29 @@ In `rulesmd.ini`: RemoveMindControl=no ; boolean ``` -### Critical damage chance +### Chance-based extra damage or Warhead detonation / 'critical hits' -- Warheads can now apply additional chance-based damage (known as "critical" damage) with the ability to customize chance, damage, warhead, affected targets, affected target HP threshold and animations of critical strike. +- Warheads can now apply additional chance-based damage or Warhead detonation ('critical hits') with the ability to customize chance, damage, affected targets, affected target HP threshold and animations of critical hit. In `rulesmd.ini`: ```ini [SOMEWARHEAD] ; Warhead -Crit.Chance=0.0 ; float, chance on [0.0-1.0] scale -Crit.ExtraDamage=0 ; integer, extra damage -Crit.Warhead= ; Warhead, used for applying the damage, current warhead is used if not set. +Crit.Chance=0.0 ; float, chance for critical hit to occur in [0.0-1.0] scale +Crit.ApplyChancePerTarget=false ; boolean, if set to true critical hit chance is determined individually for each target instead of only once when Warhead detonates. +Crit.ExtraDamage=0 ; integer, damage dealt to affected targets. +Crit.Warhead= ; Warhead, if set the warhead is detonated at every affected target instead of simply dealing damage using current warhead. Crit.Affects=all ; list of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all) Crit.AffectBelowPercent=1.0 ; float, maximum percentage of hitpoints targets (if applicable) can have left to be affected. -Crit.AnimList= ; list of animations +Crit.AnimList= ; list of animations to play instead of Warhead's AnimList. Crit.AnimList.PickRandom= ; boolean, pick animation from list by random, defaults to AnimList.PickRandom -Crit.AnimOnAffectedTargets=false ; boolean, if set plays animation on every affected target instead of once at primary target. +Crit.AnimOnAffectedTargets=false ; boolean, if set to true plays animation on every affected target instead of once at primary target. Animation from Warhead's AnimList is also played unlike if this is not set. [SOMETECHNO] ; TechnoType -ImmuneToCrit=no ; boolean +ImmuneToCrit=no ; boolean, whether TechnoType is immune to critical hits. +``` + +```{warning} +If you set `Crit.Warhead` to the same Warhead it is defined on, or create a chain of Warheads with it that loops back to the first one there is a possibility for the game to get stuck in a loop and freeze or crash afterwards. ``` ### Custom 'SplashList' on Warheads diff --git a/docs/Whats-New.md b/docs/Whats-New.md index b2767e85c3..48014d56fa 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -276,7 +276,7 @@ New: - New ways for self-killing objects under certaing cases (by FS-21) - `ForceWeapon.Naval.Decloacked` for overriding uncloaked underwater attack behavior (by FS-21) - Shared Ammo for transports to passengers (by FS-21) -- Critical damage target HP threshold & additional animation customizations (by Starkku) +- Additional critical hit logic customizations (by Starkku) Vanilla fixes: - Fixed laser drawing code to allow for thicker lasers in house color draw mode (by Kerbiter, ChrisLv_CN) diff --git a/src/Ext/BulletType/Body.cpp b/src/Ext/BulletType/Body.cpp index 74b1203235..a10aefe2f7 100644 --- a/src/Ext/BulletType/Body.cpp +++ b/src/Ext/BulletType/Body.cpp @@ -10,6 +10,16 @@ double BulletTypeExt::GetAdjustedGravity(BulletTypeClass* pType) return pType->Floater ? nGravity * 0.5 : nGravity; } +BulletTypeClass* BulletTypeExt::GetDefaultBulletType() +{ + BulletTypeClass* pType = BulletTypeClass::Find(NONE_STR); + + if (pType) + return pType; + + return GameCreate(NONE_STR); +} + // ============================= // load / save diff --git a/src/Ext/BulletType/Body.h b/src/Ext/BulletType/Body.h index b10e54e119..22ac6fc8ac 100644 --- a/src/Ext/BulletType/Body.h +++ b/src/Ext/BulletType/Body.h @@ -55,4 +55,5 @@ class BulletTypeExt static ExtContainer ExtMap; static double GetAdjustedGravity(BulletTypeClass* pType); + static BulletTypeClass* GetDefaultBulletType(); }; diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index be494dcd00..bdf4dbabd8 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -1,7 +1,10 @@ #include "Body.h" +#include #include +#include + template<> const DWORD Extension::Canary = 0x22222222; WarheadTypeExt::ExtContainer WarheadTypeExt::ExtMap; @@ -26,6 +29,36 @@ bool WarheadTypeExt::ExtData::CanTargetHouse(HouseClass* pHouse, TechnoClass* pT return true; } +void WarheadTypeExt::DetonateAt(WarheadTypeClass* pThis, ObjectClass* pTarget, TechnoClass* pOwner, int damage) +{ + BulletTypeClass* pType = BulletTypeExt::GetDefaultBulletType(); + + if (BulletClass* pBullet = pType->CreateBullet(pTarget, pOwner, + damage, pThis, 0, false)) + { + const CoordStruct& coords = pTarget->GetCoords(); + + pBullet->Limbo(); + pBullet->SetLocation(coords); + pBullet->Explode(true); + pBullet->UnInit(); + } +} + +void WarheadTypeExt::DetonateAt(WarheadTypeClass* pThis, const CoordStruct& coords, TechnoClass* pOwner, int damage) +{ + BulletTypeClass* pType = BulletTypeExt::GetDefaultBulletType(); + + if (BulletClass* pBullet = pType->CreateBullet(nullptr, pOwner, + damage, pThis, 0, false)) + { + pBullet->Limbo(); + pBullet->SetLocation(coords); + pBullet->Explode(true); + pBullet->UnInit(); + } +} + // ============================= // load / save @@ -52,6 +85,7 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) // Crits this->Crit_Chance.Read(exINI, pSection, "Crit.Chance"); + this->Crit_ApplyChancePerTarget.Read(exINI, pSection, "Crit.ApplyChancePerTarget"); this->Crit_ExtraDamage.Read(exINI, pSection, "Crit.ExtraDamage"); this->Crit_Warhead.Read(exINI, pSection, "Crit.Warhead"); this->Crit_Affects.Read(exINI, pSection, "Crit.Affects"); @@ -114,6 +148,7 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->DecloakDamagedTargets) .Process(this->Crit_Chance) + .Process(this->Crit_ApplyChancePerTarget) .Process(this->Crit_ExtraDamage) .Process(this->Crit_Warhead) .Process(this->Crit_Affects) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index 72f5ddecec..0da29f3733 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -25,9 +25,10 @@ class WarheadTypeExt Valueable AnimList_PickRandom; Valueable DecloakDamagedTargets; + Valueable Crit_Chance; + Valueable Crit_ApplyChancePerTarget; Valueable Crit_ExtraDamage; Nullable Crit_Warhead; - Valueable Crit_Chance; Valueable Crit_Affects; ValueableVector Crit_AnimList; Nullable Crit_AnimList_PickRandom; @@ -48,6 +49,7 @@ class WarheadTypeExt Nullable Shield_BreakWeapon; double RandomBuffer; + bool HasCrit; Valueable NotHuman_DeathSequence; @@ -87,6 +89,7 @@ class WarheadTypeExt , DecloakDamagedTargets { true } , Crit_Chance { 0.0 } + , Crit_ApplyChancePerTarget { false } , Crit_ExtraDamage { 0 } , Crit_Warhead {} , Crit_Affects { AffectedTarget::All } @@ -95,6 +98,7 @@ class WarheadTypeExt , Crit_AnimOnAffectedTargets { false } , Crit_AffectBelowPercent { 1.0 } , RandomBuffer { 0.0 } + , HasCrit { false } , MindControl_Anim {} @@ -164,4 +168,7 @@ class WarheadTypeExt static ExtContainer ExtMap; static bool LoadGlobals(PhobosStreamReader& Stm); static bool SaveGlobals(PhobosStreamWriter& Stm); + + static void DetonateAt(WarheadTypeClass* pThis, ObjectClass* pTarget, TechnoClass* pOwner, int damage); + static void DetonateAt(WarheadTypeClass* pThis, const CoordStruct& coords, TechnoClass* pOwner, int damage); }; diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index dc3399a8c3..789566760d 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -38,6 +38,7 @@ void WarheadTypeExt::ExtData::Detonate(TechnoClass* pOwner, HouseClass* pHouse, pHouse->TransactMoney(this->TransactMoney); } + this->HasCrit = false; this->RandomBuffer = ScenarioClass::Instance->Random.RandomDouble(); // List all Warheads here that respect CellSpread @@ -180,8 +181,12 @@ void WarheadTypeExt::ExtData::ApplyRemoveDisguiseToInf(HouseClass* pHouse, Techn void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* pOwner) { - //auto& random = ScenarioClass::Instance->Random; - const double dice = this->RandomBuffer; //double(random.RandomRanged(1, 10)) / 10; + double dice; + + if (this->Crit_ApplyChancePerTarget) + dice = ScenarioClass::Instance->Random.RandomDouble(); + else + dice = this->RandomBuffer; if (this->Crit_Chance < dice) return; @@ -201,6 +206,8 @@ void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget if (!EnumFunctions::IsTechnoEligible(pTarget, this->Crit_Affects)) return; + this->HasCrit = true; + if (this->Crit_AnimOnAffectedTargets && this->Crit_AnimList.size()) { int idx = this->OwnerObject()->EMEffect || this->Crit_AnimList_PickRandom.Get(this->AnimList_PickRandom) ? @@ -209,7 +216,10 @@ void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget GameCreate(this->Crit_AnimList[idx], pTarget->Location); } - auto Damage = this->Crit_ExtraDamage.Get(); + auto damage = this->Crit_ExtraDamage.Get(); - pTarget->ReceiveDamage(&Damage, 0, this->Crit_Warhead.Get(this->OwnerObject()), pOwner, false, false, pHouse); + if (this->Crit_Warhead.isset()) + WarheadTypeExt::DetonateAt(this->Crit_Warhead.Get(), pTarget, pOwner, damage); + else + pTarget->ReceiveDamage(&damage, 0, this->OwnerObject(), pOwner, false, false, pHouse); } \ No newline at end of file diff --git a/src/Ext/WarheadType/Hooks.cpp b/src/Ext/WarheadType/Hooks.cpp index 5ab01ba777..0e6f9898d2 100644 --- a/src/Ext/WarheadType/Hooks.cpp +++ b/src/Ext/WarheadType/Hooks.cpp @@ -92,7 +92,7 @@ DEFINE_HOOK(0x48A5B3, WarheadTypeClass_AnimList_CritAnim, 0x6) GET(WarheadTypeClass* const, pThis, ESI); auto pWHExt = WarheadTypeExt::ExtMap.Find(pThis); - if (pWHExt && !(pWHExt->Crit_Chance < pWHExt->RandomBuffer) && pWHExt->Crit_AnimList.size() && !pWHExt->Crit_AnimOnAffectedTargets) + if (pWHExt && pWHExt->HasCrit && pWHExt->Crit_AnimList.size() && !pWHExt->Crit_AnimOnAffectedTargets) { GET(int, nDamage, ECX); int idx = pThis->EMEffect || pWHExt->Crit_AnimList_PickRandom.Get(pWHExt->AnimList_PickRandom) ? diff --git a/src/Ext/WeaponType/Body.h b/src/Ext/WeaponType/Body.h index 3402a7b9c5..575ad47216 100644 --- a/src/Ext/WeaponType/Body.h +++ b/src/Ext/WeaponType/Body.h @@ -77,7 +77,6 @@ class WeaponTypeExt static int nOldCircumference; - static void DetonateAt(WeaponTypeClass* pThis, ObjectClass* pTarget, TechnoClass* pOwner); static void DetonateAt(WeaponTypeClass* pThis, ObjectClass* pTarget, TechnoClass* pOwner, int damage); static void DetonateAt(WeaponTypeClass* pThis, const CoordStruct& coords, TechnoClass* pOwner); From 2ae1f40cd54432f8c60023555e654beee3623327 Mon Sep 17 00:00:00 2001 From: Starkku Date: Fri, 4 Mar 2022 11:11:37 +0200 Subject: [PATCH 4/4] Further clarified documentation. --- docs/New-or-Enhanced-Logics.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index da0b999ccb..892788e2d9 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -612,22 +612,29 @@ RemoveMindControl=no ; boolean ### Chance-based extra damage or Warhead detonation / 'critical hits' - Warheads can now apply additional chance-based damage or Warhead detonation ('critical hits') with the ability to customize chance, damage, affected targets, affected target HP threshold and animations of critical hit. - + - `Crit.Chance` determines chance for a critical hit to occur. By default this is checked once when the Warhead is detonated and every target that is susceptible to critical hits will be affected. If `Crit.ApplyChancePerTarget` is set, then whether or not the chance roll is successful is determined individually for each target. + - `Crit.ExtraDamage` determines the damage dealt by the critical hit. If `Crit.Warhead` is set, the damage is used to detonate the specified Warhead on each affected target, otherwise the damage is directly dealt based on current Warhead's `Verses` settings. + - `Crit.Affects` can be used to customize types of targets that this Warhead can deal critical hits against. + - `Crit.AffectsBelowPercent` can be used to set minimum percentage of their maximum `Strength` that targets must have left to be affected by a critical hit. + - `Crit.AnimList` can be used to set a list of animations used instead of Warhead's `AnimList` if Warhead deals a critical hit to even one target. If `Crit.AnimList.PickRandom` is set (defaults to `AnimList.PickRandom`) then the animation is chosen randomly from the list. + - `Crit.AnimOnAffectedTargets`, if set, makes the animation(s) from `Crit.AnimList` play on each affected target *in addition* to animation from Warhead's `AnimList` playing as normal instead of replacing `AnimList` animation. + - `ImmuneToCrit` can be set on TechnoTypes to make them immune to critical hits. + In `rulesmd.ini`: ```ini [SOMEWARHEAD] ; Warhead -Crit.Chance=0.0 ; float, chance for critical hit to occur in [0.0-1.0] scale -Crit.ApplyChancePerTarget=false ; boolean, if set to true critical hit chance is determined individually for each target instead of only once when Warhead detonates. -Crit.ExtraDamage=0 ; integer, damage dealt to affected targets. -Crit.Warhead= ; Warhead, if set the warhead is detonated at every affected target instead of simply dealing damage using current warhead. +Crit.Chance=0.0 ; float, percents or absolute (0.0-1.0) +Crit.ApplyChancePerTarget=false ; boolean +Crit.ExtraDamage=0 ; integer +Crit.Warhead= ; Warhead Crit.Affects=all ; list of Affected Target Enumeration (none|land|water|empty|infantry|units|buildings|all) -Crit.AffectBelowPercent=1.0 ; float, maximum percentage of hitpoints targets (if applicable) can have left to be affected. -Crit.AnimList= ; list of animations to play instead of Warhead's AnimList. -Crit.AnimList.PickRandom= ; boolean, pick animation from list by random, defaults to AnimList.PickRandom -Crit.AnimOnAffectedTargets=false ; boolean, if set to true plays animation on every affected target instead of once at primary target. Animation from Warhead's AnimList is also played unlike if this is not set. +Crit.AffectBelowPercent=1.0 ; float, percents or absolute (0.0-1.0) +Crit.AnimList= ; list of animations +Crit.AnimList.PickRandom= ; boolean +Crit.AnimOnAffectedTargets=false ; boolean [SOMETECHNO] ; TechnoType -ImmuneToCrit=no ; boolean, whether TechnoType is immune to critical hits. +ImmuneToCrit=no ; boolean ``` ```{warning}