Skip to content

[Vanilla Enhancement] Vehicle disguise to vehicle #1803

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 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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 @@ -437,6 +437,7 @@ This page lists all the individual contributions to the project by their author.
- Fix the bug that Locomotor warhead won't stop working when firer (except for vehicle) stop firing
- Fix the bug that hover vehicle will sink if destroyed on bridge
- Customize squid grapple animation
- Vehicle disguise to vehicle
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
Expand Down
10 changes: 10 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2075,6 +2075,16 @@ FireUp= ; integer
FireUp.ResetInRetarget=true ; boolean
```

### Vehicle disguise to vehicle

- Now you can make vehicle disguise to other vehicles, like spy.

In `rulesmd.ini`:
```ini
[SOMEVEHICLE] ; VehicleType
DefaultVehicleDisguise= ; vehicle type
```

## Warheads

```{hint}
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ New:
- Units can customize the attack voice that plays when using more weapons (by FlyStar)
- Customize squid grapple animation (by NetsuNegi)
- Auto deploy for GI-like infantry (by TaranDahl)
- Vehicle disguise to vehicle (by NetsuNegi)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
258 changes: 253 additions & 5 deletions src/Ext/Techno/Hooks.Misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,28 +473,48 @@ DEFINE_HOOK(0x7295E2, TunnelLocomotionClass_ProcessStateDigging_SubterraneanHeig

DEFINE_HOOK(0x522790, InfantryClass_ClearDisguise_DefaultDisguise, 0x6)
{
enum { SetDisguise = 0x5227BF };

GET(InfantryClass*, pThis, ECX);
auto const pExt = TechnoTypeExt::ExtMap.Find(pThis->Type);
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->Type);

if (pExt->DefaultDisguise)
if (const auto pDefault = pTypeExt->DefaultDisguise.Get())
{
pThis->Disguise = pExt->DefaultDisguise;
pThis->Disguise = pDefault;
pThis->DisguisedAsHouse = pThis->Owner;
pThis->Disguised = true;
return 0x5227BF;
return SetDisguise;
}

pThis->Disguised = false;

return 0;
}

DEFINE_HOOK(0x746720, UnitClass_ClearDisguise_DefaultDisguise, 0x5)
{
enum { SetDisguise = 0x746747 };

GET(UnitClass*, pThis, ECX);
const auto pType = pThis->Type;

if (!pType->PermaDisguise)
return 0;

const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
const auto pDefault = pTypeExt->DefaultVehicleDisguise.Get();
pThis->Disguise = pDefault ? pDefault : pType;
pThis->DisguisedAsHouse = pThis->Owner;
pThis->Disguised = true;
return SetDisguise;
}

DEFINE_HOOK(0x74691D, UnitClass_UpdateDisguise_EMP, 0x6)
{
GET(UnitClass*, pThis, ESI);
// Remove mirage disguise if under emp or being flipped, approximately 15 deg
// Deactivated mirage should still be able to keep disguise
if (pThis->IsUnderEMP() || std::abs(pThis->AngleRotatedForwards) > 0.25 || std::abs(pThis->AngleRotatedSideways) > 0.25)
if (pThis->Deactivated || pThis->IsUnderEMP() || std::abs(pThis->AngleRotatedForwards) > 0.25 || std::abs(pThis->AngleRotatedSideways) > 0.25)
{
pThis->ClearDisguise();
R->EAX(pThis->MindControlRingAnim);
Expand All @@ -504,6 +524,234 @@ DEFINE_HOOK(0x74691D, UnitClass_UpdateDisguise_EMP, 0x6)
return 0x746931;
}

DEFINE_HOOK(0x7466DC, UnitClass_DisguiseAs_DisguiseAsVehicle, 0x6)
{
enum { SkipGameCode = 0x746712 };

GET(UnitClass*, pThis, EDI);
GET(UnitClass*, pTarget, ESI);
const bool targetDisguised = pTarget->IsDisguised();

pThis->Disguise = targetDisguised ? pTarget->GetDisguise(true) : pTarget->Type;
pThis->DisguisedAsHouse = targetDisguised ? pTarget->GetDisguiseHouse(true) : pTarget->Owner;
reinterpret_cast<void(__thiscall*)(TechnoClass*, AbstractClass*)>(0x70E280)(pThis, pTarget);//pThis->TechnoClass::DisguiseAs(pTarget);
return SkipGameCode;
}

DEFINE_HOOK(0x746AFF, UnitClass_Desguise_Update_MoveToClear, 0xA)
{
enum { DontClearDisguise = 0x746A9C };

GET(TechnoClass*, pThis, ESI);

const auto pDisguise = pThis->Disguise;
return pDisguise && pDisguise->WhatAmI() == UnitTypeClass::AbsID ? DontClearDisguise : 0;
}

DEFINE_HOOK(0x74659B, UnitClass_RemoveGunner_ClearDisguise, 0x6)
{
GET(UnitClass*, pThis, EDI);

if (!pThis->IsDisguised())
return 0;

if (const auto pWeapon = pThis->GetWeapon(pThis->CurrentWeaponNumber)->WeaponType)
{
const auto pWarhead = pWeapon->Warhead;

if (pWarhead && pWarhead->MakesDisguise)
return 0;
}

pThis->ClearDisguise();
return 0;
}

#pragma region UnitClass DrawSHP

DEFINE_HOOK(0x73C655, UnitClass_DrawSHP_TechnoType, 0x6)
{
enum { ApplyDisguiseType = 0x73C65B };

GET(UnitClass*, pThis, EBP);

if (pThis->IsDisguised() && !pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer))
{
const auto pTargetType = pThis->GetDisguise(true);

if (pTargetType && pTargetType->WhatAmI() == UnitTypeClass::AbsID)
{
R->ECX(pTargetType);
return ApplyDisguiseType;
}
}

return 0;
}

