Skip to content

Commit

Permalink
Teleport/Tunnel loco tilting fixes (Phobos-developers#1213)
Browse files Browse the repository at this point in the history
  • Loading branch information
chaserli authored Mar 2, 2024
1 parent 1a76acc commit e1e0178
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 32 deletions.
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ This page lists all the individual contributions to the project by their author.
- TechnoType conversion placeholder
- EIP 00529A14 crash fix on Linux
- Teleport timer reset after load game fix
- Teleport and Tunnel loco visual tilt fix
- Skip units' turret rotation and jumpjets' wobbling under EMP
- Misc code refactor & maintenance, CN doc fixes, bugfixes
- **FlyStar**
Expand Down
2 changes: 1 addition & 1 deletion YRpp
2 changes: 2 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ This page describes all ingame logics that are fixed or improved in Phobos witho
- Fixed `AmbientDamage` when used with `IsRailgun=yes` being cut off by elevation changes.
- Fixed railgun and fire particles being cut off by elevation changes.
- Fixed teleport units' (for example CLEG) frozen-still timer being cleared after load game.
- Fixed teleport units being unable to visually tilt on slopes.
- Fixed units with Teleport or Tunnel locomotor being unable to be visually flipped like other locomotors do.
- Aircraft docking on buildings now respect `[AudioVisual]`->`PoseDir` as the default setting and do not always land facing north or in case of pre-placed buildings, the building's direction.
- Spawned aircraft now align with the spawner's facing when landing.

Expand Down
4 changes: 3 additions & 1 deletion docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,9 +411,11 @@ Vanilla fixes:
- Fixed `AmbientDamage` when used with `IsRailgun=yes` being cut off by elevation changes (by Starkku)
- Fixed railgun and fire particles being cut off by elevation changes (by Starkku)
- Fixed teleport units' frozen-still timer being reset after load game (by Trsdy)
- Fixed teleport units being unable to visually tilt on slopes (by Trsdy)
- Fixed teleport and drill units being unable to be visually flipped (by Trsdy)
- Aircraft docking on buildings now respect `[AudioVisual]`->`PoseDir` as the default setting and do not always land facing north or in case of pre-placed buildings, the building's direction (by Starkku)
- Spawned aircraft now align with the spawner's facing when landing (by Starkku)
-
Phobos fixes:
- Fixed a few errors of calling for superweapon launch by `LaunchSW` or building infiltration (by Trsdy)
- Add `ImmuneToCrit` for shields (by Trsdy)
Expand Down
98 changes: 69 additions & 29 deletions src/Ext/TechnoType/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <Ext/Techno/Body.h>

#include <Utilities/Macro.h>
#include <Utilities/AresHelper.h>

DEFINE_HOOK(0x6F64A9, TechnoClass_DrawHealthBar_Hide, 0x5)
{
Expand All @@ -26,7 +27,7 @@ DEFINE_HOOK(0x6F64A9, TechnoClass_DrawHealthBar_Hide, 0x5)
return 0;
}

DEFINE_HOOK(0x6F3C56, TechnoClass_Transform_6F3AD0_TurretMultiOffset, 0x0)
DEFINE_HOOK(0x6F3C56, TechnoClass_GetFLH_TurretMultiOffset, 0x0)
{
LEA_STACK(Matrix3D*, mtx, STACK_OFFSET(0xD8, -0x90));
GET(TechnoTypeClass*, technoType, EDX);
Expand Down Expand Up @@ -58,14 +59,14 @@ DEFINE_HOOK(0x73B780, UnitClass_DrawVXL_TurretMultiOffset, 0x0)
return 0x73B790;
}

constexpr reference<double, 0xB1D008> const Pixel_Per_Lepton {};

DEFINE_HOOK(0x73BA4C, UnitClass_DrawVXL_TurretMultiOffset1, 0x0)
{
LEA_STACK(Matrix3D*, mtx, STACK_OFFSET(0x1D0, -0x13C));
GET(TechnoTypeClass*, technoType, EBX);

double& factor = *reinterpret_cast<double*>(0xB1D008);

TechnoTypeExt::ApplyTurretOffset(technoType, mtx, factor);
TechnoTypeExt::ApplyTurretOffset(technoType, mtx, Pixel_Per_Lepton);

return 0x73BA68;
}
Expand Down Expand Up @@ -105,7 +106,7 @@ DEFINE_HOOK(0x73CCE1, UnitClass_DrawSHP_TurretOffest, 0x6)
float angle = static_cast<float>(turretRad - bodyRad);
mtx.RotateZ(angle);

auto res = Matrix3D::MatrixMultiply(mtx, Vector3D<float>::Empty);
auto res = mtx.GetTranslation();
auto location = CoordStruct { static_cast<int>(res.X), static_cast<int>(-res.Y), static_cast<int>(res.Z) };

pos += TacticalClass::CoordsToScreen(location);
Expand Down Expand Up @@ -338,49 +339,88 @@ DEFINE_HOOK(0x4DB157, FootClass_DrawVoxelShadow_TurretShadow, 0x8)
GET(FootClass*, pThis, ESI);
GET_STACK(Point2D, pos, STACK_OFFSET(0x18, 0x28));
GET_STACK(Surface*, pSurface, STACK_OFFSET(0x18, 0x24));
GET_STACK(bool, a9, STACK_OFFSET(0x18, 0x20)); // unknown usage
GET_STACK(bool, a9, STACK_OFFSET(0x18, 0x20));
GET_STACK(Matrix3D*, pMatrix, STACK_OFFSET(0x18, 0x1C));
GET_STACK(Point2D*, a4, STACK_OFFSET(0x18, 0x14)); // unknown usage
GET_STACK(Point2D, a3, STACK_OFFSET(0x18, -0x10)); // unknown usage
GET_STACK(int*, a5, STACK_OFFSET(0x18, 0x10)); // unknown usage
GET_STACK(int, angle, STACK_OFFSET(0x18, 0xC));
GET_STACK(int, idx, STACK_OFFSET(0x18, 0x8));
GET_STACK(VoxelStruct*, pVXL, STACK_OFFSET(0x18, 0x4));
GET_STACK(RectangleStruct*, bound, STACK_OFFSET(0x18, 0x14));
GET_STACK(Point2D, a3, STACK_OFFSET(0x18, -0x10));
GET_STACK(decltype(ObjectTypeClass::VoxelShadowCache)*, shadow_cache, STACK_OFFSET(0x18, 0x10));
GET_STACK(VoxelIndexKey, index_key, STACK_OFFSET(0x18, 0xC));
GET_STACK(int, shadow_index, STACK_OFFSET(0x18, 0x8));
GET_STACK(VoxelStruct*, main_vxl, STACK_OFFSET(0x18, 0x4));

auto pType = pThis->GetTechnoType();
auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
auto tur = pType->Gunner || pType->IsChargeTurret
? &pType->ChargerTurrets[pThis->CurrentTurretNumber]
: &pType->TurretVoxel;

if (pTypeExt->TurretShadow.Get(RulesExt::Global()->DrawTurretShadow) && tur->VXL && tur->HVA)

// We need to handle Ares turrets/barrels
struct DummyExtHere
{
auto mtx = pThis->Locomotor->Shadow_Matrix(0);
pTypeExt->ApplyTurretOffset(&mtx, *reinterpret_cast<double*>(0xB1D008));
char before[0xA4];
std::vector<VoxelStruct> ChargerTurrets;
std::vector<VoxelStruct> ChargerBarrels;
};

auto GetTurretVoxel = [pType](int idx) ->VoxelStruct*
{
if (pType->TurretCount == 0 || pType->IsGattling || idx < 0)
return &pType->TurretVoxel;

if (idx < 18)
return &pType->ChargerTurrets[idx];

if (CAN_USE_ARES && AresHelper::CanUseAres)
{
auto* aresTypeExt = reinterpret_cast<DummyExtHere*>(pType->align_2FC);
return &aresTypeExt->ChargerTurrets[idx - 18];
}

return nullptr;
};

auto GetBarrelVoxel = [pType](int idx)->VoxelStruct*
{
if (pType->TurretCount == 0 || pType->IsGattling || idx < 0)
return &pType->BarrelVoxel;

if (idx < 18)
return &pType->ChargerBarrels[idx];

if (CAN_USE_ARES && AresHelper::CanUseAres)
{
auto* aresTypeExt = reinterpret_cast<DummyExtHere*>(pType->align_2FC);
return &aresTypeExt->ChargerBarrels[idx - 18];
}

return nullptr;
};

auto tur = GetTurretVoxel(pThis->CurrentTurretNumber);

if (tur && pTypeExt->TurretShadow.Get(RulesExt::Global()->DrawTurretShadow) && tur->VXL && tur->HVA)
{
auto mtx = Matrix3D::GetIdentity();
pTypeExt->ApplyTurretOffset(&mtx, Pixel_Per_Lepton);
mtx.TranslateZ(-tur->HVA->Matrixes[0].GetZVal());
mtx.RotateZ(static_cast<float>(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>()));
Matrix3D::MatrixMultiply(&mtx, &Matrix3D::VoxelDefaultMatrix, &mtx);
mtx = *pMatrix * mtx;

pThis->DrawVoxelShadow(tur, 0, index_key, nullptr, bound, &a3, &mtx, a9, pSurface, pos);

pThis->DrawVoxelShadow(tur, 0, angle, 0, a4, &a3, &mtx, a9, pSurface, pos);
auto bar = &pType->BarrelVoxel;
auto bar = GetBarrelVoxel(pThis->CurrentTurretNumber);

if (bar->VXL && bar->HVA)
pThis->DrawVoxelShadow(bar, 0, angle, 0, a4, &a3, &mtx, a9, pSurface, pos);
if (bar && bar->VXL && bar->HVA)
pThis->DrawVoxelShadow(bar, 0, index_key, nullptr, bound, &a3, &mtx, a9, pSurface, pos);
}

if (!pTypeExt->ShadowIndices.size())
{
pThis->DrawVoxelShadow(pVXL, idx, angle, a5, a4, &a3, pMatrix, a9, pSurface, pos);
pThis->DrawVoxelShadow(main_vxl, shadow_index, index_key, shadow_cache, bound, &a3, pMatrix, a9, pSurface, pos);
}
else
{
for (auto index : pTypeExt->ShadowIndices)
{
auto hva = pVXL->HVA;
Matrix3D idxmtx = *pMatrix;
idxmtx.TranslateZ(-hva->Matrixes[index].GetZVal());
Matrix3D::MatrixMultiply(&idxmtx, &Matrix3D::VoxelDefaultMatrix, &idxmtx);
pThis->DrawVoxelShadow(pVXL, index, angle, a5, a4, &a3, pMatrix, a9, pSurface, pos);
pThis->DrawVoxelShadow(main_vxl, index, index_key, shadow_cache, bound, &a3, pMatrix, a9, pSurface, pos);
}
}

Expand Down
55 changes: 55 additions & 0 deletions src/Ext/Unit/Hooks.Jumpjet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,58 @@ void __stdcall JumpjetLocomotionClass_Unlimbo(ILocomotion* pThis)
}

