From 8910e9943863f52098c66c4101f6f67d5fa136d2 Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Sun, 13 Apr 2025 20:19:06 +0800 Subject: [PATCH 1/7] Core --- CREDITS.md | 1 + docs/Fixed-or-Improved-Logics.md | 23 +++ docs/Whats-New.md | 1 + src/Ext/Techno/Hooks.Firing.cpp | 9 ++ src/Ext/TechnoType/Hooks.MatrixOp.cpp | 212 +++++++++++++++++++++++--- src/Ext/WeaponType/Body.cpp | 2 + src/Ext/WeaponType/Body.h | 2 + src/Misc/Hooks.BugFixes.cpp | 8 + 8 files changed, 240 insertions(+), 18 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index f6953db038..6032379f43 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -439,6 +439,7 @@ This page lists all the individual contributions to the project by their author. - Fix an issue that MCV will self-destruct when using trigger 107 to teleport - Fix an issue that moving MCV with Teleport locomotion will cause reconnection error - Jumpjet Tilts While Moving + - Restore turret recoil effect - **Noble Fish (DeathFish, DeathFishAtEase)** - Documentation maintenance - Chinese documentation maintenance and translation diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 1a64b4b575..0749cf04db 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1472,6 +1472,29 @@ In `artmd.ini`: TurretShadow= ; boolean ``` +### Turret recoil + +- Now you can use `TurretRecoil` to control units’ turret/barrel recoil effect when firing. + - `TurretTravel` and `BarrelTravel` control the maximum recoil distance. + - `TurretRecoil.Suppress` can prevent the weapon from producing this effect when firing. + +In `rulesmd.ini`: +```ini +[SOMEVEHICLE] ; VehicleType +TurretRecoil=no ; boolean +TurretTravel=2 ; integer, pixels +TurretCompressFrames=1 ; integer, game frames +TurretHoldFrames=1 ; integer, game frames +TurretRecoverFrames=1 ; integer, game frames +BarrelTravel=2 ; integer, pixels +BarrelCompressFrames=1 ; integer, game frames +BarrelHoldFrames=1 ; integer, game frames +BarrelRecoverFrames=1 ; integer, game frames + +[SOMEWEAPON] ; WeaponType +TurretRecoil.Suppress=no ; boolean +``` + ## Veinholes & Weeds ### Veinholes diff --git a/docs/Whats-New.md b/docs/Whats-New.md index efc41754ed..5221da2fbc 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -359,6 +359,7 @@ New: - Jumpjet Tilts While Moving (by CrimRecya) - [Spawned aircraft facing to match turret toggle](New-or-Enhanced-Logics.md#aircraft-spawner-customizations) (by Starkku) - Removed dependency on `blowfish.dll` (by ZivDero) +- Restore turret recoil effect (by CrimRecya) Vanilla fixes: - Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl) diff --git a/src/Ext/Techno/Hooks.Firing.cpp b/src/Ext/Techno/Hooks.Firing.cpp index 2f592e8ea9..9c70aff6a7 100644 --- a/src/Ext/Techno/Hooks.Firing.cpp +++ b/src/Ext/Techno/Hooks.Firing.cpp @@ -583,6 +583,15 @@ DEFINE_HOOK(0x6FF43F, TechnoClass_FireAt_FeedbackWeapon, 0x6) return 0; } +DEFINE_HOOK(0x6FF0DD, TechnoClass_FireAt_TurretRecoil, 0x6) +{ + enum { SkipGameCode = 0x6FF15B }; + + GET_STACK(WeaponTypeClass* const, pWeapon, STACK_OFFSET(0xB0, -0x70)); + + return WeaponTypeExt::ExtMap.Find(pWeapon)->TurretRecoil_Suppress ? SkipGameCode : 0; +} + DEFINE_HOOK(0x6FF905, TechnoClass_FireAt_FireOnce, 0x6) { GET(TechnoClass*, pThis, ESI); diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index b26cc10527..5ac1056c44 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -44,14 +44,189 @@ DEFINE_HOOK(0x73B780, UnitClass_DrawVXL_TurretMultiOffset, 0x0) return 0x73B790; } -DEFINE_HOOK(0x73BA4C, UnitClass_DrawVXL_TurretMultiOffset1, 0x0) +struct DummyTypeExtHere +{ + char _[0xA4]; + std::vector ChargerTurrets; + std::vector ChargerBarrels; + char __[0x120]; + UnitTypeClass* WaterImage; + VoxelStruct NoSpawnAltVXL; +}; + +DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) { - LEA_STACK(Matrix3D*, mtx, STACK_OFFSET(0x1D0, -0x13C)); - GET(TechnoTypeClass*, technoType, EBX); + enum { SkipGameCode = 0x73BEA4 }; + + GET(UnitClass* const, pThis, EBP); + GET(UnitTypeClass* const, pDrawType, EBX); + GET_STACK(const bool, haveTurretCache, STACK_OFFSET(0x1C4, -0x1B3)); + GET_STACK(const bool, haveBarrelVXL, STACK_OFFSET(0x1C4, -0x1B2)); + GET(const bool, haveBarrelCache, EAX); + LEA_STACK(Matrix3D* const, pMtx_buffer1, STACK_OFFSET(0x1C4, -0x130)); + LEA_STACK(Matrix3D* const, pMtx_turret, STACK_OFFSET(0x1C4, -0xF0)); + LEA_STACK(Matrix3D* const, pMtx_barrel, STACK_OFFSET(0x1C4, -0x90)); + + if (haveTurretCache && (!haveBarrelVXL || haveBarrelCache) && (!pDrawType->TurretRecoil // When in recoiling, need to recalculate drawing matrix + || pThis->TurretRecoil.State == RecoilData::RecoilState::Inactive && pThis->BarrelRecoil.State == RecoilData::RecoilState::Inactive)) + { + memcpy(pMtx_turret, pMtx_buffer1, sizeof(Matrix3D)); + memcpy(pMtx_barrel, pMtx_buffer1, sizeof(Matrix3D)); + } + else + { + LEA_STACK(Matrix3D* const, pMtx_buffer2, STACK_OFFSET(0x1C4, -0xC0)); + LEA_STACK(Matrix3D* const, pMtx_buffer3, STACK_OFFSET(0x1C4, -0x60)); + LEA_STACK(Matrix3D* const, pMtx_buffer4, STACK_OFFSET(0x1C4, -0x30)); + + // Turret + TechnoTypeExt::ApplyTurretOffset(pDrawType, pMtx_buffer1, Pixel_Per_Lepton); + pMtx_buffer1->RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); + + if (pDrawType->TurretRecoil && pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) + pMtx_buffer1->TranslateX(-pThis->TurretRecoil.TravelSoFar); + + memcpy(pMtx_buffer2, pMtx_buffer1, sizeof(Matrix3D)); + memcpy(pMtx_buffer4, &Matrix3D::VoxelDefaultMatrix, sizeof(Matrix3D)); + memcpy(pMtx_turret, Matrix3D::MatrixMultiply(pMtx_buffer3, pMtx_buffer4, pMtx_buffer1), sizeof(Matrix3D)); + + // Barrel + pMtx_buffer2->Translate(-pMtx_buffer1->Row[0].W, -pMtx_buffer1->Row[1].W, -pMtx_buffer1->Row[2].W); + pMtx_buffer2->RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); + + if (pDrawType->TurretRecoil && pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) + pMtx_buffer2->TranslateX(-pThis->BarrelRecoil.TravelSoFar); + + pMtx_buffer2->Translate(pMtx_buffer1->Row[0].W, pMtx_buffer1->Row[1].W, pMtx_buffer1->Row[2].W); + memcpy(pMtx_buffer3, &Matrix3D::VoxelDefaultMatrix, sizeof(Matrix3D)); + memcpy(pMtx_barrel, Matrix3D::MatrixMultiply(pMtx_buffer4, pMtx_buffer3, pMtx_buffer2), sizeof(Matrix3D)); + } + + GET_STACK(const int, flags, STACK_OFFSET(0x1C4, -0x198)); + GET_STACK(const int, brightness, STACK_OFFSET(0x1C4, 0x1C)); + GET_STACK(const int, hvaFrameIdx, STACK_OFFSET(0x1C4, -0x18C)); + LEA_STACK(Point2D* const, center, STACK_OFFSET(0x1C4, -0x194)); + LEA_STACK(RectangleStruct* const, rect, STACK_OFFSET(0x1C4, -0x164)); + + if (pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling) + { + bool notDrawBarrelYet = true; + const bool canDrawBarrel = pDrawType->BarrelVoxel.VXL && pDrawType->BarrelVoxel.HVA; + // When in recoiling, bypass cache and draw without saving + const bool inRecoil = pDrawType->TurretRecoil + && (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive + || pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive); + + // Barrel behind + if (canDrawBarrel) // Adjusted the inspection sequence + { + const auto dir = pThis->SecondaryFacing.Current().GetFacing<4>(); + + if (dir == 0 || dir == 3) + { + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + pThis->Draw_A_VXL(&pDrawType->BarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + + notDrawBarrelYet = false; + } + } + + // Turret + const auto turKey = inRecoil ? -1 : flags; + const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); + + pThis->Draw_A_VXL(&pDrawType->TurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, pMtx_turret, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + + // Barrel above + if (canDrawBarrel && notDrawBarrelYet) // Adjusted the inspection sequence + { + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + pThis->Draw_A_VXL(&pDrawType->BarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + } + } + else + { + GET_STACK(const int, currentTurretNumber, STACK_OFFSET(0x1C4, -0x1A8)); - TechnoTypeExt::ApplyTurretOffset(technoType, mtx, Pixel_Per_Lepton); + bool notDrawBarrelYet = true; + // When in recoiling, bypass cache and draw without saving + const bool inRecoil = pDrawType->TurretRecoil + && (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive + || pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive); - return 0x73BA68; + // Barrel behind + if (haveBarrelVXL) // Adjusted the inspection sequence + { + const auto dir = pThis->SecondaryFacing.Current().GetFacing<4>(); + + if (dir == 0 || dir == 3) + { + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + auto GetBarrelVoxel = [pDrawType](int idx)->VoxelStruct* + { + if (idx < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerBarrels[idx]; + + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerBarrels[idx - 18]; + }; + const auto pBarrelVoxel = GetBarrelVoxel(currentTurretNumber); + + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + + notDrawBarrelYet = false; + } + } + + // Turret + const auto turKey = inRecoil ? -1 : flags; + const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); + + auto GetTurretVoxel = [pDrawType](int idx) ->VoxelStruct* + { + if (idx < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerTurrets[idx]; + + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerTurrets[idx - 18]; + }; + const auto pTurretVoxel = GetTurretVoxel(currentTurretNumber); + + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, pMtx_turret, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + + // Barrel above + if (haveBarrelVXL && notDrawBarrelYet) // Adjusted the inspection sequence + { + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + auto GetBarrelVoxel = [pDrawType](int idx)->VoxelStruct* + { + if (idx < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerBarrels[idx]; + + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerBarrels[idx - 18]; + }; + const auto pBarrelVoxel = GetBarrelVoxel(currentTurretNumber); + + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + } + } + + return SkipGameCode; } DEFINE_HOOK(0x73C890, UnitClass_DrawSHP_BarrelMultiOffset, 0x0) @@ -330,16 +505,6 @@ Matrix3D* __stdcall TunnelLocomotionClass_ShadowMatrix(ILocomotion* iloco, Matri } DEFINE_FUNCTION_JUMP(VTABLE, 0x7F5A4C, TunnelLocomotionClass_ShadowMatrix); -struct DummyTypeExtHere -{ - char _[0xA4]; - std::vector ChargerTurrets; - std::vector ChargerBarrels; - char __[0x120]; - UnitTypeClass* WaterImage; - VoxelStruct NoSpawnAltVXL; -}; - DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) { GET(UnitClass*, pThis, EBP); @@ -506,6 +671,10 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) uTypeExt->ApplyTurretOffset(&mtx, Pixel_Per_Lepton); mtx.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); + auto inRecoil = pType->TurretRecoil && pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive; + if (inRecoil) + mtx.TranslateX(-pThis->TurretRecoil.TravelSoFar); + auto tur = GetTurretVoxel(pThis->CurrentTurretNumber); if (!(tur && tur->VXL && tur->HVA)) return SkipDrawing; @@ -530,17 +699,23 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) pThis->DrawVoxelShadow( tur, 0, - vxl_index_key, - cache, + (inRecoil ? VoxelIndexKey(-1) : vxl_index_key), + (inRecoil ? nullptr : cache), bnd, &why, &mtx, - cache != nullptr, + (!inRecoil && cache != nullptr), surface, shadow_point ); if (haveBar)// you are utterly fucked, for now + { + if (pType->TurretRecoil && pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) + mtx.TranslateX(-pThis->BarrelRecoil.TravelSoFar); + + mtx.ScaleX(static_cast(Math::cos(-pThis->BarrelFacing.Current().GetRadian<32>()))); + pThis->DrawVoxelShadow( bar, 0, @@ -553,6 +728,7 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) surface, shadow_point ); + } return SkipDrawing; } diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index ce628924a0..7948e7cd58 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -102,6 +102,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->ChargeTurret_Delays.Read(exINI, pSection, "ChargeTurret.Delays"); this->OmniFire_TurnToTarget.Read(exINI, pSection, "OmniFire.TurnToTarget"); this->FireOnce_ResetSequence.Read(exINI, pSection, "FireOnce.ResetSequence"); + this->TurretRecoil_Suppress.Read(exINI, pSection, "TurretRecoil.Suppress"); this->ExtraWarheads.Read(exINI, pSection, "ExtraWarheads"); this->ExtraWarheads_DamageOverrides.Read(exINI, pSection, "ExtraWarheads.DamageOverrides"); this->ExtraWarheads_DetonationChances.Read(exINI, pSection, "ExtraWarheads.DetonationChances"); @@ -160,6 +161,7 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm) .Process(this->ChargeTurret_Delays) .Process(this->OmniFire_TurnToTarget) .Process(this->FireOnce_ResetSequence) + .Process(this->TurretRecoil_Suppress) .Process(this->ExtraWarheads) .Process(this->ExtraWarheads_DamageOverrides) .Process(this->ExtraWarheads_DetonationChances) diff --git a/src/Ext/WeaponType/Body.h b/src/Ext/WeaponType/Body.h index 323910a811..3790427da6 100644 --- a/src/Ext/WeaponType/Body.h +++ b/src/Ext/WeaponType/Body.h @@ -48,6 +48,7 @@ class WeaponTypeExt ValueableVector ChargeTurret_Delays; Valueable OmniFire_TurnToTarget; Valueable FireOnce_ResetSequence; + Valueable TurretRecoil_Suppress; ValueableVector ExtraWarheads; ValueableVector ExtraWarheads_DamageOverrides; ValueableVector ExtraWarheads_DetonationChances; @@ -102,6 +103,7 @@ class WeaponTypeExt , ChargeTurret_Delays {} , OmniFire_TurnToTarget { false } , FireOnce_ResetSequence { true } + , TurretRecoil_Suppress { false } , ExtraWarheads {} , ExtraWarheads_DamageOverrides {} , ExtraWarheads_DetonationChances {} diff --git a/src/Misc/Hooks.BugFixes.cpp b/src/Misc/Hooks.BugFixes.cpp index dd3da744a6..5cf88f8f5e 100644 --- a/src/Misc/Hooks.BugFixes.cpp +++ b/src/Misc/Hooks.BugFixes.cpp @@ -1344,6 +1344,14 @@ DEFINE_HOOK(0x6FC617, TechnoClass_GetFireError_Spawner, 0x8) #pragma endregion +#pragma region TurretRecoilReadFix + +// Skip incorrect copy, why do copy like this? +DEFINE_JUMP(LJMP, 0x715326, 0x715333); // TechnoTypeClass::LoadFromINI +// Then EDI is BarrelAnimData now, not incorrect TurretAnimData + +#pragma endregion + #pragma region TeamCloseRangeFix int __fastcall Check2DDistanceInsteadOf3D(ObjectClass* pSource, void* _, AbstractClass* pTarget) From ff577fbdbb35b2365673aa66bf73195c7e641c1e Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Sun, 13 Apr 2025 20:24:31 +0800 Subject: [PATCH 2/7] Doc --- CREDITS.md | 1 + docs/Whats-New.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 6032379f43..ebeb0d1b79 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -440,6 +440,7 @@ This page lists all the individual contributions to the project by their author. - Fix an issue that moving MCV with Teleport locomotion will cause reconnection error - Jumpjet Tilts While Moving - Restore turret recoil effect + - Fix an issue that `FireAngle` was not taken into account when drawing barrel in `TurretShadow` - **Noble Fish (DeathFish, DeathFishAtEase)** - Documentation maintenance - Chinese documentation maintenance and translation diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 5221da2fbc..8411398406 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -378,6 +378,7 @@ Vanilla fixes: Phobos fixes: - Fixed an issue that MCV will self-destruct when using trigger 107 to teleport (by CrimRecya) +- Fixed an issue that `FireAngle` was not taken into account when drawing barrel in `TurretShadow` (by CrimRecya) Fixes / interactions with other extensions: - Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades (by Ollerus) From c4b073eb0c56f4c15096324b7dd7f941700f01e7 Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Sun, 27 Apr 2025 12:00:44 +0800 Subject: [PATCH 3/7] Sync --- src/Ext/TechnoType/Hooks.MatrixOp.cpp | 288 ++++++++++++++------------ 1 file changed, 158 insertions(+), 130 deletions(-) diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index 0200226c87..e94cf39c5a 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -61,170 +61,198 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) GET(UnitClass* const, pThis, EBP); GET(UnitTypeClass* const, pDrawType, EBX); GET_STACK(const bool, haveTurretCache, STACK_OFFSET(0x1C4, -0x1B3)); - GET_STACK(const bool, haveBarrelVXL, STACK_OFFSET(0x1C4, -0x1B2)); + GET_STACK(const bool, haveBar, STACK_OFFSET(0x1C4, -0x1B2)); GET(const bool, haveBarrelCache, EAX); - LEA_STACK(Matrix3D* const, pMtx_buffer1, STACK_OFFSET(0x1C4, -0x130)); - LEA_STACK(Matrix3D* const, pMtx_turret, STACK_OFFSET(0x1C4, -0xF0)); - LEA_STACK(Matrix3D* const, pMtx_barrel, STACK_OFFSET(0x1C4, -0x90)); - - if (haveTurretCache && (!haveBarrelVXL || haveBarrelCache) && (!pDrawType->TurretRecoil // When in recoiling, need to recalculate drawing matrix - || pThis->TurretRecoil.State == RecoilData::RecoilState::Inactive && pThis->BarrelRecoil.State == RecoilData::RecoilState::Inactive)) - { - memcpy(pMtx_turret, pMtx_buffer1, sizeof(Matrix3D)); - memcpy(pMtx_barrel, pMtx_buffer1, sizeof(Matrix3D)); - } - else - { - LEA_STACK(Matrix3D* const, pMtx_buffer2, STACK_OFFSET(0x1C4, -0xC0)); - LEA_STACK(Matrix3D* const, pMtx_buffer3, STACK_OFFSET(0x1C4, -0x60)); - LEA_STACK(Matrix3D* const, pMtx_buffer4, STACK_OFFSET(0x1C4, -0x30)); - - // Turret - TechnoTypeExt::ApplyTurretOffset(pDrawType, pMtx_buffer1, Pixel_Per_Lepton); - pMtx_buffer1->RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); - - if (pDrawType->TurretRecoil && pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) - pMtx_buffer1->TranslateX(-pThis->TurretRecoil.TravelSoFar); - - memcpy(pMtx_buffer2, pMtx_buffer1, sizeof(Matrix3D)); - memcpy(pMtx_buffer4, &Matrix3D::VoxelDefaultMatrix, sizeof(Matrix3D)); - memcpy(pMtx_turret, Matrix3D::MatrixMultiply(pMtx_buffer3, pMtx_buffer4, pMtx_buffer1), sizeof(Matrix3D)); - - // Barrel - pMtx_buffer2->Translate(-pMtx_buffer1->Row[0].W, -pMtx_buffer1->Row[1].W, -pMtx_buffer1->Row[2].W); - pMtx_buffer2->RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); - - if (pDrawType->TurretRecoil && pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) - pMtx_buffer2->TranslateX(-pThis->BarrelRecoil.TravelSoFar); - - pMtx_buffer2->Translate(pMtx_buffer1->Row[0].W, pMtx_buffer1->Row[1].W, pMtx_buffer1->Row[2].W); - memcpy(pMtx_buffer3, &Matrix3D::VoxelDefaultMatrix, sizeof(Matrix3D)); - memcpy(pMtx_barrel, Matrix3D::MatrixMultiply(pMtx_buffer4, pMtx_buffer3, pMtx_buffer2), sizeof(Matrix3D)); - } - + REF_STACK(Matrix3D, draw_matrix, STACK_OFFSET(0x1C4, -0x130)); GET_STACK(const int, flags, STACK_OFFSET(0x1C4, -0x198)); GET_STACK(const int, brightness, STACK_OFFSET(0x1C4, 0x1C)); GET_STACK(const int, hvaFrameIdx, STACK_OFFSET(0x1C4, -0x18C)); + GET_STACK(const int, currentTurretNumber, STACK_OFFSET(0x1C4, -0x1A8)); LEA_STACK(Point2D* const, center, STACK_OFFSET(0x1C4, -0x194)); LEA_STACK(RectangleStruct* const, rect, STACK_OFFSET(0x1C4, -0x164)); - if (pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling) - { - bool notDrawBarrelYet = true; - const bool canDrawBarrel = pDrawType->BarrelVoxel.VXL && pDrawType->BarrelVoxel.HVA; - // When in recoiling, bypass cache and draw without saving - const bool inRecoil = pDrawType->TurretRecoil - && (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive - || pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive); - - // Barrel behind - if (canDrawBarrel) // Adjusted the inspection sequence + const auto mtx = Matrix3D::VoxelDefaultMatrix * draw_matrix; + const auto pExt = TechnoExt::ExtMap.Find(pThis); + const auto pDrawTypeExt = TechnoTypeExt::ExtMap.Find(pDrawType); + const bool notChargeTurret = pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling; + + auto getTurretVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* { - const auto dir = pThis->SecondaryFacing.Current().GetFacing<4>(); + if (notChargeTurret) + return &pDrawType->TurretVoxel; - if (dir == 0 || dir == 3) - { - const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + if (currentTurretNumber < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerTurrets[currentTurretNumber]; - pThis->Draw_A_VXL(&pDrawType->BarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerTurrets[currentTurretNumber - 18]; + }; + const auto pTurretVoxel = getTurretVoxel(); - notDrawBarrelYet = false; - } - } + auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* + { + if (notChargeTurret) + return &pDrawType->BarrelVoxel; + + if (currentTurretNumber < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerBarrels[currentTurretNumber]; - // Turret - const auto turKey = inRecoil ? -1 : flags; - const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; + }; + const auto pBarrelVoxel = haveBar ? getBarrelVoxel() : nullptr; - pThis->Draw_A_VXL(&pDrawType->TurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, pMtx_turret, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + const auto turretDir = pThis->SecondaryFacing.Current().GetFacing<4>(); + const bool turretRecoil = pDrawType->TurretRecoil; + const bool barrelOverTechno = pDrawTypeExt->BarrelOverTurret.Get(turretDir != 0 && turretDir != 3); + const bool shouldRedraw = !haveTurretCache || haveBar && !haveBarrelCache || turretRecoil; - // Barrel above - if (canDrawBarrel && notDrawBarrelYet) // Adjusted the inspection sequence + auto drawTurret = [=, &mtx](int turIdx) { - const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + const auto pTurData = turretRecoil ? ((turIdx < 0) ? &pThis->TurretRecoil : &pExt->ExtraTurretRecoil[turIdx]) : nullptr; + const auto turretInRecoil = pTurData && pTurData->State != RecoilData::RecoilState::Inactive; - pThis->Draw_A_VXL(&pDrawType->BarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); - } - } - else - { - GET_STACK(const int, currentTurretNumber, STACK_OFFSET(0x1C4, -0x1A8)); + const bool turShouldRedraw = shouldRedraw || turIdx >= 0; + const auto turKey = turShouldRedraw ? -1 : flags; + const auto turCache = turShouldRedraw ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); - bool notDrawBarrelYet = true; - // When in recoiling, bypass cache and draw without saving - const bool inRecoil = pDrawType->TurretRecoil - && (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive - || pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive); + auto getTurretMatrix = [=, &mtx]() -> Matrix3D + { + auto mtx_turret = mtx; + pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton, turIdx); + mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); - // Barrel behind - if (haveBarrelVXL) // Adjusted the inspection sequence - { - const auto dir = pThis->SecondaryFacing.Current().GetFacing<4>(); + if (turretInRecoil) + mtx_turret.TranslateX(-pTurData->TravelSoFar); - if (dir == 0 || dir == 3) - { - const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + return mtx_turret; + }; + auto mtx_turret = turShouldRedraw ? getTurretMatrix() : mtx; - auto GetBarrelVoxel = [pDrawType](int idx)->VoxelStruct* - { - if (idx < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerBarrels[idx]; + auto drawBarrel = [=, &mtx_turret, &mtx](int brlIdx) + { + const auto idx = brlIdx + ((turIdx + 1) * (pDrawTypeExt->ExtraBarrelCount + 1)); + const auto pBrlData = turretRecoil ? ((idx < 0) ? &pThis->BarrelRecoil : &pExt->ExtraBarrelRecoil[idx]) : nullptr; + const auto barrelInRecoil = pBrlData && pBrlData->State != RecoilData::RecoilState::Inactive; + + const bool brlShouldRedraw = shouldRedraw || brlIdx >= 0; + const auto brlKey = brlShouldRedraw ? -1 : flags; + const auto brlCache = brlShouldRedraw ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D + { + auto mtx_barrel = mtx_turret; + mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); + mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); + const auto offset = ((brlIdx < 0) ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[brlIdx]); + mtx_barrel.TranslateY(static_cast(Pixel_Per_Lepton * offset)); + + if (barrelInRecoil) + mtx_barrel.TranslateX(-pBrlData->TravelSoFar); + + mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); + return mtx_barrel; + }; + auto mtx_barrel = brlShouldRedraw ? getBarrelMatrix() : mtx; + + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + }; + + auto drawBarrels = [&drawBarrel, pDrawTypeExt, turretDir]() + { + const auto exBrlCount = pDrawTypeExt->ExtraBarrelCount.Get(); - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerBarrels[idx - 18]; - }; - const auto pBarrelVoxel = GetBarrelVoxel(currentTurretNumber); + if (exBrlCount > 0) + { + std::vector barrels; + barrels.emplace_back(-1); + + for (int i = 0; i < exBrlCount; ++i) + barrels.emplace_back(i); + + const auto barrelsSize = barrels.size(); + const bool faceRight = turretDir == 0 || turretDir == 1; + std::sort(&barrels[0], &barrels[barrelsSize],[pDrawTypeExt, faceRight](const auto& idxA, const auto& idxB) + { + const auto offsetA = idxA < 0 ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[idxA]; + const auto offsetB = idxB < 0 ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[idxB]; + + return faceRight ? (offsetA > offsetB) : (offsetA <= offsetB); + }); + + for (const auto& i : barrels) + drawBarrel(i); + } + else + { + drawBarrel(-1); + } + }; - pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, + if (barrelOverTechno) + { + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); - notDrawBarrelYet = false; + if (haveBar) + drawBarrels(); } - } + else + { + if (haveBar) + drawBarrels(); + + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, + static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + } + }; - // Turret - const auto turKey = inRecoil ? -1 : flags; - const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); + auto drawTurrets = [&drawTurret, pThis, pDrawTypeExt]() + { + const auto exTurCount = pDrawTypeExt->ExtraTurretCount.Get(); - auto GetTurretVoxel = [pDrawType](int idx) ->VoxelStruct* + if (exTurCount > 0) { - if (idx < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerTurrets[idx]; + std::vector turrets; + turrets.emplace_back(-1); - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerTurrets[idx - 18]; - }; - const auto pTurretVoxel = GetTurretVoxel(currentTurretNumber); + for (int i = 0; i < exTurCount; ++i) + turrets.emplace_back(i); - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, pMtx_turret, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + const auto turretsSize = turrets.size(); + std::sort(&turrets[0], &turrets[turretsSize],[pThis, pDrawTypeExt](const auto& idxA, const auto& idxB) + { + const auto pOffsetA = idxA < 0 ? static_cast(pDrawTypeExt->TurretOffset.GetEx()) : &pDrawTypeExt->ExtraTurretOffsets[idxA]; + const auto pOffsetB = idxB < 0 ? static_cast(pDrawTypeExt->TurretOffset.GetEx()) : &pDrawTypeExt->ExtraTurretOffsets[idxB]; - // Barrel above - if (haveBarrelVXL && notDrawBarrelYet) // Adjusted the inspection sequence - { - const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + if (pOffsetA->Z < pOffsetB->Z) + return true; - auto GetBarrelVoxel = [pDrawType](int idx)->VoxelStruct* - { - if (idx < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerBarrels[idx]; + if (pOffsetA->Z > pOffsetB->Z) + return false; - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerBarrels[idx - 18]; - }; - const auto pBarrelVoxel = GetBarrelVoxel(currentTurretNumber); + const auto pointA = TacticalClass::Instance->CoordsToClient(TechnoExt::GetFLHAbsoluteCoords(pThis, *pOffsetA)).first; + const auto pointB = TacticalClass::Instance->CoordsToClient(TechnoExt::GetFLHAbsoluteCoords(pThis, *pOffsetB)).first; - pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, pMtx_barrel, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); - } - } + if (pointA.Y < pointB.Y) + return true; + + if (pointA.Y > pointB.Y) + return false; + + return pointA.X <= pointB.X; + }); + + for (const auto& i : turrets) + drawTurret(i); + } + else + { + drawTurret(-1); + } + }; + drawTurrets(); return SkipGameCode; } From 13583ed53bf4081ba9e713b7e4bedd1ee9ab3791 Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Sun, 27 Apr 2025 12:27:04 +0800 Subject: [PATCH 4/7] Simplify --- src/Ext/TechnoType/Hooks.MatrixOp.cpp | 218 +++++++++----------------- 1 file changed, 71 insertions(+), 147 deletions(-) diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index e94cf39c5a..cb810d01cf 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -54,7 +54,7 @@ struct DummyTypeExtHere VoxelStruct NoSpawnAltVXL; }; -DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) +DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) { enum { SkipGameCode = 0x73BEA4 }; @@ -71,8 +71,9 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) LEA_STACK(Point2D* const, center, STACK_OFFSET(0x1C4, -0x194)); LEA_STACK(RectangleStruct* const, rect, STACK_OFFSET(0x1C4, -0x164)); + // base matrix const auto mtx = Matrix3D::VoxelDefaultMatrix * draw_matrix; - const auto pExt = TechnoExt::ExtMap.Find(pThis); + const auto pDrawTypeExt = TechnoTypeExt::ExtMap.Find(pDrawType); const bool notChargeTurret = pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling; @@ -81,6 +82,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) if (notChargeTurret) return &pDrawType->TurretVoxel; + // Not considering the situation where there is no Ares and the limit is exceeded if (currentTurretNumber < 18 || !AresHelper::CanUseAres) return &pDrawType->ChargerTurrets[currentTurretNumber]; @@ -89,170 +91,92 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteCalculateTurretMatrix, 0x6) }; const auto pTurretVoxel = getTurretVoxel(); - auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* - { - if (notChargeTurret) - return &pDrawType->BarrelVoxel; + // When in recoiling or have no cache, need to recalculate drawing matrix + const bool inRecoil = pDrawType->TurretRecoil && (pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive || pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive); + const bool shouldRedraw = !haveTurretCache || haveBar && !haveBarrelCache || inRecoil; - if (currentTurretNumber < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerBarrels[currentTurretNumber]; + // When in recoiling, need to bypass cache and draw without saving + const auto turKey = inRecoil ? -1 : flags; + const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; - }; - const auto pBarrelVoxel = haveBar ? getBarrelVoxel() : nullptr; - - const auto turretDir = pThis->SecondaryFacing.Current().GetFacing<4>(); - const bool turretRecoil = pDrawType->TurretRecoil; - const bool barrelOverTechno = pDrawTypeExt->BarrelOverTurret.Get(turretDir != 0 && turretDir != 3); - const bool shouldRedraw = !haveTurretCache || haveBar && !haveBarrelCache || turretRecoil; - - auto drawTurret = [=, &mtx](int turIdx) + auto getTurretMatrix = [=, &mtx]() -> Matrix3D { - const auto pTurData = turretRecoil ? ((turIdx < 0) ? &pThis->TurretRecoil : &pExt->ExtraTurretRecoil[turIdx]) : nullptr; - const auto turretInRecoil = pTurData && pTurData->State != RecoilData::RecoilState::Inactive; - - const bool turShouldRedraw = shouldRedraw || turIdx >= 0; - const auto turKey = turShouldRedraw ? -1 : flags; - const auto turCache = turShouldRedraw ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); - - auto getTurretMatrix = [=, &mtx]() -> Matrix3D - { - auto mtx_turret = mtx; - pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton, turIdx); - mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); + auto mtx_turret = mtx; + pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton); + mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); - if (turretInRecoil) - mtx_turret.TranslateX(-pTurData->TravelSoFar); + if (pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) + mtx_turret.TranslateX(-pThis->TurretRecoil.TravelSoFar); - return mtx_turret; - }; - auto mtx_turret = turShouldRedraw ? getTurretMatrix() : mtx; - - auto drawBarrel = [=, &mtx_turret, &mtx](int brlIdx) - { - const auto idx = brlIdx + ((turIdx + 1) * (pDrawTypeExt->ExtraBarrelCount + 1)); - const auto pBrlData = turretRecoil ? ((idx < 0) ? &pThis->BarrelRecoil : &pExt->ExtraBarrelRecoil[idx]) : nullptr; - const auto barrelInRecoil = pBrlData && pBrlData->State != RecoilData::RecoilState::Inactive; - - const bool brlShouldRedraw = shouldRedraw || brlIdx >= 0; - const auto brlKey = brlShouldRedraw ? -1 : flags; - const auto brlCache = brlShouldRedraw ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); - - auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D - { - auto mtx_barrel = mtx_turret; - mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); - mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); - const auto offset = ((brlIdx < 0) ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[brlIdx]); - mtx_barrel.TranslateY(static_cast(Pixel_Per_Lepton * offset)); - - if (barrelInRecoil) - mtx_barrel.TranslateX(-pBrlData->TravelSoFar); - - mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); - return mtx_barrel; - }; - auto mtx_barrel = brlShouldRedraw ? getBarrelMatrix() : mtx; - - pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); - }; - - auto drawBarrels = [&drawBarrel, pDrawTypeExt, turretDir]() - { - const auto exBrlCount = pDrawTypeExt->ExtraBarrelCount.Get(); - - if (exBrlCount > 0) - { - std::vector barrels; - barrels.emplace_back(-1); - - for (int i = 0; i < exBrlCount; ++i) - barrels.emplace_back(i); - - const auto barrelsSize = barrels.size(); - const bool faceRight = turretDir == 0 || turretDir == 1; - std::sort(&barrels[0], &barrels[barrelsSize],[pDrawTypeExt, faceRight](const auto& idxA, const auto& idxB) - { - const auto offsetA = idxA < 0 ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[idxA]; - const auto offsetB = idxB < 0 ? pDrawTypeExt->BarrelOffset.Get() : pDrawTypeExt->ExtraBarrelOffsets[idxB]; - - return faceRight ? (offsetA > offsetB) : (offsetA <= offsetB); - }); - - for (const auto& i : barrels) - drawBarrel(i); - } - else - { - drawBarrel(-1); - } - }; + return mtx_turret; + }; + auto mtx_turret = shouldRedraw ? getTurretMatrix() : mtx; - if (barrelOverTechno) - { - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); + // 10240u -> (BlitterFlags::Alpha | BlitterFlags::Flat); - if (haveBar) - drawBarrels(); - } - else + // Only when there is a barrel will its calculation and drawing be considered + if (haveBar) + { + auto drawBarrel = [=, &mtx_turret, &mtx]() { - if (haveBar) - drawBarrels(); + // When in recoiling, need to bypass cache and draw without saving + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, - static_cast(static_cast(BlitterFlags::Alpha | BlitterFlags::Flat)), 0); - } - }; - - auto drawTurrets = [&drawTurret, pThis, pDrawTypeExt]() - { - const auto exTurCount = pDrawTypeExt->ExtraTurretCount.Get(); + auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D + { + auto mtx_barrel = mtx_turret; + mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); + mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); - if (exTurCount > 0) - { - std::vector turrets; - turrets.emplace_back(-1); + if (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) + mtx_barrel.TranslateX(-pThis->BarrelRecoil.TravelSoFar); - for (int i = 0; i < exTurCount; ++i) - turrets.emplace_back(i); + mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); + return mtx_barrel; + }; + auto mtx_barrel = shouldRedraw ? getBarrelMatrix() : mtx; - const auto turretsSize = turrets.size(); - std::sort(&turrets[0], &turrets[turretsSize],[pThis, pDrawTypeExt](const auto& idxA, const auto& idxB) - { - const auto pOffsetA = idxA < 0 ? static_cast(pDrawTypeExt->TurretOffset.GetEx()) : &pDrawTypeExt->ExtraTurretOffsets[idxA]; - const auto pOffsetB = idxB < 0 ? static_cast(pDrawTypeExt->TurretOffset.GetEx()) : &pDrawTypeExt->ExtraTurretOffsets[idxB]; + auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* + { + if (notChargeTurret) + return &pDrawType->BarrelVoxel; - if (pOffsetA->Z < pOffsetB->Z) - return true; + // Not considering the situation where there is no Ares and the limit is exceeded + if (currentTurretNumber < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerBarrels[currentTurretNumber]; - if (pOffsetA->Z > pOffsetB->Z) - return false; + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; + }; + const auto pBarrelVoxel = getBarrelVoxel(); - const auto pointA = TacticalClass::Instance->CoordsToClient(TechnoExt::GetFLHAbsoluteCoords(pThis, *pOffsetA)).first; - const auto pointB = TacticalClass::Instance->CoordsToClient(TechnoExt::GetFLHAbsoluteCoords(pThis, *pOffsetB)).first; + // draw barrel + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, 10240u, 0); + }; - if (pointA.Y < pointB.Y) - return true; + const auto turretDir = pThis->SecondaryFacing.Current().GetFacing<4>(); - if (pointA.Y > pointB.Y) - return false; + // The orientation of the turret can affect the layer order of the barrel and turret + if (turretDir != 0 && turretDir != 3) + { + // draw turret + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); - return pointA.X <= pointB.X; - }); + drawBarrel(); + } + else + { + drawBarrel(); - for (const auto& i : turrets) - drawTurret(i); - } - else - { - drawTurret(-1); - } - }; - drawTurrets(); + // draw turret + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); + } + } + else + { + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); + } return SkipGameCode; } From dc6d46fd52daac3abc026fe797b51ac6c1de07ee Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Fri, 15 Aug 2025 23:10:53 +0800 Subject: [PATCH 5/7] Doc and code style thing --- docs/Fixed-or-Improved-Logics.md | 5 + src/Ext/TechnoType/Hooks.MatrixOp.cpp | 154 +++++++++++++------------- 2 files changed, 84 insertions(+), 75 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index d0593cc7d0..e32d6b4bf1 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -254,6 +254,7 @@ This page describes all ingame logics that are fixed or improved in Phobos witho - Fixed the bug that hover vehicle will sink if destroyed on bridge. - Fixed the fact that when the selected unit is in a rearmed state, it can unconditionally use attack mouse on the target. - 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. +- Fixed an issue that barrel anim data will be incorrectly overwritten by turret anim data if the techno's section exists in the map file. ## Fixes / interactions with other extensions @@ -1840,6 +1841,10 @@ BarrelRecoverFrames=1 ; integer, game frames TurretRecoil.Suppress=no ; boolean ``` +```{note} +This is not a 1:1 restoration but a separate thing, not like it was in *Tiberian Sun*. +``` + ### Customize harvester dump amount - Now you can limit how much ore the harvester can dump out per time, like it in Tiberium Sun. diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index b0d0068661..0d591901e5 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -79,17 +79,17 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) const bool notChargeTurret = pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling; auto getTurretVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* - { - if (notChargeTurret) - return &pDrawType->TurretVoxel; + { + if (notChargeTurret) + return &pDrawType->TurretVoxel; - // Not considering the situation where there is no Ares and the limit is exceeded - if (currentTurretNumber < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerTurrets[currentTurretNumber]; + // Not considering the situation where there is no Ares and the limit is exceeded + if (currentTurretNumber < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerTurrets[currentTurretNumber]; - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerTurrets[currentTurretNumber - 18]; - }; + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerTurrets[currentTurretNumber - 18]; + }; const auto pTurretVoxel = getTurretVoxel(); // When in recoiling or have no cache, need to recalculate drawing matrix @@ -101,16 +101,16 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); auto getTurretMatrix = [=, &mtx]() -> Matrix3D - { - auto mtx_turret = mtx; - pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton); - mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); + { + auto mtx_turret = mtx; + pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton); + mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); - if (pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) - mtx_turret.TranslateX(-pThis->TurretRecoil.TravelSoFar); + if (pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) + mtx_turret.TranslateX(-pThis->TurretRecoil.TravelSoFar); - return mtx_turret; - }; + return mtx_turret; + }; auto mtx_turret = shouldRedraw ? getTurretMatrix() : mtx; // 10240u -> (BlitterFlags::Alpha | BlitterFlags::Flat); @@ -119,42 +119,42 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) if (haveBar) { auto drawBarrel = [=, &mtx_turret, &mtx]() + { + // When in recoiling, need to bypass cache and draw without saving + const auto brlKey = inRecoil ? -1 : flags; + const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + + auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D { - // When in recoiling, need to bypass cache and draw without saving - const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); - - auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D - { - auto mtx_barrel = mtx_turret; - mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); - mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); - - if (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) - mtx_barrel.TranslateX(-pThis->BarrelRecoil.TravelSoFar); - - mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); - return mtx_barrel; - }; - auto mtx_barrel = shouldRedraw ? getBarrelMatrix() : mtx; - - auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* - { - if (notChargeTurret) - return &pDrawType->BarrelVoxel; - - // Not considering the situation where there is no Ares and the limit is exceeded - if (currentTurretNumber < 18 || !AresHelper::CanUseAres) - return &pDrawType->ChargerBarrels[currentTurretNumber]; - - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); - return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; - }; - const auto pBarrelVoxel = getBarrelVoxel(); - - // draw barrel - pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, 10240u, 0); + auto mtx_barrel = mtx_turret; + mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); + mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); + + if (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) + mtx_barrel.TranslateX(-pThis->BarrelRecoil.TravelSoFar); + + mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); + return mtx_barrel; + }; + auto mtx_barrel = shouldRedraw ? getBarrelMatrix() : mtx; + + auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* + { + if (notChargeTurret) + return &pDrawType->BarrelVoxel; + + // Not considering the situation where there is no Ares and the limit is exceeded + if (currentTurretNumber < 18 || !AresHelper::CanUseAres) + return &pDrawType->ChargerBarrels[currentTurretNumber]; + + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; }; + const auto pBarrelVoxel = getBarrelVoxel(); + + // draw barrel + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, 10240u, 0); + }; const auto turretDir = pThis->SecondaryFacing.Current().GetFacing<4>(); @@ -670,6 +670,7 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) if (uTypeExt->ShadowIndices.empty()) { if (pType->ShadowIndex >= 0 && pType->ShadowIndex < main_vxl->HVA->LayerCount) + { pThis->DrawVoxelShadow( main_vxl, pType->ShadowIndex, @@ -682,10 +683,12 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) surface, shadow_point ); + } } else { for (auto& [index, _] : uTypeExt->ShadowIndices) + { pThis->DrawVoxelShadow( main_vxl, index, @@ -698,6 +701,7 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) surface, shadow_point ); + } } } @@ -705,38 +709,38 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) return SkipDrawing; auto GetTurretVoxel = [pType](int idx) ->VoxelStruct* - { - if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) - return &pType->TurretVoxel; + { + if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) + return &pType->TurretVoxel; - if (idx < 18) - return &pType->ChargerTurrets[idx]; + if (idx < 18) + return &pType->ChargerTurrets[idx]; - if (AresHelper::CanUseAres) - { - auto* aresTypeExt = reinterpret_cast(pType->align_2FC); - return &aresTypeExt->ChargerTurrets[idx - 18]; - } + if (AresHelper::CanUseAres) + { + auto* aresTypeExt = reinterpret_cast(pType->align_2FC); + return &aresTypeExt->ChargerTurrets[idx - 18]; + } - return nullptr; - }; + return nullptr; + }; auto GetBarrelVoxel = [pType](int idx)->VoxelStruct* - { - if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) - return &pType->BarrelVoxel; + { + if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) + return &pType->BarrelVoxel; - if (idx < 18) - return &pType->ChargerBarrels[idx]; + if (idx < 18) + return &pType->ChargerBarrels[idx]; - if (AresHelper::CanUseAres) - { - auto* aresTypeExt = reinterpret_cast(pType->align_2FC); - return &aresTypeExt->ChargerBarrels[idx - 18]; - } + if (AresHelper::CanUseAres) + { + auto* aresTypeExt = reinterpret_cast(pType->align_2FC); + return &aresTypeExt->ChargerBarrels[idx - 18]; + } - return nullptr; - }; + return nullptr; + }; uTypeExt->ApplyTurretOffset(&mtx, Pixel_Per_Lepton); mtx.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); From d1bf8f1e8b1a4049c231120a11b0c357fe4a8d1b Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Fri, 15 Aug 2025 23:42:42 +0800 Subject: [PATCH 6/7] More doc and code style thing --- docs/Fixed-or-Improved-Logics.md | 2 +- src/Ext/TechnoType/Hooks.MatrixOp.cpp | 189 +++++++++++++------------- 2 files changed, 95 insertions(+), 96 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index e32d6b4bf1..4406147514 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1842,7 +1842,7 @@ TurretRecoil.Suppress=no ; boolean ``` ```{note} -This is not a 1:1 restoration but a separate thing, not like it was in *Tiberian Sun*. +The logic below was not reverse-engineered but reimplemented to achieve the same effect, hence there might be some differences in behavior compared to Tiberian Sun version. ``` ### Customize harvester dump amount diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index 0d591901e5..6997106ca9 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -45,7 +45,7 @@ DEFINE_HOOK(0x73B780, UnitClass_DrawVXL_TurretMultiOffset, 0x0) return 0x73B790; } -struct DummyTypeExtHere +struct AresTechnoTypeExt { char _[0xA4]; std::vector ChargerTurrets; @@ -64,7 +64,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) GET_STACK(const bool, haveTurretCache, STACK_OFFSET(0x1C4, -0x1B3)); GET_STACK(const bool, haveBar, STACK_OFFSET(0x1C4, -0x1B2)); GET(const bool, haveBarrelCache, EAX); - REF_STACK(Matrix3D, draw_matrix, STACK_OFFSET(0x1C4, -0x130)); + REF_STACK(Matrix3D, drawMatrix, STACK_OFFSET(0x1C4, -0x130)); GET_STACK(const int, flags, STACK_OFFSET(0x1C4, -0x198)); GET_STACK(const int, brightness, STACK_OFFSET(0x1C4, 0x1C)); GET_STACK(const int, hvaFrameIdx, STACK_OFFSET(0x1C4, -0x18C)); @@ -73,7 +73,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) LEA_STACK(RectangleStruct* const, rect, STACK_OFFSET(0x1C4, -0x164)); // base matrix - const auto mtx = Matrix3D::VoxelDefaultMatrix * draw_matrix; + const auto mtx = Matrix3D::VoxelDefaultMatrix * drawMatrix; const auto pDrawTypeExt = TechnoTypeExt::ExtMap.Find(pDrawType); const bool notChargeTurret = pThis->Type->TurretCount <= 0 || pThis->Type->IsGattling; @@ -87,7 +87,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) if (currentTurretNumber < 18 || !AresHelper::CanUseAres) return &pDrawType->ChargerTurrets[currentTurretNumber]; - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); return &aresTypeExt->ChargerTurrets[currentTurretNumber - 18]; }; const auto pTurretVoxel = getTurretVoxel(); @@ -102,41 +102,40 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) auto getTurretMatrix = [=, &mtx]() -> Matrix3D { - auto mtx_turret = mtx; - pDrawTypeExt->ApplyTurretOffset(&mtx_turret, Pixel_Per_Lepton); - mtx_turret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); + auto mtxTurret = mtx; + pDrawTypeExt->ApplyTurretOffset(&mtxTurret, Pixel_Per_Lepton); + mtxTurret.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); if (pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive) - mtx_turret.TranslateX(-pThis->TurretRecoil.TravelSoFar); + mtxTurret.TranslateX(-pThis->TurretRecoil.TravelSoFar); - return mtx_turret; + return mtxTurret; }; - auto mtx_turret = shouldRedraw ? getTurretMatrix() : mtx; - - // 10240u -> (BlitterFlags::Alpha | BlitterFlags::Flat); + auto mtxTurret = shouldRedraw ? getTurretMatrix() : mtx; + constexpr size_t blit = static_cast(BlitterFlags::Alpha | BlitterFlags::Flat); // Only when there is a barrel will its calculation and drawing be considered if (haveBar) { - auto drawBarrel = [=, &mtx_turret, &mtx]() + auto drawBarrel = [=, &mtxTurret, &mtx]() { // When in recoiling, need to bypass cache and draw without saving const auto brlKey = inRecoil ? -1 : flags; const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); - auto getBarrelMatrix = [=, &mtx_turret, &mtx]() -> Matrix3D + auto getBarrelMatrix = [=, &mtxTurret, &mtx]() -> Matrix3D { - auto mtx_barrel = mtx_turret; - mtx_barrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); - mtx_barrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); + auto mtxBarrel = mtxTurret; + mtxBarrel.Translate(-mtx.Row[0].W, -mtx.Row[1].W, -mtx.Row[2].W); + mtxBarrel.RotateY(static_cast(-pThis->BarrelFacing.Current().GetRadian<32>())); if (pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) - mtx_barrel.TranslateX(-pThis->BarrelRecoil.TravelSoFar); + mtxBarrel.TranslateX(-pThis->BarrelRecoil.TravelSoFar); - mtx_barrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); - return mtx_barrel; + mtxBarrel.Translate(mtx.Row[0].W, mtx.Row[1].W, mtx.Row[2].W); + return mtxBarrel; }; - auto mtx_barrel = shouldRedraw ? getBarrelMatrix() : mtx; + auto mtxBarrel = shouldRedraw ? getBarrelMatrix() : mtx; auto getBarrelVoxel = [pDrawType, notChargeTurret, currentTurretNumber]() -> VoxelStruct* { @@ -147,13 +146,13 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) if (currentTurretNumber < 18 || !AresHelper::CanUseAres) return &pDrawType->ChargerBarrels[currentTurretNumber]; - auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); return &aresTypeExt->ChargerBarrels[currentTurretNumber - 18]; }; const auto pBarrelVoxel = getBarrelVoxel(); // draw barrel - pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtx_barrel, brightness, 10240u, 0); + pThis->Draw_A_VXL(pBarrelVoxel, hvaFrameIdx, brlKey, brlCache, rect, center, &mtxBarrel, brightness, blit, 0); }; const auto turretDir = pThis->SecondaryFacing.Current().GetFacing<4>(); @@ -162,7 +161,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) if (turretDir != 0 && turretDir != 3) { // draw turret - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtxTurret, brightness, blit, 0); drawBarrel(); } @@ -171,12 +170,12 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) drawBarrel(); // draw turret - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtxTurret, brightness, blit, 0); } } else { - pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtx_turret, brightness, 10240u, 0); + pThis->Draw_A_VXL(pTurretVoxel, hvaFrameIdx, turKey, turCache, rect, center, &mtxTurret, brightness, blit, 0); } return SkipGameCode; @@ -549,17 +548,17 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) if (pThis->CloakState != CloakState::Uncloaked || pThis->Type->NoShadow || !loco->Is_To_Have_Shadow()) return SkipDrawing; - REF_STACK(Matrix3D, shadow_matrix, STACK_OFFSET(0x1C4, -0x130)); - GET_STACK(VoxelIndexKey, vxl_index_key, STACK_OFFSET(0x1C4, -0x1B0)); + REF_STACK(Matrix3D, shadowMatrix, STACK_OFFSET(0x1C4, -0x130)); + GET_STACK(VoxelIndexKey, vxlIndexKey, STACK_OFFSET(0x1C4, -0x1B0)); LEA_STACK(RectangleStruct*, bnd, STACK_OFFSET(0x1C4, 0xC)); LEA_STACK(Point2D*, pt, STACK_OFFSET(0x1C4, -0x1A4)); GET_STACK(Surface* const, surface, STACK_OFFSET(0x1C4, -0x1A8)); - GET(UnitTypeClass*, pType, EBX); + GET(UnitTypeClass*, pDrawType, EBX); // This is not necessarily pThis->Type : UnloadingClass or WaterImage // This is the very reason I need to do this here, there's no less hacky way to get this Type from those inner calls - const auto uTypeExt = TechnoTypeExt::ExtMap.Find(pType); + const auto pDrawTypeExt = TechnoTypeExt::ExtMap.Find(pDrawType); const auto jjloco = locomotion_cast(loco); const auto height = pThis->GetHeight(); const double baseScale_log = RulesExt::Global()->AirShadowBaseScale_log; @@ -569,50 +568,50 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) const double minScale = RulesExt::Global()->HeightShadowScaling_MinScale; if (jjloco) { - const float cHeight = (float)uTypeExt->ShadowSizeCharacteristicHeight.Get(jjloco->Height); + const float cHeight = (float)pDrawTypeExt->ShadowSizeCharacteristicHeight.Get(jjloco->Height); if (cHeight > 0) { - shadow_matrix.Scale((float)std::max(Pade2_2(baseScale_log * height / cHeight), minScale)); + shadowMatrix.Scale((float)std::max(Pade2_2(baseScale_log * height / cHeight), minScale)); if (jjloco->State != JumpjetLocomotionClass::State::Hovering) - vxl_index_key.Invalidate(); + vxlIndexKey.Invalidate(); } } else { - const float cHeight = (float)uTypeExt->ShadowSizeCharacteristicHeight.Get(RulesClass::Instance->CruiseHeight); + const float cHeight = (float)pDrawTypeExt->ShadowSizeCharacteristicHeight.Get(RulesClass::Instance->CruiseHeight); if (cHeight > 0 && height > 208) { - shadow_matrix.Scale((float)std::max(Pade2_2(baseScale_log * (height - 208) / cHeight), minScale)); - vxl_index_key.Invalidate(); + shadowMatrix.Scale((float)std::max(Pade2_2(baseScale_log * (height - 208) / cHeight), minScale)); + vxlIndexKey.Invalidate(); } } } else if (!RulesExt::Global()->HeightShadowScaling && pThis->Type->ConsideredAircraft) { - shadow_matrix.Scale((float)Pade2_2(baseScale_log)); + shadowMatrix.Scale((float)Pade2_2(baseScale_log)); } auto GetMainVoxel = [&]() { - if (pType->NoSpawnAlt && pThis->SpawnManager && pThis->SpawnManager->CountDockedSpawns() == 0) + if (pDrawType->NoSpawnAlt && pThis->SpawnManager && pThis->SpawnManager->CountDockedSpawns() == 0) { if (AresHelper::CanUseAres) { - vxl_index_key.Invalidate();// I'd just assume most of the time we have spawn - return &reinterpret_cast(pType->align_2FC)->NoSpawnAltVXL; + vxlIndexKey.Invalidate();// I'd just assume most of the time we have spawn + return &reinterpret_cast(pDrawType->align_2FC)->NoSpawnAltVXL; } - return &pType->TurretVoxel; + return &pDrawType->TurretVoxel; } - return &pType->MainVoxel; + return &pDrawType->MainVoxel; }; auto const main_vxl = GetMainVoxel(); - auto shadow_point = loco->Shadow_Point(); - auto why = *pt + shadow_point; + auto shadowPoint = loco->Shadow_Point(); + auto why = *pt + shadowPoint; float arf = pThis->AngleRotatedForwards; float ars = pThis->AngleRotatedSideways; @@ -620,22 +619,22 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) if (std::abs(ars) >= 0.005 || std::abs(arf) >= 0.005) { // index key should have been already invalid, so it won't hurt to invalidate again - vxl_index_key.Invalidate(); - shadow_matrix.TranslateX(float(Math::sgn(arf) * pType->VoxelScaleX * (1 - Math::cos(arf)))); - shadow_matrix.TranslateY(float(Math::sgn(-ars) * pType->VoxelScaleY * (1 - Math::cos(ars)))); - shadow_matrix.RotateY(arf); - shadow_matrix.RotateX(ars); + vxlIndexKey.Invalidate(); + shadowMatrix.TranslateX(float(Math::sgn(arf) * pDrawType->VoxelScaleX * (1 - Math::cos(arf)))); + shadowMatrix.TranslateY(float(Math::sgn(-ars) * pDrawType->VoxelScaleY * (1 - Math::cos(ars)))); + shadowMatrix.RotateY(arf); + shadowMatrix.RotateX(ars); } else if (jjloco - && uTypeExt->JumpjetTilt + && pDrawTypeExt->JumpjetTilt && jjloco->State != JumpjetLocomotionClass::State::Grounded && jjloco->CurrentSpeed > 0.0 && pThis->IsAlive && pThis->Health > 0 && !pThis->IsAttackedByLocomotor) { - const float forwardSpeedFactor = static_cast(jjloco->CurrentSpeed * uTypeExt->JumpjetTilt_ForwardSpeedFactor); - const float forwardAccelFactor = static_cast(jjloco->Accel * uTypeExt->JumpjetTilt_ForwardAccelFactor); + const float forwardSpeedFactor = static_cast(jjloco->CurrentSpeed * pDrawTypeExt->JumpjetTilt_ForwardSpeedFactor); + const float forwardAccelFactor = static_cast(jjloco->Accel * pDrawTypeExt->JumpjetTilt_ForwardAccelFactor); arf = Math::clamp(static_cast((forwardAccelFactor + forwardSpeedFactor) * JumpjetTiltReference::ForwardBaseTilt), -JumpjetTiltReference::MaxTilt, JumpjetTiltReference::MaxTilt); @@ -644,9 +643,9 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) if (locoFace.IsRotating()) { - const float sidewaysSpeedFactor = static_cast(jjloco->CurrentSpeed * uTypeExt->JumpjetTilt_SidewaysSpeedFactor); + const float sidewaysSpeedFactor = static_cast(jjloco->CurrentSpeed * pDrawTypeExt->JumpjetTilt_SidewaysSpeedFactor); const float sidewaysRotationFactor = static_cast(static_cast(locoFace.Difference().Raw) - * uTypeExt->JumpjetTilt_SidewaysRotationFactor); + * pDrawTypeExt->JumpjetTilt_SidewaysRotationFactor); ars = Math::clamp(static_cast(sidewaysSpeedFactor * sidewaysRotationFactor * JumpjetTiltReference::SidewaysBaseTilt), -JumpjetTiltReference::MaxTilt, JumpjetTiltReference::MaxTilt); @@ -654,98 +653,98 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) if (std::abs(ars) >= 0.005 || std::abs(arf) >= 0.005) { - vxl_index_key.Invalidate(); - shadow_matrix.RotateX(ars); - shadow_matrix.RotateY(arf); + vxlIndexKey.Invalidate(); + shadowMatrix.RotateX(ars); + shadowMatrix.RotateY(arf); } } - auto mtx = Matrix3D::VoxelDefaultMatrix * shadow_matrix; + auto mtx = Matrix3D::VoxelDefaultMatrix * shadowMatrix; if (height > 0) - shadow_point.Y += 1; + shadowPoint.Y += 1; - if (!pType->UseTurretShadow) + if (!pDrawType->UseTurretShadow) { - if (uTypeExt->ShadowIndices.empty()) + if (pDrawTypeExt->ShadowIndices.empty()) { - if (pType->ShadowIndex >= 0 && pType->ShadowIndex < main_vxl->HVA->LayerCount) + if (pDrawType->ShadowIndex >= 0 && pDrawType->ShadowIndex < main_vxl->HVA->LayerCount) { pThis->DrawVoxelShadow( main_vxl, - pType->ShadowIndex, - vxl_index_key, - &pType->VoxelShadowCache, + pDrawType->ShadowIndex, + vxlIndexKey, + &pDrawType->VoxelShadowCache, bnd, &why, &mtx, true, surface, - shadow_point + shadowPoint ); } } else { - for (auto& [index, _] : uTypeExt->ShadowIndices) + for (auto& [index, _] : pDrawTypeExt->ShadowIndices) { pThis->DrawVoxelShadow( main_vxl, index, - index == pType->ShadowIndex ? vxl_index_key : VoxelIndexKey(-1), - &pType->VoxelShadowCache, + index == pDrawType->ShadowIndex ? vxlIndexKey : VoxelIndexKey(-1), + &pDrawType->VoxelShadowCache, bnd, &why, &mtx, - index == pType->ShadowIndex, + index == pDrawType->ShadowIndex, surface, - shadow_point + shadowPoint ); } } } - if (main_vxl == &pType->TurretVoxel || (!pType->UseTurretShadow && !uTypeExt->TurretShadow.Get(RulesExt::Global()->DrawTurretShadow))) + if (main_vxl == &pDrawType->TurretVoxel || (!pDrawType->UseTurretShadow && !pDrawTypeExt->TurretShadow.Get(RulesExt::Global()->DrawTurretShadow))) return SkipDrawing; - auto GetTurretVoxel = [pType](int idx) ->VoxelStruct* + auto GetTurretVoxel = [pDrawType](int idx) ->VoxelStruct* { - if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) - return &pType->TurretVoxel; + if (pDrawType->TurretCount == 0 || pDrawType->IsGattling || idx < 0) + return &pDrawType->TurretVoxel; if (idx < 18) - return &pType->ChargerTurrets[idx]; + return &pDrawType->ChargerTurrets[idx]; if (AresHelper::CanUseAres) { - auto* aresTypeExt = reinterpret_cast(pType->align_2FC); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); return &aresTypeExt->ChargerTurrets[idx - 18]; } return nullptr; }; - auto GetBarrelVoxel = [pType](int idx)->VoxelStruct* + auto GetBarrelVoxel = [pDrawType](int idx)->VoxelStruct* { - if (pType->TurretCount == 0 || pType->IsGattling || idx < 0) - return &pType->BarrelVoxel; + if (pDrawType->TurretCount == 0 || pDrawType->IsGattling || idx < 0) + return &pDrawType->BarrelVoxel; if (idx < 18) - return &pType->ChargerBarrels[idx]; + return &pDrawType->ChargerBarrels[idx]; if (AresHelper::CanUseAres) { - auto* aresTypeExt = reinterpret_cast(pType->align_2FC); + auto* aresTypeExt = reinterpret_cast(pDrawType->align_2FC); return &aresTypeExt->ChargerBarrels[idx - 18]; } return nullptr; }; - uTypeExt->ApplyTurretOffset(&mtx, Pixel_Per_Lepton); + pDrawTypeExt->ApplyTurretOffset(&mtx, Pixel_Per_Lepton); mtx.RotateZ(static_cast(pThis->SecondaryFacing.Current().GetRadian<32>() - pThis->PrimaryFacing.Current().GetRadian<32>())); - const bool inRecoil = pType->TurretRecoil && pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive; + const bool inRecoil = pDrawType->TurretRecoil && pThis->TurretRecoil.State != RecoilData::RecoilState::Inactive; if (inRecoil) mtx.TranslateX(-pThis->TurretRecoil.TravelSoFar); @@ -755,11 +754,11 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) const auto bar = GetBarrelVoxel(pThis->CurrentTurretNumber); const auto haveBar = bar && bar->VXL && bar->HVA && !bar->VXL->Initialized; - if (vxl_index_key.Is_Valid_Key()) - vxl_index_key.MinorVoxel.TurretFacing = pThis->SecondaryFacing.Current().GetFacing<32>(); + if (vxlIndexKey.Is_Valid_Key()) + vxlIndexKey.MinorVoxel.TurretFacing = pThis->SecondaryFacing.Current().GetFacing<32>(); - auto* cache = &pType->VoxelShadowCache; - if (!pType->UseTurretShadow) + auto* cache = &pDrawType->VoxelShadowCache; + if (!pDrawType->UseTurretShadow) { if (haveBar) { @@ -767,28 +766,28 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) } else { - cache = tur != &pType->TurretVoxel + cache = tur != &pDrawType->TurretVoxel ? nullptr // man what can I say, you are fucked, for now - : reinterpret_cast(&pType->VoxelTurretBarrelCache); // excuse me + : reinterpret_cast(&pDrawType->VoxelTurretBarrelCache); // excuse me } } pThis->DrawVoxelShadow( tur, 0, - (inRecoil ? VoxelIndexKey(-1) : vxl_index_key), + (inRecoil ? VoxelIndexKey(-1) : vxlIndexKey), (inRecoil ? nullptr : cache), bnd, &why, &mtx, (!inRecoil && cache != nullptr), surface, - shadow_point + shadowPoint ); if (haveBar)// you are utterly fucked, for now { - if (pType->TurretRecoil && pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) + if (pDrawType->TurretRecoil && pThis->BarrelRecoil.State != RecoilData::RecoilState::Inactive) mtx.TranslateX(-pThis->BarrelRecoil.TravelSoFar); mtx.ScaleX(static_cast(Math::cos(-pThis->BarrelFacing.Current().GetRadian<32>()))); @@ -803,7 +802,7 @@ DEFINE_HOOK(0x73C47A, UnitClass_DrawAsVXL_Shadow, 0x5) &mtx, false, surface, - shadow_point + shadowPoint ); } @@ -945,7 +944,7 @@ DEFINE_HOOK(0x7072A1, cyka707280_WhichMatrix, 0x6) else { // guess what, someone actually has a multisection nospawnalt - if (!(AresHelper::CanUseAres && pVXL == &reinterpret_cast(pType->align_2FC)->NoSpawnAltVXL)) + if (!(AresHelper::CanUseAres && pVXL == &reinterpret_cast(pType->align_2FC)->NoSpawnAltVXL)) return pThis->TurretAnimFrame % hva->FrameCount; } // you might also be WaterImage or sth else, but I don't want to care anymore, go fuck yourself From 942dc0ed35fd68206d7867016391560b49faf77f Mon Sep 17 00:00:00 2001 From: CrimRecya <335958461@qq.com> Date: Sun, 17 Aug 2025 00:50:22 +0800 Subject: [PATCH 7/7] Update YRpp --- YRpp | 2 +- src/Ext/TechnoType/Hooks.MatrixOp.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/YRpp b/YRpp index cecd628c1e..f94e05dc44 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit cecd628c1eebc31a753ab114a132a7a2c310631a +Subproject commit f94e05dc446e876e255c3a9165f252ad1be56f3f diff --git a/src/Ext/TechnoType/Hooks.MatrixOp.cpp b/src/Ext/TechnoType/Hooks.MatrixOp.cpp index 6997106ca9..a9c575e15a 100644 --- a/src/Ext/TechnoType/Hooks.MatrixOp.cpp +++ b/src/Ext/TechnoType/Hooks.MatrixOp.cpp @@ -98,7 +98,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) // When in recoiling, need to bypass cache and draw without saving const auto turKey = inRecoil ? -1 : flags; - const auto turCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretWeaponCache); + const auto turCache = inRecoil ? nullptr : &pDrawType->VoxelTurretWeaponCache; auto getTurretMatrix = [=, &mtx]() -> Matrix3D { @@ -112,7 +112,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) return mtxTurret; }; auto mtxTurret = shouldRedraw ? getTurretMatrix() : mtx; - constexpr size_t blit = static_cast(BlitterFlags::Alpha | BlitterFlags::Flat); + constexpr BlitterFlags blit = BlitterFlags::Alpha | BlitterFlags::Flat; // Only when there is a barrel will its calculation and drawing be considered if (haveBar) @@ -121,7 +121,7 @@ DEFINE_HOOK(0x73BA12, UnitClass_DrawAsVXL_RewriteTurretDrawing, 0x6) { // When in recoiling, need to bypass cache and draw without saving const auto brlKey = inRecoil ? -1 : flags; - const auto brlCache = inRecoil ? nullptr : reinterpret_cast*>(&pDrawType->VoxelTurretBarrelCache); + const auto brlCache = inRecoil ? nullptr : &pDrawType->VoxelTurretBarrelCache; auto getBarrelMatrix = [=, &mtxTurret, &mtx]() -> Matrix3D {