diff --git a/CREDITS.md b/CREDITS.md index f88715bcb3..5fd1d7b462 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -293,6 +293,7 @@ This page lists all the individual contributions to the project by their author. - GapGen + SpySat desync fix - Frame CRC generation rewrite - Laser drawing Z-adjust customization + - `ProjectileRange` weapon range modifiers interaction fix - **Morton (MortonPL)**: - `XDrawOffset` for animations - Shield passthrough & absorption diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index e87e8d0a93..445ec165a4 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -377,6 +377,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho - `EVA.Tag` already supports being set for specific countries, and `EVAIndex` is no longer reset after load game. - `DisableWeapons.Duration` now makes `Gattling=yes` rate tick down and stops the sounds from playing, no longer interferes with target acquisition and works together with Phobos' `OpenTopped.CheckTransportDisableWeapons`. - Allowed Ares' `SW.AuxBuildings` and `SW.NegBuildings` to count building upgrades. +- `ProjectileRange` now has weapon range modifiers applied to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is set to false on the WeaponType ## Newly added global settings diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 26dac9cde1..ac31c831b5 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -29,6 +29,7 @@ This serves as a changelog for when you just need to drop the new version in wit ### Version TBD (develop branch nightly builds) +- `ProjectileRange` (Ares feature) now has weapon range modifiers applied to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is set to false on the WeaponType. - `Splits.TargetCellRange` < 0 now applies special behaviour where the projectile does not consider nearby cells as additional targets if there are not enough techno targets to match `Cluster` count at all. - Combat light customizations introduced a bug that removed vanilla behaviour of ignoring detail level / framerate checks for colored combat light. This bug has been fixed but the previous behaviour can be restored by setting `CombatLightDetailLevel.CheckColored` on Warhead or globally under `[AudioVisual]`. - `[TechnoType] -> WarpAway=` has now been changed to set the animation when units are erased to maintain semantic consistency with `[General] -> WarpAway=`. The animation that was originally controlled by `[TechnoType] -> WarpAway=`, which played instead of `[General] -> WarpOut=` when a Techno is chronowarped by chronosphere, now needs to be specified using `[TechnoType] -> Chronoshift.WarpOut=`, which defaults to the value of `[TechnoType] -> WarpOut=`. @@ -732,6 +733,7 @@ HideShakeEffects=false ; boolean - `DisableWeapons.Duration` now makes `Gattling=yes` rate tick down and stops the sounds from playing, no longer interferes with target acquisition and works together with Phobos' `OpenTopped.CheckTransportDisableWeapons` (by Starkku) - Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades (by Ollerus & NetsuNegi) - [Aux technos and TechLevel requirement of superweapon](New-or-Enhanced-Logics.md#aux-technos-and-techlevel-requirement-of-superweapon) (by NetsuNegi & Ollerus) +- `ProjectileRange` now has weapon range modifiers applied to it if greater than 0 and unless `ProjectileRange.ApplyModifiers` is set to false on the WeaponType (by Starkku) ``` ### 0.4.0.3 diff --git a/src/Ext/Bullet/Body.cpp b/src/Ext/Bullet/Body.cpp index 73aa3a2077..6d93fe9552 100644 --- a/src/Ext/Bullet/Body.cpp +++ b/src/Ext/Bullet/Body.cpp @@ -446,6 +446,7 @@ void BulletExt::ExtData::Serialize(T& Stm) .Process(this->DamageNumberOffset) .Process(this->ParabombFallRate) .Process(this->IsInstantDetonation) + .Process(this->DistanceTraveled) .Process(this->Trajectory) // Keep this shit at last ; diff --git a/src/Ext/Bullet/Body.h b/src/Ext/Bullet/Body.h index 7b458e51b2..65d475ae9a 100644 --- a/src/Ext/Bullet/Body.h +++ b/src/Ext/Bullet/Body.h @@ -27,6 +27,7 @@ class BulletExt int DamageNumberOffset; int ParabombFallRate; bool IsInstantDetonation; + int DistanceTraveled; TrajectoryPointer Trajectory; @@ -43,6 +44,7 @@ class BulletExt , DamageNumberOffset { INT32_MIN } , ParabombFallRate { 0 } , IsInstantDetonation { false } + , DistanceTraveled { 0 } { } virtual ~ExtData() = default; diff --git a/src/Ext/Bullet/Hooks.cpp b/src/Ext/Bullet/Hooks.cpp index 340f3e2fb7..ba5bbf6796 100644 --- a/src/Ext/Bullet/Hooks.cpp +++ b/src/Ext/Bullet/Hooks.cpp @@ -600,3 +600,30 @@ DEFINE_HOOK(0x467AB2, BulletClass_AI_Parabomb, 0x7) } #pragma endregion + +// Replaces Ares' handling of Ranged=true projectiles. +DEFINE_HOOK(0x467BA4, BulletClass_AI_Ranged, 0x6) +{ + GET(BulletClass*, pThis, EBP); + REF_STACK(CoordStruct, coordNew, STACK_OFFSET(0x1A8, -0x184)); + REF_STACK(bool, shouldExplode, STACK_OFFSET(0x1A8, -0x190)); + + if (pThis->Type->Ranged) + { + auto const pExt = BulletExt::ExtMap.Find(pThis); + pExt->DistanceTraveled += Game::F2I(coordNew.DistanceFrom(pThis->GetCoords())); + int maxRange = pThis->Range; + + if (maxRange > 0 && pThis->WeaponType && pThis->Owner + && WeaponTypeExt::ExtMap.Find(pThis->WeaponType)->ProjectileRange_ApplyModifiers) + { + maxRange = WeaponTypeExt::GetRangeWithModifiers(pThis->WeaponType, pThis->Owner, maxRange); + } + + shouldExplode |= pExt->DistanceTraveled >= maxRange; + } + + pThis->SetLocation(coordNew); + + return 0; +} diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index f98678cfdc..f34e566dac 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -81,6 +81,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->DiskLaser_Radius.Read(exINI, pSection, "DiskLaser.Radius"); this->ProjectileRange.Read(exINI, pSection, "ProjectileRange"); + this->ProjectileRange_ApplyModifiers.Read(exINI, pSection, "ProjectileRange.ApplyModifiers"); for (int idx = 0; idx < 3; ++idx) { @@ -190,6 +191,7 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm) Stm .Process(this->DiskLaser_Radius) .Process(this->ProjectileRange) + .Process(this->ProjectileRange_ApplyModifiers) .Process(this->Bolt_Color) .Process(this->Bolt_Disable) .Process(this->Bolt_ParticleSystem) @@ -376,7 +378,7 @@ int WeaponTypeExt::GetRangeWithModifiers(WeaponTypeClass* pThis, TechnoClass* pF if (type->WeaponRange_DisallowWeapons.size() > 0 && type->WeaponRange_DisallowWeapons.Contains(pThis)) continue; - range = static_cast(range * Math::max(type->WeaponRange_Multiplier, 0.0)); + range = GeneralUtils::SafeMultiply(range, Math::max(type->WeaponRange_Multiplier, 0.0)); extraRange += type->WeaponRange_ExtraRange; } diff --git a/src/Ext/WeaponType/Body.h b/src/Ext/WeaponType/Body.h index 5bb8734a4b..572888097f 100644 --- a/src/Ext/WeaponType/Body.h +++ b/src/Ext/WeaponType/Body.h @@ -19,6 +19,7 @@ class WeaponTypeExt Valueable DiskLaser_Radius; Valueable ProjectileRange; + Valueable ProjectileRange_ApplyModifiers; Valueable RadType; Nullable Bolt_Color[3]; Valueable Bolt_Disable[3]; @@ -108,6 +109,7 @@ class WeaponTypeExt ExtData(WeaponTypeClass* OwnerObject) : Extension(OwnerObject) , DiskLaser_Radius { DiskLaserClass::Radius } , ProjectileRange { Leptons(100000) } + , ProjectileRange_ApplyModifiers { true } , RadType {} , Bolt_Color {} , Bolt_Disable { Valueable(false) } diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp index 197061c6da..983fd62f4d 100644 --- a/src/Misc/Hooks.Ares.cpp +++ b/src/Misc/Hooks.Ares.cpp @@ -203,6 +203,9 @@ void Apply_Ares3_0_Patches() // Fix building direction of Ares's UnitDelivery Patch::Apply_VTABLE(AresHelper::AresBaseAddress + 0xA8D94, &UnitDeliveryStateMachine_Update_Wrapper); + + // Skip Ares' ProjectileRange handling - our replacement hooked at 0x467BA4 (BulletClass_AI_Ranged). + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x1ACA3, AresHelper::AresBaseAddress + 0x1AD20); } void Apply_Ares3_0p1_Patches() @@ -289,4 +292,7 @@ void Apply_Ares3_0p1_Patches() // Fix building direction of Ares's UnitDelivery Patch::Apply_VTABLE(AresHelper::AresBaseAddress + 0xA9F28, &UnitDeliveryStateMachine_Update_Wrapper); + + // Skip Ares' ProjectileRange handling - our replacement hooked at 0x467BA4 (BulletClass_AI_Ranged). + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x1B393, AresHelper::AresBaseAddress + 0x1B410); }