DEFINE_JUMP(VTABLE, 0x7ECDB8, GET_OFFSET(JumpjetLocomotionClass_Unlimbo))


// Visual bugfix : Teleport loco vxls could not tilt
Matrix3D* __stdcall TeleportLocomotionClass_Draw_Matrix(ILocomotion* iloco, Matrix3D* ret, VoxelIndexKey* pIndex)
{
__assume(iloco != nullptr);
auto const pThis = static_cast<LocomotionClass*>(iloco);
auto linked = pThis->LinkedTo;
auto slope_idx = MapClass::Instance->GetCellAt(linked->Location)->SlopeIndex;

if (pIndex && pIndex->Is_Valid_Key())
*(int*)(pIndex) = slope_idx + (*(int*)(pIndex) << 6);

if (slope_idx && pIndex && pIndex->Is_Valid_Key())
*ret = Matrix3D::VoxelRampMatrix[slope_idx] * pThis->LocomotionClass::Draw_Matrix(pIndex);
else
*ret = pThis->LocomotionClass::Draw_Matrix(pIndex);

float arf = linked->AngleRotatedForwards;
float ars = linked->AngleRotatedSideways;

if (std::abs(ars) >= 0.005 || std::abs(arf) >= 0.005)
{
if (pIndex)// just forget it bro, no one cares
*(int*)pIndex = -1;

double scalex = linked->GetTechnoType()->VoxelScaleX;
double scaley = linked->GetTechnoType()->VoxelScaleY;

Matrix3D pre = Matrix3D::GetIdentity();
pre.TranslateZ(float(std::abs(Math::sin(ars)) * scalex + std::abs(Math::sin(arf)) * scaley));
ret->TranslateX(float(Math::sgn(arf) * (scaley * (1 - Math::cos(arf)))));
ret->TranslateY(float(Math::sgn(-ars) * (scalex * (1 - Math::cos(ars)))));
ret->RotateX(ars);
ret->RotateY(arf);

*ret = pre * *ret;
}
return ret;
}