DEFINE_HOOK(0x73C69D, UnitClass_DrawSHP_TechnoType2, 0x6)
{
enum { ApplyDisguiseType = 0x73C6A3 };

GET(UnitClass*, pThis, EBP);

if (pThis->IsDisguised() && !pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer))
{
const auto pTargetType = pThis->GetDisguise(true);

if (pTargetType && pTargetType->WhatAmI() == UnitTypeClass::AbsID)
{
R->ECX(pThis->GetDisguise(true));
return ApplyDisguiseType;
}
}

return 0;
}

DEFINE_HOOK(0x73C702, UnitClass_DrawSHP_TechnoType3, 0x6)
{
enum { ApplyDisguiseType = 0x73C708 };

GET(UnitClass*, pThis, EBP);

if (pThis->IsDisguised() && !pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer))
{
const auto pTargetType = pThis->GetDisguise(true);

if (pTargetType && pTargetType->WhatAmI() == UnitTypeClass::AbsID)
{
R->ECX(pThis->GetDisguise(true));
return ApplyDisguiseType;
}
}

return 0;
}

DEFINE_HOOK(0x73C725, UnitClass_DrawSHP_HasTurret, 0x5)
{
enum { SkipDrawTurret = 0x73CE0D };

GET(UnitClass*, pThis, EBP);

if (pThis->IsDisguised() && !pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer))
{
const auto pDisguise = pThis->GetDisguise(true);

if (pDisguise)
{
const auto pTargetType = TechnoTypeExt::GetTechnoType(pDisguise);

if (pTargetType && !pTargetType->Turret)
return SkipDrawTurret;
}
}

return 0;
}

#pragma endregion

#pragma region UnitClass DrawVoxel

DEFINE_HOOK_AGAIN(0x73B765, UnitClass_DrawVoxel_TurretFacing, 0x5)
DEFINE_HOOK_AGAIN(0x73BA78, UnitClass_DrawVoxel_TurretFacing, 0x6)
DEFINE_HOOK_AGAIN(0x73BD8B, UnitClass_DrawVoxel_TurretFacing, 0x5)
DEFINE_HOOK(0x73BDA3, UnitClass_DrawVoxel_TurretFacing, 0x5)
{
GET(UnitClass*, pThis, EBP);

if (!pThis->Type->Turret && pThis->IsDisguised() && !pThis->IsClearlyVisibleTo(HouseClass::CurrentPlayer))
{
const auto pTargetType = TechnoTypeExt::GetTechnoType(pThis->GetDisguise(true));

if (pTargetType && pTargetType->Turret)
{
GET(DirStruct*, dir, EAX);
*dir = pThis->PrimaryFacing.Current();
}
}

return 0;
}

