diff --git a/ChaosMod/ChaosMod.vcxproj b/ChaosMod/ChaosMod.vcxproj index c6cc7cdf9..dacb5106a 100644 --- a/ChaosMod/ChaosMod.vcxproj +++ b/ChaosMod/ChaosMod.vcxproj @@ -190,6 +190,7 @@ + diff --git a/ChaosMod/Effects/db/Vehs/VehsMonterTrucks.cpp b/ChaosMod/Effects/db/Vehs/VehsMonterTrucks.cpp new file mode 100644 index 000000000..23482bf57 --- /dev/null +++ b/ChaosMod/Effects/db/Vehs/VehsMonterTrucks.cpp @@ -0,0 +1,70 @@ +#include + +#include "Memory/Vehicle.h" + +struct VehicleData +{ + float fRaise; +}; + +static std::map vehiclesMap; +static std::map vehiclesCGMap; + +static void OnStop() +{ + for (auto const &[model, data] : vehiclesMap) + { + LoadModel(model); + Vehicle temp = CREATE_VEHICLE(model, 0.f, 0.f, -50.f, 0.f, true, false, true); + FREEZE_ENTITY_POSITION(temp, true); + + Memory::SetVehicleRaise(temp, data.fRaise); + + DELETE_ENTITY(&temp); + vehiclesMap.erase(model); + } + + for (auto const &[veh, CG] : vehiclesCGMap) + { + SET_CGOFFSET(veh, CG.x, CG.y, CG.z); + } + + vehiclesMap.clear(); + vehiclesCGMap.clear(); +} + +static void OnTick() +{ + for (Vehicle veh : GetAllVehs()) + { + if (!DOES_ENTITY_EXIST(veh)) + continue; + + Hash vehModel = GET_ENTITY_MODEL(veh); + if (!vehiclesMap.contains(vehModel)) + { + Memory::SetVehicleRaise(veh, 1.f); + + _SET_VEHICLE_WHEELS_DEAL_DAMAGE(veh, true); + + vehiclesMap.emplace(vehModel, VehicleData(0.f)); + } + + if (!vehiclesCGMap.contains(veh)) + { + Vector3 ogCG = GET_CGOFFSET(veh); + SET_CGOFFSET(veh, ogCG.x, ogCG.y, ogCG.z - 1.2f); + + vehiclesCGMap.emplace(veh, ogCG); + } + } +} + +// clang-format off +REGISTER_EFFECT(nullptr, OnStop, OnTick, EffectInfo + { + .Name = "Monster Trucks", + .Id = "vehs_monster_trucks", + .IsTimed = true + } +); diff --git a/ChaosMod/Memory/Vehicle.h b/ChaosMod/Memory/Vehicle.h index a30ff14a9..a1252eb73 100644 --- a/ChaosMod/Memory/Vehicle.h +++ b/ChaosMod/Memory/Vehicle.h @@ -211,4 +211,98 @@ namespace Memory Memory::SetVector3(vehicleMatrixAddress + 0x10, vehicleRightVec * scaleMultiplier); Memory::SetVector3(vehicleMatrixAddress + 0x20, vehicleUpVec * scaleMultiplier); } + + inline void SetVehicleRaise(Vehicle vehicle, float height) + { + auto vehAddr = getScriptHandleBaseAddress(vehicle); + *reinterpret_cast(*reinterpret_cast(vehAddr + 0x938) + 0xD0) = height; + } + + inline void SetVehicleWheelSize(Vehicle vehicle, float size) + { + auto addr = hook::get_pattern("44 0F 2F 43 48 45 8D"); + auto vehAddr = getScriptHandleBaseAddress(vehicle); + + auto drawHandlerPtrOffset = *(uint8_t *)(addr + 4); + auto streamRenderGfxPtrOffset = *hook::get_pattern("4C 8D 48 ? 80 E1 01", -4); + + auto drawHandler = *reinterpret_cast((uint64_t)vehAddr + drawHandlerPtrOffset); + auto streamRenderGfx = *reinterpret_cast(drawHandler + streamRenderGfxPtrOffset); + + if (streamRenderGfx == 0) + { + return; + } + + addr = hook::get_pattern("48 89 01 B8 00 00 80 3F 66 44 89 51"); + auto streamRenderWheelSizeOffset = *(uint8_t *)(addr + 20); + + *reinterpret_cast(streamRenderGfx + streamRenderWheelSizeOffset) = size; + } + + inline float GetVehicleWheelSize(Vehicle vehicle) + { + auto addr = hook::get_pattern("44 0F 2F 43 48 45 8D"); + auto vehAddr = getScriptHandleBaseAddress(vehicle); + + auto drawHandlerPtrOffset = *(uint8_t *)(addr + 4); + auto streamRenderGfxPtrOffset = *hook::get_pattern("4C 8D 48 ? 80 E1 01", -4); + + auto drawHandler = *reinterpret_cast((uint64_t)vehAddr + drawHandlerPtrOffset); + auto streamRenderGfx = *reinterpret_cast(drawHandler + streamRenderGfxPtrOffset); + + if (streamRenderGfx == 0) + { + return 0.f; + } + + addr = hook::get_pattern("48 89 01 B8 00 00 80 3F 66 44 89 51"); + auto streamRenderWheelSizeOffset = *(uint8_t *)(addr + 20); + + return *reinterpret_cast(streamRenderGfx + streamRenderWheelSizeOffset); + } + + inline void SetVehicleWheelWidth(Vehicle vehicle, float width) + { + auto addr = hook::get_pattern("44 0F 2F 43 48 45 8D"); + auto vehAddr = getScriptHandleBaseAddress(vehicle); + + auto drawHandlerPtrOffset = *(uint8_t *)(addr + 4); + auto streamRenderGfxPtrOffset = *hook::get_pattern("4C 8D 48 ? 80 E1 01", -4); + + auto drawHandler = *reinterpret_cast((uint64_t)vehAddr + drawHandlerPtrOffset); + auto streamRenderGfx = *reinterpret_cast(drawHandler + streamRenderGfxPtrOffset); + + if (streamRenderGfx == 0) + { + return; + } + + addr = hook::get_pattern("48 89 01 B8 00 00 80 3F 66 44 89 51"); + auto streamRenderWheelWidthOffset = *(uint32_t *)(addr + 23); + + *reinterpret_cast(streamRenderGfx + streamRenderWheelWidthOffset) = width; + } + + inline float GetVehicleWheelWidth(Vehicle vehicle) + { + auto addr = hook::get_pattern("44 0F 2F 43 48 45 8D"); + auto vehAddr = getScriptHandleBaseAddress(vehicle); + + auto drawHandlerPtrOffset = *(uint8_t *)(addr + 4); + auto streamRenderGfxPtrOffset = *hook::get_pattern("4C 8D 48 ? 80 E1 01", -4); + + auto drawHandler = *reinterpret_cast((uint64_t)vehAddr + drawHandlerPtrOffset); + auto streamRenderGfx = *reinterpret_cast(drawHandler + streamRenderGfxPtrOffset); + + if (streamRenderGfx == 0) + { + return 0.f; + } + + addr = hook::get_pattern("48 89 01 B8 00 00 80 3F 66 44 89 51"); + auto streamRenderWheelWidthOffset = *(uint32_t *)(addr + 23); + + return *reinterpret_cast(streamRenderGfx + streamRenderWheelWidthOffset); + } } \ No newline at end of file