Skip to content

Unlimbo Detonate warhead #1822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ This page lists all the individual contributions to the project by their author.
- Units can customize the attack voice that plays when using more weapons
- When `Speed=0` or the TechnoTypes cell cannot move due to `MovementRestrictedTo`, vehicles cannot attack targets beyond the weapon's range. `Area Guard` and `Hunt` missions will also become ineffective
- When the vehicle loses its target, you can customize whether to align the turret direction with the vehicle body
- Unlimbo Detonate warhead
- **NetsuNegi**:
- Forbidding parallel AI queues by type
- Jumpjet crash speed fix when crashing onto building
Expand Down
23 changes: 23 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,29 @@ In `rulesmd.ini`:
NotHuman.DeathSequence= ; integer (1 to 5)
```

### Unlimbo Detonate

![Unlimbo Detonate](_static/images/unlimbodetonate.gif)
*Unlimbo Detonate used in **The Call of the Panic Spear** by @[Octagonal prism](https://space.bilibili.com/360577336)*

- `UnlimboDetonate` allows units that have fired weapons with `LimboLaunch=yes` to reappear.
- `UnlimboDetonate.Force` allows units to forcefully appear at the projectile explosion location, otherwise they will search for other available cells.
- `UnlimboDetonate.KeepTarget` allows units to retain their original attack target when they reappear.
- `UnlimboDetonate.KeepSelected` allows units to retain their original selected state when they appear.

In `rulesmd.ini`:
```ini
[SOMEWARHEAD] ; WarheadType
UnlimboDetonate=no ; boolean
UnlimboDetonate.Force=no ; boolean
UnlimboDetonate.KeepTarget=no ; boolean
UnlimboDetonate.KeepSelected=no ; boolean
```

```{warning}
`UnlimboDetonate` cannot be used in conjunction with `Parasite`.
```

## Weapons

### AreaFire target customization
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ New:
- AI base construction modification (by CrimRecya)
- Restore turret recoil effect (by CrimRecya)
- Jumpjet Climbing Logic Enhancement (by CrimRecya)
- Unlimbo Detonate warhead (by FlyStar)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
Binary file added docs/_static/images/unlimbodetonate.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 55 additions & 1 deletion src/Ext/Bullet/Hooks.DetonateLogics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,61 @@ DEFINE_HOOK(0x469AA4, BulletClass_Logics_Extras, 0x5)
}
}

WarheadTypeExt::ExtMap.Find(pThis->WH)->InDamageArea = true;
// Unlimbo Detonate
const auto pWH = pThis->WH;
const auto pWHExt = WarheadTypeExt::ExtMap.Find(pWH);
pWHExt->InDamageArea = true;

if (pTechno && !pWH->Parasite && pWHExt->UnlimboDetonate)
{
CoordStruct location = *coords;
const auto pTarget = pThis->Target;
bool isInAir = pTarget ? pTarget->IsInAir() : false;

if (!pWHExt->UnlimboDetonate_Force)
{
const auto pType = pTechno->GetTechnoType();
const auto nCell = MapClass::Instance.NearByLocation(CellClass::Coord2Cell(location),
pType->SpeedType, -1, pType->MovementZone, false, 1, 1, true,
false, false, true, CellStruct::Empty, false, false);

const auto pCell = MapClass::Instance.TryGetCellAt(nCell);

if (pCell)
location = pCell->GetCoordsWithBridge();

if (isInAir)
location.Z = coords->Z;
}

++Unsorted::ScenarioInit;
pTechno->Unlimbo(location, pTechno->PrimaryFacing.Current().GetDir());
--Unsorted::ScenarioInit;

if (isInAir)
{
pTechno->IsFallingDown = true;
pTechno->FallRate = 0;
}

if (pWHExt->UnlimboDetonate_KeepTarget
&& pTarget && pTarget->AbstractFlags & AbstractFlags::Object)
{
pTechno->SetTarget(pThis->Target);
}
else
{
pTechno->SetTarget(nullptr);
}

const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno);

if (pTechnoExt->IsSelected)
{
pTechno->Select();
pTechnoExt->IsSelected = false;
}
}

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions src/Ext/Techno/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ void TechnoExt::ExtData::Serialize(T& Stm)
.Process(this->DelayedFireWeaponIndex)
.Process(this->CurrentDelayedFireAnim)
.Process(this->AttachedEffectInvokerCount)
.Process(this->IsSelected)
.Process(this->TintColorOwner)
.Process(this->TintColorAllies)
.Process(this->TintColorEnemies)
Expand Down
3 changes: 3 additions & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class TechnoExt

CDTimerClass FiringAnimationTimer;

bool IsSelected;

// cache tint values
int TintColorOwner;
int TintColorAllies;
Expand Down Expand Up @@ -139,6 +141,7 @@ class TechnoExt
, DelayedFireTimer {}
, CurrentDelayedFireAnim { nullptr }
, AttachedEffectInvokerCount { 0 }
, IsSelected { false }
, TintColorOwner { 0 }
, TintColorAllies { 0 }
, TintColorEnemies { 0 }
Expand Down
10 changes: 10 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

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

this->UnlimboDetonate.Read(exINI, pSection, "UnlimboDetonate");
this->UnlimboDetonate_Force.Read(exINI, pSection, "UnlimboDetonate.Force");
this->UnlimboDetonate_KeepTarget.Read(exINI, pSection, "UnlimboDetonate.KeepTarget");
this->UnlimboDetonate_KeepSelected.Read(exINI, pSection, "UnlimboDetonate.KeepSelected");

// Convert.From & Convert.To
TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All);

Expand Down Expand Up @@ -572,6 +577,11 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)

.Process(this->ReverseEngineer)

.Process(this->UnlimboDetonate)
.Process(this->UnlimboDetonate_Force)
.Process(this->UnlimboDetonate_KeepTarget)
.Process(this->UnlimboDetonate_KeepSelected)

// Ares tags
.Process(this->AffectsEnemies)
.Process(this->AffectsOwner)
Expand Down
10 changes: 10 additions & 0 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ class WarheadTypeExt

Valueable<bool> CanKill;

Valueable<bool> UnlimboDetonate;
Valueable<bool> UnlimboDetonate_Force;
Valueable<bool> UnlimboDetonate_KeepTarget;
Valueable<bool> UnlimboDetonate_KeepSelected;

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
Valueable<bool> AffectsEnemies;
Expand Down Expand Up @@ -402,6 +407,11 @@ class WarheadTypeExt
, KillWeapon_OnFirer_Affects { AffectedTarget::All }

, ReverseEngineer { false }

, UnlimboDetonate { false }
, UnlimboDetonate_Force { false }
, UnlimboDetonate_KeepTarget { true }
, UnlimboDetonate_KeepSelected { true }
{ }

void ApplyConvert(HouseClass* pHouse, TechnoClass* pTarget);
Expand Down
42 changes: 42 additions & 0 deletions src/Ext/WarheadType/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,45 @@ DEFINE_HOOK(0x4D73DE, FootClass_ReceiveDamage_RemoveParasite, 0x5)

return Continue;
}

#pragma region UnlimboDetonate

namespace UnlimboDetonateFireTemp
{
BulletClass* Bullet;
bool InSelected;
bool InLimbo;
}

DEFINE_HOOK(0x6FE562, TechnoClass_Fire_SetContext, 0x6)
{
GET(TechnoClass* const, pThis, ESI);
GET(BulletClass* const, pBullet, EAX);

UnlimboDetonateFireTemp::Bullet = pBullet;
UnlimboDetonateFireTemp::InSelected = pThis->IsSelected;
UnlimboDetonateFireTemp::InLimbo = pThis->InLimbo;

return 0;
}

DEFINE_HOOK(0x6FF7FF, TechnoClass_Fire_UnlimboDetonate, 0x6)
{
GET(TechnoClass* const, pThis, ESI);
GET(WarheadTypeClass* const, pWH, EAX);

const auto pBullet = UnlimboDetonateFireTemp::Bullet;
const auto pWHExt = WarheadTypeExt::ExtMap.Find(pWH);

if (!UnlimboDetonateFireTemp::InLimbo && pBullet && !pWH->Parasite && pWHExt->UnlimboDetonate)
{
if (pWHExt->UnlimboDetonate_KeepSelected)
TechnoExt::ExtMap.Find(pThis)->IsSelected = UnlimboDetonateFireTemp::InSelected;

pBullet->Owner = pThis;
}

return 0;
}

#pragma endregion
Loading