DEFINE_HOOK(0x73B8E3, UnitClass_DrawVoxel_HasChargeTurret, 0x5)
{
GET(UnitClass*, pThis, EBP);
GET(UnitTypeClass*, pType, EBX);

if (pType != pThis->Type)
{
if (pType->TurretCount > 0 && !pType->IsGattling)
return 0x73B8EC;
else
return 0x73B92F;
}
else
{
if (!pType->HasMultipleTurrets() || pType->IsGattling)
return 0x73B92F;
else
return 0x73B8FC;
}
}

DEFINE_HOOK(0x73BC28, UnitClass_DrawVoxel_HasChargeTurret2, 0x5)
{
GET(UnitClass*, pThis, EBP);
GET(UnitTypeClass*, pType, EBX);

if (pType != pThis->Type)
{
if (pType->TurretCount > 0 && !pType->IsGattling)
{
if (pThis->CurrentTurretNumber < 0)
R->Stack<int>(0x1C, 0);

return 0x73BC35;
}
else
{
return 0x73BD79;
}
}
else
{
if (!pType->HasMultipleTurrets() || pType->IsGattling)
return 0x73BD79;
else
return 0x73BC49;
}
}

DEFINE_HOOK(0x73BA63, UnitClass_DrawVoxel_TurretOffset, 0x5)
{
GET(UnitClass*, pThis, EBP);
GET(UnitTypeClass*, pType, EBX);

if (pType != pThis->Type)
{
if (pType->TurretCount > 0 && !pType->IsGattling)
{
if (pThis->CurrentTurretNumber < 0)
R->Stack<int>(0x1C, 0);

return 0x73BC35;
}
else
{
return 0x73BD79;
}
}

return 0;
}

DEFINE_JUMP(LJMP, 0x706724, 0x706731);

#pragma endregion

#pragma endregion

#pragma region AttackMindControlledDelay
Expand Down
37 changes: 28 additions & 9 deletions src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,21 +245,40 @@ DEFINE_HOOK(0x6F42F7, TechnoClass_Init, 0x2)

DEFINE_HOOK(0x6F421C, TechnoClass_Init_DefaultDisguise, 0x6)
{
GET(TechnoClass*, pThis, ESI);
enum { DefaultDisguise = 0x6F4277 };

auto const pExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());
GET(TechnoClass*, pThis, ESI);
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType());

// mirage is not here yet
if (pThis->WhatAmI() == AbstractType::Infantry && pExt->DefaultDisguise)
switch (pThis->WhatAmI())
{
pThis->Disguise = pExt->DefaultDisguise;
pThis->DisguisedAsHouse = pThis->Owner;
pThis->Disguised = true;
return 0x6F4277;
case AbstractType::Unit:
if (const auto pDefault = pTypeExt->DefaultVehicleDisguise.Get())
{
pThis->Disguise = pDefault;
pThis->DisguisedAsHouse = pThis->Owner;
pThis->Disguised = true;
return DefaultDisguise;
}

break;

case AbstractType::Infantry:
if (const auto pDefault = pTypeExt->DefaultDisguise.Get())
{
pThis->Disguise = pDefault;
pThis->DisguisedAsHouse = pThis->Owner;
pThis->Disguised = true;
return DefaultDisguise;
}

break;

default:
break;
}

pThis->Disguised = false;

return 0;
}

Expand Down
2 changes: 2 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->NotHuman_RandomDeathSequence.Read(exINI, pSection, "NotHuman.RandomDeathSequence");

this->DefaultDisguise.Read(exINI, pSection, "DefaultDisguise");
this->DefaultVehicleDisguise.Read(exINI, pSection, "DefaultVehicleDisguise");
this->UseDisguiseMovementSpeed.Read(exINI, pSection, "UseDisguiseMovementSpeed");

this->OpenTopped_RangeBonus.Read(exINI, pSection, "OpenTopped.RangeBonus");
Expand Down Expand Up @@ -1319,6 +1320,7 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->DestroyAnim_Random)
.Process(this->NotHuman_RandomDeathSequence)
.Process(this->DefaultDisguise)
.Process(this->DefaultVehicleDisguise)
.Process(this->UseDisguiseMovementSpeed)
.Process(this->WeaponBurstFLHs)
.Process(this->EliteWeaponBurstFLHs)
Expand Down
Loading
Loading