Skip to content

Commit 037574d

Browse files
Custom cruise missiles (#2273)
1 parent a76f8c2 commit 037574d

6 files changed

Lines changed: 128 additions & 1 deletion

File tree

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ This page lists all the individual contributions to the project by their author.
690690
- Customize the landing animation of technos that have `Locomotor=Fly`
691691
- Allow infantry to use `Convert.Deploy` without requiring `IsSimpleDeployer=true`
692692
- Allow infantry to perform type conversion when deploying and undeploying
693+
- Custom cruise missiles
693694
- **Ollerus**:
694695
- Build limit group enhancement
695696
- Customizable rocker amplitude

docs/New-or-Enhanced-Logics.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,27 @@ Shield.InheritStateOnReplace=false ; boolean
503503

504504
## Aircraft
505505

506+
### Custom cruise missiles
507+
508+
- From RockPatch to Ares, custom missiles have never had a way to enter cruise missile mode, so neither RP's `MissileRaiseRate` nor Ares' `Missile.RaiseRate` have ever been effective, and modders cannot create another type of cruise missile beyond the type set in `[General] -> CMislType=`. Now, you can customize whether a custom missile is a cruise missile.
509+
- The take-off animation of a cruise missile is actually the continuously created trail smoke during the ascent phase, rather than the animation created only once at launch like a conventional missile. Now, the creation interval of this animation can be customized via `Missile.TakeOffSeparation`.
510+
511+
In `rulesmd.ini`:
512+
```ini
513+
[SOMEAIRCRAFT] ; AircraftType with Missile.Custom=yes
514+
Missile.Cruise=false ; boolean
515+
Missile.TakeOffSeparation=24 ; integer
516+
```
517+
518+
```{note}
519+
Like Ares' `Missile.TrailerSeparation`, `Missile.TakeOffSeparation` also works without requiring `Missile.Custom=true`, which means it can be directly applied to the unit specified by `[General] -> CMislType=` without completely rewriting it as a custom missile.
520+
```
521+
522+
```{seealso}
523+
- [MissileSpawn Control on ModEnc](https://modenc.renegadeprojects.com/MissileSpawn_Control)
524+
- [Custom Missiles - Ares documentation](http://ares-developers.github.io/Ares-docs/new/custommissiles.html)
525+
```
526+
506527
### Damaged aircraft image changes
507528

508529
- When an aircraft is damaged (health points percentage is lower than `[AudioVisual] -> ConditionYellow` percentage), it now may use different image set by `Image.ConditionYellow` AircraftType.

docs/Whats-New.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ HideShakeEffects=false ; boolean
597597
- Add `ClampToScreen` tag for `BannerType` (defaults to `true`) to control whether banner position is clamped to the visible area (by Chang_zhi)
598598
- [Customizable Berzerk mission](Fixed-or-Improved-Logics.md#enhanced-berzerk-behavior) (by TaranDahl)
599599
- [Tank Bunker foundation and state update delay improvements](Fixed-or-Improved-Logics.md#tank-bunker-improvements) (by Starkku)
600+
- [Custom cruise missiles](New-or-Enhanced-Logics.md#custom-cruise-missiles) (by Noble_Fish)
600601
601602
#### Vanilla fixes:
602603
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
@@ -761,6 +762,7 @@ HideShakeEffects=false ; boolean
761762
- Allowed `MindControl.Permanent` warhead to mute `MindClearedSound` (by NetsuNegi & Noble_Fish)
762763
- [Export interface for accessing scenario local/global variables](Interoperability.md#scenarioext) (by Chang_zhi)
763764
- Allowed infantry to use `Convert.Deploy` without requiring `IsSimpleDeployer=true` (by Noble_Fish)
765+
- Added the scenario where `Missile.Raise` can be applied by custom missiles (by Noble_Fish)
764766
765767
```
766768

src/Ext/Techno/Hooks.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,83 @@ DEFINE_HOOK(0x4CF8B1, FlyLocomotionClass_Draw_Point_NoWobbles, 0x6)
21282128
return Continue;
21292129
}
21302130

2131+
#pragma region IsCruiseMissile
2132+
2133+
DEFINE_HOOK(0x662354, RocketLocomotionClass_Process_CruiseMissileCheck, 0x6)
2134+
{
2135+
GET(ILocomotion*, pThis, ESI);
2136+
const auto pLoco = static_cast<RocketLocomotionClass*>(pThis);
2137+
const auto pLinkedTo = abstract_cast<AircraftClass*>(pLoco->LinkedTo);
2138+
2139+
if (!pLinkedTo)
2140+
return 0;
2141+
2142+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pLinkedTo->Type);
2143+
if (pTypeExt->Missile_Cruise)
2144+
return 0x662369;
2145+
2146+
return 0;
2147+
}
2148+
2149+
DEFINE_HOOK(0x6623FC, RocketLocomotionClass_Process_CustomSmokeInterval, 0x5)
2150+
{
2151+
GET(ILocomotion*, pThis, ESI);
2152+
const auto pLoco = static_cast<RocketLocomotionClass*>(pThis);
2153+
const auto pLinkedTo = abstract_cast<AircraftClass*>(pLoco->LinkedTo);
2154+
2155+
if (!pLinkedTo)
2156+
return 0;
2157+
2158+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pLinkedTo->Type);
2159+
2160+
R->ECX(pTypeExt->Missile_TakeOffSeparation);
2161+
return 0x662401;
2162+
}
2163+
2164+
DEFINE_HOOK(0x6624FB, RocketLocomotionClass_Process_CustomMissileTakeoff, 0x5)
2165+
{
2166+
enum { SkipAnimation = 0x662599 };
2167+
GET(ILocomotion*, pThis, ESI);
2168+
2169+
const auto pLoco = static_cast<RocketLocomotionClass*>(pThis);
2170+
const auto pLinkedTo = abstract_cast<AircraftClass*>(pLoco->LinkedTo);
2171+
2172+
if (!pLinkedTo)
2173+
return SkipAnimation;
2174+
2175+
if (pLoco->TrailerTimer.HasTimeLeft())
2176+
return SkipAnimation;
2177+
2178+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pLinkedTo->Type);
2179+
2180+
if (pTypeExt->Missile_TakeOffAnim)
2181+
{
2182+
GameCreate<AnimClass>(pTypeExt->Missile_TakeOffAnim, pLinkedTo->Location, 2, 1, 0x600, -10, false);
2183+
pLoco->TrailerTimer.Start(pTypeExt->Missile_TakeOffSeparation);
2184+
}
2185+
2186+
// Do not return 0x662512, otherwise it will enter Ares' CustomMissileTakeoff2 for duplicate processing.
2187+
return SkipAnimation;
2188+
}
2189+
2190+
DEFINE_HOOK(0x662720, RocketLocomotionClass_Process_CruiseMissileRaise, 0x6)
2191+
{
2192+
GET(ILocomotion*, pThis, ESI);
2193+
const auto pLoco = static_cast<RocketLocomotionClass*>(pThis);
2194+
const auto pLinkedTo = abstract_cast<AircraftClass*>(pLoco->LinkedTo);
2195+
2196+
if (!pLinkedTo)
2197+
return 0;
2198+
2199+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pLinkedTo->Type);
2200+
if (pTypeExt->Missile_Cruise)
2201+
return 0x6624C8;
2202+
2203+
return 0;
2204+
}
2205+
2206+
#pragma endregion
2207+
21312208
namespace WarpPerStep
21322209
{
21332210
class TemporalClassFake final : public TemporalClass

src/Ext/TechnoType/Body.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
TechnoTypeExt::ExtContainer TechnoTypeExt::ExtMap;
1515
bool TechnoTypeExt::SelectWeaponMutex = false;
1616

17+
void TechnoTypeExt::ExtData::Initialize()
18+
{
19+
auto pThis = this->OwnerObject();
20+
21+
if (pThis->WhatAmI() == AircraftTypeClass::AbsID)
22+
this->Missile_TakeOffAnim = AnimTypeClass::Find("V3TAKOFF");
23+
}
24+
1725
void TechnoTypeExt::ExtData::ApplyTurretOffset(Matrix3D* mtx, double factor)
1826
{
1927
// Does not verify if the offset actually has all values parsed as it makes no difference, it will be 0 for the unparsed ones either way.
@@ -1204,9 +1212,15 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
12041212

12051213
this->LandingAnim.Read(exINI, pSection, "LandingAnim");
12061214

1215+
this->Missile_Cruise.Read(exINI, pSection, "Missile.Cruise");
1216+
this->Missile_TakeOffSeparation.Read(exINI, pSection, "Missile.TakeOffSeparation");
1217+
12071218
// Ares 0.2
12081219
this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius");
12091220

1221+
// Ares 0.3
1222+
this->Missile_TakeOffAnim.Read(exINI, pSection, "Missile.TakeOffAnim");
1223+
12101224
// Ares 0.9
12111225
this->InhibitorRange.Read(exINI, pSection, "InhibitorRange");
12121226
this->DesignatorRange.Read(exINI, pSection, "DesignatorRange");
@@ -1951,6 +1965,10 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
19511965
.Process(this->FlyNoWobbles)
19521966

19531967
.Process(this->LandingAnim)
1968+
1969+
.Process(this->Missile_Cruise)
1970+
.Process(this->Missile_TakeOffAnim)
1971+
.Process(this->Missile_TakeOffSeparation)
19541972
;
19551973
}
19561974
void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)

src/Ext/TechnoType/Body.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,10 @@ class TechnoTypeExt
517517

518518
Nullable<AnimTypeClass*> LandingAnim;
519519

520+
Valueable<bool> Missile_Cruise;
521+
Valueable<AnimTypeClass*> Missile_TakeOffAnim;
522+
Valueable<int> Missile_TakeOffSeparation;
523+
520524
ExtData(TechnoTypeClass* OwnerObject) : Extension<TechnoTypeClass>(OwnerObject)
521525
, HealthBar_Hide { false }
522526
, HealthBar_HidePips { false }
@@ -986,11 +990,15 @@ class TechnoTypeExt
986990
, FlyNoWobbles {}
987991

988992
, LandingAnim {}
993+
994+
, Missile_Cruise { false }
995+
, Missile_TakeOffAnim { nullptr }
996+
, Missile_TakeOffSeparation { 24 }
989997
{ }
990998

991999
virtual ~ExtData() = default;
9921000
virtual void LoadFromINIFile(CCINIClass* pINI) override;
993-
virtual void Initialize() override { }
1001+
virtual void Initialize() override;
9941002

9951003
virtual void InvalidatePointer(void* ptr, bool bRemoved) override { }
9961004

0 commit comments

Comments
 (0)