DEFINE_JUMP(VTABLE, 0x7F5024, GET_OFFSET(TeleportLocomotionClass_Draw_Matrix));
DEFINE_JUMP(VTABLE, 0x7F5028, 0x5142A0);//TeleportLocomotionClass_Shadow_Matrix : just use hover's to save my time

// Visual bugfix: Tunnel loco could not tilt when being flipped
DEFINE_HOOK(0x729B5D, TunnelLocomotionClass_DrawMatrix_Tilt, 0x8)
{
GET(ILocomotion*, iloco, ESI);
GET_BASE(VoxelIndexKey*, pIndex, 0x10);
GET_BASE(Matrix3D*, ret, 0xC);
R->EAX(TeleportLocomotionClass_Draw_Matrix(iloco, ret, pIndex));
return 0x729C09;
}

DEFINE_JUMP(VTABLE, 0x7F5A4C, 0x5142A0);//TunnelLocomotionClass_Shadow_Matrix : just use hover's to save my time
6 changes: 5 additions & 1 deletion src/Misc/Hooks.BugFixes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,4 +794,8 @@ DEFINE_HOOK(0x689EB0, ScenarioClass_ReadMap_SkipHeaderInCampaign, 0x6)
return SessionClass::IsCampaign() ? 0x689FC0 : 0;
}

DEFINE_JUMP(LJMP, 0x719CBC, 0x719CD8);//Skip incorrect load ctor call in TeleportLocomotionClass_Load
//Skip incorrect load ctor call in various LocomotionClass_Load
DEFINE_JUMP(LJMP, 0x719CBC, 0x719CD8);//Teleport, notorious CLEG frozen state removal on loading game
DEFINE_JUMP(LJMP, 0x72A16A, 0x72A186);//Tunnel, not a big deal
DEFINE_JUMP(LJMP, 0x663428, 0x663445);//Rocket, not a big deal
DEFINE_JUMP(LJMP, 0x5170CE, 0x5170E0);//Hover, not a big deal

0 comments on commit e1e0178

Please sign in to comment.