From ec1c16f893cf4189bfc2e137383bb66c2fe7ccee Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Sun, 22 Mar 2026 08:07:15 +0800 Subject: [PATCH 1/4] init --- CREDITS.md | 1 + docs/Fixed-or-Improved-Logics.md | 18 +++++++++ docs/Whats-New.md | 1 + docs/locale/zh_CN/LC_MESSAGES/CREDITS.po | 5 +++ .../LC_MESSAGES/Fixed-or-Improved-Logics.po | 6 +++ docs/locale/zh_CN/LC_MESSAGES/Whats-New.po | 3 ++ src/Ext/Unit/Hooks.Jumpjet.cpp | 39 +++++++++++++++++++ src/Ext/WarheadType/Body.cpp | 22 +++++++++++ src/Ext/WarheadType/Body.h | 22 +++++++++++ src/Ext/WarheadType/Hooks.cpp | 15 +++++++ 10 files changed, 132 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index a9620465ef..d3b3bf0e05 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -513,6 +513,7 @@ This page lists all the individual contributions to the project by their author. - Customize which parasite can remove by warhead - Fix the bug that unit will play crashing voice & sound when dropped by warhead with `IsLocomotor=yes` - Add toggle of whether shield use ArmorMultiplier or not + - Allow customize jumpjet properties on warhead - **Apollo** - Translucent SHP drawing patches - **ststl**: - Customizable `ShowTimer` priority of superweapons diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 487490ccf5..98fc80f2ed 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -2498,6 +2498,24 @@ Parasite.CullingTarget=infantry ; List of Affected Target Enumeration (n Parasite.GrappleAnim= ; AnimationType, default to [AudioVisual] -> Parasite.GrappleAnim ``` +### Customizing locomotor warhead + +- Now you can customize jumpjet properties on warhead. + +In `rulesmd.ini`: +```ini +[SOMEWARHEAD] ; WarheadType +JumpjetTurnRate= ; Integer, default to [TechnoType] -> JumpjetTurnRate +JumpjetSpeed= ; Integer, default to [TechnoType] -> JumpjetSpeed +JumpjetClimb= ; floating point value, default to [TechnoType] -> JumpjetClimb +JumpjetCrash= ; floating point value, default to [TechnoType] -> JumpjetCrash +JumpjetHeight= ; Integer, default to [TechnoType] -> JumpjetHeight +JumpjetAccel= ; floating point value, default to [TechnoType] -> JumpjetAccel +JumpjetWobbles= ; floating point value, default to [TechnoType] -> JumpjetWobbles +JumpjetNoWobbles= ; boolean, default to [TechnoType] -> JumpjetNoWobbles +JumpjetDeviation= ; Integer, default to [TechnoType] -> JumpjetDeviation +``` + ### Dehardcode the `ZAdjust` of warhead anim - In vanilla, the animations generated by `AnimList` have a hard-coded `ZAdjust=-15`. Now you can customize it in the following ways. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 9d0ded6b6f..3e5d13dff3 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -553,6 +553,7 @@ New: - [Implement `CurleyShuffle` for AircraftTypes](Fixed-or-Improved-Logics.md#implement-curleyshuffle-for-aircrafttypes) (ported from Vinifera by Noble_Fish) - Customize which parasite can remove by warhead (by NetsuNegi) - Add toggle of whether shield use ArmorMultiplier or not (by NetsuNegi) +- Allow customize jumpjet properties on warhead (by NetsuNegi) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po index 3993d8c689..547394aeb3 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po +++ b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po @@ -1671,6 +1671,11 @@ msgid "" msgstr "" "添加了护盾是否使用护甲倍率的开关" +msgid "" +"Allow customize jumpjet properties on warhead" +msgstr "" +"允许在弹头上自定义 Jumpjet 属性" + msgid "**Apollo** - Translucent SHP drawing patches" msgstr "**Apollo** - 半透明 SHP 绘制补丁" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po index 2772504dcf..695728febd 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po @@ -5136,6 +5136,12 @@ msgid "" "choose it." msgstr "在原版中乌贼拖拽的动画被硬编码为 `SQDG`,现在选择权归你了。" +msgid "Customizing locomotor warhead" +msgstr "自定义 Locomotor 弹头" + +msgid "Now you can customize jumpjet properties on warhead." +msgstr "现在你可以在弹头上指定 Jumpjet 属性了。" + msgid "Dehardcode the `ZAdjust` of warhead anim" msgstr "弹头动画 `ZAdjust` 去硬编码" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po index 9e93d848ef..957b9cc3b3 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po @@ -1755,6 +1755,9 @@ msgstr "添加了护盾是否使用护甲倍率的开关(by NetsuNegi)" msgid "Customize which parasite can remove by warhead (by NetsuNegi)" msgstr "自定义哪些寄生者可被弹头移除(by NetsuNegi)" +msgid "Allow customize jumpjet properties on warhead (by NetsuNegi)" +msgstr "允许在弹头上自定义 Jumpjet 属性(by NetsuNegi)" + msgid "Vanilla fixes:" msgstr "原版问题修复:" diff --git a/src/Ext/Unit/Hooks.Jumpjet.cpp b/src/Ext/Unit/Hooks.Jumpjet.cpp index 280a9082ca..38325ae202 100644 --- a/src/Ext/Unit/Hooks.Jumpjet.cpp +++ b/src/Ext/Unit/Hooks.Jumpjet.cpp @@ -2,6 +2,7 @@ #include #include +#include // Misc jumpjet facing, turning, drawing fix -- Author: Trsdy // Jumpjets stuck at FireError::FACING because Jumpjet has its own facing just for JumpjetTurnRate @@ -454,3 +455,41 @@ DEFINE_HOOK(0x54D859, JumpjetLocomotionClass_GetFloorZ_IgnoreBuilding, 0x9) } #pragma endregion + +DEFINE_HOOK(0x54AD41, JumpjetLocomotionClass_Link_To_Object_LocomotorWarhead, 0x8) +{ + enum { SkipGameCode = 0x54ADF8 }; + + GET(ILocomotion*, pThis, EBP); + GET(FootClass*, pLinkedTo, EBX); + const auto pLoco = static_cast(pThis); + const auto pType = pLinkedTo->GetTechnoType(); + + if (const auto pLocomotorWarhead = WarheadTypeExt::LocomotorWarhead) + { + const auto pWHExt = WarheadTypeExt::ExtMap.Find(pLocomotorWarhead); + pLoco->TurnRate = pWHExt->JumpjetTurnRate.Get(pType->JumpjetTurnRate); + pLoco->Speed = pWHExt->JumpjetSpeed.Get(pType->JumpjetSpeed); + pLoco->Climb = pWHExt->JumpjetClimb.Get(pType->JumpjetClimb); + pLoco->Crash = pWHExt->JumpjetCrash.Get(pType->JumpjetCrash); + pLoco->Height = std::max(pWHExt->JumpjetHeight.Get(pType->JumpjetHeight), Unsorted::CellHeight); + pLoco->Accel = pWHExt->JumpjetAccel.Get(pType->JumpjetAccel); + pLoco->Wobbles = pWHExt->JumpjetWobbles.Get(pType->JumpjetWobbles); + pLoco->Deviation = pWHExt->JumpjetDeviation.Get(pType->JumpjetDeviation); + pLoco->NoWobbles = pWHExt->JumpjetNoWobbles.Get(pType->JumpjetNoWobbles); + } + else + { + pLoco->TurnRate = pType->JumpjetTurnRate; + pLoco->Speed = pType->JumpjetSpeed; + pLoco->Climb = pType->JumpjetClimb; + pLoco->Crash = pType->JumpjetCrash; + pLoco->Height = std::max(pType->JumpjetHeight, Unsorted::CellHeight); + pLoco->Accel = pType->JumpjetAccel; + pLoco->Wobbles = pType->JumpjetWobbles; + pLoco->Deviation = pType->JumpjetDeviation; + pLoco->NoWobbles = pType->JumpjetNoWobbles; + } + + return SkipGameCode; +} diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 3124129d53..cccf621672 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -4,6 +4,8 @@ WarheadTypeExt::ExtContainer WarheadTypeExt::ExtMap; +WarheadTypeClass* WarheadTypeExt::LocomotorWarhead = nullptr; + bool WarheadTypeExt::ExtData::CanTargetHouse(HouseClass* pHouse, TechnoClass* pTarget) const { if (pHouse && pTarget) @@ -291,6 +293,16 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Parasite_CullingTarget.Read(exINI, pSection, "Parasite.CullingTarget"); this->Parasite_GrappleAnim.Read(exINI, pSection, "Parasite.GrappleAnim"); + this->JumpjetTurnRate.Read(exINI, pSection, "JumpjetTurnRate"); + this->JumpjetSpeed.Read(exINI, pSection, "JumpjetSpeed"); + this->JumpjetClimb.Read(exINI, pSection, "JumpjetClimb"); + this->JumpjetCrash.Read(exINI, pSection, "JumpjetCrash"); + this->JumpjetHeight.Read(exINI, pSection, "JumpjetHeight"); + this->JumpjetAccel.Read(exINI, pSection, "JumpjetAccel"); + this->JumpjetWobbles.Read(exINI, pSection, "JumpjetWobbles"); + this->JumpjetNoWobbles.Read(exINI, pSection, "JumpjetNoWobbles"); + this->JumpjetDeviation.Read(exINI, pSection, "JumpjetDeviation"); + this->Nonprovocative.Read(exINI, pSection, "Nonprovocative"); this->MergeBuildingDamage.Read(exINI, pSection, "MergeBuildingDamage"); @@ -666,6 +678,16 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->Parasite_DisableParticleSystem) .Process(this->Parasite_CullingTarget) .Process(this->Parasite_GrappleAnim) + + .Process(this->JumpjetTurnRate) + .Process(this->JumpjetSpeed) + .Process(this->JumpjetClimb) + .Process(this->JumpjetCrash) + .Process(this->JumpjetHeight) + .Process(this->JumpjetAccel) + .Process(this->JumpjetWobbles) + .Process(this->JumpjetNoWobbles) + .Process(this->JumpjetDeviation) .Process(this->Nonprovocative) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index 1a08e540fc..72028e4d1a 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -159,6 +159,16 @@ class WarheadTypeExt Valueable Parasite_CullingTarget; NullableIdx Parasite_GrappleAnim; + Nullable JumpjetTurnRate; + Nullable JumpjetSpeed; + Nullable JumpjetClimb; + Nullable JumpjetCrash; + Nullable JumpjetHeight; + Nullable JumpjetAccel; + Nullable JumpjetWobbles; + Nullable JumpjetNoWobbles; + Nullable JumpjetDeviation; + Valueable Nonprovocative; Nullable MergeBuildingDamage; @@ -405,6 +415,16 @@ class WarheadTypeExt , Parasite_CullingTarget { AffectedTarget::Infantry } , Parasite_GrappleAnim {} + , JumpjetTurnRate {} + , JumpjetSpeed {} + , JumpjetClimb {} + , JumpjetCrash {} + , JumpjetHeight {} + , JumpjetAccel {} + , JumpjetWobbles {} + , JumpjetNoWobbles {} + , JumpjetDeviation {} + , Nonprovocative { false } , MergeBuildingDamage {} @@ -553,6 +573,8 @@ class WarheadTypeExt static bool LoadGlobals(PhobosStreamReader& Stm); static bool SaveGlobals(PhobosStreamWriter& Stm); + static WarheadTypeClass* LocomotorWarhead; + static void DetonateAt(WarheadTypeClass* pThis, AbstractClass* pTarget, TechnoClass* pOwner, int damage, HouseClass* pFiringHouse = nullptr); static void DetonateAt(WarheadTypeClass* pThis, const CoordStruct& coords, TechnoClass* pOwner, int damage, HouseClass* pFiringHouse = nullptr, AbstractClass* pTarget = nullptr); }; diff --git a/src/Ext/WarheadType/Hooks.cpp b/src/Ext/WarheadType/Hooks.cpp index a706148224..2b59d709ac 100644 --- a/src/Ext/WarheadType/Hooks.cpp +++ b/src/Ext/WarheadType/Hooks.cpp @@ -21,6 +21,21 @@ DEFINE_HOOK(0x46920B, BulletClass_Detonate, 0x6) return 0; } +// Customize Jumpjet properties on warhead +DEFINE_HOOK(0x4696CE, BulletClass_Detonate_ImbueLocomotor, 0x6) +{ + enum { SkipGameCode = 0x469AA4 }; + + GET(BulletClass* const, pBullet, ESI); + GET(FootClass* const, pTarget, EDI); + const auto pWH = pBullet->WH; + + WarheadTypeExt::LocomotorWarhead = pWH; + pBullet->Owner->ImbueLocomotor(pTarget, pWH->Locomotor); + WarheadTypeExt::LocomotorWarhead = nullptr; + return SkipGameCode; +} + DEFINE_HOOK(0x489286, MapClass_DamageArea, 0x6) { GET_BASE(const WarheadTypeClass*, pWH, 0xC); From c193342c5237ec58942975169ab7f52e71821635 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sun, 22 Mar 2026 13:40:36 +0800 Subject: [PATCH 2/4] [doc] Add link, correct position --- docs/Fixed-or-Improved-Logics.md | 36 +++++++++---------- docs/Whats-New.md | 2 +- .../LC_MESSAGES/Fixed-or-Improved-Logics.po | 12 +++---- docs/locale/zh_CN/LC_MESSAGES/Whats-New.po | 8 +++-- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 98fc80f2ed..0799cb44f8 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -2481,30 +2481,13 @@ In `rulesmd.ini`: DecloakDamagedTargets=true ; boolean ``` -### Customizing parasite - -- Now you can specify which targets the parasite will culling them. -- Squid grapple anim is hardcoded to use `SQDG` in vanilla, Now you can choose it. - -In `rulesmd.ini`: -```ini -[AudioVisual] -Parasite.GrappleAnim=SQDG ; AnimationType - -[SOMEWARHEAD] ; WarheadType -Parasite.ParticleSystem= ; ParticleSystemType, default to [CombatDamage] -> DefaultSparkSystem -Parasite.DisableParticleSystem=false ; boolean -Parasite.CullingTarget=infantry ; List of Affected Target Enumeration (none|aircraft|infantry|units|all) -Parasite.GrappleAnim= ; AnimationType, default to [AudioVisual] -> Parasite.GrappleAnim -``` - ### Customizing locomotor warhead - Now you can customize jumpjet properties on warhead. In `rulesmd.ini`: ```ini -[SOMEWARHEAD] ; WarheadType +[SOMEWARHEAD] ; WarheadType with IsLocomotor and Locomotor=Jumpjet JumpjetTurnRate= ; Integer, default to [TechnoType] -> JumpjetTurnRate JumpjetSpeed= ; Integer, default to [TechnoType] -> JumpjetSpeed JumpjetClimb= ; floating point value, default to [TechnoType] -> JumpjetClimb @@ -2516,6 +2499,23 @@ JumpjetNoWobbles= ; boolean, default to [TechnoType] -> Ju JumpjetDeviation= ; Integer, default to [TechnoType] -> JumpjetDeviation ``` +### Customizing parasite + +- Now you can specify which targets the parasite will culling them. +- Squid grapple anim is hardcoded to use `SQDG` in vanilla, Now you can choose it. + +In `rulesmd.ini`: +```ini +[AudioVisual] +Parasite.GrappleAnim=SQDG ; AnimationType + +[SOMEWARHEAD] ; WarheadType +Parasite.ParticleSystem= ; ParticleSystemType, default to [CombatDamage] -> DefaultSparkSystem +Parasite.DisableParticleSystem=false ; boolean +Parasite.CullingTarget=infantry ; List of Affected Target Enumeration (none|aircraft|infantry|units|all) +Parasite.GrappleAnim= ; AnimationType, default to [AudioVisual] -> Parasite.GrappleAnim +``` + ### Dehardcode the `ZAdjust` of warhead anim - In vanilla, the animations generated by `AnimList` have a hard-coded `ZAdjust=-15`. Now you can customize it in the following ways. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 3e5d13dff3..7d890ed5b1 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -553,7 +553,7 @@ New: - [Implement `CurleyShuffle` for AircraftTypes](Fixed-or-Improved-Logics.md#implement-curleyshuffle-for-aircrafttypes) (ported from Vinifera by Noble_Fish) - Customize which parasite can remove by warhead (by NetsuNegi) - Add toggle of whether shield use ArmorMultiplier or not (by NetsuNegi) -- Allow customize jumpjet properties on warhead (by NetsuNegi) +- [Allow customize jumpjet properties on warhead](Fixed-or-Improved-Logics.md#customizing-locomotor-warhead) (by NetsuNegi) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po index 695728febd..215a35b813 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Fixed-or-Improved-Logics.po @@ -5125,6 +5125,12 @@ msgid "" "damaged by the warhead." msgstr "现在你可以指定被这个弹头杀伤的对象是否解除隐形。" +msgid "Customizing locomotor warhead" +msgstr "自定义运动模式弹头" + +msgid "Now you can customize jumpjet properties on warhead." +msgstr "现在你可以在弹头上指定 Jumpjet 属性了。" + msgid "Customizing parasite" msgstr "自定义寄生" @@ -5136,12 +5142,6 @@ msgid "" "choose it." msgstr "在原版中乌贼拖拽的动画被硬编码为 `SQDG`,现在选择权归你了。" -msgid "Customizing locomotor warhead" -msgstr "自定义 Locomotor 弹头" - -msgid "Now you can customize jumpjet properties on warhead." -msgstr "现在你可以在弹头上指定 Jumpjet 属性了。" - msgid "Dehardcode the `ZAdjust` of warhead anim" msgstr "弹头动画 `ZAdjust` 去硬编码" diff --git a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po index 957b9cc3b3..72e18c01d3 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po @@ -1755,8 +1755,12 @@ msgstr "添加了护盾是否使用护甲倍率的开关(by NetsuNegi)" msgid "Customize which parasite can remove by warhead (by NetsuNegi)" msgstr "自定义哪些寄生者可被弹头移除(by NetsuNegi)" -msgid "Allow customize jumpjet properties on warhead (by NetsuNegi)" -msgstr "允许在弹头上自定义 Jumpjet 属性(by NetsuNegi)" +msgid "" +"[Allow customize jumpjet properties on warhead](Fixed-or-Improved-" +"Logics.md#customizing-locomotor-warhead) (by NetsuNegi)" +msgstr "" +"[允许在弹头上自定义 Jumpjet 属性](Fixed-or-Improved-" +"Logics.md#customizing-locomotor-warhead)(by NetsuNegi)" msgid "Vanilla fixes:" msgstr "原版问题修复:" From c198e3e14acf52b6cd87f8e7936e7d25b3b9d9b5 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Sun, 22 Mar 2026 16:05:16 +0800 Subject: [PATCH 3/4] fix with `JumpjetSpeed` --- src/Ext/Techno/Body.cpp | 1 + src/Ext/Techno/Body.h | 2 ++ src/Ext/Unit/Hooks.Jumpjet.cpp | 5 +++-- src/Misc/Hooks.BugFixes.cpp | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index dfc6d58c79..9ed28305bf 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -1014,6 +1014,7 @@ void TechnoExt::ExtData::Serialize(T& Stm) .Process(this->PassengerDeletionTimer) .Process(this->CurrentShieldType) .Process(this->LastWarpDistance) + .Process(this->JumpjetSpeed) .Process(this->ChargeTurretTimer) .Process(this->AutoDeathTimer) .Process(this->MindControlRingAnimType) diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 57d9f650dd..7cceb902fb 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -36,6 +36,7 @@ class TechnoExt CDTimerClass PassengerDeletionTimer; ShieldTypeClass* CurrentShieldType; int LastWarpDistance; + int JumpjetSpeed; CDTimerClass ChargeTurretTimer; // Used for charge turrets instead of RearmTimer if weapon has ChargeTurret.Delays set. CDTimerClass AutoDeathTimer; AnimTypeClass* MindControlRingAnimType; @@ -119,6 +120,7 @@ class TechnoExt , PassengerDeletionTimer {} , CurrentShieldType { nullptr } , LastWarpDistance {} + , JumpjetSpeed { 14 } // 0x7115B8 , ChargeTurretTimer {} , AutoDeathTimer {} , MindControlRingAnimType { nullptr } diff --git a/src/Ext/Unit/Hooks.Jumpjet.cpp b/src/Ext/Unit/Hooks.Jumpjet.cpp index 38325ae202..1ffa9e3eb4 100644 --- a/src/Ext/Unit/Hooks.Jumpjet.cpp +++ b/src/Ext/Unit/Hooks.Jumpjet.cpp @@ -463,13 +463,14 @@ DEFINE_HOOK(0x54AD41, JumpjetLocomotionClass_Link_To_Object_LocomotorWarhead, 0x GET(ILocomotion*, pThis, EBP); GET(FootClass*, pLinkedTo, EBX); const auto pLoco = static_cast(pThis); + const auto pLinkedToExt = TechnoExt::ExtMap.Find(pLinkedTo); const auto pType = pLinkedTo->GetTechnoType(); if (const auto pLocomotorWarhead = WarheadTypeExt::LocomotorWarhead) { const auto pWHExt = WarheadTypeExt::ExtMap.Find(pLocomotorWarhead); pLoco->TurnRate = pWHExt->JumpjetTurnRate.Get(pType->JumpjetTurnRate); - pLoco->Speed = pWHExt->JumpjetSpeed.Get(pType->JumpjetSpeed); + pLoco->Speed = pLinkedToExt->JumpjetSpeed = pWHExt->JumpjetSpeed.Get(pType->JumpjetSpeed); pLoco->Climb = pWHExt->JumpjetClimb.Get(pType->JumpjetClimb); pLoco->Crash = pWHExt->JumpjetCrash.Get(pType->JumpjetCrash); pLoco->Height = std::max(pWHExt->JumpjetHeight.Get(pType->JumpjetHeight), Unsorted::CellHeight); @@ -481,7 +482,7 @@ DEFINE_HOOK(0x54AD41, JumpjetLocomotionClass_Link_To_Object_LocomotorWarhead, 0x else { pLoco->TurnRate = pType->JumpjetTurnRate; - pLoco->Speed = pType->JumpjetSpeed; + pLoco->Speed = pLinkedToExt->JumpjetSpeed = pType->JumpjetSpeed; pLoco->Climb = pType->JumpjetClimb; pLoco->Crash = pType->JumpjetCrash; pLoco->Height = std::max(pType->JumpjetHeight, Unsorted::CellHeight); diff --git a/src/Misc/Hooks.BugFixes.cpp b/src/Misc/Hooks.BugFixes.cpp index 0787b4041d..ab5514becc 100644 --- a/src/Misc/Hooks.BugFixes.cpp +++ b/src/Misc/Hooks.BugFixes.cpp @@ -443,7 +443,7 @@ DEFINE_HOOK(0x54D138, JumpjetLocomotionClass_Movement_AI_SpeedModifiers, 0x6) GET(JumpjetLocomotionClass*, pThis, ESI); const double multiplier = TechnoExt::GetCurrentSpeedMultiplier(pThis->LinkedTo); - pThis->Speed = (int)(pThis->LinkedTo->GetTechnoType()->JumpjetSpeed * multiplier); + pThis->Speed = static_cast(TechnoExt::ExtMap.Find(pThis->LinkedTo)->JumpjetSpeed * multiplier); return 0; } From 53fa7e39a0c7a79f59cc197df2d4f50ba581a5ed Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Sun, 22 Mar 2026 16:33:45 +0800 Subject: [PATCH 4/4] Update Hooks.Jumpjet.cpp --- src/Ext/Unit/Hooks.Jumpjet.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Ext/Unit/Hooks.Jumpjet.cpp b/src/Ext/Unit/Hooks.Jumpjet.cpp index 1ffa9e3eb4..dd50e3324f 100644 --- a/src/Ext/Unit/Hooks.Jumpjet.cpp +++ b/src/Ext/Unit/Hooks.Jumpjet.cpp @@ -181,13 +181,14 @@ DEFINE_FUNCTION_JUMP(VTABLE, 0x7ECDF4, JumpjetLocomotionClass_Can_Fire); DEFINE_HOOK(0x54DAC4, JumpjetLocomotionClass_EndPiggyback_Blyat, 0x6) { GET(FootClass*, pLinkedTo, EAX); - auto const* pType = pLinkedTo->GetTechnoType(); + const auto pType = pLinkedTo->GetTechnoType(); + const auto pExt = TechnoExt::ExtMap.Find(pLinkedTo); + pExt->JumpjetSpeed = pType->JumpjetSpeed; pLinkedTo->PrimaryFacing.SetROT(pType->ROT); if (pType->SensorsSight) { - const auto pExt = TechnoExt::ExtMap.Find(pLinkedTo); pLinkedTo->RemoveSensorsAt(pExt->LastSensorsMapCoords); pLinkedTo->AddSensorsAt(CellStruct::Empty); }