From 53023eb65bdcde43e341c1ecb7cf0c7f8ee524fb Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 7 Jul 2019 13:09:11 +0200 Subject: the great reorganization --- src/Camera.cpp | 1301 ----------------- src/Camera.h | 476 ------- src/CdStream.cpp | 529 ------- src/CdStream.h | 46 - src/Clock.cpp | 131 -- src/Clock.h | 31 - src/Collision.cpp | 1887 ------------------------- src/Collision.h | 157 --- src/ControllerConfig.cpp | 57 - src/ControllerConfig.h | 58 - src/CullZones.cpp | 370 ----- src/CullZones.h | 94 -- src/CutsceneMgr.cpp | 7 - src/CutsceneMgr.h | 15 - src/DamageManager.cpp | 243 ---- src/DamageManager.h | 92 -- src/Directory.cpp | 65 - src/Directory.h | 22 - src/FileLoader.cpp | 1182 ---------------- src/FileLoader.h | 42 - src/FileMgr.cpp | 300 ---- src/FileMgr.h | 21 - src/Fire.cpp | 5 - src/Fire.h | 23 - src/Frontend.cpp | 2353 ------------------------------- src/Frontend.h | 512 ------- src/Game.cpp | 23 - src/Game.h | 37 - src/General.h | 91 -- src/Lists.cpp | 26 - src/Lists.h | 130 -- src/MenuScreens.h | 380 ----- src/Messages.cpp | 15 - src/Messages.h | 44 - src/MloInstance.cpp | 7 - src/MloInstance.h | 9 - src/NodeName.cpp | 77 - src/NodeName.h | 4 - src/PCSave.cpp | 20 - src/PCSave.h | 21 - src/Pad.cpp | 2091 --------------------------- src/Pad.h | 367 ----- src/ParticleObject.cpp | 23 - src/ParticleObject.h | 39 - src/Placeable.cpp | 72 - src/Placeable.h | 26 - src/Pools.cpp | 25 - src/Pools.h | 43 - src/Radar.cpp | 1117 --------------- src/Radar.h | 146 -- src/References.cpp | 65 - src/References.h | 20 - src/RwClumpRead.cpp | 230 --- src/RwHelper.cpp | 356 ----- src/RwHelper.h | 27 - src/RwMatFX.cpp | 212 --- src/RwTexRead.cpp | 126 -- src/Stats.cpp | 6 - src/Stats.h | 9 - src/Streaming.cpp | 2509 --------------------------------- src/Streaming.h | 188 --- src/SurfaceTable.cpp | 150 -- src/SurfaceTable.h | 106 -- src/TempColModels.cpp | 17 - src/TempColModels.h | 21 - src/Text.cpp | 232 --- src/Text.h | 52 - src/Timecycle.cpp | 322 ----- src/Timecycle.h | 141 -- src/Timer.cpp | 235 ---- src/Timer.h | 51 - src/TxdStore.cpp | 208 --- src/TxdStore.h | 44 - src/User.cpp | 176 --- src/User.h | 64 - src/Wanted.cpp | 36 - src/Wanted.h | 45 - src/Weather.cpp | 35 - src/Weather.h | 39 - src/World.cpp | 718 ---------- src/World.h | 119 -- src/Zones.cpp | 874 ------------ src/Zones.h | 112 -- src/common.h | 178 --- src/config.h | 116 -- src/control/HandlingMgr.cpp | 247 ---- src/control/HandlingMgr.h | 139 -- src/control/ObjectData.cpp | 103 -- src/control/ObjectData.h | 27 - src/control/PedPlacement.cpp | 40 - src/control/PedPlacement.h | 8 - src/control/PedStats.cpp | 125 -- src/control/PedStats.h | 79 -- src/control/PedType.cpp | 243 ---- src/control/PedType.h | 90 -- src/control/PhoneInfo.cpp | 6 - src/control/PhoneInfo.h | 6 - src/control/Phones.cpp | 6 + src/control/Phones.h | 6 + src/control/Replay.cpp | 6 +- src/control/Transmission.cpp | 37 - src/control/Transmission.h | 26 - src/core/Camera.cpp | 1301 +++++++++++++++++ src/core/Camera.h | 476 +++++++ src/core/CdStream.cpp | 529 +++++++ src/core/CdStream.h | 46 + src/core/Clock.cpp | 131 ++ src/core/Clock.h | 31 + src/core/Collision.cpp | 1887 +++++++++++++++++++++++++ src/core/Collision.h | 157 +++ src/core/ControllerConfig.cpp | 57 + src/core/ControllerConfig.h | 58 + src/core/CutsceneMgr.cpp | 7 + src/core/CutsceneMgr.h | 15 + src/core/Directory.cpp | 65 + src/core/Directory.h | 22 + src/core/FileLoader.cpp | 1182 ++++++++++++++++ src/core/FileLoader.h | 42 + src/core/FileMgr.cpp | 300 ++++ src/core/FileMgr.h | 21 + src/core/Fire.cpp | 5 + src/core/Fire.h | 23 + src/core/Frontend.cpp | 2353 +++++++++++++++++++++++++++++++ src/core/Frontend.h | 512 +++++++ src/core/Game.cpp | 23 + src/core/Game.h | 37 + src/core/General.h | 91 ++ src/core/Lists.cpp | 26 + src/core/Lists.h | 130 ++ src/core/MenuScreens.h | 380 +++++ src/core/Messages.cpp | 15 + src/core/Messages.h | 44 + src/core/NodeName.cpp | 77 + src/core/NodeName.h | 4 + src/core/PCSave.cpp | 20 + src/core/PCSave.h | 21 + src/core/Pad.cpp | 2091 +++++++++++++++++++++++++++ src/core/Pad.h | 367 +++++ src/core/Placeable.cpp | 72 + src/core/Placeable.h | 26 + src/core/PlayerInfo.cpp | 5 + src/core/PlayerInfo.h | 72 + src/core/PlayerSkin.cpp | 5 + src/core/PlayerSkin.h | 7 + src/core/Pools.cpp | 25 + src/core/Pools.h | 43 + src/core/Radar.cpp | 1117 +++++++++++++++ src/core/Radar.h | 146 ++ src/core/References.cpp | 65 + src/core/References.h | 20 + src/core/RwClumpRead.cpp | 230 +++ src/core/RwHelper.cpp | 356 +++++ src/core/RwHelper.h | 27 + src/core/RwMatFX.cpp | 212 +++ src/core/RwTexRead.cpp | 126 ++ src/core/Stats.cpp | 6 + src/core/Stats.h | 9 + src/core/Streaming.cpp | 2509 +++++++++++++++++++++++++++++++++ src/core/Streaming.h | 188 +++ src/core/SurfaceTable.cpp | 150 ++ src/core/SurfaceTable.h | 106 ++ src/core/TempColModels.cpp | 17 + src/core/TempColModels.h | 21 + src/core/Text.cpp | 232 +++ src/core/Text.h | 52 + src/core/Timer.cpp | 235 ++++ src/core/Timer.h | 51 + src/core/TxdStore.cpp | 208 +++ src/core/TxdStore.h | 44 + src/core/User.cpp | 176 +++ src/core/User.h | 64 + src/core/Wanted.cpp | 36 + src/core/Wanted.h | 45 + src/core/World.cpp | 718 ++++++++++ src/core/World.h | 119 ++ src/core/ZoneCull.cpp | 370 +++++ src/core/ZoneCull.h | 94 ++ src/core/Zones.cpp | 874 ++++++++++++ src/core/Zones.h | 112 ++ src/core/common.h | 178 +++ src/core/config.h | 116 ++ src/core/debugmenu_public.h | 154 ++ src/core/main.cpp | 891 ++++++++++++ src/core/main.h | 22 + src/core/patcher.cpp | 22 + src/core/patcher.h | 192 +++ src/core/re3.cpp | 381 +++++ src/core/rw.cpp | 415 ++++++ src/core/templates.h | 205 +++ src/debugmenu_public.h | 154 -- src/entities/Automobile.cpp | 18 - src/entities/Automobile.h | 68 - src/entities/Boat.cpp | 14 - src/entities/Boat.h | 17 - src/entities/CivilianPed.cpp | 19 - src/entities/CivilianPed.h | 16 - src/entities/CopPed.cpp | 14 - src/entities/CopPed.h | 73 - src/entities/CutsceneHead.cpp | 118 -- src/entities/CutsceneHead.h | 24 - src/entities/CutsceneObject.cpp | 100 -- src/entities/CutsceneObject.h | 25 - src/entities/DummyObject.cpp | 17 - src/entities/DummyObject.h | 14 - src/entities/DummyPed.h | 11 - src/entities/EmergencyPed.cpp | 7 - src/entities/EmergencyPed.h | 13 - src/entities/Heli.cpp | 15 - src/entities/Heli.h | 17 - src/entities/Object.cpp | 93 -- src/entities/Object.h | 81 -- src/entities/Ped.cpp | 2949 --------------------------------------- src/entities/Ped.h | 577 -------- src/entities/PedIK.cpp | 109 -- src/entities/PedIK.h | 40 - src/entities/Physical.cpp | 8 +- src/entities/Plane.cpp | 19 - src/entities/Plane.h | 18 - src/entities/PlayerInfo.cpp | 5 - src/entities/PlayerInfo.h | 72 - src/entities/PlayerPed.cpp | 14 - src/entities/PlayerPed.h | 48 - src/entities/PlayerSkin.cpp | 5 - src/entities/PlayerSkin.h | 7 - src/entities/Projectile.cpp | 7 - src/entities/Projectile.h | 11 - src/entities/Train.cpp | 14 - src/entities/Train.h | 26 - src/entities/Vehicle.cpp | 489 ------- src/entities/Vehicle.h | 240 ---- src/main.cpp | 891 ------------ src/main.h | 22 - src/modelinfo/MloInstance.cpp | 7 + src/modelinfo/MloInstance.h | 9 + src/objects/CutsceneHead.cpp | 118 ++ src/objects/CutsceneHead.h | 24 + src/objects/CutsceneObject.cpp | 100 ++ src/objects/CutsceneObject.h | 25 + src/objects/DummyObject.cpp | 17 + src/objects/DummyObject.h | 14 + src/objects/Object.cpp | 93 ++ src/objects/Object.h | 81 ++ src/objects/ObjectData.cpp | 103 ++ src/objects/ObjectData.h | 27 + src/objects/ParticleObject.cpp | 23 + src/objects/ParticleObject.h | 39 + src/objects/Projectile.cpp | 7 + src/objects/Projectile.h | 11 + src/patcher.cpp | 22 - src/patcher.h | 192 --- src/peds/CivilianPed.cpp | 19 + src/peds/CivilianPed.h | 16 + src/peds/CopPed.cpp | 14 + src/peds/CopPed.h | 73 + src/peds/DummyPed.h | 11 + src/peds/EmergencyPed.cpp | 7 + src/peds/EmergencyPed.h | 13 + src/peds/Ped.cpp | 2949 +++++++++++++++++++++++++++++++++++++++ src/peds/Ped.h | 577 ++++++++ src/peds/PedIK.cpp | 109 ++ src/peds/PedIK.h | 40 + src/peds/PedPlacement.cpp | 40 + src/peds/PedPlacement.h | 8 + src/peds/PedStats.cpp | 125 ++ src/peds/PedStats.h | 79 ++ src/peds/PedType.cpp | 243 ++++ src/peds/PedType.h | 90 ++ src/peds/PlayerPed.cpp | 14 + src/peds/PlayerPed.h | 48 + src/re3.cpp | 381 ----- src/render/Lights.cpp | 2 +- src/render/Timecycle.cpp | 322 +++++ src/render/Timecycle.h | 141 ++ src/render/Weather.cpp | 35 + src/render/Weather.h | 39 + src/rw.cpp | 415 ------ src/templates.h | 205 --- src/vehicles/Automobile.cpp | 18 + src/vehicles/Automobile.h | 67 + src/vehicles/Boat.cpp | 14 + src/vehicles/Boat.h | 17 + src/vehicles/DamageManager.cpp | 243 ++++ src/vehicles/DamageManager.h | 92 ++ src/vehicles/HandlingMgr.cpp | 247 ++++ src/vehicles/HandlingMgr.h | 139 ++ src/vehicles/Heli.cpp | 15 + src/vehicles/Heli.h | 17 + src/vehicles/Plane.cpp | 19 + src/vehicles/Plane.h | 18 + src/vehicles/Train.cpp | 14 + src/vehicles/Train.h | 26 + src/vehicles/Transmission.cpp | 37 + src/vehicles/Transmission.h | 26 + src/vehicles/Vehicle.cpp | 489 +++++++ src/vehicles/Vehicle.h | 240 ++++ 295 files changed, 31580 insertions(+), 31581 deletions(-) delete mode 100644 src/Camera.cpp delete mode 100644 src/Camera.h delete mode 100644 src/CdStream.cpp delete mode 100644 src/CdStream.h delete mode 100644 src/Clock.cpp delete mode 100644 src/Clock.h delete mode 100644 src/Collision.cpp delete mode 100644 src/Collision.h delete mode 100644 src/ControllerConfig.cpp delete mode 100644 src/ControllerConfig.h delete mode 100644 src/CullZones.cpp delete mode 100644 src/CullZones.h delete mode 100644 src/CutsceneMgr.cpp delete mode 100644 src/CutsceneMgr.h delete mode 100644 src/DamageManager.cpp delete mode 100644 src/DamageManager.h delete mode 100644 src/Directory.cpp delete mode 100644 src/Directory.h delete mode 100644 src/FileLoader.cpp delete mode 100644 src/FileLoader.h delete mode 100644 src/FileMgr.cpp delete mode 100644 src/FileMgr.h delete mode 100644 src/Fire.cpp delete mode 100644 src/Fire.h delete mode 100644 src/Frontend.cpp delete mode 100644 src/Frontend.h delete mode 100644 src/Game.cpp delete mode 100644 src/Game.h delete mode 100644 src/General.h delete mode 100644 src/Lists.cpp delete mode 100644 src/Lists.h delete mode 100644 src/MenuScreens.h delete mode 100644 src/Messages.cpp delete mode 100644 src/Messages.h delete mode 100644 src/MloInstance.cpp delete mode 100644 src/MloInstance.h delete mode 100644 src/NodeName.cpp delete mode 100644 src/NodeName.h delete mode 100644 src/PCSave.cpp delete mode 100644 src/PCSave.h delete mode 100644 src/Pad.cpp delete mode 100644 src/Pad.h delete mode 100644 src/ParticleObject.cpp delete mode 100644 src/ParticleObject.h delete mode 100644 src/Placeable.cpp delete mode 100644 src/Placeable.h delete mode 100644 src/Pools.cpp delete mode 100644 src/Pools.h delete mode 100644 src/Radar.cpp delete mode 100644 src/Radar.h delete mode 100644 src/References.cpp delete mode 100644 src/References.h delete mode 100644 src/RwClumpRead.cpp delete mode 100644 src/RwHelper.cpp delete mode 100644 src/RwHelper.h delete mode 100644 src/RwMatFX.cpp delete mode 100644 src/RwTexRead.cpp delete mode 100644 src/Stats.cpp delete mode 100644 src/Stats.h delete mode 100644 src/Streaming.cpp delete mode 100644 src/Streaming.h delete mode 100644 src/SurfaceTable.cpp delete mode 100644 src/SurfaceTable.h delete mode 100644 src/TempColModels.cpp delete mode 100644 src/TempColModels.h delete mode 100644 src/Text.cpp delete mode 100644 src/Text.h delete mode 100644 src/Timecycle.cpp delete mode 100644 src/Timecycle.h delete mode 100644 src/Timer.cpp delete mode 100644 src/Timer.h delete mode 100644 src/TxdStore.cpp delete mode 100644 src/TxdStore.h delete mode 100644 src/User.cpp delete mode 100644 src/User.h delete mode 100644 src/Wanted.cpp delete mode 100644 src/Wanted.h delete mode 100644 src/Weather.cpp delete mode 100644 src/Weather.h delete mode 100644 src/World.cpp delete mode 100644 src/World.h delete mode 100644 src/Zones.cpp delete mode 100644 src/Zones.h delete mode 100644 src/common.h delete mode 100644 src/config.h delete mode 100644 src/control/HandlingMgr.cpp delete mode 100644 src/control/HandlingMgr.h delete mode 100644 src/control/ObjectData.cpp delete mode 100644 src/control/ObjectData.h delete mode 100644 src/control/PedPlacement.cpp delete mode 100644 src/control/PedPlacement.h delete mode 100644 src/control/PedStats.cpp delete mode 100644 src/control/PedStats.h delete mode 100644 src/control/PedType.cpp delete mode 100644 src/control/PedType.h delete mode 100644 src/control/PhoneInfo.cpp delete mode 100644 src/control/PhoneInfo.h create mode 100644 src/control/Phones.cpp create mode 100644 src/control/Phones.h delete mode 100644 src/control/Transmission.cpp delete mode 100644 src/control/Transmission.h create mode 100644 src/core/Camera.cpp create mode 100644 src/core/Camera.h create mode 100644 src/core/CdStream.cpp create mode 100644 src/core/CdStream.h create mode 100644 src/core/Clock.cpp create mode 100644 src/core/Clock.h create mode 100644 src/core/Collision.cpp create mode 100644 src/core/Collision.h create mode 100644 src/core/ControllerConfig.cpp create mode 100644 src/core/ControllerConfig.h create mode 100644 src/core/CutsceneMgr.cpp create mode 100644 src/core/CutsceneMgr.h create mode 100644 src/core/Directory.cpp create mode 100644 src/core/Directory.h create mode 100644 src/core/FileLoader.cpp create mode 100644 src/core/FileLoader.h create mode 100644 src/core/FileMgr.cpp create mode 100644 src/core/FileMgr.h create mode 100644 src/core/Fire.cpp create mode 100644 src/core/Fire.h create mode 100644 src/core/Frontend.cpp create mode 100644 src/core/Frontend.h create mode 100644 src/core/Game.cpp create mode 100644 src/core/Game.h create mode 100644 src/core/General.h create mode 100644 src/core/Lists.cpp create mode 100644 src/core/Lists.h create mode 100644 src/core/MenuScreens.h create mode 100644 src/core/Messages.cpp create mode 100644 src/core/Messages.h create mode 100644 src/core/NodeName.cpp create mode 100644 src/core/NodeName.h create mode 100644 src/core/PCSave.cpp create mode 100644 src/core/PCSave.h create mode 100644 src/core/Pad.cpp create mode 100644 src/core/Pad.h create mode 100644 src/core/Placeable.cpp create mode 100644 src/core/Placeable.h create mode 100644 src/core/PlayerInfo.cpp create mode 100644 src/core/PlayerInfo.h create mode 100644 src/core/PlayerSkin.cpp create mode 100644 src/core/PlayerSkin.h create mode 100644 src/core/Pools.cpp create mode 100644 src/core/Pools.h create mode 100644 src/core/Radar.cpp create mode 100644 src/core/Radar.h create mode 100644 src/core/References.cpp create mode 100644 src/core/References.h create mode 100644 src/core/RwClumpRead.cpp create mode 100644 src/core/RwHelper.cpp create mode 100644 src/core/RwHelper.h create mode 100644 src/core/RwMatFX.cpp create mode 100644 src/core/RwTexRead.cpp create mode 100644 src/core/Stats.cpp create mode 100644 src/core/Stats.h create mode 100644 src/core/Streaming.cpp create mode 100644 src/core/Streaming.h create mode 100644 src/core/SurfaceTable.cpp create mode 100644 src/core/SurfaceTable.h create mode 100644 src/core/TempColModels.cpp create mode 100644 src/core/TempColModels.h create mode 100644 src/core/Text.cpp create mode 100644 src/core/Text.h create mode 100644 src/core/Timer.cpp create mode 100644 src/core/Timer.h create mode 100644 src/core/TxdStore.cpp create mode 100644 src/core/TxdStore.h create mode 100644 src/core/User.cpp create mode 100644 src/core/User.h create mode 100644 src/core/Wanted.cpp create mode 100644 src/core/Wanted.h create mode 100644 src/core/World.cpp create mode 100644 src/core/World.h create mode 100644 src/core/ZoneCull.cpp create mode 100644 src/core/ZoneCull.h create mode 100644 src/core/Zones.cpp create mode 100644 src/core/Zones.h create mode 100644 src/core/common.h create mode 100644 src/core/config.h create mode 100644 src/core/debugmenu_public.h create mode 100644 src/core/main.cpp create mode 100644 src/core/main.h create mode 100644 src/core/patcher.cpp create mode 100644 src/core/patcher.h create mode 100644 src/core/re3.cpp create mode 100644 src/core/rw.cpp create mode 100644 src/core/templates.h delete mode 100644 src/debugmenu_public.h delete mode 100644 src/entities/Automobile.cpp delete mode 100644 src/entities/Automobile.h delete mode 100644 src/entities/Boat.cpp delete mode 100644 src/entities/Boat.h delete mode 100644 src/entities/CivilianPed.cpp delete mode 100644 src/entities/CivilianPed.h delete mode 100644 src/entities/CopPed.cpp delete mode 100644 src/entities/CopPed.h delete mode 100644 src/entities/CutsceneHead.cpp delete mode 100644 src/entities/CutsceneHead.h delete mode 100644 src/entities/CutsceneObject.cpp delete mode 100644 src/entities/CutsceneObject.h delete mode 100644 src/entities/DummyObject.cpp delete mode 100644 src/entities/DummyObject.h delete mode 100644 src/entities/DummyPed.h delete mode 100644 src/entities/EmergencyPed.cpp delete mode 100644 src/entities/EmergencyPed.h delete mode 100644 src/entities/Heli.cpp delete mode 100644 src/entities/Heli.h delete mode 100644 src/entities/Object.cpp delete mode 100644 src/entities/Object.h delete mode 100644 src/entities/Ped.cpp delete mode 100644 src/entities/Ped.h delete mode 100644 src/entities/PedIK.cpp delete mode 100644 src/entities/PedIK.h delete mode 100644 src/entities/Plane.cpp delete mode 100644 src/entities/Plane.h delete mode 100644 src/entities/PlayerInfo.cpp delete mode 100644 src/entities/PlayerInfo.h delete mode 100644 src/entities/PlayerPed.cpp delete mode 100644 src/entities/PlayerPed.h delete mode 100644 src/entities/PlayerSkin.cpp delete mode 100644 src/entities/PlayerSkin.h delete mode 100644 src/entities/Projectile.cpp delete mode 100644 src/entities/Projectile.h delete mode 100644 src/entities/Train.cpp delete mode 100644 src/entities/Train.h delete mode 100644 src/entities/Vehicle.cpp delete mode 100644 src/entities/Vehicle.h delete mode 100644 src/main.cpp delete mode 100644 src/main.h create mode 100644 src/modelinfo/MloInstance.cpp create mode 100644 src/modelinfo/MloInstance.h create mode 100644 src/objects/CutsceneHead.cpp create mode 100644 src/objects/CutsceneHead.h create mode 100644 src/objects/CutsceneObject.cpp create mode 100644 src/objects/CutsceneObject.h create mode 100644 src/objects/DummyObject.cpp create mode 100644 src/objects/DummyObject.h create mode 100644 src/objects/Object.cpp create mode 100644 src/objects/Object.h create mode 100644 src/objects/ObjectData.cpp create mode 100644 src/objects/ObjectData.h create mode 100644 src/objects/ParticleObject.cpp create mode 100644 src/objects/ParticleObject.h create mode 100644 src/objects/Projectile.cpp create mode 100644 src/objects/Projectile.h delete mode 100644 src/patcher.cpp delete mode 100644 src/patcher.h create mode 100644 src/peds/CivilianPed.cpp create mode 100644 src/peds/CivilianPed.h create mode 100644 src/peds/CopPed.cpp create mode 100644 src/peds/CopPed.h create mode 100644 src/peds/DummyPed.h create mode 100644 src/peds/EmergencyPed.cpp create mode 100644 src/peds/EmergencyPed.h create mode 100644 src/peds/Ped.cpp create mode 100644 src/peds/Ped.h create mode 100644 src/peds/PedIK.cpp create mode 100644 src/peds/PedIK.h create mode 100644 src/peds/PedPlacement.cpp create mode 100644 src/peds/PedPlacement.h create mode 100644 src/peds/PedStats.cpp create mode 100644 src/peds/PedStats.h create mode 100644 src/peds/PedType.cpp create mode 100644 src/peds/PedType.h create mode 100644 src/peds/PlayerPed.cpp create mode 100644 src/peds/PlayerPed.h delete mode 100644 src/re3.cpp create mode 100644 src/render/Timecycle.cpp create mode 100644 src/render/Timecycle.h create mode 100644 src/render/Weather.cpp create mode 100644 src/render/Weather.h delete mode 100644 src/rw.cpp delete mode 100644 src/templates.h create mode 100644 src/vehicles/Automobile.cpp create mode 100644 src/vehicles/Automobile.h create mode 100644 src/vehicles/Boat.cpp create mode 100644 src/vehicles/Boat.h create mode 100644 src/vehicles/DamageManager.cpp create mode 100644 src/vehicles/DamageManager.h create mode 100644 src/vehicles/HandlingMgr.cpp create mode 100644 src/vehicles/HandlingMgr.h create mode 100644 src/vehicles/Heli.cpp create mode 100644 src/vehicles/Heli.h create mode 100644 src/vehicles/Plane.cpp create mode 100644 src/vehicles/Plane.h create mode 100644 src/vehicles/Train.cpp create mode 100644 src/vehicles/Train.h create mode 100644 src/vehicles/Transmission.cpp create mode 100644 src/vehicles/Transmission.h create mode 100644 src/vehicles/Vehicle.cpp create mode 100644 src/vehicles/Vehicle.h (limited to 'src') diff --git a/src/Camera.cpp b/src/Camera.cpp deleted file mode 100644 index d7ee398b..00000000 --- a/src/Camera.cpp +++ /dev/null @@ -1,1301 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Draw.h" -#include "World.h" -#include "Vehicle.h" -#include "Ped.h" -#include "PlayerPed.h" -#include "Pad.h" -#include "General.h" -#include "CullZones.h" -#include "SurfaceTable.h" -#include "MBlur.h" -#include "Camera.h" - -const float DefaultFOV = 70.0f; // beta: 80.0f - -CCamera &TheCamera = *(CCamera*)0x6FACF8; -bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8; - -WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); } -WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); } -WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); } -WRAPPER void CCamera::SetWidescreenOff(void) { EAXJMP(0x46FF10); } - -bool -CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) -{ - RwV3d c; - c = *(RwV3d*)¢er; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); - if(c.y + radius < CDraw::GetNearClipZ()) return false; - if(c.y - radius > CDraw::GetFarClipZ()) return false; - if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; - if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false; - if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false; - if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false; - return true; -} - -bool -CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) -{ - RwV3d c; - c = *(RwV3d*)¢er; - RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); - if(c.y < CDraw::GetNearClipZ()) return false; - if(c.y > CDraw::GetFarClipZ()) return false; - if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; - if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false; - if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false; - if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false; - return true; -} - -bool -CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) -{ - int i; - int frustumTests[6] = { 0 }; - RwV3dTransformPoints(box, box, 8, &mat->m_matrix); - - for(i = 0; i < 8; i++){ - if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; - if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++; - if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++; - if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++; -// Why not test z? -// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++; -// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++; - } - for(i = 0; i < 6; i++) - if(frustumTests[i] == 8) - return false; // Box is completely outside of one plane - return true; -} - -int -CCamera::GetLookDirection(void) -{ - if(Cams[ActiveCam].Mode == CCam::MODE_CAMONASTRING || - Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON || - Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT || - Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED) - return Cams[ActiveCam].DirectionWasLooking; - return LOOKING_FORWARD;; -} - -WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); } -WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); } -WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); } - -int -CCamera::GetScreenFadeStatus(void) -{ - if(m_fFLOATingFade == 0.0f) - return FADE_0; - if(m_fFLOATingFade == 255.0f) - return FADE_2; - return FADE_1; -} - -void -CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b) -{ - m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0; - CDraw::FadeRed = r; - CDraw::FadeGreen = g; - CDraw::FadeBlue = b; -} - -void -CCamera::SetMotionBlur(int r, int g, int b, int a, int type) -{ - m_BlurRed = r; - m_BlurGreen = g; - m_BlurBlue = b; - m_motionBlur = a; - m_BlurType = type; -} - -void -CCamera::SetMotionBlurAlpha(int a) -{ - m_imotionBlurAddAlpha = a; -} - -void -CCamera::RenderMotionBlur(void) -{ - if(m_BlurType == 0) - return; - - CMBlur::MotionBlurRender(m_pRwCamera, - m_BlurRed, m_BlurGreen, m_BlurBlue, - m_motionBlur, m_BlurType, m_imotionBlurAddAlpha); -} - - -/* - * - * CCam - * - */ - - -// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms -// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms -void -WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle) -{ - float Delta = Target - *CurrentValue; - - if(IsAngle){ - while(Delta >= PI) Delta -= 2*PI; - while(Delta < -PI) Delta += 2*PI; - } - - float TargetSpeed = Delta * MaxSpeed; - // Add or subtract absolute depending on sign, genius! -// if(TargetSpeed - *CurrentSpeed > 0.0f) -// *CurrentSpeed += Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); -// else -// *CurrentSpeed -= Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); - // this is simpler: - *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); - - // Clamp speed if we overshot - if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed) - *CurrentSpeed = TargetSpeed; - else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed) - *CurrentSpeed = TargetSpeed; - - *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep()); -} - -void -CCam::GetVectorsReadyForRW(void) -{ - CVector right; - Up = CVector(0.0f, 0.0f, 1.0f); - Front.Normalise(); - if(Front.x == 0.0f && Front.y == 0.0f){ - Front.x = 0.0001f; - Front.y = 0.0001f; - } - right = CrossProduct(Front, Up); - right.Normalise(); - Up = CrossProduct(right, Front); -} - -// This code is really bad. wtf R*? -CVector -CCam::DoAverageOnVector(const CVector &vec) -{ - int i; - CVector Average = { 0.0f, 0.0f, 0.0f }; - - if(ResetStatics){ - m_iRunningVectorArrayPos = 0; - m_iRunningVectorCounter = 1; - } - - // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2 - if(m_iRunningVectorCounter == 3){ - m_arrPreviousVectors[0] = m_arrPreviousVectors[1]; - m_arrPreviousVectors[1] = vec; - }else - m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec; - - for(i = 0; i <= m_iRunningVectorArrayPos; i++) - Average += m_arrPreviousVectors[i]; - Average /= i; - - m_iRunningVectorArrayPos++; - m_iRunningVectorCounter++; - if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE) - m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1; - if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1) - m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1; - - return Average; -} - -// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps. -// Return the first angle for which Beta + BetaOffset + Angle has a clear view. -// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear. -// If BetaOffset == 0, try both directions. -float -CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) -{ - CColPoint point; - CEntity *ent = nil; - CVector ToSource; - float a; - - // This would be so much nicer if we just got the step variable before the loop...R* - - for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){ - if(BetaOffset <= 0.0f){ - ToSource = CVector(cos(Beta + BetaOffset + a), sin(Beta + BetaOffset + a), 0.0f)*Dist; - if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, - point, ent, checkBuildings, checkVehicles, checkPeds, - checkObjects, checkDummies, true, true)) - return a; - } - if(BetaOffset >= 0.0f){ - ToSource = CVector(cos(Beta + BetaOffset - a), sin(Beta + BetaOffset - a), 0.0f)*Dist; - if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, - point, ent, checkBuildings, checkVehicles, checkPeds, - checkObjects, checkDummies, true, true)) - return -a; - } - } - return 0.0f; -} - -static float DefaultAcceleration = 0.045f; -static float DefaultMaxStep = 0.15f; - -void -CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - const float GroundDist = 1.85f; - - CVector TargetCoors, Dist, IdealSource; - float Length = 0.0f; - float LateralLeft = 0.0f; - float LateralRight = 0.0f; - float Center = 0.0f; - static bool PreviouslyObscured; - static bool PickedASide; - static float FixedTargetOrientation = 0.0f; - float AngleToGoTo = 0.0f; - float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg - float BetaOffsetGoingBehind = 0.45f; - bool GoingBehind = false; - bool Obscured = false; - bool BuildingCheckObscured = false; - bool HackPlayerOnStoppingTrain = false; - static int TimeIndicatedWantedToGoDown = 0; - static bool StartedCountingForGoDown = false; - float DeltaBeta; - - m_bFixingBeta = false; - bBelowMinDist = false; - bBehindPlayerDesired = false; - - assert(CamTargetEntity->IsPed()); - - // CenterDist should be > LateralDist because we don't have an angle for safety in this case - float CenterDist, LateralDist; - float AngleToGoToSpeed; - if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){ - LateralDist = 0.55f; - CenterDist = 1.25f; - BetaOffsetAvoidBuildings = 0.9f; // ~50 deg - BetaOffsetGoingBehind = 0.9f; - AngleToGoToSpeed = 0.88254666f; - }else{ - LateralDist = 0.8f; - CenterDist = 1.35f; - if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){ - LateralDist = 1.25f; - CenterDist = 1.6f; - } - AngleToGoToSpeed = 0.43254671f; - } - - FOV = DefaultFOV; - - if(ResetStatics){ - Rotating = false; - m_bCollisionChecksOn = true; - FixedTargetOrientation = 0.0f; - PreviouslyObscured = false; - PickedASide = false; - StartedCountingForGoDown = false; - AngleToGoTo = 0.0f; - // unused LastAngleWithNoPickedASide - } - - - TargetCoors = CameraTarget; - IdealSource = Source; - TargetCoors.z += m_fSyphonModeTargetZOffSet; - - CVector TempTargetCoors; - TempTargetCoors = DoAverageOnVector(TargetCoors); - TargetCoors = TempTargetCoors; - // Add this unknown offset, but later it's removed again - TargetCoors.z += m_fUnknownZOffSet; - - Dist.x = IdealSource.x - TargetCoors.x; - Dist.y = IdealSource.y - TargetCoors.y; - Length = Dist.Magnitude2D(); - - // Cam on a string. With a fixed distance. Zoom in/out is done later. - if(Length != 0.0f) - IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist; - else - IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f); - - // TODO: what's transition beta? - if(TheCamera.m_bUseTransitionBeta && ResetStatics){ - CVector VecDistance; - IdealSource.x = TargetCoors.x + GroundDist*cos(m_fTransitionBeta); - IdealSource.y = TargetCoors.y + GroundDist*sin(m_fTransitionBeta); - Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y); - }else - Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); - - if(TheCamera.m_bCamDirectlyBehind){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation + PI; - } - - if(FindPlayerVehicle()) - if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN) - HackPlayerOnStoppingTrain = true; - - if(TheCamera.m_bCamDirectlyInFront){ - m_bCollisionChecksOn = true; - Beta = TargetOrientation; - } - - while(Beta >= PI) Beta -= 2.0f * PI; - while(Beta < -PI) Beta += 2.0f * PI; - - // BUG? is this ever used? - // The values seem to be roughly m_fPedZoomValueSmooth + 1.85 - if(ResetStatics){ - if(TheCamera.PedZoomIndicator == 1.0) m_fRealGroundDist = 2.090556f; - if(TheCamera.PedZoomIndicator == 2.0) m_fRealGroundDist = 3.34973f; - if(TheCamera.PedZoomIndicator == 3.0) m_fRealGroundDist = 4.704914f; - if(TheCamera.PedZoomIndicator == 4.0) m_fRealGroundDist = 2.090556f; - } - // And what is this? It's only used for collision and rotation it seems - float RealGroundDist; - if(TheCamera.PedZoomIndicator == 1.0) RealGroundDist = 2.090556f; - if(TheCamera.PedZoomIndicator == 2.0) RealGroundDist = 3.34973f; - if(TheCamera.PedZoomIndicator == 3.0) RealGroundDist = 4.704914f; - if(TheCamera.PedZoomIndicator == 4.0) RealGroundDist = 2.090556f; - if(m_fCloseInPedHeightOffset > 0.00001f) - RealGroundDist = 1.7016; - - - bool Shooting = false; - CPed *ped = (CPed*)CamTargetEntity; - if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) - if(CPad::GetPad(0)->GetWeapon()) - Shooting = true; - if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR || - ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) - Shooting = false; - - - if(m_fCloseInPedHeightOffset > 0.00001f) - TargetCoors.z -= m_fUnknownZOffSet; - - // Figure out if and where we want to rotate - - if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ - - // Center cam behind player - - GoingBehind = true; - m_bCollisionChecksOn = true; - float OriginalBeta = Beta; - // Set Beta behind player - Beta = TargetOrientation + PI; - TargetCoors.z -= 0.1f; - - AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); - if(AngleToGoTo != 0.0f){ - if(AngleToGoTo < 0.0f) - AngleToGoTo -= AngleToGoToSpeed; - else - AngleToGoTo += AngleToGoToSpeed; - }else{ - float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false); - float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false); - if(LateralLeft == 0.0f && LateralRight != 0.0f) - AngleToGoTo += LateralRight; - else if(LateralLeft != 0.0f && LateralRight == 0.0f) - AngleToGoTo += LateralLeft; - } - - TargetCoors.z += 0.1f; - Beta = OriginalBeta; - - if(PickedASide){ - if(AngleToGoTo == 0.0f) - FixedTargetOrientation = TargetOrientation + PI; - Rotating = true; - }else{ - FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo; - Rotating = true; - PickedASide = true; - } - }else{ - - // Rotate cam to avoid clipping into buildings - - TargetCoors.z -= 0.1f; - - Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); - if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){ - if(Center != 0.0f){ - AngleToGoTo = Center; - }else{ - LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false); - LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false); - if(LateralLeft == 0.0f && LateralRight != 0.0f){ - AngleToGoTo += LateralRight; - if(m_fCloseInPedHeightOffset > 0.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.7f); - }else if(LateralLeft != 0.0f && LateralRight == 0.0f){ - AngleToGoTo += LateralLeft; - if(m_fCloseInPedHeightOffset > 0.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.7f); - } - } - if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f) - BuildingCheckObscured = true; - } - - TargetCoors.z += 0.1f; - } - - if(m_fCloseInPedHeightOffset > 0.00001f) - TargetCoors.z += m_fUnknownZOffSet; - - - // Have to fix to avoid collision - - if(AngleToGoTo != 0.0f){ - Obscured = true; - Rotating = true; - if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ - if(!PickedASide) - FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen? - }else - FixedTargetOrientation = Beta + AngleToGoTo; - - // This calculation is only really used to figure out how fast to rotate out of collision - - m_fAmountFractionObscured = 1.0f; - CVector PlayerPos = FindPlayerPed()->GetPosition(); - float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist; - // What's going on here? - AngleToGoTo? - CVector RotatedSource = PlayerPos + CVector(cos(Beta - AngleToGoTo), sin(Beta - AngleToGoTo), 0.0f) * RotationDist; - - CColPoint colpoint; - CEntity *entity; - if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){ - if((PlayerPos - RotatedSource).Magnitude() != 0.0f) - m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude(); - else - m_fAmountFractionObscured = 1.0f; - } - } - if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f; - if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f; - - - - // Figure out speed values for Beta rotation - - float Acceleration, MaxSpeed; - static float AccelerationMult = 0.35f; - static float MaxSpeedMult = 0.85f; - static float AccelerationMultClose = 0.7f; - static float MaxSpeedMultClose = 1.6f; - float BaseAcceleration = 0.025f; - float BaseMaxSpeed = 0.09f; - if(m_fCloseInPedHeightOffset > 0.00001f){ - if(AngleToGoTo == 0.0f){ - BaseAcceleration = 0.022f; - BaseMaxSpeed = 0.04f; - }else{ - BaseAcceleration = DefaultAcceleration; - BaseMaxSpeed = DefaultMaxStep; - } - } - if(AngleToGoTo == 0.0f){ - Acceleration = BaseAcceleration; - MaxSpeed = BaseMaxSpeed; - }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){ - Acceleration = 0.051f; - MaxSpeed = 0.18f; - }else if(m_fCloseInPedHeightOffset > 0.00001f){ - Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f); - MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f); - }else{ - Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f); - MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f); - } - static float AccelerationLimit = 0.3f; - static float MaxSpeedLimit = 0.65f; - if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit; - if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit; - - - int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; - if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && - !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){ - Rotating = false; - BetaSpeed = 0.0f; - } - - // Now do the Beta rotation - - float Distance = (IdealSource - TargetCoors).Magnitude2D(); - m_fDistanceBeforeChanges = Distance; - - if(Rotating){ - m_bFixingBeta = true; - - while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI; - while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI; - - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - -/* - // This is inlined WellBufferMe - DeltaBeta = FixedTargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - - float ReqSpeed = DeltaBeta * MaxSpeed; - // Add or subtract absolute depending on sign, genius! - if(ReqSpeed - BetaSpeed > 0.0f) - BetaSpeed += SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); - else - BetaSpeed -= SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); - // this would be simpler: - // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep; - - if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed) - BetaSpeed = ReqSpeed; - else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed) - BetaSpeed = ReqSpeed; - - Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep()); -*/ - WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true); - - if(ResetStatics){ - Beta = FixedTargetOrientation; - BetaSpeed = 0.0f; - } - - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); - - // Check if we can stop rotating - DeltaBeta = FixedTargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(fabs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ - // Stop rotation - PickedASide = false; - Rotating = false; - BetaSpeed = 0.0f; - } - } - - - if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || - HackPlayerOnStoppingTrain || Rotating){ - if(TheCamera.m_bCamDirectlyBehind){ - Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); - } - if(TheCamera.m_bCamDirectlyInFront){ - Beta = TargetOrientation; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); - } - if(HackPlayerOnStoppingTrain){ - Beta = TargetOrientation + PI; - Source.x = TargetCoors.x + Distance * cos(Beta); - Source.y = TargetCoors.y + Distance * sin(Beta); - m_fDimensionOfHighestNearCar = 0.0f; - m_fCamBufferedHeight = 0.0f; - m_fCamBufferedHeightSpeed = 0.0f; - } - // Beta and Source already set in the rotation code - }else{ - Source = IdealSource; - BetaSpeed = 0.0f; - } - - // Subtract m_fUnknownZOffSet from both? - TargetCoors.z -= m_fUnknownZOffSet; - Source.z = IdealSource.z - m_fUnknownZOffSet; - - // Apply zoom now - // m_fPedZoomValueSmooth makes the cam go down the further out it is - // 0.25 -> 0.20 for nearest dist - // 1.50 -> -0.05 for mid dist - // 2.90 -> -0.33 for far dist - Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f; - // Zoom out camera - Front = TargetCoors - Source; - Front.Normalise(); - Source -= Front * TheCamera.m_fPedZoomValueSmooth; - // and then we move up again - // -0.375 - // 0.25 - // 0.95 - Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset; - - - // Process height offset to avoid peds and cars - - float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar; - TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset); - float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z; - - if(TargetHeight > m_fCamBufferedHeight){ - // Have to go up - if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false); - else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){ - // TODO: figure this out - bool foo = false; - switch(((CPhysical*)CamTargetEntity)->m_nLastCollType) - case 2: case 3: case 5: - case 11: case 23: case 26: - foo = true; - if(foo) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false); - else - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); - }else - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); - StartedCountingForGoDown = false; - }else{ - // Have to go down - if(StartedCountingForGoDown){ - if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){ - if(TargetHeight > 0.0f) - WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); - else - WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); - } - }else{ - StartedCountingForGoDown = true; - TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds(); - } - } - - Source.z += m_fCamBufferedHeight; - - - // Clip Source if necessary - - bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f; - if(GoingBehind || ResetStatics || ClipSource){ - CColPoint colpoint; - CEntity *entity; - if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){ - Source = colpoint.point; - if((TargetCoors - Source).Magnitude2D() < 1.0f) - RwCameraSetNearClipPlane(Scene.camera, 0.05f); - } - } - - TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f); - m_cvecTargetCoorsForFudgeInter = TargetCoors; - - Front = TargetCoors - Source; - m_fRealGroundDist = Front.Magnitude2D(); - m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist; - Front.Normalise(); - GetVectorsReadyForRW(); - TheCamera.m_bCamDirectlyBehind = false; - TheCamera.m_bCamDirectlyInFront = false; - PreviouslyObscured = BuildingCheckObscured; - - ResetStatics = false; -} - -void -CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - FOV = DefaultFOV; - - if(!CamTargetEntity->IsVehicle()) - return; - - CVector TargetCoors = CameraTarget; - TargetCoors.z -= 0.2f; - CA_MAX_DISTANCE = 9.95f; - CA_MIN_DISTANCE = 8.5f; - - CVector Dist = Source - TargetCoors; - float Length = Dist.Magnitude2D(); - m_fDistanceBeforeChanges = Length; - if(Length < 0.002f) - Length = 0.002f; - Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); - if(Length > CA_MAX_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; - }else if(Length < CA_MIN_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; - } - TargetCoors.z += 0.8f; - - WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation); - RotCamIfInFrontCar(TargetCoors, TargetOrientation); - FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation); - - Front = TargetCoors - Source; - m_cvecTargetCoorsForFudgeInter = TargetCoors; - ResetStatics = false; - GetVectorsReadyForRW(); -} - -void -CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation) -{ - CColPoint colpoint; - CEntity *ent; - float TargetZOffSet = 0.0f; - static bool PreviouslyFailedRoadHeightCheck = false; - static float RoadHeightFix = 0.0f; - static float RoadHeightFixSpeed = 0.0f; - - if(ResetStatics){ - RoadHeightFix = 0.0f; - RoadHeightFixSpeed = 0.0f; - Alpha = DEGTORAD(25.0f); - AlphaSpeed = 0.0f; - } - float AlphaTarget = DEGTORAD(25.0f); - if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) - AlphaTarget = DEGTORAD(14.0f); - WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true); - Source.z = TargetCoors.z + CA_MAX_DISTANCE*sin(Alpha); - - if(FindPlayerVehicle()){ - m_fUnknownZOffSet = 0.0f; - bool FoundRoad = false; - bool FoundRoof = false; - float RoadZ = 0.0f; - float RoofZ = 0.0f; - - if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && - ent->IsBuilding()){ - FoundRoad = true; - RoadZ = colpoint.point.z; - } - - if(FoundRoad){ - if(Source.z - RoadZ < 0.9f){ - PreviouslyFailedRoadHeightCheck = true; - TargetZOffSet = RoadZ + 0.9f - Source.z; - }else{ - if(m_bCollisionChecksOn) - PreviouslyFailedRoadHeightCheck = false; - else - TargetZOffSet = 0.0f; - } - }else{ - if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && - ent->IsBuilding()){ - FoundRoof = true; - RoofZ = colpoint.point.z; - } - if(FoundRoof){ - if(Source.z - RoofZ < 0.9f){ - PreviouslyFailedRoadHeightCheck = true; - TargetZOffSet = RoofZ + 0.9f - Source.z; - }else{ - if(m_bCollisionChecksOn) - PreviouslyFailedRoadHeightCheck = false; - else - TargetZOffSet = 0.0f; - } - } - } - } - - if(TargetZOffSet > RoadHeightFix) - RoadHeightFix = TargetZOffSet; - else - WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false); - - if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) && - colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE && - RoadHeightFix > 1.4f) - RoadHeightFix = 1.4f; - - Source.z += RoadHeightFix; -} - -void -CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) -{ - static float LastTargetAlphaWithCollisionOn = 0.0f; - static float LastTopAlphaSpeed = 0.0f; - static float LastAlphaSpeedStep = 0.0f; - static bool PreviousNearCheckNearClipSmall = false; - - bool CamClear = true; - float ModeAlpha = 0.0f; - - if(ResetStatics){ - LastTargetAlphaWithCollisionOn = 0.0f; - LastTopAlphaSpeed = 0.0f; - LastAlphaSpeedStep = 0.0f; - PreviousNearCheckNearClipSmall = false; - } - - float TopAlphaSpeed = 0.15f; - float AlphaSpeedStep = 0.015f; - - float zoomvalue = TheCamera.CarZoomValueSmooth; - if(zoomvalue < 0.1f) - zoomvalue = 0.1f; - if(TheCamera.CarZoomIndicator == 1.0f) - ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near - else if(TheCamera.CarZoomIndicator == 2.0f) - ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid - else if(TheCamera.CarZoomIndicator == 3.0f) - ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far - - - float Length = (Source - TargetCoors).Magnitude2D(); - if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised - CVector Forward = CamTargetEntity->GetForward(); - float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z); - // this shouldn't be necessary.... - while(CarAlpha >= PI) CarAlpha -= 2*PI; - while(CarAlpha < -PI) CarAlpha += 2*PI; - - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - float deltaBeta = Beta - TargetOrientation; - while(deltaBeta >= PI) deltaBeta -= 2*PI; - while(deltaBeta < -PI) deltaBeta += 2*PI; - - float BehindCarNess = cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front - CarAlpha = -CarAlpha * BehindCarNess; - if(CarAlpha < -0.01f) - CarAlpha = -0.01f; - - float DeltaAlpha = CarAlpha - Alpha; - while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; - while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; - // What's this?? wouldn't it make more sense to clamp? - float AngleLimit = DEGTORAD(1.8f); - if(DeltaAlpha < -AngleLimit) - DeltaAlpha += AngleLimit; - else if(DeltaAlpha > AngleLimit) - DeltaAlpha -= AngleLimit; - else - DeltaAlpha = 0.0f; - - // Now the collision - - float TargetAlpha = 0.0f; - bool FoundRoofCenter = false; - bool FoundRoofSide1 = false; - bool FoundRoofSide2 = false; - bool FoundCamRoof = false; - bool FoundCamGround = false; - float CamRoof = 0.0f; - float CarBottom = TargetCoors.z - TargetHeight/2.0f; - - // Check car center - float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter); - - // Check sides of the car - Forward = CamTargetEntity->GetForward(); // we actually still have that... - Forward.Normalise(); // shouldn't be necessary - float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f; - float SideX = 2.5f * cos(CarSideAngle); - float SideY = 2.5f * sin(CarSideAngle); - CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1); - CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2); - - // Now find out at what height we'd like to place the camera - float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); - float CamTargetZ = 0.0f; - if(FoundCamGround){ - // This is the normal case - CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof); - CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f; - }else{ - FoundCamRoof = false; - CamTargetZ = TargetCoors.z; - } - - if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){ - // Car is under something but camera isn't - // This seems weird... - TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f); - CamClear = false; - } - if(FoundCamRoof){ - // Camera is under something - float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof; - // Same weirdness again? - TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f); - CamClear = false; - } - while(TargetAlpha >= PI) TargetAlpha -= 2*PI; - while(TargetAlpha < -PI) TargetAlpha += 2*PI; - if(TargetAlpha < DEGTORAD(-7.0f)) - TargetAlpha = DEGTORAD(-7.0f); - - // huh? - if(TargetAlpha > ModeAlpha) - CamClear = true; - // Camera is contrained by collision in some way - PreviousNearCheckNearClipSmall = false; - if(!CamClear){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha); - while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; - while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; - - TopAlphaSpeed = 0.3f; - AlphaSpeedStep = 0.03f; - } - - // Now do things if CamClear...but what is that anyway? - float CamZ = TargetCoors.z + Length*sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; - bool FoundGround, FoundRoof; - float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround); - if(FoundGround){ - if(CamClear) - if(CamZ - CamGround2 < 1.5f){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - float a; - if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f) - a = Alpha; - else - a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z); - while(a > PI) a -= 2*PI; - while(a < -PI) a += 2*PI; - DeltaAlpha = a - Alpha; - } - }else{ - if(CamClear){ - float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof); - if(FoundRoof && CamZ - CamRoof2 < 1.5f){ - PreviousNearCheckNearClipSmall = true; - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - - if(CamRoof2 > TargetCoors.z + 3.5f) - CamRoof2 = TargetCoors.z + 3.5f; - - float a; - if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f) - a = Alpha; - else - a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z); - while(a > PI) a -= 2*PI; - while(a < -PI) a += 2*PI; - DeltaAlpha = a - Alpha; - } - } - } - - LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha; - LastTopAlphaSpeed = TopAlphaSpeed; - LastAlphaSpeedStep = AlphaSpeedStep; - }else{ - if(PreviousNearCheckNearClipSmall) - RwCameraSetNearClipPlane(Scene.camera, 0.9f); - } - - WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true); - - Source.z = TargetCoors.z + sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; -} - -// Rotate cam behind the car when the car is moving forward -bool -CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) -{ - bool MovingForward = false; - CPhysical *phys = (CPhysical*)CamTargetEntity; - - float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); - if(ForwardSpeed > 0.02f) - MovingForward = true; - - float Dist = (Source - TargetCoors).Magnitude2D(); - - float DeltaBeta = TargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - - if(fabs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) - m_bFixingBeta = true; - - CPad *pad = CPad::GetPad(0); - if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) - if(DirectionWasLooking != LOOKING_FORWARD) - TheCamera.m_bCamDirectlyBehind = true; - - if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront) - return false; - - bool SetBeta = false; - if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta) - if(&TheCamera.Cams[TheCamera.ActiveCam] == this) - SetBeta = true; - - if(m_bFixingBeta || SetBeta){ - WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true); - - if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = TargetOrientation; - if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = TargetOrientation + PI; - if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this) - Beta = m_fTransitionBeta; - - Source.x = TargetCoors.x - cos(Beta)*Dist; - Source.y = TargetCoors.y - sin(Beta)*Dist; - - // Check if we're done - DeltaBeta = TargetOrientation - Beta; - while(DeltaBeta >= PI) DeltaBeta -= 2*PI; - while(DeltaBeta < -PI) DeltaBeta += 2*PI; - if(fabs(DeltaBeta) < DEGTORAD(2.0f)) - m_bFixingBeta = false; - } - TheCamera.m_bCamDirectlyBehind = false; - TheCamera.m_bCamDirectlyInFront = false; - return true; -} - -// Move the cam to avoid clipping through buildings -bool -CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation) -{ - CVector Target = TargetCoors; - bool UseEntityPos = false; - CVector EntityPos; - static CColPoint colPoint; - static bool LastObscured = false; - - if(Mode == MODE_BEHINDCAR) - Target.z += TargetHeight/2.0f; - if(Mode == MODE_CAMONASTRING){ - UseEntityPos = true; - Target.z += TargetHeight/2.0f; - EntityPos = CamTargetEntity->GetPosition(); - } - - CVector TempSource = Source; - - bool Obscured1 = false; - bool Obscured2 = false; - bool Fix1 = false; - float Dist1 = 0.0f; - float Dist2 = 0.0f; - CEntity *ent; - if(m_bCollisionChecksOn || LastObscured){ - Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); - if(Obscured1){ - Dist1 = (Target - colPoint.point).Magnitude2D(); - Fix1 = true; - if(UseEntityPos) - Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); - }else if(m_bFixingBeta){ - float d = (TempSource - Target).Magnitude(); - TempSource.x = Target.x - d*cos(TargetOrientation); - TempSource.y = Target.y - d*sin(TargetOrientation); - - // same check again - Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); - if(Obscured2){ - Dist2 = (Target - colPoint.point).Magnitude2D(); - if(UseEntityPos) - Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); - } - } - LastObscured = Obscured1 || Obscured2; - } - - // nothing to do - if(!LastObscured) - return false; - - if(Fix1){ - Source.x = Target.x - cos(Beta)*Dist1; - Source.y = Target.y - sin(Beta)*Dist1; - if(Mode == MODE_BEHINDCAR) - Source = colPoint.point; - }else{ - WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false); - Source.x = Target.x - cos(Beta)*m_fDistanceBeforeChanges; - Source.y = Target.y - sin(Beta)*m_fDistanceBeforeChanges; - } - - if(ResetStatics){ - m_fDistanceBeforeChanges = (Source - Target).Magnitude2D(); - DistanceSpeed = 0.0f; - Source.x = colPoint.point.x; - Source.y = colPoint.point.y; - } - return true; -} - -void -CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) -{ - if(!CamTargetEntity->IsVehicle()) - return; - - FOV = DefaultFOV; - - if(ResetStatics){ - AlphaSpeed = 0.0f; - if(TheCamera.m_bIdleOn) - TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); - } - - CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); - CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min; - float BaseDist = Dimensions.Magnitude2D(); - - CVector TargetCoors = CameraTarget; - TargetCoors.z += Dimensions.z - 0.1f; // final - Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); - while(Alpha >= PI) Alpha -= 2*PI; - while(Alpha < -PI) Alpha += 2*PI; - while(Beta >= PI) Beta -= 2*PI; - while(Beta < -PI) Beta += 2*PI; - - m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D(); - - Cam_On_A_String_Unobscured(TargetCoors, BaseDist); - WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z); - RotCamIfInFrontCar(TargetCoors, TargetOrientation); - FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation); - FixCamWhenObscuredByVehicle(TargetCoors); - - m_cvecTargetCoorsForFudgeInter = TargetCoors; - Front = TargetCoors - Source; - Front.Normalise(); - GetVectorsReadyForRW(); - ResetStatics = false; -} - -// Basic Cam on a string algorithm -void -CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) -{ - CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth; - CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f); - - CVector Dist = Source - TargetCoors; - - if(ResetStatics) - Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); - - float Length = Dist.Magnitude2D(); - if(Length < 0.001f){ - // This probably shouldn't happen. reset view - CVector Forward = CamTargetEntity->GetForward(); - Forward.z = 0.0f; - Forward.Normalise(); - Source = TargetCoors - Forward*CA_MAX_DISTANCE; - Dist = Source - TargetCoors; - Length = Dist.Magnitude2D(); - } - - if(Length > CA_MAX_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; - }else if(Length < CA_MIN_DISTANCE){ - Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; - Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; - } -} - -void -CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) -{ - // BUG? is this never reset - static float HeightFixerCarsObscuring = 0.0f; - static float HeightFixerCarsObscuringSpeed = 0.0f; - CColPoint colPoint; - CEntity *entity; - - float HeightTarget = 0.0f; - if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){ - CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex()); - HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z; - if(HeightTarget < 0.0f) - HeightTarget = 0.0f; - } - WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false); - Source.z += HeightFixerCarsObscuring; -} - -bool -CCam::Using3rdPersonMouseCam() -{ - return CCamera::m_bUseMouse3rdPerson && - (Mode == MODE_FOLLOWPED || - TheCamera.m_bPlayerIsInGarage && - FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING && - Mode != MODE_TOPDOWN1 && this->CamTargetEntity == FindPlayerPed()); -} - -bool -CCam::GetWeaponFirstPersonOn() -{ - CEntity *target = this->CamTargetEntity; - if (target && target->IsPed()) - return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; - - return false; -} - -STARTPATCHES - InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP); - InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP); - - InjectHook(0x46FD40, &CCamera::SetMotionBlur, PATCH_JUMP); - InjectHook(0x46FD80, &CCamera::SetMotionBlurAlpha, PATCH_JUMP); - InjectHook(0x46F940, &CCamera::RenderMotionBlur, PATCH_JUMP); - - InjectHook(0x456F40, WellBufferMe, PATCH_JUMP); - InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP); - InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP); - InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP); - InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP); - InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP); - InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP); - InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP); - InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP); - InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP); - - InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP); - InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP); - InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP); - - InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP); -ENDPATCHES diff --git a/src/Camera.h b/src/Camera.h deleted file mode 100644 index 84c3060b..00000000 --- a/src/Camera.h +++ /dev/null @@ -1,476 +0,0 @@ -#pragma once -#include "Placeable.h" - -class CEntity; -class CPed; -class CAutomobile; - -#define NUMBER_OF_VECTORS_FOR_AVERAGE 2 - -struct CCam -{ - enum - { - MODE_TOPDOWN1 = 1, - MODE_TOPDOWN2, - MODE_BEHINDCAR, - MODE_FOLLOWPED, - MODE_AIMING, - MODE_DEBUG, - MODE_SNIPER, - MODE_ROCKET, - MODE_MODELVIEW, - MODE_BILL, - MODE_SYPHON, - MODE_CIRCLE, - MODE_CHEESYZOOM, - MODE_WHEELCAM, - MODE_FIXED, - MODE_FIRSTPERSON, - MODE_FLYBY, - MODE_CAMONASTRING, - MODE_REACTIONCAM, - MODE_FOLLOWPEDWITHBINDING, - MODE_CHRISWITHBINDINGPLUSROTATION, - MODE_BEHINDBOAT, - MODE_PLAYERFALLENWATER, - MODE_CAMONTRAINROOF, - MODE_CAMRUNNINGSIDETRAIN, - MODE_BLOODONTHETRACKS, - MODE_IMTHEPASSENGERWOOWOO, - MODE_SYPHONCRIMINFRONT, - MODE_PEDSDEADBABY, - MODE_CUSHYPILLOWSARSE, - MODE_LOOKATCARS, - MODE_ARRESTCAMONE, - MODE_ARRESTCAMTWO, - MODE_M16FIRSTPERSON_34, - MODE_SPECIALFIXEDFORSYPHON, - MODE_FIGHT, - MODE_TOPDOWNPED, - MODE_SNIPER_RUN_AROUND, - MODE_ROCKET_RUN_AROUND, - MODE_FIRSTPERSONPEDONPC_40, - MODE_FIRSTPERSONPEDONPC_41, - MODE_FIRSTPERSONPEDONPC_42, - MODE_EDITOR, - MODE_M16FIRSTPERSON_44 - }; - - bool bBelowMinDist; //used for follow ped mode - bool bBehindPlayerDesired; //used for follow ped mode - bool m_bCamLookingAtVector; - bool m_bCollisionChecksOn; - bool m_bFixingBeta; //used for camera on a string - bool m_bTheHeightFixerVehicleIsATrain; - bool LookBehindCamWasInFront; - bool LookingBehind; - bool LookingLeft; // 32 - bool LookingRight; - bool ResetStatics; //for interpolation type stuff to work - bool Rotating; - - int16 Mode; // CameraMode - uint32 m_uiFinishTime; // 52 - - int m_iDoCollisionChecksOnFrameNum; - int m_iDoCollisionCheckEveryNumOfFrames; - int m_iFrameNumWereAt; // 64 - int m_iRunningVectorArrayPos; - int m_iRunningVectorCounter; - int DirectionWasLooking; - - float f_max_role_angle; //=DEGTORAD(5.0f); - float f_Roll; //used for adding a slight roll to the camera in the - float f_rollSpeed; - float m_fSyphonModeTargetZOffSet; - float m_fUnknownZOffSet; - float m_fAmountFractionObscured; - float m_fAlphaSpeedOverOneFrame; // 100 - float m_fBetaSpeedOverOneFrame; - float m_fBufferedTargetBeta; - float m_fBufferedTargetOrientation; - float m_fBufferedTargetOrientationSpeed; - float m_fCamBufferedHeight; - float m_fCamBufferedHeightSpeed; - float m_fCloseInPedHeightOffset; - float m_fCloseInPedHeightOffsetSpeed; // 132 - float m_fCloseInCarHeightOffset; - float m_fCloseInCarHeightOffsetSpeed; - float m_fDimensionOfHighestNearCar; - float m_fDistanceBeforeChanges; - float m_fFovSpeedOverOneFrame; - float m_fMinDistAwayFromCamWhenInterPolating; - float m_fPedBetweenCameraHeightOffset; - float m_fPlayerInFrontSyphonAngleOffSet; // 164 - float m_fRadiusForDead; - float m_fRealGroundDist; //used for follow ped mode - float m_fTargetBeta; - float m_fTimeElapsedFloat; - - float m_fTransitionBeta; - float m_fTrueBeta; - float m_fTrueAlpha; // 200 - float m_fInitialPlayerOrientation; //used for first person - - float Alpha; - float AlphaSpeed; - float FOV; - float FOVSpeed; - float Beta; - float BetaSpeed; - float Distance; // 232 - float DistanceSpeed; - float CA_MIN_DISTANCE; - float CA_MAX_DISTANCE; - float SpeedVar; - - // ped onfoot zoom distance - float m_fTargetZoomGroundOne; - float m_fTargetZoomGroundTwo; // 256 - float m_fTargetZoomGroundThree; - // ped onfoot alpha angle offset - float m_fTargetZoomOneZExtra; - float m_fTargetZoomTwoZExtra; - float m_fTargetZoomThreeZExtra; - - float m_fTargetZoomZCloseIn; - float m_fMinRealGroundDist; - float m_fTargetCloseInDist; - - CVector m_cvecTargetCoorsForFudgeInter; // 360 - CVector m_cvecCamFixedModeVector; // 372 - CVector m_cvecCamFixedModeSource; // 384 - CVector m_cvecCamFixedModeUpOffSet; // 396 - CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water - CVector m_vecBufferedPlayerBodyOffset; // 420 - - // The three vectors that determine this camera for this frame - CVector Front; // 432 // Direction of looking in - CVector Source; // Coors in world space - CVector SourceBeforeLookBehind; - CVector Up; // Just that - CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff - CEntity *CamTargetEntity; - - float m_fCameraDistance; - float m_fIdealAlpha; - float m_fPlayerVelocity; - CAutomobile *m_pLastCarEntered; // So interpolation works - CPed *m_pLastPedLookedAt;// So interpolation works - bool m_bFirstPersonRunAboutActive; - - - void GetVectorsReadyForRW(void); - CVector DoAverageOnVector(const CVector &vec); - float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies); - void WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation); - void WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight); - bool RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation); - bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation); - void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist); - void FixCamWhenObscuredByVehicle(const CVector &TargetCoors); - bool Using3rdPersonMouseCam(); - bool GetWeaponFirstPersonOn(); - - void Process_Debug(float *vec, float a, float b, float c); - void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float); - void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float); - void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float); -}; -static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size"); -static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error"); -static_assert(offsetof(CCam, Front) == 0x140, "CCam: error"); - -struct CCamPathSplines -{ - float m_arr_PathData[800]; -}; - -struct CTrainCamNode -{ - CVector m_cvecCamPosition; - CVector m_cvecPointToLookAt; - CVector m_cvecMinPointInRange; - CVector m_cvecMaxPointInRange; - float m_fDesiredFOV; - float m_fNearClip; -}; - -struct CQueuedMode -{ - int16 Mode; - float Duration; - int16 MinZoom; - int16 MaxZoom; -}; - -enum -{ - LOOKING_BEHIND, - LOOKING_LEFT, - LOOKING_RIGHT, - LOOKING_FORWARD, -}; - -enum -{ - // TODO: figure out - FADE_0, - FADE_1, // mid fade - FADE_2, - - FADE_OUT = 0, - FADE_IN, -}; - -enum -{ - MBLUR_NONE, - MBLUR_SNIPER, - MBLUR_NORMAL, - MBLUR_INTRO1, // green camera - MBLUR_INTRO2, // unused - MBLUR_INTRO3, // bank scene - MBLUR_INTRO4, // jail break scene - MBLUR_INTRO5, // explosion - MBLUR_INTRO6, // player shot - MBLUR_UNUSED, // pinkish -}; - -struct CCamera : public CPlaceable -{ - bool m_bAboveGroundTrainNodesLoaded; - bool m_bBelowGroundTrainNodesLoaded; - bool m_bCamDirectlyBehind; - bool m_bCamDirectlyInFront; - bool m_bCameraJustRestored; - bool m_bcutsceneFinished; - bool m_bCullZoneChecksOn; - bool m_bFirstPersonBeingUsed; - bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; - bool m_bIdleOn; - bool m_bInATunnelAndABigVehicle; - bool m_bInitialNodeFound; - bool m_bInitialNoNodeStaticsSet; - bool m_bIgnoreFadingStuffForMusic; - bool m_bPlayerIsInGarage; - bool m_bJustCameOutOfGarage; - bool m_bJustInitalised; - bool m_bJust_Switched; - bool m_bLookingAtPlayer; - bool m_bLookingAtVector; - bool m_bMoveCamToAvoidGeom; - bool m_bObbeCinematicPedCamOn; - bool m_bObbeCinematicCarCamOn; - bool m_bRestoreByJumpCut; - bool m_bUseNearClipScript; - bool m_bStartInterScript; - bool m_bStartingSpline; - bool m_bTargetJustBeenOnTrain; - bool m_bTargetJustCameOffTrain; - bool m_bUseSpecialFovTrain; - bool m_bUseTransitionBeta; - bool m_bUseScriptZoomValuePed; - bool m_bUseScriptZoomValueCar; - bool m_bWaitForInterpolToFinish; - bool m_bItsOkToLookJustAtThePlayer; - bool m_bWantsToSwitchWidescreenOff; - bool m_WideScreenOn; - bool m_1rstPersonRunCloseToAWall; - bool m_bHeadBob; - bool m_bFailedCullZoneTestPreviously; - -bool m_FadeTargetIsSplashScreen; - - bool WorldViewerBeingUsed; - uint8 ActiveCam; - uint32 m_uiCamShakeStart; - uint32 m_uiFirstPersonCamLastInputTime; -// where are those? -//bool m_bVehicleSuspenHigh; -//bool m_bEnable1rstPersonCamCntrlsScript; -//bool m_bAllow1rstPersonWeaponsCamera; - - uint32 m_uiLongestTimeInMill; - uint32 m_uiNumberOfTrainCamNodes; - uint8 m_uiTransitionJUSTStarted; - uint8 m_uiTransitionState; // 0:one mode 1:transition - - uint32 m_uiTimeLastChange; - uint32 m_uiTimeWeEnteredIdle; - uint32 m_uiTimeTransitionStart; - uint32 m_uiTransitionDuration; - int m_BlurBlue; - int m_BlurGreen; - int m_BlurRed; - int m_BlurType; - -uint32 unknown; - int m_iWorkOutSpeedThisNumFrames; - int m_iNumFramesSoFar; - - - int m_iCurrentTrainCamNode; - int m_motionBlur; - int m_imotionBlurAddAlpha; - int m_iCheckCullZoneThisNumFrames; - int m_iZoneCullFrameNumWereAt; - int WhoIsInControlOfTheCamera; - - float CamFrontXNorm; - float CamFrontYNorm; - float CarZoomIndicator; - float CarZoomValue; - float CarZoomValueSmooth; - - float DistanceToWater; - float FOVDuringInter; - float LODDistMultiplier; - float GenerationDistMultiplier; - float m_fAlphaSpeedAtStartInter; - float m_fAlphaWhenInterPol; - float m_fAlphaDuringInterPol; - float m_fBetaDuringInterPol; - float m_fBetaSpeedAtStartInter; - float m_fBetaWhenInterPol; - float m_fFOVWhenInterPol; - float m_fFOVSpeedAtStartInter; - float m_fStartingBetaForInterPol; - float m_fStartingAlphaForInterPol; - float m_PedOrientForBehindOrInFront; - float m_CameraAverageSpeed; - float m_CameraSpeedSoFar; - float m_fCamShakeForce; - float m_fCarZoomValueScript; - float m_fFovForTrain; - float m_fFOV_Wide_Screen; - float m_fNearClipScript; - float m_fOldBetaDiff; - float m_fPedZoomValue; - - float m_fPedZoomValueScript; - float m_fPedZoomValueSmooth; - float m_fPositionAlongSpline; - float m_ScreenReductionPercentage; - float m_ScreenReductionSpeed; - float m_AlphaForPlayerAnim1rstPerson; - float Orientation; - float PedZoomIndicator; - float PlayerExhaustion; - float SoundDistUp, SoundDistLeft, SoundDistRight; - float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; - float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; - float m_fWideScreenReductionAmount; - float m_fStartingFOVForInterPol; - - // not static yet - float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls - float m_fMouseAccelVertical;// acceleration multiplier for 1st person controls - float m_f3rdPersonCHairMultX; - float m_f3rdPersonCHairMultY; - - - CCam Cams[3]; - void *pToGarageWeAreIn; - void *pToGarageWeAreInForHackAvoidFirstPerson; - CQueuedMode m_PlayerMode; - CQueuedMode PlayerWeaponMode; - CVector m_PreviousCameraPosition; - CVector m_RealPreviousCameraPosition; - CVector m_cvecAimingTargetCoors; - CVector m_vecFixedModeVector; - - // one of those has to go - CVector m_vecFixedModeSource; - CVector m_vecFixedModeUpOffSet; -// CVector m_vecCutSceneOffset; - CVector m_cvecStartingSourceForInterPol; - CVector m_cvecStartingTargetForInterPol; - CVector m_cvecStartingUpForInterPol; - CVector m_cvecSourceSpeedAtStartInter; - CVector m_cvecTargetSpeedAtStartInter; - CVector m_cvecUpSpeedAtStartInter; - CVector m_vecSourceWhenInterPol; - CVector m_vecTargetWhenInterPol; - CVector m_vecUpWhenInterPol; - CVector m_vecClearGeometryVec; - - CVector m_vecGameCamPos; - CVector SourceDuringInter; - CVector TargetDuringInter; - CVector UpDuringInter; - RwCamera *m_pRwCamera; - CEntity *pTargetEntity; - CCamPathSplines m_arrPathArray[4]; - CTrainCamNode m_arrTrainCamNode[800]; - CMatrix m_cameraMatrix; - bool m_bGarageFixedCamPositionSet; - bool m_vecDoingSpecialInterPolation; - bool m_bScriptParametersSetForInterPol; - bool m_bFading; - bool m_bMusicFading; - CMatrix m_viewMatrix; - CVector m_vecFrustumNormals[4]; - CVector m_vecOldSourceForInter; - CVector m_vecOldFrontForInter; - CVector m_vecOldUpForInter; - - float m_vecOldFOVForInter; - float m_fFLOATingFade; - float m_fFLOATingFadeMusic; - float m_fTimeToFadeOut; - float m_fTimeToFadeMusic; - float m_fFractionInterToStopMovingTarget; - float m_fFractionInterToStopCatchUpTarget; - float m_fGaitSwayBuffer; - float m_fScriptPercentageInterToStopMoving; - float m_fScriptPercentageInterToCatchUp; - -uint32 m_fScriptTimeForInterPolation; - - -int16 m_iFadingDirection; -int m_iModeObbeCamIsInForCar; - int16 m_iModeToGoTo; - int16 m_iMusicFadingDirection; - int16 m_iTypeOfSwitch; - - uint32 m_uiFadeTimeStarted; - uint32 m_uiFadeTimeStartedMusic; - - static bool &m_bUseMouse3rdPerson; - - CMatrix &GetCameraMatrix(void) { return m_cameraMatrix; } - CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } - bool IsPointVisible(const CVector ¢er, const CMatrix *mat); - bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); - bool IsBoxVisible(RwV3d *box, const CMatrix *mat); - int GetLookDirection(void); - - void Fade(float timeout, int16 direction); - int GetScreenFadeStatus(void); - void ProcessFade(void); - void ProcessMusicFade(void); - void SetFadeColour(uint8 r, uint8 g, uint8 b); - - void SetMotionBlur(int r, int g, int b, int a, int type); - void SetMotionBlurAlpha(int a); - void RenderMotionBlur(void); - void CalculateDerivedValues(void); - - void DrawBordersForWideScreen(void); - void Restore(void); - void SetWidescreenOff(void); - - void dtor(void) { this->CCamera::~CCamera(); } -}; -static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error"); -static_assert(offsetof(CCamera, WorldViewerBeingUsed) == 0x75, "CCamera: error"); -static_assert(offsetof(CCamera, m_uiNumberOfTrainCamNodes) == 0x84, "CCamera: error"); -static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error"); -static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error"); -static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error"); -static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error"); -static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size"); -extern CCamera &TheCamera; diff --git a/src/CdStream.cpp b/src/CdStream.cpp deleted file mode 100644 index 255e46bb..00000000 --- a/src/CdStream.cpp +++ /dev/null @@ -1,529 +0,0 @@ -#include -#include "common.h" -#include "patcher.h" -#include "CdStream.h" -#include "rwcore.h" -#include "RwHelper.h" - -#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", __VA_ARGS__) -#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", __VA_ARGS__) - -struct CdReadInfo -{ - uint32 nSectorOffset; - uint32 nSectorsToRead; - void *pBuffer; - char field_C; - bool bLocked; - bool bInUse; - char _pad0; - int32 nStatus; - HANDLE hSemaphore; - HANDLE hFile; - OVERLAPPED Overlapped; -}; -VALIDATE_SIZE(CdReadInfo, 0x30); - -char gCdImageNames[MAX_CDIMAGES+1][64]; -int32 gNumImages; -int32 gNumChannels; - -HANDLE gImgFiles[MAX_CDIMAGES]; - -HANDLE _gCdStreamThread; -HANDLE gCdStreamSema; -DWORD _gCdStreamThreadId; - -CdReadInfo *gpReadInfo; -Queue gChannelRequestQ; - -int32 lastPosnRead; - -BOOL _gbCdStreamOverlapped; -BOOL _gbCdStreamAsync; -DWORD _gdwCdStreamFlags; - - -void -CdStreamInitThread(void) -{ - SetLastError(0); - - if ( gNumChannels > 0 ) - { - for ( int32 i = 0; i < gNumChannels; i++ ) - { - gpReadInfo[i].hSemaphore = CreateSemaphore(nil, 0, 2, nil); - - if ( gpReadInfo[i].hSemaphore == nil ) - { - CDTRACE("failed to create sync semaphore"); - ASSERT(0); - return; - } - } - } - - gChannelRequestQ.items = (int32 *)LocalAlloc(LMEM_ZEROINIT, sizeof(int32) * (gNumChannels + 1)); - gChannelRequestQ.head = 0; - gChannelRequestQ.tail = 0; - gChannelRequestQ.size = gNumChannels + 1; - ASSERT(gChannelRequestQ.items != nil ); - - gCdStreamSema = CreateSemaphore(nil, 0, 5, "CdStream"); - - if ( gCdStreamSema == nil ) - { - CDTRACE("failed to create stream semaphore"); - ASSERT(0); - return; - } - - _gCdStreamThread = CreateThread(nil, 64*1024/*64KB*/, CdStreamThread, nil, CREATE_SUSPENDED, &_gCdStreamThreadId); - - if ( _gCdStreamThread == nil ) - { - CDTRACE("failed to create streaming thread"); - ASSERT(0); - return; - } - - SetThreadPriority(_gCdStreamThread, GetThreadPriority(GetCurrentThread()) - 1); - - ResumeThread(_gCdStreamThread); -} - -void -CdStreamInit(int32 numChannels) -{ - DWORD SectorsPerCluster; - DWORD BytesPerSector; - DWORD NumberOfFreeClusters; - DWORD TotalNumberOfClusters; - - GetDiskFreeSpace(nil, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters); - - _gdwCdStreamFlags = 0; - - if ( BytesPerSector <= CDSTREAM_SECTOR_SIZE ) - { - _gdwCdStreamFlags |= FILE_FLAG_NO_BUFFERING; - debug("Using no buffered loading for streaming\n"); - } - - _gbCdStreamOverlapped = TRUE; - - _gdwCdStreamFlags |= FILE_FLAG_OVERLAPPED; - - _gbCdStreamAsync = FALSE; - - void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, BytesPerSector); - ASSERT( pBuffer != nil ); - - SetLastError(0); - - gNumImages = 0; - - gNumChannels = numChannels; - - gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels); - ASSERT( gpReadInfo != nil ); - - CDDEBUG("read info %p", gpReadInfo); - - CdStreamAddImage("MODELS\\GTA3.IMG"); - - int32 nStatus = CdStreamRead(0, pBuffer, 0, 1); - - CdStreamRemoveImages(); - - if ( nStatus == STREAM_SUCCESS ) - { - _gbCdStreamAsync = TRUE; - - debug("Using async loading for streaming\n"); - } - else - { - _gdwCdStreamFlags &= ~FILE_FLAG_OVERLAPPED; - - _gbCdStreamOverlapped = FALSE; - - _gbCdStreamAsync = TRUE; - - debug("Using sync loading for streaming\n"); - } - - CdStreamInitThread(); - - ASSERT( pBuffer != nil ); - RwFreeAlign(pBuffer); -} - -uint32 -GetGTA3ImgSize(void) -{ - ASSERT( gImgFiles[0] != nil ); - return (uint32)GetFileSize(gImgFiles[0], nil); -} - -void -CdStreamShutdown(void) -{ - if ( _gbCdStreamAsync ) - { - LocalFree(gChannelRequestQ.items); - CloseHandle(gCdStreamSema); - CloseHandle(_gCdStreamThread); - - for ( int32 i = 0; i < gNumChannels; i++ ) - CloseHandle(gpReadInfo[i].hSemaphore); - } - - LocalFree(gpReadInfo); -} - - - -int32 -CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) -{ - ASSERT( channel < gNumChannels ); - ASSERT( buffer != nil ); - - lastPosnRead = size + offset; - - ASSERT( _GET_INDEX(offset) < MAX_CDIMAGES ); - HANDLE hImage = gImgFiles[_GET_INDEX(offset)]; - ASSERT( hImage != nil ); - - - CdReadInfo *pChannel = &gpReadInfo[channel]; - ASSERT( pChannel != nil ); - - pChannel->hFile = hImage; - - SetLastError(0); - - if ( _gbCdStreamAsync ) - { - if ( pChannel->nSectorsToRead != 0 || pChannel->bInUse ) - return STREAM_NONE; - - pChannel->nStatus = STREAM_NONE; - pChannel->nSectorOffset = _GET_OFFSET(offset); - pChannel->nSectorsToRead = size; - pChannel->pBuffer = buffer; - pChannel->bLocked = 0; - - AddToQueue(&gChannelRequestQ, channel); - - if ( !ReleaseSemaphore(gCdStreamSema, 1, nil) ) - printf("Signal Sema Error\n"); - - return STREAM_SUCCESS; - } - - if ( _gbCdStreamOverlapped ) - { - ASSERT( channel < gNumChannels ); - CdReadInfo *pChannel = &gpReadInfo[channel]; - ASSERT( pChannel != nil ); - - pChannel->Overlapped.Offset = _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE; - - if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, NULL, &pChannel->Overlapped) - && GetLastError() != ERROR_IO_PENDING ) - return STREAM_NONE; - else - return STREAM_SUCCESS; - } - - SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN); - - DWORD NumberOfBytesRead; - - if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, &NumberOfBytesRead, nil) ) - return STREAM_NONE; - else - return STREAM_SUCCESS; -} - -int32 -CdStreamGetStatus(int32 channel) -{ - ASSERT( channel < gNumChannels ); - CdReadInfo *pChannel = &gpReadInfo[channel]; - ASSERT( pChannel != nil ); - - if ( _gbCdStreamAsync ) - { - if ( pChannel->bInUse ) - return STREAM_READING; - - if ( pChannel->nSectorsToRead != 0 ) - return STREAM_WAITING; - - if ( pChannel->nStatus != STREAM_NONE ) - { - int32 status = pChannel->nStatus; - - pChannel->nStatus = STREAM_NONE; - - return status; - } - - return STREAM_NONE; - } - - if ( _gbCdStreamOverlapped ) - { - ASSERT( pChannel->hFile != nil ); - if ( WaitForSingleObjectEx(pChannel->hFile, 0, TRUE) == WAIT_OBJECT_0 ) - return STREAM_NONE; - else - return STREAM_READING; - } - - return STREAM_NONE; -} - -int32 -CdStreamGetLastPosn(void) -{ - return lastPosnRead; -} - -int32 -CdStreamSync(int32 channel) -{ - ASSERT( channel < gNumChannels ); - CdReadInfo *pChannel = &gpReadInfo[channel]; - ASSERT( pChannel != nil ); - - if ( _gbCdStreamAsync ) - { - if ( pChannel->nSectorsToRead != 0 ) - { - pChannel->bLocked = true; - - ASSERT( pChannel->hSemaphore != nil ); - - WaitForSingleObject(pChannel->hSemaphore, INFINITE); - } - - pChannel->bInUse = false; - - return pChannel->nStatus; - } - - DWORD NumberOfBytesTransferred; - - if ( _gbCdStreamOverlapped && pChannel->hFile ) - { - ASSERT(pChannel->hFile != nil ); - if ( GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) ) - return STREAM_NONE; - else - return STREAM_ERROR; - } - - return STREAM_NONE; -} - -void -AddToQueue(Queue *queue, int32 item) -{ - ASSERT( queue != nil ); - ASSERT( queue->items != nil ); - queue->items[queue->tail] = item; - - queue->tail = (queue->tail + 1) % queue->size; - - if ( queue->head == queue->tail ) - debug("Queue is full\n"); -} - -int32 -GetFirstInQueue(Queue *queue) -{ - ASSERT( queue != nil ); - if ( queue->head == queue->tail ) - return -1; - - ASSERT( queue->items != nil ); - return queue->items[queue->head]; -} - -void -RemoveFirstInQueue(Queue *queue) -{ - ASSERT( queue != nil ); - if ( queue->head == queue->tail ) - { - debug("Queue is empty\n"); - return; - } - - queue->head = (queue->head + 1) % queue->size; -} - -DWORD -WINAPI CdStreamThread(LPVOID lpThreadParameter) -{ - debug("Created cdstream thread\n"); - - while ( true ) - { - WaitForSingleObject(gCdStreamSema, INFINITE); - - int32 channel = GetFirstInQueue(&gChannelRequestQ); - ASSERT( channel < gNumChannels ); - - CdReadInfo *pChannel = &gpReadInfo[channel]; - ASSERT( pChannel != nil ); - - pChannel->bInUse = true; - - if ( pChannel->nStatus == STREAM_NONE ) - { - if ( _gbCdStreamOverlapped ) - { - pChannel->Overlapped.Offset = pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE; - - ASSERT(pChannel->hFile != nil ); - ASSERT(pChannel->pBuffer != nil ); - - DWORD NumberOfBytesTransferred; - - if ( ReadFile(pChannel->hFile, - pChannel->pBuffer, - pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE, - NULL, - &pChannel->Overlapped) ) - { - pChannel->nStatus = STREAM_NONE; - } - else if ( GetLastError() == ERROR_IO_PENDING - && GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) ) - { - pChannel->nStatus = STREAM_NONE; - } - else - { - pChannel->nStatus = STREAM_ERROR; - } - } - else - { - ASSERT(pChannel->hFile != nil ); - ASSERT(pChannel->pBuffer != nil ); - - SetFilePointer(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN); - - DWORD NumberOfBytesRead; - if ( ReadFile(pChannel->hFile, - pChannel->pBuffer, - pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE, - &NumberOfBytesRead, - NULL) ) - { - pChannel->nStatus = STREAM_NONE; - } - } - } - - RemoveFirstInQueue(&gChannelRequestQ); - - pChannel->nSectorsToRead = 0; - - if ( pChannel->bLocked ) - { - ASSERT( pChannel->hSemaphore != nil ); - ReleaseSemaphore(pChannel->hSemaphore, 1, NULL); - } - - pChannel->bInUse = false; - } -} - -bool -CdStreamAddImage(char const *path) -{ - ASSERT(path != nil); - ASSERT(gNumImages < MAX_CDIMAGES); - - SetLastError(0); - - gImgFiles[gNumImages] = CreateFile(path, - GENERIC_READ, - FILE_SHARE_READ, - nil, - OPEN_EXISTING, - _gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY, - nil); - - ASSERT( gImgFiles[gNumImages] != nil ); - if ( gImgFiles[gNumImages] == NULL ) - return false; - - strcpy(gCdImageNames[gNumImages], path); - - gNumImages++; - - return true; -} - -char * -CdStreamGetImageName(int32 cd) -{ - ASSERT(cd < MAX_CDIMAGES); - if ( gImgFiles[cd] != nil ) - return gCdImageNames[cd]; - - return nil; -} - -void -CdStreamRemoveImages(void) -{ - for ( int32 i = 0; i < gNumChannels; i++ ) - CdStreamSync(i); - - for ( int32 i = 0; i < gNumImages; i++ ) - { - SetLastError(0); - - CloseHandle(gImgFiles[i]); - gImgFiles[i] = nil; - } - - gNumImages = 0; -} - -int32 -CdStreamGetNumImages(void) -{ - return gNumImages; -} - - -STARTPATCHES - InjectHook(0x405B50, CdStreamInitThread, PATCH_JUMP); - InjectHook(0x405C80, CdStreamInit, PATCH_JUMP); - //InjectHook(0x405DB0, debug, PATCH_JUMP); - InjectHook(0x405DC0, GetGTA3ImgSize, PATCH_JUMP); - InjectHook(0x405DD0, CdStreamShutdown, PATCH_JUMP); - InjectHook(0x405E40, CdStreamRead, PATCH_JUMP); - InjectHook(0x405F90, CdStreamGetStatus, PATCH_JUMP); - InjectHook(0x406000, CdStreamGetLastPosn, PATCH_JUMP); - InjectHook(0x406010, CdStreamSync, PATCH_JUMP); - InjectHook(0x4060B0, AddToQueue, PATCH_JUMP); - InjectHook(0x4060F0, GetFirstInQueue, PATCH_JUMP); - InjectHook(0x406110, RemoveFirstInQueue, PATCH_JUMP); - InjectHook(0x406140, CdStreamThread, PATCH_JUMP); - InjectHook(0x406270, CdStreamAddImage, PATCH_JUMP); - InjectHook(0x4062E0, CdStreamGetImageName, PATCH_JUMP); - InjectHook(0x406300, CdStreamRemoveImages, PATCH_JUMP); - InjectHook(0x406370, CdStreamGetNumImages, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/CdStream.h b/src/CdStream.h deleted file mode 100644 index 55507aa8..00000000 --- a/src/CdStream.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#define CDSTREAM_SECTOR_SIZE 2048 - -#define _GET_INDEX(a) (a >> 24) -#define _GET_OFFSET(a) (a & 0xFFFFFF) - -enum -{ - STREAM_NONE = uint8( 0), - STREAM_SUCCESS = uint8( 1), - STREAM_READING = uint8(-1), // 0xFF, - STREAM_ERROR = uint8(-2), // 0xFE, - STREAM_ERROR_NOCD = uint8(-3), // 0xFD, - STREAM_ERROR_WRONGCD = uint8(-4), // 0xFC, - STREAM_ERROR_OPENCD = uint8(-5), // 0xFB, - STREAM_WAITING = uint8(-6) // 0xFA, -}; - -struct Queue -{ - int32 *items; - int32 head; - int32 tail; - int32 size; -}; - -VALIDATE_SIZE(Queue, 0x10); - - -void CdStreamInitThread(void); -void CdStreamInit(int32 numChannels); -uint32 GetGTA3ImgSize(void); -void CdStreamShutdown(void); -int32 CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size); -int32 CdStreamGetStatus(int32 channel); -int32 CdStreamGetLastPosn(void); -int32 CdStreamSync(int32 channel); -void AddToQueue(Queue *queue, int32 item); -int32 GetFirstInQueue(Queue *queue); -void RemoveFirstInQueue(Queue *queue); -DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter); -bool CdStreamAddImage(char const *path); -char *CdStreamGetImageName(int32 cd); -void CdStreamRemoveImages(void); -int32 CdStreamGetNumImages(void); \ No newline at end of file diff --git a/src/Clock.cpp b/src/Clock.cpp deleted file mode 100644 index 707b0e57..00000000 --- a/src/Clock.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Timer.h" -#include "Pad.h" -#include "Clock.h" -#include "Stats.h" - -_TODO("gbFastTime"); -bool &gbFastTime = *(bool*)0x95CDBB; - -uint8 &CClock::ms_nGameClockHours = *(uint8*)0x95CDA6; -uint8 &CClock::ms_nGameClockMinutes = *(uint8*)0x95CDC8; -uint16 &CClock::ms_nGameClockSeconds = *(uint16*)0x95CC7C; -uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B; -uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B; -uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C; -uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64; -int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4; -bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82; - -void -CClock::Initialise(uint32 scale) -{ - debug("Initialising CClock...\n"); - ms_nGameClockHours = 12; - ms_nGameClockMinutes = 0; - ms_nGameClockSeconds = 0; - ms_nMillisecondsPerGameMinute = scale; - ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); - ms_bClockHasBeenStored = false; - debug("CClock ready\n"); -} - -void -CClock::Update(void) -{ - if(CPad::GetPad(1)->GetRightShoulder1()) - { - ms_nGameClockMinutes += 8; - ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); - - if(ms_nGameClockMinutes >= 60) - { - ms_nGameClockHours++; - ms_nGameClockMinutes = 0; - if(ms_nGameClockHours >= 24) - ms_nGameClockHours = 0; - } - - } - else if(CTimer::GetTimeInMilliseconds() - ms_nLastClockTick > ms_nMillisecondsPerGameMinute || gbFastTime) - { - ms_nGameClockMinutes++; - ms_nLastClockTick += ms_nMillisecondsPerGameMinute; - - if ( gbFastTime ) - ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); - - if(ms_nGameClockMinutes >= 60) - { - ms_nGameClockHours++; - ms_nGameClockMinutes = 0; - if(ms_nGameClockHours >= 24) - { - CStats::DaysPassed++; - ms_nGameClockHours = 0; - } - } - } - ms_nGameClockSeconds += - 60 - * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) - / ms_nMillisecondsPerGameMinute; -} - -void -CClock::SetGameClock(uint8 h, uint8 m) -{ - ms_nGameClockHours = h; - ms_nGameClockMinutes = m; - ms_nGameClockSeconds = 0; - ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); -} - -int32 -CClock::GetGameClockMinutesUntil(uint8 h, uint8 m) -{ - int32 now, then; - now = ms_nGameClockHours*60 + ms_nGameClockMinutes; - then = h*60 + m; - if(then < now) - then += 24*60; - return then-now; -} - -bool -CClock::GetIsTimeInRange(uint8 h1, uint8 h2) -{ - if(h1 > h2) - return ms_nGameClockHours >= h1 || ms_nGameClockHours < h2; - else - return ms_nGameClockHours >= h1 && ms_nGameClockHours < h2; -} - -void -CClock::StoreClock(void) -{ - ms_Stored_nGameClockHours = ms_nGameClockHours; - ms_Stored_nGameClockMinutes = ms_nGameClockMinutes; - ms_Stored_nGameClockSeconds = ms_nGameClockSeconds; - ms_bClockHasBeenStored = true; -} - -void -CClock::RestoreClock(void) -{ - ms_nGameClockHours = ms_Stored_nGameClockHours; - ms_nGameClockMinutes = ms_Stored_nGameClockMinutes; - ms_nGameClockSeconds = ms_Stored_nGameClockSeconds; -} - - -STARTPATCHES - InjectHook(0x473370, CClock::Initialise, PATCH_JUMP); - InjectHook(0x473460, CClock::Update, PATCH_JUMP); - InjectHook(0x4733C0, CClock::SetGameClock, PATCH_JUMP); - InjectHook(0x4733F0, CClock::GetGameClockMinutesUntil, PATCH_JUMP); - InjectHook(0x473420, CClock::GetIsTimeInRange, PATCH_JUMP); - InjectHook(0x473540, CClock::StoreClock, PATCH_JUMP); - InjectHook(0x473570, CClock::RestoreClock, PATCH_JUMP); -ENDPATCHES diff --git a/src/Clock.h b/src/Clock.h deleted file mode 100644 index e11b2293..00000000 --- a/src/Clock.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -class CClock -{ - static uint8 &ms_nGameClockHours; - static uint8 &ms_nGameClockMinutes; - static uint16 &ms_nGameClockSeconds; - static uint8 &ms_Stored_nGameClockHours; - static uint8 &ms_Stored_nGameClockMinutes; - static uint16 &ms_Stored_nGameClockSeconds; - static uint32 &ms_nMillisecondsPerGameMinute; - static int32 &ms_nLastClockTick; - static bool &ms_bClockHasBeenStored; -public: - - static void Initialise(uint32 scale); - static void Update(void); - static void SetGameClock(uint8 h, uint8 m); - static int32 GetGameClockMinutesUntil(uint8 h, uint8 m); - static bool GetIsTimeInRange(uint8 h1, uint8 h2); - static void StoreClock(void); - static void RestoreClock(void); - - static uint8 GetHours(void) { return ms_nGameClockHours; } - static uint8 GetMinutes(void) { return ms_nGameClockMinutes; } - static int16 GetSeconds(void) { return ms_nGameClockSeconds; } - - - static uint8 &GetHoursRef(void) { return ms_nGameClockHours; } - static uint8 &GetMinutesRef(void) { return ms_nGameClockMinutes; } -}; diff --git a/src/Collision.cpp b/src/Collision.cpp deleted file mode 100644 index 62b27eff..00000000 --- a/src/Collision.cpp +++ /dev/null @@ -1,1887 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Lists.h" -#include "Game.h" -#include "Zones.h" -#include "General.h" -#include "CullZones.h" -#include "World.h" -#include "Entity.h" -#include "Train.h" -#include "Streaming.h" -#include "Pad.h" -#include "DMAudio.h" -#include "Population.h" -#include "FileLoader.h" -#include "Replay.h" -#include "CutsceneMgr.h" -#include "RenderBuffer.h" -#include "SurfaceTable.h" -#include "Collision.h" - -enum Direction -{ - DIR_X_POS, - DIR_X_NEG, - DIR_Y_POS, - DIR_Y_NEG, - DIR_Z_POS, - DIR_Z_NEG, -}; - -eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250; -CLinkList &CCollision::ms_colModelCache = *(CLinkList*)0x95CB58; - -void -CCollision::Init(void) -{ - ms_colModelCache.Init(NUMCOLCACHELINKS); - ms_collisionInMemory = LEVEL_NONE; -} - -void -CCollision::Shutdown(void) -{ - ms_colModelCache.Shutdown(); -} - -void -CCollision::Update(void) -{ - CVector playerCoors; - playerCoors = FindPlayerCoors(); - eLevelName level = CTheZones::m_CurrLevel; - bool forceLevelChange = false; - - if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) - return; - - // hardcode a level if there are no zones - if(level == LEVEL_NONE){ - if(CGame::currLevel == LEVEL_INDUSTRIAL && - playerCoors.x < 400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else if(CGame::currLevel == LEVEL_SUBURBAN && - playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else{ - if(playerCoors.x > 800.0f){ - level = LEVEL_INDUSTRIAL; - forceLevelChange = true; - }else if(playerCoors.x < -800.0f){ - level = LEVEL_SUBURBAN; - forceLevelChange = true; - } - } - } - if(level != LEVEL_NONE && level != CGame::currLevel) - CGame::currLevel = level; - if(ms_collisionInMemory != CGame::currLevel) - LoadCollisionWhenINeedIt(forceLevelChange); - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); -} - -eLevelName -GetCollisionInSectorList(CPtrList &list) -{ - CPtrNode *node; - CEntity *e; - int level; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; - if(level != LEVEL_NONE) - return (eLevelName)level; - } - return LEVEL_NONE; -} - -// Get a level this sector is in based on collision models -eLevelName -GetCollisionInSector(CSector §) -{ - int level; - - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); - if(level == LEVEL_NONE) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - if(level == LEVEL_NONE) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); - if(level == LEVEL_NONE) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); - if(level == LEVEL_NONE) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); - if(level == LEVEL_NONE) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); - return (eLevelName)level; -} - -void -CCollision::LoadCollisionWhenINeedIt(bool forceChange) -{ - eLevelName level, l; - bool multipleLevels; - CVector playerCoors; - CVehicle *veh; - CEntryInfoNode *ei; - int sx, sy; - int xmin, xmax, ymin, ymax; - int x, y; - - level = LEVEL_NONE; - - playerCoors = FindPlayerCoors(); - sx = CWorld::GetSectorIndexX(playerCoors.x); - sy = CWorld::GetSectorIndexY(playerCoors.y); - multipleLevels = false; - - veh = FindPlayerVehicle(); - if(veh && veh->IsTrain()){ - if(((CTrain*)veh)->m_doorState != TRAIN_DOOR_STATE2) - return ; - }else if(playerCoors.z < 4.0f && !CCullZones::DoINeedToLoadCollision()) - return; - - // Figure out whose level's collisions we're most likely to be interested in - if(!forceChange){ - if(veh && veh->IsBoat()){ - // on water we expect to be between levels - multipleLevels = true; - }else{ - xmin = max(sx - 1, 0); - xmax = min(sx + 1, NUMSECTORS_X-1); - ymin = max(sy - 1, 0); - ymax = min(sy + 1, NUMSECTORS_Y-1); - - for(x = xmin; x <= xmax; x++) - for(y = ymin; y <= ymax; y++){ - l = GetCollisionInSector(*CWorld::GetSector(x, y)); - if(l != LEVEL_NONE){ - if(level == LEVEL_NONE) - level = l; - if(level != l) - multipleLevels = true; - } - } - } - - if(multipleLevels && veh && veh->IsBoat()) - for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ - level = GetCollisionInSector(*ei->sector); - if(level != LEVEL_NONE) - break; - } - } - - if(level == CGame::currLevel || forceChange){ - CTimer::Stop(); - DMAudio.SetEffectsFadeVol(0); - CPad::StopPadsShaking(); - LoadCollisionScreen(CGame::currLevel); - DMAudio.Service(); - CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); - CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); - CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); - CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); - CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - CStreaming::RemoveUnusedModelsInLoadedList(); - CGame::TidyUpMemory(true, true); - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); - ms_collisionInMemory = CGame::currLevel; - CReplay::EmptyReplayBuffer(); - if(CGame::currLevel != LEVEL_NONE) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); - CStreaming::RemoveUnusedBuildings(CGame::currLevel); - CStreaming::RequestBigBuildings(CGame::currLevel); - CStreaming::LoadAllRequestedModels(true); - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); - CGame::TidyUpMemory(true, true); - CTimer::Update(); - DMAudio.SetEffectsFadeVol(127); - } -} - -void -CCollision::SortOutCollisionAfterLoad(void) -{ - if(ms_collisionInMemory == CGame::currLevel) - return; - - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - if(CGame::currLevel != LEVEL_NONE){ - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); - if(!CGame::playingIntro) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - } - ms_collisionInMemory = CGame::currLevel; - CGame::TidyUpMemory(true, false); -} - -void -CCollision::LoadCollisionScreen(eLevelName level) -{ - static char *levelNames[4] = { - "", - "IND_ZON", - "COM_ZON", - "SUB_ZON" - }; - - // Why twice? - LoadingIslandScreen(levelNames[level]); - LoadingIslandScreen(levelNames[level]); -} - -// -// Test -// - - -bool -CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) -{ - float d = s1.radius + s2.radius; - return (s1.center - s2.center).MagnitudeSqr() < d*d; -} - -bool -CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) -{ - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - return true; -} - -bool -CCollision::TestLineBox(const CColLine &line, const CColBox &box) -{ - float t, x, y, z; - // If either line point is in the box, we have a collision - if(line.p0.x > box.min.x && line.p0.x < box.max.x && - line.p0.y > box.min.y && line.p0.y < box.max.y && - line.p0.z > box.min.z && line.p0.z < box.max.z) - return true; - if(line.p1.x > box.min.x && line.p1.x < box.max.x && - line.p1.y > box.min.y && line.p1.y < box.max.y && - line.p1.z > box.min.z && line.p1.z < box.max.z) - return true; - - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // same test with max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - return false; -} - -bool -CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) -{ - if(line.p0.x <= box.min.x) return false; - if(line.p0.y <= box.min.y) return false; - if(line.p0.x >= box.max.x) return false; - if(line.p0.y >= box.max.y) return false; - if(line.p0.z < line.p1.z){ - if(line.p0.z > box.max.z) return false; - if(line.p1.z < box.min.z) return false; - }else{ - if(line.p1.z > box.max.z) return false; - if(line.p0.z < box.min.z) return false; - } - return true; -} - -bool -CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - const CVector &va = verts[tri.a]; - const CVector &vb = verts[tri.b]; - const CVector &vc = verts[tri.c]; - CVector2D vec1, vec2, vec3, vect; - - // We do the test in 2D. With the plane direction we - // can figure out how to project the vectors. - // normal = (c-a) x (b-a) - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - // This is our triangle: - // 3-------2 - // \ P / - // \ / - // \ / - // 1 - // We can use the "2d cross product" to check on which side - // a vector is of another. Test is true if point is inside of all edges. - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - return true; -} - -// Test if line segment intersects with sphere. -// If the first point is inside the sphere this test does not register a collision! -// The code is reversed from the original code and rather ugly, see Process for a clear version. -// TODO: actually rewrite this mess -bool -CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) -{ - CVector v01 = line.p1 - line.p0; // vector from p0 to p1 - CVector v0c = sph.center - line.p0; // vector from p0 to center - float linesq = v01.MagnitudeSqr(); - // I leave in the strange -2 factors even though they serve no real purpose - float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line - // Square of tangent from p0 multiplied by line length so we can compare with projline. - // The length of the tangent would be this: sqrt((c-p0)^2 - r^2). - // Negative if p0 is inside the sphere! This breaks the test! - float tansq = 4.0f * linesq * - (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); - float diffsq = projline*projline - tansq; - // if diffsq < 0 that means the line is a passant, so no intersection - if(diffsq < 0.0f) - return false; - // projline (negative in GTA for some reason) is the point on the line - // in the middle of the two intersection points (startin from p0). - // sqrt(diffsq) somehow works out to be the distance from that - // midpoint to the intersection points. - // So subtract that and get rid of the awkward scaling: - float f = (-projline - sqrt(diffsq)) / (2.0f*linesq); - // f should now be in range [0, 1] for [p0, p1] - return f >= 0.0f && f <= 1.0f; -} - -bool -CCollision::TestSphereTriangle(const CColSphere &sphere, - const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ - // If sphere and plane don't intersect, no collision - if(fabs(plane.CalcPoint(sphere.center)) > sphere.radius) - return false; - - const CVector &va = verts[tri.a]; - const CVector &vb = verts[tri.b]; - const CVector &vc = verts[tri.c]; - - // calculate two orthogonal basis vectors for the triangle - CVector vec2 = vb - va; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector vec1 = CrossProduct(vec2, plane.normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - if(testcase == 1){ - // closest to a vertex - if(insideAB) dist = (sphere.center - vc).Magnitude(); - else if(insideAC) dist = (sphere.center - vb).Magnitude(); - else if(insideBC) dist = (sphere.center - va).Magnitude(); - else assert(0); - }else if(testcase == 2){ - // closest to an edge - if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); - else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); - else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); - else assert(0); - }else if(testcase == 3){ - // center is in triangle - return true; - }else - assert(0); // front fell off - - return dist < sphere.radius; -} - -bool -CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) -{ - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - for(i = 0; i < model.numSpheres; i++) - if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) - if(TestLineSphere(newline, model.spheres[i])) - return true; - - for(i = 0; i < model.numBoxes; i++) - if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) - if(TestLineBox(newline, model.boxes[i])) - return true; - - CalculateTrianglePlanes(&model); - for(i = 0; i < model.numTriangles; i++) - if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) - if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) - return true; - - return false; -} - - -// -// Process -// - -// For Spheres mindist is the squared distance to its center -// For Lines mindist is between [0,1] - -bool -CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) -{ - CVector dist = s1.center - s2.center; - float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 - float dc = d < 0.0f ? 0.0f : d; // clamp to zero, i.e. if s1's center is inside s2 - // no collision if sphere is not close enough - if(mindistsq <= dc*dc || s1.radius <= dc) - return false; - dist.Normalise(); - point.point = s1.center - dist*dc; - point.normal = dist; - point.surfaceA = s1.surface; - point.pieceA = s1.piece; - point.surfaceB = s2.surface; - point.pieceB = s2.piece; - point.depth = s1.radius - d; // sphere overlap - mindistsq = dc*dc; // collision radius - return true; -} - -bool -CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) -{ - CVector p; - CVector dist; - - // GTA's code is too complicated, uses a huge 3x3x3 if statement - // we can simplify the structure a lot - - // first make sure we have a collision at all - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - - // Now find out where the sphere center lies in relation to all the sides - int xpos = sph.center.x < box.min.x ? 1 : - sph.center.x > box.max.x ? 2 : - 0; - int ypos = sph.center.y < box.min.y ? 1 : - sph.center.y > box.max.y ? 2 : - 0; - int zpos = sph.center.z < box.min.z ? 1 : - sph.center.z > box.max.z ? 2 : - 0; - - if(xpos == 0 && ypos == 0 && zpos == 0){ - // sphere is inside the box - p = (box.min + box.max)*0.5f; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - point.normal = dist * (1.0f/sqrt(lensq)); - point.point = sph.center - point.normal; - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; - - // find absolute distance to the closer side in each dimension - float dx = dist.x > 0.0f ? - box.max.x - sph.center.x : - sph.center.x - box.min.x; - float dy = dist.y > 0.0f ? - box.max.y - sph.center.y : - sph.center.y - box.min.y; - float dz = dist.z > 0.0f ? - box.max.z - sph.center.z : - sph.center.z - box.min.z; - // collision depth is maximum of that: - if(dx > dy && dx > dz) - point.depth = dx; - else if(dy > dz) - point.depth = dy; - else - point.depth = dz; - return true; - } - }else{ - // sphere is outside. - // closest point on box: - p.x = xpos == 1 ? box.min.x : - xpos == 2 ? box.max.x : - sph.center.x; - p.y = ypos == 1 ? box.min.y : - ypos == 2 ? box.max.y : - sph.center.y; - p.z = zpos == 1 ? box.min.z : - zpos == 2 ? box.max.z : - sph.center.z; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - float len = sqrt(lensq); - point.point = p; - point.normal = dist * (1.0f/len); - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; - point.depth = sph.radius - len; - mindistsq = lensq; - return true; - } - } - return false; -} - -bool -CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) -{ - float mint, t, x, y, z; - CVector normal; - CVector p; - - mint = 1.0f; - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.min.x, y, z); - normal = CVector(-1.0f, 0.0f, 0.0f); - } - } - } - - // max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.max.x, y, z); - normal = CVector(1.0f, 0.0f, 0.0f); - } - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.min.y, z); - normal = CVector(0.0f, -1.0f, 0.0f); - } - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.max.y, z); - normal = CVector(0.0f, 1.0f, 0.0f); - } - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.min.z); - normal = CVector(0.0f, 0.0f, -1.0f); - } - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.max.z); - normal = CVector(0.0f, 0.0f, 1.0f); - } - } - } - - if(mint >= mindist) - return false; - - point.point = p; - point.normal = normal; - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = box.surface; - point.pieceB = box.piece; - mindist = mint; - - return true; -} - -// If line.p0 lies inside sphere, no collision is registered. -bool -CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) -{ - CVector v01 = line.p1 - line.p0; - CVector v0c = sphere.center - line.p0; - float linesq = v01.MagnitudeSqr(); - // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections - float projline = DotProduct(v01, v0c); - // tangent of p0 to sphere, scaled by linesq just like projline^2 - float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; - // this works out to be the square of the distance between the midpoint and the intersections - float diffsq = projline*projline - tansq; - // no intersection - if(diffsq < 0.0f) - return false; - // point of first intersection, in range [0,1] between p0 and p1 - float t = (projline - sqrt(diffsq)) / linesq; - // if not on line or beyond mindist, no intersection - if(t < 0.0f || t > 1.0f || t >= mindist) - return false; - point.point = line.p0 + v01*t; - point.normal = point.point - sphere.center; - point.normal.Normalise(); - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = sphere.surface; - point.pieceB = sphere.piece; - mindist = t; - return true; -} - -bool -CCollision::ProcessVerticalLineTriangle(const CColLine &line, - const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist, CStoredCollPoly *poly) -{ - float t; - CVector normal; - - const CVector &p0 = line.p0; - const CVector &va = verts[tri.a]; - const CVector &vb = verts[tri.b]; - const CVector &vc = verts[tri.c]; - - // early out bound rect test - if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; - if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; - if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; - if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; - - plane.GetNormal(normal); - // if points are on the same side, no collision - if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - float h = (line.p1 - p0).z; - t = -plane.CalcPoint(p0) / (h * normal.z); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - CVector p(p0.x, p0.y, p0.z + h*t); - - CVector2D vec1, vec2, vec3, vect; - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - point.point = p; - point.normal = normal; - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = tri.surface; - point.pieceB = 0; - if(poly){ - poly->verts[0] = va; - poly->verts[1] = vb; - poly->verts[2] = vc; - poly->valid = true; - } - mindist = t; - return true; -} - -bool -CCollision::ProcessLineTriangle(const CColLine &line , - const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist) -{ - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - const CVector &va = verts[tri.a]; - const CVector &vb = verts[tri.b]; - const CVector &vc = verts[tri.c]; - CVector2D vec1, vec2, vec3, vect; - - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - point.point = p; - point.normal = normal; - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = tri.surface; - point.pieceB = 0; - mindist = t; - return true; -} - -bool -CCollision::ProcessSphereTriangle(const CColSphere &sphere, - const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindistsq) -{ - // If sphere and plane don't intersect, no collision - float planedist = plane.CalcPoint(sphere.center); - float distsq = planedist*planedist; - if(fabs(planedist) > sphere.radius || distsq > mindistsq) - return false; - - const CVector &va = verts[tri.a]; - const CVector &vb = verts[tri.b]; - const CVector &vc = verts[tri.c]; - - // calculate two orthogonal basis vectors for the triangle - CVector normal; - plane.GetNormal(normal); - CVector vec2 = vb - va; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector vec1 = CrossProduct(vec2, normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - CVector p; - if(testcase == 1){ - // closest to a vertex - if(insideAB) p = vc; - else if(insideAC) p = vb; - else if(insideBC) p = va; - else assert(0); - dist = (sphere.center - p).Magnitude(); - }else if(testcase == 2){ - // closest to an edge - if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); - else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); - else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); - else assert(0); - }else if(testcase == 3){ - // center is in triangle - dist = fabs(planedist); - p = sphere.center - normal*planedist; - }else - assert(0); // front fell off - - if(dist >= sphere.radius || dist*dist >= mindistsq) - return false; - - point.point = p; - point.normal = sphere.center - p; - point.normal.Normalise(); - point.surfaceA = sphere.surface; - point.pieceA = sphere.piece; - point.surfaceB = tri.surface; - point.pieceB = 0; - point.depth = sphere.radius - dist; - mindistsq = dist*dist; - return true; -} - -bool -CCollision::ProcessLineOfSight(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough) -{ - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - float coldist = mindist; - for(i = 0; i < model.numSpheres; i++) - if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) - ProcessLineSphere(newline, model.spheres[i], point, coldist); - - for(i = 0; i < model.numBoxes; i++) - if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) - ProcessLineBox(newline, model.boxes[i], point, coldist); - - CalculateTrianglePlanes(&model); - for(i = 0; i < model.numTriangles; i++) - if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) - ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); - - if(coldist < mindist){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - mindist = coldist; - return true; - } - return false; -} - -bool -CCollision::ProcessVerticalLine(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ - static CStoredCollPoly TempStoredPoly; - int i; - - // transform line to model space - // Why does the game seem to do this differently than above? - CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); - newline.p1.x = newline.p0.x; - newline.p1.y = newline.p0.y; - - if(!TestVerticalLineBox(newline, model.boundingBox)) - return false; - - float coldist = mindist; - for(i = 0; i < model.numSpheres; i++) - if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) - ProcessLineSphere(newline, model.spheres[i], point, coldist); - - for(i = 0; i < model.numBoxes; i++) - if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) - ProcessLineBox(newline, model.boxes[i], point, coldist); - - CalculateTrianglePlanes(&model); - TempStoredPoly.valid = false; - for(i = 0; i < model.numTriangles; i++) - if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) - ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); - - if(coldist < mindist){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - if(poly && TempStoredPoly.valid){ - *poly = TempStoredPoly; - poly->verts[0] = matrix * poly->verts[0]; - poly->verts[1] = matrix * poly->verts[1]; - poly->verts[2] = matrix * poly->verts[2]; - } - mindist = coldist; - return true; - } - return false; -} - -enum { - MAXNUMSPHERES = 128, - MAXNUMBOXES = 32, - MAXNUMLINES = 16, - MAXNUMTRIS = 600 -}; - -// This checks model A's spheres and lines against model B's spheres, boxes and triangles. -// Returns the number of A's spheres that collide. -// Returned ColPoints are in world space. -// NB: lines do not seem to be supported very well, use with caution -int32 -CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, - const CMatrix &matrixB, CColModel &modelB, - CColPoint *spherepoints, CColPoint *linepoints, float *linedists) -{ - static int aSphereIndicesA[MAXNUMSPHERES]; - static int aLineIndicesA[MAXNUMLINES]; - static int aSphereIndicesB[MAXNUMSPHERES]; - static int aBoxIndicesB[MAXNUMBOXES]; - static int aTriangleIndicesB[MAXNUMTRIS]; - static bool aCollided[MAXNUMLINES]; - static CColSphere aSpheresA[MAXNUMSPHERES]; - static CColLine aLinesA[MAXNUMLINES]; - static CMatrix matAB, matBA; - CColSphere s; - int i, j; - - assert(modelA.numSpheres <= MAXNUMSPHERES); - assert(modelA.numLines <= MAXNUMLINES); - - // From model A space to model B space - matAB = Invert(matrixB, matAB) * matrixA; - - CColSphere bsphereAB; // bounding sphere of A in B space - bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); - if(!TestSphereBox(bsphereAB, modelB.boundingBox)) - return 0; - // B to A space - matBA = Invert(matrixA, matBA) * matrixB; - - // transform modelA's spheres and lines to B space - for(i = 0; i < modelA.numSpheres; i++){ - CColSphere &s = modelA.spheres[i]; - aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); - } - for(i = 0; i < modelA.numLines; i++) - aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); - - // Test them against model B's bounding volumes - int numSpheresA = 0; - int numLinesA = 0; - for(i = 0; i < modelA.numSpheres; i++) - if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) - aSphereIndicesA[numSpheresA++] = i; - // no actual check??? - for(i = 0; i < modelA.numLines; i++) - aLineIndicesA[numLinesA++] = i; - // No collision - if(numSpheresA == 0 && numLinesA == 0) - return 0; - - // Check model B against A's bounding volumes - int numSpheresB = 0; - int numBoxesB = 0; - int numTrianglesB = 0; - for(i = 0; i < modelB.numSpheres; i++){ - s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); - if(TestSphereBox(s, modelA.boundingBox)) - aSphereIndicesB[numSpheresB++] = i; - } - for(i = 0; i < modelB.numBoxes; i++) - if(TestSphereBox(bsphereAB, modelB.boxes[i])) - aBoxIndicesB[numBoxesB++] = i; - CalculateTrianglePlanes(&modelB); - for(i = 0; i < modelB.numTriangles; i++) - if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) - aTriangleIndicesB[numTrianglesB++] = i; - assert(numSpheresB <= MAXNUMSPHERES); - assert(numBoxesB <= MAXNUMBOXES); - assert(numTrianglesB <= MAXNUMTRIS); - // No collision - if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) - return 0; - - // We now have the collision volumes in A and B that are worth processing. - - // Process A's spheres against B's collision volumes - int numCollisions = 0; - for(i = 0; i < numSpheresA; i++){ - float coldist = 1.0e24f; - bool hasCollided = false; - - for(j = 0; j < numSpheresB; j++) - hasCollided |= ProcessSphereSphere( - aSpheresA[aSphereIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numBoxesB; j++) - hasCollided |= ProcessSphereBox( - aSpheresA[aSphereIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numTrianglesB; j++) - hasCollided |= ProcessSphereTriangle( - aSpheresA[aSphereIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - spherepoints[numCollisions], coldist); - if(hasCollided) - numCollisions++; - } - for(i = 0; i < numCollisions; i++){ - spherepoints[i].point = matrixB * spherepoints[i].point; - spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); - } - - // And the same thing for the lines in A - for(i = 0; i < numLinesA; i++){ - aCollided[i] = false; - - for(j = 0; j < numSpheresB; j++) - aCollided[i] |= ProcessLineSphere( - aLinesA[aLineIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numBoxesB; j++) - aCollided[i] |= ProcessLineBox( - aLinesA[aLineIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numTrianglesB; j++) - aCollided[i] |= ProcessLineTriangle( - aLinesA[aLineIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - } - for(i = 0; i < numLinesA; i++) - if(aCollided[i]){ - j = aLineIndicesA[i]; - linepoints[j].point = matrixB * linepoints[j].point; - linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); - } - - return numCollisions; // sphere collisions -} - - -// -// Misc -// - -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // Between 0 and len we're above the line. - // if not, calculate distance to endpoint - if(dot <= 0.0f) - return (*point - *l0).Magnitude(); - if(dot >= lensq) - return (*point - *l1).Magnitude(); - // distance to line - return sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); -} - -// same as above but also return the point on the line -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // find out which point we're closest to - if(dot <= 0.0f) - closest = *l0; - else if(dot >= lensq) - closest = *l1; - else - closest = *l0 + (*l1 - *l0)*(dot/lensq); - // this is the distance - return (*point - closest).Magnitude(); -} - -void -CCollision::CalculateTrianglePlanes(CColModel *model) -{ - if(model->numTriangles == 0) - return; - - CLink *lptr; - if(model->trianglePlanes){ - // re-insert at front so it's not removed again soon - lptr = model->GetLinkPtr(); - lptr->Remove(); - ms_colModelCache.head.Insert(lptr); - }else{ - assert(model); - lptr = ms_colModelCache.Insert(model); - if(lptr == nil){ - // make room if we have to, remove last in list - lptr = ms_colModelCache.tail.prev; - assert(lptr); - assert(lptr->item); - lptr->item->RemoveTrianglePlanes(); - ms_colModelCache.Remove(lptr); - // now this cannot fail - lptr = ms_colModelCache.Insert(model); - assert(lptr); - } - model->CalculateTrianglePlanes(); - model->SetLinkPtr(lptr); - } -} - -void -CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) -{ -} - -void -CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) -{ - int i; - int s; - float f; - CVector verts[8]; - CVector min, max; - int r, g, b; - RwImVertexIndex *iptr; - RwIm3DVertex *vptr; - - RenderBuffer::ClearRenderBuffer(); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); -extern int gDbgSurf; - - for(i = 0; i < colModel.numTriangles; i++){ - colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); - colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); - colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - verts[2] = mat * verts[2]; - - // TODO: surface - r = 255; - g = 128; - b = 0; - - s = colModel.triangles[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - // TODO: make some surface types flicker? -//if(s != gDbgSurf) continue; - - if(s > SURFACE_32){ - r = CGeneral::GetRandomNumber(); - g = CGeneral::GetRandomNumber(); - b = CGeneral::GetRandomNumber(); - printf("Illegal surfacetype:%d on MI:%d\n", s, id); - } - - RenderBuffer::StartStoring(6, 3, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; - RenderBuffer::StopStoring(); - } - - for(i = 0; i < colModel.numBoxes; i++){ - min = colModel.boxes[i].min; - max = colModel.boxes[i].max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - s = colModel.boxes[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - // TODO: make some surface types flicker? -//if(s != gDbgSurf) continue; - - RenderBuffer::StartStoring(36, 8, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetU(&vptr[3], 0.0f); - RwIm3DVertexSetV(&vptr[3], 0.0f); - RwIm3DVertexSetU(&vptr[4], 0.0f); - RwIm3DVertexSetV(&vptr[4], 1.0f); - RwIm3DVertexSetU(&vptr[5], 1.0f); - RwIm3DVertexSetV(&vptr[5], 1.0f); - RwIm3DVertexSetU(&vptr[6], 0.0f); - RwIm3DVertexSetV(&vptr[6], 1.0f); - RwIm3DVertexSetU(&vptr[7], 1.0f); - RwIm3DVertexSetV(&vptr[7], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); - RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); - RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); - RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); - RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; - iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; - iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; - iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; - iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; - iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; - iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; - iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; - iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; - iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; - iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; - RenderBuffer::StopStoring(); - } - - RenderBuffer::RenderStuffInBuffer(); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - - -/* - * ColModel code - */ - -void -CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) -{ - this->radius = radius; - this->center = center; - this->surface = surf; - this->piece = piece; -} - -void -CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) -{ - this->min = min; - this->max = max; - this->surface = surf; - this->piece = piece; -} - -void -CColLine::Set(const CVector &p0, const CVector &p1) -{ - this->p0 = p0; - this->p1 = p1; -} - -void -CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece) -{ - this->a = a; - this->b = b; - this->c = c; - this->surface = surf; -} - -void -CColTrianglePlane::Set(const CVector *v, CColTriangle &tri) -{ - const CVector &va = v[tri.a]; - const CVector &vb = v[tri.b]; - const CVector &vc = v[tri.c]; - - normal = CrossProduct(vc-va, vb-va); - normal.Normalise(); - dist = DotProduct(normal, va); - CVector an(fabs(normal.x), fabs(normal.y), fabs(normal.z)); - // find out largest component and its direction - if(an.x > an.y && an.x > an.z) - dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; - else if(an.y > an.z) - dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; - else - dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; -} - -CColModel::CColModel(void) -{ - numSpheres = 0; - spheres = nil; - numLines = 0; - lines = nil; - numBoxes = 0; - boxes = nil; - numTriangles = 0; - vertices = nil; - triangles = nil; - trianglePlanes = nil; - level = CGame::currLevel; - ownsCollisionVolumes = true; -} - -CColModel::~CColModel(void) -{ - RemoveCollisionVolumes(); - RemoveTrianglePlanes(); -} - -void -CColModel::RemoveCollisionVolumes(void) -{ - if(ownsCollisionVolumes){ - RwFree(spheres); - RwFree(lines); - RwFree(boxes); - RwFree(vertices); - RwFree(triangles); - } - numSpheres = 0; - numLines = 0; - numBoxes = 0; - numTriangles = 0; - spheres = nil; - lines = nil; - boxes = nil; - vertices = nil; - triangles = nil; -} - -void -CColModel::CalculateTrianglePlanes(void) -{ - // HACK: allocate space for one more element to stuff the link pointer into - trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); - for(int i = 0; i < numTriangles; i++) - trianglePlanes[i].Set(vertices, triangles[i]); -} - -void -CColModel::RemoveTrianglePlanes(void) -{ - RwFree(trianglePlanes); - trianglePlanes = nil; -} - -void -CColModel::SetLinkPtr(CLink *lptr) -{ - assert(trianglePlanes); - *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; -} - -CLink* -CColModel::GetLinkPtr(void) -{ - assert(trianglePlanes); - return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); -} - -void -CColModel::GetTrianglePoint(CVector &v, int i) const -{ - v = vertices[i]; -} - -CColModel& -CColModel::operator=(const CColModel &other) -{ - int i; - int numVerts; - - boundingSphere = other.boundingSphere; - boundingBox = other.boundingBox; - - // copy spheres - if(other.numSpheres){ - if(numSpheres != other.numSpheres){ - numSpheres = other.numSpheres; - if(spheres) - RwFree(spheres); - spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); - } - for(i = 0; i < numSpheres; i++) - spheres[i] = other.spheres[i]; - }else{ - numSpheres = 0; - if(spheres) - RwFree(spheres); - spheres = nil; - } - - // copy lines - if(other.numLines){ - if(numLines != other.numLines){ - numLines = other.numLines; - if(lines) - RwFree(lines); - lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); - } - for(i = 0; i < numLines; i++) - lines[i] = other.lines[i]; - }else{ - numLines = 0; - if(lines) - RwFree(lines); - lines = nil; - } - - // copy boxes - if(other.numBoxes){ - if(numBoxes != other.numBoxes){ - numBoxes = other.numBoxes; - if(boxes) - RwFree(boxes); - boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); - } - for(i = 0; i < numBoxes; i++) - boxes[i] = other.boxes[i]; - }else{ - numBoxes = 0; - if(boxes) - RwFree(boxes); - boxes = nil; - } - - // copy mesh - if(other.numTriangles){ - // copy vertices - numVerts = 0; - for(i = 0; i < other.numTriangles; i++){ - if(other.triangles[i].a > numVerts) - other.triangles[i].a = numVerts; - if(other.triangles[i].b > numVerts) - other.triangles[i].b = numVerts; - if(other.triangles[i].c > numVerts) - other.triangles[i].c = numVerts; - } - numVerts++; - if(vertices) - RwFree(vertices); - if(numVerts){ - vertices = (CVector*)RwMalloc(numVerts*sizeof(CVector)); - for(i = 0; i < numVerts; i++) - vertices[i] = other.vertices[i]; - } - - // copy triangles - if(numTriangles != other.numTriangles){ - numTriangles = other.numTriangles; - if(triangles) - RwFree(triangles); - triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); - } - for(i = 0; i < numTriangles; i++) - triangles[i] = other.triangles[i]; - }else{ - numTriangles = 0; - if(triangles) - RwFree(triangles); - triangles = nil; - if(vertices) - RwFree(vertices); - vertices = nil; - } - return *this; -} - -STARTPATCHES - InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP); - - InjectHook(0x40B380, CCollision::Init, PATCH_JUMP); - InjectHook(0x40B3A0, CCollision::Shutdown, PATCH_JUMP); - InjectHook(0x40B3B0, CCollision::Update, PATCH_JUMP); - InjectHook(0x40B5B0, CCollision::LoadCollisionWhenINeedIt, PATCH_JUMP); - InjectHook(0x40B900, CCollision::SortOutCollisionAfterLoad, PATCH_JUMP); - - InjectHook(0x40BB70, CCollision::TestSphereBox, PATCH_JUMP); - InjectHook(0x40E130, CCollision::TestLineBox, PATCH_JUMP); - InjectHook(0x40E5C0, CCollision::TestVerticalLineBox, PATCH_JUMP); - InjectHook(0x40EC10, CCollision::TestLineTriangle, PATCH_JUMP); - InjectHook(0x40DAA0, CCollision::TestLineSphere, PATCH_JUMP); - InjectHook(0x40C580, CCollision::TestSphereTriangle, PATCH_JUMP); - InjectHook(0x40F720, CCollision::TestLineOfSight, PATCH_JUMP); - - InjectHook(0x40B9F0, CCollision::ProcessSphereSphere, PATCH_JUMP); - InjectHook(0x40BC00, CCollision::ProcessSphereBox, PATCH_JUMP); - InjectHook(0x40E670, CCollision::ProcessLineBox, PATCH_JUMP); - InjectHook(0x40DE80, CCollision::ProcessLineSphere, PATCH_JUMP); - InjectHook(0x40FB50, CCollision::ProcessVerticalLineTriangle, PATCH_JUMP); - InjectHook(0x40F140, CCollision::ProcessLineTriangle, PATCH_JUMP); - InjectHook(0x40CE30, CCollision::ProcessSphereTriangle, PATCH_JUMP); - - InjectHook(0x40F910, CCollision::ProcessLineOfSight, PATCH_JUMP); - InjectHook(0x410120, CCollision::ProcessVerticalLine, PATCH_JUMP); - InjectHook(0x410BE0, CCollision::ProcessColModels, PATCH_JUMP); - - InjectHook(0x40B960, CCollision::CalculateTrianglePlanes, PATCH_JUMP); - InjectHook(0x411640, &CLink::Remove, PATCH_JUMP); - InjectHook(0x411620, &CLink::Insert, PATCH_JUMP); - InjectHook(0x4115C0, &CLinkList::Insert, PATCH_JUMP); - InjectHook(0x411600, &CLinkList::Remove, PATCH_JUMP); -// InjectHook(0x411530, &CLinkList::Init, PATCH_JUMP); - - InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP); - InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP); - InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP); - InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP); - InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP); - - InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP); - InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP); - - InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP); - InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP); - InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP); - InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP); - InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP); - InjectHook(0x411D40, &CColModel::SetLinkPtr, PATCH_JUMP); - InjectHook(0x411D60, &CColModel::GetLinkPtr, PATCH_JUMP); -ENDPATCHES diff --git a/src/Collision.h b/src/Collision.h deleted file mode 100644 index 5a9058d3..00000000 --- a/src/Collision.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include "templates.h" -#include "Game.h" // for eLevelName - -struct CColSphere -{ - CVector center; - float radius; - uint8 surface; - uint8 piece; - - void Set(float radius, const CVector ¢er, uint8 surf, uint8 piece); - void Set(float radius, const CVector ¢er) { this->center = center; this->radius = radius; } -}; - -struct CColBox -{ - CVector min; - CVector max; - uint8 surface; - uint8 piece; - - void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece); - CVector GetSize(void) { return max - min; } -}; - -struct CColLine -{ - CVector p0; - int pad0; - CVector p1; - int pad1; - - CColLine(void) { }; - CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; - void Set(const CVector &p0, const CVector &p1); - - CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); } -}; - -struct CColTriangle -{ - uint16 a; - uint16 b; - uint16 c; - uint8 surface; - - void Set(const CVector *v, int a, int b, int c, uint8 surf, uint8 piece); -}; - -struct CColTrianglePlane -{ - CVector normal; - float dist; - uint8 dir; - - void Set(const CVector *v, CColTriangle &tri); - void GetNormal(CVector &n) const { n = normal; } - float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; -}; - -struct CColPoint -{ - CVector point; - int pad1; - // the surface normal on the surface of point - CVector normal; - int pad2; - uint8 surfaceA; - uint8 pieceA; - uint8 surfaceB; - uint8 pieceB; - float depth; -}; - -struct CStoredCollPoly -{ - CVector verts[3]; - bool valid; -}; - -struct CColModel -{ - CColSphere boundingSphere; - CColBox boundingBox; - short numSpheres; - short numLines; - short numBoxes; - short numTriangles; - int level; - bool ownsCollisionVolumes; - CColSphere *spheres; - CColLine *lines; - CColBox *boxes; - CVector *vertices; - CColTriangle *triangles; - CColTrianglePlane *trianglePlanes; - - CColModel(void); - ~CColModel(void); - void RemoveCollisionVolumes(void); - void CalculateTrianglePlanes(void); - void RemoveTrianglePlanes(void); - CLink *GetLinkPtr(void); - void SetLinkPtr(CLink*); - void GetTrianglePoint(CVector &v, int i) const; - - CColModel *ctor(void) { return ::new (this) CColModel(); } - void dtor(void) { this->CColModel::~CColModel(); } - CColModel& operator=(const CColModel& other); -}; - -class CCollision -{ -public: - static eLevelName &ms_collisionInMemory; - static CLinkList &ms_colModelCache; - - static void Init(void); - static void Shutdown(void); - static void Update(void); - static void LoadCollisionWhenINeedIt(bool changeLevel); - static void SortOutCollisionAfterLoad(void); - static void LoadCollisionScreen(eLevelName level); - static void DrawColModel(const CMatrix &mat, const CColModel &colModel); - static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); - - static void CalculateTrianglePlanes(CColModel *model); - - // all these return true if there's a collision - static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); - static bool TestSphereBox(const CColSphere &sph, const CColBox &box); - static bool TestLineBox(const CColLine &line, const CColBox &box); - static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); - static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineSphere(const CColLine &line, const CColSphere &sph); - static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); - - static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); - static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); - static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); - static bool ProcessVerticalLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); - static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); - static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); - static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); - static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); - static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); - static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists); - - // TODO: - // CCollision::IsStoredPolyStillValidVerticalLine - - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); -}; diff --git a/src/ControllerConfig.cpp b/src/ControllerConfig.cpp deleted file mode 100644 index d7567ac4..00000000 --- a/src/ControllerConfig.cpp +++ /dev/null @@ -1,57 +0,0 @@ - #define DIRECTINPUT_VERSION 0x0800 - #include -#include "common.h" -#include "patcher.h" -#include "ControllerConfig.h" -#include "Pad.h" -#include "FileMgr.h" - -CControllerConfigManager &ControlsManager = *(CControllerConfigManager*)0x8F43A4; - -WRAPPER void CControllerConfigManager::UpdateJoyButtonState(int padnumber) { EAXJMP(0x58F5B0); } -WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber) { EAXJMP(0x58C5E0); } -WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonDown(int button, eControllerType type) { EAXJMP(0x58C730); } -WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber) { EAXJMP(0x58CE80); } -WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonUp(int button, int padnumber) { EAXJMP(0x58CFD0); } -WRAPPER void CControllerConfigManager::MakeControllerActionsBlank() { EAXJMP(0x58B7A0); } -WRAPPER void CControllerConfigManager::InitDefaultControlConfiguration() { EAXJMP(0x58B930); } -WRAPPER void CControllerConfigManager::InitDefaultControlConfigMouse(CMouseControllerState const &mousestate) { EAXJMP(0x58BD00); } -WRAPPER int32 CControllerConfigManager::GetJoyButtonJustDown() { EAXJMP(0x58B7D0); } -WRAPPER void CControllerConfigManager::InitDefaultControlConfigJoyPad(unsigned int buttons) { EAXJMP(0x58BD90); } -WRAPPER void CControllerConfigManager::ClearSimButtonPressCheckers() { EAXJMP(0x58D220); } -WRAPPER void CControllerConfigManager::AffectPadFromKeyBoard() { EAXJMP(0x58D0C0); } -WRAPPER void CControllerConfigManager::AffectPadFromMouse() { EAXJMP(0x58D1A0); } - -void CControllerConfigManager::LoadSettings(int32 file) -{ - bool bValid = true; - - if ( file ) - { - char buff[29]; - CFileMgr::Read(file, buff, sizeof(buff)); - - if ( !strncmp(buff, "THIS FILE IS NOT VALID YET", sizeof(buff) - 3) ) - bValid = false; - else - CFileMgr::Seek(file, 0, 0); - } - - if ( bValid ) - { - ControlsManager.MakeControllerActionsBlank(); - - for ( int i = 0; i < 4; i++ ) - { - for ( int j = 0; j < 41; j++ ) - { - CFileMgr::Read(file, (char *)&ControlsManager.m_aSettings[j][i], sizeof(tControllerConfigBind)); - } - } - } -} - -WRAPPER void CControllerConfigManager::SaveSettings(int32 file) -{ - EAXJMP(0x58B800); -} diff --git a/src/ControllerConfig.h b/src/ControllerConfig.h deleted file mode 100644 index 581efe05..00000000 --- a/src/ControllerConfig.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - - -// based on x-gtasa - -enum eControllerType -{ - KEYBOARD, - OPTIONAL_EXTRA, - MOUSE, - JOYSTICK, -}; - -class CMouseControllerState; - -class CControllerConfigManager -{ -public: - struct tControllerConfigBind - { - RsKeyCodes m_Key; - int32 m_ContSetOrder; - }; - - bool field_0; - char _pad0[3]; - DIJOYSTATE2 m_OldState; - DIJOYSTATE2 m_NewState; - wchar m_aActionNames[41][40]; - bool m_aButtonStates[17]; - char _pad1[3]; - tControllerConfigBind m_aSettings[41][4]; - uint8 m_aSimCheckers[4][4]; - bool m_bMouseAssociated; - char _pad2[3]; - - void UpdateJoyButtonState(int padnumber); - void UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber); - void AffectControllerStateOn_ButtonDown(int button, eControllerType type); - void UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber); - void AffectControllerStateOn_ButtonUp(int button, int padnumber); - - int32 GetJoyButtonJustDown(); - void LoadSettings(int32 file); - void SaveSettings(int32 file); - void MakeControllerActionsBlank(); - void InitDefaultControlConfiguration(); - void InitDefaultControlConfigMouse(CMouseControllerState const &mousestate); - void InitDefaultControlConfigJoyPad(unsigned int buttons); - void ClearSimButtonPressCheckers(); - void AffectPadFromKeyBoard(); - void AffectPadFromMouse(); - -}; - -VALIDATE_SIZE(CControllerConfigManager, 0x143C); - -extern CControllerConfigManager &ControlsManager; \ No newline at end of file diff --git a/src/CullZones.cpp b/src/CullZones.cpp deleted file mode 100644 index 6155ae57..00000000 --- a/src/CullZones.cpp +++ /dev/null @@ -1,370 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Building.h" -#include "Treadable.h" -#include "Train.h" -#include "Pools.h" -#include "Timer.h" -#include "Camera.h" -#include "World.h" -#include "FileMgr.h" -#include "CullZones.h" - -int32 &CCullZones::NumCullZones = *(int*)0x8F2564; -CCullZone *CCullZones::aZones = (CCullZone*)0x864750; // [NUMCULLZONES]; -int32 &CCullZones::NumAttributeZones = *(int*)0x8E29D0; -CAttributeZone *CCullZones::aAttributeZones = (CAttributeZone*)0x709C60; // [NUMATTRIBZONES]; -uint16 *CCullZones::aIndices = (uint16*)0x847330; // [NUMZONEINDICES]; -int16 *CCullZones::aPointersToBigBuildingsForBuildings = (int16*)0x86C9D0; // [NUMBUILDINGS]; -int16 *CCullZones::aPointersToBigBuildingsForTreadables = (int16*)0x8F1B8C; // [NUMTREADABLES]; - -int32 &CCullZones::CurrentWantedLevelDrop_Player = *(int32*)0x880DA8; -int32 &CCullZones::CurrentFlags_Camera = *(int32*)0x940718; -int32 &CCullZones::CurrentFlags_Player = *(int32*)0x9415F0; -int32 &CCullZones::OldCullZone = *(int32*)0x8E2C90; -int32 &CCullZones::EntityIndicesUsed = *(int32*)0x8F2508; -bool &CCullZones::bCurrentSubwayIsInvisible = *(bool*)0x95CDA5; -bool &CCullZones::bCullZonesDisabled = *(bool*)0x95CD4A; - - -void -CCullZones::Init(void) -{ - int i; - - NumAttributeZones = 0; - NumCullZones = 0; - CurrentWantedLevelDrop_Player = 0; - CurrentFlags_Camera = 0; - CurrentFlags_Player = 0; - OldCullZone = -1; - EntityIndicesUsed = 0; - bCurrentSubwayIsInvisible = false; - - for(i = 0; i < NUMBUILDINGS; i++) - aPointersToBigBuildingsForBuildings[i] = -1; - for(i = 0; i < NUMTREADABLES; i++) - aPointersToBigBuildingsForTreadables[i] = -1; -} - -void -CCullZones::ResolveVisibilities(void) -{ - int fd; - - CFileMgr::SetDir(""); - fd = CFileMgr::OpenFile("DATA\\cullzone.dat", "rb"); - if(fd > 0){ - CFileMgr::Read(fd, (char*)&NumCullZones, 4); - CFileMgr::Read(fd, (char*)aZones, NUMCULLZONES*sizeof(CCullZone)); - CFileMgr::Read(fd, (char*)&NumAttributeZones, 4); - CFileMgr::Read(fd, (char*)aAttributeZones, NUMATTRIBZONES*sizeof(CAttributeZone)); - CFileMgr::Read(fd, (char*)aIndices, NUMZONEINDICES*2); - CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForBuildings, NUMBUILDINGS*2); - CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForTreadables, NUMTREADABLES*2); - CFileMgr::CloseFile(fd); - }else{ - // TODO: implement code from mobile to generate data here - } -} - -void -CCullZones::Update(void) -{ - bool invisible; - - if(bCullZonesDisabled) - return; - - switch(CTimer::GetFrameCounter() & 7){ - case 0: - case 4: - /* Update Cull zone */ - ForceCullZoneCoors(TheCamera.GetGameCamPosition()); - break; - - case 2: - /* Update camera attributes */ - CurrentFlags_Camera = FindAttributesForCoors(TheCamera.GetGameCamPosition(), nil); - invisible = (CurrentFlags_Camera & ATTRZONE_SUBWAYVISIBLE) == 0; - if(invisible != bCurrentSubwayIsInvisible){ - MarkSubwayAsInvisible(!invisible); - bCurrentSubwayIsInvisible = invisible; - } - break; - - case 6: - /* Update player attributes */ - CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(), - &CurrentWantedLevelDrop_Player); - break; - } -} - -void -CCullZones::ForceCullZoneCoors(CVector coors) -{ - int32 z; - z = FindCullZoneForCoors(coors); - if(z != OldCullZone){ - if(OldCullZone >= 0) - aZones[OldCullZone].DoStuffLeavingZone(); - if(z >= 0) - aZones[z].DoStuffEnteringZone(); - OldCullZone = z; - } -} - -int32 -CCullZones::FindCullZoneForCoors(CVector coors) -{ - int i; - - for(i = 0; i < NumCullZones; i++) - if(coors.x >= aZones[i].minx && coors.x <= aZones[i].maxx && - coors.y >= aZones[i].miny && coors.y <= aZones[i].maxy && - coors.z >= aZones[i].minz && coors.z <= aZones[i].maxz) - return i; - return -1; -} - -int32 -CCullZones::FindAttributesForCoors(CVector coors, int32 *wantedLevel) -{ - int i; - int32 attribs; - - attribs = 0; - for(i = 0; i < NumAttributeZones; i++) - if(coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && - coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && - coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz){ - attribs |= aAttributeZones[i].attributes; - if(wantedLevel && *wantedLevel <= aAttributeZones[i].wantedLevel) - *wantedLevel = aAttributeZones[i].wantedLevel; - } - return attribs; -} - -CAttributeZone* -CCullZones::FindZoneWithStairsAttributeForPlayer(void) -{ - int i; - CVector coors; - - coors = FindPlayerCoors(); - for(i = 0; i < NumAttributeZones; i++) - if(aAttributeZones[i].attributes & ATTRZONE_STAIRS && - coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && - coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && - coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz) - return &aAttributeZones[i]; - return nil; -} - -void -CCullZones::MarkSubwayAsInvisible(bool visible) -{ - int i, n; - CEntity *e; - CVehicle *v; - - n = CPools::GetBuildingPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetBuildingPool()->GetSlot(i); - if(e && e->bIsSubway) - e->bIsVisible = visible; - } - - n = CPools::GetTreadablePool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetTreadablePool()->GetSlot(i); - if(e && e->bIsSubway) - e->bIsVisible = visible; - } - - n = CPools::GetVehiclePool()->GetSize(); - for(i = 0; i < n; i++){ - v = CPools::GetVehiclePool()->GetSlot(i); - if(v && v->IsTrain() && ((CTrain*)v)->m_trackId != 0) - v->bIsVisible = visible; - } -} - -void -CCullZones::AddCullZone(CVector const &position, - float minx, float maxx, - float miny, float maxy, - float minz, float maxz, - uint16 flag, int16 wantedLevel) -{ - CCullZone *cull; - CAttributeZone *attrib; - - CVector v; - if((flag & ATTRZONE_NOTCULLZONE) == 0){ - cull = &aZones[NumCullZones++]; - v = position; - // WTF is this? - if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f) - v = CVector(1061.7f, -613.0f, 19.0f); - if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f) - v = CVector(1061.4f, -506.0f, 18.5f); - cull->position.x = clamp(v.x, minx, maxx); - cull->position.y = clamp(v.y, miny, maxy); - cull->position.z = clamp(v.z, minz, maxz); - cull->minx = minx; - cull->maxx = maxx; - cull->miny = miny; - cull->maxy = maxy; - cull->minz = minz; - cull->maxz = maxz; - cull->unk2 = 0; - cull->unk3 = 0; - cull->unk4 = 0; - cull->m_indexStart = 0; - } - if(flag & ~ATTRZONE_NOTCULLZONE){ - attrib = &aAttributeZones[NumAttributeZones++]; - attrib->minx = minx; - attrib->maxx = maxx; - attrib->miny = miny; - attrib->maxy = maxy; - attrib->minz = minz; - attrib->maxz = maxz; - attrib->attributes = flag; - attrib->wantedLevel = wantedLevel; - } -} - - - -void -CCullZone::DoStuffLeavingZone(void) -{ - int i; - - for(i = 0; i < m_numBuildings; i++) - DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); - for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables ; i++) - DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[m_indexStart + i]); -} - -void -CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i) -{ - int16 bb; - int j; - - if(i < 6000){ - CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false; - bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; - if(bb != -1) - CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; - }else{ - i -= 6000; - for(j = 0; j < 3; j++) - DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); - } -} - -void -CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i) -{ - int16 bb; - int j; - - if(i < 6000){ - CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false; - CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false; - bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; - if(bb != -1) - CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; - }else{ - i -= 6000; - for(j = 0; j < 3; j++) - DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]); - } -} - -void -CCullZone::DoStuffEnteringZone(void) -{ - int i; - - for(i = 0; i < m_numBuildings; i++) - DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); - for(; i < m_numBuildings + m_numTreadablesPlus10m; i++) - DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[m_indexStart + i]); - for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables; i++) - DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[m_indexStart + i]); -} - -void -CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i) -{ - int16 bb; - int j; - - if(i < 6000){ - CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true; - bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; - if(bb != -1) - CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; - }else{ - i -= 6000; - for(j = 0; j < 3; j++) - DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); - } -} - -void -CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i) -{ - int16 bb; - int j; - - if(i < 6000){ - CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;; - CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true;; - bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; - if(bb != -1) - CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; - }else{ - i -= 6000; - for(j = 0; j < 3; j++) - DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); - } -} - -void -CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i) -{ - int16 bb; - int j; - - if(i < 6000){ - CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;; - bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; - if(bb != -1) - CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; - }else{ - i -= 6000; - for(j = 0; j < 3; j++) - DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); - } -} - -STARTPATCHES - InjectHook(0x524BC0, &CCullZones::Init, PATCH_JUMP); - InjectHook(0x524EC0, &CCullZones::ResolveVisibilities, PATCH_JUMP); - InjectHook(0x524F80, &CCullZones::Update, PATCH_JUMP); - InjectHook(0x525370, &CCullZones::AddCullZone, PATCH_JUMP); - InjectHook(0x5250D0, &CCullZones::ForceCullZoneCoors, PATCH_JUMP); - InjectHook(0x525130, &CCullZones::FindCullZoneForCoors, PATCH_JUMP); - InjectHook(0x5251C0, &CCullZones::FindAttributesForCoors, PATCH_JUMP); - InjectHook(0x525290, &CCullZones::FindZoneWithStairsAttributeForPlayer, PATCH_JUMP); - - InjectHook(0x525610, &CCullZone::DoStuffLeavingZone, PATCH_JUMP); - InjectHook(0x525810, &CCullZone::DoStuffEnteringZone, PATCH_JUMP); -ENDPATCHES diff --git a/src/CullZones.h b/src/CullZones.h deleted file mode 100644 index 5b04b4f9..00000000 --- a/src/CullZones.h +++ /dev/null @@ -1,94 +0,0 @@ -class CCullZone -{ -public: - CVector position; - float minx; - float maxx; - float miny; - float maxy; - float minz; - float maxz; - - // TODO: figure these out: - int32 m_indexStart; - int16 unk2; - int16 unk3; - int16 unk4; - int16 m_numBuildings; - int16 m_numTreadablesPlus10m; - int16 m_numTreadables; - - void DoStuffLeavingZone(void); - static void DoStuffLeavingZone_OneBuilding(uint16 i); - static void DoStuffLeavingZone_OneTreadableBoth(uint16 i); - void DoStuffEnteringZone(void); - static void DoStuffEnteringZone_OneBuilding(uint16 i); - static void DoStuffEnteringZone_OneTreadablePlus10m(uint16 i); - static void DoStuffEnteringZone_OneTreadable(uint16 i); -}; - -enum eZoneAttribs -{ - ATTRZONE_CAMCLOSEIN = 1, - ATTRZONE_STAIRS = 2, - ATTRZONE_1STPERSON = 4, - ATTRZONE_NORAIN = 8, - ATTRZONE_NOPOLICE = 0x10, - ATTRZONE_NOTCULLZONE = 0x20, - ATTRZONE_DOINEEDCOLLISION = 0x40, - ATTRZONE_SUBWAYVISIBLE = 0x80, -}; - -struct CAttributeZone -{ - float minx; - float maxx; - float miny; - float maxy; - float minz; - float maxz; - int16 attributes; - int16 wantedLevel; -}; - -class CCullZones -{ -public: - static int32 &NumCullZones; - static CCullZone *aZones; // [NUMCULLZONES]; - static int32 &NumAttributeZones; - static CAttributeZone *aAttributeZones; // [NUMATTRIBZONES]; - static uint16 *aIndices; // [NUMZONEINDICES]; - static int16 *aPointersToBigBuildingsForBuildings; // [NUMBUILDINGS]; - static int16 *aPointersToBigBuildingsForTreadables; // [NUMTREADABLES]; - - static int32 &CurrentWantedLevelDrop_Player; - static int32 &CurrentFlags_Camera; - static int32 &CurrentFlags_Player; - static int32 &OldCullZone; - static int32 &EntityIndicesUsed; - static bool &bCurrentSubwayIsInvisible; - static bool &bCullZonesDisabled; - - static void Init(void); - static void ResolveVisibilities(void); - static void Update(void); - static void ForceCullZoneCoors(CVector coors); - static int32 FindCullZoneForCoors(CVector coors); - static int32 FindAttributesForCoors(CVector coors, int32 *wantedLevel); - static CAttributeZone *FindZoneWithStairsAttributeForPlayer(void); - static void MarkSubwayAsInvisible(bool visible); - static void AddCullZone(CVector const &position, - float minx, float maxx, - float miny, float maxy, - float minz, float maxz, - uint16 flag, int16 wantedLevel); - static bool CamCloseInForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_CAMCLOSEIN) != 0; } - static bool CamStairsForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_STAIRS) != 0; } - static bool Cam1stPersonForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_1STPERSON) != 0; } - static bool NoPolice(void) { return (CurrentFlags_Player & ATTRZONE_NOPOLICE) != 0; } - static bool DoINeedToLoadCollision(void) { return (CurrentFlags_Player & ATTRZONE_DOINEEDCOLLISION) != 0; } - static bool PlayerNoRain(void) { return (CurrentFlags_Player & ATTRZONE_NORAIN) != 0; } - static bool CamNoRain(void) { return (CurrentFlags_Camera & ATTRZONE_NORAIN) != 0; } - static int32 GetWantedLevelDrop(void) { return CurrentWantedLevelDrop_Player; } -}; diff --git a/src/CutsceneMgr.cpp b/src/CutsceneMgr.cpp deleted file mode 100644 index 744ef53d..00000000 --- a/src/CutsceneMgr.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "CutsceneMgr.h" - -bool &CCutsceneMgr::ms_running = *(bool*)0x95CCF5; -bool &CCutsceneMgr::ms_cutsceneProcessing = *(bool*)0x95CD9F; -CDirectory *&CCutsceneMgr::ms_pCutsceneDir = *(CDirectory**)0x8F5F88; diff --git a/src/CutsceneMgr.h b/src/CutsceneMgr.h deleted file mode 100644 index 89f6ab8d..00000000 --- a/src/CutsceneMgr.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -class CDirectory; - -class CCutsceneMgr -{ - static bool &ms_running; - static bool &ms_cutsceneProcessing; - -public: - static CDirectory *&ms_pCutsceneDir; - - static bool IsRunning(void) { return ms_running; } - static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; } -}; diff --git a/src/DamageManager.cpp b/src/DamageManager.cpp deleted file mode 100644 index 1a7f25ed..00000000 --- a/src/DamageManager.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "General.h" -#include "DamageManager.h" - - -float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f }; - -void -CDamageManager::ResetDamageStatus(void) -{ - memset(this, 0, sizeof(*this)); -} - -void -CDamageManager::FuckCarCompletely(void) -{ - int i; - - m_wheelStatus[0] = 2; - // wheels 1-3 not reset? - - m_doorStatus[0] = 3; - m_doorStatus[1] = 3; - m_doorStatus[2] = 3; - m_doorStatus[3] = 3; - m_doorStatus[4] = 3; - m_doorStatus[5] = 3; - - for(i = 0; i < 3; i++){ -#ifdef FIX_BUGS - ProgressPanelDamage(VEHBUMPER_FRONT); - ProgressPanelDamage(VEHBUMPER_REAR); -#else - // this can't be right - ProgressPanelDamage(COMPONENT_BUMPER_FRONT); - ProgressPanelDamage(COMPONENT_BUMPER_REAR); -#endif - } - // Why set to no damage? - m_lightStatus = 0; - m_panelStatus = 0; - SetEngineStatus(250); -} - -bool -CDamageManager::ApplyDamage(tComponent component, float damage, float unused) -{ - tComponentGroup group; - uint8 subComp; - - GetComponentGroup(component, &group, &subComp); - damage *= G_aComponentDamage[group]; - if(damage > 150.0f){ - switch(group){ - case COMPGROUP_WHEEL: - ProgressWheelDamage(subComp); - break; - case COMPGROUP_DOOR: - case COMPGROUP_BOOT: - ProgressDoorDamage(subComp); - break; - case COMPGROUP_BONNET: - if(damage > 220.0f) - ProgressEngineDamage(); - ProgressDoorDamage(subComp); - break; - case COMPGROUP_PANEL: - // so windscreen is a light? - SetLightStatus((eLights)subComp, 1); - // fall through - case COMPGROUP_BUMPER: - if(damage > 220.0f && - (component == COMPONENT_PANEL_FRONT_LEFT || - component == COMPONENT_PANEL_FRONT_RIGHT || - component == COMPONENT_PANEL_WINDSCREEN)) - ProgressEngineDamage(); - ProgressPanelDamage(subComp); - break; - } - return true; - } - return false; -} - -bool -CDamageManager::GetComponentGroup(tComponent component, tComponentGroup *componentGroup, uint8 *subComp) -{ - *subComp = -2; // ?? - - // This is done very strangely in the game, maybe an optimized switch? - if(component >= COMPONENT_PANEL_FRONT_LEFT){ - if(component >= COMPONENT_BUMPER_FRONT) - *componentGroup = COMPGROUP_BUMPER; - else - *componentGroup = COMPGROUP_PANEL; - *subComp = component - COMPONENT_PANEL_FRONT_LEFT; - return true; - }else if(component >= COMPONENT_DOOR_BONNET){ - if(component == COMPONENT_DOOR_BONNET) - *componentGroup = COMPGROUP_BONNET; - else if(component == COMPONENT_DOOR_BOOT) - *componentGroup = COMPGROUP_BOOT; - else - *componentGroup = COMPGROUP_DOOR; - *subComp = component - COMPONENT_DOOR_BONNET; - return true; - }else if(component >= COMPONENT_WHEEL_FRONT_LEFT){ - *componentGroup = COMPGROUP_WHEEL; - *subComp = component - COMPONENT_WHEEL_FRONT_LEFT; - return true; - }else if(component >= COMPONENT_DEFAULT){ - *componentGroup = COMPGROUP_DEFAULT; - *subComp = component - COMPONENT_DEFAULT; - return true; - }else - return false; -} - -void -CDamageManager::SetDoorStatus(int32 door, uint32 status) -{ - m_doorStatus[door] = status; -} - -int32 -CDamageManager::GetDoorStatus(int32 door) -{ - return m_doorStatus[door]; -} - -bool -CDamageManager::ProgressDoorDamage(uint8 door) -{ - int status = GetDoorStatus(door); - if(status == 3) - return false; - SetDoorStatus(door, status+1); - return true; -} - -void -CDamageManager::SetPanelStatus(int32 panel, uint32 status) -{ - m_panelStatus = dpb(status, panel*4, 4, m_panelStatus); -} - -int32 -CDamageManager::GetPanelStatus(int32 panel) -{ - return ldb(panel*4, 4, m_panelStatus); -} - -bool -CDamageManager::ProgressPanelDamage(uint8 panel) -{ - int status = GetPanelStatus(panel); - if(status == 3) - return false; - SetPanelStatus(panel, status+1); - return true; -} - -void -CDamageManager::SetLightStatus(eLights light, uint32 status) -{ - m_lightStatus = dpb(status, light*2, 2, m_lightStatus); -} - -int32 -CDamageManager::GetLightStatus(eLights light) -{ - return ldb(light*2, 2, m_lightStatus); -} - -void -CDamageManager::SetWheelStatus(int32 wheel, uint32 status) -{ - m_wheelStatus[wheel] = status; -} - -int32 -CDamageManager::GetWheelStatus(int32 wheel) -{ - return m_wheelStatus[wheel]; -} - -bool -CDamageManager::ProgressWheelDamage(uint8 wheel) -{ - int status = GetWheelStatus(wheel); - if(status == 3) - return false; - SetWheelStatus(wheel, status+1); - return true; -} - -void -CDamageManager::SetEngineStatus(uint32 status) -{ - if(status > 250) - m_engineStatus = 250; - else - m_engineStatus = status; -} - -int32 -CDamageManager::GetEngineStatus(void) -{ - return m_engineStatus; -} - -bool -CDamageManager::ProgressEngineDamage(void) -{ - int status = GetEngineStatus(); - int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F); - if(status < 225 && newstatus > 224) - newstatus = 224; - SetEngineStatus(newstatus); - return true; -} - -STARTPATCHES - InjectHook(0x545850, &CDamageManager::ResetDamageStatus, PATCH_JUMP); - InjectHook(0x545B70, &CDamageManager::FuckCarCompletely, PATCH_JUMP); - InjectHook(0x545790, &CDamageManager::GetComponentGroup, PATCH_JUMP); - InjectHook(0x545A80, &CDamageManager::ApplyDamage, PATCH_JUMP); - InjectHook(0x545920, &CDamageManager::SetDoorStatus, PATCH_JUMP); - InjectHook(0x545930, &CDamageManager::GetDoorStatus, PATCH_JUMP); - InjectHook(0x545970, &CDamageManager::ProgressDoorDamage, PATCH_JUMP); - InjectHook(0x5458B0, &CDamageManager::SetPanelStatus, PATCH_JUMP); - InjectHook(0x5458E0, (int32 (CDamageManager::*)(int32))&CDamageManager::GetPanelStatus, PATCH_JUMP); - InjectHook(0x545A00, &CDamageManager::ProgressPanelDamage, PATCH_JUMP); - InjectHook(0x545860, &CDamageManager::SetLightStatus, PATCH_JUMP); - InjectHook(0x545890, &CDamageManager::GetLightStatus, PATCH_JUMP); - InjectHook(0x545900, &CDamageManager::SetWheelStatus, PATCH_JUMP); - InjectHook(0x545910, &CDamageManager::GetWheelStatus, PATCH_JUMP); - InjectHook(0x545A40, &CDamageManager::ProgressWheelDamage, PATCH_JUMP); - InjectHook(0x545940, &CDamageManager::SetEngineStatus, PATCH_JUMP); - InjectHook(0x545960, &CDamageManager::GetEngineStatus, PATCH_JUMP); - InjectHook(0x5459B0, &CDamageManager::ProgressEngineDamage, PATCH_JUMP); -ENDPATCHES diff --git a/src/DamageManager.h b/src/DamageManager.h deleted file mode 100644 index 1fdbc6b1..00000000 --- a/src/DamageManager.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include "common.h" - -// TODO: move some of this into Vehicle.h - -enum tComponent -{ - COMPONENT_DEFAULT, - COMPONENT_WHEEL_FRONT_LEFT, - COMPONENT_WHEEL_FRONT_RIGHT, - COMPONENT_WHEEL_REAR_LEFT, - COMPONENT_WHEEL_REAR_RIGHT, - COMPONENT_DOOR_BONNET, - COMPONENT_DOOR_BOOT, - COMPONENT_DOOR_FRONT_LEFT, - COMPONENT_DOOR_FRONT_RIGHT, - COMPONENT_DOOR_REAR_LEFT, - COMPONENT_DOOR_REAR_RIGHT, - COMPONENT_PANEL_FRONT_LEFT, - COMPONENT_PANEL_FRONT_RIGHT, - COMPONENT_PANEL_REAR_LEFT, - COMPONENT_PANEL_REAR_RIGHT, - COMPONENT_PANEL_WINDSCREEN, - COMPONENT_BUMPER_FRONT, - COMPONENT_BUMPER_REAR, -}; - -enum tComponentGroup -{ - COMPGROUP_BUMPER, - COMPGROUP_WHEEL, - COMPGROUP_DOOR, - COMPGROUP_BONNET, - COMPGROUP_BOOT, - COMPGROUP_PANEL, - COMPGROUP_DEFAULT, -}; - -enum eLights -{ - VEHLIGHT_FRONT_LEFT, - VEHLIGHT_FRONT_RIGHT, - VEHLIGHT_REAR_LEFT, - VEHLIGHT_REAR_RIGHT, -}; - -enum { - VEHPANEL_FRONT_LEFT, - VEHPANEL_FRONT_RIGHT, - VEHPANEL_REAR_LEFT, - VEHPANEL_REAR_RIGHT, - VEHPANEL_WINDSCREEN, - VEHBUMPER_FRONT, - VEHBUMPER_REAR, -}; - -class CDamageManager -{ -public: - - float field_0; - uint8 m_engineStatus; - uint8 m_wheelStatus[4]; - uint8 m_doorStatus[6]; - uint32 m_lightStatus; - uint32 m_panelStatus; - uint32 field_24; - - void ResetDamageStatus(void); - void FuckCarCompletely(void); - bool ApplyDamage(tComponent component, float damage, float unused); - bool GetComponentGroup(tComponent component, tComponentGroup *componentGroup, uint8 *foo); - - void SetDoorStatus(int32 door, uint32 status); - int32 GetDoorStatus(int32 door); - bool ProgressDoorDamage(uint8 door); - void SetPanelStatus(int32 panel, uint32 status); - int32 GetPanelStatus(int32 panel); - bool ProgressPanelDamage(uint8 panel); - // needed for CReplay - static int32 GetPanelStatus(uint32 panelstatus, int32 panel) { return ldb(panel*4, 4, panelstatus); } - void SetLightStatus(eLights light, uint32 status); - int32 GetLightStatus(eLights light); - void SetWheelStatus(int32 wheel, uint32 status); - int32 GetWheelStatus(int32 wheel); - bool ProgressWheelDamage(uint8 wheel); - void SetEngineStatus(uint32 status); - int32 GetEngineStatus(void); - bool ProgressEngineDamage(void); -}; -VALIDATE_SIZE(CDamageManager, 0x1C); diff --git a/src/Directory.cpp b/src/Directory.cpp deleted file mode 100644 index 3e0d5382..00000000 --- a/src/Directory.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" -#include "Directory.h" - -CDirectory::CDirectory(int32 maxEntries) - : numEntries(0), maxEntries(maxEntries) -{ - entries = new DirectoryInfo[maxEntries]; -} - -CDirectory::~CDirectory(void) -{ - delete[] entries; -} - -void -CDirectory::ReadDirFile(const char *filename) -{ - int fd; - DirectoryInfo dirinfo; - - fd = CFileMgr::OpenFile(filename, "rb"); - while(CFileMgr::Read(fd, (char*)&dirinfo, sizeof(dirinfo))) - AddItem(dirinfo); - CFileMgr::CloseFile(fd); -} - -bool -CDirectory::WriteDirFile(const char *filename) -{ - int fd, n; - fd = CFileMgr::OpenFileForWriting(filename); - n = CFileMgr::Write(fd, (char*)entries, numEntries*sizeof(DirectoryInfo)); - CFileMgr::CloseFile(fd); - return n == numEntries*sizeof(DirectoryInfo); -} - -void -CDirectory::AddItem(const DirectoryInfo &dirinfo) -{ - assert(numEntries < maxEntries); - entries[numEntries++] = dirinfo; -} - -bool -CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size) -{ - int i; - - for(i = 0; i < numEntries; i++) - if(strcmpi(entries[i].name, name) == 0){ - offset = entries[i].offset; - size = entries[i].size; - return true; - } - return false; -} - -STARTPATCHES - InjectHook(0x473630, &CDirectory::ReadDirFile, PATCH_JUMP); - InjectHook(0x473690, &CDirectory::WriteDirFile, PATCH_JUMP); - InjectHook(0x473600, &CDirectory::AddItem, PATCH_JUMP); - InjectHook(0x4736E0, &CDirectory::FindItem, PATCH_JUMP); -ENDPATCHES diff --git a/src/Directory.h b/src/Directory.h deleted file mode 100644 index 06e6bba4..00000000 --- a/src/Directory.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -class CDirectory -{ -public: - struct DirectoryInfo { - uint32 offset; - uint32 size; - char name[24]; - }; - DirectoryInfo *entries; - int32 maxEntries; - int32 numEntries; - - CDirectory(int32 maxEntries); - ~CDirectory(void); - - void ReadDirFile(const char *filename); - bool WriteDirFile(const char *filename); - void AddItem(const DirectoryInfo &dirinfo); - bool FindItem(const char *name, uint32 &offset, uint32 &size); -}; diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp deleted file mode 100644 index d87964ac..00000000 --- a/src/FileLoader.cpp +++ /dev/null @@ -1,1182 +0,0 @@ -#include "common.h" -#include "main.h" -#include "patcher.h" -#include "math/Quaternion.h" -#include "ModelInfo.h" -#include "ModelIndices.h" -#include "TempColModels.h" -#include "VisibilityPlugins.h" -#include "FileMgr.h" -#include "HandlingMgr.h" -#include "CarCtrl.h" -#include "PedType.h" -#include "PedStats.h" -#include "AnimManager.h" -#include "Game.h" -#include "RwHelper.h" -#include "NodeName.h" -#include "TxdStore.h" -#include "PathFind.h" -#include "ObjectData.h" -#include "DummyObject.h" -#include "World.h" -#include "Zones.h" -#include "CullZones.h" -#include "CdStream.h" -#include "FileLoader.h" - -char CFileLoader::ms_line[256]; - -const char* -GetFilename(const char *filename) -{ - char *s = strrchr((char*)filename, '\\'); - return s ? s+1 : filename; -} - -void -LoadingScreenLoadingFile(const char *filename) -{ - sprintf(gString, "Loading %s", GetFilename(filename)); - LoadingScreen("Loading the Game", gString, nil); -} - -void -CFileLoader::LoadLevel(const char *filename) -{ - int fd; - RwTexDictionary *savedTxd; - eLevelName savedLevel; - bool objectsLoaded; - char *line; - char txdname[64]; - - savedTxd = RwTexDictionaryGetCurrent(); - objectsLoaded = false; - savedLevel = CGame::currLevel; - if(savedTxd == nil){ - savedTxd = RwTexDictionaryCreate(); - RwTexDictionarySetCurrent(savedTxd); - } - fd = CFileMgr::OpenFile(filename, "r"); - assert(fd > 0); - - for(line = LoadLine(fd); line; line = LoadLine(fd)){ - if(*line == '#') - continue; - - if(strncmp(line, "EXIT", 9) == 0) // BUG: 9? - break; - - if(strncmp(line, "IMAGEPATH", 9) == 0){ - RwImageSetPath(line + 10); - }else if(strncmp(line, "TEXDICTION", 10) == 0){ - strcpy(txdname, line+11); - LoadingScreenLoadingFile(txdname); - RwTexDictionary *txd = LoadTexDictionary(txdname); - AddTexDictionaries(savedTxd, txd); - RwTexDictionaryDestroy(txd); - }else if(strncmp(line, "COLFILE", 7) == 0){ - int level; - sscanf(line+8, "%d", &level); - CGame::currLevel = (eLevelName)level; - LoadingScreenLoadingFile(line+10); - LoadCollisionFile(line+10); - CGame::currLevel = savedLevel; - }else if(strncmp(line, "MODELFILE", 9) == 0){ - LoadingScreenLoadingFile(line + 10); - LoadModelFile(line + 10); - }else if(strncmp(line, "HIERFILE", 8) == 0){ - LoadingScreenLoadingFile(line + 9); - LoadClumpFile(line + 9); - }else if(strncmp(line, "IDE", 3) == 0){ - LoadingScreenLoadingFile(line + 4); - LoadObjectTypes(line + 4); - }else if(strncmp(line, "IPL", 3) == 0){ - if(!objectsLoaded){ - // CModelInfo::ConstructMloClumps(); - CObjectData::Initialise("DATA\\OBJECT.DAT"); - objectsLoaded = true; - } - LoadingScreenLoadingFile(line + 4); - LoadScene(line + 4); - }else if(strncmp(line, "MAPZONE", 7) == 0){ - LoadingScreenLoadingFile(line + 8); - LoadMapZones(line + 8); - }else if(strncmp(line, "SPLASH", 6) == 0){ - LoadSplash(GetRandomSplashScreen()); - }else if(strncmp(line, "CDIMAGE", 7) == 0){ - CdStreamAddImage(line + 8); - } - } - - CFileMgr::CloseFile(fd); - RwTexDictionarySetCurrent(savedTxd); -} - -void -CFileLoader::LoadCollisionFromDatFile(int currlevel) -{ - int fd; - char *line; - - fd = CFileMgr::OpenFile(CGame::aDatFile, "r"); - assert(fd > 0); - - for(line = LoadLine(fd); line; line = LoadLine(fd)){ - if(*line == '#') - continue; - - if(strncmp(line, "COLFILE", 7) == 0){ - int level; - sscanf(line+8, "%d", &level); - if(currlevel == level) - LoadCollisionFile(line+10); - } - } - - CFileMgr::CloseFile(fd); -} - -char* -CFileLoader::LoadLine(int fd) -{ - int i; - char *line; - - if(CFileMgr::ReadLine(fd, ms_line, 256) == false) - return nil; - for(i = 0; ms_line[i] != '\0'; i++) - if(ms_line[i] < ' ' || ms_line[i] == ',') - ms_line[i] = ' '; - for(line = ms_line; *line <= ' ' && *line != '\0'; line++); - return line; -} - -RwTexDictionary* -CFileLoader::LoadTexDictionary(const char *filename) -{ - RwTexDictionary *txd; - RwStream *stream; - - txd = nil; - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); - debug("Loading texture dictionary file %s\n", filename); - if(stream){ - if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)) - txd = RwTexDictionaryGtaStreamRead(stream); - RwStreamClose(stream, nil); - } - if(txd == nil) - txd = RwTexDictionaryCreate(); - return txd; -} - -void -CFileLoader::LoadCollisionFile(const char *filename) -{ - int fd; - char modelname[24]; - CBaseModelInfo *mi; - struct { - char ident[4]; - uint32 size; - } header; - - debug("Loading collision file %s\n", filename); - fd = CFileMgr::OpenFile(filename, "rb"); - - while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){ - assert(strncmp(header.ident, "COLL", 4) == 0); - CFileMgr::Read(fd, (char*)work_buff, header.size); - memcpy(modelname, work_buff, 24); - - mi = CModelInfo::GetModelInfo(modelname, nil); - if(mi){ - if(mi->GetColModel()){ - LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname); - }else{ - CColModel *model = new CColModel; - LoadCollisionModel(work_buff+24, *model, modelname); - mi->SetColModel(model, true); - } - }else{ - debug("colmodel %s can't find a modelinfo\n", modelname); - } - } - - CFileMgr::CloseFile(fd); -} - -void -CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) -{ - int i; - - model.boundingSphere.radius = *(float*)(buf); - model.boundingSphere.center.x = *(float*)(buf+4); - model.boundingSphere.center.y = *(float*)(buf+8); - model.boundingSphere.center.z = *(float*)(buf+12); - model.boundingBox.min.x = *(float*)(buf+16); - model.boundingBox.min.y = *(float*)(buf+20); - model.boundingBox.min.z = *(float*)(buf+24); - model.boundingBox.max.x = *(float*)(buf+28); - model.boundingBox.max.y = *(float*)(buf+32); - model.boundingBox.max.z = *(float*)(buf+36); - model.numSpheres = *(int16*)(buf+40); - buf += 44; - if(model.numSpheres > 0){ - model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere)); - for(i = 0; i < model.numSpheres; i++){ - model.spheres[i].Set(*(float*)buf, *(CVector*)(buf+4), buf[16], buf[17]); - buf += 20; - } - }else - model.spheres = nil; - - model.numLines = *(int16*)buf; - buf += 4; - if(model.numLines > 0){ - model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine)); - for(i = 0; i < model.numLines; i++){ - model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12)); - buf += 24; - } - }else - model.lines = nil; - - model.numBoxes = *(int16*)buf; - buf += 4; - if(model.numBoxes > 0){ - model.boxes = (CColBox*)RwMalloc(model.numBoxes*sizeof(CColBox)); - for(i = 0; i < model.numBoxes; i++){ - model.boxes[i].Set(*(CVector*)buf, *(CVector*)(buf+12), buf[24], buf[25]); - buf += 28; - } - }else - model.boxes = nil; - - int32 numVertices = *(int16*)buf; - buf += 4; - if(numVertices > 0){ - model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector)); - for(i = 0; i < numVertices; i++){ - model.vertices[i] = *(CVector*)buf; - if(fabs(model.vertices[i].x) >= 256.0f || - fabs(model.vertices[i].y) >= 256.0f || - fabs(model.vertices[i].z) >= 256.0f) - printf("%s:Collision volume too big\n", modelname); - buf += 12; - } - }else - model.vertices = nil; - - model.numTriangles = *(int16*)buf; - buf += 4; - if(model.numTriangles > 0){ - model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle)); - for(i = 0; i < model.numTriangles; i++){ - model.triangles[i].Set(model.vertices, *(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12], buf[13]); - buf += 16; - } - }else - model.triangles = nil; -} - -static void -GetNameAndLOD(char *nodename, char *name, int *n) -{ - char *underscore = nil; - for(char *s = nodename; *s != '\0'; s++){ - if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L')) - underscore = s; - } - if(underscore){ - strncpy(name, nodename, underscore - nodename); - name[underscore - nodename] = '\0'; - *n = atoi(underscore + 2); - }else{ - strncpy(name, nodename, 24); - *n = 0; - } -} - -RpAtomic* -CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data) -{ - CSimpleModelInfo *mi; - char *nodename, name[24]; - int n; - RpClump *clump = (RpClump*)data; - - nodename = GetFrameNodeName(RpClumpGetFrame(atomic)); - GetNameAndLOD(nodename, name, &n); - mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, nil); - if(mi){ - assert(mi->IsSimple()); - mi->SetAtomic(n, atomic); - RpClumpRemoveAtomic(clump, atomic); - RpAtomicSetFrame(atomic, RwFrameCreate()); - CVisibilityPlugins::SetAtomicModelInfo(atomic, mi); - CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); - }else{ - debug("Can't find Atomic %s\n", name); - } - - return atomic; -} - -void -CFileLoader::LoadModelFile(const char *filename) -{ - RwStream *stream; - RpClump *clump; - - debug("Loading model file %s\n", filename); - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); - if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - clump = RpClumpStreamRead(stream); - if(clump){ - RpClumpForAllAtomics(clump, FindRelatedModelInfoCB, clump); - RpClumpDestroy(clump); - } - } - RwStreamClose(stream, nil); -} - -void -CFileLoader::LoadClumpFile(const char *filename) -{ - RwStream *stream; - RpClump *clump; - char *nodename, name[24]; - int n; - CClumpModelInfo *mi; - - debug("Loading model file %s\n", filename); - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); - while(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - clump = RpClumpStreamRead(stream); - if(clump){ - nodename = GetFrameNodeName(RpClumpGetFrame(clump)); - GetNameAndLOD(nodename, name, &n); - mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil); - assert(mi->IsClump()); - if(mi) - mi->SetClump(clump); - else - RpClumpDestroy(clump); - } - } - RwStreamClose(stream, nil); -} - -bool -CFileLoader::LoadClumpFile(RwStream *stream, uint32 id) -{ - RpClump *clump; - CClumpModelInfo *mi; - - if(!RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) - return false; - clump = RpClumpStreamRead(stream); - if(clump == nil) - return false; - mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); - mi->SetClump(clump); - if(mi->m_type == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - // Read LOD ped - clump = RpClumpStreamRead(stream); - if(clump){ - ((CPedModelInfo*)mi)->SetLowDetailClump(clump); - RpClumpDestroy(clump); - } - } - return true; -} - -bool -CFileLoader::StartLoadClumpFile(RwStream *stream, uint32 id) -{ - if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); - return RpClumpGtaStreamRead1(stream); - }else{ - printf("FAILED\n"); - return false; - } -} - -bool -CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id) -{ - RpClump *clump; - CClumpModelInfo *mi; - - printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); - clump = RpClumpGtaStreamRead2(stream); - - if(clump){ - mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); - mi->SetClump(clump); - return true; - }else{ - printf("FAILED\n"); - return false; - } -} - -CSimpleModelInfo *gpRelatedModelInfo; - -bool -CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id) -{ - RpClump *clump; - - if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ - clump = RpClumpStreamRead(stream); - if(clump == nil) - return false; - gpRelatedModelInfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); - RpClumpForAllAtomics(clump, SetRelatedModelInfoCB, clump); - RpClumpDestroy(clump); - } - return true; -} - -RpAtomic* -CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data) -{ - char *nodename, name[24]; - int n; - RpClump *clump = (RpClump*)data; - - nodename = GetFrameNodeName(RpAtomicGetFrame(atomic)); - GetNameAndLOD(nodename, name, &n); - gpRelatedModelInfo->SetAtomic(n, atomic); - RpClumpRemoveAtomic(clump, atomic); - RpAtomicSetFrame(atomic, RwFrameCreate()); - CVisibilityPlugins::SetAtomicModelInfo(atomic, gpRelatedModelInfo); - CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); - return atomic; -} - -RpClump* -CFileLoader::LoadAtomicFile2Return(const char *filename) -{ - RwStream *stream; - RpClump *clump; - - clump = nil; - debug("Loading model file %s\n", filename); - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); - if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) - clump = RpClumpStreamRead(stream); - RwStreamClose(stream, nil); - return clump; -} - -static RwTexture* -MoveTexturesCB(RwTexture *texture, void *pData) -{ - RwTexDictionaryAddTexture((RwTexDictionary*)pData, texture); - return texture; -} - -void -CFileLoader::AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src) -{ - RwTexDictionaryForAllTextures(src, MoveTexturesCB, dst); -} - -void -CFileLoader::LoadObjectTypes(const char *filename) -{ - enum { - NONE, - OBJS, - MLO, - TOBJ, - HIER, - CARS, - PEDS, - PATH, - TWODFX - }; - char *line; - int fd; - int section; - int pathIndex; - char pathTypeStr[20]; - int id, pathType; -// int mlo; - - section = NONE; - pathIndex = -1; -// mlo = 0; - debug("Loading object types from %s...\n", filename); - - fd = CFileMgr::OpenFile(filename, "rb"); - for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ - if(*line == '\0' || *line == '#') - continue; - - if(section == NONE){ - if(strncmp(line, "objs", 4) == 0) section = OBJS; - else if(strncmp(line, "tobj", 4) == 0) section = TOBJ; - else if(strncmp(line, "hier", 4) == 0) section = HIER; - else if(strncmp(line, "cars", 4) == 0) section = CARS; - else if(strncmp(line, "peds", 4) == 0) section = PEDS; - else if(strncmp(line, "path", 4) == 0) section = PATH; - else if(strncmp(line, "2dfx", 4) == 0) section = TWODFX; - }else if(strncmp(line, "end", 3) == 0){ - section = section == MLO ? OBJS : NONE; - }else switch(section){ - case OBJS: - if(strncmp(line, "sta", 3) == 0) - assert(0); // LoadMLO - else - LoadObject(line); - break; - case MLO: - assert(0); // LoadMLOInstance - break; - case TOBJ: - LoadTimeObject(line); - break; - case HIER: - LoadClumpObject(line); - break; - case CARS: - LoadVehicleObject(line); - break; - case PEDS: - LoadPedObject(line); - break; - case PATH: - if(pathIndex == -1){ - id = LoadPathHeader(line, pathTypeStr); - if(strncmp(pathTypeStr, "ped", 4) == 0) - pathType = 1; - else if(strncmp(pathTypeStr, "car", 4) == 0) - pathType = 0; - pathIndex = 0; - }else{ - if(pathType == 1) - LoadPedPathNode(line, id, pathIndex); - else if(pathType == 0) - LoadCarPathNode(line, id, pathIndex); - pathIndex++; - if(pathIndex == 12) - pathIndex = -1; - } - break; - case TWODFX: - Load2dEffect(line); - break; - } - } - CFileMgr::CloseFile(fd); - - for(id = 0; id < MODELINFOSIZE; id++){ - CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); - if(mi && mi->IsSimple()) - mi->SetupBigBuilding(); - } -} - -void -SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags) -{ - mi->m_normalCull = !!(flags & 1); - mi->m_noFade = !!(flags & 2); - mi->m_drawLast = !!(flags & (4|8)); - mi->m_additive = !!(flags & 8); - mi->m_isSubway = !!(flags & 0x10); - mi->m_ignoreLight = !!(flags & 0x20); - mi->m_noZwrite = !!(flags & 0x40); -} - -void -CFileLoader::LoadObject(const char *line) -{ - int id, numObjs; - char model[24], txd[24]; - float dist[3]; - uint32 flags; - int damaged; - CSimpleModelInfo *mi; - - if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) - return; - - switch(numObjs){ - case 1: - sscanf(line, "%d %s %s %d %f %d", - &id, model, txd, &numObjs, &dist[0], &flags); - damaged = 0; - break; - case 2: - sscanf(line, "%d %s %s %d %f %f %d", - &id, model, txd, &numObjs, &dist[0], &dist[1], &flags); - damaged = dist[0] < dist[1] ? // Are distances increasing? - 0 : // Yes, no damage model - 1; // No, 1 is damaged - break; - case 3: - sscanf(line, "%d %s %s %d %f %f %f %d", - &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags); - damaged = dist[0] < dist[1] ? // Are distances increasing? - (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model - 1; // No, 1 and 2 are damaged - break; - } - - mi = CModelInfo::AddSimpleModel(id); - mi->SetName(model); - mi->SetNumAtomics(numObjs); - mi->SetLodDistances(dist); - SetModelInfoFlags(mi, flags); - mi->m_firstDamaged = damaged; - mi->SetTexDictionary(txd); - MatchModelString(model, id); -} - -void -CFileLoader::LoadTimeObject(const char *line) -{ - int id, numObjs; - char model[24], txd[24]; - float dist[3]; - uint32 flags; - int timeOn, timeOff; - int damaged; - CTimeModelInfo *mi, *other; - - if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) - return; - - switch(numObjs){ - case 1: - sscanf(line, "%d %s %s %d %f %d %d %d", - &id, model, txd, &numObjs, &dist[0], &flags, &timeOn, &timeOff); - damaged = 0; - break; - case 2: - sscanf(line, "%d %s %s %d %f %f %d %d %d", - &id, model, txd, &numObjs, &dist[0], &dist[1], &flags, &timeOn, &timeOff); - damaged = dist[0] < dist[1] ? // Are distances increasing? - 0 : // Yes, no damage model - 1; // No, 1 is damaged - break; - case 3: - sscanf(line, "%d %s %s %d %f %f %f %d %d %d", - &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags, &timeOn, &timeOff); - damaged = dist[0] < dist[1] ? // Are distances increasing? - (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model - 1; // No, 1 and 2 are damaged - break; - } - - mi = CModelInfo::AddTimeModel(id); - mi->SetName(model); - mi->SetNumAtomics(numObjs); - mi->SetLodDistances(dist); - SetModelInfoFlags(mi, flags); - mi->m_firstDamaged = damaged; - mi->SetTimes(timeOn, timeOff); - mi->SetTexDictionary(txd); - other = mi->FindOtherTimeModel(); - if(other) - other->SetOtherTimeModel(id); - MatchModelString(model, id); -} - -void -CFileLoader::LoadClumpObject(const char *line) -{ - int id; - char model[24], txd[24]; - CClumpModelInfo *mi; - - if(sscanf(line, "%d %s %s", &id, &model, &txd) == 3){ - mi = CModelInfo::AddClumpModel(id); - mi->SetName(model); - mi->SetTexDictionary(txd); - mi->SetColModel(&CTempColModels::ms_colModelBBox); - } -} - -void -CFileLoader::LoadVehicleObject(const char *line) -{ - int id; - char model[24], txd[24]; - char type[8], handlingId[16], gamename[32], vehclass[12]; - uint32 frequency, comprules; - int32 level, misc; - float wheelScale; - CVehicleModelInfo *mi; - char *p; - - sscanf(line, "%d %s %s %s %s %s %s %d %d %x %d %f", - &id, model, txd, - type, handlingId, gamename, vehclass, - &frequency, &level, &comprules, &misc, &wheelScale); - - mi = CModelInfo::AddVehicleModel(id); - mi->SetName(model); - mi->SetTexDictionary(txd); - for(p = gamename; *p; p++) - if(*p == '_') *p = ' '; - strncpy(mi->m_gameName, gamename, 32); - mi->m_level = level; - mi->m_compRules = comprules; - - if(strncmp(type, "car", 4) == 0){ - mi->m_wheelId = misc; - mi->m_wheelScale = wheelScale; - mi->m_vehicleType = VEHICLE_TYPE_CAR; - }else if(strncmp(type, "boat", 5) == 0){ - mi->m_vehicleType = VEHICLE_TYPE_BOAT; - }else if(strncmp(type, "train", 6) == 0){ - mi->m_vehicleType = VEHICLE_TYPE_TRAIN; - }else if(strncmp(type, "heli", 5) == 0){ - mi->m_vehicleType = VEHICLE_TYPE_HELI; - }else if(strncmp(type, "plane", 6) == 0){ - mi->m_wheelId = misc; - mi->m_wheelScale = 1.0f; - mi->m_vehicleType = VEHICLE_TYPE_PLANE; - }else if(strncmp(type, "bike", 5) == 0){ - mi->m_bikeSteerAngle = misc; - mi->m_wheelScale = wheelScale; - mi->m_vehicleType = VEHICLE_TYPE_BIKE; - }else - assert(0); - - mi->m_handlingId = mod_HandlingManager.GetHandlingId(handlingId); - - // Well this is kinda dumb.... - if(strncmp(vehclass, "poorfamily", 11) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_POOR; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_POOR); - }else if(strncmp(vehclass, "richfamily", 11) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_RICH; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_RICH); - }else if(strncmp(vehclass, "executive", 10) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_EXECUTIVE; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_EXECUTIVE); - }else if(strncmp(vehclass, "worker", 7) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_WORKER; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_WORKER); - }else if(strncmp(vehclass, "special", 8) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_SPECIAL; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_SPECIAL); - }else if(strncmp(vehclass, "big", 4) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_BIG; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_BIG); - }else if(strncmp(vehclass, "taxi", 5) == 0){ - mi->m_vehicleClass = VEHICLE_CLASS_TAXI; - while(frequency-- > 0) - CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_TAXI); - } -} - -void -CFileLoader::LoadPedObject(const char *line) -{ - int id; - char model[24], txd[24]; - char pedType[24], pedStats[24], animGroup[24]; - int carsCanDrive; - CPedModelInfo *mi; - int animGroupId; - - if(sscanf(line, "%d %s %s %s %s %s %x", - &id, model, txd, - pedType, pedStats, animGroup, &carsCanDrive) != 7) - return; - - mi = CModelInfo::AddPedModel(id); - mi->SetName(model); - mi->SetTexDictionary(txd); - mi->SetColModel(&CTempColModels::ms_colModelPed1); - mi->m_pedType = CPedType::FindPedType(pedType); - mi->m_pedStatType = CPedStats::GetPedStatType(pedStats); - for(animGroupId = 0; animGroupId < NUM_ANIM_ASSOC_GROUPS; animGroupId++) - if(strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)animGroupId)) == 0) - break; - mi->m_animGroup = animGroupId; - - // ??? - CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1); -} - -int -CFileLoader::LoadPathHeader(const char *line, char *type) -{ - int id; - char modelname[32]; - - sscanf(line, "%s %d %s", type, &id, modelname); - return id; -} - -void -CFileLoader::LoadPedPathNode(const char *line, int id, int node) -{ - int type, next, cross; - float x, y, z, width; - - sscanf(line, "%d %d %d %f %f %f %f", &type, &next, &cross, &x, &y, &z, &width); - ThePaths.StoreNodeInfoPed(id, node, type, next, x, y, z, 0, !!cross); -} - -void -CFileLoader::LoadCarPathNode(const char *line, int id, int node) -{ - int type, next, cross, numLeft, numRight; - float x, y, z, width; - - sscanf(line, "%d %d %d %f %f %f %f %d %d", &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight); - ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight); -} - - -void -CFileLoader::Load2dEffect(const char *line) -{ - int id, r, g, b, a, type; - float x, y, z; - char corona[32], shadow[32]; - int shadowIntens, lightType, roadReflection, flare, flags, probability; - CBaseModelInfo *mi; - C2dEffect *effect; - char *p; - - sscanf(line, "%d %f %f %f %d %d %d %d %d", &id, &x, &y, &z, &r, &g, &b, &a, &type); - - CTxdStore::PushCurrentTxd(); - CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle")); - - mi = CModelInfo::GetModelInfo(id); - effect = CModelInfo::Get2dEffectStore().alloc(); - mi->Add2dEffect(effect); - effect->pos = CVector(x, y, z); - effect->col = CRGBA(r, g, b, a); - effect->type = type; - - switch(effect->type){ - case EFFECT_LIGHT: - while(*line++ != '"'); - p = corona; - while(*line != '"') *p++ = *line++; - *p = '\0'; - line++; - - while(*line++ != '"'); - p = shadow; - while(*line != '"') *p++ = *line++; - *p = '\0'; - line++; - - sscanf(line, "%f %f %f %f %d %d %d %d %d", - &effect->light.dist, - &effect->light.range, - &effect->light.size, - &effect->light.shadowRange, - &shadowIntens, &lightType, &roadReflection, &flare, &flags); - effect->light.corona = RwTextureRead(corona, nil); - effect->light.shadow = RwTextureRead(shadow, nil); - effect->light.shadowIntensity = shadowIntens; - effect->light.lightType = lightType; - effect->light.roadReflection = roadReflection; - effect->light.flareType = flare; - // TODO: check out the flags - if(flags & 4) - flags &= ~2; - effect->light.flags = flags; - break; - - case EFFECT_PARTICLE: - sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f", - &id, &x, &y, &z, &r, &g, &b, &a, &type, - &effect->particle.particleType, - &effect->particle.dir.x, - &effect->particle.dir.y, - &effect->particle.dir.z, - &effect->particle.scale); - break; - - case EFFECT_ATTRACTOR: - sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %d", - &id, &x, &y, &z, &r, &g, &b, &a, &type, - &flags, - &effect->attractor.dir.x, - &effect->attractor.dir.y, - &effect->attractor.dir.z, - &probability); - effect->attractor.flags = flags; - effect->attractor.probability = probability; - break; - } - - CTxdStore::PopCurrentTxd(); -} - -void -CFileLoader::LoadScene(const char *filename) -{ - enum { - NONE, - INST, - ZONE, - CULL, - PICK, - PATH, - }; - char *line; - int fd; - int section; - int pathIndex; - char pathTypeStr[20]; - - section = NONE; - pathIndex = -1; - debug("Creating objects from %s...\n", filename); - - fd = CFileMgr::OpenFile(filename, "rb"); - for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ - if(*line == '\0' || *line == '#') - continue; - - if(section == NONE){ - if(strncmp(line, "inst", 4) == 0) section = INST; - else if(strncmp(line, "zone", 4) == 0) section = ZONE; - else if(strncmp(line, "cull", 4) == 0) section = CULL; - else if(strncmp(line, "pick", 4) == 0) section = PICK; - else if(strncmp(line, "path", 4) == 0) section = PATH; - }else if(strncmp(line, "end", 3) == 0){ - section = NONE; - }else switch(section){ - case INST: - LoadObjectInstance(line); - break; - case ZONE: - LoadZone(line); - break; - case CULL: - LoadCullZone(line); - break; - case PICK: - // unused - LoadPickup(line); - break; - case PATH: - // unfinished in the game - if(pathIndex == -1){ - LoadPathHeader(line, pathTypeStr); - // type not set - pathIndex = 0; - }else{ - // nodes not loaded - pathIndex++; - if(pathIndex == 12) - pathIndex = -1; - } - break; - } - } - CFileMgr::CloseFile(fd); - - debug("Finished loading IPL\n"); -} - -void -CFileLoader::LoadObjectInstance(const char *line) -{ - int id; - char name[24]; - RwV3d trans, scale, axis; - float angle; - CSimpleModelInfo *mi; - RwMatrix *xform; - CEntity *entity; - - if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f", - &id, name, - &trans.x, &trans.y, &trans.z, - &scale.x, &scale.y, &scale.z, - &axis.x, &axis.y, &axis.z, &angle) != 12) - return; - - mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); - if(mi == nil) - return; - assert(mi->IsSimple()); - - angle = -RADTODEG(2.0f * acosf(angle)); - xform = RwMatrixCreate(); - RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE); - RwMatrixTranslate(xform, &trans, rwCOMBINEPOSTCONCAT); - - if(mi->GetObjectID() == -1){ - if(ThePaths.IsPathObject(id)){ - entity = new CTreadable; - ThePaths.RegisterMapObject((CTreadable*)entity); - }else - entity = new CBuilding; - entity->SetModelIndexNoCreate(id); - entity->GetMatrix() = CMatrix(xform); - entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); - if(mi->IsSimple()){ - if(mi->m_isBigBuilding) - entity->SetupBigBuilding(); - if(mi->m_isSubway) - entity->bIsSubway = true; - } - if(mi->GetLargestLodDistance() < 2.0f) - entity->bIsVisible = false; - CWorld::Add(entity); - }else{ - entity = new CDummyObject; - entity->SetModelIndexNoCreate(id); - entity->GetMatrix() = CMatrix(xform); - CWorld::Add(entity); - if(IsGlass(entity->GetModelIndex())) - entity->bIsVisible = false; - entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); - } - - RwMatrixDestroy(xform); -} - -void -CFileLoader::LoadZone(const char *line) -{ - char name[24]; - int type, level; - float minx, miny, minz; - float maxx, maxy, maxz; - - if(sscanf(line, "%s %d %f %f %f %f %f %f %d", name, &type, &minx, &miny, &minz, &maxx, &maxy, &maxz, &level) == 9) - CTheZones::CreateZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level); -} - -void -CFileLoader::LoadCullZone(const char *line) -{ - CVector pos; - float minx, miny, minz; - float maxx, maxy, maxz; - int flags; - int wantedLevelDrop = 0; - - sscanf(line, "%f %f %f %f %f %f %f %f %f %d %d", - &pos.x, &pos.y, &pos.z, - &minx, &miny, &minz, - &maxx, &maxy, &maxz, - &flags, &wantedLevelDrop); - CCullZones::AddCullZone(pos, minx, maxx, miny, maxy, minz, maxz, flags, wantedLevelDrop); -} - -// unused -void -CFileLoader::LoadPickup(const char *line) -{ - int id; - float x, y, z; - - sscanf(line, "%d %f %f %f", &id, &x, &y, &z); -} - -void -CFileLoader::LoadMapZones(const char *filename) -{ - enum { - NONE, - INST, - ZONE, - CULL, - PICK, - PATH, - }; - char *line; - int fd; - int section; - - section = NONE; - debug("Creating zones from %s...\n", filename); - - fd = CFileMgr::OpenFile(filename, "rb"); - for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ - if(*line == '\0' || *line == '#') - continue; - - if(section == NONE){ - if(strncmp(line, "zone", 4) == 0) section = ZONE; - }else if(strncmp(line, "end", 3) == 0){ - section = NONE; - }else switch(section){ - case ZONE: { - char name[24]; - int type, level; - float minx, miny, minz; - float maxx, maxy, maxz; - if(sscanf(line, "%s %d %f %f %f %f %f %f %d", - &name, &type, - &minx, &miny, &minz, - &maxx, &maxy, &maxz, - &level) == 9) - CTheZones::CreateMapZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level); - } - break; - } - } - CFileMgr::CloseFile(fd); - - debug("Finished loading IPL\n"); -} - - -STARTPATCHES - InjectHook(0x476290, CFileLoader::LoadLevel, PATCH_JUMP); - - InjectHook(0x476520, CFileLoader::LoadCollisionFromDatFile, PATCH_JUMP); - InjectHook(0x4761D0, CFileLoader::LoadLine, PATCH_JUMP); - InjectHook(0x4765B0, CFileLoader::LoadTexDictionary, PATCH_JUMP); - InjectHook(0x478B20, CFileLoader::LoadCollisionFile, PATCH_JUMP); - InjectHook(0x478C20, CFileLoader::LoadCollisionModel, PATCH_JUMP); - InjectHook(0x476750, CFileLoader::LoadModelFile, PATCH_JUMP); - InjectHook(0x476810, (void (*)(const char*))CFileLoader::LoadClumpFile, PATCH_JUMP); - InjectHook(0x476990, (bool (*)(RwStream*,uint32))CFileLoader::LoadClumpFile, PATCH_JUMP); - InjectHook(0x476A20, CFileLoader::StartLoadClumpFile, PATCH_JUMP); - InjectHook(0x476A70, CFileLoader::FinishLoadClumpFile, PATCH_JUMP); - InjectHook(0x476930, CFileLoader::LoadAtomicFile, PATCH_JUMP); - InjectHook(0x4767C0, CFileLoader::LoadAtomicFile2Return, PATCH_JUMP); - InjectHook(0x476630, CFileLoader::AddTexDictionaries, PATCH_JUMP); - - InjectHook(0x476AC0, CFileLoader::LoadObjectTypes, PATCH_JUMP); - InjectHook(0x477040, CFileLoader::LoadObject, PATCH_JUMP); - InjectHook(0x4774B0, CFileLoader::LoadTimeObject, PATCH_JUMP); - InjectHook(0x477920, CFileLoader::LoadClumpObject, PATCH_JUMP); - InjectHook(0x477990, CFileLoader::LoadVehicleObject, PATCH_JUMP); - InjectHook(0x477DE0, CFileLoader::LoadPedObject, PATCH_JUMP); - InjectHook(0x477ED0, CFileLoader::LoadPathHeader, PATCH_JUMP); - InjectHook(0x477FF0, CFileLoader::LoadCarPathNode, PATCH_JUMP); - InjectHook(0x477F00, CFileLoader::LoadPedPathNode, PATCH_JUMP); - InjectHook(0x4780E0, CFileLoader::Load2dEffect, PATCH_JUMP); - - InjectHook(0x478370, CFileLoader::LoadScene, PATCH_JUMP); - InjectHook(0x4786B0, CFileLoader::LoadObjectInstance, PATCH_JUMP); - InjectHook(0x478A00, CFileLoader::LoadZone, PATCH_JUMP); - InjectHook(0x478A90, CFileLoader::LoadCullZone, PATCH_JUMP); - - InjectHook(0x478550, CFileLoader::LoadMapZones, PATCH_JUMP); -ENDPATCHES diff --git a/src/FileLoader.h b/src/FileLoader.h deleted file mode 100644 index f9121ace..00000000 --- a/src/FileLoader.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -class CFileLoader -{ - static char ms_line[256]; -public: - static void LoadLevel(const char *filename); - static void LoadCollisionFromDatFile(int currlevel); - static char *LoadLine(int fd); - static RwTexDictionary *LoadTexDictionary(const char *filename); - static void LoadCollisionFile(const char *filename); - static void LoadCollisionModel(uint8 *buf, CColModel &model, char *name); - static void LoadModelFile(const char *filename); - static RpAtomic *FindRelatedModelInfoCB(RpAtomic *atomic, void *data); - static void LoadClumpFile(const char *filename); - static bool LoadClumpFile(RwStream *stream, uint32 id); - static bool StartLoadClumpFile(RwStream *stream, uint32 id); - static bool FinishLoadClumpFile(RwStream *stream, uint32 id); - static bool LoadAtomicFile(RwStream *stream, uint32 id); - static RpAtomic *SetRelatedModelInfoCB(RpAtomic *atomic, void *data); - static RpClump *LoadAtomicFile2Return(const char *filename); - static void AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src); - - static void LoadObjectTypes(const char *filename); - static void LoadObject(const char *line); - static void LoadTimeObject(const char *line); - static void LoadClumpObject(const char *line); - static void LoadVehicleObject(const char *line); - static void LoadPedObject(const char *line); - static int LoadPathHeader(const char *line, char *type); - static void LoadPedPathNode(const char *line, int id, int node); - static void LoadCarPathNode(const char *line, int id, int node); - static void Load2dEffect(const char *line); - - static void LoadScene(const char *filename); - static void LoadObjectInstance(const char *line); - static void LoadZone(const char *line); - static void LoadCullZone(const char *line); - static void LoadPickup(const char *line); - - static void LoadMapZones(const char *filename); -}; diff --git a/src/FileMgr.cpp b/src/FileMgr.cpp deleted file mode 100644 index 954fcdef..00000000 --- a/src/FileMgr.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#define _CRT_SECURE_NO_WARNINGS -#include -#include -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" - -const char *_psGetUserFilesFolder(); - -/* - * Windows FILE is BROKEN for GTA. - * - * We need to support mapping between LF and CRLF for text files - * but we do NOT want to end the file at the first sight of a SUB character. - * So here is a simple implementation of a FILE interface that works like GTA expects. - */ - -struct myFILE -{ - bool isText; - FILE *file; -}; - -#define NUMFILES 20 -static myFILE myfiles[NUMFILES]; - -/* Force file to open as binary but remember if it was text mode */ -static int -myfopen(const char *filename, const char *mode) -{ - int fd; - char realmode[10], *p; - - for(fd = 1; fd < NUMFILES; fd++) - if(myfiles[fd].file == nil) - goto found; - return 0; // no free fd -found: - myfiles[fd].isText = strchr(mode, 'b') == nil; - p = realmode; - while(*mode) - if(*mode != 't' && *mode != 'b') - *p++ = *mode++; - else - mode++; - *p++ = 'b'; - *p = '\0'; - myfiles[fd].file = fopen(filename, realmode); - if(myfiles[fd].file == nil) - return 0; - return fd; -} - -static int -myfclose(int fd) -{ - int ret; - assert(fd < NUMFILES); - if(myfiles[fd].file){ - ret = fclose(myfiles[fd].file); - myfiles[fd].file = nil; - return ret; - } - return EOF; -} - -static int -myfgetc(int fd) -{ - int c; - c = fgetc(myfiles[fd].file); - if(myfiles[fd].isText && c == 015){ - /* translate CRLF to LF */ - c = fgetc(myfiles[fd].file); - if(c == 012) - return c; - ungetc(c, myfiles[fd].file); - return 015; - } - return c; -} - -static int -myfputc(int c, int fd) -{ - /* translate LF to CRLF */ - if(myfiles[fd].isText && c == 012) - fputc(015, myfiles[fd].file); - return fputc(c, myfiles[fd].file); -} - -static char* -myfgets(char *buf, int len, int fd) -{ - int c; - char *p; - - p = buf; - len--; // NUL byte - while(len--){ - c = myfgetc(fd); - if(c == EOF){ - if(p == buf) - return nil; - break; - } - *p++ = c; - if(c == '\n') - break; - } - *p = '\0'; - return buf; -} - -static int -myfread(void *buf, size_t elt, size_t n, int fd) -{ - if(myfiles[fd].isText){ - char *p; - size_t i; - int c; - - n *= elt; - p = (char*)buf; - for(i = 0; i < n; i++){ - c = myfgetc(fd); - if(c == EOF) - break; - *p++ = c; - } - return i / elt; - } - return fread(buf, elt, n, myfiles[fd].file); -} - -static int -myfwrite(void *buf, size_t elt, size_t n, int fd) -{ - if(myfiles[fd].isText){ - char *p; - size_t i; - int c; - - n *= elt; - p = (char*)buf; - for(i = 0; i < n; i++){ - c = *p++; - myfputc(c, fd); - if(feof(myfiles[fd].file)) // is this right? - break; - } - return i / elt; - } - return fwrite(buf, elt, n, myfiles[fd].file); -} - -static int -myfseek(int fd, long offset, int whence) -{ - return fseek(myfiles[fd].file, offset, whence); -} - -static int -myfeof(int fd) -{ - return feof(myfiles[fd].file); -// return ferror(myfiles[fd].file); -} - - -char *CFileMgr::ms_rootDirName = (char*)0x5F18F8; -char *CFileMgr::ms_dirName = (char*)0x713CA8; - -void -CFileMgr::Initialise(void) -{ - _getcwd(ms_rootDirName, 128); - strcat(ms_rootDirName, "\\"); -} - -void -CFileMgr::ChangeDir(const char *dir) -{ - if(*dir == '\\'){ - strcpy(ms_dirName, ms_rootDirName); - dir++; - } - if(*dir != '\0'){ - strcat(ms_dirName, dir); - // BUG in the game it seems, it's off by one - if(dir[strlen(dir)-1] != '\\') - strcat(ms_dirName, "\\"); - } - chdir(ms_dirName); -} - -void -CFileMgr::SetDir(const char *dir) -{ - strcpy(ms_dirName, ms_rootDirName); - if(*dir != '\0'){ - strcat(ms_dirName, dir); - // BUG in the game it seems, it's off by one - if(dir[strlen(dir)-1] != '\\') - strcat(ms_dirName, "\\"); - } - chdir(ms_dirName); -} - -void -CFileMgr::SetDirMyDocuments(void) -{ - SetDir(""); // better start at the root if user directory is relative - chdir(_psGetUserFilesFolder()); -} - -int -CFileMgr::LoadFile(const char *file, uint8 *buf, int unused, const char *mode) -{ - int fd; - int n, len; - - fd = myfopen(file, mode); - if(fd == 0) - return 0; - len = 0; - do{ - n = myfread(buf + len, 1, 0x4000, fd); - if(n < 0) - return -1; - len += n; - }while(n == 0x4000); - buf[len] = 0; - myfclose(fd); - return len; -} - -int -CFileMgr::OpenFile(const char *file, const char *mode) -{ - return myfopen(file, mode); -} - -int -CFileMgr::OpenFileForWriting(const char *file) -{ - return OpenFile(file, "wb"); -} - -int -CFileMgr::Read(int fd, char *buf, int len) -{ - return myfread(buf, 1, len, fd); -} - -int -CFileMgr::Write(int fd, char *buf, int len) -{ - return myfwrite(buf, 1, len, fd); -} - -bool -CFileMgr::Seek(int fd, int offset, int whence) -{ - return !!myfseek(fd, offset, whence); -} - -bool -CFileMgr::ReadLine(int fd, char *buf, int len) -{ - return myfgets(buf, len, fd) != nil; -} - -int -CFileMgr::CloseFile(int fd) -{ - return myfclose(fd); -} - -int -CFileMgr::GetErrorReadWrite(int fd) -{ - return myfeof(fd); -} - -STARTPATCHES - InjectHook(0x478F80, CFileMgr::Initialise, PATCH_JUMP); - InjectHook(0x478FB0, CFileMgr::ChangeDir, PATCH_JUMP); - InjectHook(0x479020, CFileMgr::SetDir, PATCH_JUMP); - InjectHook(0x479080, CFileMgr::SetDirMyDocuments, PATCH_JUMP); - InjectHook(0x479090, CFileMgr::LoadFile, PATCH_JUMP); - InjectHook(0x479100, CFileMgr::OpenFile, PATCH_JUMP); - InjectHook(0x479120, CFileMgr::OpenFileForWriting, PATCH_JUMP); - InjectHook(0x479140, CFileMgr::Read, PATCH_JUMP); - InjectHook(0x479160, CFileMgr::Write, PATCH_JUMP); - InjectHook(0x479180, CFileMgr::Seek, PATCH_JUMP); - InjectHook(0x4791D0, CFileMgr::ReadLine, PATCH_JUMP); - InjectHook(0x479200, CFileMgr::CloseFile, PATCH_JUMP); - InjectHook(0x479210, CFileMgr::GetErrorReadWrite, PATCH_JUMP); -ENDPATCHES diff --git a/src/FileMgr.h b/src/FileMgr.h deleted file mode 100644 index bab86e38..00000000 --- a/src/FileMgr.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -class CFileMgr -{ - static char *ms_rootDirName; //[128]; - static char *ms_dirName; //[128]; -public: - static void Initialise(void); - static void ChangeDir(const char *dir); - static void SetDir(const char *dir); - static void SetDirMyDocuments(void); - static int LoadFile(const char *file, uint8 *buf, int unused, const char *mode); - static int OpenFile(const char *file, const char *mode); - static int OpenFileForWriting(const char *file); - static int Read(int fd, char *buf, int len); - static int Write(int fd, char *buf, int len); - static bool Seek(int fd, int offset, int whence); - static bool ReadLine(int fd, char *buf, int len); - static int CloseFile(int fd); - static int GetErrorReadWrite(int fd); -}; diff --git a/src/Fire.cpp b/src/Fire.cpp deleted file mode 100644 index 05d72199..00000000 --- a/src/Fire.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Fire.h" - -WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); } \ No newline at end of file diff --git a/src/Fire.h b/src/Fire.h deleted file mode 100644 index c7f83fd8..00000000 --- a/src/Fire.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "common.h" -#include "Entity.h" - -class CFire -{ - char m_bIsOngoing; - char m_bExists; - char m_bPropogationFlag; - char m_bAudioSet; - CVector m_vecPos; - CEntity *m_pEntity; - CEntity *m_pSource; - int m_nExtinguishTime; - int m_nStartTime; - int field_20; - int field_24; - int field_28; - float field_2C; - -public: - void Extinguish(void); -}; \ No newline at end of file diff --git a/src/Frontend.cpp b/src/Frontend.cpp deleted file mode 100644 index fdb2420b..00000000 --- a/src/Frontend.cpp +++ /dev/null @@ -1,2353 +0,0 @@ -#define DIRECTINPUT_VERSION 0x0800 -#include -#include "common.h" -#include "patcher.h" -#include "win.h" -#include "Frontend.h" -#include "Font.h" -#include "Pad.h" -#include "Text.h" -#include "main.h" -#include "Timer.h" -#include "Game.h" -#include "DMAudio.h" -#include "MusicManager.h" -#include "FileMgr.h" -#include "Streaming.h" -#include "TxdStore.h" -#include "General.h" -#include "PCSave.h" -#include "Script.h" -#include "Camera.h" -#include "MenuScreens.h" -#include "ControllerConfig.h" -#include "Vehicle.h" -#include "MBlur.h" -#include "PlayerSkin.h" - -int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; -int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92; -int8 &CMenuManager::m_DisplayControllerOnFoot = *(int8*)0x95CD8D; -int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58; -int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C; -int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60; -int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54; -int8 &CMenuManager::m_PrefsSpeakers = *(int8*)0x95CD7E; -int8 &CMenuManager::m_ControlMethod = *(int8*)0x8F5F7C; -int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74; -int8 &CMenuManager::m_PrefsLanguage = *(int8*)0x941238; - -bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64; -bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4; -bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A; - -int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23; -int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4; -int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; -int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; -float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4; -int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC; -int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; -int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; - -uint8 *CMenuManager::m_PrefsSkinFile = (uint8*)0x5F2E74; - -CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; - -// Move this somewhere else. -float lodMultiplier = *(float*)0x5F726C; - -// Stuff not in CMenuManager: -int VibrationTime; -char* pEditString; -int32 pControlEdit; -int8 DisplayComboButtonErrMsg; -bool MouseButtonJustClicked; -bool JoyButtonJustClicked; - -// Frontend inputs. -bool GetPadBack(); -bool GetPadExitEnter(); -bool GetPadForward(); -bool GetPadMoveUp(); -bool GetPadMoveDown(); -bool GetPadMoveLeft(); -bool GetPadMoveRight(); -bool GetMouseForward(); -bool GetMouseBack(); -bool GetMousePos(); -bool GetMouseMoveLeft(); -bool GetMouseMoveRight(); -bool GetPadInput(); -bool GetMouseInput(); - -char *FrontendFilenames[] = { - "fe2_mainpanel_ul", - "fe2_mainpanel_ur", - "fe2_mainpanel_dl", - "fe2_mainpanel_dr", - "fe2_mainpanel_dr2", - "fe2_tabactive", - "fe_iconbrief", - "fe_iconstats", - "fe_iconcontrols", - "fe_iconsave", - "fe_iconaudio", - "fe_icondisplay", - "fe_iconlanguage", - "fe_controller", - "fe_controllersh", - "fe_arrows1", - "fe_arrows2", - "fe_arrows3", - "fe_arrows4", - "fe_radio1", // HEAD_RADIO - "fe_radio2", // DOUBLE_CLEF - "fe_radio5", // JAH_RADIO - "fe_radio7", // RISE_FM - "fe_radio8", // LIPS_106 - "fe_radio3", // GAME_FM - "fe_radio4", // MSX_FM - "fe_radio6", // FLASHBACK - "fe_radio9", // CHATTERBOX -}; - -char *MenuFilenames[] = { - "connection24", "", - "findgame24", "", - "hostgame24", "", - "mainmenu24", "", - "Playersetup24", "", - "singleplayer24", "", - "multiplayer24", "", - "dmalogo128", "dmalogo128m", - "gtaLogo128", "gtaLogo128", - "rockstarLogo128", "rockstarlogo128m", - "gamespy256", "gamespy256a", - "mouse", "mousetimera", - "mousetimer", "mousetimera", - "mp3logo", "mp3logoA", - "downOFF", "buttonA", - "downON", "buttonA", - "upOFF", "buttonA", - "upON", "buttonA", - "gta3logo256", "gta3logo256m", - nil, nil -}; - -#if 1 -WRAPPER void CMenuManager::BuildStatLine(char *, void *, uint16, void *) { EAXJMP(0x483870); } -#else -void CMenuManager::BuildStatLine(char *, void *, uint16, void *) -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); } -#else -void CMenuManager::CentreMousePointer() -{ - tagPOINT Point; - - if (SCREEN_WIDTH * 0.5f == 0.0f && 0.0f == SCREEN_HEIGHT * 0.5f) { - Point.x = SCREEN_WIDTH / 2; - Point.y = SCREEN_HEIGHT / 2; - ClientToScreen(PSGLOBAL(window), &Point); - SetCursorPos(Point.x, Point.y); - - PSGLOBAL(lastMousePos.x) = SCREEN_WIDTH / 2; - PSGLOBAL(lastMousePos.y) = SCREEN_HEIGHT / 2; - } -} -#endif - -#if 1 -WRAPPER void CMenuManager::CheckCodesForControls(int, int) { EAXJMP(0x48A950); } -#else -void CMenuManager::CheckCodesForControls() -{ - -} -#endif - -#if 0 -WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); } -#else -bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2) -{ - return m_nMousePosX > x1 && m_nMousePosX < x2 && - m_nMousePosY > y1 && m_nMousePosY < y2; -} -#endif - -void CMenuManager::CheckSliderMovement(int value) -{ - float fBrightness = 0.0f; - float fDrawDistance = 0.0f; - float fRadioVolume = 0.0f; - float fSfxVolume = 0.0f; - float fMouseSens = 0.0f; - - switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) { - case MENUACTION_BRIGHTNESS: - fBrightness = m_PrefsBrightness + (value * (512.0f) / 16.0f); - - if (fBrightness > 511.0f) - fBrightness = 511.0f; - else if (fBrightness < 0.0f) - fBrightness = 0.0f; - - m_PrefsBrightness = fBrightness; - SaveSettings(); - break; - case MENUACTION_DRAWDIST: - fDrawDistance = m_PrefsLOD + (value * (1.8f - 0.8f) / 16.0f); - - if (fDrawDistance > 1.8f) - fDrawDistance = 1.8f; - else if (fDrawDistance < 0.8f) - fDrawDistance = 0.8f; - - m_PrefsLOD = fDrawDistance; - SaveSettings(); - break; - case MENUACTION_MUSICVOLUME: - fRadioVolume = m_PrefsMusicVolume + (value * (128.0f) / 16.0f); - - if (fRadioVolume > 127.0f) - fRadioVolume = 127.0f; - else if (fRadioVolume < 0.0f) - fRadioVolume = 0.0f; - - m_PrefsMusicVolume = fRadioVolume; - DMAudio.SetMusicMasterVolume(fRadioVolume); - SaveSettings(); - break; - case MENUACTION_SFXVOLUME: - fSfxVolume = m_PrefsSfxVolume + (value * (128.0f) / 16.0f); - - if (fSfxVolume > 127) - fSfxVolume = 127; - else if (fSfxVolume < 0.0f) - fSfxVolume = 0.0f; - - m_PrefsSfxVolume = fSfxVolume; - DMAudio.SetEffectsMasterVolume(fSfxVolume); - SaveSettings(); - break; - case MENUACTION_MOUSESENS: - fMouseSens = TheCamera.m_fMouseAccelHorzntl + (value * (0.005f - 0.0003125f) / 16.0f); - - if (fMouseSens > 0.005f) - fMouseSens = 0.005f; - else if (fMouseSens < 0.0003125f) - fMouseSens = 0.0003125f; - - TheCamera.m_fMouseAccelHorzntl = fMouseSens; - - // BUG: game doesn't set Y Axis. - TheCamera.m_fMouseAccelVertical = fMouseSens; - SaveSettings(); - break; - }; -} - -#if 1 -WRAPPER int CMenuManager::CostructStatLine(int) { EAXJMP(0x482800); } -#else -int CMenuManager::CostructStatLine(int) -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); } -#else -void CMenuManager::DisplayHelperText() -{ - static int32 AlphaText = 255; - static int32 Time = 0; - - if (m_nHelperTextMsgId && m_nHelperTextMsgId != 1) { - if (CTimer::GetTimeInMillisecondsPauseMode() - Time > 10) { - Time = CTimer::GetTimeInMillisecondsPauseMode(); - m_nHelperTextAlpha -= 2; - - if (AlphaText < 1) - ResetHelperText(); - - AlphaText = m_nHelperTextAlpha > 255 ? 255 : m_nHelperTextAlpha; - } - } - - wchar *HelperTextToPrint = nil; - // TODO: name this cases? - switch (m_nHelperTextMsgId) { - case 0: - HelperTextToPrint = TheText.Get("FET_MIG"); - break; - case 1: - HelperTextToPrint = TheText.Get("FET_APP"); - break; - case 2: - HelperTextToPrint = TheText.Get("FET_HRD"); - break; - case 3: - HelperTextToPrint = TheText.Get("FET_RSO"); - break; - case 4: - HelperTextToPrint = TheText.Get("FET_RSC"); - break; - default: - break; - }; - - CFont::SetAlignment(ALIGN_CENTER); - CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f)); - CFont::SetFontStyle(FONT_HEADING); - CFont::SetDropColor(CRGBA(0, 0, 0, AlphaText)); - CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); - CFont::SetColor(CRGBA(255, 255, 255, AlphaText)); - - CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_SCALE_FROM_BOTTOM(120.0f), HelperTextToPrint); -} -#endif - -#if 0 -WRAPPER float CMenuManager::DisplaySlider(float, float, float, float, float, float) { EAXJMP(0x488420); } -#else -float CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightSize, float rectSize, float progress) -{ - CRGBA color; - float sizeRange; - - float input = 0.0f; - for (int i = 0; i < 16; i++) { - input = i * rectSize/16.0f + x; - - if (i/16.0f + 1/32.0f < progress) - color = CRGBA(255, 217, 106, FadeIn(255)); - else - color = CRGBA(185, 120, 0, FadeIn(255)); - - sizeRange = max(leftSize, rightSize); - - float _x = i * rectSize/16.0f + x; - float _y = y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f; - float _w = SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x; - float _h = y + sizeRange; - float _s = SCREEN_SCALE_X(2.0f); - CSprite2d::DrawRect(CRect(_x + _s, _y + _s, _w + _s, _h + _s), CRGBA(0, 0, 0, FadeIn(255))); // Shadow - CSprite2d::DrawRect(CRect(i * rectSize/16.0f + x, y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f, SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x, y + sizeRange), color); - }; - return input; -} -#endif - -#if 0 -WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); } -#else -void CMenuManager::DoSettingsBeforeStartingAGame() -{ - CCamera::m_bUseMouse3rdPerson = m_ControlMethod == 0; - if (m_PrefsVsyncDisp != m_PrefsVsync) - m_PrefsVsync = m_PrefsVsyncDisp; - - m_bStartGameLoading = true; - - ShutdownJustMenu(); - UnloadTextures(); - DMAudio.SetEffectsFadeVol(0); - DMAudio.SetMusicFadeVol(0); - DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); -} -#endif - -#if 0 -WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); } -#else -void CMenuManager::Draw() -{ - CFont::SetBackgroundOff(); - CFont::SetPropOn(); - CFont::SetCentreOff(); - CFont::SetJustifyOn(); - CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f)); - CFont::SetRightJustifyWrap(0.0f); - CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); - - switch (m_nCurrScreen) { - case MENUPAGE_STATS: - PrintStats(); - break; - case MENUPAGE_BRIEFS: - PrintBriefs(); - break; - case MENUPAGE_CONTROLLER_DEBUG: - DrawControllerScreenExtraText(0, 350, 20); - break; - } - - // Header. - if (aScreens[m_nCurrScreen].m_ScreenName[0]) { - CFont::SetDropShadowPosition(0); - CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255))); - CFont::SetRightJustifyOn(); - CFont::SetFontStyle(FONT_HEADING); - CFont::SetScale(SCREEN_SCALE_X(MENUHEADER_WIDTH), SCREEN_SCALE_Y(MENUHEADER_HEIGHT)); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName)); - } - - // Action text. - wchar *str; - if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { - switch (m_nCurrScreen) { - case MENUPAGE_LOAD_SLOT_CONFIRM: - if (m_bGameNotLoaded) - str = TheText.Get("FES_LCG"); - else - str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); - break; - case MENUPAGE_SAVE_OVERWRITE_CONFIRM: - if (Slots[m_nCurrSaveSlot] == 1) - str = TheText.Get("FESZ_QZ"); - else - str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); - break; - case MENUPAGE_EXIT: - if (m_bGameNotLoaded) - str = TheText.Get("FEQ_SRW"); - else - str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); - break; - default: - str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); - break; - }; - - CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); - CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); - CFont::SetFontStyle(FONT_BANK); - CFont::SetScale(SCREEN_SCALE_X(MENUACTION_WIDTH), SCREEN_SCALE_Y(MENUACTION_HEIGHT)); - CFont::SetAlignment(ALIGN_LEFT); - CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); - CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str); - } - - for (int i = 0; i < MENUROWS; ++i) { - if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0]) { - wchar *textToPrint[MENUCOLUMNS] = { nil, nil }; - bool Locked = false; - - if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot <= SAVESLOT_8) { - textToPrint[MENUCOLUMN_LEFT] = GetNameOfSavedGame(i - 1); - textToPrint[MENUCOLUMN_RIGHT] = GetSavedGameDateAndTime(i - 1); - - if (!textToPrint[MENUCOLUMN_LEFT][0]) { - sprintf(gString, "FEM_SL%d", i); - textToPrint[MENUCOLUMN_LEFT] = TheText.Get(gString); - } - } - else { - textToPrint[MENUCOLUMN_LEFT] = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName); - - if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_SCREENRES) { - if (m_bGameNotLoaded) - Locked = false; - else - Locked = true; - } - } - - switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { - case MENUACTION_CTRLVIBRATION: - break; - case MENUACTION_CTRLCONFIG: - switch (CPad::GetPad(0)->Mode) { - case 0: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF1"); - break; - case 1: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF2"); - break; - case 2: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF3"); - break; - case 3: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF4"); - break; - }; - break; - case MENUACTION_CTRLDISPLAY: - break; - case MENUACTION_FRAMESYNC: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsVsyncDisp ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_FRAMELIMIT: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsFrameLimiter ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_TRAILS: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CMBlur::BlurOn ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_SUBTITLES: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsShowSubtitles ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_WIDESCREEN: -#ifndef ASPECT_RATIO_SCALE - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsUseWideScreen ? "FEM_ON" : "FEM_OFF"); -#else - switch (m_PrefsUseWideScreen) { - case AR_AUTO: - textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"AUTO"; - break; - case AR_4_3: - textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"4:3"; - break; - case AR_16_9: - textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9"; - break; - }; -#endif - break; - case MENUACTION_RADIO: - sprintf(gString, "FEA_FM%d", m_PrefsRadioStation); - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gString); - break; - case MENUACTION_SETDBGFLAG: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_SWITCHBIGWHITEDEBUGLIGHT: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_INVVERT: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(MousePointerStateHelper.bInvertVertically ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_SCREENRES: - { - char *res = _psGetVideoModeList()[m_nDisplayVideoMode]; - - if (!res) - res = ""; - - AsciiToUnicode(res, gUString); - textToPrint[MENUCOLUMN_RIGHT] = gUString; - } - break; - case MENUACTION_AUDIOHW: - if (m_nPrefsAudio3DProviderIndex == -1) - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH"); - else { - char *provider = MusicManager.Get3DProviderName(m_nPrefsAudio3DProviderIndex); - AsciiToUnicode(provider, gUString); - textToPrint[MENUCOLUMN_RIGHT] = gUString; - } - break; - case MENUACTION_SPEAKERCONF: - if (m_nPrefsAudio3DProviderIndex == -1) - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH"); - else { - switch (m_PrefsSpeakers) { - case 0: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_2SP"); - break; - case 1: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_EAR"); - break; - case 2: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_4SP"); - break; - }; - } - break; - case MENUACTION_CTRLMETHOD: - switch (m_ControlMethod) { - case 0: - textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_SCN"); - break; - case 1: - textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_CCN"); - break; - }; - break; - case MENUACTION_DYNAMICACOUSTIC: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF"); - break; - case MENUACTION_MOUSESTEER: - textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF"); - break; - }; - - CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); - CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); - CFont::SetCentreSize(SCREEN_WIDTH); - CFont::SetWrapx(SCREEN_WIDTH); - CFont::SetRightJustifyWrap(-SCREEN_WIDTH); - - // Set alignment. - CVector2D vecPositions = { 0.0f, 0.0f }; - float fVerticalSpacing; - float fBarSize; - - int SavePageSlot = - m_nCurrScreen == MENUPAGE_CHOOSE_LOAD_SLOT || - m_nCurrScreen == MENUPAGE_CHOOSE_DELETE_SLOT || - m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT; - - if (SavePageSlot) { - CFont::SetFontStyle(FONT_BANK); - CFont::SetAlignment(ALIGN_LEFT); - CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f)); - fVerticalSpacing = MENUCOLUMN_SPACING_MIN; - fBarSize = MENUSELECT_BOX_MIN; - - vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_SAVE_X); - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_SAVE_Y); - } - else { - CFont::SetFontStyle(FONT_HEADING); - - int LeftMenuColumn = - m_nCurrScreen == MENUPAGE_SOUND_SETTINGS || - m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS || - m_nCurrScreen == MENUPAGE_MOUSE_CONTROLS; - - if (LeftMenuColumn) { - CFont::SetAlignment(ALIGN_LEFT); - CFont::SetScale(SCREEN_SCALE_X(0.55f), SCREEN_SCALE_Y(0.8f)); - fVerticalSpacing = MENUCOLUMN_SPACING_MIN; - fBarSize = MENUSELECT_BOX_MIN; - } - else { - CFont::SetAlignment(ALIGN_CENTER); - CFont::SetScale(SCREEN_SCALE_X(0.75f), SCREEN_SCALE_Y(0.9f)); - fVerticalSpacing = MENUCOLUMN_SPACING_MAX; - fBarSize = MENUSELECT_BOX_MAX; - } - - // Set positions. - if (CFont::GetDetails().centre) - vecPositions.x = SCREEN_WIDTH / 2; - else - vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_POS_X); - - switch (m_nCurrScreen) { - case MENUPAGE_BRIEFS: - case MENUPAGE_STATS: - vecPositions.y = SCREEN_SCALE_FROM_BOTTOM(MENUCOLUMN_FEDS); - break; - case MENUPAGE_SOUND_SETTINGS: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y); - - if (i > 5) - vecPositions.y += SCREEN_SCALE_Y(MENURADIO_ICON_H * 1.16f); - break; - case MENUPAGE_LANGUAGE_SETTINGS: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MIN_Y); - break; - case MENUPAGE_MOUSE_CONTROLS: - case MENUPAGE_GRAPHICS_SETTINGS: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y); - break; - case MENUPAGE_OPTIONS: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); - break; - case MENUPAGE_PAUSE_MENU: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_PAUSE_Y); - break; - case MENUPAGE_NEW_GAME: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); - break; - case MENUPAGE_START_MENU: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_START_Y); - break; - default: - vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); - break; - }; - } - - if (i > 0) - vecPositions.y += SCREEN_SCALE_Y(fVerticalSpacing * i); - - // Set color and draw selection bar. - if (i == m_nCurrOption && m_nMenuFadeAlpha >= 255) { - CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255))); - CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(11.0f), vecPositions.y - SCREEN_STRETCH_Y(fBarSize * 0.13f), SCREEN_STRETCH_FROM_RIGHT(11.0f), vecPositions.y + SCREEN_STRETCH_Y(fBarSize)), CRGBA(100, 200, 50, 50)); - } - else - CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); - - // Draw - if (textToPrint[MENUCOLUMN_LEFT]) - CFont::PrintString(vecPositions.x, vecPositions.y, textToPrint[MENUCOLUMN_LEFT]); - - if (textToPrint[MENUCOLUMN_RIGHT]) { - if (Locked) - CFont::SetColor(CRGBA(190, 130, 40, FadeIn(255))); - - CFont::SetAlignment(ALIGN_RIGHT); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(SavePageSlot ? MENUCOLUMN_SAVE_X : MENUCOLUMN_POS_X), vecPositions.y, textToPrint[MENUCOLUMN_RIGHT]); - } - - // Mouse support. - // TODO: inputs for these pages. - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - } - else if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - - } - else { - static bool bIsMouseInPosition = false; - if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) { - CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) }; - if (m_bShowMouse && - ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f))))) - bIsMouseInPosition = true; - else - bIsMouseInPosition = false; - - if (bIsMouseInPosition) { - if (m_nCurrOption != i) { - m_nCurrOption = i; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); - } - - m_nPrevOption = m_nCurrOption; - - if (GetMouseForward()) - m_nHoverOption = IGNORE_OPTION; - else - m_nHoverOption = ACTIVATE_OPTION; - } - } - } - - // Sliders - // TODO: CheckHover - switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { - case MENUACTION_BRIGHTNESS: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness/512.0f); - break; - case MENUACTION_DRAWDIST: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), (m_PrefsLOD - 0.8f) * 1.0f); - break; - case MENUACTION_MUSICVOLUME: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume/128.0f); - break; - case MENUACTION_SFXVOLUME: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume/128.0f); - break; - case MENUACTION_MOUSESENS: - DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), TheCamera.m_fMouseAccelHorzntl * 200.0f); - break; - }; - - // Radio icons. - float fIconSpacing = 59.52f; - if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { - for (int i = 0; i < POLICE_RADIO; i++) { -#ifndef ASPECT_RATIO_SCALE - if (i < USERTRACK) - m_aFrontEndSprites[i + FE_RADIO1].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); - if (i > CHATTERBOX && DMAudio.IsMP3RadioChannelAvailable()) - m_aMenuSprites[MENUSPRITE_MP3LOGO].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); -#else - float fMp3Pos = 0.0f; - if (DMAudio.IsMP3RadioChannelAvailable()) - fMp3Pos = 34.0f; - - if (i < USERTRACK) - m_aFrontEndSprites[i + FE_RADIO1].Draw((SCREEN_WIDTH * 0.5) + SCREEN_SCALE_X(-fMp3Pos + MENURADIO_ICON_X + (fIconSpacing * i)), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); - if (i > CHATTERBOX && DMAudio.IsMP3RadioChannelAvailable()) - m_aMenuSprites[MENUSPRITE_MP3LOGO].Draw((SCREEN_WIDTH * 0.5) + SCREEN_SCALE_X(-fMp3Pos + MENURADIO_ICON_X + (fIconSpacing * i)), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); -#endif - } - } - - // Helpers - if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FED_RES")) { - if (m_nDisplayVideoMode == m_nPrefsVideoMode) { - if (m_nHelperTextMsgId == 1) - ResetHelperText(); - } - else - SetHelperText(1); - } - else { - if (m_nDisplayVideoMode != m_nPrefsVideoMode) { - m_nDisplayVideoMode = m_nPrefsVideoMode; - SetHelperText(3); - } - } - - switch (m_nCurrScreen) { - case MENUPAGE_CONTROLLER_SETTINGS: - case MENUPAGE_SOUND_SETTINGS: - case MENUPAGE_GRAPHICS_SETTINGS: - case MENUPAGE_SKIN_SELECT: - case MENUPAGE_CONTROLLER_PC: - case MENUPAGE_MOUSE_CONTROLS: - DisplayHelperText(); - break; - }; - } - }; -} -#endif - -#if 1 -WRAPPER void CMenuManager::DrawControllerBound(int, int, int, uint8) { EAXJMP(0x489710); } -#else -void CMenuManager::DrawControllerBound(int, int, int, uint8) -{ - -} -#endif - -#if 1 -WRAPPER void CMenuManager::DrawControllerScreenExtraText(int, int, int) { EAXJMP(0x4892F0); } -#else -void CMenuManager::DrawControllerScreenExtraText(int, int, int) -{ - -} -#endif - -#if 1 -WRAPPER void CMenuManager::DrawControllerSetupScreen() { EAXJMP(0x481210); } -#else -void CMenuManager::DrawControllerSetupScreen() -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } -#else -void CMenuManager::DrawFrontEnd() -{ - CFont::SetAlphaFade(255.0f); - - if (m_nCurrScreen == MENUPAGE_NONE) { - m_nMenuFadeAlpha = 0; - - if (m_bGameNotLoaded) - m_nCurrScreen = MENUPAGE_START_MENU; - else - m_nCurrScreen = MENUPAGE_PAUSE_MENU; - } - - if (!m_nCurrOption && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) - m_nCurrOption = MENUROW_1; - - CMenuManager::DrawFrontEndNormal(); - CMenuManager::PrintErrorMessage(); -} -#endif - -#if 0 -WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } -#else -void CMenuManager::DrawFrontEndNormal() -{ - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSCLAMP); - - CSprite2d::InitPerFrame(); - CFont::InitPerFrame(); - - eMenuSprites previousSprite = MENUSPRITE_MAINMENU; - if (m_nMenuFadeAlpha < 255) { - switch (m_nPrevScreen) { - case MENUPAGE_STATS: - case MENUPAGE_START_MENU: - case MENUPAGE_PAUSE_MENU: - previousSprite = MENUSPRITE_MAINMENU; - break; - case MENUPAGE_NEW_GAME: - case MENUPAGE_CHOOSE_LOAD_SLOT: - case MENUPAGE_CHOOSE_DELETE_SLOT: - case MENUPAGE_NEW_GAME_RELOAD: - case MENUPAGE_LOAD_SLOT_CONFIRM: - case MENUPAGE_DELETE_SLOT_CONFIRM: - case MENUPAGE_EXIT: - previousSprite = MENUSPRITE_SINGLEPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAIN: - previousSprite = MENUSPRITE_MULTIPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAP: - case MENUPAGE_MULTIPLAYER_FIND_GAME: - case MENUPAGE_SKIN_SELECT: - case MENUPAGE_KEYBOARD_CONTROLS: - case MENUPAGE_MOUSE_CONTROLS: - previousSprite = MENUSPRITE_FINDGAME; - break; - case MENUPAGE_MULTIPLAYER_CONNECTION: - case MENUPAGE_MULTIPLAYER_MODE: - previousSprite = MENUSPRITE_CONNECTION; - break; - case MENUPAGE_MULTIPLAYER_CREATE: - previousSprite = MENUSPRITE_HOSTGAME; - break; - case MENUPAGE_SKIN_SELECT_OLD: - case MENUPAGE_OPTIONS: - previousSprite = MENUSPRITE_PLAYERSET; - break; - }; - - if (m_nPrevScreen == MENUPAGE_NONE) - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255)); - else - m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - } - - eMenuSprites currentSprite = MENUSPRITE_MAINMENU; - switch (m_nCurrScreen) { - case MENUPAGE_STATS: - case MENUPAGE_START_MENU: - case MENUPAGE_PAUSE_MENU: - currentSprite = MENUSPRITE_MAINMENU; - break; - case MENUPAGE_NEW_GAME: - case MENUPAGE_CHOOSE_LOAD_SLOT: - case MENUPAGE_CHOOSE_DELETE_SLOT: - case MENUPAGE_NEW_GAME_RELOAD: - case MENUPAGE_LOAD_SLOT_CONFIRM: - case MENUPAGE_DELETE_SLOT_CONFIRM: - case MENUPAGE_EXIT: - currentSprite = MENUSPRITE_SINGLEPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAIN: - currentSprite = MENUSPRITE_MULTIPLAYER; - break; - case MENUPAGE_MULTIPLAYER_MAP: - case MENUPAGE_MULTIPLAYER_FIND_GAME: - case MENUPAGE_SKIN_SELECT: - case MENUPAGE_KEYBOARD_CONTROLS: - case MENUPAGE_MOUSE_CONTROLS: - currentSprite = MENUSPRITE_FINDGAME; - break; - case MENUPAGE_MULTIPLAYER_CONNECTION: - case MENUPAGE_MULTIPLAYER_MODE: - currentSprite = MENUSPRITE_CONNECTION; - break; - case MENUPAGE_MULTIPLAYER_CREATE: - currentSprite = MENUSPRITE_HOSTGAME; - break; - case MENUPAGE_SKIN_SELECT_OLD: - case MENUPAGE_OPTIONS: - currentSprite = MENUSPRITE_PLAYERSET; - break; - }; - - uint32 savedShade; - uint32 savedAlpha; - RwRenderStateGet(rwRENDERSTATESHADEMODE, &savedShade); - RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast(rwSHADEMODEGOURAUD)); - RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &savedAlpha); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(TRUE)); - if (m_nMenuFadeAlpha >= 255) { - m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - } - else { - if (m_nMenuFadeAlpha < 255) { - m_nMenuFadeAlpha += 0.1f * 255.0f; - - if (m_nMenuFadeAlpha >= 255) - m_nMenuFadeAlpha = 255; - - m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha)); - } - else - m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - } - - // GTA LOGO - if (m_nCurrScreen == MENUPAGE_START_MENU || m_nCurrScreen == MENUPAGE_PAUSE_MENU) { - if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) - m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(70.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(180.0f)), CRGBA(255, 255, 255, FadeIn(255))); - else - m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(40.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(210.0f)), CRGBA(255, 255, 255, FadeIn(255))); - } - RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast(savedShade)); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(savedAlpha)); - - switch (m_nCurrScreen) { - case MENUPAGE_SKIN_SELECT: - CMenuManager::DrawPlayerSetupScreen(); - break; - case MENUPAGE_KEYBOARD_CONTROLS: - CMenuManager::DrawControllerSetupScreen(); - break; - default: - CMenuManager::Draw(); - break; - }; - - CFont::DrawFonts(); - - // Draw mouse - if (m_bShowMouse) - m_aMenuSprites[MENUSPRITE_MOUSE].Draw(m_nMousePosX, m_nMousePosY, SCREEN_SCALE_X(60.0f), SCREEN_SCALE_Y(60.0f), CRGBA(255, 255, 255, 255)); -} -#endif - -#if 1 -WRAPPER void CMenuManager::DrawPlayerSetupScreen() { EAXJMP(0x47F2B0); } -#else -void CMenuManager::DrawPlayerSetupScreen() -{ - -} -#endif - -#if 0 -WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); } -#else -int CMenuManager::FadeIn(int alpha) -{ - if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS || - m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS || - m_nCurrScreen == MENUPAGE_DELETING) - return alpha; - - if (m_nMenuFadeAlpha >= alpha) - return alpha; - - return m_nMenuFadeAlpha; -} -#endif - -#if 1 -WRAPPER void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) { EAXJMP(0x4889C0); } -#else -void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) -{ - -} -#endif - -#if 1 -WRAPPER int CMenuManager::GetStartOptionsCntrlConfigScreens() { EAXJMP(0x489270); } -#else -int CMenuManager::GetStartOptionsCntrlConfigScreens() -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); } -#else -void CMenuManager::InitialiseChangedLanguageSettings() -{ - if (m_bFrontEnd_ReloadObrTxtGxt) { - m_bFrontEnd_ReloadObrTxtGxt = false; - CTimer::Stop(); - TheText.Unload(); - TheText.Load(); - CTimer::Update(); - CGame::frenchGame = false; - CGame::germanGame = false; - switch (CMenuManager::m_PrefsLanguage) { - case LANGUAGE_FRENCH: - CGame::frenchGame = true; - break; - case LANGUAGE_GERMAN: - CGame::germanGame = true; - break; - default: - break; - }; - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::LoadAllTextures() { EAXJMP(0x47A230); } -#else -void CMenuManager::LoadAllTextures() -{ - if (!m_bSpritesLoaded) { - CMenuManager::CentreMousePointer(); - DMAudio.ChangeMusicMode(0); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); - m_nCurrOption = MENUROW_0; - m_PrefsRadioStation = DMAudio.GetRadioInCar(); - - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CMenuManager::m_PrefsRadioStation > USERTRACK) - CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10; - } - else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX) - CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9; - - CFileMgr::SetDir(""); - CTimer::Stop(); - CStreaming::MakeSpaceFor(700 * 1024); - CStreaming::ImGonnaUseStreamingMemory(); - CTxdStore::PushCurrentTxd(); - - int frontend = CTxdStore::AddTxdSlot("frontend"); - CTxdStore::LoadTxd(frontend, "MODELS/FRONTEND.TXD"); - CTxdStore::AddRef(frontend); - CTxdStore::SetCurrentTxd(frontend); - CStreaming::IHaveUsedStreamingMemory(); - CTimer::Update(); - - debug("LOAD frontend\n"); - for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) { - m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i]); - m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - }; - - CTxdStore::PopCurrentTxd(); - - int menu = CTxdStore::AddTxdSlot("menu"); - CTxdStore::LoadTxd(menu, "MODELS/MENU.TXD"); - CTxdStore::AddRef(menu); - CTxdStore::SetCurrentTxd(menu); - - debug("LOAD sprite\n"); - for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; i++) { - m_aMenuSprites[i].SetTexture(MenuFilenames[i*2], MenuFilenames[i*2+1]); - m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); - }; - - CTxdStore::PopCurrentTxd(); - - m_bSpritesLoaded = true; - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } -#else -void CMenuManager::LoadSettings() -{ - - CFileMgr::SetDirMyDocuments(); - - uint8 prevLang = m_PrefsLanguage; - MousePointerStateHelper.bInvertVertically = true; - - static char Ver; - int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); - if (fileHandle) { - CFileMgr::Read(fileHandle, buf(&Ver), sizeof(Ver)); - - if (strncmp(&Ver, "THIS FILE IS NOT VALID YET", 26)) { - CFileMgr::Seek(fileHandle, 0, 0); - ControlsManager.LoadSettings(fileHandle); - CFileMgr::Read(fileHandle, buf(&gString), 20); - CFileMgr::Read(fileHandle, buf(&gString), 20); - CFileMgr::Read(fileHandle, buf(&gString), 4); - CFileMgr::Read(fileHandle, buf(&gString), 4); - CFileMgr::Read(fileHandle, buf(&gString), 1); - CFileMgr::Read(fileHandle, buf(&gString), 1); - CFileMgr::Read(fileHandle, buf(&gString), 1); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_bHeadBob), 1); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); - CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); - CFileMgr::Read(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); - CFileMgr::Read(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsSfxVolume), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsMusicVolume), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsRadioStation), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsSpeakers), 1); - CFileMgr::Read(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsDMA), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsBrightness), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsLOD), 4); - CFileMgr::Read(fileHandle, buf(&m_PrefsShowSubtitles), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsUseWideScreen), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsVsyncDisp), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsFrameLimiter), 1); - CFileMgr::Read(fileHandle, buf(&m_nDisplayVideoMode), 1); - CFileMgr::Read(fileHandle, buf(&CMBlur::BlurOn), 1); - CFileMgr::Read(fileHandle, buf(m_PrefsSkinFile), 256); - CFileMgr::Read(fileHandle, buf(&m_ControlMethod), 1); - CFileMgr::Read(fileHandle, buf(&m_PrefsLanguage), 1); - } - } - - CFileMgr::CloseFile(fileHandle); - CFileMgr::SetDir(""); - - m_PrefsVsync = m_PrefsVsyncDisp; - lodMultiplier = m_PrefsLOD; - - if (m_nPrefsAudio3DProviderIndex == -1) - m_nPrefsAudio3DProviderIndex = -2; - - if (m_PrefsLanguage == prevLang) - m_bLanguageLoaded = false; - else { - m_bLanguageLoaded = true; - TheText.Unload(); - TheText.Load(); - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - - debug("The previously saved language is now in use"); - } - - /*struct _WIN32_FIND_DATAA FindFileData; - HANDLE H = FindFirstFileA("skins\*.bmp", &FindFileData); - char Dest; - bool SkinFound = false; - - for (int i = 1; H != (HANDLE)-1 && i; i = FindNextFileA(H, &FindFileData)) { - strcpy(&Dest, buf(m_PrefsSkinFile)); - strcat(&Dest, ".bmp"); - if (!strcmp(FindFileData.cFileName, &Dest)) - SkinFound = true; - } - - FindClose(H); - - if (!SkinFound) { - debug("Default skin set as no other skins are available OR saved skin not found!"); - strcpy((char *)CMenuManager::m_PrefsSkinFile, "$$\"\""); - strcpy(m_aSkinName, "$$\"\""); - }*/ -} -#endif - -#if 1 -WRAPPER void CMenuManager::MessageScreen(char *) { EAXJMP(0x48B7E0); } -#else -void CMenuManager::MessageScreen(char *) -{ - -} -#endif - -#if 1 -WRAPPER void CMenuManager::PickNewPlayerColour() { EAXJMP(0x488C40); } -#else -void CMenuManager::PickNewPlayerColour() -{ - -} -#endif - -#if 1 -WRAPPER void CMenuManager::PrintBriefs() { EAXJMP(0x484D60); } -#else -void CMenuManager::PrintBriefs() -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); } -#else -void CMenuManager::PrintErrorMessage() -{ - if (!CPad::bDisplayNoControllerMessage && !CPad::bObsoleteControllerMessage) - return; - - CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(20.0f), SCREEN_SCALE_Y(140.0f), SCREEN_WIDTH - SCREEN_SCALE_X(20.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(140.0f)), CRGBA(64, 16, 16, 224)); - CFont::SetFontStyle(FONT_BANK); - CFont::SetBackgroundOff(); - CFont::SetPropOn(); - CFont::SetCentreOff(); - CFont::SetJustifyOn(); - CFont::SetRightJustifyOff(); - CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(SCREEN_WIDTH - 40.0f); - CFont::SetColor(CRGBA(165, 165, 165, 255)); - CFont::SetScale(SCREEN_SCALE_X(0.9f), SCREEN_SCALE_Y(0.9f)); - CFont::PrintString(SCREEN_SCALE_X(40.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(60.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT")); - CFont::DrawFonts(); -} -#endif - -#if 1 -WRAPPER void CMenuManager::PrintStats() { EAXJMP(0x482100); } -#else -void CMenuManager::PrintStats() -{ - -} -#endif - -#if 0 -WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); } -#else -void CMenuManager::Process(void) -{ - if (m_bSaveMenuActive && TheCamera.GetScreenFadeStatus()) - return; - - field_113 = 0; - InitialiseChangedLanguageSettings(); - - SwitchMenuOnAndOff(); - - if (m_bMenuActive) { - LoadAllTextures(); - - if (m_nCurrScreen == MENUPAGE_DELETING) { - bool SlotPopulated = false; - - if (PcSaveHelper.DeleteSlot(m_nCurrSaveSlot)) { - PcSaveHelper.PopulateSlotInfo(); - SlotPopulated = true; - } - - if (SlotPopulated) { - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_DELETE_SUCCESS; - m_nCurrOption = 0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - } - else - SaveLoadFileError_SetUpErrorScreen(); - } - if (m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS) { - int8 SaveSlot = PcSaveHelper.SaveSlot(m_nCurrSaveSlot); - PcSaveHelper.PopulateSlotInfo(); - if (SaveSlot) { - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_SAVE_SUCCESSFUL; - m_nCurrOption = 0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - } - else - SaveLoadFileError_SetUpErrorScreen(); - } - if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS) { - if (CheckSlotDataValid(m_nCurrSaveSlot)) { - TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == 0; - if (m_PrefsVsyncDisp != m_PrefsVsync) - m_PrefsVsync = m_PrefsVsyncDisp; - DMAudio.Service(); - m_bStartGameLoading = 1; - RequestFrontEndShutdown(); - m_bLoadingSavedGame = 1; - b_FoundRecentSavedGameWantToLoad = 1; - DMAudio.SetEffectsFadeVol(0); - DMAudio.SetMusicFadeVol(0); - DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); - } - else - SaveLoadFileError_SetUpErrorScreen(); - } - - ProcessButtonPresses(); - } - else { - if (GetPadExitEnter()) - RequestFrontEndStartUp(); - - UnloadTextures(); - m_nPrevScreen = MENUPAGE_NONE; - m_nCurrScreen = m_nPrevScreen; - m_nCurrOption = MENUROW_0; - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); } -#else -void CMenuManager::ProcessButtonPresses() -{ - // Update Mouse Position - m_nMouseOldPosX = m_nMousePosX; - m_nMouseOldPosY = m_nMousePosY; - - m_nMousePosX = m_nMouseTempPosX; - m_nMousePosY = m_nMouseTempPosY; - - if (m_nMousePosX < 0) - m_nMousePosX = 0; - if (m_nMousePosX > SCREEN_WIDTH) - m_nMousePosX = SCREEN_WIDTH; - if (m_nMousePosY < 0) - m_nMousePosY = 0; - if (m_nMousePosY > SCREEN_HEIGHT) - m_nMousePosY = SCREEN_HEIGHT; - - // Show/hide mouse cursor. - if (GetMouseInput()) - m_bShowMouse = true; - else if (GetPadInput()) - m_bShowMouse = false; - - // Get number of menu options. - uint8 NumberOfMenuOptions = GetNumberOfMenuOptions(); - - // Select next/previous option with pad. Mouse is done in drawing function. - if (GetPadMoveUp()) { - m_nPrevOption = m_nCurrOption; - m_nCurrOption -= 1; - - if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { - if (m_nCurrOption < MENUROW_1) - m_nCurrOption = NumberOfMenuOptions; - } - else { - if (m_nCurrOption < MENUROW_0) - m_nCurrOption = NumberOfMenuOptions; - } - - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); - } - else if (GetPadMoveDown()) { - m_nPrevOption = m_nCurrOption; - m_nCurrOption += 1; - - if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { - if (m_nCurrOption > NumberOfMenuOptions) - m_nCurrOption = MENUROW_1; - } - else { - if (m_nCurrOption > NumberOfMenuOptions) - m_nCurrOption = MENUROW_0; - } - - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); - } - - // Set what happens if ESC is pressed. - if (GetPadBack()) { - bool PlayEscSound = false; - switch (m_nCurrScreen) { - case MENUPAGE_START_MENU: - break; - case MENUPAGE_CHOOSE_SAVE_SLOT: - case MENUPAGE_PAUSE_MENU: - RequestFrontEndShutdown(); - PlayEscSound = true; - break; - default: - SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); - PlayEscSound = true; - break; - }; - - if (PlayEscSound) - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); - } - - // TODO: finish hover options. - // Set mouse buttons. - if (GetMouseForward()) { - switch (m_nHoverOption) { - case ACTIVATE_OPTION: - if (m_nCurrOption || m_nCurrScreen != MENUPAGE_PAUSE_MENU) - m_nCurrOption = m_nPrevOption; - - m_nHoverOption = ACTIVATE_OPTION; - break; - default: - break; - }; - } - - // Process all menu options here, but first check if it's an option or a redirect. - int32 CurrAction = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action; - if ((GetPadForward() || GetMouseForward()) || - ((GetPadMoveLeft() || GetMouseMoveRight()) || (GetPadMoveRight() || GetMouseMoveLeft())) && - (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu == m_nCurrScreen && - CurrAction != MENUACTION_CHANGEMENU && - CurrAction != MENUACTION_LOADRADIO && - CurrAction != MENUACTION_RESTOREDEF && - CurrAction != MENUACTION_PLAYERSETUP)) { - - if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB")) - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); - else - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0); - - ProcessOnOffMenuOptions(); - } - - // Process screens that may redirect you somewhere, or may not. - switch (m_nCurrScreen) { - case MENUPAGE_LOAD_SLOT_CONFIRM: - break; - case MENUPAGE_NEW_GAME_RELOAD: - if (m_bGameNotLoaded) - DoSettingsBeforeStartingAGame(); - break; - case MENUPAGE_CHOOSE_DELETE_SLOT: - case MENUPAGE_CHOOSE_SAVE_SLOT: - case MENUPAGE_CHOOSE_LOAD_SLOT: - PcSaveHelper.PopulateSlotInfo(); - break; - default: - break; - }; - - // Reset pad shaking. - if (VibrationTime != 0) { - if (CTimer::GetTimeInMillisecondsPauseMode() > VibrationTime) { - CPad::GetPad(0)->StopShaking(0); - VibrationTime = 0; - } - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::ProcessOnOffMenuOptions() { EAXJMP(0x48AE60); } -#else -void CMenuManager::ProcessOnOffMenuOptions() -{ - int8 InputDirection = (GetPadMoveLeft() || GetMouseMoveLeft()) && (!GetPadForward() && !GetMouseForward()) ? -1 : 1; - int8 InputEnter = GetPadForward(); - - uint8 NumberOfMenuOptions = GetNumberOfMenuOptions(); - - // In numerical order. - switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) { - case MENUACTION_CHANGEMENU: - SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); - break; - case MENUACTION_CTRLVIBRATION: - if (!m_PrefsUseVibration) - m_PrefsUseVibration = true; - - if (m_PrefsUseVibration) { - CPad::GetPad(0)->StartShake(350, 150); - VibrationTime = CTimer::GetTimeInMillisecondsPauseMode() + 500; - } - SaveSettings(); - break; - case MENUACTION_FRAMESYNC: - m_PrefsVsync = m_PrefsVsync == false; - SaveSettings(); - break; - case MENUACTION_FRAMELIMIT: - m_PrefsFrameLimiter = m_PrefsFrameLimiter == false; - SaveSettings(); - break; - case MENUACTION_TRAILS: - CMBlur::BlurOn = CMBlur::BlurOn == false; - if (CMBlur::BlurOn) - CMBlur::MotionBlurOpen(Scene.camera); - else - CMBlur::MotionBlurClose(); - - SaveSettings(); - break; - case MENUACTION_SUBTITLES: - m_PrefsShowSubtitles = m_PrefsShowSubtitles == false; - SaveSettings(); - break; - case MENUACTION_WIDESCREEN: -#ifndef ASPECT_RATIO_SCALE - m_PrefsUseWideScreen = m_PrefsUseWideScreen == false; -#else - if (InputDirection > 0) { - switch (m_PrefsUseWideScreen) { - case AR_AUTO: - m_PrefsUseWideScreen = AR_4_3; - break; - case AR_4_3: - m_PrefsUseWideScreen = AR_16_9; - break; - case AR_16_9: - m_PrefsUseWideScreen = AR_AUTO; - break; - }; - } - else { - switch (m_PrefsUseWideScreen) { - case AR_AUTO: - m_PrefsUseWideScreen = AR_16_9; - break; - case AR_4_3: - m_PrefsUseWideScreen = AR_AUTO; - break; - case AR_16_9: - m_PrefsUseWideScreen = AR_4_3; - break; - }; - } -#endif - SaveSettings(); - break; - case MENUACTION_BRIGHTNESS: - case MENUACTION_DRAWDIST: - case MENUACTION_MUSICVOLUME: - case MENUACTION_SFXVOLUME: - case MENUACTION_MOUSESENS: - if (InputDirection > 0) - CheckSliderMovement(1.0f); - else - CheckSliderMovement(-1.0f); - break; - case MENUACTION_RADIO: - if (InputDirection < 0) - m_PrefsRadioStation -= 1; - else - m_PrefsRadioStation += 1; - - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (m_PrefsRadioStation > USERTRACK) - m_PrefsRadioStation = HEAD_RADIO; - else if (m_PrefsRadioStation < HEAD_RADIO) - m_PrefsRadioStation = USERTRACK; - } - else { - if (m_PrefsRadioStation > CHATTERBOX) - m_PrefsRadioStation = HEAD_RADIO; - else if (m_PrefsRadioStation < HEAD_RADIO) - m_PrefsRadioStation = CHATTERBOX; - } - - SaveSettings(); - DMAudio.SetRadioInCar(m_PrefsRadioStation); - DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); - break; - case MENUACTION_LANG_ENG: - if (m_PrefsLanguage != LANGUAGE_AMERICAN) { - m_PrefsLanguage = LANGUAGE_AMERICAN; - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - SaveSettings(); - } - break; - case MENUACTION_LANG_FRE: - if (m_PrefsLanguage != LANGUAGE_FRENCH) { - m_PrefsLanguage = LANGUAGE_FRENCH; - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - SaveSettings(); - } - break; - case MENUACTION_LANG_GER: - if (m_PrefsLanguage != LANGUAGE_GERMAN) { - m_PrefsLanguage = LANGUAGE_GERMAN; - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - SaveSettings(); - } - break; - case MENUACTION_LANG_ITA: - if (m_PrefsLanguage != LANGUAGE_ITALIAN) { - m_PrefsLanguage = LANGUAGE_ITALIAN; - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - SaveSettings(); - } - break; - case MENUACTION_LANG_SPA: - if (m_PrefsLanguage != LANGUAGE_SPANISH) { - m_PrefsLanguage = LANGUAGE_SPANISH; - m_bFrontEnd_ReloadObrTxtGxt = true; - InitialiseChangedLanguageSettings(); - SaveSettings(); - } - break; - case MENUACTION_UPDATESAVE: - PcSaveHelper.PopulateSlotInfo(); - if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { - m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; - - SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); - } - break; - case MENUACTION_CHECKSAVE: - if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { - m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; - - if (Slots[m_nCurrSaveSlot] != 1 && Slots[m_nCurrSaveSlot] != 2) - SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); - } - break; - case MENUACTION_NEWGAME: - DoSettingsBeforeStartingAGame(); - break; - case MENUACTION_SETDBGFLAG: - CTheScripts::DbgFlag = CTheScripts::DbgFlag == false; - break; - case MENUACTION_UPDATEMEMCARDSAVE: - RequestFrontEndShutdown(); - break; - case MENUACTION_INVVERT: - MousePointerStateHelper.bInvertVertically = MousePointerStateHelper.bInvertVertically == false; - return; - case MENUACTION_CANCLEGAME: - DMAudio.Service(); - RsEventHandler(rsQUITAPP, 0); - break; - case MENUACTION_RESUME: - RequestFrontEndShutdown(); - break; - case MENUACTION_SCREENRES: - if (m_bGameNotLoaded) { - if (InputEnter) { - if (m_nDisplayVideoMode != m_nPrefsVideoMode) { - m_nPrefsVideoMode = m_nDisplayVideoMode; - _psSelectScreenVM(m_nPrefsVideoMode); - CentreMousePointer(); - m_PrefsUseWideScreen = false; - SaveSettings(); - } - } - else { - char** VideoModeList = _psGetVideoModeList(); - int NumVideoModes = _psGetNumVideModes(); - - if (InputDirection > 0) { - int nCurrentVidMode = m_nDisplayVideoMode + 1; - - if (nCurrentVidMode >= NumVideoModes) - nCurrentVidMode = 0; - - while (!VideoModeList[nCurrentVidMode]) { - ++nCurrentVidMode; - - if (nCurrentVidMode >= NumVideoModes) - nCurrentVidMode = 0; - } - - m_nDisplayVideoMode = nCurrentVidMode; - } - else { - int nCurrentVidMode = m_nDisplayVideoMode - 1; - - if (nCurrentVidMode < 0) - nCurrentVidMode = NumVideoModes - 1; - - while (!VideoModeList[nCurrentVidMode]) { - --nCurrentVidMode; - - if (nCurrentVidMode < 0) - nCurrentVidMode = NumVideoModes - 1; - } - - m_nDisplayVideoMode = nCurrentVidMode; - } - } - } - break; - case MENUACTION_AUDIOHW: - { - int8 AudioHardware = m_nPrefsAudio3DProviderIndex; - if (m_nPrefsAudio3DProviderIndex == -1) - break; - - if (InputDirection > 0) { - switch (m_nPrefsAudio3DProviderIndex) { - case 0: - m_nPrefsAudio3DProviderIndex = 1; - break; - case 1: - m_nPrefsAudio3DProviderIndex = 2; - break; - case 2: - m_nPrefsAudio3DProviderIndex = 3; - break; - case 3: - m_nPrefsAudio3DProviderIndex = 4; - break; - case 4: - m_nPrefsAudio3DProviderIndex = 5; - break; - case 5: - m_nPrefsAudio3DProviderIndex = 6; - break; - case 6: - m_nPrefsAudio3DProviderIndex = 0; - break; - } - } - else { - switch (m_nPrefsAudio3DProviderIndex) { - case 0: - m_nPrefsAudio3DProviderIndex = 6; - break; - case 1: - m_nPrefsAudio3DProviderIndex = 0; - break; - case 2: - m_nPrefsAudio3DProviderIndex = 1; - break; - case 3: - m_nPrefsAudio3DProviderIndex = 2; - break; - case 4: - m_nPrefsAudio3DProviderIndex = 3; - break; - case 5: - m_nPrefsAudio3DProviderIndex = 4; - break; - case 6: - m_nPrefsAudio3DProviderIndex = 5; - break; - } - } - - DMAudio.SetCurrent3DProvider(m_nPrefsAudio3DProviderIndex); - - if (AudioHardware == m_nPrefsAudio3DProviderIndex) - SetHelperText(0); - else - SetHelperText(4); - - SaveSettings(); - break; - } - case MENUACTION_SPEAKERCONF: - if (m_nPrefsAudio3DProviderIndex == -1) - break; - - if (InputDirection > 0) { - switch (m_PrefsSpeakers) { - case 0: - m_PrefsSpeakers = 1; - break; - case 1: - m_PrefsSpeakers = 2; - break; - case 2: - m_PrefsSpeakers = 0; - break; - }; - } - else { - switch (m_PrefsSpeakers) { - case 0: - m_PrefsSpeakers = 2; - break; - case 1: - m_PrefsSpeakers = 0; - break; - case 2: - m_PrefsSpeakers = 1; - break; - }; - } - - DMAudio.SetSpeakerConfig(m_PrefsSpeakers); - SaveSettings(); - break; - case MENUACTION_RESTOREDEF: - SetDefaultPreferences(m_nCurrScreen); - SetHelperText(2); - SaveSettings(); - break; - case MENUACTION_CTRLMETHOD: - if (m_ControlMethod) { - TheCamera.m_bUseMouse3rdPerson = 1; - m_ControlMethod = 0; - } - else { - TheCamera.m_bUseMouse3rdPerson = 0; - m_ControlMethod = 1; - } - SaveSettings(); - break; - case MENUACTION_DYNAMICACOUSTIC: - m_PrefsDMA = m_PrefsDMA == false; - break; - case MENUACTION_MOUSESTEER: - m_bDisableMouseSteering = m_bDisableMouseSteering == false; - return; - }; -} -#endif - -#if 0 -WRAPPER void CMenuManager::RequestFrontEndShutdown() { EAXJMP(0x488750); } -#else -void CMenuManager::RequestFrontEndShutdown() -{ - m_bShutDownFrontEndRequested = true; - DMAudio.ChangeMusicMode(1); -} -#endif - -#if 0 -WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); } -#else -void CMenuManager::RequestFrontEndStartUp() -{ - m_bStartUpFrontEndRequested = 1; -} -#endif - -#if 0 -WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); } -#else -void CMenuManager::ResetHelperText() -{ - m_nHelperTextMsgId = 0; - m_nHelperTextAlpha = 300; -} -#endif - -#if 0 -WRAPPER void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { EAXJMP(0x488930); } -#else -void CMenuManager::SaveLoadFileError_SetUpErrorScreen() -{ - switch (PcSaveHelper.m_nHelper) { - case 1: - case 2: - case 3: - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_SAVE_FAILED; - m_nCurrOption = MENUROW_0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - break; - case 4: - case 5: - case 6: - this->m_nPrevScreen = m_nCurrScreen; - this->m_nCurrScreen = MENUPAGE_LOAD_FAILED; - m_nCurrOption = MENUROW_0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - case 7: - this->m_nPrevScreen = m_nCurrScreen; - this->m_nCurrScreen = MENUPAGE_LOAD_FAILED_2; - m_nCurrOption = MENUROW_0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - case 8: - case 9: - case 10: - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = MENUPAGE_DELETE_FAILED; - m_nCurrOption = MENUROW_0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - break; - default: - return; - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::SetHelperText() { EAXJMP(0x48B450); } -#else -void CMenuManager::SetHelperText(int text) -{ - m_nHelperTextMsgId = text; - m_nHelperTextAlpha = 300; -} -#endif - -#if 0 -WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); } -#else -void CMenuManager::SaveSettings() -{ - CFileMgr::SetDirMyDocuments(); - - int fileHandle = CFileMgr::OpenFile("gta3.set", "w"); - if (fileHandle) { - - ControlsManager.SaveSettings(fileHandle); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_bHeadBob), 1); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); - CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); - CFileMgr::Write(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); - CFileMgr::Write(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsSfxVolume), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsMusicVolume), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsRadioStation), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsSpeakers), 1); - CFileMgr::Write(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsDMA), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsBrightness), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsLOD), sizeof(m_PrefsLOD)); - CFileMgr::Write(fileHandle, buf(&m_PrefsShowSubtitles), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsUseWideScreen), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsVsyncDisp), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsFrameLimiter), 1); - CFileMgr::Write(fileHandle, buf(&m_nDisplayVideoMode), 1); - CFileMgr::Write(fileHandle, buf(&CMBlur::BlurOn), 1); - CFileMgr::Write(fileHandle, buf(m_PrefsSkinFile), 256); - CFileMgr::Write(fileHandle, buf(&m_ControlMethod), 1); - CFileMgr::Write(fileHandle, buf(&m_PrefsLanguage), 1); - } - - CFileMgr::CloseFile(fileHandle); - CFileMgr::SetDir(""); -} -#endif - -#if 0 -WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); } -#else -void CMenuManager::ShutdownJustMenu() -{ - m_bMenuActive = false; - CTimer::EndUserPause(); -} -#endif - -// We won't ever use this again. -#if 0 -WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); } -#else -float CMenuManager::StretchX(float x) -{ - if (SCREEN_WIDTH == 640) - return x; - else - return SCREEN_WIDTH * x * 0.0015625f; -} -#endif - -#if 0 -WRAPPER float CMenuManager::StretchY(float) { EAXJMP(0x48AC20); } -#else -float CMenuManager::StretchY(float y) -{ - if (SCREEN_HEIGHT == 448) - return y; - else - return SCREEN_HEIGHT * y * 0.002232143f; -} -#endif - -#if 0 -WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); } -#else -void CMenuManager::SwitchMenuOnAndOff() -{ - // Just what the function name says. - if (m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) { - if (!m_bMenuActive) - m_bMenuActive = true; - - if (m_bShutDownFrontEndRequested) - m_bMenuActive = false; - if (m_bStartUpFrontEndRequested) - m_bMenuActive = true; - - if (m_bMenuActive) { - CTimer::StartUserPause(); - } - else { - ShutdownJustMenu(); - SaveSettings(); - m_bStartUpFrontEndRequested = false; - pControlEdit = 0; - m_bShutDownFrontEndRequested = false; - DisplayComboButtonErrMsg = 0; - CPad::GetPad(0)->Clear(0); - CPad::GetPad(1)->Clear(0); - SwitchToNewScreen(0); - } - } - if (m_bSaveMenuActive && !m_bQuitGameNoCD) { - m_bSaveMenuActive = false; - m_bMenuActive = true; - CTimer::StartUserPause(); - SwitchToNewScreen(MENUPAGE_CHOOSE_SAVE_SLOT); - PcSaveHelper.PopulateSlotInfo(); - } - - if (!m_bMenuActive) - field_112 = 1; - - m_bStartUpFrontEndRequested = false; - m_bShutDownFrontEndRequested = false; -} -#endif - -#if 0 -WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); } -#else -void CMenuManager::UnloadTextures() -{ - if (m_bSpritesLoaded) { - debug("Remove frontend\n"); - for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); ++i) - m_aFrontEndSprites[i].Delete(); - - int frontend = CTxdStore::FindTxdSlot("frontend"); - CTxdStore::RemoveTxdSlot(frontend); - - debug("Remove menu textures\n"); - for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; ++i) - m_aMenuSprites[i].Delete(); - - int menu = CTxdStore::FindTxdSlot("menu"); - CTxdStore::RemoveTxdSlot(menu); - - m_bSpritesLoaded = false; - } -} -#endif - -#if 0 -WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); } -#else -void CMenuManager::WaitForUserCD() -{ - LoadSplash(0); - if (!RsGlobal.quit) { - HandleExit(); - CPad::UpdatePads(); - MessageScreen("NO_PCCD"); - - if (GetPadBack()) { - m_bQuitGameNoCD = true; - RsEventHandler(rsQUITAPP, 0); - } - } -} -#endif - -// New content: -uint8 CMenuManager::GetNumberOfMenuOptions() -{ - uint8 Rows = MENUROW_NONE; - for (int i = 0; i < MENUROWS; i++) { - if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_NOTHING) - break; - - ++Rows; - }; - return Rows; -} - -void CMenuManager::SwitchToNewScreen(int8 screen) -{ - ResetHelperText(); - - // Return to - behaviour. - if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB") || - (screen == aScreens[m_nCurrScreen].m_PreviousPage[0])) { - if (m_bGameNotLoaded) { - m_nCurrOption = aScreens[m_nCurrScreen].m_ParentEntry[0]; - m_nCurrScreen = aScreens[m_nCurrScreen].m_PreviousPage[0]; - } - else { - m_nCurrOption = aScreens[m_nCurrScreen].m_ParentEntry[1]; - m_nCurrScreen = aScreens[m_nCurrScreen].m_PreviousPage[1]; - } - - m_nMenuFadeAlpha = 0; - } - else { - // Go through - behaviour. - if (screen) { - m_nPrevScreen = m_nCurrScreen; - m_nCurrScreen = screen; - m_nCurrOption = MENUROW_0; - m_nMenuFadeAlpha = 0; - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); - } - else { - m_nPrevScreen = MENUPAGE_NONE; - m_nCurrScreen = MENUPAGE_NONE; - m_nCurrOption = MENUROW_0; - } - } - - // Set player skin. - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - CPlayerSkin::BeginFrontEndSkinEdit(); - field_535 = 19; - m_bSkinsFound = false; - } - - // Set radio station. - if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { - DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); - OutputDebugStringA("FRONTEND AUDIO TRACK STOPPED"); - } - else - DMAudio.StopFrontEndTrack(); -} - -void CMenuManager::SetDefaultPreferences(int8 screen) -{ - switch (screen) { - case MENUPAGE_SOUND_SETTINGS: - m_PrefsMusicVolume = 102; - m_PrefsSfxVolume = 102; - m_PrefsSpeakers = 0; - m_nPrefsAudio3DProviderIndex = 6; - m_PrefsDMA = true; - DMAudio.SetMusicMasterVolume(m_PrefsMusicVolume); - DMAudio.SetEffectsMasterVolume(m_PrefsSfxVolume); - DMAudio.SetCurrent3DProvider(m_nPrefsAudio3DProviderIndex); - break; - case MENUPAGE_GRAPHICS_SETTINGS: - m_PrefsBrightness = 256; - m_PrefsFrameLimiter = true; - m_PrefsVsync = true; - m_PrefsLOD = 1.2f; - m_PrefsVsyncDisp = true; - lodMultiplier = 1.2; - CMBlur::BlurOn = true; - CMBlur::MotionBlurOpen(Scene.camera); - m_PrefsUseVibration = false; - m_PrefsShowSubtitles = true; - m_nDisplayVideoMode = m_nPrefsVideoMode; - m_PrefsUseWideScreen = false; - break; - case MENUPAGE_CONTROLLER_PC: - ControlsManager.MakeControllerActionsBlank(); - ControlsManager.InitDefaultControlConfiguration(); - - CMouseControllerState state = MousePointerStateHelper.GetMouseSetUp(); - ControlsManager.InitDefaultControlConfigMouse(state); - - if (1) { - //TODO: JoyPad stuff. - } - TheCamera.m_bUseMouse3rdPerson = 1; - m_ControlMethod = 0; - MousePointerStateHelper.bInvertVertically = true; - TheCamera.m_fMouseAccelHorzntl = 0.0025f; - TheCamera.m_fMouseAccelVertical = 0.0025f; - CVehicle::m_bDisableMouseSteering = true; - TheCamera.m_bHeadBob = false; - break; - }; -} - -// Frontend inputs. -bool GetPadBack() -{ - return - (CPad::GetPad(0)->NewKeyState.ESC && !CPad::GetPad(0)->OldKeyState.ESC) || - (CPad::GetPad(0)->NewState.Triangle && !CPad::GetPad(0)->OldState.Triangle); -} - -bool GetPadExitEnter() -{ - return - (CPad::GetPad(0)->NewKeyState.ESC && !CPad::GetPad(0)->OldKeyState.ESC) || - (CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start); -} - -bool GetPadForward() -{ - return - (CPad::GetPad(0)->NewKeyState.EXTENTER && !CPad::GetPad(0)->OldKeyState.EXTENTER) || - (CPad::GetPad(0)->NewKeyState.ENTER && !CPad::GetPad(0)->OldKeyState.ENTER) || - (CPad::GetPad(0)->NewState.Cross && !CPad::GetPad(0)->OldState.Cross); -} - -bool GetPadMoveUp() -{ - return - (CPad::GetPad(0)->NewState.DPadUp && !CPad::GetPad(0)->OldState.DPadUp) || - (CPad::GetPad(0)->NewKeyState.UP && !CPad::GetPad(0)->OldKeyState.UP) || - (CPad::GetPad(0)->NewState.LeftStickY < 0 && !CPad::GetPad(0)->OldState.LeftStickY < 0); -} - -bool GetPadMoveDown() -{ - return - (CPad::GetPad(0)->NewState.DPadDown && !CPad::GetPad(0)->OldState.DPadDown) || - (CPad::GetPad(0)->NewKeyState.DOWN && !CPad::GetPad(0)->OldKeyState.DOWN) || - (CPad::GetPad(0)->NewState.LeftStickY > 0 && !CPad::GetPad(0)->OldState.LeftStickY > 0); -} - -bool GetPadMoveLeft() -{ - return - (CPad::GetPad(0)->NewState.DPadLeft && !CPad::GetPad(0)->OldState.DPadLeft) || - (CPad::GetPad(0)->NewKeyState.LEFT && !CPad::GetPad(0)->OldKeyState.LEFT) || - (CPad::GetPad(0)->NewState.LeftStickX < 0 && !CPad::GetPad(0)->OldState.LeftStickX < 0); -} - -bool GetPadMoveRight() -{ - return - (CPad::GetPad(0)->NewState.DPadRight && !CPad::GetPad(0)->OldState.DPadRight) || - (CPad::GetPad(0)->NewKeyState.RIGHT && !CPad::GetPad(0)->OldKeyState.RIGHT) || - (CPad::GetPad(0)->NewState.LeftStickX > 0 && !CPad::GetPad(0)->OldState.LeftStickX > 0); -} - -bool GetMouseForward() -{ - return - (CPad::GetPad(0)->NewMouseControllerState.LMB && !CPad::GetPad(0)->OldMouseControllerState.LMB); -} - -bool GetMouseBack() -{ - return - (CPad::GetPad(0)->NewMouseControllerState.RMB && !CPad::GetPad(0)->OldMouseControllerState.RMB); -} - -bool GetMousePos() -{ - return - (CPad::GetPad(0)->NewMouseControllerState.x != 0.0f || CPad::GetPad(0)->OldMouseControllerState.y != 0.0f); -} - -bool GetMouseMoveLeft() -{ - return - (CPad::GetPad(0)->NewMouseControllerState.WHEELDN && !CPad::GetPad(0)->OldMouseControllerState.WHEELDN != 0.0f); -} - -bool GetMouseMoveRight() -{ - return - (CPad::GetPad(0)->NewMouseControllerState.WHEELUP && !CPad::GetPad(0)->OldMouseControllerState.WHEELUP != 0.0f); -} - -bool GetPadInput() -{ - return - GetPadBack() || - GetPadForward() || - GetPadMoveUp() || - GetPadMoveDown() || - GetPadMoveLeft() || - GetPadMoveRight(); -} - -bool GetMouseInput() -{ - return - GetMouseForward() || - GetMouseBack() || - GetMousePos() || - GetMouseMoveLeft() || - GetMouseMoveRight(); -} - -STARTPATCHES - InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); - InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP); - InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP); - InjectHook(0x4856F0, &CMenuManager::ProcessButtonPresses, PATCH_JUMP); - InjectHook(0x48AE60, &CMenuManager::ProcessOnOffMenuOptions, PATCH_JUMP); - InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP); - InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP); - - for (int i = 1; i < ARRAY_SIZE(aScreens); i++) - Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]); -ENDPATCHES \ No newline at end of file diff --git a/src/Frontend.h b/src/Frontend.h deleted file mode 100644 index 9b9377da..00000000 --- a/src/Frontend.h +++ /dev/null @@ -1,512 +0,0 @@ -#pragma - -#include "Sprite2d.h" - -#define MENUHEADER_POS_X 35.0f -#define MENUHEADER_POS_Y 93.0f -#define MENUHEADER_WIDTH 0.84f -#define MENUHEADER_HEIGHT 1.6f - -#define MENUACTION_POS_X 20.0f -#define MENUACTION_POS_Y 37.5f -#define MENUACTION_WIDTH 0.675f -#define MENUACTION_HEIGHT 0.81f - -#define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f -#define MENUCOLUMN_MAX_Y 149.0f -#define MENUCOLUMN_MID_Y 100.0f -#define MENUCOLUMN_MIN_Y 110.0f -#define MENUCOLUMN_PAUSE_Y 25.0f -#define MENUCOLUMN_START_Y 9.0f -#define MENUCOLUMN_FEDS 139.0f - -#define MENUCOLUMN_SAVE_X 121.0f -#define MENUCOLUMN_SAVE_Y 111.0f - -#define MENUCOLUMN_SPACING_MAX 24.0f -#define MENUCOLUMN_SPACING_MIN 20.0f - -#define MENUSELECT_BOX_MAX 20.5f -#define MENUSELECT_BOX_MIN 17.0f - -#ifndef ASPECT_RATIO_SCALE -#define MENURADIO_ICON_X 31.5f -#else -#define MENURADIO_ICON_X -262.0f -#endif -#define MENURADIO_ICON_Y 29.5f -#define MENURADIO_ICON_W 60.0f -#define MENURADIO_ICON_H 60.0f - -#define MENUDROP_COLOR_A 150 -#define MENUDROP_COLOR_SIZE -1 - -#define MENUSLIDER_X 306.0f - -#define buf(a) (char*)(a) - -enum eLanguages -{ - LANGUAGE_AMERICAN, - LANGUAGE_FRENCH, - LANGUAGE_GERMAN, - LANGUAGE_ITALIAN, - LANGUAGE_SPANISH, -}; - -enum eFrontendSprites -{ - FE2_MAINPANEL_UL, - FE2_MAINPANEL_UR, - FE2_MAINPANEL_DL, - FE2_MAINPANEL_DR, - FE2_MAINPANEL_DR2, - FE2_TABACTIVE, - FE_ICONBRIEF, - FE_ICONSTATS, - FE_ICONCONTROLS, - FE_ICONSAVE, - FE_ICONAUDIO, - FE_ICONDISPLAY, - FE_ICONLANGUAGE, - FE_CONTROLLER, - FE_CONTROLLERSH, - FE_ARROWS1, - FE_ARROWS2, - FE_ARROWS3, - FE_ARROWS4, - FE_RADIO1, - FE_RADIO2, - FE_RADIO3, - FE_RADIO4, - FE_RADIO5, - FE_RADIO6, - FE_RADIO7, - FE_RADIO8, - FE_RADIO9, -}; - -enum eMenuSprites -{ - MENUSPRITE_CONNECTION, - MENUSPRITE_FINDGAME, - MENUSPRITE_HOSTGAME, - MENUSPRITE_MAINMENU, - MENUSPRITE_PLAYERSET, - MENUSPRITE_SINGLEPLAYER, - MENUSPRITE_MULTIPLAYER, - MENUSPRITE_DMALOGO, - MENUSPRITE_GTALOGO, - MENUSPRITE_RSTARLOGO, - MENUSPRITE_GAMESPY, - MENUSPRITE_MOUSE, - MENUSPRITE_MOUSET, - MENUSPRITE_MP3LOGO, - MENUSPRITE_DOWNOFF, - MENUSPRITE_DOWNON, - MENUSPRITE_UPOFF, - MENUSPRITE_UPON, - MENUSPRITE_GTA3LOGO, -}; - -enum eSaveSlot -{ - SAVESLOT_NONE, - SAVESLOT_0, - SAVESLOT_1, - SAVESLOT_2, - SAVESLOT_3, - SAVESLOT_4, - SAVESLOT_5, - SAVESLOT_6, - SAVESLOT_7, - SAVESLOT_8, - SAVESLOT_LABEL = 36 -}; - -enum eMenuScreen -{ - MENUPAGE_DISABLED = -1, - MENUPAGE_NONE = 0, - MENUPAGE_STATS = 1, - MENUPAGE_NEW_GAME = 2, - MENUPAGE_BRIEFS = 3, - MENUPAGE_CONTROLLER_SETTINGS = 4, - MENUPAGE_SOUND_SETTINGS = 5, - MENUPAGE_GRAPHICS_SETTINGS = 6, - MENUPAGE_LANGUAGE_SETTINGS = 7, - MENUPAGE_CHOOSE_LOAD_SLOT = 8, - MENUPAGE_CHOOSE_DELETE_SLOT = 9, - MENUPAGE_NEW_GAME_RELOAD = 10, - MENUPAGE_LOAD_SLOT_CONFIRM = 11, - MENUPAGE_DELETE_SLOT_CONFIRM = 12, - MENUPAGE_13 = 13, - MENUPAGE_LOADING_IN_PROGRESS = 14, - MENUPAGE_DELETING_IN_PROGRESS = 15, - MENUPAGE_16 = 16, - MENUPAGE_DELETE_FAILED = 17, - MENUPAGE_DEBUG_MENU = 18, - MENUPAGE_MEMORY_CARD_1 = 19, - MENUPAGE_MEMORY_CARD_2 = 20, - MENUPAGE_MULTIPLAYER_MAIN = 21, - MENUPAGE_SAVE_FAILED_1 = 22, - MENUPAGE_SAVE_FAILED_2 = 23, - MENUPAGE_SAVE = 24, - MENUPAGE_NO_MEMORY_CARD = 25, - MENUPAGE_CHOOSE_SAVE_SLOT = 26, - MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27, - MENUPAGE_MULTIPLAYER_MAP = 28, - MENUPAGE_MULTIPLAYER_CONNECTION = 29, - MENUPAGE_MULTIPLAYER_FIND_GAME = 30, - MENUPAGE_MULTIPLAYER_MODE = 31, - MENUPAGE_MULTIPLAYER_CREATE = 32, - MENUPAGE_MULTIPLAYER_START = 33, - MENUPAGE_SKIN_SELECT_OLD = 34, - MENUPAGE_CONTROLLER_PC = 35, - MENUPAGE_CONTROLLER_PC_OLD1 = 36, - MENUPAGE_CONTROLLER_PC_OLD2 = 37, - MENUPAGE_CONTROLLER_PC_OLD3 = 38, - MENUPAGE_CONTROLLER_PC_OLD4 = 39, - MENUPAGE_CONTROLLER_DEBUG = 40, - MENUPAGE_OPTIONS = 41, - MENUPAGE_EXIT = 42, - MENUPAGE_SAVING_IN_PROGRESS = 43, - MENUPAGE_SAVE_SUCCESSFUL = 44, - MENUPAGE_DELETING = 45, - MENUPAGE_DELETE_SUCCESS = 46, - MENUPAGE_SAVE_FAILED = 47, - MENUPAGE_LOAD_FAILED = 48, - MENUPAGE_LOAD_FAILED_2 = 49, - MENUPAGE_FILTER_GAME = 50, - MENUPAGE_START_MENU = 51, - MENUPAGE_PAUSE_MENU = 52, - MENUPAGE_CHOOSE_MODE = 53, - MENUPAGE_SKIN_SELECT = 54, - MENUPAGE_KEYBOARD_CONTROLS = 55, - MENUPAGE_MOUSE_CONTROLS = 56, - MENUPAGE_57 = 57, - MENUPAGE_58 = 58, - MENUPAGES -}; - -enum eMenuAction -{ - MENUACTION_NOTHING, - MENUACTION_LABEL, - MENUACTION_CHANGEMENU, - MENUACTION_CTRLVIBRATION, - MENUACTION_CTRLCONFIG, - MENUACTION_CTRLDISPLAY, - MENUACTION_FRAMESYNC, - MENUACTION_FRAMELIMIT, - MENUACTION_TRAILS, - MENUACTION_SUBTITLES, - MENUACTION_WIDESCREEN, - MENUACTION_BRIGHTNESS, - MENUACTION_DRAWDIST, - MENUACTION_MUSICVOLUME, - MENUACTION_SFXVOLUME, - MENUACTION_UNK15, - MENUACTION_RADIO, - MENUACTION_LANG_ENG, - MENUACTION_LANG_FRE, - MENUACTION_LANG_GER, - MENUACTION_LANG_ITA, - MENUACTION_LANG_SPA, - MENUACTION_UPDATESAVE, - MENUACTION_CHECKSAVE, - MENUACTION_UNK24, - MENUACTION_NEWGAME, - MENUACTION_RELOADIDE, - MENUACTION_RELOADIPL, - MENUACTION_SETDBGFLAG, - MENUACTION_SWITCHBIGWHITEDEBUGLIGHT, - MENUACTION_PEDROADGROUPS, - MENUACTION_CARROADGROUPS, - MENUACTION_COLLISIONPOLYS, - MENUACTION_REGMEMCARD1, - MENUACTION_TESTFORMATMEMCARD1, - MENUACTION_TESTUNFORMATMEMCARD1, - MENUACTION_CREATEROOTDIR, - MENUACTION_CREATELOADICONS, - MENUACTION_FILLWITHGUFF, - MENUACTION_SAVEONLYTHEGAME, - MENUACTION_SAVEGAME, - MENUACTION_SAVEGAMEUNDERGTA, - MENUACTION_CREATECOPYPROTECTED, - MENUACTION_TESTSAVE, - MENUACTION_TESTLOAD, - MENUACTION_TESTDELETE, - MENUACTION_PARSEHEAP, - MENUACTION_SHOWCULL, - MENUACTION_MEMCARDSAVECONFIRM, - MENUACTION_UPDATEMEMCARDSAVE, - MENUACTION_UNK50, - MENUACTION_DEBUGSTREAM, - MENUACTION_MPMAP_LIBERTY, - MENUACTION_MPMAP_REDLIGHT, - MENUACTION_MPMAP_CHINATOWN, - MENUACTION_MPMAP_TOWER, - MENUACTION_MPMAP_SEWER, - MENUACTION_MPMAP_INDUSTPARK, - MENUACTION_MPMAP_DOCKS, - MENUACTION_MPMAP_STAUNTON, - MENUACTION_MPMAP_DEATHMATCH1, - MENUACTION_MPMAP_DEATHMATCH2, - MENUACTION_MPMAP_TEAMDEATH1, - MENUACTION_MPMAP_TEAMDEATH2, - MENUACTION_MPMAP_STASH, - MENUACTION_MPMAP_CAPTURE, - MENUACTION_MPMAP_RATRACE, - MENUACTION_MPMAP_DOMINATION, - MENUACTION_STARTMP, - MENUACTION_UNK69, - MENUACTION_UNK70, - MENUACTION_FINDMP, - MENUACTION_REDEFCTRL, - MENUACTION_UNK73, - MENUACTION_INITMP, - MENUACTION_MP_PLAYERCOLOR, - MENUACTION_MP_PLAYERNAME, - MENUACTION_MP_GAMENAME, - MENUACTION_GETKEY, - MENUACTION_SHOWHEADBOB, - MENUACTION_UNK80, - MENUACTION_INVVERT, - MENUACTION_CANCLEGAME, - MENUACTION_MP_PLAYERNUMBER, - MENUACTION_MOUSESENS, - MENUACTION_CHECKMPGAMES, - MENUACTION_CHECKMPPING, - MENUACTION_MP_SERVER, - MENUACTION_MP_MAP, - MENUACTION_MP_GAMETYPE, - MENUACTION_MP_LAN, - MENUACTION_MP_INTERNET, - MENUACTION_RESUME, - MENUACTION_DONTCANCLE, - MENUACTION_SCREENRES, - MENUACTION_AUDIOHW, - MENUACTION_SPEAKERCONF, - MENUACTION_PLAYERSETUP, - MENUACTION_RESTOREDEF, - MENUACTION_CTRLMETHOD, - MENUACTION_DYNAMICACOUSTIC, - MENUACTION_LOADRADIO, - MENUACTION_MOUSESTEER, - MENUACTION_UNK103, - MENUACTION_UNK104, - MENUACTION_UNK105, - MENUACTION_UNK106, - MENUACTION_UNK107, - MENUACTION_UNK108, - MENUACTION_UNK109, - MENUACTION_UNK110, -}; - -enum eCheckHover -{ - ACTIVATE_OPTION = 2, - IGNORE_OPTION = 42, -}; - -enum eMenuColumns -{ - MENUCOLUMN_LEFT, - MENUCOLUMN_CENTER, - MENUCOLUMN_RIGHT, - MENUCOLUMNS, -}; - -enum eMenuRow -{ - MENUROW_NONE = -1, - MENUROW_0, - MENUROW_1, - MENUROW_2, - MENUROW_3, - MENUROW_4, - MENUROW_5, - MENUROW_6, - MENUROW_7, - MENUROW_8, - MENUROW_9, - MENUROW_10, - MENUROW_11, - MENUROW_12, - MENUROW_13, - MENUROW_14, - MENUROW_15, - MENUROW_16, - MENUROW_17, - MENUROWS, -}; - -struct tSkinInfo -{ - int field_0; - char skinName[256]; - char currSkinName[256]; - char date[256]; - int field_304; -}; - -struct CMenuScreen -{ - char m_ScreenName[8]; - int32 unk; - int32 m_PreviousPage[2]; // eMenuScreen - int32 m_ParentEntry[2]; // eMenuRow - - struct CMenuEntry - { - int32 m_Action; // eMenuAction - char m_EntryName[8]; - int32 m_SaveSlot; // eSaveSlot - int32 m_TargetMenu; // eMenuScreen - } m_aEntries[MENUROWS]; -}; - -class CMenuManager -{ -public: - int32 m_nPrefsVideoMode; - int32 m_nDisplayVideoMode; - int8 m_nPrefsAudio3DProviderIndex; - bool m_bKeyChangeNotProcessed; - char m_aSkinName[256]; - int32 m_nHelperTextMsgId; - bool m_bLanguageLoaded; - bool m_bMenuActive; - char field_112; - char field_113; - bool m_bStartGameLoading; - bool m_bFirstTime; - bool m_bGameNotLoaded; - int32 m_nMousePosX; - int32 m_nMousePosY; - int32 m_nMouseTempPosX; - int32 m_nMouseTempPosY; - bool m_bShowMouse; - tSkinInfo field_12C; - tSkinInfo *m_pSelectedSkin; - tSkinInfo *field_438; - float field_43C; - int field_440; - int m_nSkinsTotal; - char _unk0[4]; - int field_44C; - bool m_bSkinsFound; - bool m_bQuitGameNoCD; - char field_452; - bool m_bSaveMenuActive; - bool m_bLoadingSavedGame; - char field_455; - char field_456; - bool m_bSpritesLoaded; - CSprite2d m_aFrontEndSprites[28]; - CSprite2d m_aMenuSprites[20]; - int field_518; - int m_nMenuFadeAlpha; - char field_520; - char field_521; - char field_522; - char field_523; - char field_524; - int m_CurrCntrlAction; - char _unk1[4]; - int field_530; - char field_534; - char field_535; - int8 field_536; - int m_nHelperTextAlpha; - int m_nMouseOldPosX; - int m_nMouseOldPosY; - int m_nHoverOption; - int m_nCurrScreen; - int m_nCurrOption; - int m_nPrevOption; - int m_nPrevScreen; - int field_558; - int m_nCurrSaveSlot; - int m_nScreenChangeDelayTimer; - - static int32 &OS_Language; - static int8 &m_PrefsUseVibration; - static int8 &m_DisplayControllerOnFoot; - static int8 &m_PrefsUseWideScreen; - static int8 &m_PrefsRadioStation; - static int8 &m_PrefsVsync; - static int8 &m_PrefsVsyncDisp; - static int8 &m_PrefsFrameLimiter; - static int8 &m_PrefsShowSubtitles; - static int8 &m_PrefsSpeakers; - static int8 &m_ControlMethod; - static int8 &m_PrefsDMA; - static int8 &m_PrefsLanguage; - static int8 &m_bDisableMouseSteering; - static int32 &m_PrefsBrightness; - static float &m_PrefsLOD; - static int8 &m_bFrontEnd_ReloadObrTxtGxt; - static int32 &m_PrefsMusicVolume; - static int32 &m_PrefsSfxVolume; - static uint8 *m_PrefsSkinFile; - - static bool &m_bStartUpFrontEndRequested; - static bool &m_bShutDownFrontEndRequested; - static bool &m_PrefsAllowNastyGame; - -public: - void BuildStatLine(char *, void *, uint16, void *); - static void CentreMousePointer(); - void CheckCodesForControls(int, int); - bool CheckHover(int x1, int x2, int y1, int y2); - void CheckSliderMovement(int); - int CostructStatLine(int); - void DisplayHelperText(); - float DisplaySlider(float, float, float, float, float, float); - void DoSettingsBeforeStartingAGame(); - void Draw(); - void DrawControllerBound(int, int, int, uint8); - void DrawControllerScreenExtraText(int, int, int); - void DrawControllerSetupScreen(); - void DrawFrontEnd(); - void DrawFrontEndNormal(); - void DrawPlayerSetupScreen(); - int FadeIn(int alpha); - void FilterOutColorMarkersFromString(uint16, CRGBA &); - int GetStartOptionsCntrlConfigScreens(); - static void InitialiseChangedLanguageSettings(); - void LoadAllTextures(); - void LoadSettings(); - static void MessageScreen(char *); - static void PickNewPlayerColour(); - void PrintBriefs(); - static void PrintErrorMessage(); - void PrintStats(); - void Process(); - void ProcessButtonPresses(); - void ProcessOnOffMenuOptions(); - static void RequestFrontEndShutdown(); - static void RequestFrontEndStartUp(); - void ResetHelperText(); - void SaveLoadFileError_SetUpErrorScreen(); - void SaveSettings(); - void SetHelperText(int text); - void ShutdownJustMenu(); - static float StretchX(float); - static float StretchY(float); - void SwitchMenuOnAndOff(); - void UnloadTextures(); - void WaitForUserCD(); - - // New content: - uint8 GetNumberOfMenuOptions(); - void SwitchToNewScreen(int8 screen); - void SetDefaultPreferences(int8 screen); - -}; - -static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error"); - -extern CMenuManager &FrontEndMenuManager; diff --git a/src/Game.cpp b/src/Game.cpp deleted file mode 100644 index cbd55c48..00000000 --- a/src/Game.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Game.h" - -eLevelName &CGame::currLevel = *(eLevelName*)0x941514; -bool &CGame::bDemoMode = *(bool*)0x5F4DD0; -bool &CGame::nastyGame = *(bool*)0x5F4DD4; -bool &CGame::frenchGame = *(bool*)0x95CDCB; -bool &CGame::germanGame = *(bool*)0x95CD1E; -bool &CGame::noProstitutes = *(bool*)0x95CDCF; -bool &CGame::playingIntro = *(bool*)0x95CDC2; -char *CGame::aDatFile = (char*)0x773A48; - -WRAPPER void CGame::Initialise(const char *datFile) { EAXJMP(0x48BED0); } -WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); } -WRAPPER bool CGame::InitialiseOnceBeforeRW(void) { EAXJMP(0x48BB80); } -WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); } -WRAPPER void CGame::ShutdownRenderWare(void) { EAXJMP(0x48BCB0); } -WRAPPER void CGame::FinalShutdown(void) { EAXJMP(0x48BEC0); } -WRAPPER void CGame::ShutDown(void) { EAXJMP(0x48C3A0); } -WRAPPER void CGame::ShutDownForRestart(void) { EAXJMP(0x48C6B0); } -WRAPPER void CGame::InitialiseWhenRestarting(void) { EAXJMP(0x48C740); } -WRAPPER bool CGame::InitialiseOnceAfterRW(void) { EAXJMP(0x48BD50); } diff --git a/src/Game.h b/src/Game.h deleted file mode 100644 index 3bc3e633..00000000 --- a/src/Game.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -enum eLevelName -{ - LEVEL_NONE = 0, - LEVEL_INDUSTRIAL, - LEVEL_COMMERCIAL, - LEVEL_SUBURBAN -}; - -class CGame -{ -public: - static eLevelName &currLevel; - static bool &bDemoMode; - static bool &nastyGame; - static bool &frenchGame; - static bool &germanGame; - static bool &noProstitutes; - static bool &playingIntro; - static char *aDatFile; //[32]; - - static void Initialise(const char *datFile); - static bool InitialiseOnceBeforeRW(void); - static bool InitialiseRenderWare(void); - static bool InitialiseOnceAfterRW(void); - static void InitialiseWhenRestarting(void); - static void ShutDown(void); - static void ShutdownRenderWare(void); - static void FinalShutdown(void); - static void ShutDownForRestart(void); - static void Process(void); - - // NB: these do something on PS2 - static void TidyUpMemory(bool, bool) {} - static void DrasticTidyUpMemory(void) {} -}; diff --git a/src/General.h b/src/General.h deleted file mode 100644 index cae1caa0..00000000 --- a/src/General.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -class CGeneral -{ -public: - static float GetATanOfXY(float x, float y){ - if(x == 0.0f && y == 0.0f) - return 0.0f; - float xabs = fabs(x); - float yabs = fabs(y); - - if(xabs < yabs){ - if(y > 0.0f){ - if(x > 0.0f) - return 0.5f*PI - atan2(x / y, 1.0f); - else - return 0.5f*PI + atan2(-x / y, 1.0f); - }else{ - if(x > 0.0f) - return 1.5f*PI + atan2(x / -y, 1.0f); - else - return 1.5f*PI - atan2(-x / -y, 1.0f); - } - }else{ - if(y > 0.0f){ - if(x > 0.0f) - return atan2(y / x, 1.0f); - else - return PI - atan2(y / -x, 1.0f); - }else{ - if(x > 0.0f) - return 2.0f*PI - atan2(-y / x, 1.0f); - else - return PI + atan2(-y / -x, 1.0f); - } - } - } - - static float LimitRadianAngle(float angle) - { - float result; - - if (angle < -25.0f) - result = -25.0f; - else if (angle > 25.0f) - result = 25.0f; - else - result = angle; - - while (result >= PI) { - result -= 2 * PI; - } - - while (result < -PI) { - result += 2 * PI; - } - - return result; - } - - static float GetRadianAngleBetweenPoints(float x1, float y1, float x2, float y2) - { - float x = x2 - x1; - float y = y2 - y1; - - if (y == 0.0f) - y = 0.0001f; - - if (x > 0.0f) { - if (y > 0.0f) - return PI - atan2(x / y, 1.0f); - else - return -atan2(x / y, 1.0f); - } else { - if (y > 0.0f) - return -(PI + atan2(x / y, 1.0f)); - else - return -atan2(x / y, 1.0f); - } - } - - // not too sure about all these... - static uint16 GetRandomNumber(void) - { return myrand() & MYRAND_MAX; } - // Probably don't want to ever reach high - static float GetRandomNumberInRange(float low, float high) - { return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); } - - static int32 GetRandomNumberInRange(int32 low, int32 high) - { return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); } -}; diff --git a/src/Lists.cpp b/src/Lists.cpp deleted file mode 100644 index 448a0ff1..00000000 --- a/src/Lists.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "common.h" -#include "Pools.h" -#include "Lists.h" - -void* -CPtrNode::operator new(size_t){ - CPtrNode *node = CPools::GetPtrNodePool()->New(); - assert(node); - return node; -} - -void -CPtrNode::operator delete(void *p, size_t){ - CPools::GetPtrNodePool()->Delete((CPtrNode*)p); -} - -void* -CEntryInfoNode::operator new(size_t){ - CEntryInfoNode *node = CPools::GetEntryInfoNodePool()->New(); - assert(node); - return node; -} -void -CEntryInfoNode::operator delete(void *p, size_t){ - CPools::GetEntryInfoNodePool()->Delete((CEntryInfoNode*)p); -} diff --git a/src/Lists.h b/src/Lists.h deleted file mode 100644 index 7572e882..00000000 --- a/src/Lists.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -class CPtrNode -{ -public: - void *item; - CPtrNode *prev; - CPtrNode *next; - - void *operator new(size_t); - void operator delete(void *p, size_t); -}; - -class CPtrList -{ -public: - CPtrNode *first; - - CPtrList(void) { first = nil; } - ~CPtrList(void) { Flush(); } - CPtrNode *FindItem(void *item){ - CPtrNode *node; - for(node = first; node; node = node->next) - if(node->item == item) - return node; - return nil; - } - CPtrNode *InsertNode(CPtrNode *node){ - node->prev = nil; - node->next = first; - if(first) - first->prev = node; - first = node; - return node; - } - CPtrNode *InsertItem(void *item){ - CPtrNode *node = new CPtrNode; - node->item = item; - InsertNode(node); - return node; - } - void RemoveNode(CPtrNode *node){ - if(node == first) - first = node->next; - if(node->prev) - node->prev->next = node->next; - if(node->next) - node->next->prev = node->prev; - } - void DeleteNode(CPtrNode *node){ - RemoveNode(node); - delete node; - } - void RemoveItem(void *item){ - CPtrNode *node, *next; - for(node = first; node; node = next){ - next = node->next; - if(node->item == item) - DeleteNode(node); - } - } - void Flush(void){ - CPtrNode *node, *next; - for(node = first; node; node = next){ - next = node->next; - DeleteNode(node); - } - } -}; - -class CSector; - -// This records in which sector list a Physical is -class CEntryInfoNode -{ -public: - CPtrList *list; // list in sector - CPtrNode *listnode; // node in list - CSector *sector; - - CEntryInfoNode *prev; - CEntryInfoNode *next; - - void *operator new(size_t); - void operator delete(void *p, size_t); -}; - -class CEntryInfoList -{ -public: - CEntryInfoNode *first; - - CEntryInfoList(void) { first = nil; } - ~CEntryInfoList(void) { Flush(); } - CEntryInfoNode *InsertNode(CEntryInfoNode *node){ - node->prev = nil; - node->next = first; - if(first) - first->prev = node; - first = node; - return node; - } - CEntryInfoNode *InsertItem(CPtrList *list, CPtrNode *listnode, CSector *sect){ - CEntryInfoNode *node = new CEntryInfoNode; - node->list = list; - node->listnode = listnode; - node->sector = sect; - InsertNode(node); - return node; - } - void RemoveNode(CEntryInfoNode *node){ - if(node == first) - first = node->next; - if(node->prev) - node->prev->next = node->next; - if(node->next) - node->next->prev = node->prev; - } - void DeleteNode(CEntryInfoNode *node){ - RemoveNode(node); - delete node; - } - void Flush(void){ - CEntryInfoNode *node, *next; - for(node = first; node; node = next){ - next = node->next; - DeleteNode(node); - } - } -}; diff --git a/src/MenuScreens.h b/src/MenuScreens.h deleted file mode 100644 index 2da81f1d..00000000 --- a/src/MenuScreens.h +++ /dev/null @@ -1,380 +0,0 @@ -#pragma once - -const CMenuScreen aScreens[] = { - // MENUPAGE_NONE = 0 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, }, - - // MENUPAGE_STATS = 1 - { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_NEW_GAME = 2 - { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1, - MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD, - MENUACTION_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, - MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_BRIEFS = 3 - { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENU_CONTROLLER_SETTINGS = 4 - { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_SOUND_SETTINGS = 5 - { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1, - MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_SPEAKERCONF, "FEA_SPK", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_DYNAMICACOUSTIC, "FET_DAM", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_RADIO, "FEA_RSS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - }, - - // MENUPAGE_GRAPHICS_SETTINGS = 6 - { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2, - MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - //MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_WIDESCREEN, "FED_WIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_SCREENRES, "FED_RES", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_LANGUAGE_SETTINGS = 7 - { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3, - MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_CHOOSE_LOAD_SLOT = 8 - { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1, - MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, - MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM, - }, - - // MENUPAGE_CHOOSE_DELETE_SLOT = 9 - { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2, - MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, - MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM, - MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM, - }, - - // MENUPAGE_NEW_GAME_RELOAD = 10 - { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME, - MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_LOAD_SLOT_CONFIRM = 11 - { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, - MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS, - }, - - // MENUPAGE_DELETE_SLOT_CONFIRM = 12 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, - MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING, - }, - - // MENUPAGE_13 = 13 - { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_LOADING_IN_PROGRESS = 14 - { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM, - }, - - // MENUPAGE_DELETING_IN_PROGRESS = 15 - { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_16 = 16 - { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_DELETE_FAILED = 17 - { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, - }, - - // MENUPAGE_DEBUG_MENU = 18 - { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MEMORY_CARD_1 = 19 - { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MEMORY_CARD_2 = 20 - { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_MAIN = 21 - { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_SAVE_FAILED_1 = 22 - { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_SAVE_FAILED_2 = 23 - { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_SAVE = 24 - { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, - MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_NO_MEMORY_CARD = 25 - { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CHOOSE_SAVE_SLOT = 26 - { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_UPDATESAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - MENUACTION_UPDATESAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM, - }, - - // MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS, - MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, - }, - - // MENUPAGE_MULTIPLAYER_MAP = 28 - { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_CONNECTION = 29 - { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_FIND_GAME = 30 - { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_MODE = 31 - { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_CREATE = 32 - { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_MULTIPLAYER_START = 33 - { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_SKIN_SELECT_OLD = 34 - { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CONTROLLER_PC = 35 - { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, - MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, - MENUACTION_CHANGEMENU, "FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS, - MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, - MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_CONTROLLER_PC_OLD1 = 36 - { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CONTROLLER_PC_OLD2 = 37 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CONTROLLER_PC_OLD3 = 38 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CONTROLLER_PC_OLD4 = 39 - { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_CONTROLLER_DEBUG = 40 - { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_OPTIONS = 41 - { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4, - MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, - MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, - MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, - MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS, - //MENUACTION_CHANGEMENU, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_EXIT = 42 - { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5, - MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_SAVING_IN_PROGRESS = 43 - { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_SAVE_SUCCESSFUL = 44 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE, - MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, - }, - - // MENUPAGE_DELETING = 45 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_DELETE_SUCCESS = 46 - { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, - }, - - // MENUPAGE_SAVE_FAILED = 47 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, - }, - - // MENUPAGE_LOAD_FAILED = 48 - { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_LOAD_FAILED_2 = 49 - { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, - MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, - }, - - // MENUPAGE_FILTER_GAME = 50 - { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_START_MENU = 51 - { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, - MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, - MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT, - }, - - // MENUPAGE_PAUSE_MENU = 52 - { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE, - MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, - MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS, - MENUACTION_CHANGEMENU, "FEP_BRI", SAVESLOT_NONE, MENUPAGE_BRIEFS, - MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, - MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT, - }, - - // MENUPAGE_CHOOSE_MODE = 53 - { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_SKIN_SELECT = 54 - { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4, - //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN, - }, - - // MENUPAGE_KEYBOARD_CONTROLS = 55 - { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1, - //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, - }, - - // MENUPAGE_MOUSE_CONTROLS = 56 - { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_2, - MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, - MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, - MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, - - // MENUPAGE_57 = 57 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, - - // MENUPAGE_58 = 58 - { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, - - }, -}; diff --git a/src/Messages.cpp b/src/Messages.cpp deleted file mode 100644 index 7fc23593..00000000 --- a/src/Messages.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Messages.h" - -WRAPPER void CMessages::Display(void) { EAXJMP(0x529800); } -WRAPPER void CMessages::ClearAllMessagesDisplayedByGame(void) { EAXJMP(0x52B670); } -WRAPPER int CMessages::WideStringCopy(wchar* dst, wchar* src, unsigned short size) { EAXJMP(0x5294B0); } -WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned short size) { EAXJMP(0x529510); } -WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); } -WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); } -WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); } - -tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08; -tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0; -tBigMessage *CMessages::BIGMessages = (tBigMessage *)0x773628; diff --git a/src/Messages.h b/src/Messages.h deleted file mode 100644 index 69cf117c..00000000 --- a/src/Messages.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -struct tMessage -{ - wchar *m_pText; - uint16 m_nFlag; -private: - int8 _pad6[2]; -public: - uint32 m_nTime; - uint32 m_nStartTime; - int32 m_nNumber[6]; - wchar *m_pString; -}; - -struct tBigMessage -{ - tMessage m_Current; - tMessage m_Stack[3]; -}; - -struct tPreviousBrief -{ - wchar *m_pText; - int32 m_nNumber[6]; - wchar *m_pString; -}; - -class CMessages -{ -public: - static tPreviousBrief *PreviousBriefs; - static tMessage *BriefMessages; - static tBigMessage *BIGMessages; - -public: - static void Display(void); - static void ClearAllMessagesDisplayedByGame(void); - static int WideStringCopy(wchar* dst, wchar* src, unsigned short size); - static char WideStringCompare(wchar* str1, wchar* str2, unsigned short size); - static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst); - static void InsertPlayerControlKeysInString(wchar* src); - static int GetWideStringLength(wchar *src); -}; diff --git a/src/MloInstance.cpp b/src/MloInstance.cpp deleted file mode 100644 index dbd83727..00000000 --- a/src/MloInstance.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "MloInstance.h" - -STARTPATCHES -InjectHook(0x50BE90, &CMloInstance::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/MloInstance.h b/src/MloInstance.h deleted file mode 100644 index 00afc379..00000000 --- a/src/MloInstance.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "Placeable.h" - -class CMloInstance : CPlaceable -{ -public: - void dtor() { this->CMloInstance::~CMloInstance(); } -}; \ No newline at end of file diff --git a/src/NodeName.cpp b/src/NodeName.cpp deleted file mode 100644 index 2aea3c83..00000000 --- a/src/NodeName.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "NodeName.h" - -static int32 &gPluginOffset = *(int32*)0x64C610; - -enum -{ - ID_NODENAME = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0xFE), -}; - -#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset)) - -void* -NodeNameConstructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - if(gPluginOffset > 0) - NODENAMEEXT(object)[0] = '\0'; - return object; -} - -void* -NodeNameDestructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - return object; -} - -void* -NodeNameCopy(void *dstObject, const void *srcObject, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - strncpy(NODENAMEEXT(dstObject), NODENAMEEXT(srcObject), 23); - return nil; -} - -RwStream* -NodeNameStreamRead(RwStream *stream, RwInt32 binaryLength, void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - RwStreamRead(stream, NODENAMEEXT(object), binaryLength); - NODENAMEEXT(object)[binaryLength] = '\0'; - return stream; -} - -RwStream* -NodeNameStreamWrite(RwStream *stream, RwInt32 binaryLength, const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - RwStreamWrite(stream, NODENAMEEXT(object), binaryLength); - return stream; -} - -RwInt32 -NodeNameStreamGetSize(const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) -{ - // game checks for null pointer on node name extension but that really happen - return rwstrlen(NODENAMEEXT(object)); -} - -bool -NodeNamePluginAttach(void) -{ - gPluginOffset = RwFrameRegisterPlugin(24, ID_NODENAME, - NodeNameConstructor, - NodeNameDestructor, - NodeNameCopy); - RwFrameRegisterPluginStream(ID_NODENAME, - NodeNameStreamRead, - NodeNameStreamWrite, - NodeNameStreamGetSize); - return gPluginOffset != -1; -} - -char* -GetFrameNodeName(RwFrame *frame) -{ - if(gPluginOffset < 0) - return nil; - return NODENAMEEXT(frame); -} diff --git a/src/NodeName.h b/src/NodeName.h deleted file mode 100644 index 1a3e057b..00000000 --- a/src/NodeName.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -bool NodeNamePluginAttach(void); -char *GetFrameNodeName(RwFrame *frame); diff --git a/src/PCSave.cpp b/src/PCSave.cpp deleted file mode 100644 index 628e1218..00000000 --- a/src/PCSave.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Frontend.h" -#include "PCSave.h" - -WRAPPER void C_PcSave::SetSaveDirectory(const char *path) { EAXJMP(0x591EA0); } -WRAPPER int8 C_PcSave::PopulateSlotInfo() { EAXJMP(0x592090); } -WRAPPER int8 C_PcSave::DeleteSlot(int) { EAXJMP(0x5922F0); } -WRAPPER int8 C_PcSave::SaveSlot(int) { EAXJMP(0x591EC0); } - -WRAPPER int8 CheckSlotDataValid(int) { EAXJMP(0x591A40); } - -WRAPPER wchar *GetNameOfSavedGame(int counter) { EAXJMP(0x591B60); } -WRAPPER wchar *GetSavedGameDateAndTime(int counter) { EAXJMP(0x591B50); } - - -C_PcSave PcSaveHelper = *(C_PcSave*)0x8E2C60; -int *Slots = (int*)0x728040; -int *SlotFileName = (int*)0x6F07C8; -int *SlotSaveDate = (int*)0x72B858; diff --git a/src/PCSave.h b/src/PCSave.h deleted file mode 100644 index 696e158a..00000000 --- a/src/PCSave.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -class C_PcSave -{ -public: - int32 m_nHelper; - - static void SetSaveDirectory(const char *path); - int8 PopulateSlotInfo(); - int8 DeleteSlot(int); - int8 SaveSlot(int); -}; - -extern int8 CheckSlotDataValid(int); -extern wchar *GetNameOfSavedGame(int counter); -extern wchar *GetSavedGameDateAndTime(int counter); - -extern C_PcSave PcSaveHelper; -extern int *Slots; -extern int *SlotFileName; -extern int *SlotSaveDate; diff --git a/src/Pad.cpp b/src/Pad.cpp deleted file mode 100644 index 002e7180..00000000 --- a/src/Pad.cpp +++ /dev/null @@ -1,2091 +0,0 @@ -#pragma warning( push ) -#pragma warning( disable : 4005) -#define DIRECTINPUT_VERSION 0x0800 -#include -#pragma warning( pop ) - -#include "common.h" -#include "patcher.h" -#include "Pad.h" -#include "ControllerConfig.h" -#include "Timer.h" -#include "Frontend.h" -#include "Camera.h" -#include "Game.h" -#include "CutsceneMgr.h" -#include "Font.h" -#include "Hud.h" -#include "Text.h" -#include "Timer.h" -#include "World.h" -#include "Vehicle.h" -#include "Ped.h" -#include "Population.h" -#include "Replay.h" -#include "Weather.h" -#include "win.h" - -CPad *Pads = (CPad*)0x6F0360; // [2] -CMousePointerStateHelper &MousePointerStateHelper = *(CMousePointerStateHelper*)0x95CC8C; - -bool &CPad::bDisplayNoControllerMessage = *(bool *)0x95CD52; -bool &CPad::bObsoleteControllerMessage = *(bool *)0x95CDB8; -bool &CPad::m_bMapPadOneToPadTwo = *(bool *)0x95CD48; - -CKeyboardState &CPad::OldKeyState = *(CKeyboardState*)0x6F1E70; -CKeyboardState &CPad::NewKeyState = *(CKeyboardState*)0x6E60D0; -CKeyboardState &CPad::TempKeyState = *(CKeyboardState*)0x774DE8; - -char CPad::KeyBoardCheatString[18]; - -CMouseControllerState &CPad::OldMouseControllerState = *(CMouseControllerState*)0x8472A0; -CMouseControllerState &CPad::NewMouseControllerState = *(CMouseControllerState*)0x8809F0; -CMouseControllerState &CPad::PCTempMouseControllerState = *(CMouseControllerState*)0x6F1E60; - -_TODO("gbFastTime"); -extern bool &gbFastTime; - -WRAPPER void WeaponCheat() { EAXJMP(0x490D90); } -WRAPPER void HealthCheat() { EAXJMP(0x490E70); } -WRAPPER void TankCheat() { EAXJMP(0x490EE0); } -WRAPPER void BlowUpCarsCheat() { EAXJMP(0x491040); } -WRAPPER void ChangePlayerCheat() { EAXJMP(0x4910B0); } -WRAPPER void MayhemCheat() { EAXJMP(0x4911C0); } -WRAPPER void EverybodyAttacksPlayerCheat() { EAXJMP(0x491270); } -WRAPPER void WeaponsForAllCheat() { EAXJMP(0x491370); } -WRAPPER void FastTimeCheat() { EAXJMP(0x4913A0); } -WRAPPER void SlowTimeCheat() { EAXJMP(0x4913F0); } -WRAPPER void MoneyCheat() { EAXJMP(0x491430); } -WRAPPER void ArmourCheat() { EAXJMP(0x491460); } -WRAPPER void WantedLevelUpCheat() { EAXJMP(0x491490); } -WRAPPER void WantedLevelDownCheat() { EAXJMP(0x4914F0); } -WRAPPER void SunnyWeatherCheat() { EAXJMP(0x491520); } -WRAPPER void CloudyWeatherCheat() { EAXJMP(0x491550); } -WRAPPER void RainyWeatherCheat() { EAXJMP(0x491580); } -WRAPPER void FoggyWeatherCheat() { EAXJMP(0x4915B0); } -WRAPPER void FastWeatherCheat() { EAXJMP(0x4915E0); } -WRAPPER void OnlyRenderWheelsCheat() { EAXJMP(0x491610); } -WRAPPER void ChittyChittyBangBangCheat() { EAXJMP(0x491640); } -WRAPPER void StrongGripCheat() { EAXJMP(0x491670); } -WRAPPER void NastyLimbsCheat() { EAXJMP(0x4916A0); } -////////////////////////////////////////////////////////////////////////// - -#ifdef KANGAROO_CHEAT -void KangarooCheat() -{ - wchar *string; - CPed *playerPed = FindPlayerPed(); - int m_fMass; - - if (playerPed->m_ped_flagI80) { - string = TheText.Get("CHEATOF"); - m_fMass = 70.0f; - } else { - string = TheText.Get("CHEAT1"); - m_fMass = 15.0f; - } - CHud::SetHelpMessage(string, 1); - playerPed->m_ped_flagI80 = !playerPed->m_ped_flagI80; - - playerPed->m_fMass = m_fMass; - playerPed->m_fAirResistance = 0.4f / m_fMass; -} -#endif - -void -CControllerState::Clear(void) -{ - LeftStickX = LeftStickY = RightStickX = RightStickY = 0; - LeftShoulder1 = LeftShoulder2 = RightShoulder1 = RightShoulder2 = 0; - DPadUp = DPadDown = DPadLeft = DPadRight = 0; - Start = Select = 0; - Square = Triangle = Cross = Circle = 0; - LeftShock = RightShock = 0; - NetworkTalk = 0; -} - -void CKeyboardState::Clear() -{ - for ( int32 i = 0; i < 12; i++ ) - F[i] = 0; - - for ( int32 i = 0; i < 256; i++ ) - VK_KEYS[i] = 0; - - ESC = INS = DEL = HOME = END = PGUP = PGDN = 0; - - UP = DOWN = LEFT = RIGHT = 0; - - NUMLOCK = 0; - - DIV = MUL = SUB = ADD = 0; - - DECIMAL = NUM1 = NUM2 = NUM3 = NUM4 = 0; - - NUM5 = NUM6 = NUM7 = NUM8 = 0; - - NUM9 = NUM0 = SCROLLLOCK = PAUSE = 0; - - BACKSP = TAB = CAPSLOCK = EXTENTER = 0; - - LSHIFT = SHIFT = RSHIFT = LCTRL = RCTRL = LALT = RALT = 0; - - LWIN = RWIN = APPS = 0; -} - -void CPad::Clear(bool bResetPlayerControls) -{ - NewState.Clear(); - OldState.Clear(); - - PCTempKeyState.Clear(); - PCTempJoyState.Clear(); - PCTempMouseState.Clear(); - - NewKeyState.Clear(); - OldKeyState.Clear(); - TempKeyState.Clear(); - - NewMouseControllerState.Clear(); - OldMouseControllerState.Clear(); - PCTempMouseControllerState.Clear(); - - Phase = 0; - ShakeFreq = 0; - ShakeDur = 0; - - if ( bResetPlayerControls ) - DisablePlayerControls = false; - - bApplyBrakes = false; - - - for ( int32 i = 0; i < _TODOCONST(5); i++ ) - bHornHistory[i] = false; - - iCurrHornHistory = 0; - - for ( int32 i = 0; i < _TODOCONST(12); i++ ) - _unk[i] = ' '; - - LastTimeTouched = CTimer::GetTimeInMilliseconds(); - AverageWeapon = 0; - AverageEntries = 0; -} - -void CPad::ClearMouseHistory() -{ - PCTempMouseControllerState.Clear(); - NewMouseControllerState.Clear(); - OldMouseControllerState.Clear(); -} - -CMouseControllerState::CMouseControllerState() -{ - LMB = 0; - RMB = 0; - MMB = 0; - WHEELUP = 0; - WHEELDN = 0; - MXB1 = 0; - MXB2 = 0; - - x = 0.0f; - y = 0.0f; -} - -void CMouseControllerState::Clear() -{ - LMB = 0; - RMB = 0; - MMB = 0; - WHEELUP = 0; - WHEELDN = 0; - MXB1 = 0; - MXB2 = 0; -} - -CMouseControllerState CMousePointerStateHelper::GetMouseSetUp() -{ - CMouseControllerState state; - - if ( PSGLOBAL(mouse) == nil ) - _InputInitialiseMouse(); - - if ( PSGLOBAL(mouse) != nil ) - { - DIDEVCAPS devCaps; - devCaps.dwSize = sizeof(DIDEVCAPS); - - PSGLOBAL(mouse)->GetCapabilities(&devCaps); - - switch ( devCaps.dwButtons ) - { - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - state.MMB = true; - - case 2: - state.RMB = true; - - case 1: - state.LMB = true; - } - - if ( devCaps.dwAxes == 3 ) - { - state.WHEELDN = true; - state.WHEELUP = true; - } - } - - return state; -} - -void CPad::UpdateMouse() -{ - if ( IsForegroundApp() ) - { - if ( PSGLOBAL(mouse) == nil ) - _InputInitialiseMouse(); - - DIMOUSESTATE2 state; - - if ( PSGLOBAL(mouse) != nil && SUCCEEDED(_InputGetMouseState(&state)) ) - { - int32 signX = 1; - int32 signy = 1; - - if ( !FrontEndMenuManager.m_bMenuActive ) - { - if ( MousePointerStateHelper.bInvertVertically ) - signy = -1; - if ( MousePointerStateHelper.bInvertHorizontally ) - signX = -1; - } - - PCTempMouseControllerState.Clear(); - - PCTempMouseControllerState.x = (float)(signX * state.lX); - PCTempMouseControllerState.y = (float)(signy * state.lY); - PCTempMouseControllerState.LMB = state.rgbButtons[0] & 128; - PCTempMouseControllerState.RMB = state.rgbButtons[1] & 128; - PCTempMouseControllerState.MMB = state.rgbButtons[2] & 128; - PCTempMouseControllerState.MXB1 = state.rgbButtons[3] & 128; - PCTempMouseControllerState.MXB2 = state.rgbButtons[4] & 128; - - if ( state.lZ > 0 ) - PCTempMouseControllerState.WHEELUP = 1; - else if ( state.lZ < 0 ) - PCTempMouseControllerState.WHEELDN = 1; - - OldMouseControllerState = NewMouseControllerState; - NewMouseControllerState = PCTempMouseControllerState; - } - } -} - -CControllerState CPad::ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2) -{ - static CControllerState ReconState; - - ReconState.Clear(); - -#define _RECONCILE_BUTTON(button) \ - { if ( State1.button || State2.button ) ReconState.button = 255; } - -#define _RECONCILE_AXIS_POSITIVE(axis) \ - { if ( State1.axis >= 0 && State2.axis >= 0 ) ReconState.axis = max(State1.axis, State2.axis); } - -#define _RECONCILE_AXIS_NEGATIVE(axis) \ - { if ( State1.axis <= 0 && State2.axis <= 0 ) ReconState.axis = min(State1.axis, State2.axis); } - -#define _RECONCILE_AXIS(axis) \ - { _RECONCILE_AXIS_POSITIVE(axis); _RECONCILE_AXIS_NEGATIVE(axis); } - -#define _FIX_AXIS_DIR(axis) \ - { if ( State1.axis > 0 && State2.axis < 0 || State1.axis < 0 && State2.axis > 0 ) ReconState.axis = 0; } - -#define _FIX_RECON_DIR(pos, neg, axis) \ - { if ( (ReconState.pos || ReconState.axis < 0) && (ReconState.neg || ReconState.axis > 0) ) { ReconState.pos = 0; ReconState.neg = 0; ReconState.axis = 0; } } - - _RECONCILE_BUTTON(LeftShoulder1); - _RECONCILE_BUTTON(LeftShoulder2); - _RECONCILE_BUTTON(RightShoulder1); - _RECONCILE_BUTTON(RightShoulder2); - _RECONCILE_BUTTON(Start); - _RECONCILE_BUTTON(Select); - _RECONCILE_BUTTON(Square); - _RECONCILE_BUTTON(Triangle); - _RECONCILE_BUTTON(Cross); - _RECONCILE_BUTTON(Circle); - _RECONCILE_BUTTON(LeftShock); - _RECONCILE_BUTTON(RightShock); - _RECONCILE_BUTTON(NetworkTalk); - _RECONCILE_AXIS(LeftStickX); - _RECONCILE_AXIS(LeftStickY); - _FIX_AXIS_DIR(LeftStickX); - _FIX_AXIS_DIR(LeftStickY); - _RECONCILE_AXIS(RightStickX); - _RECONCILE_AXIS(RightStickY); - _FIX_AXIS_DIR(RightStickX); - _FIX_AXIS_DIR(RightStickY); - _RECONCILE_BUTTON(DPadUp); - _RECONCILE_BUTTON(DPadDown); - _RECONCILE_BUTTON(DPadLeft); - _RECONCILE_BUTTON(DPadRight); - _FIX_RECON_DIR(DPadUp, DPadDown, LeftStickY); - _FIX_RECON_DIR(DPadLeft, DPadRight, LeftStickX); - - return ReconState; - -#undef _RECONCILE_BUTTON -#undef _RECONCILE_AXIS_POSITIVE -#undef _RECONCILE_AXIS_NEGATIVE -#undef _RECONCILE_AXIS -#undef _FIX_AXIS_DIR -#undef _FIX_RECON_DIR -} - -void CPad::StartShake(int16 nDur, uint8 nFreq) -{ - if ( !CMenuManager::m_PrefsUseVibration ) - return; - - if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) - return; - - if ( nFreq == 0 ) - { - ShakeDur = 0; - ShakeFreq = 0; - return; - } - - if ( nDur > ShakeDur ) - { - ShakeDur = nDur; - ShakeFreq = nFreq; - } -} - -void CPad::StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fZ) -{ - if ( !CMenuManager::m_PrefsUseVibration ) - return; - - if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) - return; - - float fDist = ( TheCamera.GetPosition() - CVector(fX, fY, fZ) ).Magnitude(); - - if ( fDist < 70.0f ) - { - if ( nFreq == 0 ) - { - ShakeDur = 0; - ShakeFreq = 0; - return; - } - - if ( nDur > ShakeDur ) - { - ShakeDur = nDur; - ShakeFreq = nFreq; - } - } -} - -void CPad::StartShake_Train(float fX, float fY) -{ - if ( !CMenuManager::m_PrefsUseVibration ) - return; - - if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) - return; - - if (FindPlayerVehicle() != nil && FindPlayerVehicle()->IsTrain() ) - return; - - float fDist = ( TheCamera.GetPosition() - CVector(fX, fY, 0.0f) ).Magnitude2D(); - - if ( fDist < 70.0f ) - { - int32 freq = (int32)((70.0f - fDist) * 70.0f / 70.0f + 30.0f); - - if ( ShakeDur < 100 ) - { - ShakeDur = 100; - ShakeFreq = freq; - } - } -} - -void CPad::AddToPCCheatString(char c) -{ - for ( int32 i = ARRAY_SIZE(KeyBoardCheatString); i >= 0; i-- ) - KeyBoardCheatString[i + 1] = KeyBoardCheatString[i]; - - KeyBoardCheatString[0] = c; - - #define _CHEATCMP(str) strncmp(str, KeyBoardCheatString, sizeof(str)-1) - - // "GUNSGUNSGUNS" - if ( !_CHEATCMP("SNUGSNUGSNUG") ) - WeaponCheat(); - - // "IFIWEREARICHMAN" - if ( !_CHEATCMP("NAMHCIRAEREWIFI") ) - MoneyCheat(); - - // "GESUNDHEIT" - if ( !_CHEATCMP("TIEHDNUSEG") ) - HealthCheat(); - - // "MOREPOLICEPLEASE" - if ( !_CHEATCMP("ESAELPECILOPEROM") ) - WantedLevelUpCheat(); - - // "NOPOLICEPLEASE" - if ( !_CHEATCMP("ESAELPECILOPON") ) - WantedLevelDownCheat(); - - // "GIVEUSATANK" - if ( !_CHEATCMP("KNATASUEVIG") ) - TankCheat(); - - // "BANGBANGBANG" - if ( !_CHEATCMP("GNABGNABGNAB") ) - BlowUpCarsCheat(); - - // "ILIKEDRESSINGUP" - if ( !_CHEATCMP("PUGNISSERDEKILI") ) - ChangePlayerCheat(); - - // "ITSALLGOINGMAAAD" - if ( !_CHEATCMP("DAAAMGNIOGLLASTI") ) - MayhemCheat(); - - // "NOBODYLIKESME" - if ( !_CHEATCMP("EMSEKILYDOBON") ) - EverybodyAttacksPlayerCheat(); - - // "WEAPONSFORALL" - if ( !_CHEATCMP("LLAROFSNOPAEW") ) - WeaponsForAllCheat(); - - // "TIMEFLIESWHENYOU" - if ( !_CHEATCMP("UOYNEHWSEILFEMIT") ) - FastTimeCheat(); - - // "BOOOOORING" - if ( !_CHEATCMP("GNIROOOOOB") ) - SlowTimeCheat(); - -#ifndef GTA3_1_1_PATCH - // "TURTOISE" - if ( !_CHEATCMP("ESIOTRUT") ) - ArmourCheat(); -#else - // "TORTOISE" - if ( !_CHEATCMP("ESIOTROT") ) - ArmourCheat(); -#endif - - // "SKINCANCERFORME" - if ( !_CHEATCMP("EMROFRECNACNIKS") ) - SunnyWeatherCheat(); - - // "ILIKESCOTLAND" - if ( !_CHEATCMP("DNALTOCSEKILI") ) - CloudyWeatherCheat(); - - // "ILOVESCOTLAND" - if ( !_CHEATCMP("DNALTOCSEVOLI") ) - RainyWeatherCheat(); - - // "PEASOUP" - if ( !_CHEATCMP("PUOSAEP") ) - FoggyWeatherCheat(); - - // "MADWEATHER" - if ( !_CHEATCMP("REHTAEWDAM") ) - FastWeatherCheat(); - - // "ANICESETOFWHEELS" - if ( !_CHEATCMP("SLEEHWFOTESECINA") ) - OnlyRenderWheelsCheat(); - - // "CHITTYCHITTYBB" - if ( !_CHEATCMP("BBYTTIHCYTTIHC") ) - ChittyChittyBangBangCheat(); - - // "CORNERSLIKEMAD" - if ( !_CHEATCMP("DAMEKILSRENROC") ) - StrongGripCheat(); - - // "NASTYLIMBSCHEAT" - if ( !_CHEATCMP("TAEHCSBMILYTSAN") ) - NastyLimbsCheat(); - -#ifdef KANGAROO_CHEAT - // "KANGAROO" - if (!_CHEATCMP("OORAGNAK")) - KangarooCheat(); -#endif - - #undef _CHEATCMP -} - -void CPad::UpdatePads(void) -{ - bool bUpdate = true; - - GetPad(0)->UpdateMouse(); - CapturePad(0); - - - ControlsManager.ClearSimButtonPressCheckers(); - ControlsManager.AffectPadFromKeyBoard(); - ControlsManager.AffectPadFromMouse(); - - if ( CReplay::IsPlayingBackFromFile() ) - bUpdate = false; - - if ( bUpdate ) - { - GetPad(0)->Update(0); - } - - GetPad(1)->NewState.Clear(); - GetPad(1)->OldState.Clear(); - - OldKeyState = NewKeyState; - NewKeyState = TempKeyState; -} - -void CPad::ProcessPCSpecificStuff(void) -{ - ; -} - -void CPad::Update(int16 unk) -{ - OldState = NewState; - - NewState = ReconcileTwoControllersInput(PCTempKeyState, PCTempJoyState); - NewState = ReconcileTwoControllersInput(PCTempMouseState, NewState); - - PCTempJoyState.Clear(); - PCTempKeyState.Clear(); - PCTempMouseState.Clear(); - - ProcessPCSpecificStuff(); - - if ( ++iCurrHornHistory >= _TODOCONST(5) ) - iCurrHornHistory = 0; - - bHornHistory[iCurrHornHistory] = GetHorn(); - - - if ( !bDisplayNoControllerMessage ) - CGame::bDemoMode = false; -} - -void CPad::DoCheats(void) -{ - GetPad(0)->DoCheats(0); -} - -void CPad::DoCheats(int16 unk) -{ -#ifdef PS2 - if ( GetTriangleJustDown() ) - AddToCheatString('T'); - - if ( GetCircleJustDown() ) - AddToCheatString('C'); - - if ( GetCrossJustDown() ) - AddToCheatString('X'); - - if ( GetSquareJustDown() ) - AddToCheatString('S'); - - if ( GetDPadUpJustDown() ) - AddToCheatString('U'); - - if ( GetDPadDownJustDown() ) - AddToCheatString('D'); - - if ( GetDPadLeftJustDown() ) - AddToCheatString('L'); - - if ( GetDPadRightJustDown() ) - AddToCheatString('R'); - - if ( GetLeftShoulder1JustDown() ) - AddToCheatString('1'); - - if ( GetLeftShoulder2JustDown() ) - AddToCheatString('2'); - - if ( GetRightShoulder1JustDown() ) - AddToCheatString('3'); - - if ( GetRightShoulder2JustDown() ) - AddToCheatString('4'); -#endif -} - -void CPad::StopPadsShaking(void) -{ - GetPad(0)->StopShaking(0); -} - -void CPad::StopShaking(int16 unk) -{ - ; -} - -CPad *CPad::GetPad(int32 pad) -{ - return &Pads[pad]; -} - -int16 CPad::GetSteeringLeftRight(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - int16 axis = NewState.LeftStickX; - int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; - - break; - } - - case 1: - case 3: - { - return NewState.LeftStickX; - - break; - } - } - - return 0; -} - -int16 CPad::GetSteeringUpDown(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - int16 axis = NewState.LeftStickY; - int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; - - break; - } - - case 1: - case 3: - { - return NewState.LeftStickY; - - break; - } - } - - return 0; -} - -int16 CPad::GetCarGunUpDown(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return NewState.RightStickY; - - break; - } - - case 3: - { - return (NewState.DPadUp - NewState.DPadDown) / 2; - - break; - } - } - - return 0; -} - -int16 CPad::GetCarGunLeftRight(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return NewState.RightStickX; - - break; - } - - case 3: - { - return (NewState.DPadRight - NewState.DPadLeft) / 2; - - break; - } - } - - return 0; -} - -int16 CPad::GetPedWalkLeftRight(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - int16 axis = NewState.LeftStickX; - int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; - - break; - } - - case 1: - case 3: - { - return NewState.LeftStickX; - - break; - } - } - - return 0; -} - - -int16 CPad::GetPedWalkUpDown(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - int16 axis = NewState.LeftStickY; - int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; - - break; - } - - case 1: - case 3: - { - return NewState.LeftStickY; - - break; - } - } - - return 0; -} - -int16 CPad::GetAnalogueUpDown(void) -{ - switch ( Mode ) - { - case 0: - case 2: - { - int16 axis = NewState.LeftStickY; - int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; - - break; - } - - case 1: - case 3: - { - return NewState.LeftStickY; - - break; - } - } - - return 0; -} - -bool CPad::GetLookLeft(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2); -} - -bool CPad::GetLookRight(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2); -} - - -bool CPad::GetLookBehindForCar(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.RightShoulder2 && NewState.LeftShoulder2); -} - -bool CPad::GetLookBehindForPed(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!NewState.RightShock; -} - -bool CPad::GetHorn(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - { - return !!NewState.LeftShock; - - break; - } - - case 1: - { - return !!NewState.LeftShoulder1; - - break; - } - - case 2: - { - return !!NewState.RightShoulder1; - - break; - } - - case 3: - { - return !!NewState.LeftShock; - - break; - } - } - - return false; -} - -bool CPad::HornJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - { - return !!(NewState.LeftShock && !OldState.LeftShock); - - break; - } - - case 1: - { - return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); - - break; - } - - case 2: - { - return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); - - break; - } - - case 3: - { - return !!(NewState.LeftShock && !OldState.LeftShock); - - break; - } - } - - return false; -} - - -bool CPad::GetCarGunFired(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return !!NewState.Circle; - - break; - } - - case 3: - { - return !!NewState.RightShoulder1; - - break; - } - } - - return false; -} - -bool CPad::CarGunJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return !!(NewState.Circle && !OldState.Circle); - - break; - } - - case 3: - { - return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); - - break; - } - } - - return false; -} - -int16 CPad::GetHandBrake(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 1: - { - return NewState.RightShoulder1; - - break; - } - - case 2: - { - return NewState.Triangle; - - break; - } - - case 3: - { - return NewState.LeftShoulder1; - - break; - } - } - - return 0; -} - -int16 CPad::GetBrake(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - return NewState.Square; - - break; - } - - case 1: - { - return NewState.Square; - - break; - } - - case 3: - { - int16 axis = 2 * NewState.RightStickY; - - if ( axis < 0 ) - return 0; - else - return axis; - - break; - } - } - - return 0; -} - -bool CPad::GetExitVehicle(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 3: - { - return !!NewState.Triangle; - - break; - } - - case 2: - { - return !!NewState.LeftShoulder1; - - break; - } - } - - return false; -} - -bool CPad::ExitVehicleJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 3: - { - return !!(NewState.Triangle && !OldState.Triangle); - - break; - } - - case 2: - { - return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); - - break; - } - } - - return false; -} - -int32 CPad::GetWeapon(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - { - return NewState.Circle; - - break; - } - - case 2: - { - return NewState.Cross; - - break; - } - - case 3: - { - return NewState.RightShoulder1; - - break; - } - } - - return false; -} - -bool CPad::WeaponJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - { - return !!(NewState.Circle && !OldState.Circle); - - break; - } - - case 2: - { - return !!(NewState.Cross && !OldState.Cross); - - break; - } - - case 3: - { - return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); - - break; - } - } - - return false; -} - -int16 CPad::GetAccelerate(void) -{ - if ( DisablePlayerControls ) - return 0; - - switch ( Mode ) - { - case 0: - case 2: - { - return NewState.Cross; - - break; - } - - case 1: - { - return NewState.Cross; - - break; - } - - case 3: - { - int16 axis = -2 * NewState.RightStickY; - - if ( axis < 0 ) - return 0; - else - return axis; - - break; - } - } - - return 0; -} - -bool CPad::CycleCameraModeUpJustDown(void) -{ - switch ( Mode ) - { - case 0: - case 2: - case 3: - { - return !!(NewState.Select && !OldState.Select); - - break; - } - - case 1: - { - return !!(NewState.DPadUp && !OldState.DPadUp); - - break; - } - } - - return false; -} - -bool CPad::CycleCameraModeDownJustDown(void) -{ - switch ( Mode ) - { - case 0: - case 2: - case 3: - { - return false; - - break; - } - - case 1: - { - return !!(NewState.DPadDown && !OldState.DPadDown); - - break; - } - } - - return false; -} - -bool CPad::ChangeStationJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - { - return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); - - break; - } - - case 1: - { - return !!(NewState.Select && !OldState.Select); - - break; - } - - case 2: - { - return !!(NewState.LeftShock && !OldState.LeftShock); - - break; - } - - case 3: - { - return !!(NewState.Circle && !OldState.Circle); - - break; - } - } - - return false; -} - - -bool CPad::CycleWeaponLeftJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); -} - -bool CPad::CycleWeaponRightJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); -} - -bool CPad::GetTarget(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return !!NewState.RightShoulder1; - - break; - } - - case 3: - { - return !!NewState.LeftShoulder1; - - break; - } - } - - return false; -} - -bool CPad::TargetJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 2: - { - return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); - - break; - } - - case 3: - { - return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); - - break; - } - } - - return false; -} - -bool CPad::JumpJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.Square && !OldState.Square); -} - -bool CPad::GetSprint(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 3: - { - return !!NewState.Cross; - - break; - } - - case 2: - { - return !!NewState.Circle; - - break; - } - } - - return false; -} - -bool CPad::ShiftTargetLeftJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); -} - -bool CPad::ShiftTargetRightJustDown(void) -{ - if ( DisablePlayerControls ) - return false; - - return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); -} - -bool CPad::GetAnaloguePadUp(void) -{ - static int16 oldfStickY = 0; - - int16 Y = CPad::GetPad(0)->GetAnalogueUpDown(); - - if ( Y < 0 && oldfStickY >= 0 ) - { - oldfStickY = Y; - return true; - } - else - { - oldfStickY = Y; - return false; - } -} - -bool CPad::GetAnaloguePadDown(void) -{ - static int16 oldfStickY = 0; - - int16 Y = CPad::GetPad(0)->GetAnalogueUpDown(); - - if ( Y > 0 && oldfStickY <= 0 ) - { - oldfStickY = Y; - return true; - } - else - { - oldfStickY = Y; - return false; - } -} - -bool CPad::GetAnaloguePadLeft(void) -{ - static int16 oldfStickX = 0; - - int16 X = CPad::GetPad(0)->GetPedWalkLeftRight(); - - if ( X < 0 && oldfStickX >= 0 ) - { - oldfStickX = X; - return true; - } - else - { - oldfStickX = X; - return false; - } -} - -bool CPad::GetAnaloguePadRight(void) -{ - static int16 oldfStickX = 0; - - int16 X = CPad::GetPad(0)->GetPedWalkLeftRight(); - - if ( X > 0 && oldfStickX <= 0 ) - { - oldfStickX = X; - return true; - } - else - { - oldfStickX = X; - return false; - } -} - -bool CPad::GetAnaloguePadLeftJustUp(void) -{ - static int16 oldfStickX = 0; - - int16 X = GetPad(0)->GetPedWalkLeftRight(); - - if ( X == 0 && oldfStickX < 0 ) - { - oldfStickX = X; - - return true; - } - else - { - oldfStickX = X; - - return false; - } -} - -bool CPad::GetAnaloguePadRightJustUp(void) -{ - static int16 oldfStickX = 0; - - int16 X = GetPad(0)->GetPedWalkLeftRight(); - - if ( X == 0 && oldfStickX > 0 ) - { - oldfStickX = X; - - return true; - } - else - { - oldfStickX = X; - - return false; - } -} - -bool CPad::ForceCameraBehindPlayer(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - { - return !!NewState.LeftShoulder1; - - break; - } - - case 2: - { - return !!NewState.Triangle; - - break; - } - - case 3: - { - return !!NewState.Circle; - - break; - } - } - - return false; -} - -bool CPad::SniperZoomIn(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 3: - { - return !!NewState.Square; - - break; - } - - case 2: - { - return !!NewState.Triangle; - - break; - } - } - - return false; -} - -bool CPad::SniperZoomOut(void) -{ - if ( DisablePlayerControls ) - return false; - - switch ( Mode ) - { - case 0: - case 1: - case 3: - { - return !!NewState.Cross; - - break; - } - - case 2: - { - return !!NewState.Square; - - break; - } - } - - return false; -} - - -int16 CPad::SniperModeLookLeftRight(void) -{ - int16 axis = NewState.LeftStickX; - int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; -} - -int16 CPad::SniperModeLookUpDown(void) -{ - int16 axis = NewState.LeftStickY; - int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; - - if ( abs(axis) > abs(dpad) ) - return axis; - else - return dpad; -} - -int16 CPad::LookAroundLeftRight(void) -{ - float axis = GetPad(0)->NewState.RightStickX; - - if ( fabs(axis) > 85 && !GetLookBehindForPed() ) - return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) - * (127.0f / 32.0f) ); // 3.96875f - - else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && fabs(axis) > 10 ) - return (int16) ( (axis + ( ( axis > 0 ) ? -10 : 10) ) - * (127.0f / 64.0f) ); // 1.984375f - - return 0; -} - -int16 CPad::LookAroundUpDown(void) -{ - int16 axis = GetPad(0)->NewState.RightStickY; - - if ( abs(axis) > 85 && !GetLookBehindForPed() ) - return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) - * (127.0f / 32.0f) ); // 3.96875f - - else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && abs(axis) > 40 ) - return (int16) ( (axis + ( ( axis > 0 ) ? -40 : 40) ) - * (127.0f / 64.0f) ); // 1.984375f - - return 0; -} - - -void CPad::ResetAverageWeapon(void) -{ - AverageWeapon = GetWeapon(); - AverageEntries = 1; -} - -void CPad::PrintErrorMessage(void) -{ - if ( bDisplayNoControllerMessage && !CGame::playingIntro && !FrontEndMenuManager.m_bMenuActive ) - { - CFont::SetScale(0.85f, 1.0f); - CFont::SetJustifyOff(); - CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_WIDTH - 20); - CFont::SetCentreOn(); - CFont::SetPropOn(); - CFont::SetColor(CRGBA(255, 255, 200, 200)); - CFont::SetFontStyle(FONT_BANK); - CFont::PrintString - ( - SCREEN_WIDTH / 2, - SCREEN_HEIGHT / 2, - TheText.Get("NOCONT") // Please reconnect an analog controller (DUALSHOCK@) or analog controller (DUALSHOCK@2). to controller port 1 to continue - ); - } - else if ( bObsoleteControllerMessage ) - { - CFont::SetScale(0.85f, 1.0f); - CFont::SetJustifyOff(); - CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_WIDTH - 20); - CFont::SetCentreOn(); - CFont::SetPropOn(); - CFont::SetColor(CRGBA(255, 255, 200, 200)); - CFont::SetFontStyle(FONT_BANK); - CFont::PrintString - ( - SCREEN_WIDTH / 2, - SCREEN_HEIGHT / 2, - TheText.Get("WRCONT") // The controller connected to controller port 1 is an unsupported controller. Grand Theft Auto III requires an analog controller (DUALSHOCK@) or analog controller (DUALSHOCK@2). - ); - } - -} - -void LittleTest(void) -{ - static int32 Cunt = 0; - - Cunt++; // ??? -} - -void CPad::ResetCheats(void) -{ - CWeather::ReleaseWeather(); - - CPopulation::ms_bGivePedsWeapons = false; - - CPed::bNastyLimbsCheat = false; - CPed::bPedCheat2 = false; - CPed::bPedCheat3 = false; - - CVehicle::bWheelsOnlyCheat = false; - CVehicle::bAllDodosCheat = false; - CVehicle::bCheat3 = false; - CVehicle::bCheat4 = false; - CVehicle::bCheat5 = false; - - gbFastTime = false; - CTimer::SetTimeScale(1.0f); -} - -char *CPad::EditString(char *pStr, int32 nSize) -{ - int32 pos = strlen(pStr); - - // letters - for ( int32 i = 0; i < ('Z' - 'A' + 1); i++ ) - { - if ( GetPad(0)->GetCharJustDown(i + 'A') && pos < nSize - 1 ) - { - pStr[pos++] = i + 'A'; - pStr[pos] = '\0'; - } - - if ( GetPad(0)->GetCharJustDown(i + 'a') && pos < nSize - 1 ) - { - pStr[pos++] = i + 'a'; - pStr[pos] = '\0'; - } - } - - // numbers - for ( int32 i = 0; i < ('0' - '9' + 1); i++ ) - { - if ( GetPad(0)->GetCharJustDown(i + '0') && pos < nSize - 1 ) - { - pStr[pos++] = i + '0'; - pStr[pos] = '\0'; - } - } - - // space - if ( GetPad(0)->GetCharJustDown(' ') && pos < nSize - 1 ) - { - pStr[pos++] = ' '; - pStr[pos] = '\0'; - } - - - // del - if ( GetPad(0)->GetDeleteJustDown() || GetPad(0)->GetBackspaceJustDown() ) - { - if ( pos > 0 ) - pStr[pos - 1] = '\0'; - } - - // extenter/up/down - if ( GetPad(0)->GetEnterJustDown() || GetPad(0)->GetUpJustDown() || GetPad(0)->GetDownJustDown() ) - return nil; - - return pStr; -} - -int32 *CPad::EditCodesForControls(int32 *pRsKeys, int32 nSize) -{ - *pRsKeys = rsNULL; - - for ( int32 i = 0; i < 255; i++ ) - { - if ( GetPad(0)->GetCharJustDown(i) ) - *pRsKeys = i; - } - - for ( int32 i = 0; i < 12; i++ ) - { - if ( GetPad(0)->GetFJustDown(i) ) - *pRsKeys = i + rsF1; - } - - if ( GetPad(0)->GetEscapeJustDown() ) - *pRsKeys = rsESC; - - if ( GetPad(0)->GetInsertJustDown() ) - *pRsKeys = rsINS; - - if ( GetPad(0)->GetDeleteJustDown() ) - *pRsKeys = rsDEL; - - if ( GetPad(0)->GetHomeJustDown() ) - *pRsKeys = rsHOME; - - if ( GetPad(0)->GetEndJustDown() ) - *pRsKeys = rsEND; - - if ( GetPad(0)->GetPageUpJustDown() ) - *pRsKeys = rsPGUP; - - if ( GetPad(0)->GetPageDownJustDown() ) - *pRsKeys = rsPGDN; - - if ( GetPad(0)->GetUpJustDown() ) - *pRsKeys = rsUP; - - if ( GetPad(0)->GetDownJustDown() ) - *pRsKeys = rsDOWN; - - if ( GetPad(0)->GetLeftJustDown() ) - *pRsKeys = rsLEFT; - - if ( GetPad(0)->GetRightJustDown() ) - *pRsKeys = rsRIGHT; - - if ( GetPad(0)->GetScrollLockJustDown() ) - *pRsKeys = rsSCROLL; - - if ( GetPad(0)->GetPauseJustDown() ) - *pRsKeys = rsPAUSE; - - if ( GetPad(0)->GetNumLockJustDown() ) - *pRsKeys = rsNUMLOCK; - - if ( GetPad(0)->GetDivideJustDown() ) - *pRsKeys = rsDIVIDE; - - if ( GetPad(0)->GetTimesJustDown() ) - *pRsKeys = rsTIMES; - - if ( GetPad(0)->GetMinusJustDown() ) - *pRsKeys = rsMINUS; - - if ( GetPad(0)->GetPlusJustDown() ) - *pRsKeys = rsPLUS; - - if ( GetPad(0)->GetPadEnterJustDown() ) - *pRsKeys = rsPADENTER; - - if ( GetPad(0)->GetPadDelJustDown() ) - *pRsKeys = rsPADDEL; - - if ( GetPad(0)->GetPad1JustDown() ) - *pRsKeys = rsPADEND; - - if ( GetPad(0)->GetPad2JustDown() ) - *pRsKeys = rsPADDOWN; - - if ( GetPad(0)->GetPad3JustDown() ) - *pRsKeys = rsPADPGDN; - - if ( GetPad(0)->GetPad4JustDown() ) - *pRsKeys = rsPADLEFT; - - if ( GetPad(0)->GetPad5JustDown() ) - *pRsKeys = rsPAD5; - - if ( GetPad(0)->GetPad6JustDown() ) - *pRsKeys = rsPADRIGHT; - - if ( GetPad(0)->GetPad7JustDown() ) - *pRsKeys = rsPADHOME; - - if ( GetPad(0)->GetPad8JustDown() ) - *pRsKeys = rsPADUP; - - if ( GetPad(0)->GetPad9JustDown() ) - *pRsKeys = rsPADPGUP; - - if ( GetPad(0)->GetPad0JustDown() ) - *pRsKeys = rsPADINS; - - if ( GetPad(0)->GetBackspaceJustDown() ) - *pRsKeys = rsBACKSP; - - if ( GetPad(0)->GetTabJustDown() ) - *pRsKeys = rsTAB; - - if ( GetPad(0)->GetCapsLockJustDown() ) - *pRsKeys = rsCAPSLK; - - if ( GetPad(0)->GetEnterJustDown() ) - *pRsKeys = rsENTER; - - if ( GetPad(0)->GetLeftShiftJustDown() ) - *pRsKeys = rsLSHIFT; - - if ( GetPad(0)->GetShiftJustDown() ) - *pRsKeys = rsSHIFT; - - if ( GetPad(0)->GetRightShiftJustDown() ) - *pRsKeys = rsRSHIFT; - - if ( GetPad(0)->GetLeftCtrlJustDown() ) - *pRsKeys = rsLCTRL; - - if ( GetPad(0)->GetRightCtrlJustDown() ) - *pRsKeys = rsRCTRL; - - if ( GetPad(0)->GetLeftAltJustDown() ) - *pRsKeys = rsLALT; - - if ( GetPad(0)->GetRightAltJustDown() ) - *pRsKeys = rsRALT; - - if ( GetPad(0)->GetLeftWinJustDown() ) - *pRsKeys = rsLWIN; - - if ( GetPad(0)->GetRightWinJustDown() ) - *pRsKeys = rsRWIN; - - if ( GetPad(0)->GetAppsJustDown() ) - *pRsKeys = rsAPPS; - - return pRsKeys; -} - -STARTPATCHES - InjectHook(0x4916C0, &CControllerState::Clear, PATCH_JUMP); - InjectHook(0x491760, &CKeyboardState::Clear, PATCH_JUMP); - InjectHook(0x491A10, &CPad::Clear, PATCH_JUMP); - InjectHook(0x491B50, &CPad::ClearMouseHistory, PATCH_JUMP); - //InjectHook(0x491B80, &CMouseControllerState::CMouseControllerState, PATCH_JUMP); - InjectHook(0x491BB0, &CMouseControllerState::Clear, PATCH_JUMP); - InjectHook(0x491BD0, &CMousePointerStateHelper::GetMouseSetUp, PATCH_JUMP); - InjectHook(0x491CA0, &CPad::UpdateMouse, PATCH_JUMP); - InjectHook(0x491E60, &CPad::ReconcileTwoControllersInput, PATCH_JUMP); - InjectHook(0x492230, &CPad::StartShake, PATCH_JUMP); - InjectHook(0x492290, &CPad::StartShake_Distance, PATCH_JUMP); - InjectHook(0x492360, &CPad::StartShake_Train, PATCH_JUMP); - InjectHook(0x492450, &CPad::AddToPCCheatString, PATCH_JUMP); - InjectHook(0x492720, CPad::UpdatePads, PATCH_JUMP); - InjectHook(0x492C60, &CPad::ProcessPCSpecificStuff, PATCH_JUMP); - InjectHook(0x492C70, &CPad::Update, PATCH_JUMP); -#pragma warning( push ) -#pragma warning( disable : 4573) - InjectHook(0x492F00, (void (*)())CPad::DoCheats, PATCH_JUMP); -#pragma warning( pop ) - InjectHook(0x492F20, (void (CPad::*)(int16))&CPad::DoCheats, PATCH_JUMP); - InjectHook(0x492F30, CPad::StopPadsShaking, PATCH_JUMP); - InjectHook(0x492F50, &CPad::StopShaking, PATCH_JUMP); - InjectHook(0x492F60, CPad::GetPad, PATCH_JUMP); - InjectHook(0x492F70, &CPad::GetSteeringLeftRight, PATCH_JUMP); - InjectHook(0x492FF0, &CPad::GetSteeringUpDown, PATCH_JUMP); - InjectHook(0x493070, &CPad::GetCarGunUpDown, PATCH_JUMP); - InjectHook(0x4930C0, &CPad::GetCarGunLeftRight, PATCH_JUMP); - InjectHook(0x493110, &CPad::GetPedWalkLeftRight, PATCH_JUMP); - InjectHook(0x493190, &CPad::GetPedWalkUpDown, PATCH_JUMP); - InjectHook(0x493210, &CPad::GetAnalogueUpDown, PATCH_JUMP); - InjectHook(0x493290, &CPad::GetLookLeft, PATCH_JUMP); - InjectHook(0x4932C0, &CPad::GetLookRight, PATCH_JUMP); - InjectHook(0x4932F0, &CPad::GetLookBehindForCar, PATCH_JUMP); - InjectHook(0x493320, &CPad::GetLookBehindForPed, PATCH_JUMP); - InjectHook(0x493350, &CPad::GetHorn, PATCH_JUMP); - InjectHook(0x4933F0, &CPad::HornJustDown, PATCH_JUMP); - InjectHook(0x493490, &CPad::GetCarGunFired, PATCH_JUMP); - InjectHook(0x4934F0, &CPad::CarGunJustDown, PATCH_JUMP); - InjectHook(0x493560, &CPad::GetHandBrake, PATCH_JUMP); - InjectHook(0x4935A0, &CPad::GetBrake, PATCH_JUMP); - InjectHook(0x4935F0, &CPad::GetExitVehicle, PATCH_JUMP); - InjectHook(0x493650, &CPad::ExitVehicleJustDown, PATCH_JUMP); - InjectHook(0x4936C0, &CPad::GetWeapon, PATCH_JUMP); - InjectHook(0x493700, &CPad::WeaponJustDown, PATCH_JUMP); - InjectHook(0x493780, &CPad::GetAccelerate, PATCH_JUMP); - InjectHook(0x4937D0, &CPad::CycleCameraModeUpJustDown, PATCH_JUMP); - InjectHook(0x493830, &CPad::CycleCameraModeDownJustDown, PATCH_JUMP); - InjectHook(0x493870, &CPad::ChangeStationJustDown, PATCH_JUMP); - InjectHook(0x493910, &CPad::CycleWeaponLeftJustDown, PATCH_JUMP); - InjectHook(0x493940, &CPad::CycleWeaponRightJustDown, PATCH_JUMP); - InjectHook(0x493970, &CPad::GetTarget, PATCH_JUMP); - InjectHook(0x4939D0, &CPad::TargetJustDown, PATCH_JUMP); - InjectHook(0x493A40, &CPad::JumpJustDown, PATCH_JUMP); - InjectHook(0x493A70, &CPad::GetSprint, PATCH_JUMP); - InjectHook(0x493AE0, &CPad::ShiftTargetLeftJustDown, PATCH_JUMP); - InjectHook(0x493B10, &CPad::ShiftTargetRightJustDown, PATCH_JUMP); - InjectHook(0x493B40, &CPad::GetAnaloguePadUp, PATCH_JUMP); - InjectHook(0x493BA0, &CPad::GetAnaloguePadDown, PATCH_JUMP); - InjectHook(0x493C00, &CPad::GetAnaloguePadLeft, PATCH_JUMP); - InjectHook(0x493C60, &CPad::GetAnaloguePadRight, PATCH_JUMP); - InjectHook(0x493CC0, &CPad::GetAnaloguePadLeftJustUp, PATCH_JUMP); - InjectHook(0x493D20, &CPad::GetAnaloguePadRightJustUp, PATCH_JUMP); - InjectHook(0x493D80, &CPad::ForceCameraBehindPlayer, PATCH_JUMP); - InjectHook(0x493E00, &CPad::SniperZoomIn, PATCH_JUMP); - InjectHook(0x493E70, &CPad::SniperZoomOut, PATCH_JUMP); - InjectHook(0x493EE0, &CPad::SniperModeLookLeftRight, PATCH_JUMP); - InjectHook(0x493F30, &CPad::SniperModeLookUpDown, PATCH_JUMP); - InjectHook(0x493F80, &CPad::LookAroundLeftRight, PATCH_JUMP); - InjectHook(0x494130, &CPad::LookAroundUpDown, PATCH_JUMP); - InjectHook(0x494290, &CPad::ResetAverageWeapon, PATCH_JUMP); - InjectHook(0x4942B0, CPad::PrintErrorMessage, PATCH_JUMP); - InjectHook(0x494420, LittleTest, PATCH_JUMP); - InjectHook(0x494450, CPad::ResetCheats, PATCH_JUMP); - InjectHook(0x4944B0, CPad::EditString, PATCH_JUMP); - InjectHook(0x494690, CPad::EditCodesForControls, PATCH_JUMP); - - //InjectHook(0x494E50, `global constructor keyed to'Pad.cpp, PATCH_JUMP); - //InjectHook(0x494EB0, sub_494EB0, PATCH_JUMP); - //InjectHook(0x494ED0, &CPad::~CPad, PATCH_JUMP); - //InjectHook(0x494EE0, &CPad::CPad, PATCH_JUMP); -ENDPATCHES diff --git a/src/Pad.h b/src/Pad.h deleted file mode 100644 index 30cdb8df..00000000 --- a/src/Pad.h +++ /dev/null @@ -1,367 +0,0 @@ -#pragma once - -// same as RW skeleton -/* -enum Key -{ - // ascii... - - KEY_ESC = 128, - - KEY_F1 = 129, - KEY_F2 = 130, - KEY_F3 = 131, - KEY_F4 = 132, - KEY_F5 = 133, - KEY_F6 = 134, - KEY_F7 = 135, - KEY_F8 = 136, - KEY_F9 = 137, - KEY_F10 = 138, - KEY_F11 = 139, - KEY_F12 = 140, - - KEY_INS = 141, - KEY_DEL = 142, - KEY_HOME = 143, - KEY_END = 144, - KEY_PGUP = 145, - KEY_PGDN = 146, - - KEY_UP = 147, - KEY_DOWN = 148, - KEY_LEFT = 149, - KEY_RIGHT = 150, - - // some stuff ommitted - - KEY_BACKSP = 168, - KEY_TAB = 169, - KEY_CAPSLK = 170, - KEY_ENTER = 171, - KEY_LSHIFT = 172, - KEY_RSHIFT = 173, - KEY_LCTRL = 174, - KEY_RCTRL = 175, - KEY_LALT = 176, - KEY_RALT = 177, - - KEY_NULL, // unused - KEY_NUMKEYS -}; -*/ - - -class CControllerState -{ -public: - int16 LeftStickX, LeftStickY; - int16 RightStickX, RightStickY; - int16 LeftShoulder1, LeftShoulder2; - int16 RightShoulder1, RightShoulder2; - int16 DPadUp, DPadDown, DPadLeft, DPadRight; - int16 Start, Select; - int16 Square, Triangle, Cross, Circle; - int16 LeftShock, RightShock; - int16 NetworkTalk; - float GetLeftStickX(void) { return LeftStickX/32767.0f; }; - float GetLeftStickY(void) { return LeftStickY/32767.0f; }; - float GetRightStickX(void) { return RightStickX/32767.0f; }; - float GetRightStickY(void) { return RightStickY/32767.0f; }; - - void Clear(void); -}; -VALIDATE_SIZE(CControllerState, 0x2A); - -class CMouseControllerState -{ -public: - //uint32 btns; // bit 0-2 button 1-3 - - bool LMB; - bool RMB; - bool MMB; - bool WHEELUP; - bool WHEELDN; - bool MXB1; - bool MXB2; - char _pad0; - - float x, y; - - CMouseControllerState(); - void Clear(); -}; - -VALIDATE_SIZE(CMouseControllerState, 0x10); - -class CMousePointerStateHelper -{ -public: - bool bInvertHorizontally; - bool bInvertVertically; - - CMouseControllerState GetMouseSetUp(); -}; - -VALIDATE_SIZE(CMousePointerStateHelper, 0x2); - -extern CMousePointerStateHelper &MousePointerStateHelper; - - -class CKeyboardState -{ -public: - int16 F[12]; - int16 VK_KEYS[256]; - int16 ESC; - int16 INS; - int16 DEL; - int16 HOME; - int16 END; - int16 PGUP; - int16 PGDN; - int16 UP; - int16 DOWN; - int16 LEFT; - int16 RIGHT; - int16 SCROLLLOCK; - int16 PAUSE; - int16 NUMLOCK; - int16 DIV; - int16 MUL; - int16 SUB; - int16 ADD; - int16 ENTER; - int16 DECIMAL; - int16 NUM1; - int16 NUM2; - int16 NUM3; - int16 NUM4; - int16 NUM5; - int16 NUM6; - int16 NUM7; - int16 NUM8; - int16 NUM9; - int16 NUM0; - int16 BACKSP; - int16 TAB; - int16 CAPSLOCK; - int16 EXTENTER; - int16 LSHIFT; - int16 RSHIFT; - int16 SHIFT; - int16 LCTRL; - int16 RCTRL; - int16 LALT; - int16 RALT; - int16 LWIN; - int16 RWIN; - int16 APPS; - - void Clear(); -}; - -VALIDATE_SIZE(CKeyboardState, 0x270); - -enum -{ - // taken from miss2 - PAD1 = 0, - PAD2, - - MAX_PADS -}; - -class CPad -{ -public: - CControllerState NewState; - CControllerState OldState; - CControllerState PCTempKeyState; - CControllerState PCTempJoyState; - CControllerState PCTempMouseState; - // straight out of my IDB - int16 Phase; - int16 Mode; - int16 ShakeDur; - uint8 ShakeFreq; - int8 bHornHistory[5]; - uint8 iCurrHornHistory; - bool DisablePlayerControls; - int8 bApplyBrakes; - char _unk[12]; //int32 unk[3]; - char _pad0[3]; - int32 LastTimeTouched; - int32 AverageWeapon; - int32 AverageEntries; - - CPad() { } - ~CPad() { } - - static bool &bDisplayNoControllerMessage; - static bool &bObsoleteControllerMessage; - static bool &m_bMapPadOneToPadTwo; - - static CKeyboardState &OldKeyState; - static CKeyboardState &NewKeyState; - static CKeyboardState &TempKeyState; - static char KeyBoardCheatString[18]; - static CMouseControllerState &OldMouseControllerState; - static CMouseControllerState &NewMouseControllerState; - static CMouseControllerState &PCTempMouseControllerState; - - - - - void Clear(bool bResetPlayerControls); - void ClearMouseHistory(); - void UpdateMouse(); - CControllerState ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2); - void StartShake(int16 nDur, uint8 nFreq); - void StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fz); - void StartShake_Train(float fX, float fY); - void AddToPCCheatString(char c); - - static void UpdatePads(void); - void ProcessPCSpecificStuff(void); - void Update(int16 unk); - - static void DoCheats(void); - void DoCheats(int16 unk); - - static void StopPadsShaking(void); - void StopShaking(int16 unk); - - static CPad *GetPad(int32 pad); - - int16 GetSteeringLeftRight(void); - int16 GetSteeringUpDown(void); - int16 GetCarGunUpDown(void); - int16 GetCarGunLeftRight(void); - int16 GetPedWalkLeftRight(void); - int16 GetPedWalkUpDown(void); - int16 GetAnalogueUpDown(void); - bool GetLookLeft(void); - bool GetLookRight(void); - bool GetLookBehindForCar(void); - bool GetLookBehindForPed(void); - bool GetHorn(void); - bool HornJustDown(void); - bool GetCarGunFired(void); - bool CarGunJustDown(void); - int16 GetHandBrake(void); - int16 GetBrake(void); - bool GetExitVehicle(void); - bool ExitVehicleJustDown(void); - int32 GetWeapon(void); - bool WeaponJustDown(void); - int16 GetAccelerate(void); - bool CycleCameraModeUpJustDown(void); - bool CycleCameraModeDownJustDown(void); - bool ChangeStationJustDown(void); - bool CycleWeaponLeftJustDown(void); - bool CycleWeaponRightJustDown(void); - bool GetTarget(void); - bool TargetJustDown(void); - bool JumpJustDown(void); - bool GetSprint(void); - bool ShiftTargetLeftJustDown(void); - bool ShiftTargetRightJustDown(void); - bool GetAnaloguePadUp(void); - bool GetAnaloguePadDown(void); - bool GetAnaloguePadLeft(void); - bool GetAnaloguePadRight(void); - bool GetAnaloguePadLeftJustUp(void); - bool GetAnaloguePadRightJustUp(void); - bool ForceCameraBehindPlayer(void); - bool SniperZoomIn(void); - bool SniperZoomOut(void); - int16 SniperModeLookLeftRight(void); - int16 SniperModeLookUpDown(void); - int16 LookAroundLeftRight(void); - int16 LookAroundUpDown(void); - void ResetAverageWeapon(void); - static void PrintErrorMessage(void); - static void ResetCheats(void); - static char *EditString(char *pStr, int32 nSize); - static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize); - - // mouse - bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); } - - // keyboard - - bool GetCharJustDown(int32 c) { return !!(NewKeyState.VK_KEYS[c] && !OldKeyState.VK_KEYS[c]); } - bool GetFJustDown(int32 n) { return !!(NewKeyState.F[n] && !OldKeyState.F[n]); } - bool GetEscapeJustDown() { return !!(NewKeyState.ESC && !OldKeyState.ESC); } - bool GetInsertJustDown() { return !!(NewKeyState.INS && !OldKeyState.INS); } - bool GetDeleteJustDown() { return !!(NewKeyState.DEL && !OldKeyState.DEL); } - bool GetHomeJustDown() { return !!(NewKeyState.HOME && !OldKeyState.HOME); } - bool GetEndJustDown() { return !!(NewKeyState.END && !OldKeyState.END); } - bool GetPageUpJustDown() { return !!(NewKeyState.PGUP && !OldKeyState.PGUP); } - bool GetPageDownJustDown() { return !!(NewKeyState.PGDN && !OldKeyState.PGDN); } - bool GetUpJustDown() { return !!(NewKeyState.UP && !OldKeyState.UP); } - bool GetDownJustDown() { return !!(NewKeyState.DOWN && !OldKeyState.DOWN); } - bool GetLeftJustDown() { return !!(NewKeyState.LEFT && !OldKeyState.LEFT); } - bool GetRightJustDown() { return !!(NewKeyState.RIGHT && !OldKeyState.RIGHT); } - bool GetScrollLockJustDown() { return !!(NewKeyState.SCROLLLOCK && !OldKeyState.SCROLLLOCK); } - bool GetPauseJustDown() { return !!(NewKeyState.PAUSE && !OldKeyState.PAUSE); } - bool GetNumLockJustDown() { return !!(NewKeyState.NUMLOCK && !OldKeyState.NUMLOCK); } - bool GetDivideJustDown() { return !!(NewKeyState.DIV && !OldKeyState.DIV); } - bool GetTimesJustDown() { return !!(NewKeyState.MUL && !OldKeyState.MUL); } - bool GetMinusJustDown() { return !!(NewKeyState.SUB && !OldKeyState.SUB); } - bool GetPlusJustDown() { return !!(NewKeyState.ADD && !OldKeyState.ADD); } - bool GetPadEnterJustDown() { return !!(NewKeyState.ENTER && !OldKeyState.ENTER); } // GetEnterJustDown - bool GetPadDelJustDown() { return !!(NewKeyState.DECIMAL && !OldKeyState.DECIMAL); } - bool GetPad1JustDown() { return !!(NewKeyState.NUM1 && !OldKeyState.NUM1); } - bool GetPad2JustDown() { return !!(NewKeyState.NUM2 && !OldKeyState.NUM2); } - bool GetPad3JustDown() { return !!(NewKeyState.NUM3 && !OldKeyState.NUM3); } - bool GetPad4JustDown() { return !!(NewKeyState.NUM4 && !OldKeyState.NUM4); } - bool GetPad5JustDown() { return !!(NewKeyState.NUM5 && !OldKeyState.NUM5); } - bool GetPad6JustDown() { return !!(NewKeyState.NUM6 && !OldKeyState.NUM6); } - bool GetPad7JustDown() { return !!(NewKeyState.NUM7 && !OldKeyState.NUM7); } - bool GetPad8JustDown() { return !!(NewKeyState.NUM8 && !OldKeyState.NUM8); } - bool GetPad9JustDown() { return !!(NewKeyState.NUM9 && !OldKeyState.NUM9); } - bool GetPad0JustDown() { return !!(NewKeyState.NUM0 && !OldKeyState.NUM0); } - bool GetBackspaceJustDown() { return !!(NewKeyState.BACKSP && !OldKeyState.BACKSP); } - bool GetTabJustDown() { return !!(NewKeyState.TAB && !OldKeyState.TAB); } - bool GetCapsLockJustDown() { return !!(NewKeyState.CAPSLOCK && !OldKeyState.CAPSLOCK); } - bool GetEnterJustDown() { return !!(NewKeyState.EXTENTER && !OldKeyState.EXTENTER); } - bool GetLeftShiftJustDown() { return !!(NewKeyState.LSHIFT && !OldKeyState.LSHIFT); } - bool GetShiftJustDown() { return !!(NewKeyState.SHIFT && !OldKeyState.SHIFT); } - bool GetRightShiftJustDown() { return !!(NewKeyState.RSHIFT && !OldKeyState.RSHIFT); } - bool GetLeftCtrlJustDown() { return !!(NewKeyState.LCTRL && !OldKeyState.LCTRL); } - bool GetRightCtrlJustDown() { return !!(NewKeyState.RCTRL && !OldKeyState.RCTRL); } - bool GetLeftAltJustDown() { return !!(NewKeyState.LALT && !OldKeyState.LALT); } - bool GetRightAltJustDown() { return !!(NewKeyState.RALT && !OldKeyState.RALT); } - bool GetLeftWinJustDown() { return !!(NewKeyState.LWIN && !OldKeyState.LWIN); } - bool GetRightWinJustDown() { return !!(NewKeyState.RWIN && !OldKeyState.RWIN); } - bool GetAppsJustDown() { return !!(NewKeyState.APPS && !OldKeyState.APPS); } - - // pad - - bool GetTriangleJustDown() { return !!(NewState.Triangle && !OldState.Triangle); } - bool GetCircleJustDown() { return !!(NewState.Circle && !OldState.Circle); } - bool GetCrossJustDown() { return !!(NewState.Cross && !OldState.Cross); } - bool GetSquareJustDown() { return !!(NewState.Square && !OldState.Square); } - bool GetDPadUpJustDown() { return !!(NewState.DPadUp && !OldState.DPadUp); } - bool GetDPadDownJustDown() { return !!(NewState.DPadDown && !OldState.DPadDown); } - bool GetDPadLeftJustDown() { return !!(NewState.DPadLeft && !OldState.DPadLeft); } - bool GetDPadRightJustDown() { return !!(NewState.DPadRight && !OldState.DPadRight); } - bool GetLeftShoulder1JustDown() { return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); } - bool GetLeftShoulder2JustDown() { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); } - bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); } - bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); } - - int32 GetLeftShoulder1(void) { return NewState.LeftShoulder1; } - int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; } - int32 GetRightShoulder1(void) { return NewState.RightShoulder1; } - int32 GetRightShoulder2(void) { return NewState.RightShoulder2; } -}; -VALIDATE_SIZE(CPad, 0xFC); - -#define IsButtonJustDown(pad, btn) \ - (!(pad)->OldState.btn && (pad)->NewState.btn) - -void LittleTest(void); diff --git a/src/ParticleObject.cpp b/src/ParticleObject.cpp deleted file mode 100644 index cf6e84bf..00000000 --- a/src/ParticleObject.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "ParticleObject.h" - -WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } -WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, float size, bool remove) { EAXJMP(0x4BC520); } -WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove) { EAXJMP(0x4BC570); } - -// Converted from static void __cdecl CParticleObject::Initialise() 0x42C760 -void CParticleObject::Initialise() -{ - ((void (__cdecl *)())0x4BC440)(); -} - -// Converted from static void __cdecl CParticleObject::UpdateAll() 0x4BCA30 -void CParticleObject::UpdateAll() -{ - ((void (__cdecl *)())0x4BCA30)(); -} - -STARTPATCHES - InjectHook(0x4BC420, &CParticleObject::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/ParticleObject.h b/src/ParticleObject.h deleted file mode 100644 index def7b7de..00000000 --- a/src/ParticleObject.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "Placeable.h" - -enum eParticleObjectType -{ - POBJECT_PAVEMENT_STEAM, - POBJECT_PAVEMENT_STEAM_SLOWMOTION, - POBJECT_WALL_STEAM, - POBJECT_WALL_STEAM_SLOWMOTION, - POBJECT_DARK_SMOKE, - POBJECT_FIRE_HYDRANT, - POBJECT_CAR_WATER_SPLASH, - POBJECT_PED_WATER_SPLASH, - POBJECT_SPLASHES_AROUND, - POBJECT_SMALL_FIRE, - POBJECT_BIG_FIRE, - POBJECT_DRY_ICE, - POBJECT_DRY_ICE_SLOWMOTION, - POBJECT_FIRE_TRAIL, - POBJECT_SMOKE_TRAIL, - POBJECT_FIREBALL_AND_SMOKE, - POBJECT_ROCKET_TRAIL, - POBJECT_EXPLOSION_ONCE, - POBJECT_CATALINAS_GUNFLASH, - POBJECT_CATALINAS_SHOTGUNFLASH, -}; - -class CParticleObject : CPlaceable -{ -public: - static void AddObject(uint16 type, const CVector &pos, bool remove); - static void AddObject(uint16 type, const CVector &pos, float size, bool remove); - static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove); - static void Initialise(); - static void UpdateAll(); - - void dtor() { this->CParticleObject::~CParticleObject(); } -}; diff --git a/src/Placeable.cpp b/src/Placeable.cpp deleted file mode 100644 index b4b2a37b..00000000 --- a/src/Placeable.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "common.h" -#include "Placeable.h" -#include "patcher.h" - -CPlaceable::CPlaceable(void) -{ - m_matrix.SetScale(1.0f); -} - -CPlaceable::~CPlaceable(void) { } - -void -CPlaceable::SetHeading(float angle) -{ - CVector pos = GetPosition(); - m_matrix.SetRotateZ(angle); - GetPosition() += pos; -} - -bool -CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2) -{ - float tmp; - - if(x1 > x2){ - tmp = x1; - x1 = x2; - x2 = tmp; - } - if(y1 > y2){ - tmp = y1; - y1 = y2; - y2 = tmp; - } - - return x1 <= GetPosition().x && GetPosition().x <= x2 && - y1 <= GetPosition().y && GetPosition().y <= y2; -} - -bool -CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2) -{ - float tmp; - - if(x1 > x2){ - tmp = x1; - x1 = x2; - x2 = tmp; - } - if(y1 > y2){ - tmp = y1; - y1 = y2; - y2 = tmp; - } - if(z1 > z2){ - tmp = z1; - z1 = z2; - z2 = tmp; - } - - return x1 <= GetPosition().x && GetPosition().x <= x2 && - y1 <= GetPosition().y && GetPosition().y <= y2 && - z1 <= GetPosition().z && GetPosition().z <= z2; -} - -STARTPATCHES - InjectHook(0x49F9A0, &CPlaceable::ctor, PATCH_JUMP); - InjectHook(0x49F9E0, &CPlaceable::dtor, PATCH_JUMP); - InjectHook(0x49FA00, &CPlaceable::SetHeading, PATCH_JUMP); - InjectHook(0x49FA50, (bool (CPlaceable::*)(float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); - InjectHook(0x49FAF0, (bool (CPlaceable::*)(float, float, float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); -ENDPATCHES diff --git a/src/Placeable.h b/src/Placeable.h deleted file mode 100644 index 868ca9e7..00000000 --- a/src/Placeable.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -class CPlaceable -{ -public: - // disable allocation - static void *operator new(size_t) = delete; - - CMatrix m_matrix; - - CPlaceable(void); - virtual ~CPlaceable(void); - CVector &GetPosition(void) { return *m_matrix.GetPosition(); } - CVector &GetRight(void) { return *m_matrix.GetRight(); } - CVector &GetForward(void) { return *m_matrix.GetForward(); } - CVector &GetUp(void) { return *m_matrix.GetUp(); } - CMatrix &GetMatrix(void) { return m_matrix; } - void SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); } - void SetHeading(float angle); - bool IsWithinArea(float x1, float y1, float x2, float y2); - bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2); - - CPlaceable *ctor(void) { return ::new (this) CPlaceable(); } - void dtor(void) { this->CPlaceable::~CPlaceable(); } -}; -static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error"); diff --git a/src/Pools.cpp b/src/Pools.cpp deleted file mode 100644 index f7f93292..00000000 --- a/src/Pools.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "common.h" -#include "Pools.h" - -CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044; -CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448; -CPedPool *&CPools::ms_pPedPool = *(CPedPool**)0x8F2C60; -CVehiclePool *&CPools::ms_pVehiclePool = *(CVehiclePool**)0x9430DC; -CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04; -CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568; -CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28; -CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18; - -void -CPools::Initialise(void) -{ - // TODO: unused right now - ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES); - ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS); - ms_pPedPool = new CPedPool(NUMPEDS); - ms_pVehiclePool = new CVehiclePool(NUMVEHICLES); - ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS); - ms_pTreadablePool = new CTreadablePool(NUMTREADABLES); - ms_pObjectPool = new CObjectPool(NUMOBJECTS); - ms_pDummyPool = new CDummyPool(NUMDUMMIES); -} diff --git a/src/Pools.h b/src/Pools.h deleted file mode 100644 index 3496064c..00000000 --- a/src/Pools.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "templates.h" -#include "Lists.h" -#include "Treadable.h" -#include "Object.h" -#include "CutsceneHead.h" -#include "PlayerPed.h" -#include "Automobile.h" -#include "DummyPed.h" - -typedef CPool CCPtrNodePool; -typedef CPool CEntryInfoNodePool; -typedef CPool CPedPool; -typedef CPool CVehiclePool; -typedef CPool CBuildingPool; -typedef CPool CTreadablePool; -typedef CPool CObjectPool; -typedef CPool CDummyPool; - -class CPools -{ - static CCPtrNodePool *&ms_pPtrNodePool; - static CEntryInfoNodePool *&ms_pEntryInfoNodePool; - static CPedPool *&ms_pPedPool; - static CVehiclePool *&ms_pVehiclePool; - static CBuildingPool *&ms_pBuildingPool; - static CTreadablePool *&ms_pTreadablePool; - static CObjectPool *&ms_pObjectPool; - static CDummyPool *&ms_pDummyPool; - // ms_pAudioScriptObjectPool -public: - static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; } - static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; } - static CPedPool *GetPedPool(void) { return ms_pPedPool; } - static CVehiclePool *GetVehiclePool(void) { return ms_pVehiclePool; } - static CBuildingPool *GetBuildingPool(void) { return ms_pBuildingPool; } - static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; } - static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; } - static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; } - - static void Initialise(void); -}; diff --git a/src/Radar.cpp b/src/Radar.cpp deleted file mode 100644 index a071b96b..00000000 --- a/src/Radar.cpp +++ /dev/null @@ -1,1117 +0,0 @@ -#include "config.h" -#include "common.h" -#include "patcher.h" -#include "RwHelper.h" -#include "Radar.h" -#include "Camera.h" -#include "Hud.h" -#include "World.h" -#include "Frontend.h" -#include "General.h" -#include "Vehicle.h" -#include "Pools.h" -#include "Script.h" -#include "TxdStore.h" -#include "World.h" -#include "Streaming.h" - -float &CRadar::m_RadarRange = *(float*)0x8E281C; -CBlip *CRadar::ms_RadarTrace = (CBlip*)0x6ED5E0; - -CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8; -int *gRadarTxdIds = (int*)0x6299C0; - -CSprite2d *CRadar::AsukaSprite = (CSprite2d*)0x8F1A40; -CSprite2d *CRadar::BombSprite = (CSprite2d*)0x8F5FB4; -CSprite2d *CRadar::CatSprite = (CSprite2d*)0x885B24; -CSprite2d *CRadar::CentreSprite = (CSprite2d*)0x8F6268; -CSprite2d *CRadar::CopcarSprite = (CSprite2d*)0x8F1A2C; -CSprite2d *CRadar::DonSprite = (CSprite2d*)0x8F2BE0; -CSprite2d *CRadar::EightSprite = (CSprite2d*)0x8F2BCC; -CSprite2d *CRadar::ElSprite = (CSprite2d*)0x8F1B80; -CSprite2d *CRadar::IceSprite = (CSprite2d*)0x9415FC; -CSprite2d *CRadar::JoeySprite = (CSprite2d*)0x8F2C00; -CSprite2d *CRadar::KenjiSprite = (CSprite2d*)0x8F2C68; -CSprite2d *CRadar::LizSprite = (CSprite2d*)0x8F5830; -CSprite2d *CRadar::LuigiSprite = (CSprite2d*)0x8F1A3C; -CSprite2d *CRadar::NorthSprite = (CSprite2d*)0x8F6274; -CSprite2d *CRadar::RaySprite = (CSprite2d*)0x8E2A7C; -CSprite2d *CRadar::SalSprite = (CSprite2d*)0x8F29EC; -CSprite2d *CRadar::SaveSprite = (CSprite2d*)0x8F5F74; -CSprite2d *CRadar::SpraySprite = (CSprite2d*)0x94307C; -CSprite2d *CRadar::TonySprite = (CSprite2d*)0x885B58; -CSprite2d *CRadar::WeaponSprite = (CSprite2d*)0x941534; - -CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { - nil, - AsukaSprite, - BombSprite, - CatSprite, - CentreSprite, - CopcarSprite, - DonSprite, - EightSprite, - ElSprite, - IceSprite, - JoeySprite, - KenjiSprite, - LizSprite, - LuigiSprite, - NorthSprite, - RaySprite, - SalSprite, - SaveSprite, - SpraySprite, - TonySprite, - WeaponSprite -}; - -#define RADAR_NUM_TILES (8) -#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES) -static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); - -#define RADAR_MIN_RANGE (120.0f) -#define RADAR_MAX_RANGE (350.0f) -#define RADAR_MIN_SPEED (0.3f) -#define RADAR_MAX_SPEED (0.9f) - -#if 0 -WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); } -#else -int CRadar::CalculateBlipAlpha(float dist) -{ - if (dist <= 1.0f) - return 255; - - if (dist <= 5.0f) - return (((1.0f - ((dist * 0.25f) - 0.25f)) * 255.0f) + (((dist * 0.25f) - 0.25f) * 128.0f)); - - return 128; -} -#endif - -#if 1 -WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); } -#else -void CRadar::ChangeBlipBrightness(int32 i, int32 bright) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::ChangeBlipColour(int32) { EAXJMP(0x4A5770); } -#else -void CRadar::ChangeBlipColour(int32 i) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::ChangeBlipDisplay(int32, int16) { EAXJMP(0x4A5810); } -#else -void CRadar::ChangeBlipDisplay(int32 i, int16 flag) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::ChangeBlipScale(int32, int16) { EAXJMP(0x4A57E0); } -#else -void CRadar::ChangeBlipScale(int32 i, int16 scale) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); } -#else -void CRadar::ClearBlip(int32 i) -{ - -} -#endif - -#if 0 -WRAPPER void CRadar::ClearBlipForEntity(int16, int32) { EAXJMP(0x4A56C0); } -#else -void CRadar::ClearBlipForEntity(int16 type, int32 id) -{ - for (int i = 0; i < NUMRADARBLIPS; i++) { - if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) { - SetRadarMarkerState(i, 0); - ms_RadarTrace[i].m_bInUse = 0; - ms_RadarTrace[i].m_eBlipType = 0; - ms_RadarTrace[i].m_eBlipDisplay = 0; - ms_RadarTrace[i].m_IconID = 0; - } - }; -} -#endif - -#if 0 -WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); } -#else -// Why not a proper clipping algorithm? -int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect) -{ - CVector2D corners[4] = { - { 1.0f, -1.0f }, // top right - { 1.0f, 1.0f }, // bottom right - { -1.0f, 1.0f }, // bottom left - { -1.0f, -1.0f }, // top left - }; - CVector2D tmp; - int i, j, n; - int laste, e, e1, e2;; - bool inside[4]; - - for (i = 0; i < 4; i++) - inside[i] = IsPointInsideRadar(rect[i]); - - laste = -1; - n = 0; - for (i = 0; i < 4; i++) - if (inside[i]) { - // point is inside, just add - poly[n++] = rect[i]; - } - else { - // point is outside but line to this point might be clipped - e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]); - if (e1 != -1) { - laste = e1; - n++; - } - // and line from this point might be clipped as well - e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]); - if (e2 != -1) { - if (e1 == -1) { - // if other line wasn't clipped, i.e. it was complete outside, - // we may have to insert another vertex if last clipped line - // was on a different edge - - // find the last intersection if we haven't seen it yet - if (laste == -1) - for (j = 3; j >= i; j--) { - // game uses an if here for j == 0 - e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]); - if (e != -1) { - laste = e; - break; - } - } - assert(laste != -1); - - // insert corners that were skipped - tmp = poly[n]; - for (e = laste; e != e2; e = (e + 1) % 4) - poly[n++] = corners[e]; - poly[n] = tmp; - } - n++; - } - } - - if (n == 0) { - // If no points, either the rectangle is completely outside or completely surrounds the radar - // no idea what's going on here... - float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x); - if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) { - m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x); - if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) { - poly[0] = corners[0]; - poly[1] = corners[1]; - poly[2] = corners[2]; - poly[3] = corners[3]; - n = 4; - } - } - } - - return n; -} -#endif - -bool CRadar::DisplayThisBlip(int32 counter) -{ - switch (ms_RadarTrace[counter].m_IconID) { - case RADAR_SPRITE_BOMB: - case RADAR_SPRITE_SPRAY: - case RADAR_SPRITE_WEAPON: - return true; - default: - return false; - } -} - -#if 1 -WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); } -#else -void CRadar::Draw3dMarkers() -{ - -} -#endif - - -#if 0 -WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); } -#else -void CRadar::DrawBlips() -{ - if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) { - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); - - CVector2D out; - CVector2D in = CVector2D(0.0f, 0.0f); - TransformRadarPointToScreenSpace(out, in); - - float angle; - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1) - angle = PI + FindPlayerHeading(); - else - angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading()); - - DrawRotatingRadarSprite(CentreSprite, out.x, out.y, angle, 255); - - CVector2D vec2d; - vec2d.x = vec2DRadarOrigin.x; - vec2d.y = M_SQRT2 * m_RadarRange + vec2DRadarOrigin.y; - TransformRealWorldPointToRadarSpace(in, vec2d); - LimitRadarPoint(in); - TransformRadarPointToScreenSpace(out, in); - DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255); - - /* - DrawEntityBlip - */ - for (int i = 0; i < NUMRADARBLIPS; i++) { - if (ms_RadarTrace[i].m_bInUse) { - if (ms_RadarTrace[i].m_eBlipType <= BLIP_OBJECT) { - CEntity *e = nil; - switch (ms_RadarTrace[i].m_eBlipType) { - case BLIP_CAR: - e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); - break; - case BLIP_CHAR: - e = CPools::GetPedPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); - break; - case BLIP_OBJECT: - e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); - break; - }; - - if (e) { - if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) { - if (CTheScripts::DbgFlag) { - ShowRadarMarker(e->GetPosition(), GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius); - - ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f; - if (ms_RadarTrace[i].m_Radius >= 1.0f) - ms_RadarTrace[i].m_Radius = 5.0; - } - } - if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) { - vec2d = e->GetPosition(); - TransformRealWorldPointToRadarSpace(in, vec2d); - float dist = LimitRadarPoint(in); - int a = CalculateBlipAlpha(dist); - TransformRadarPointToScreenSpace(out, in); - - int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim); - - if (ms_RadarTrace[i].m_IconID) - DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a); - else - ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255); - } - } - } - - /* - DrawCoordBlip - */ - if (ms_RadarTrace[i].m_eBlipType >= BLIP_COORD) { - if (ms_RadarTrace[i].m_eBlipType != BLIP_CONTACT_POINT || ms_RadarTrace[i].m_eBlipType == BLIP_CONTACT_POINT && DisplayThisBlip(i) || !CTheScripts::IsPlayerOnAMission()) { - if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) { - if (CTheScripts::DbgFlag) { - ShowRadarMarker(ms_RadarTrace[i].m_vecPos, GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius); - ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f; - if (ms_RadarTrace[i].m_Radius >= 1.0f) - ms_RadarTrace[i].m_Radius = 5.0f; - } - } - - if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) { - TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[i].m_vec2DPos); - float dist = LimitRadarPoint(in); - int a = CalculateBlipAlpha(dist); - TransformRadarPointToScreenSpace(out, in); - - int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim); - - if (ms_RadarTrace[i].m_IconID) - DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a); - else - ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255); - } - } - } - }; - } - } -} -#endif - - -#if 0 -WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); } -#else -void CRadar::DrawMap() -{ - if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) { - if (FindPlayerVehicle()) { - float speed = FindPlayerSpeed().Magnitude(); - if (speed < RADAR_MIN_SPEED) - m_RadarRange = RADAR_MIN_RANGE; - else if (speed < RADAR_MAX_SPEED) - m_RadarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE; - else - m_RadarRange = RADAR_MAX_RANGE; - } - else - m_RadarRange = RADAR_MIN_RANGE; - - vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift()); - DrawRadarMap(); - } -} -#endif - -#if 0 -WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); } -#else -void CRadar::DrawRadarMap() -{ - // Game calculates an unused CRect here - - DrawRadarMask(); - - // top left ist (0, 0) - int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE); - int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE); - StreamRadarSections(x, y); - - RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); - RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE); - - DrawRadarSection(x - 1, y - 1); - DrawRadarSection(x, y - 1); - DrawRadarSection(x + 1, y - 1); - DrawRadarSection(x - 1, y); - DrawRadarSection(x, y); - DrawRadarSection(x + 1, y); - DrawRadarSection(x - 1, y + 1); - DrawRadarSection(x, y + 1); - DrawRadarSection(x + 1, y + 1); -} -#endif - -#if 0 -WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); } -#else -void CRadar::DrawRadarMask() -{ - CVector2D corners[4] = { - CVector2D(1.0f, -1.0f), - CVector2D(1.0f, 1.0f), - CVector2D(-1.0f, 1.0f), - CVector2D(-1.0, -1.0f) - }; - - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS); - - CVector2D out[8]; - CVector2D in; - - // Draw the shape we want to mask out from the radar in four segments - for (int i = 0; i < 4; i++) { - // First point is always the corner itself - in.x = corners[i].x; - in.y = corners[i].y; - TransformRadarPointToScreenSpace(out[0], in); - - // Then generate a quarter of the circle - for (int j = 0; j < 7; j++) { - in.x = corners[i].x * cos(j * (PI / 2.0f / 6.0f)); - in.y = corners[i].y * sin(j * (PI / 2.0f / 6.0f)); - TransformRadarPointToScreenSpace(out[j + 1], in); - }; - - CSprite2d::SetMaskVertices(8, (float *)out); - RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8); - }; - - RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER); -} -#endif - -#if 0 -WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); } -#else -void CRadar::DrawRadarSection(int32 x, int32 y) -{ - int i; - RwTexDictionary *txd; - CVector2D worldPoly[8]; - CVector2D radarCorners[4]; - CVector2D radarPoly[8]; - CVector2D texCoords[8]; - CVector2D screenPoly[8]; - int numVertices; - RwTexture *texture = nil; - - GetTextureCorners(x, y, worldPoly); - ClipRadarTileCoords(x, y); - - assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])); - txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict; - if (txd) - texture = GetFirstTexture(txd); - if (texture == nil) - return; - - for (i = 0; i < 4; i++) - TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]); - - numVertices = ClipRadarPoly(radarPoly, radarCorners); - - // FIX: can return earlier here -// if(numVertices == 0) - if (numVertices < 3) - return; - - for (i = 0; i < numVertices; i++) { - TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]); - TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y); - TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]); - } - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture)); - CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255)); - // check done above now -// if(numVertices > 2) - RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices); -} -#endif - -#if 0 -WRAPPER void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha) { EAXJMP(0x4A5EF0); } -#else -void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha) -{ - RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha)); -} -#endif - -#if 0 -WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); } -#else -void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) -{ - CVector curPosn[4]; - CVector oldPosn[4]; - - curPosn[0].x = x - SCREEN_SCALE_X(5.6f); - curPosn[0].y = y + SCREEN_SCALE_Y(5.6f); - - curPosn[1].x = x + SCREEN_SCALE_X(5.6f); - curPosn[1].y = y + SCREEN_SCALE_Y(5.6f); - - curPosn[2].x = x - SCREEN_SCALE_X(5.6f); - curPosn[2].y = y - SCREEN_SCALE_Y(5.6f); - - curPosn[3].x = x + SCREEN_SCALE_X(5.6f); - curPosn[3].y = y - SCREEN_SCALE_Y(5.6f); - - for (uint32 i = 0; i < 4; i++) { - oldPosn[i] = curPosn[i]; - - curPosn[i].x = x + (oldPosn[i].x - x) * cosf(angle) + (oldPosn[i].y - y) * sinf(angle); - curPosn[i].y = y - (oldPosn[i].x - x) * sinf(angle) + (oldPosn[i].y - y) * cosf(angle); - } - - sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha)); -} -#endif - -#if 1 -WRAPPER int32 CRadar::GetActualBlipArray(int32) { EAXJMP(0x4A41C0); } -#else -int32 CRadar::GetActualBlipArray(int32 i) -{ - return int32(); -} -#endif - -#if 1 -WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); } -#else -int32 CRadar::GetNewUniqueBlipIndex(int32 i) -{ - return int32(); -} -#endif - -#if 0 -WRAPPER int32 CRadar::GetRadarTraceColour(int32 color, bool bright) { EAXJMP(0x4A5BB0); } -#else -int32 CRadar::GetRadarTraceColour(int32 color, bool bright) -{ - int32 c; - switch (color) { - case 0: - if (bright) - c = 0x712B49FF; - else - c = 0x7F0000FF; - break; - case 1: - if (bright) - c = 0x5FA06AFF; - else - c = 0x7F00FF; - break; - case 2: - if (bright) - c = 0x80A7F3FF; - else - c = 0x007FFF; - break; - case 3: - if (bright) - c = 0xE1E1E1FF; - else - c = 0x7F7F7FFF; - break; - case 4: - if (bright) - c = 0xFFFF00FF; - else - c = 0x7F7F00FF; - break; - case 5: - if (bright) - c = 0xFF00FFFF; - else - c = 0x7F007FFF; - break; - case 6: - if (bright) - c = 0xFFFFFF; - else - c = 0x7F7FFF; - break; - default: - c = color; - break; - }; - return c; -} -#endif - -#if 1 -WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); } -#else -void CRadar::Initialise() -{ - -} -#endif - -#if 0 -WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); } -#else -float CRadar::LimitRadarPoint(CVector2D &point) -{ - float dist, invdist; - - dist = point.Magnitude(); - if (dist > 1.0f) { - invdist = 1.0f / dist; - point.x *= invdist; - point.y *= invdist; - } - return dist; -} -#endif - -#if 1 -WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); } -#else -void CRadar::LoadAllRadarBlips(int32) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); } -#else -void CRadar::LoadTextures() -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); } -#else -void CRadar::RemoveRadarSections() -{ - -} -#endif - -#if 0 -WRAPPER void CRadar::RemoveMapSection(int32, int32) { EAXJMP(0x00); } -#else -void CRadar::RemoveMapSection(int32 x, int32 y) -{ - if (x >= 0 && x <= 7 && y >= 0 && y <= 7) - CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]); -} -#endif - -#if 0 -WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); } -#else -void CRadar::RequestMapSection(int32 x, int32 y) -{ - ClipRadarTileCoords(x, y); - CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY); -} -#endif - -#if 1 -WRAPPER void CRadar::SaveAllRadarBlips(int32) { EAXJMP(0x4A6E30); } -#else -void CRadar::SaveAllRadarBlips(int32) -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); } -#else -void CRadar::SetBlipSprite(int32 i, int32 icon) -{ - -} -#endif - -#if 1 -WRAPPER int CRadar::SetCoordBlip(int32, CVector, int32) { EAXJMP(0x4A5590); } -#else -int CRadar::SetCoordBlip(int32 type, CVector pos, int32 flag) -{ - return 0; -} -#endif - -#if 1 -WRAPPER int CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag) { EAXJMP(0x4A5640); } -#else -int CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag) -{ - return 0; -} -#endif - -#if 0 -WRAPPER void CRadar::SetRadarMarkerState(int32, int32) { EAXJMP(0x4A5C60); } -#else -void CRadar::SetRadarMarkerState(int32 counter, int32 flag) -{ - CEntity *e; - switch (ms_RadarTrace[counter].m_eBlipType) { - case BLIP_CAR: - e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); - break; - case BLIP_CHAR: - e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); - break; - case BLIP_OBJECT: - e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); - break; - default: - return; - } - - if (e) - e->bHasBlip = flag; -} -#endif - -#if 0 -WRAPPER void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) { EAXJMP(0x4A59C0); } -#else -void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) { - float f1 = radius * 0.5f; - float f2 = radius * 1.4f; - CVector p1, p2; - - p1 = pos + TheCamera.GetUp()*f1; - p2 = pos + TheCamera.GetUp()*f2; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); - - p1 = pos - TheCamera.GetUp()*f1; - p2 = pos - TheCamera.GetUp()*f2; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); - - p1 = pos + TheCamera.GetRight()*f1; - p2 = pos + TheCamera.GetRight()*f2; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); - - p1 = pos - TheCamera.GetRight()*f1; - p2 = pos - TheCamera.GetRight()*f2; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); -} -#endif - -#if 0 -WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); } -#else -void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) -{ - CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha)); - CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha)); -} -#endif - -#if 1 -WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); } -#else -void CRadar::Shutdown() -{ - -} -#endif - -#if 1 -WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); } -#else -void CRadar::StreamRadarSections(const CVector &posn) -{ - -} -#endif - -#if 0 -WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); } -#else -void CRadar::StreamRadarSections(int32 x, int32 y) -{ - for (int i = 0; i < RADAR_NUM_TILES; ++i) { - for (int j = 0; j < RADAR_NUM_TILES; ++j) { - if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1)) - RequestMapSection(i, j); - else - RemoveMapSection(i, j); - }; - }; -} -#endif - -#if 0 -WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); } -#else -void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) -{ - out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X); - out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y)); - out.x /= RADAR_TILE_SIZE; - out.y /= RADAR_TILE_SIZE; -} -#endif - -#if 0 -WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); } -#else -void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) -{ - float s, c; - - s = -sin(TheCamera.GetForward().Heading()); - c = cos(TheCamera.GetForward().Heading()); - - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { - s = 0.0f; - c = 1.0f; - } - else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) { - CVector forward; - - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) { - forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward(); - forward.Normalise(); // a bit useless... - } - else - forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - - s = -sin(forward.Heading()); - c = cos(forward.Heading()); - } - - out.x = s * in.y + c * in.x; - out.y = c * in.y - s * in.x; - - out = out * m_RadarRange + vec2DRadarOrigin; -} -#endif - -// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0) -void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in) -{ - // FIX? scale RADAR_LEFT here somehow - out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT; - out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT); -} - -#if 0 -WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); } -#else -void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) -{ - float s, c; - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { - s = 0.0f; - c = 1.0f; - } - else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) { - s = sin(TheCamera.GetForward().Heading()); - c = cos(TheCamera.GetForward().Heading()); - } - else { - CVector forward; - - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) { - forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward(); - forward.Normalise(); // a bit useless... - } - else - forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - - s = sin(forward.Heading()); - c = cos(forward.Heading()); - } - - float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange); - float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_RadarRange); - - out.x = s * y + c * x; - out.y = c * y - s * x; -} -#endif - -#if 0 -WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); }; -#else -// Transform from section indices to world coordinates -void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) -{ - x = x - RADAR_NUM_TILES/2; - y = -(y - RADAR_NUM_TILES/2); - - // bottom left - out[0].x = RADAR_TILE_SIZE * (x); - out[0].y = RADAR_TILE_SIZE * (y - 1); - - // bottom right - out[1].x = RADAR_TILE_SIZE * (x + 1); - out[1].y = RADAR_TILE_SIZE * (y - 1); - - // top right - out[2].x = RADAR_TILE_SIZE * (x + 1); - out[2].y = RADAR_TILE_SIZE * (y); - - // top left - out[3].x = RADAR_TILE_SIZE * (x); - out[3].y = RADAR_TILE_SIZE * (y); -} -#endif - -#if 0 -WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); }; -#else -void CRadar::ClipRadarTileCoords(int32 &x, int32 &y) -{ - if (x < 0) - x = 0; - if (x > RADAR_NUM_TILES-1) - x = RADAR_NUM_TILES-1; - if (y < 0) - y = 0; - if (y > RADAR_NUM_TILES-1) - y = RADAR_NUM_TILES-1; -} -#endif - - -#if 0 -WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); } -#else -bool CRadar::IsPointInsideRadar(const CVector2D &point) -{ - if (point.x < -1.0f || point.x > 1.0f) return false; - if (point.y < -1.0f || point.y > 1.0f) return false; - return true; -} -#endif - -// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1 -#if 0 -WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); } -#else -int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2) -{ - float d1, d2; - float t; - float x, y; - float shortest = 1.0f; - int edge = -1; - - // clip against left edge, x = -1.0 - d1 = -1.0f - p1.x; - d2 = -1.0f - p2.x; - if (d1 * d2 < 0.0f) { - // they are on opposite sides, get point of intersection - t = d1 / (d1 - d2); - y = (p2.y - p1.y)*t + p1.y; - if (y >= -1.0f && y <= 1.0f && t <= shortest) { - out.x = -1.0f; - out.y = y; - edge = 3; - shortest = t; - } - } - - // clip against right edge, x = 1.0 - d1 = p1.x - 1.0f; - d2 = p2.x - 1.0f; - if (d1 * d2 < 0.0f) { - // they are on opposite sides, get point of intersection - t = d1 / (d1 - d2); - y = (p2.y - p1.y)*t + p1.y; - if (y >= -1.0f && y <= 1.0f && t <= shortest) { - out.x = 1.0f; - out.y = y; - edge = 1; - shortest = t; - } - } - - // clip against top edge, y = -1.0 - d1 = -1.0f - p1.y; - d2 = -1.0f - p2.y; - if (d1 * d2 < 0.0f) { - // they are on opposite sides, get point of intersection - t = d1 / (d1 - d2); - x = (p2.x - p1.x)*t + p1.x; - if (x >= -1.0f && x <= 1.0f && t <= shortest) { - out.y = -1.0f; - out.x = x; - edge = 0; - shortest = t; - } - } - - // clip against bottom edge, y = 1.0 - d1 = p1.y - 1.0f; - d2 = p2.y - 1.0f; - if (d1 * d2 < 0.0f) { - // they are on opposite sides, get point of intersection - t = d1 / (d1 - d2); - x = (p2.x - p1.x)*t + p1.x; - if (x >= -1.0f && x <= 1.0f && t <= shortest) { - out.y = 1.0f; - out.x = x; - edge = 2; - shortest = t; - } - } - - return edge; -} -#endif - -STARTPATCHES -// InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP); -// InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP); -// InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP); -// InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP); -// InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP); - InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP); - InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP); -// InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP); - InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP); - InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP); - InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP); - InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP); - InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP); - InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP); -// InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP); -// InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP); - InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP); -// InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP); -// InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP); -// InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP); -// InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP); -// InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP); -// InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP); - InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP); - InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP); - //InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP); - InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP); - InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP); - InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP); -// InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP); -// InjectHook(0x4A6100, CRadar::StreamRadarSections, PATCH_JUMP); - InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP); - InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP); - InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP); -// InjectHook(0x4A6B60, CRadar::StreamRadarSections, PATCH_JUMP); - InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP); -// InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP); -// InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP); - - InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP); - InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP); - InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP); -ENDPATCHES diff --git a/src/Radar.h b/src/Radar.h deleted file mode 100644 index e5396a50..00000000 --- a/src/Radar.h +++ /dev/null @@ -1,146 +0,0 @@ -#pragma once -#include "Sprite2d.h" - -enum eBlipType -{ - BLIP_NONE, - BLIP_CAR, - BLIP_CHAR, - BLIP_OBJECT, - BLIP_COORD, - BLIP_CONTACT_POINT -}; - -enum eBlipDisplay -{ - BLIP_DISPLAY_NEITHER = 0, - BLIP_DISPLAY_MARKER_ONLY = 1, - BLIP_DISPLAY_BLIP_ONLY = 2, - BLIP_DISPLAY_BOTH = 3, -}; - -enum eRadarSprite -{ - RADAR_SPRITE_NONE = 0, - RADAR_SPRITE_ASUKA = 1, - RADAR_SPRITE_BOMB = 2, - RADAR_SPRITE_CAT = 3, - RADAR_SPRITE_CENTRE = 4, - RADAR_SPRITE_COPCAR = 5, - RADAR_SPRITE_DON = 6, - RADAR_SPRITE_EIGHT = 7, - RADAR_SPRITE_EL = 8, - RADAR_SPRITE_ICE = 9, - RADAR_SPRITE_JOEY = 10, - RADAR_SPRITE_KENJI = 11, - RADAR_SPRITE_LIZ = 12, - RADAR_SPRITE_LUIGI = 13, - RADAR_SPRITE_NORTH = 14, - RADAR_SPRITE_RAY = 15, - RADAR_SPRITE_SAL = 16, - RADAR_SPRITE_SAVE = 17, - RADAR_SPRITE_SPRAY = 18, - RADAR_SPRITE_TONY = 19, - RADAR_SPRITE_WEAPON = 20, - RADAR_SPRITE_COUNT = 21, -}; - -struct CBlip -{ - int32 m_nColor; - int16 m_eBlipType; // eBlipType - int32 m_nEntityHandle; - CVector2D m_vec2DPos; - CVector m_vecPos; - int16 m_BlipIndex; - bool m_bDim; - bool m_bInUse; - float m_Radius; - int16 m_wScale; - int16 m_eBlipDisplay; // eBlipDisplay - int16 m_IconID; // eRadarSprite -}; -static_assert(sizeof(CBlip) == 0x30, "CBlip: error"); - -// Values for screen space -#define RADAR_LEFT (40.0f) -#define RADAR_BOTTOM (47.0f) -#define RADAR_WIDTH (94.0f) -#define RADAR_HEIGHT (76.0f) - -class CRadar -{ -public: - static float &m_RadarRange; - static CBlip *ms_RadarTrace; //[NUMRADARBLIPS] - static CSprite2d *AsukaSprite; - static CSprite2d *BombSprite; - static CSprite2d *CatSprite; - static CSprite2d *CentreSprite; - static CSprite2d *CopcarSprite; - static CSprite2d *DonSprite; - static CSprite2d *EightSprite; - static CSprite2d *ElSprite; - static CSprite2d *IceSprite; - static CSprite2d *JoeySprite; - static CSprite2d *KenjiSprite; - static CSprite2d *LizSprite; - static CSprite2d *LuigiSprite; - static CSprite2d *NorthSprite; - static CSprite2d *RaySprite; - static CSprite2d *SalSprite; - static CSprite2d *SaveSprite; - static CSprite2d *SpraySprite; - static CSprite2d *TonySprite; - static CSprite2d *WeaponSprite; - static CSprite2d *RadarSprites[21]; - -public: - static int CalculateBlipAlpha(float dist); - static void ChangeBlipBrightness(int32 i, int32 bright); - static void ChangeBlipColour(int32 i); - static void ChangeBlipDisplay(int32 i, int16 flag); - static void ChangeBlipScale(int32 i, int16 scale); - static void ClearBlip(int32 i); - static void ClearBlipForEntity(int16 type, int32 id); - static int ClipRadarPoly(CVector2D *out, const CVector2D *in); - static bool DisplayThisBlip(int32 i); - static void Draw3dMarkers(); - static void DrawBlips(); - static void DrawMap(); - static void DrawRadarMap(); - static void DrawRadarMask(); - static void DrawRadarSection(int32 x, int32 y); - static void DrawRadarSprite(int32 sprite, float x, float y, int32 alpha); - static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha); - static int32 GetActualBlipArray(int32 i); - static int32 GetNewUniqueBlipIndex(int32 i); - static int32 GetRadarTraceColour(int32 color, bool bright); - static void Initialise(); - static float LimitRadarPoint(CVector2D &point); - static void LoadAllRadarBlips(int32); - static void LoadTextures(); - static void RemoveRadarSections(); - static void RemoveMapSection(int32 x, int32 y); - static void RequestMapSection(int32 x, int32 y); - static void SaveAllRadarBlips(int32); - static void SetBlipSprite(int32 i, int32 icon); - static int SetCoordBlip(int32 type, CVector pos, int32 flag); - static int SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag); - static void SetRadarMarkerState(int32 i, int32 flag); - static void ShowRadarMarker(CVector pos, int16 color, float radius); - static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha); - static void Shutdown(); - static void StreamRadarSections(const CVector &posn); - static void StreamRadarSections(int32 x, int32 y); - static void TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y); - static void TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in); - static void TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in); - static void TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in); - - // no in CRadar in the game: - static void GetTextureCorners(int32 x, int32 y, CVector2D *out); - static void ClipRadarTileCoords(int32 &x, int32 &y); - static bool IsPointInsideRadar(const CVector2D &); - static int LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &); -}; diff --git a/src/References.cpp b/src/References.cpp deleted file mode 100644 index e87f0fd5..00000000 --- a/src/References.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "World.h" -#include "Vehicle.h" -#include "PlayerPed.h" -#include "Pools.h" -#include "References.h" - -CReference *CReferences::aRefs = (CReference*)0x70BBE0; //[NUMREFERENCES]; -CReference *&CReferences::pEmptyList = *(CReference**)0x8F1AF8; - -void -CReferences::Init(void) -{ - int i; - pEmptyList = &aRefs[0]; - for(i = 0; i < NUMREFERENCES; i++){ - aRefs[i].pentity = nil; - aRefs[i].next = &aRefs[i+1]; - } - aRefs[NUMREFERENCES-1].next = nil; -} - -void -CReferences::RemoveReferencesToPlayer(void) -{ - if(FindPlayerVehicle()) - FindPlayerVehicle()->ResolveReferences(); - if(FindPlayerPed()) - FindPlayerPed()->ResolveReferences(); -} - -void -CReferences::PruneAllReferencesInWorld(void) -{ - int i; - CEntity *e; - - i = CPools::GetPedPool()->GetSize(); - while(--i >= 0){ - e = CPools::GetPedPool()->GetSlot(i); - if(e) - e->PruneReferences(); - } - - i = CPools::GetVehiclePool()->GetSize(); - while(--i >= 0){ - e = CPools::GetVehiclePool()->GetSlot(i); - if(e) - e->PruneReferences(); - } - - i = CPools::GetObjectPool()->GetSize(); - while(--i >= 0){ - e = CPools::GetObjectPool()->GetSlot(i); - if(e) - e->PruneReferences(); - } -} - -STARTPATCHES - InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP); - InjectHook(0x4A7570, CReferences::RemoveReferencesToPlayer, PATCH_JUMP); - InjectHook(0x4A75A0, CReferences::PruneAllReferencesInWorld, PATCH_JUMP); -ENDPATCHES diff --git a/src/References.h b/src/References.h deleted file mode 100644 index 6476e243..00000000 --- a/src/References.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -class CEntity; - -struct CReference -{ - CReference *next; - CEntity **pentity; -}; - -class CReferences -{ -public: - static CReference *aRefs; //[NUMREFERENCES]; - static CReference *&pEmptyList; - - static void Init(void); - static void RemoveReferencesToPlayer(void); - static void PruneAllReferencesInWorld(void); -}; diff --git a/src/RwClumpRead.cpp b/src/RwClumpRead.cpp deleted file mode 100644 index c9f027e7..00000000 --- a/src/RwClumpRead.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include "common.h" -#include "patcher.h" - -struct rpGeometryList -{ - RpGeometry **geometries; - int32 numGeoms; -}; - -struct rpAtomicBinary -{ - RwInt32 frameIndex; - RwInt32 geomIndex; - RwInt32 flags; - RwInt32 unused; -}; - -static int32 numberGeometrys; -static int32 streamPosition; -static rpGeometryList gGeomList; -static rwFrameList gFrameList; -static RpClumpChunkInfo gClumpInfo; - -rpGeometryList* -GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist) -{ - int i; - RwUInt32 size, version; - RwInt32 numGeoms; - - numberGeometrys = 0; - if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) - return nil; - assert(size == 4); - if(RwStreamRead(stream, &numGeoms, 4) != 4) - return nil; - - numberGeometrys = numGeoms/2; - geomlist->numGeoms = numGeoms; - if(geomlist->numGeoms > 0){ - geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*)); - if(geomlist->geometries == nil) - return nil; - memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*)); - }else - geomlist->geometries = nil; - - for(i = 0; i < numberGeometrys; i++){ - if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) - return nil; - geomlist->geometries[i] = RpGeometryStreamRead(stream); - if(geomlist->geometries[i] == nil) - return nil; - } - - return geomlist; -} - -rpGeometryList* -GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist) -{ - int i; - RwUInt32 version; - - for(i = numberGeometrys; i < geomlist->numGeoms; i++){ - if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) - return nil; - geomlist->geometries[i] = RpGeometryStreamRead(stream); - if(geomlist->geometries[i] == nil) - return nil; - } - - return geomlist; -} - -void -GeometryListDeinitialize(rpGeometryList *geomlist) -{ - int i; - - for(i = 0; i < geomlist->numGeoms; i++) - if(geomlist->geometries[i]) - RpGeometryDestroy(geomlist->geometries[i]); - - if(geomlist->numGeoms){ - RwFree(geomlist->geometries); - geomlist->numGeoms = 0; - } -} - -RpAtomic* -ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList) -{ - RwUInt32 size, version; - rpAtomicBinary a; - RpAtomic *atomic; - - numberGeometrys = 0; - if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) - return nil; - assert(size <= sizeof(rpAtomicBinary)); - if(RwStreamRead(stream, &a, size) != size) - return nil; - - atomic = RpAtomicCreate(); - if(atomic == nil) - return nil; - - RpAtomicSetFlags(atomic, a.flags); - - if(frmList->numFrames){ - assert(a.frameIndex < frmList->numFrames); - RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]); - } - - if(geomList->numGeoms){ - assert(a.geomIndex < geomList->numGeoms); - RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0); - }else{ - RpGeometry *geom; - if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){ - RpAtomicDestroy(atomic); - return nil; - } - geom = RpGeometryStreamRead(stream); - if(geom == nil){ - RpAtomicDestroy(atomic); - return nil; - } - RpAtomicSetGeometry(atomic, geom, 0); - RpGeometryDestroy(geom); - } - - return atomic; -} - -bool -RpClumpGtaStreamRead1(RwStream *stream) -{ - RwUInt32 size, version; - - if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) - return false; - if(version >= 0x33000){ - assert(size == 12); - if(RwStreamRead(stream, &gClumpInfo, 12) != 12) - return false; - }else{ - assert(size == 4); - if(RwStreamRead(stream, &gClumpInfo, 4) != 4) - return false; - } - - if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version)) - return false; - if(_rwFrameListStreamRead(stream, &gFrameList) == nil) - return false; - - if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){ - rwFrameListDeinitialize(&gFrameList); - return false; - } - if(GeometryListStreamRead1(stream, &gGeomList) == nil){ - rwFrameListDeinitialize(&gFrameList); - return false; - } - streamPosition = stream->Type.memory.position; - return true; -} - -RpClump* -RpClumpGtaStreamRead2(RwStream *stream) -{ - int i; - RwUInt32 version; - RpAtomic *atomic; - RpClump *clump; - - clump = RpClumpCreate(); - if(clump == nil) - return nil; - - RwStreamSkip(stream, streamPosition - stream->Type.memory.position); - - if(GeometryListStreamRead2(stream, &gGeomList) == nil){ - GeometryListDeinitialize(&gGeomList); - rwFrameListDeinitialize(&gFrameList); - RpClumpDestroy(clump); - return nil; - } - - RpClumpSetFrame(clump, gFrameList.frames[0]); - - for(i = 0; i < gClumpInfo.numAtomics; i++){ - if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){ - GeometryListDeinitialize(&gGeomList); - rwFrameListDeinitialize(&gFrameList); - RpClumpDestroy(clump); - return nil; - } - - atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList); - if(atomic == nil){ - GeometryListDeinitialize(&gGeomList); - rwFrameListDeinitialize(&gFrameList); - RpClumpDestroy(clump); - return nil; - } - - RpClumpAddAtomic(clump, atomic); - } - - GeometryListDeinitialize(&gGeomList); - rwFrameListDeinitialize(&gFrameList); - return clump; -} - -void -RpClumpGtaCancelStream(void) -{ - GeometryListDeinitialize(&gGeomList); - rwFrameListDeinitialize(&gFrameList); - gFrameList.numFrames = 0; -} - -STARTPATCHES - InjectHook(0x526060, RpClumpGtaStreamRead1, PATCH_JUMP); - InjectHook(0x526180, RpClumpGtaStreamRead2, PATCH_JUMP); - InjectHook(0x5262D0, RpClumpGtaCancelStream, PATCH_JUMP); -ENDPATCHES diff --git a/src/RwHelper.cpp b/src/RwHelper.cpp deleted file mode 100644 index 8dade266..00000000 --- a/src/RwHelper.cpp +++ /dev/null @@ -1,356 +0,0 @@ -#define WITHD3D -#include "common.h" -#include "patcher.h" -#include "Timecycle.h" -#include "skeleton.h" - -void * -RwMallocAlign(RwUInt32 size, RwUInt32 align) -{ - void *mem = (void *)malloc(size + align); - - ASSERT(mem != nil); - - void *addr = (void *)((((RwUInt32)mem) + align) & ~(align - 1)); - - ASSERT(addr != nil); - - *(((void **)addr) - 1) = mem; - - return addr; -} - -void -RwFreeAlign(void *mem) -{ - ASSERT(mem != nil); - - void *addr = *(((void **)mem) - 1); - - ASSERT(addr != nil); - - free(addr); -} - -void -DefinedState(void) -{ - RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP); - RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD); - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255)); - RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEFOGCOLOR, - (void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255)); - RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR); - RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE); - - // D3D stuff - RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); - RwD3D8SetRenderState(D3DRS_ALPHAREF, 2); -} - -RwFrame* -GetFirstFrameCallback(RwFrame *child, void *data) -{ - *(RwFrame**)data = child; - return nil; -} - -RwFrame* -GetFirstChild(RwFrame *frame) -{ - RwFrame *child; - - child = nil; - RwFrameForAllChildren(frame, GetFirstFrameCallback, &child); - return child; -} - -RwObject* -GetFirstObjectCallback(RwObject *object, void *data) -{ - *(RwObject**)data = object; - return nil; -} - -RwObject* -GetFirstObject(RwFrame *frame) -{ - RwObject *obj; - - obj = nil; - RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj); - return obj; -} - -RpAtomic* -GetFirstAtomicCallback(RpAtomic *atm, void *data) -{ - *(RpAtomic**)data = atm; - return nil; -} - -RpAtomic* -GetFirstAtomic(RpClump *clump) -{ - RpAtomic *atm; - - atm = nil; - RpClumpForAllAtomics(clump, GetFirstAtomicCallback, &atm); - return atm; -} - -RwTexture* -GetFirstTextureCallback(RwTexture *tex, void *data) -{ - *(RwTexture**)data = tex; - return nil; -} - -RwTexture* -GetFirstTexture(RwTexDictionary *txd) -{ - RwTexture *tex; - - tex = nil; - RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex); - return tex; -} - -void -CameraSize(RwCamera * camera, RwRect * rect, - RwReal viewWindow, RwReal aspectRatio) -{ - if (camera) - { - RwVideoMode videoMode; - RwRect r; - RwRect origSize = { 0, 0, 0, 0 }; // FIX just to make the compier happy - RwV2d vw; - - RwEngineGetVideoModeInfo(&videoMode, - RwEngineGetCurrentVideoMode()); - - origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera)); - origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera)); - - if (!rect) - { - if (videoMode.flags & rwVIDEOMODEEXCLUSIVE) - { - /* For full screen applications, resizing the camera just doesn't - * make sense, use the video mode size. - */ - - r.x = r.y = 0; - r.w = videoMode.width; - r.h = videoMode.height; - rect = &r; - } - else - { - /* - rect not specified - reuse current values - */ - r.w = RwRasterGetWidth(RwCameraGetRaster(camera)); - r.h = RwRasterGetHeight(RwCameraGetRaster(camera)); - r.x = r.y = 0; - rect = &r; - } - } - - if (( origSize.w != rect->w ) && ( origSize.h != rect->h )) - { - RwRaster *raster; - RwRaster *zRaster; - - /* - * Destroy rasters... - */ - - raster = RwCameraGetRaster(camera); - if( raster ) - { - RwRasterDestroy(raster); - } - - zRaster = RwCameraGetZRaster(camera); - if( zRaster ) - { - RwRasterDestroy(zRaster); - } - - /* - * Create new rasters... - */ - - raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); - zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); - - if( raster && zRaster ) - { - RwCameraSetRaster(camera, raster); - RwCameraSetZRaster(camera, zRaster); - } - else - { - if( raster ) - { - RwRasterDestroy(raster); - } - - if( zRaster ) - { - RwRasterDestroy(zRaster); - } - - rect->x = origSize.x; - rect->y = origSize.y; - rect->w = origSize.w; - rect->h = origSize.h; - - /* - * Use default values... - */ - raster = - RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); - - zRaster = - RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); - - RwCameraSetRaster(camera, raster); - RwCameraSetZRaster(camera, zRaster); - } - } - - /* Figure out the view window */ - if (videoMode.flags & rwVIDEOMODEEXCLUSIVE) - { - /* derive ratio from aspect ratio */ - vw.x = viewWindow; - vw.y = viewWindow / aspectRatio; - } - else - { - /* derive from pixel ratios */ - if (rect->w > rect->h) - { - vw.x = viewWindow; - vw.y = (rect->h * viewWindow) / rect->w; - } - else - { - vw.x = (rect->w * viewWindow) / rect->h; - vw.y = viewWindow; - } - } - - RwCameraSetViewWindow(camera, &vw); - - RsGlobal.width = rect->w; - RsGlobal.height = rect->h; - } - - return; -} - -void -CameraDestroy(RwCamera *camera) -{ - RwRaster *raster, *tmpRaster; - RwFrame *frame; - - if (camera) - { - frame = RwCameraGetFrame(camera); - if (frame) - { - RwFrameDestroy(frame); - } - - raster = RwCameraGetRaster(camera); - if (raster) - { - tmpRaster = RwRasterGetParent(raster); - - RwRasterDestroy(raster); - - if ((tmpRaster != nil) && (tmpRaster != raster)) - { - RwRasterDestroy(tmpRaster); - } - } - - raster = RwCameraGetZRaster(camera); - if (raster) - { - tmpRaster = RwRasterGetParent(raster); - - RwRasterDestroy(raster); - - if ((tmpRaster != nil) && (tmpRaster != raster)) - { - RwRasterDestroy(tmpRaster); - } - } - - RwCameraDestroy(camera); - } - - return; -} - -RwCamera * -CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) -{ - RwCamera *camera; - - camera = RwCameraCreate(); - - if (camera) - { - RwCameraSetFrame(camera, RwFrameCreate()); - RwCameraSetRaster(camera, - RwRasterCreate(0, 0, 0, rwRASTERTYPECAMERA)); - - if (zBuffer) - { - RwCameraSetZRaster(camera, - RwRasterCreate(0, 0, 0, - rwRASTERTYPEZBUFFER)); - } - - /* now check that everything is valid */ - if (RwCameraGetFrame(camera) && - RwCameraGetRaster(camera) && - RwRasterGetParent(RwCameraGetRaster(camera)) && - (!zBuffer || (RwCameraGetZRaster(camera) && - RwRasterGetParent(RwCameraGetZRaster - (camera))))) - { - /* everything OK */ - return (camera); - } - } - - /* if we're here then an error must have occurred so clean up */ - - CameraDestroy(camera); - return (nil); -} - -STARTPATCHES - //InjectHook(0x526450, GetFirstObjectCallback, PATCH_JUMP); - InjectHook(0x526460, GetFirstObject, PATCH_JUMP); - InjectHook(0x527170, CameraSize, PATCH_JUMP); - InjectHook(0x527340, CameraDestroy, PATCH_JUMP); - InjectHook(0x5273B0, CameraCreate, PATCH_JUMP); -ENDPATCHES diff --git a/src/RwHelper.h b/src/RwHelper.h deleted file mode 100644 index ef20467d..00000000 --- a/src/RwHelper.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -void *RwMallocAlign(RwUInt32 size, RwUInt32 align); -void RwFreeAlign(void *mem); - -void DefinedState(void); -RwFrame *GetFirstChild(RwFrame *frame); -RwObject *GetFirstObject(RwFrame *frame); -RpAtomic *GetFirstAtomic(RpClump *clump); -RwTexture *GetFirstTexture(RwTexDictionary *txd); - -RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream); -RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream); -RwTexDictionary *RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict); - -bool RpClumpGtaStreamRead1(RwStream *stream); -RpClump *RpClumpGtaStreamRead2(RwStream *stream); -void RpClumpGtaCancelStream(void); - -void CameraSize(RwCamera *camera, - RwRect *rect, - RwReal viewWindow, - RwReal aspectRatio); -void CameraDestroy(RwCamera *camera); -RwCamera *CameraCreate(RwInt32 width, - RwInt32 height, - RwBool zBuffer); diff --git a/src/RwMatFX.cpp b/src/RwMatFX.cpp deleted file mode 100644 index 5fd00c54..00000000 --- a/src/RwMatFX.cpp +++ /dev/null @@ -1,212 +0,0 @@ -#define WITHD3D -#include "common.h" -#include "patcher.h" - -struct MatFXNothing { int pad[5]; int effect; }; - -struct MatFXBump -{ - RwFrame *bumpFrame; - RwTexture *bumpedTex; - RwTexture *bumpTex; - float negBumpCoefficient; - int pad; - int effect; -}; - -struct MatFXEnv -{ - RwFrame *envFrame; - RwTexture *envTex; - float envCoeff; - int envFBalpha; - int pad; - int effect; -}; - -struct MatFXDual -{ - RwTexture *dualTex; - RwInt32 srcBlend; - RwInt32 dstBlend; -}; - - -struct MatFX -{ - union { - MatFXNothing n; - MatFXBump b; - MatFXEnv e; - MatFXDual d; - } fx[2]; - int effects; -}; - -int &MatFXMaterialDataOffset = *(int*)0x66188C; -int &MatFXAtomicDataOffset = *(int*)0x66189C; - -#ifdef PS2_MATFX - -void -_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture) -{ - if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) - RwD3D8SetTexture(texture, 0); - else - RwD3D8SetTexture(nil, 0); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); - RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0); - RwD3D8SetPixelShader(0); - RwD3D8SetVertexShader(inst->vertexShader); - RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); - - if(inst->indexBuffer){ - RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); - RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); - }else - RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); -} - -// map [-1; -1] -> [0; 1], flip V -static RwMatrix scalenormal = { - { 0.5f, 0.0f, 0.0f }, 0, - { 0.0f, -0.5f, 0.0f }, 0, - { 0.0f, 0.0f, 1.0f }, 0, - { 0.5f, 0.5f, 0.0f }, 0, - -}; - -// flipped U for PS2 -static RwMatrix scalenormal_flipU = { - { -0.5f, 0.0f, 0.0f }, 0, - { 0.0f, -0.5f, 0.0f }, 0, - { 0.0f, 0.0f, 1.0f }, 0, - { 0.5f, 0.5f, 0.0f }, 0, - -}; - -void -ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame) -{ - RwD3D8SetTexture(tex, n); - RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2); - RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL); - if(frame){ - RwMatrix *envframemat = RwMatrixCreate(); - RwMatrix *tmpmat = RwMatrixCreate(); - RwMatrix *envmat = RwMatrixCreate(); - - RwMatrixInvert(envframemat, RwFrameGetLTM(frame)); - // PS2 - // can this be simplified? - *tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera))); - RwV3dNegate(&tmpmat->right, &tmpmat->right); - tmpmat->flags = 0; - tmpmat->pos.x = 0.0f; - tmpmat->pos.y = 0.0f; - tmpmat->pos.z = 0.0f; - RwMatrixMultiply(envmat, tmpmat, envframemat); - *tmpmat = *envmat; - // important because envframemat can have a translation that we don't like - tmpmat->pos.x = 0.0f; - tmpmat->pos.y = 0.0f; - tmpmat->pos.z = 0.0f; - // for some reason we flip in U as well - RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU); - - RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat); - - RwMatrixDestroy(envmat); - RwMatrixDestroy(tmpmat); - RwMatrixDestroy(envframemat); - }else - RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal); -} - -void -_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap) -{ - MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset); - MatFXEnv *env = &matfx->fx[sel].e; - - uint8 intens = (uint8)(env->envCoeff*255.0f); - - if(intens == 0 || envMap == nil){ - if(sel == 0) - _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture); - return; - } - - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); - if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) - RwD3D8SetTexture(texture, 0); - else - RwD3D8SetTexture(nil, 0); - RwD3D8SetVertexShader(inst->vertexShader); - RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); - RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); - if(inst->indexBuffer) - RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); - else - RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); - - // Effect pass - - ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwUInt32 src, dst, lighting, zwrite, fog, fogcol; - RwRenderStateGet(rwRENDERSTATESRCBLEND, &src); - RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst); - - // This is of course not using framebuffer alpha, - // but if the diffuse texture had no alpha, the result should actually be rather the same - if(env->envFBalpha) - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - else - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); - RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting); - RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite); - RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog); - RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - if(fog){ - RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol); - RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0); - } - - D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens); - RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor); - RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); - RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT); - RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR); - // alpha unused - //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); - //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT); - //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR); - - if(inst->indexBuffer) - RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); - else - RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); - - // Reset states - - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst); - RwD3D8SetRenderState(D3DRS_LIGHTING, lighting); - RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite); - if(fog) - RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol); - RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); - RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); - RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); -} - -STARTPATCHES - InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP); -ENDPATCHES - -#endif diff --git a/src/RwTexRead.cpp b/src/RwTexRead.cpp deleted file mode 100644 index a1a7050a..00000000 --- a/src/RwTexRead.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "common.h" -#include "patcher.h" - -RwTexture* -RwTextureGtaStreamRead(RwStream *stream) -{ - RwUInt32 size, version; - RwTexture *tex; - - if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version)) - return nil; - - // TODO: unused timing - - if(!RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, &tex, size))) - return nil; - - return tex; -} - -RwTexture* -destroyTexture(RwTexture *texture, void *data) -{ - RwTextureDestroy(texture); - return texture; -} - -RwTexDictionary* -RwTexDictionaryGtaStreamRead(RwStream *stream) -{ - RwUInt32 size, version; - RwInt32 numTextures; - RwTexDictionary *texDict; - RwTexture *tex; - - if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) - return nil; - assert(size == 4); - if(RwStreamRead(stream, &numTextures, size) != size) - return nil; - - texDict = RwTexDictionaryCreate(); - if(texDict == nil) - return nil; - - while(numTextures--){ - tex = RwTextureGtaStreamRead(stream); - if(tex == nil){ - RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); - RwTexDictionaryDestroy(texDict); - return nil; - } - RwTexDictionaryAddTexture(texDict, tex); - } - - return texDict; -} - -static int32 numberTextures = -1; -static int32 streamPosition; - -RwTexDictionary* -RwTexDictionaryGtaStreamRead1(RwStream *stream) -{ - RwUInt32 size, version; - RwInt32 numTextures; - RwTexDictionary *texDict; - RwTexture *tex; - - numberTextures = 0; - if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) - return nil; - assert(size == 4); - if(RwStreamRead(stream, &numTextures, size) != size) - return nil; - - texDict = RwTexDictionaryCreate(); - if(texDict == nil) - return nil; - - numberTextures = numTextures/2; - - while(numTextures > numberTextures){ - numTextures--; - - tex = RwTextureGtaStreamRead(stream); - if(tex == nil){ - RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); - RwTexDictionaryDestroy(texDict); - return nil; - } - RwTexDictionaryAddTexture(texDict, tex); - } - - numberTextures = numTextures; - streamPosition = stream->Type.memory.position; - - return texDict; -} - -RwTexDictionary* -RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict) -{ - RwTexture *tex; - - RwStreamSkip(stream, streamPosition - stream->Type.memory.position); - - while(numberTextures--){ - tex = RwTextureGtaStreamRead(stream); - if(tex == nil){ - RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); - RwTexDictionaryDestroy(texDict); - return nil; - } - RwTexDictionaryAddTexture(texDict, tex); - } - - return texDict; -} - -STARTPATCHES - InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP); - InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP); - InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP); - InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP); -ENDPATCHES diff --git a/src/Stats.cpp b/src/Stats.cpp deleted file mode 100644 index 3c5b55e4..00000000 --- a/src/Stats.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "common.h" -#include "Stats.h" - -int32& CStats::DaysPassed = *(int32*)0x8F2BB8; -int32& CStats::HeadShots = *(int32*)0x8F647C; -bool& CStats::CommercialPassed = *(bool*)0x8F4334; \ No newline at end of file diff --git a/src/Stats.h b/src/Stats.h deleted file mode 100644 index 39b0e184..00000000 --- a/src/Stats.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -class CStats -{ -public: - static int32& DaysPassed; - static int32& HeadShots; - static bool& CommercialPassed; -}; \ No newline at end of file diff --git a/src/Streaming.cpp b/src/Streaming.cpp deleted file mode 100644 index 08fd80f0..00000000 --- a/src/Streaming.cpp +++ /dev/null @@ -1,2509 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Pad.h" -#include "Hud.h" -#include "Text.h" -#include "Clock.h" -#include "Renderer.h" -#include "ModelInfo.h" -#include "TxdStore.h" -#include "ModelIndices.h" -#include "Pools.h" -#include "Directory.h" -#include "RwHelper.h" -#include "World.h" -#include "Entity.h" -#include "FileMgr.h" -#include "FileLoader.h" -#include "Zones.h" -#include "CullZones.h" -#include "Radar.h" -#include "Camera.h" -#include "Record.h" -#include "CarCtrl.h" -#include "Population.h" -#include "Gangs.h" -#include "CutsceneMgr.h" -#include "CdStream.h" -#include "Streaming.h" - -bool &CStreaming::ms_disableStreaming = *(bool*)0x95CD6E; -bool &CStreaming::ms_bLoadingBigModel = *(bool*)0x95CDB0; -int32 &CStreaming::ms_numModelsRequested = *(int32*)0x8E2C10; -CStreamingInfo *CStreaming::ms_aInfoForModel = (CStreamingInfo*)0x6C7088; -CStreamingInfo &CStreaming::ms_startLoadedList = *(CStreamingInfo*)0x942F60; -CStreamingInfo &CStreaming::ms_endLoadedList = *(CStreamingInfo*)0x8F1AC0; -CStreamingInfo &CStreaming::ms_startRequestedList = *(CStreamingInfo*)0x8F1B3C; -CStreamingInfo &CStreaming::ms_endRequestedList = *(CStreamingInfo*)0x940738; -int32 &CStreaming::ms_oldSectorX = *(int32*)0x8F2C84; -int32 &CStreaming::ms_oldSectorY = *(int32*)0x8F2C88; -int32 &CStreaming::ms_streamingBufferSize = *(int32*)0x942FB0; -int8 **CStreaming::ms_pStreamingBuffer = (int8**)0x87F818; -int32 &CStreaming::ms_memoryUsed = *(int32*)0x940568; -CStreamingChannel *CStreaming::ms_channel = (CStreamingChannel*)0x727EE0; -int32 &CStreaming::ms_channelError = *(int32*)0x880DB8; -int32 &CStreaming::ms_numVehiclesLoaded = *(int32*)0x8F2C80; -int32 *CStreaming::ms_vehiclesLoaded = (int32*)0x773560; -int32 &CStreaming::ms_lastVehicleDeleted = *(int32*)0x95CBF8; -CDirectory *&CStreaming::ms_pExtraObjectsDir = *(CDirectory**)0x95CB90; -int32 &CStreaming::ms_numPriorityRequests = *(int32*)0x8F31C4; -bool &CStreaming::ms_hasLoadedLODs = *(bool*)0x95CD47; -int32 &CStreaming::ms_currentPedGrp = *(int32*)0x8F2BBC; -int32 CStreaming::ms_currentPedLoading; -int32 CStreaming::ms_lastCullZone; -uint16 &CStreaming::ms_loadedGangs = *(uint16*)0x95CC60; -uint16 &CStreaming::ms_loadedGangCars = *(uint16*)0x95CC2E; -int32 *CStreaming::ms_imageOffsets = (int32*)0x6E60A0; -int32 &CStreaming::ms_lastImageRead = *(int32*)0x880E2C; -int32 &CStreaming::ms_imageSize = *(int32*)0x8F1A34; -uint32 &CStreaming::ms_memoryAvailable = *(uint32*)0x880F8C; - -int32 &desiredNumVehiclesLoaded = *(int32*)0x5EC194; - -CEntity *&pIslandLODindustEntity = *(CEntity**)0x6212DC; -CEntity *&pIslandLODcomIndEntity = *(CEntity**)0x6212E0; -CEntity *&pIslandLODcomSubEntity = *(CEntity**)0x6212E4; -CEntity *&pIslandLODsubIndEntity = *(CEntity**)0x6212E8; -CEntity *&pIslandLODsubComEntity = *(CEntity**)0x6212EC; -int32 &islandLODindust = *(int32*)0x6212C8; -int32 &islandLODcomInd = *(int32*)0x6212CC; -int32 &islandLODcomSub = *(int32*)0x6212D0; -int32 &islandLODsubInd = *(int32*)0x6212D4; -int32 &islandLODsubCom = *(int32*)0x6212D8; - -bool -CStreamingInfo::GetCdPosnAndSize(uint32 &posn, uint32 &size) -{ - if(m_size == 0) - return false; - posn = m_position; - size = m_size; - return true; -} - -void -CStreamingInfo::SetCdPosnAndSize(uint32 posn, uint32 size) -{ - m_position = posn; - m_size = size; -} - -void -CStreamingInfo::AddToList(CStreamingInfo *link) -{ - // Insert this after link - m_next = link->m_next; - m_prev = link; - link->m_next = this; - m_next->m_prev = this; -} - -void -CStreamingInfo::RemoveFromList(void) -{ - m_next->m_prev = m_prev; - m_prev->m_next = m_next; - m_next = nil; - m_prev = nil; -} - -void -CStreaming::Init(void) -{ - int i; - - for(i = 0; i < NUMSTREAMINFO; i++){ - ms_aInfoForModel[i].m_loadState = STREAMSTATE_NOTLOADED; - ms_aInfoForModel[i].m_next = nil; - ms_aInfoForModel[i].m_prev = nil; - ms_aInfoForModel[i].m_nextID = -1; - ms_aInfoForModel[i].m_size = 0; - ms_aInfoForModel[i].m_position = 0; - } - - ms_channelError = -1; - - // init lists - - ms_startLoadedList.m_next = &ms_endLoadedList; - ms_startLoadedList.m_prev = nil; - ms_endLoadedList.m_prev = &ms_startLoadedList; - ms_endLoadedList.m_next = nil; - - ms_startRequestedList.m_next = &ms_endRequestedList; - ms_startRequestedList.m_prev = nil; - ms_endRequestedList.m_prev = &ms_startRequestedList; - ms_endRequestedList.m_next = nil; - - // init misc - - ms_oldSectorX = 0; - ms_oldSectorY = 0; - ms_streamingBufferSize = 0; - ms_disableStreaming = false; - ms_memoryUsed = 0; - ms_bLoadingBigModel = false; - - // init channels - - ms_channel[0].state = CHANNELSTATE_IDLE; - ms_channel[1].state = CHANNELSTATE_IDLE; - for(i = 0; i < 4; i++){ - ms_channel[0].streamIds[i] = -1; - ms_channel[0].offsets[i] = -1; - ms_channel[1].streamIds[i] = -1; - ms_channel[1].offsets[i] = -1; - } - - // init stream info, mark things that are already loaded - - for(i = 0; i < MODELINFOSIZE; i++){ - CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); - if(mi && mi->GetRwObject()){ - ms_aInfoForModel[i].m_loadState = STREAMSTATE_LOADED; - ms_aInfoForModel[i].m_flags = STREAMFLAGS_DONT_REMOVE; - if(mi->IsSimple()) - ((CSimpleModelInfo*)mi)->m_alpha = 255; - } - } - - for(i = 0; i < TXDSTORESIZE; i++) - if(CTxdStore::GetSlot(i) && CTxdStore::GetSlot(i)->texDict) - ms_aInfoForModel[i + STREAM_OFFSET_TXD].m_loadState = STREAMSTATE_LOADED; - - - for(i = 0; i < MAXVEHICLESLOADED; i++) - ms_vehiclesLoaded[i] = -1; - ms_numVehiclesLoaded = 0; - - ms_pExtraObjectsDir = new CDirectory(EXTRADIRSIZE); - ms_numPriorityRequests = 0; - ms_hasLoadedLODs = true; - ms_currentPedGrp = -1; - ms_lastCullZone = -1; // unused because RemoveModelsNotVisibleFromCullzone is gone - ms_loadedGangs = 0; - ms_currentPedLoading = 8; // unused, whatever it is - - LoadCdDirectory(); - - // allocate streaming buffers - if(ms_streamingBufferSize & 1) ms_streamingBufferSize++; - ms_pStreamingBuffer[0] = (int8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE); - ms_streamingBufferSize /= 2; - ms_pStreamingBuffer[1] = ms_pStreamingBuffer[0] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE; - debug("Streaming buffer size is %d sectors", ms_streamingBufferSize); - - // PC only, figure out how much memory we got -#ifdef GTA_PC -#define MB (1024*1024) - extern DWORD &_dwMemAvailPhys; - ms_memoryAvailable = (_dwMemAvailPhys - 10*MB)/2; - if(ms_memoryAvailable < 50*MB) - ms_memoryAvailable = 50*MB; - desiredNumVehiclesLoaded = (ms_memoryAvailable/MB - 50)/3 + 12; - if(desiredNumVehiclesLoaded > MAXVEHICLESLOADED) - desiredNumVehiclesLoaded = MAXVEHICLESLOADED; - debug("Memory allocated to Streaming is %dMB", ms_memoryAvailable/MB); -#undef MB -#endif - - // find island LODs - - pIslandLODindustEntity = nil; - pIslandLODcomIndEntity = nil; - pIslandLODcomSubEntity = nil; - pIslandLODsubIndEntity = nil; - pIslandLODsubComEntity = nil; - islandLODindust = -1; - islandLODcomInd = -1; - islandLODcomSub = -1; - islandLODsubInd = -1; - islandLODsubCom = -1; - CModelInfo::GetModelInfo("IslandLODInd", &islandLODindust); - CModelInfo::GetModelInfo("IslandLODcomIND", &islandLODcomInd); - CModelInfo::GetModelInfo("IslandLODcomSUB", &islandLODcomSub); - CModelInfo::GetModelInfo("IslandLODsubIND", &islandLODsubInd); - CModelInfo::GetModelInfo("IslandLODsubCOM", &islandLODsubCom); - - for(i = 0; i < CPools::GetBuildingPool()->GetSize(); i++){ - CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); - if(building == nil) - continue; - if(building->GetModelIndex() == islandLODindust) pIslandLODindustEntity = building; - if(building->GetModelIndex() == islandLODcomInd) pIslandLODcomIndEntity = building; - if(building->GetModelIndex() == islandLODcomSub) pIslandLODcomSubEntity = building; - if(building->GetModelIndex() == islandLODsubInd) pIslandLODsubIndEntity = building; - if(building->GetModelIndex() == islandLODsubCom) pIslandLODsubComEntity = building; - } -} - -void -CStreaming::Shutdown(void) -{ - RwFreeAlign(ms_pStreamingBuffer[0]); - ms_streamingBufferSize = 0; - if(ms_pExtraObjectsDir) - delete ms_pExtraObjectsDir; -} - -void -CStreaming::Update(void) -{ - CEntity *train; - CStreamingInfo *si, *prev; - bool requestedSubway = false; - - UpdateMemoryUsed(); - - if(ms_channelError != -1){ - RetryLoadFile(ms_channelError); - return; - } - - if(CTimer::GetIsPaused()) - return; - - train = FindPlayerTrain(); - if(train && train->GetPosition().z < 0.0f){ - RequestSubway(); - requestedSubway = true; - }else if(!ms_disableStreaming) - AddModelsToRequestList(TheCamera.GetPosition()); - - DeleteFarAwayRwObjects(TheCamera.GetPosition()); - - if(!ms_disableStreaming && - !CCutsceneMgr::IsRunning() && - !requestedSubway && - !CGame::playingIntro && - ms_numModelsRequested < 5 && - !CRenderer::m_loadingPriority){ - StreamVehiclesAndPeds(); - StreamZoneModels(FindPlayerCoors()); - } - - LoadRequestedModels(); - - for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ - prev = si->m_prev; - if((si->m_flags & (STREAMFLAGS_KEEP_IN_MEMORY|STREAMFLAGS_PRIORITY)) == 0) - RemoveModel(si - ms_aInfoForModel); - } -} - -void -CStreaming::LoadCdDirectory(void) -{ - char dirname[132]; - int i; - -#ifdef GTA_PC - ms_imageOffsets[0] = 0; - ms_imageOffsets[1] = -1; - ms_imageOffsets[2] = -1; - ms_imageOffsets[3] = -1; - ms_imageOffsets[4] = -1; - ms_imageOffsets[5] = -1; - ms_imageOffsets[6] = -1; - ms_imageOffsets[7] = -1; - ms_imageOffsets[8] = -1; - ms_imageOffsets[9] = -1; - ms_imageOffsets[10] = -1; - ms_imageOffsets[11] = -1; - ms_imageSize = GetGTA3ImgSize(); - // PS2 uses CFileMgr::GetCdFile on all IMG files to fill the array -#endif - - i = CdStreamGetNumImages(); - while(i-- >= 1){ - strcpy(dirname, CdStreamGetImageName(i)); - strncpy(strrchr(dirname, '.') + 1, "DIR", 3); - LoadCdDirectory(dirname, i); - } - - ms_lastImageRead = 0; - ms_imageSize /= CDSTREAM_SECTOR_SIZE; -} - -void -CStreaming::LoadCdDirectory(const char *dirname, int n) -{ - int fd, lastID, imgSelector; - int modelId, txdId; - uint32 posn, size; - CDirectory::DirectoryInfo direntry; - char *dot; - - lastID = -1; - fd = CFileMgr::OpenFile(dirname, "rb"); - assert(fd > 0); - - imgSelector = n<<24; - assert(sizeof(direntry) == 32); - while(CFileMgr::Read(fd, (char*)&direntry, sizeof(direntry))){ - dot = strchr(direntry.name, '.'); - if(dot) *dot = '\0'; - if(direntry.size > (uint32)ms_streamingBufferSize) - ms_streamingBufferSize = direntry.size; - - if(strcmp(dot+1, "DFF") == 0 || strcmp(dot+1, "dff") == 0){ - if(CModelInfo::GetModelInfo(direntry.name, &modelId)){ - if(ms_aInfoForModel[modelId].GetCdPosnAndSize(posn, size)){ - debug("%s appears more than once in %s\n", direntry.name, dirname); - lastID = -1; - }else{ - direntry.offset |= imgSelector; - ms_aInfoForModel[modelId].SetCdPosnAndSize(direntry.offset, direntry.size); - if(lastID != -1) - ms_aInfoForModel[lastID].m_nextID = modelId; - lastID = modelId; - } - }else{ - // BUG: doesn't remember which cdimage this was in - ms_pExtraObjectsDir->AddItem(direntry); - lastID = -1; - } - }else if(strcmp(dot+1, "TXD") == 0 || strcmp(dot+1, "txd") == 0){ - txdId = CTxdStore::FindTxdSlot(direntry.name); - if(txdId == -1) - txdId = CTxdStore::AddTxdSlot(direntry.name); - if(ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].GetCdPosnAndSize(posn, size)){ - debug("%s appears more than once in %s\n", direntry.name, dirname); - lastID = -1; - }else{ - direntry.offset |= imgSelector; - ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].SetCdPosnAndSize(direntry.offset, direntry.size); - if(lastID != -1) - ms_aInfoForModel[lastID].m_nextID = txdId + STREAM_OFFSET_TXD; - lastID = txdId + STREAM_OFFSET_TXD; - } - }else - lastID = -1; - } - - CFileMgr::CloseFile(fd); -} - -bool -CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) -{ - RwMemory mem; - RwStream *stream; - int cdsize; - uint32 startTime, endTime, timeDiff; - CBaseModelInfo *mi; - bool success; - - startTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); - - cdsize = ms_aInfoForModel[streamId].GetCdSize(); - mem.start = (uint8*)buf; - mem.length = cdsize * CDSTREAM_SECTOR_SIZE; - stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); - - if(streamId < STREAM_OFFSET_TXD){ - // Model - mi = CModelInfo::GetModelInfo(streamId); - - // Txd has to be loaded - if(CTxdStore::GetSlot(mi->GetTxdSlot())->texDict == nil){ - debug("failed to load %s because TXD %s is not in memory\n", mi->GetName(), CTxdStore::GetTxdName(mi->GetTxdSlot())); - RemoveModel(streamId); - RemoveTxd(mi->GetTxdSlot()); - ReRequestModel(streamId); - RwStreamClose(stream, &mem); - return false; - } - - // Set Txd to use - CTxdStore::AddRef(mi->GetTxdSlot()); - CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); - - if(mi->IsSimple()){ - success = CFileLoader::LoadAtomicFile(stream, streamId); - }else if(mi->m_type == MITYPE_VEHICLE){ - // load vehicles in two parts - CModelInfo::GetModelInfo(streamId)->AddRef(); - success = CFileLoader::StartLoadClumpFile(stream, streamId); - if(success) - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; - }else{ - success = CFileLoader::LoadClumpFile(stream, streamId); - } - UpdateMemoryUsed(); - - // Txd no longer needed unless we only read part of the file - if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED) - CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); - - if(!success){ - debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId)->GetName()); - RemoveModel(streamId); - ReRequestModel(streamId); - RwStreamClose(stream, &mem); - return false; - } - }else{ - // Txd - assert(streamId < NUMSTREAMINFO); - if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY) == 0 && - !IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)){ - RemoveModel(streamId); - RwStreamClose(stream, &mem); - return false; - } - - if(ms_bLoadingBigModel || cdsize > 200){ - success = CTxdStore::StartLoadTxd(streamId - STREAM_OFFSET_TXD, stream); - if(success) - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; - }else - success = CTxdStore::LoadTxd(streamId - STREAM_OFFSET_TXD, stream); - UpdateMemoryUsed(); - - if(!success){ - debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); - RemoveModel(streamId); - ReRequestModel(streamId); - RwStreamClose(stream, &mem); - return false; - } - } - - RwStreamClose(stream, &mem); - - // We shouldn't even end up here unless load was successful - if(!success){ - ReRequestModel(streamId); - if(streamId < STREAM_OFFSET_TXD) - debug("Failed to load %s.dff\n", mi->GetName()); - else - debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); - return false; - } - - if(streamId < STREAM_OFFSET_TXD){ - // Model - // Vehicles and Peds not in loaded list - if(mi->m_type != MITYPE_VEHICLE && mi->m_type != MITYPE_PED){ - CSimpleModelInfo *smi = (CSimpleModelInfo*)mi; - - // Set fading for some objects - if(mi->IsSimple() && !smi->m_isBigBuilding){ - if(ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOFADE) - smi->m_alpha = 255; - else - smi->m_alpha = 0; - } - - if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) - ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); - } - }else{ - // Txd - if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) - ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); - } - - // Mark objects as loaded - if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){ - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; - ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; - } - - endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); - timeDiff = endTime - startTime; - if(timeDiff > 5){ - if(streamId < STREAM_OFFSET_TXD) - debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); - else - debug("txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); - } - - return true; -} - - -bool -CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) -{ - RwMemory mem; - RwStream *stream; - uint32 startTime, endTime, timeDiff; - CBaseModelInfo *mi; - bool success; - - startTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); - - if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){ - if(streamId < STREAM_OFFSET_TXD) - CModelInfo::GetModelInfo(streamId)->RemoveRef(); - return false; - } - - mem.start = (uint8*)buf; - mem.length = ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; - stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); - - if(streamId < STREAM_OFFSET_TXD){ - // Model - mi = CModelInfo::GetModelInfo(streamId); - CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); - success = CFileLoader::FinishLoadClumpFile(stream, streamId); - if(success) - success = AddToLoadedVehiclesList(streamId); - mi->RemoveRef(); - CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); - }else{ - // Txd - CTxdStore::AddRef(streamId - STREAM_OFFSET_TXD); - success = CTxdStore::FinishLoadTxd(streamId - STREAM_OFFSET_TXD, stream); - CTxdStore::RemoveRefWithoutDelete(streamId - STREAM_OFFSET_TXD); - } - - RwStreamClose(stream, &mem); - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; - ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; - - if(!success){ - RemoveModel(streamId); - ReRequestModel(streamId); - UpdateMemoryUsed(); - return false; - } - - UpdateMemoryUsed(); - - endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); - timeDiff = endTime - startTime; - if(timeDiff > 5){ - if(streamId < STREAM_OFFSET_TXD) - debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); - else - debug("finish txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); - } - - return true; -} - -void -CStreaming::RequestModel(int32 id, int32 flags) -{ - CSimpleModelInfo *mi; - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE){ - // updgrade to priority - if(flags & STREAMFLAGS_PRIORITY && !ms_aInfoForModel[id].IsPriority()){ - ms_numPriorityRequests++; - ms_aInfoForModel[id].m_flags |= STREAMFLAGS_PRIORITY; - } - }else if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_NOTLOADED){ - flags &= ~STREAMFLAGS_PRIORITY; - } - ms_aInfoForModel[id].m_flags |= flags; - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ - // Already loaded, only check changed flags - - if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOFADE && id < STREAM_OFFSET_TXD){ - mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); - if(mi->IsSimple()) - mi->m_alpha = 255; - } - - // reinsert into list - if(ms_aInfoForModel[id].m_next){ - ms_aInfoForModel[id].RemoveFromList(); - if((ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) - ms_aInfoForModel[id].AddToList(&ms_startLoadedList); - } - }else if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED || - ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ // how can this be true again? - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED){ - if(id < STREAM_OFFSET_TXD) - RequestTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot(), flags); - ms_aInfoForModel[id].AddToList(&ms_startRequestedList); - ms_numModelsRequested++; - if(flags & STREAMFLAGS_PRIORITY) - ms_numPriorityRequests++; - } - - ms_aInfoForModel[id].m_loadState = STREAMSTATE_INQUEUE; - ms_aInfoForModel[id].m_flags = flags; - } -} - -void -CStreaming::RequestSubway(void) -{ - RequestModel(MI_SUBWAY1, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY2, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY3, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY4, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY5, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY6, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY7, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY8, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY9, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY10, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY11, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY12, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY13, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY14, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY15, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY16, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY17, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBWAY18, STREAMFLAGS_NOFADE); - - switch(CGame::currLevel){ - case LEVEL_INDUSTRIAL: - RequestModel(MI_SUBPLATFORM_IND, STREAMFLAGS_NOFADE); - break; - case LEVEL_COMMERCIAL: - if(FindPlayerTrain()->GetPosition().y < -700.0f){ - RequestModel(MI_SUBPLATFORM_COMS, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBPLATFORM_COMS2, STREAMFLAGS_NOFADE); - }else{ - RequestModel(MI_SUBPLATFORM_COMN, STREAMFLAGS_NOFADE); - } - break; - case LEVEL_SUBURBAN: - RequestModel(MI_SUBPLATFORM_SUB, STREAMFLAGS_NOFADE); - RequestModel(MI_SUBPLATFORM_SUB2, STREAMFLAGS_NOFADE); - break; - } -} - -void -CStreaming::RequestBigBuildings(eLevelName level) -{ - int i, n; - CBuilding *b; - - n = CPools::GetBuildingPool()->GetSize(); - for(i = 0; i < n; i++){ - b = CPools::GetBuildingPool()->GetSlot(i); - if(b && b->bIsBIGBuilding && b->m_level == level) - RequestModel(b->GetModelIndex(), STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - } - RequestIslands(level); - ms_hasLoadedLODs = false; -} - -void -CStreaming::RequestIslands(eLevelName level) -{ - switch(level){ - case LEVEL_INDUSTRIAL: - RequestModel(islandLODcomInd, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - RequestModel(islandLODsubInd, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - break; - case LEVEL_COMMERCIAL: - RequestModel(islandLODindust, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - RequestModel(islandLODsubCom, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - break; - case LEVEL_SUBURBAN: - RequestModel(islandLODindust, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - RequestModel(islandLODcomSub, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); - break; - } -} - -void -CStreaming::RequestSpecialModel(int32 modelId, const char *modelName, int32 flags) -{ - CBaseModelInfo *mi; - int txdId; - char oldName[48]; - uint32 pos, size; - - mi = CModelInfo::GetModelInfo(modelId); - if(strcmp(mi->GetName(), modelName) == 0){ - // Already have the correct name, just request it - RequestModel(modelId, flags); - return; - } - - strcpy(oldName, mi->GetName()); - mi->SetName(modelName); - - // What exactly is going on here? - if(CModelInfo::GetModelInfo(oldName, nil)){ - txdId = CTxdStore::FindTxdSlot(oldName); - if(txdId != -1 && CTxdStore::GetSlot(txdId)->texDict){ - CTxdStore::AddRef(txdId); - RemoveModel(modelId); - CTxdStore::RemoveRefWithoutDelete(txdId); - }else - RemoveModel(modelId); - }else - RemoveModel(modelId); - - ms_pExtraObjectsDir->FindItem(modelName, pos, size); - mi->ClearTexDictionary(); - if(CTxdStore::FindTxdSlot(modelName) == -1) - mi->SetTexDictionary("generic"); - else - mi->SetTexDictionary(modelName); - ms_aInfoForModel[modelId].SetCdPosnAndSize(pos, size); - RequestModel(modelId, flags); -} - -void -CStreaming::RequestSpecialChar(int32 charId, const char *modelName, int32 flags) -{ - RequestSpecialModel(charId + MI_SPECIAL01, modelName, flags); -} - -bool -CStreaming::HasSpecialCharLoaded(int32 id) -{ - return HasModelLoaded(id + MI_SPECIAL01); -} - -void -CStreaming::SetMissionDoesntRequireSpecialChar(int32 id) -{ - return SetMissionDoesntRequireModel(id + MI_SPECIAL01); -} - -void -CStreaming::DecrementRef(int32 id) -{ - ms_numModelsRequested--; - if(ms_aInfoForModel[id].IsPriority()){ - ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_PRIORITY; - ms_numPriorityRequests--; - } -} - -void -CStreaming::RemoveModel(int32 id) -{ - int i; - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED) - return; - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ - if(id < STREAM_OFFSET_TXD) - CModelInfo::GetModelInfo(id)->DeleteRwObject(); - else - CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); - ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE; - } - - if(ms_aInfoForModel[id].m_next){ - // Remove from list, model is neither loaded nor requested - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE) - DecrementRef(id); - ms_aInfoForModel[id].RemoveFromList(); - }else if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_READING){ - for(i = 0; i < 4; i++){ - if(ms_channel[0].streamIds[i] == id) - ms_channel[0].streamIds[i] = -1; - if(ms_channel[1].streamIds[i] == id) - ms_channel[1].streamIds[i] = -1; - } - } - - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){ - if(id < STREAM_OFFSET_TXD) - RpClumpGtaCancelStream(); - else - CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); - } - - ms_aInfoForModel[id].m_loadState = STREAMSTATE_NOTLOADED; -} - -void -CStreaming::RemoveUnusedBuildings(eLevelName level) -{ - if(level != LEVEL_INDUSTRIAL) - RemoveBuildings(LEVEL_INDUSTRIAL); - if(level != LEVEL_COMMERCIAL) - RemoveBuildings(LEVEL_COMMERCIAL); - if(level != LEVEL_SUBURBAN) - RemoveBuildings(LEVEL_SUBURBAN); -} - -void -CStreaming::RemoveBuildings(eLevelName level) -{ - int i, n; - CEntity *e; - CBaseModelInfo *mi; - - n = CPools::GetBuildingPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetBuildingPool()->GetSlot(i); - if(e && e->m_level == level){ - mi = CModelInfo::GetModelInfo(e->GetModelIndex()); - if(!e->bImBeingRendered){ - e->DeleteRwObject(); - if(mi->m_refCount == 0) - RemoveModel(e->GetModelIndex()); - } - } - } - - n = CPools::GetTreadablePool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetTreadablePool()->GetSlot(i); - if(e && e->m_level == level){ - mi = CModelInfo::GetModelInfo(e->GetModelIndex()); - if(!e->bImBeingRendered){ - e->DeleteRwObject(); - if(mi->m_refCount == 0) - RemoveModel(e->GetModelIndex()); - } - } - } - - n = CPools::GetObjectPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetObjectPool()->GetSlot(i); - if(e && e->m_level == level){ - mi = CModelInfo::GetModelInfo(e->GetModelIndex()); - if(!e->bImBeingRendered && ((CObject*)e)->ObjectCreatedBy == GAME_OBJECT){ - e->DeleteRwObject(); - if(mi->m_refCount == 0) - RemoveModel(e->GetModelIndex()); - } - } - } - - n = CPools::GetDummyPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetDummyPool()->GetSlot(i); - if(e && e->m_level == level){ - mi = CModelInfo::GetModelInfo(e->GetModelIndex()); - if(!e->bImBeingRendered){ - e->DeleteRwObject(); - if(mi->m_refCount == 0) - RemoveModel(e->GetModelIndex()); - } - } - } -} - -void -CStreaming::RemoveUnusedBigBuildings(eLevelName level) -{ - if(level != LEVEL_INDUSTRIAL) - RemoveBigBuildings(LEVEL_INDUSTRIAL); - if(level != LEVEL_COMMERCIAL) - RemoveBigBuildings(LEVEL_COMMERCIAL); - if(level != LEVEL_SUBURBAN) - RemoveBigBuildings(LEVEL_SUBURBAN); - RemoveIslandsNotUsed(level); -} - -void -DeleteIsland(CEntity *island) -{ - if(island == nil) - return; - if(island->bImBeingRendered) - debug("Didn't delete island because it was being rendered\n"); - else{ - island->DeleteRwObject(); - CStreaming::RemoveModel(island->GetModelIndex()); - } -} - -void -CStreaming::RemoveIslandsNotUsed(eLevelName level) -{ - switch(level){ - case LEVEL_INDUSTRIAL: - DeleteIsland(pIslandLODindustEntity); - DeleteIsland(pIslandLODcomSubEntity); - DeleteIsland(pIslandLODsubComEntity); - break; - case LEVEL_COMMERCIAL: - DeleteIsland(pIslandLODcomIndEntity); - DeleteIsland(pIslandLODcomSubEntity); - DeleteIsland(pIslandLODsubIndEntity); - break; - case LEVEL_SUBURBAN: - DeleteIsland(pIslandLODsubIndEntity); - DeleteIsland(pIslandLODsubComEntity); - DeleteIsland(pIslandLODcomIndEntity); - break; - default: - DeleteIsland(pIslandLODindustEntity); - DeleteIsland(pIslandLODcomIndEntity); - DeleteIsland(pIslandLODcomSubEntity); - DeleteIsland(pIslandLODsubIndEntity); - DeleteIsland(pIslandLODsubComEntity); - break; - } -} - -void -CStreaming::RemoveBigBuildings(eLevelName level) -{ - int i, n; - CEntity *e; - CBaseModelInfo *mi; - - n = CPools::GetBuildingPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetBuildingPool()->GetSlot(i); - if(e && e->bIsBIGBuilding && e->m_level == level){ - mi = CModelInfo::GetModelInfo(e->GetModelIndex()); - if(!e->bImBeingRendered){ - e->DeleteRwObject(); - if(mi->m_refCount == 0) - RemoveModel(e->GetModelIndex()); - } - } - } -} - -bool -CStreaming::RemoveLoadedVehicle(void) -{ - int i, id; - - for(i = 0; i < MAXVEHICLESLOADED; i++){ - ms_lastVehicleDeleted++; - if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) - ms_lastVehicleDeleted = 0; - id = ms_vehiclesLoaded[ms_lastVehicleDeleted]; - if(id != -1 && - (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 && - CModelInfo::GetModelInfo(id)->m_refCount == 0 && - ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED) - goto found; - } - return false; -found: - RemoveModel(ms_vehiclesLoaded[ms_lastVehicleDeleted]); - ms_numVehiclesLoaded--; - ms_vehiclesLoaded[ms_lastVehicleDeleted] = -1; - return true; -} - -bool -CStreaming::RemoveLeastUsedModel(void) -{ - CStreamingInfo *si; - int streamId; - - for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){ - streamId = si - ms_aInfoForModel; - if(streamId < STREAM_OFFSET_TXD){ - if(CModelInfo::GetModelInfo(streamId)->m_refCount == 0){ - RemoveModel(streamId); - return true; - } - }else{ - if(CTxdStore::GetNumRefs(streamId - STREAM_OFFSET_TXD) == 0 && - !IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)){ - RemoveModel(streamId); - return true; - } - } - } - return ms_numVehiclesLoaded > 7 && RemoveLoadedVehicle(); -} - -void -CStreaming::RemoveAllUnusedModels(void) -{ - int i; - - for(i = 0; i < MAXVEHICLESLOADED; i++) - RemoveLoadedVehicle(); - - for(i = NUM_DEFAULT_MODELS; i < MODELINFOSIZE; i++){ - if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED && - ms_aInfoForModel[i].m_flags & STREAMFLAGS_DONT_REMOVE && - CModelInfo::GetModelInfo(i)->m_refCount == 0){ - RemoveModel(i); - ms_aInfoForModel[i].m_loadState = STREAMSTATE_NOTLOADED; - } - } -} - -bool -CStreaming::RemoveReferencedTxds(int32 mem) -{ - CStreamingInfo *si; - int streamId; - - for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){ - streamId = si - ms_aInfoForModel; - if(streamId >= STREAM_OFFSET_TXD && - CTxdStore::GetNumRefs(streamId-STREAM_OFFSET_TXD) == 0){ - RemoveModel(streamId); - if(ms_memoryUsed < mem) - return true; - } - } - return false; -} - -// TODO: RemoveCurrentZonesModels - -void -CStreaming::RemoveUnusedModelsInLoadedList(void) -{ - // empty -} - -bool -CStreaming::IsTxdUsedByRequestedModels(int32 txdId) -{ - CStreamingInfo *si; - int streamId; - int i; - - for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = si->m_next){ - streamId = si - ms_aInfoForModel; - if(streamId < STREAM_OFFSET_TXD && - CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) - return true; - } - - for(i = 0; i < 4; i++){ - streamId = ms_channel[0].streamIds[i]; - if(streamId != -1 && streamId < STREAM_OFFSET_TXD && - CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) - return true; - streamId = ms_channel[1].streamIds[i]; - if(streamId != -1 && streamId < STREAM_OFFSET_TXD && - CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) - return true; - } - - return false; -} - -int32 -CStreaming::GetAvailableVehicleSlot(void) -{ - int i; - for(i = 0; i < MAXVEHICLESLOADED; i++) - if(ms_vehiclesLoaded[i] == -1) - return i; - return -1; -} - -bool -CStreaming::AddToLoadedVehiclesList(int32 modelId) -{ - int i; - int id; - - if(ms_numVehiclesLoaded < desiredNumVehiclesLoaded){ - // still room for vehicles - for(i = 0; i < MAXVEHICLESLOADED; i++){ - if(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1) - break; - ms_lastVehicleDeleted++; - if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) - ms_lastVehicleDeleted = 0; - } - assert(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1); - ms_numVehiclesLoaded++; - }else{ - // find vehicle we can remove - for(i = 0; i < MAXVEHICLESLOADED; i++){ - id = ms_vehiclesLoaded[ms_lastVehicleDeleted]; - if(id != -1 && - (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 && - CModelInfo::GetModelInfo(id)->m_refCount == 0) - goto found; - ms_lastVehicleDeleted++; - if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) - ms_lastVehicleDeleted = 0; - } - id = -1; -found: - if(id == -1){ - // didn't find anything, try a free slot - id = GetAvailableVehicleSlot(); - if(id == -1) - return false; // still no luck - ms_lastVehicleDeleted = id; - // this is more that we wanted actually - ms_numVehiclesLoaded++; - }else - RemoveModel(id); - } - - ms_vehiclesLoaded[ms_lastVehicleDeleted++] = modelId; - if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) - ms_lastVehicleDeleted = 0; - return true; -} - -bool -CStreaming::IsObjectInCdImage(int32 id) -{ - uint32 posn, size; - return ms_aInfoForModel[id].GetCdPosnAndSize(posn, size); -} - -void -CStreaming::HaveAllBigBuildingsLoaded(eLevelName level) -{ - int i, n; - CEntity *e; - - if(ms_hasLoadedLODs) - return; - - if(level == LEVEL_INDUSTRIAL){ - if(ms_aInfoForModel[islandLODcomInd].m_loadState != STREAMSTATE_LOADED || - ms_aInfoForModel[islandLODsubInd].m_loadState != STREAMSTATE_LOADED) - return; - }else if(level == LEVEL_COMMERCIAL){ - if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED || - ms_aInfoForModel[islandLODsubCom].m_loadState != STREAMSTATE_LOADED) - return; - }else if(level == LEVEL_SUBURBAN){ - if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED || - ms_aInfoForModel[islandLODcomSub].m_loadState != STREAMSTATE_LOADED) - return; - } - - n = CPools::GetBuildingPool()->GetSize(); - for(i = 0; i < n; i++){ - e = CPools::GetBuildingPool()->GetSlot(i); - if(e && e->bIsBIGBuilding && e->m_level == level && - ms_aInfoForModel[e->GetModelIndex()].m_loadState != STREAMSTATE_LOADED) - return; - } - - RemoveUnusedBigBuildings(level); - ms_hasLoadedLODs = true; -} - -void -CStreaming::SetModelIsDeletable(int32 id) -{ - ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_DONT_REMOVE; - if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) && - (ms_aInfoForModel[id].m_flags & STREAMFLAGS_SCRIPTOWNED) == 0){ - if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED) - RemoveModel(id); - else if(ms_aInfoForModel[id].m_next == nil) - ms_aInfoForModel[id].AddToList(&ms_startLoadedList); - } -} - -void -CStreaming::SetModelTxdIsDeletable(int32 id) -{ - SetModelIsDeletable(CModelInfo::GetModelInfo(id)->GetTxdSlot() + STREAM_OFFSET_TXD); -} - -void -CStreaming::SetMissionDoesntRequireModel(int32 id) -{ - ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_SCRIPTOWNED; - if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) && - (ms_aInfoForModel[id].m_flags & STREAMFLAGS_DONT_REMOVE) == 0){ - if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED) - RemoveModel(id); - else if(ms_aInfoForModel[id].m_next == nil) - ms_aInfoForModel[id].AddToList(&ms_startLoadedList); - } -} - -void -CStreaming::LoadInitialPeds(void) -{ - RequestModel(MI_COP, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_MALE01, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_TAXI_D, STREAMFLAGS_DONT_REMOVE); -} - -void -CStreaming::LoadInitialVehicles(void) -{ - int id; - - ms_numVehiclesLoaded = 0; - ms_lastVehicleDeleted = 0; - - if(CModelInfo::GetModelInfo("taxi", &id)) - RequestModel(id, STREAMFLAGS_DONT_REMOVE); - if(CModelInfo::GetModelInfo("police", &id)) - RequestModel(id, STREAMFLAGS_DONT_REMOVE); -} - -void -CStreaming::StreamVehiclesAndPeds(void) -{ - int i, model; - static int timeBeforeNextLoad = 0; - static int modelQualityClass = 0; - - if(CRecordDataForGame::RecordingState == RECORDSTATE_1 || - CRecordDataForGame::RecordingState == RECORDSTATE_2) - return; - - if(FindPlayerPed()->m_pWanted->AreSwatRequired()){ - RequestModel(MI_ENFORCER, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_SWAT, STREAMFLAGS_DONT_REMOVE); - }else{ - SetModelIsDeletable(MI_ENFORCER); - if(!HasModelLoaded(MI_ENFORCER)) - SetModelIsDeletable(MI_SWAT); - } - - if(FindPlayerPed()->m_pWanted->AreFbiRequired()){ - RequestModel(MI_FBICAR, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_FBI, STREAMFLAGS_DONT_REMOVE); - }else{ - SetModelIsDeletable(MI_FBICAR); - if(!HasModelLoaded(MI_FBICAR)) - SetModelIsDeletable(MI_FBI); - } - - if(FindPlayerPed()->m_pWanted->AreArmyRequired()){ - RequestModel(MI_RHINO, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_BARRACKS, STREAMFLAGS_DONT_REMOVE); - RequestModel(MI_ARMY, STREAMFLAGS_DONT_REMOVE); - }else{ - SetModelIsDeletable(MI_RHINO); - SetModelIsDeletable(MI_BARRACKS); - if(!HasModelLoaded(MI_RHINO) && !HasModelLoaded(MI_BARRACKS)) - SetModelIsDeletable(MI_ARMY); - } - - if(FindPlayerPed()->m_pWanted->NumOfHelisRequired() > 0) - RequestModel(MI_CHOPPER, STREAMFLAGS_DONT_REMOVE); - else - SetModelIsDeletable(MI_CHOPPER); - - if(timeBeforeNextLoad >= 0) - timeBeforeNextLoad--; - else if(ms_numVehiclesLoaded <= desiredNumVehiclesLoaded){ - for(i = 0; i <= 10; i++){ - model = CCarCtrl::ChooseCarModel(modelQualityClass); - modelQualityClass++; - if(modelQualityClass >= NUM_VEHICLE_CLASSES) - modelQualityClass = 0; - - // check if we want to load this model - if(ms_aInfoForModel[model].m_loadState == STREAMSTATE_NOTLOADED && - ((CVehicleModelInfo*)CModelInfo::GetModelInfo(model))->m_level & (1 << (CGame::currLevel-1))) - break; - } - - if(i <= 10){ - RequestModel(model, STREAMFLAGS_DEPENDENCY); - timeBeforeNextLoad = 500; - } - } -} - -void -CStreaming::StreamZoneModels(const CVector &pos) -{ - int i; - uint16 gangsToLoad, gangCarsToLoad, bit; - CZoneInfo info; - - CTheZones::GetZoneInfoForTimeOfDay(&pos, &info); - - if(info.pedGroup != ms_currentPedGrp){ - - // unload pevious group - if(ms_currentPedGrp != -1) - for(i = 0; i < 8; i++){ - if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) - break; - SetModelIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); - SetModelTxdIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); - } - - ms_currentPedGrp = info.pedGroup; - - for(i = 0; i < 8; i++){ - if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) - break; - RequestModel(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i], STREAMFLAGS_DONT_REMOVE); - } - } - RequestModel(MI_MALE01, STREAMFLAGS_DONT_REMOVE); - - gangsToLoad = 0; - gangCarsToLoad = 0; - if(info.gangDensity[0] != 0) gangsToLoad |= 1<<0; - if(info.gangDensity[1] != 0) gangsToLoad |= 1<<1; - if(info.gangDensity[2] != 0) gangsToLoad |= 1<<2; - if(info.gangDensity[3] != 0) gangsToLoad |= 1<<3; - if(info.gangDensity[4] != 0) gangsToLoad |= 1<<4; - if(info.gangDensity[5] != 0) gangsToLoad |= 1<<5; - if(info.gangDensity[6] != 0) gangsToLoad |= 1<<6; - if(info.gangDensity[7] != 0) gangsToLoad |= 1<<7; - if(info.gangDensity[8] != 0) gangsToLoad |= 1<<8; - if(info.gangThreshold[0] != info.copDensity) gangCarsToLoad |= 1<<0; - if(info.gangThreshold[1] != info.gangThreshold[0]) gangCarsToLoad |= 1<<1; - if(info.gangThreshold[2] != info.gangThreshold[1]) gangCarsToLoad |= 1<<2; - if(info.gangThreshold[3] != info.gangThreshold[2]) gangCarsToLoad |= 1<<3; - if(info.gangThreshold[4] != info.gangThreshold[3]) gangCarsToLoad |= 1<<4; - if(info.gangThreshold[5] != info.gangThreshold[4]) gangCarsToLoad |= 1<<5; - if(info.gangThreshold[6] != info.gangThreshold[5]) gangCarsToLoad |= 1<<6; - if(info.gangThreshold[7] != info.gangThreshold[6]) gangCarsToLoad |= 1<<7; - if(info.gangThreshold[8] != info.gangThreshold[7]) gangCarsToLoad |= 1<<8; - - if(gangsToLoad == ms_loadedGangs && gangCarsToLoad == ms_loadedGangCars) - return; - - // This makes things simpler than the game does it - gangsToLoad |= gangCarsToLoad; - - for(i = 0; i < NUM_GANGS; i++){ - bit = 1<m_nVehicleMI, STREAMFLAGS_DONT_REMOVE); - }else if((gangCarsToLoad & bit) == 0 && ms_loadedGangCars & bit){ - SetModelIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); - SetModelTxdIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); - } - } - ms_loadedGangCars = gangCarsToLoad; -} - -void -CStreaming::RemoveCurrentZonesModels(void) -{ - int i; - - if(ms_currentPedGrp != -1) - for(i = 0; i < 8; i++){ - if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) - break; - if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] != MI_MALE01) - SetModelIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); - } - - for(i = 0; i < NUM_GANGS; i++){ - SetModelIsDeletable(MI_GANG01 + i*2); - SetModelIsDeletable(MI_GANG01 + i*2 + 1); - if(CGangs::GetGangInfo(i)->m_nVehicleMI != -1) - SetModelIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); - } - - ms_currentPedGrp = -1; - ms_loadedGangs = 0; - ms_loadedGangCars = 0; -} - - - -// Find starting offset of the cdimage we next want to read -// Not useful at all on PC... -int32 -CStreaming::GetCdImageOffset(int32 lastPosn) -{ - int offset, off; - int i, img; - int dist, mindist; - - img = -1; - mindist = INT_MAX; - offset = ms_imageOffsets[ms_lastImageRead]; - if(lastPosn <= offset || lastPosn > offset + ms_imageSize){ - // last read position is not in last image - for(i = 0; i < NUMCDIMAGES; i++){ - off = ms_imageOffsets[i]; - if(off == -1) continue; - if((uint32)lastPosn > (uint32)off) - // after start of image, get distance from end - // negative if before end! - dist = lastPosn - (off + ms_imageSize); - else - // before image, get offset to start - // this will never be negative - dist = off - lastPosn; - if(dist < mindist){ - img = i; - mindist = dist; - } - } - assert(img >= 0); - offset = ms_imageOffsets[img]; - ms_lastImageRead = img; - } - return offset; -} - -inline bool -TxdAvailable(int32 txdId) -{ - CStreamingInfo *si = &CStreaming::ms_aInfoForModel[txdId + STREAM_OFFSET_TXD]; - return si->m_loadState == STREAMSTATE_LOADED || si->m_loadState == STREAMSTATE_READING; -} - -// Find stream id of next requested file in cdimage -int32 -CStreaming::GetNextFileOnCd(int32 lastPosn, bool priority) -{ - CStreamingInfo *si, *next; - int streamId; - uint32 posn, size; - int streamIdFirst, streamIdNext; - uint32 posnFirst, posnNext; - - streamIdFirst = -1; - streamIdNext = -1; - posnFirst = UINT_MAX; - posnNext = UINT_MAX; - - for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){ - next = si->m_next; - streamId = si - ms_aInfoForModel; - - // only priority requests if there are any - if(priority && ms_numPriorityRequests != 0 && !si->IsPriority()) - continue; - - // request Txd if necessary - if(streamId < STREAM_OFFSET_TXD && - !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot())){ - ReRequestTxd(CModelInfo::GetModelInfo(streamId)->GetTxdSlot()); - }else if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){ - if(posn < posnFirst){ - // find first requested file in image - streamIdFirst = streamId; - posnFirst = posn; - } - if(posn < posnNext && posn >= (uint32)lastPosn){ - // find first requested file after last read position - streamIdNext = streamId; - posnNext = posn; - } - }else{ - // empty file - DecrementRef(streamId); - si->RemoveFromList(); - si->m_loadState = STREAMSTATE_LOADED; - } - } - - // wrap around - if(streamIdNext == -1) - streamIdNext = streamIdFirst; - - if(streamIdNext == -1 && ms_numPriorityRequests != 0){ - // try non-priority files - ms_numPriorityRequests = 0; - streamIdNext = GetNextFileOnCd(lastPosn, false); - } - - return streamIdNext; -} - -/* - * Streaming buffer size is half of the largest file. - * Files larger than the buffer size can only be loaded by channel 0, - * which then uses both buffers, while channel 1 is idle. - * ms_bLoadingBigModel is set to true to indicate this state. - * - * TODO: two-part files - */ - -// Make channel read from disc -void -CStreaming::RequestModelStream(int32 ch) -{ - int lastPosn, imgOffset, streamId; - int totalSize; - uint32 posn, size, unused; - int i; - int haveBigFile, havePed; - - lastPosn = CdStreamGetLastPosn(); - imgOffset = GetCdImageOffset(lastPosn); - streamId = GetNextFileOnCd(lastPosn - imgOffset, true); - - if(streamId == -1) - return; - - // remove Txds that aren't requested anymore - while(streamId >= STREAM_OFFSET_TXD){ - if(ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY || - IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)) - break; - RemoveModel(streamId); - // so try next file - ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size); - streamId = GetNextFileOnCd(posn + size, true); - } - - if(streamId == -1) - return; - - ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size); - if(size > (uint32)ms_streamingBufferSize){ - // Can only load big models on channel 0, and 1 has to be idle - if(ch == 1 || ms_channel[1].state != CHANNELSTATE_IDLE) - return; - ms_bLoadingBigModel = true; - } - - // Load up to 4 adjacent files - haveBigFile = 0; - havePed = 0; - totalSize = 0; - for(i = 0; i < 4; i++){ - // no more files we can read - if(streamId == -1 || ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_INQUEUE) - break; - - // also stop at non-priority files - ms_aInfoForModel[streamId].GetCdPosnAndSize(unused, size); - if(ms_numPriorityRequests != 0 && !ms_aInfoForModel[streamId].IsPriority()) - break; - - // Can't load certain combinations of files together - if(streamId < STREAM_OFFSET_TXD){ - if(havePed && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED || - haveBigFile && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE || - !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot())) - break; - }else{ - if(haveBigFile && size > 200) - break; - } - - // Now add the file - ms_channel[ch].streamIds[i] = streamId; - ms_channel[ch].offsets[i] = totalSize; - totalSize += size; - - // To big for buffer, remove again - if(totalSize > ms_streamingBufferSize && i > 0){ - totalSize -= size; - break; - } - if(streamId < STREAM_OFFSET_TXD){ - if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED) - havePed = 1; - if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE) - haveBigFile = 1; - }else{ - if(size > 200) - haveBigFile = 1; - } - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING; - ms_aInfoForModel[streamId].RemoveFromList(); - DecrementRef(streamId); - - streamId = ms_aInfoForModel[streamId].m_nextID; - } - - // clear remaining slots - for(; i < 4; i++) - ms_channel[ch].streamIds[i] = -1; - // Now read the data - assert(!(ms_bLoadingBigModel && ch == 1)); // this would clobber the buffer - if(CdStreamRead(ch, ms_pStreamingBuffer[ch], imgOffset+posn, totalSize) == STREAM_NONE) - debug("FUCKFUCKFUCK\n"); - ms_channel[ch].state = CHANNELSTATE_READING; - ms_channel[ch].field24 = 0; - ms_channel[ch].size = totalSize; - ms_channel[ch].position = imgOffset+posn; - ms_channel[ch].numTries = 0; -} - -// Load data previously read from disc -bool -CStreaming::ProcessLoadingChannel(int32 ch) -{ - int status; - int i, id, cdsize; - - status = CdStreamGetStatus(ch); - if(status != STREAM_NONE){ - // busy - if(status != STREAM_READING && status != STREAM_WAITING){ - ms_channelError = ch; - ms_channel[ch].state = CHANNELSTATE_ERROR; - ms_channel[ch].status = status; - } - return false; - } - - if(ms_channel[ch].state == CHANNELSTATE_STARTED){ - ms_channel[ch].state = CHANNELSTATE_IDLE; - FinishLoadingLargeFile(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[0]*CDSTREAM_SECTOR_SIZE], - ms_channel[ch].streamIds[0]); - ms_channel[ch].streamIds[0] = -1; - }else{ - ms_channel[ch].state = CHANNELSTATE_IDLE; - for(i = 0; i < 4; i++){ - id = ms_channel[ch].streamIds[i]; - if(id == -1) - continue; - - cdsize = ms_aInfoForModel[id].GetCdSize(); - if(id < STREAM_OFFSET_TXD && - CModelInfo::GetModelInfo(id)->m_type == MITYPE_VEHICLE && - ms_numVehiclesLoaded >= desiredNumVehiclesLoaded && - !RemoveLoadedVehicle() && - ((ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 || GetAvailableVehicleSlot() == -1)){ - // can't load vehicle - RemoveModel(id); - if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) - ReRequestModel(id); - else if(CTxdStore::GetNumRefs(CModelInfo::GetModelInfo(id)->GetTxdSlot()) == 0) - RemoveTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot()); - }else{ - MakeSpaceFor(cdsize * CDSTREAM_SECTOR_SIZE); - ConvertBufferToObject(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[i]*CDSTREAM_SECTOR_SIZE], - id); - if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){ - // queue for second part - ms_channel[ch].state = CHANNELSTATE_STARTED; - ms_channel[ch].offsets[0] = ms_channel[ch].offsets[i]; - ms_channel[ch].streamIds[0] = id; - if(i != 0) - ms_channel[ch].streamIds[i] = -1; - }else - ms_channel[ch].streamIds[i] = -1; - } - } - } - - if(ms_bLoadingBigModel && ms_channel[ch].state != CHANNELSTATE_STARTED){ - ms_bLoadingBigModel = false; - // reset channel 1 after loading a big model - for(i = 0; i < 4; i++) - ms_channel[1].streamIds[i] = -1; - ms_channel[1].state = CHANNELSTATE_IDLE; - } - - return true; -} - -void -CStreaming::RetryLoadFile(int32 ch) -{ - char *key; - - CPad::StopPadsShaking(); - - if(ms_channel[ch].numTries >= 3){ - switch(ms_channel[ch].status){ - case STREAM_ERROR_NOCD: key = "NOCD"; break; - case STREAM_ERROR_OPENCD: key = "OPENCD"; break; - case STREAM_ERROR_WRONGCD: key = "WRONGCD"; break; - default: key = "CDERROR"; break; - } - CHud::SetMessage(TheText.Get(key)); - CTimer::SetCodePause(true); - } - - switch(ms_channel[ch].state){ - case CHANNELSTATE_IDLE: -streamread: - CdStreamRead(ch, ms_pStreamingBuffer[ch], ms_channel[ch].position, ms_channel[ch].size); - ms_channel[ch].state = CHANNELSTATE_READING; - ms_channel[ch].field24 = -600; - break; - case CHANNELSTATE_READING: - if(ProcessLoadingChannel(ch)){ - ms_channelError = -1; - CTimer::SetCodePause(false); - } - break; - case CHANNELSTATE_ERROR: - ms_channel[ch].numTries++; - if(CdStreamGetStatus(ch) != STREAM_READING && CdStreamGetStatus(ch) != STREAM_WAITING) - goto streamread; - break; - } -} - -void -CStreaming::LoadRequestedModels(void) -{ - static int currentChannel = 0; - - // We can't read with channel 1 while channel 0 is using its buffer - if(ms_bLoadingBigModel) - currentChannel = 0; - - // We have data, load - if(ms_channel[currentChannel].state == CHANNELSTATE_READING || - ms_channel[currentChannel].state == CHANNELSTATE_STARTED) - ProcessLoadingChannel(currentChannel); - - if(ms_channelError == -1){ - // Channel is idle, read more data - if(ms_channel[currentChannel].state == CHANNELSTATE_IDLE) - RequestModelStream(currentChannel); - // Switch channel - if(ms_channel[currentChannel].state != CHANNELSTATE_STARTED) - currentChannel = 1 - currentChannel; - } -} - -void -CStreaming::LoadAllRequestedModels(bool priority) -{ - static bool bInsideLoadAll = false; - int imgOffset, streamId, status; - int i; - uint32 posn, size; - - if(bInsideLoadAll) - return; - - FlushChannels(); - imgOffset = GetCdImageOffset(CdStreamGetLastPosn()); - - while(ms_endRequestedList.m_prev != &ms_startRequestedList){ - streamId = GetNextFileOnCd(0, priority); - if(streamId == -1) - break; - - ms_aInfoForModel[streamId].RemoveFromList(); - DecrementRef(streamId); - - if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){ - do - status = CdStreamRead(0, ms_pStreamingBuffer[0], imgOffset+posn, size); - while(CdStreamSync(0) || status == STREAM_NONE); - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING; - - MakeSpaceFor(size * CDSTREAM_SECTOR_SIZE); - ConvertBufferToObject(ms_pStreamingBuffer[0], streamId); - if(ms_aInfoForModel[streamId].m_loadState == STREAMSTATE_STARTED) - FinishLoadingLargeFile(ms_pStreamingBuffer[0], streamId); - - if(streamId < STREAM_OFFSET_TXD){ - CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamId); - if(mi->IsSimple()) - mi->m_alpha = 255; - } - }else{ - // empty - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; - } - } - - ms_bLoadingBigModel = false; - for(i = 0; i < 4; i++){ - ms_channel[1].streamIds[i] = -1; - ms_channel[1].offsets[i] = -1; - } - ms_channel[1].state = CHANNELSTATE_IDLE; - bInsideLoadAll = false; -} - -void -CStreaming::FlushChannels(void) -{ - if(ms_channel[1].state == CHANNELSTATE_STARTED) - ProcessLoadingChannel(1); - - if(ms_channel[0].state == CHANNELSTATE_READING){ - CdStreamSync(0); - ProcessLoadingChannel(0); - } - if(ms_channel[0].state == CHANNELSTATE_STARTED) - ProcessLoadingChannel(0); - - if(ms_channel[1].state == CHANNELSTATE_READING){ - CdStreamSync(1); - ProcessLoadingChannel(1); - } - if(ms_channel[1].state == CHANNELSTATE_STARTED) - ProcessLoadingChannel(1); -} - -void -CStreaming::FlushRequestList(void) -{ - CStreamingInfo *si, *next; - - for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){ - next = si->m_next; - RemoveModel(si - ms_aInfoForModel); - } - FlushChannels(); -} - - -void -CStreaming::ImGonnaUseStreamingMemory(void) -{ - // empty -} - -void -CStreaming::IHaveUsedStreamingMemory(void) -{ - UpdateMemoryUsed(); -} - -void -CStreaming::UpdateMemoryUsed(void) -{ - // empty -} - -#define STREAM_DIST (2*SECTOR_SIZE_X) - -void -CStreaming::AddModelsToRequestList(const CVector &pos) -{ - float xmin, xmax, ymin, ymax; - int ixmin, ixmax, iymin, iymax; - int ix, iy; - int dx, dy, d; - CSector *sect; - - xmin = pos.x - STREAM_DIST; - ymin = pos.y - STREAM_DIST; - xmax = pos.x + STREAM_DIST; - ymax = pos.y + STREAM_DIST; - - ixmin = CWorld::GetSectorIndexX(xmin); - if(ixmin < 0) ixmin = 0; - ixmax = CWorld::GetSectorIndexX(xmax); - if(ixmax >= NUMSECTORS_X) ixmax = NUMSECTORS_X-1; - iymin = CWorld::GetSectorIndexY(ymin); - if(iymin < 0) iymin = 0; - iymax = CWorld::GetSectorIndexY(ymax); - if(iymax >= NUMSECTORS_Y) iymax = NUMSECTORS_Y-1; - - CWorld::AdvanceCurrentScanCode(); - - for(iy = iymin; iy < iymax; iy++){ - dy = iy - CWorld::GetSectorIndexY(pos.y); - for(ix = ixmin; ix < ixmax; ix++){ - - if(CRenderer::m_loadingPriority && ms_numModelsRequested > 5) - return; - - dx = ix - CWorld::GetSectorIndexX(pos.x); - d = dx*dx + dy*dy; - sect = CWorld::GetSector(ix, iy); - if(d <= 1){ - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - }else if(d <= 4*4){ - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], pos.x, pos.y, xmin, ymin, xmax, ymax); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], pos.x, pos.y, xmin, ymin, xmax, ymax); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], pos.x, pos.y, xmin, ymin, xmax, ymax); - ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], pos.x, pos.y, xmin, ymin, xmax, ymax); - } - } - } -} - -void -CStreaming::ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float xmin, float ymin, float xmax, float ymax) -{ - CPtrNode *node; - CEntity *e; - float lodDistSq; - CVector2D pos; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - - if(e->m_scanCode == CWorld::GetCurrentScanCode()) - continue; - - e->m_scanCode = CWorld::GetCurrentScanCode(); - if(!e->bStreamingDontDelete && !e->bIsSubway && - (!e->IsObject() || ((CObject*)e)->ObjectCreatedBy != TEMP_OBJECT)){ - CTimeModelInfo *mi = (CTimeModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()); - if(mi->m_type != MITYPE_TIME || CClock::GetIsTimeInRange(mi->GetTimeOn(), mi->GetTimeOff())){ - lodDistSq = sq(mi->GetLargestLodDistance()); - lodDistSq = min(lodDistSq, sq(STREAM_DIST)); - pos = CVector2D(e->GetPosition()); - if(xmin < pos.x && pos.x < xmax && - ymin < pos.y && pos.y < ymax && - (CVector2D(x, y) - pos).MagnitudeSqr() < lodDistSq) - if(CRenderer::IsEntityCullZoneVisible(e)) - RequestModel(e->GetModelIndex(), 0); - } - } - } -} - -void -CStreaming::ProcessEntitiesInSectorList(CPtrList &list) -{ - CPtrNode *node; - CEntity *e; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - - if(e->m_scanCode == CWorld::GetCurrentScanCode()) - continue; - - e->m_scanCode = CWorld::GetCurrentScanCode(); - if(!e->bStreamingDontDelete && !e->bIsSubway && - (!e->IsObject() || ((CObject*)e)->ObjectCreatedBy != TEMP_OBJECT)){ - CTimeModelInfo *mi = (CTimeModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()); - if(mi->m_type != MITYPE_TIME || CClock::GetIsTimeInRange(mi->GetTimeOn(), mi->GetTimeOff())) - if(CRenderer::IsEntityCullZoneVisible(e)) - RequestModel(e->GetModelIndex(), 0); - } - } -} - -void -CStreaming::DeleteFarAwayRwObjects(const CVector &pos) -{ - int posx, posy; - int x, y; - int r, i; - CSector *sect; - - posx = CWorld::GetSectorIndexX(pos.x); - posy = CWorld::GetSectorIndexY(pos.y); - - // Move oldSectorX/Y to new sector and delete RW objects in its "wake" for every step: - // O is the old sector, <- is the direction in which we move it, - // X are the sectors we delete RW objects from (except we go up to 10) - // X - // X X - // X X X - // X X X - // <- O X X X - // X X X - // X X X - // X X - // X - - while(posx != ms_oldSectorX){ - if(posx < ms_oldSectorX){ - for(r = 2; r <= 10; r++){ - x = ms_oldSectorX + r; - if(x < 0) - continue; - if(x >= NUMSECTORS_X) - break; - - for(i = -r; i <= r; i++){ - y = ms_oldSectorY + i; - if(y < 0) - continue; - if(y >= NUMSECTORS_Y) - break; - - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - } - } - ms_oldSectorX--; - }else{ - for(r = 2; r <= 10; r++){ - x = ms_oldSectorX - r; - if(x < 0) - break; - if(x >= NUMSECTORS_X) - continue; - - for(i = -r; i <= r; i++){ - y = ms_oldSectorY + i; - if(y < 0) - continue; - if(y >= NUMSECTORS_Y) - break; - - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - } - } - ms_oldSectorX++; - } - } - - while(posy != ms_oldSectorY){ - if(posy < ms_oldSectorY){ - for(r = 2; r <= 10; r++){ - y = ms_oldSectorY + r; - if(y < 0) - continue; - if(y >= NUMSECTORS_Y) - break; - - for(i = -r; i <= r; i++){ - x = ms_oldSectorX + i; - if(x < 0) - continue; - if(x >= NUMSECTORS_X) - break; - - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - } - } - ms_oldSectorY--; - }else{ - for(r = 2; r <= 10; r++){ - y = ms_oldSectorY - r; - if(y < 0) - break; - if(y >= NUMSECTORS_Y) - continue; - - for(i = -r; i <= r; i++){ - x = ms_oldSectorX + i; - if(x < 0) - continue; - if(x >= NUMSECTORS_X) - break; - - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - } - } - ms_oldSectorY++; - } - } -} - -void -CStreaming::DeleteAllRwObjects(void) -{ - int x, y; - CSector *sect; - - for(x = 0; x < NUMSECTORS_X; x++) - for(y = 0; y < NUMSECTORS_Y; y++){ - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS_OVERLAP]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES_OVERLAP]); - } -} - -void -CStreaming::DeleteRwObjectsAfterDeath(const CVector &pos) -{ - int ix, iy; - int x, y; - CSector *sect; - - ix = CWorld::GetSectorIndexX(pos.x); - iy = CWorld::GetSectorIndexX(pos.y); - - for(x = 0; x < NUMSECTORS_X; x++) - for(y = 0; y < NUMSECTORS_Y; y++) - if(fabs(ix - x) > 3.0f && - fabs(iy - y) > 3.0f){ - sect = CWorld::GetSector(x, y); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS_OVERLAP]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); - DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES_OVERLAP]); - } -} - -void -CStreaming::DeleteRwObjectsBehindCamera(int32 mem) -{ - int ix, iy; - int x, y; - int xmin, xmax, ymin, ymax; - int inc; - CSector *sect; - - if(ms_memoryUsed < mem) - return; - - ix = CWorld::GetSectorIndexX(TheCamera.GetPosition().x); - iy = CWorld::GetSectorIndexX(TheCamera.GetPosition().y); - - if(fabs(TheCamera.GetForward().x) > fabs(TheCamera.GetForward().y)){ - // looking west/east - - ymin = max(iy - 10, 0); - ymax = min(iy + 10, NUMSECTORS_Y); - assert(ymin <= ymax); - - // Delete a block of sectors that we know is behind the camera - if(TheCamera.GetForward().x > 0){ - // looking east - xmax = max(ix - 2, 0); - xmin = max(ix - 10, 0); - inc = 1; - }else{ - // looking west - xmax = min(ix + 2, NUMSECTORS_X); - xmin = min(ix + 10, NUMSECTORS_X); - inc = -1; - } - for(y = ymin; y <= ymax; y++){ - for(x = xmin; x != xmax; x += inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - - // Now a block that intersects with the camera's frustum - if(TheCamera.GetForward().x > 0){ - // looking east - xmax = max(ix + 10, 0); - xmin = max(ix - 2, 0); - inc = 1; - }else{ - // looking west - xmax = min(ix - 10, NUMSECTORS_X); - xmin = min(ix + 2, NUMSECTORS_X); - inc = -1; - } - for(y = ymin; y <= ymax; y++){ - for(x = xmin; x != xmax; x += inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - - if(RemoveReferencedTxds(mem)) - return; - - // As last resort, delete objects from the last step more aggressively - for(y = ymin; y <= ymax; y++){ - for(x = xmax; x != xmin; x -= inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - }else{ - // looking north/south - - xmin = max(ix - 10, 0); - xmax = min(ix + 10, NUMSECTORS_X); - assert(xmin <= xmax); - - // Delete a block of sectors that we know is behind the camera - if(TheCamera.GetForward().y > 0){ - // looking north - ymax = max(iy - 2, 0); - ymin = max(iy - 10, 0); - inc = 1; - }else{ - // looking south - ymax = min(iy + 2, NUMSECTORS_Y); - ymin = min(iy + 10, NUMSECTORS_Y); - inc = -1; - } - for(x = xmin; x <= xmax; x++){ - for(y = ymin; y != ymax; y += inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - - // Now a block that intersects with the camera's frustum - if(TheCamera.GetForward().y > 0){ - // looking north - ymax = max(iy + 10, 0); - ymin = max(iy - 2, 0); - inc = 1; - }else{ - // looking south - ymax = min(iy - 10, NUMSECTORS_Y); - ymin = min(iy + 2, NUMSECTORS_Y); - inc = -1; - } - for(x = xmin; x <= xmax; x++){ - for(y = ymin; y != ymax; y += inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - - if(RemoveReferencedTxds(mem)) - return; - - // As last resort, delete objects from the last step more aggressively - for(x = xmin; x <= xmax; x++){ - for(y = ymax; y != ymin; y -= inc){ - sect = CWorld::GetSector(x, y); - if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || - DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) - return; - } - } - } -} - -void -CStreaming::DeleteRwObjectsInSectorList(CPtrList &list) -{ - CPtrNode *node; - CEntity *e; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(!e->bStreamingDontDelete && !e->bImBeingRendered) - e->DeleteRwObject(); - } -} - -void -CStreaming::DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y) -{ - CPtrNode *node; - CEntity *e; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(e->m_rwObject && !e->bStreamingDontDelete && !e->bImBeingRendered){ - // Now this is pretty weird... - if(fabs(CWorld::GetSectorIndexX(e->GetPosition().x) - x) >= 2.0f) -// { - e->DeleteRwObject(); -// return; // BUG? -// } - else // FIX? - if(fabs(CWorld::GetSectorIndexY(e->GetPosition().y) - y) >= 2.0f) - e->DeleteRwObject(); - } - } -} - -bool -CStreaming::DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, int32 mem) -{ - CPtrNode *node; - CEntity *e; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(!e->bStreamingDontDelete && !e->bImBeingRendered && - e->m_rwObject && ms_aInfoForModel[e->GetModelIndex()].m_next){ - e->DeleteRwObject(); - if(CModelInfo::GetModelInfo(e->GetModelIndex())->m_refCount == 0){ - RemoveModel(e->GetModelIndex()); - if(ms_memoryUsed < mem) - return true; - } - } - } - return false; -} - -bool -CStreaming::DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, int32 mem) -{ - CPtrNode *node; - CEntity *e; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(!e->bStreamingDontDelete && !e->bImBeingRendered && - e->m_rwObject && !e->IsVisible() && ms_aInfoForModel[e->GetModelIndex()].m_next){ - e->DeleteRwObject(); - if(CModelInfo::GetModelInfo(e->GetModelIndex())->m_refCount == 0){ - RemoveModel(e->GetModelIndex()); - if(ms_memoryUsed < mem) - return true; - } - } - } - return false; -} - -void -CStreaming::MakeSpaceFor(int32 size) -{ - // BUG: ms_memoryAvailable can be uninitialized - // the code still happens to work in that case because ms_memoryAvailable is unsigned - // but it's not nice.... - - while((uint32)ms_memoryUsed >= ms_memoryAvailable - size) - if(!RemoveLeastUsedModel()){ - DeleteRwObjectsBehindCamera(ms_memoryAvailable - size); - return; - } -} - -void -CStreaming::LoadScene(const CVector &pos) -{ - CStreamingInfo *si, *prev; - eLevelName level; - - level = CTheZones::GetLevelFromPosition(pos); - debug("Start load scene\n"); - for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ - prev = si->m_prev; - if((si->m_flags & (STREAMFLAGS_KEEP_IN_MEMORY|STREAMFLAGS_PRIORITY)) == 0) - RemoveModel(si - ms_aInfoForModel); - } - CRenderer::m_loadingPriority = false; - CCullZones::ForceCullZoneCoors(pos); - DeleteAllRwObjects(); - AddModelsToRequestList(pos); - CRadar::StreamRadarSections(pos); - RemoveUnusedBigBuildings(level); - RequestBigBuildings(level); - LoadAllRequestedModels(false); - debug("End load scene\n"); -} - -void -CStreaming::MemoryCardSave(uint8 *buffer, uint32 *length) -{ - int i; - - *length = NUM_DEFAULT_MODELS; - for(i = 0; i < NUM_DEFAULT_MODELS; i++) - if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED) - buffer[i] = ms_aInfoForModel[i].m_flags; - else - buffer[i] = 0xFF; -} - -void -CStreaming::MemoryCardLoad(uint8 *buffer, uint32 length) -{ - uint32 i; - - assert(length == NUM_DEFAULT_MODELS); - for(i = 0; i < length; i++) - if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED) - if(buffer[i] != 0xFF) - ms_aInfoForModel[i].m_flags = buffer[i]; -} - -STARTPATCHES - InjectHook(0x406430, CStreaming::Init, PATCH_JUMP); - InjectHook(0x406C80, CStreaming::Shutdown, PATCH_JUMP); - InjectHook(0x4076C0, CStreaming::Update, PATCH_JUMP); - InjectHook(0x406CC0, (void (*)(void))CStreaming::LoadCdDirectory, PATCH_JUMP); - InjectHook(0x406DA0, (void (*)(const char*, int))CStreaming::LoadCdDirectory, PATCH_JUMP); - InjectHook(0x409740, CStreaming::ConvertBufferToObject, PATCH_JUMP); - InjectHook(0x409580, CStreaming::FinishLoadingLargeFile, PATCH_JUMP); - InjectHook(0x407EA0, CStreaming::RequestModel, PATCH_JUMP); - InjectHook(0x407FD0, CStreaming::RequestSubway, PATCH_JUMP); - InjectHook(0x408190, CStreaming::RequestBigBuildings, PATCH_JUMP); - InjectHook(0x408210, CStreaming::RequestIslands, PATCH_JUMP); - InjectHook(0x40A890, CStreaming::RequestSpecialModel, PATCH_JUMP); - InjectHook(0x40ADA0, CStreaming::RequestSpecialChar, PATCH_JUMP); - InjectHook(0x54A5F0, CStreaming::HasModelLoaded, PATCH_JUMP); - InjectHook(0x40ADC0, CStreaming::HasSpecialCharLoaded, PATCH_JUMP); - InjectHook(0x40ADE0, CStreaming::SetMissionDoesntRequireSpecialChar, PATCH_JUMP); - - InjectHook(0x408830, CStreaming::RemoveModel, PATCH_JUMP); - InjectHook(0x4083A0, CStreaming::RemoveUnusedBuildings, PATCH_JUMP); - InjectHook(0x4083D0, CStreaming::RemoveBuildings, PATCH_JUMP); - InjectHook(0x408640, CStreaming::RemoveUnusedBigBuildings, PATCH_JUMP); - InjectHook(0x408680, CStreaming::RemoveBigBuildings, PATCH_JUMP); - InjectHook(0x408780, CStreaming::RemoveIslandsNotUsed, PATCH_JUMP); - InjectHook(0x40B180, CStreaming::RemoveLoadedVehicle, PATCH_JUMP); - InjectHook(0x4089B0, CStreaming::RemoveLeastUsedModel, PATCH_JUMP); - InjectHook(0x408940, CStreaming::RemoveAllUnusedModels, PATCH_JUMP); - InjectHook(0x409450, CStreaming::RemoveReferencedTxds, PATCH_JUMP); - - InjectHook(0x40B160, CStreaming::GetAvailableVehicleSlot, PATCH_JUMP); - InjectHook(0x40B060, CStreaming::AddToLoadedVehiclesList, PATCH_JUMP); - InjectHook(0x4094C0, CStreaming::IsTxdUsedByRequestedModels, PATCH_JUMP); - InjectHook(0x407E70, CStreaming::IsObjectInCdImage, PATCH_JUMP); - InjectHook(0x408280, CStreaming::HaveAllBigBuildingsLoaded, PATCH_JUMP); - InjectHook(0x40A790, CStreaming::SetModelIsDeletable, PATCH_JUMP); - InjectHook(0x40A800, CStreaming::SetModelTxdIsDeletable, PATCH_JUMP); - InjectHook(0x40A820, CStreaming::SetMissionDoesntRequireModel, PATCH_JUMP); - - InjectHook(0x40AA00, CStreaming::LoadInitialPeds, PATCH_JUMP); - InjectHook(0x40ADF0, CStreaming::LoadInitialVehicles, PATCH_JUMP); - InjectHook(0x40AE60, CStreaming::StreamVehiclesAndPeds, PATCH_JUMP); - InjectHook(0x40AA30, CStreaming::StreamZoneModels, PATCH_JUMP); - InjectHook(0x40AD00, CStreaming::RemoveCurrentZonesModels, PATCH_JUMP); - - InjectHook(0x409BE0, CStreaming::ProcessLoadingChannel, PATCH_JUMP); - InjectHook(0x40A610, CStreaming::FlushChannels, PATCH_JUMP); - InjectHook(0x40A680, CStreaming::FlushRequestList, PATCH_JUMP); - InjectHook(0x409FF0, CStreaming::GetCdImageOffset, PATCH_JUMP); - InjectHook(0x409E50, CStreaming::GetNextFileOnCd, PATCH_JUMP); - InjectHook(0x40A060, CStreaming::RequestModelStream, PATCH_JUMP); - InjectHook(0x4077F0, CStreaming::RetryLoadFile, PATCH_JUMP); - InjectHook(0x40A390, CStreaming::LoadRequestedModels, PATCH_JUMP); - InjectHook(0x40A440, CStreaming::LoadAllRequestedModels, PATCH_JUMP); - - InjectHook(0x4078F0, CStreaming::AddModelsToRequestList, PATCH_JUMP); - InjectHook(0x407C50, (void (*)(CPtrList&,float,float,float,float,float,float))CStreaming::ProcessEntitiesInSectorList, PATCH_JUMP); - InjectHook(0x407DD0, (void (*)(CPtrList&))CStreaming::ProcessEntitiesInSectorList, PATCH_JUMP); - - InjectHook(0x407070, CStreaming::DeleteFarAwayRwObjects, PATCH_JUMP); - InjectHook(0x407390, CStreaming::DeleteAllRwObjects, PATCH_JUMP); - InjectHook(0x407400, CStreaming::DeleteRwObjectsAfterDeath, PATCH_JUMP); - InjectHook(0x408A60, CStreaming::DeleteRwObjectsBehindCamera, PATCH_JUMP); - InjectHook(0x407560, CStreaming::DeleteRwObjectsInSectorList, PATCH_JUMP); - InjectHook(0x4075A0, CStreaming::DeleteRwObjectsInOverlapSectorList, PATCH_JUMP); - InjectHook(0x409340, CStreaming::DeleteRwObjectsBehindCameraInSectorList, PATCH_JUMP); - InjectHook(0x4093C0, CStreaming::DeleteRwObjectsNotInFrustumInSectorList, PATCH_JUMP); - InjectHook(0x409B70, CStreaming::MakeSpaceFor, PATCH_JUMP); - InjectHook(0x40A6D0, CStreaming::LoadScene, PATCH_JUMP); - - InjectHook(0x40B210, CStreaming::MemoryCardSave, PATCH_JUMP); - InjectHook(0x40B250, CStreaming::MemoryCardLoad, PATCH_JUMP); - - InjectHook(0x4063E0, &CStreamingInfo::GetCdPosnAndSize, PATCH_JUMP); - InjectHook(0x406410, &CStreamingInfo::SetCdPosnAndSize, PATCH_JUMP); - InjectHook(0x4063D0, &CStreamingInfo::GetCdSize, PATCH_JUMP); - InjectHook(0x406380, &CStreamingInfo::AddToList, PATCH_JUMP); - InjectHook(0x4063A0, &CStreamingInfo::RemoveFromList, PATCH_JUMP); -ENDPATCHES diff --git a/src/Streaming.h b/src/Streaming.h deleted file mode 100644 index 212a6d71..00000000 --- a/src/Streaming.h +++ /dev/null @@ -1,188 +0,0 @@ -#pragma once - -#include "Game.h" - -enum { - STREAM_OFFSET_MODEL = 0, - STREAM_OFFSET_TXD = STREAM_OFFSET_MODEL+MODELINFOSIZE, - NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE -}; - -enum StreamFlags -{ - STREAMFLAGS_DONT_REMOVE = 0x01, - STREAMFLAGS_SCRIPTOWNED = 0x02, - STREAMFLAGS_DEPENDENCY = 0x04, // Is this right? - STREAMFLAGS_PRIORITY = 0x08, - STREAMFLAGS_NOFADE = 0x10, - - // TODO: this isn't named well, maybe CANT_REMOVE? - STREAMFLAGS_NOT_IN_LIST = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED, - STREAMFLAGS_KEEP_IN_MEMORY = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED|STREAMFLAGS_DEPENDENCY, -}; - -enum StreamLoadState -{ - STREAMSTATE_NOTLOADED = 0, - STREAMSTATE_LOADED = 1, - STREAMSTATE_INQUEUE = 2, - STREAMSTATE_READING = 3, // channel is reading - STREAMSTATE_STARTED = 4, // first part loaded -}; - -enum ChannelState -{ - CHANNELSTATE_IDLE = 0, - CHANNELSTATE_READING = 1, - CHANNELSTATE_STARTED = 2, - CHANNELSTATE_ERROR = 3, -}; - -class CStreamingInfo -{ -public: - CStreamingInfo *m_next; - CStreamingInfo *m_prev; - uint8 m_loadState; - uint8 m_flags; - - int16 m_nextID; - uint32 m_position; - uint32 m_size; - - bool GetCdPosnAndSize(uint32 &posn, uint32 &size); - void SetCdPosnAndSize(uint32 posn, uint32 size); - void AddToList(CStreamingInfo *link); - void RemoveFromList(void); - uint32 GetCdSize(void) { return m_size; } - bool IsPriority(void) { return !!(m_flags & STREAMFLAGS_PRIORITY); } -}; - -struct CStreamingChannel -{ - int32 streamIds[4]; - int32 offsets[4]; - int32 state; - int32 field24; - int32 position; - int32 size; - int32 numTries; - int32 status; // from CdStream -}; - -class CDirectory; -enum eLevelName; -class CPtrList; - -class CStreaming -{ -public: - static bool &ms_disableStreaming; - static bool &ms_bLoadingBigModel; - static int32 &ms_numModelsRequested; - static CStreamingInfo *ms_aInfoForModel; //[NUMSTREAMINFO] - static CStreamingInfo &ms_startLoadedList; - static CStreamingInfo &ms_endLoadedList; - static CStreamingInfo &ms_startRequestedList; - static CStreamingInfo &ms_endRequestedList; - static int32 &ms_oldSectorX; - static int32 &ms_oldSectorY; - static int32 &ms_streamingBufferSize; - static int8 **ms_pStreamingBuffer; //[2] - static int32 &ms_memoryUsed; - static CStreamingChannel *ms_channel; //[2] - static int32 &ms_channelError; - static int32 &ms_numVehiclesLoaded; - static int32 *ms_vehiclesLoaded; //[MAXVEHICLESLOADED] - static int32 &ms_lastVehicleDeleted; - static CDirectory *&ms_pExtraObjectsDir; - static int32 &ms_numPriorityRequests; - static bool &ms_hasLoadedLODs; - static int32 &ms_currentPedGrp; - static int32 ms_lastCullZone; - static uint16 &ms_loadedGangs; - static uint16 &ms_loadedGangCars; - static int32 ms_currentPedLoading; - static int32 *ms_imageOffsets; //[NUMCDIMAGES] - static int32 &ms_lastImageRead; - static int32 &ms_imageSize; - static uint32 &ms_memoryAvailable; - - static void Init(void); - static void Shutdown(void); - static void Update(void); - static void LoadCdDirectory(void); - static void LoadCdDirectory(const char *dirname, int32 n); - static bool ConvertBufferToObject(int8 *buf, int32 streamId); - static bool FinishLoadingLargeFile(int8 *buf, int32 streamId); - static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; } - static void RequestModel(int32 model, int32 flags); - static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); } - static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); } - static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); } - static void RequestSubway(void); - static void RequestBigBuildings(eLevelName level); - static void RequestIslands(eLevelName level); - static void RequestSpecialModel(int32 modelId, const char *modelName, int32 flags); - static void RequestSpecialChar(int32 charId, const char *modelName, int32 flags); - static bool HasSpecialCharLoaded(int32 id); - static void SetMissionDoesntRequireSpecialChar(int32 id); - static void DecrementRef(int32 id); - static void RemoveModel(int32 id); - static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); } - static void RemoveUnusedBuildings(eLevelName level); - static void RemoveBuildings(eLevelName level); - static void RemoveUnusedBigBuildings(eLevelName level); - static void RemoveIslandsNotUsed(eLevelName level); - static void RemoveBigBuildings(eLevelName level); - static bool RemoveLoadedVehicle(void); - static bool RemoveLeastUsedModel(void); - static void RemoveAllUnusedModels(void); - static void RemoveUnusedModelsInLoadedList(void); - static bool RemoveReferencedTxds(int32 mem); - static int32 GetAvailableVehicleSlot(void); - static bool IsTxdUsedByRequestedModels(int32 txdId); - static bool AddToLoadedVehiclesList(int32 modelId); - static bool IsObjectInCdImage(int32 id); - static void HaveAllBigBuildingsLoaded(eLevelName level); - static void SetModelIsDeletable(int32 id); - static void SetModelTxdIsDeletable(int32 id); - static void SetMissionDoesntRequireModel(int32 id); - static void LoadInitialPeds(void); - static void LoadInitialVehicles(void); - static void StreamVehiclesAndPeds(void); - static void StreamZoneModels(const CVector &pos); - static void RemoveCurrentZonesModels(void); - - static int32 GetCdImageOffset(int32 lastPosn); - static int32 GetNextFileOnCd(int32 position, bool priority); - static void RequestModelStream(int32 ch); - static bool ProcessLoadingChannel(int32 ch); - static void RetryLoadFile(int32 ch); - static void LoadRequestedModels(void); - static void LoadAllRequestedModels(bool priority); - static void FlushChannels(void); - static void FlushRequestList(void); - - static void MakeSpaceFor(int32 size); - static void ImGonnaUseStreamingMemory(void); - static void IHaveUsedStreamingMemory(void); - static void UpdateMemoryUsed(void); - - static void AddModelsToRequestList(const CVector &pos); - static void ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float xmin, float ymin, float xmax, float ymax); - static void ProcessEntitiesInSectorList(CPtrList &list); - static void DeleteFarAwayRwObjects(const CVector &pos); - static void DeleteAllRwObjects(void); - static void DeleteRwObjectsAfterDeath(const CVector &pos); - static void DeleteRwObjectsBehindCamera(int32 mem); - static void DeleteRwObjectsInSectorList(CPtrList &list); - static void DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y); - static bool DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, int32 mem); - static bool DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, int32 mem); - - static void LoadScene(const CVector &pos); - - static void MemoryCardSave(uint8 *buffer, uint32 *length); - static void MemoryCardLoad(uint8 *buffer, uint32 length); -}; diff --git a/src/SurfaceTable.cpp b/src/SurfaceTable.cpp deleted file mode 100644 index 2ba884b1..00000000 --- a/src/SurfaceTable.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "FileMgr.h" -#include "Weather.h" -#include "Collision.h" -#include "SurfaceTable.h" - -float (*CSurfaceTable::ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS] = (float (*)[NUMADHESIVEGROUPS])0x8E29D4; - -void -CSurfaceTable::Initialise(char *filename) -{ - int lineno, fieldno; - char *line; - char surfname[256]; - float adhesiveLimit; - - CFileMgr::SetDir(""); - CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r"); - - line = (char*)work_buff; - for(lineno = 0; lineno < NUMADHESIVEGROUPS; lineno++){ - // skip white space and comments - while(*line == ' ' || *line == '\t' || *line == '\n' || *line == '\r' || *line == ';'){ - if(*line == ';'){ - while(*line != '\n' && *line != '\r') - line++; - }else - line++; - } - - sscanf(line, "%s", surfname); - // skip what we just read - while(!(*line == ' ' || *line == '\t' || *line == ',')) - line++; - - for(fieldno = 0; fieldno <= lineno; fieldno++){ - // skip white space - while(*line == ' ' || *line == '\t' || *line == ',') - line++; - adhesiveLimit = 0.0f; - if(*line != '-') - sscanf(line, "%f", &adhesiveLimit); - // skip what we just read - while(!(*line == ' ' || *line == '\t' || *line == ',' || *line == '\n')) - line++; - - ms_aAdhesiveLimitTable[lineno][fieldno] = adhesiveLimit; - ms_aAdhesiveLimitTable[fieldno][lineno] = adhesiveLimit; - } - } -} - -int -CSurfaceTable::GetAdhesionGroup(uint8 surfaceType) -{ - switch(surfaceType){ - case SURFACE_0: return ADHESIVE_ROAD; - case SURFACE_1: return ADHESIVE_ROAD; - case SURFACE_2: return ADHESIVE_LOOSE; - case SURFACE_3: return ADHESIVE_LOOSE; - case SURFACE_4: return ADHESIVE_HARD; - case SURFACE_5: return ADHESIVE_ROAD; - case SURFACE_6: return ADHESIVE_HARD; - case SURFACE_7: return ADHESIVE_HARD; - case SURFACE_8: return ADHESIVE_HARD; - case SURFACE_9: return ADHESIVE_HARD; - case SURFACE_10: return ADHESIVE_HARD; - case SURFACE_11: return ADHESIVE_HARD; - case SURFACE_12: return ADHESIVE_HARD; - case SURFACE_13: return ADHESIVE_HARD; - case SURFACE_14: return ADHESIVE_HARD; - case SURFACE_15: return ADHESIVE_HARD; - case SURFACE_16: return ADHESIVE_HARD; - case SURFACE_17: return ADHESIVE_RUBBER; - case SURFACE_18: return ADHESIVE_LOOSE; - case SURFACE_19: return ADHESIVE_WET; - case SURFACE_20: return ADHESIVE_ROAD; - case SURFACE_21: return ADHESIVE_ROAD; - case SURFACE_22: return ADHESIVE_ROAD; - case SURFACE_23: return ADHESIVE_RUBBER; - case SURFACE_24: return ADHESIVE_HARD; - case SURFACE_25: return ADHESIVE_LOOSE; - case SURFACE_26: return ADHESIVE_LOOSE; - case SURFACE_27: return ADHESIVE_HARD; - case SURFACE_28: return ADHESIVE_HARD; - case SURFACE_29: return ADHESIVE_RUBBER; - case SURFACE_30: return ADHESIVE_LOOSE; - case SURFACE_31: return ADHESIVE_HARD; - case SURFACE_32: return ADHESIVE_HARD; - default: return ADHESIVE_ROAD; - } -} - -float -CSurfaceTable::GetWetMultiplier(uint8 surfaceType) -{ - switch(surfaceType){ - case SURFACE_0: - case SURFACE_1: - case SURFACE_4: - case SURFACE_5: - case SURFACE_8: - case SURFACE_20: - case SURFACE_21: - case SURFACE_22: - case SURFACE_25: - case SURFACE_30: - case SURFACE_31: - return 1.0f - CWeather::WetRoads*0.25f; - - case SURFACE_2: - case SURFACE_6: - case SURFACE_7: - case SURFACE_9: - case SURFACE_10: - case SURFACE_11: - case SURFACE_12: - case SURFACE_13: - case SURFACE_14: - case SURFACE_15: - case SURFACE_16: - case SURFACE_17: - case SURFACE_23: - case SURFACE_24: - case SURFACE_26: - case SURFACE_27: - case SURFACE_28: - case SURFACE_29: - case SURFACE_32: - return 1.0f - CWeather::WetRoads*0.4f; - - default: - return 1.0f; - } -} - -float -CSurfaceTable::GetAdhesiveLimit(CColPoint &colpoint) -{ - return ms_aAdhesiveLimitTable[GetAdhesionGroup(colpoint.surfaceB)][GetAdhesionGroup(colpoint.surfaceA)]; -} - -STARTPATCHES - InjectHook(0x4AB8F0, CSurfaceTable::Initialise, PATCH_JUMP); - InjectHook(0x4ABA60, CSurfaceTable::GetAdhesionGroup, PATCH_JUMP); - InjectHook(0x4ABAA0, CSurfaceTable::GetWetMultiplier, PATCH_JUMP); - InjectHook(0x4ABA30, CSurfaceTable::GetAdhesiveLimit, PATCH_JUMP); -ENDPATCHES diff --git a/src/SurfaceTable.h b/src/SurfaceTable.h deleted file mode 100644 index e1882e69..00000000 --- a/src/SurfaceTable.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - - -enum -{ - SURFACE_0, - SURFACE_1, - SURFACE_2, - SURFACE_3, - SURFACE_4, - SURFACE_5, - SURFACE_6, - SURFACE_7, - SURFACE_8, - SURFACE_9, - SURFACE_10, - SURFACE_11, - SURFACE_12, - SURFACE_13, - SURFACE_14, - SURFACE_15, - SURFACE_16, - SURFACE_17, - SURFACE_18, - SURFACE_19, - SURFACE_20, - SURFACE_21, - SURFACE_22, - SURFACE_23, - SURFACE_24, - SURFACE_25, - SURFACE_26, - SURFACE_27, - SURFACE_28, - SURFACE_29, - SURFACE_30, - SURFACE_31, - SURFACE_32, - - NUMSURFACETYPES -}; - -// From nick -// TODO: check and use this -enum eSurfaceType -{ - SURFACE_DEFAULT, - SURFACE_TARMAC, - SURFACE_GRASS, - SURFACE_DIRT, - SURFACE_DIRTTRACK, - SURFACE_PAVEMENT, - SURFACE_METAL6, - SURFACE_GLASS, - SURFACE_SCAFFOLD, - SURFACE_METAL_DOOR, // garage door - SURFACE_BILLBOARD, - SURFACE_STEEL, //? - SURFACE_METAL_POLE, // ? - SURFACE_STREET_LIGHT, - SURFACE_METAL14, - SURFACE_METAL15, - SURFACE_METAL_FENCE, - SURFACE_FLESH, - SURFACE_SAND, - SURFACE_PUDDLE, - SURFACE_WOOD, - SURFACE_WOOD_BOX, - SURFACE_WOOD_PLANK, - SURFACE_TIRE, - SURFACE_HARD24, - SURFACE_HEDGE, - SURFACE_STONE, - SURFACE_METAL27, - SURFACE_METAL28, - SURFACE_RUBBER29, - SURFACE_LOOSE30, - SURFACE_BOLLARD, - SURFACE_GATE, - SURFACE_SAND33, - SURFACE_ROAD34, -}; - -enum -{ - ADHESIVE_RUBBER, - ADHESIVE_HARD, - ADHESIVE_ROAD, - ADHESIVE_LOOSE, - ADHESIVE_WET, - - NUMADHESIVEGROUPS -}; - -struct CColPoint; - -class CSurfaceTable -{ -// static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS]; - static float (*ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS]; -public: - static void Initialise(char *filename); - static int GetAdhesionGroup(uint8 surfaceType); - static float GetWetMultiplier(uint8 surfaceType); - static float GetAdhesiveLimit(CColPoint &colpoint); -}; diff --git a/src/TempColModels.cpp b/src/TempColModels.cpp deleted file mode 100644 index a323d7c9..00000000 --- a/src/TempColModels.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "TempColModels.h" - -CColModel &CTempColModels::ms_colModelPed1 = *(CColModel*)0x726CB0; -CColModel &CTempColModels::ms_colModelPed2 = *(CColModel*)0x726D08; -CColModel &CTempColModels::ms_colModelBBox = *(CColModel*)0x727FE0; -CColModel &CTempColModels::ms_colModelBumper1 = *(CColModel*)0x86BE88; -CColModel &CTempColModels::ms_colModelWheel1 = *(CColModel*)0x878C40; -CColModel &CTempColModels::ms_colModelPanel1 = *(CColModel*)0x87BDD8; -CColModel &CTempColModels::ms_colModelBodyPart2 = *(CColModel*)0x87BE30; -CColModel &CTempColModels::ms_colModelBodyPart1 = *(CColModel*)0x87BE88; -CColModel &CTempColModels::ms_colModelCutObj = *(CColModel*)0x87C960; -CColModel &CTempColModels::ms_colModelPedGroundHit = *(CColModel*)0x880480; -CColModel &CTempColModels::ms_colModelBoot1 = *(CColModel*)0x880670; -CColModel &CTempColModels::ms_colModelDoor1 = *(CColModel*)0x880850; -CColModel &CTempColModels::ms_colModelBonnet1 = *(CColModel*)0x8808A8; diff --git a/src/TempColModels.h b/src/TempColModels.h deleted file mode 100644 index 8ac74428..00000000 --- a/src/TempColModels.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "Collision.h" - -class CTempColModels -{ -public: - static CColModel &ms_colModelPed1; - static CColModel &ms_colModelPed2; - static CColModel &ms_colModelBBox; - static CColModel &ms_colModelBumper1; - static CColModel &ms_colModelWheel1; - static CColModel &ms_colModelPanel1; - static CColModel &ms_colModelBodyPart2; - static CColModel &ms_colModelBodyPart1; - static CColModel &ms_colModelCutObj; - static CColModel &ms_colModelPedGroundHit; - static CColModel &ms_colModelBoot1; - static CColModel &ms_colModelDoor1; - static CColModel &ms_colModelBonnet1; -}; diff --git a/src/Text.cpp b/src/Text.cpp deleted file mode 100644 index d7d63467..00000000 --- a/src/Text.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" -#include "Frontend.h" -#include "Messages.h" -#include "Text.h" - -static wchar WideErrorString[25]; - -CText &TheText = *(CText*)0x941520; - -CText::CText(void) -{ - keyArray.entries = nil; - keyArray.numEntries = 0; - data.chars = nil; - data.numChars = 0; - encoding = 101; - memset(WideErrorString, 0, sizeof(WideErrorString)); -} - -CText::~CText(void) -{ - data.Unload(); - keyArray.Unload(); -} - -void -CText::Load(void) -{ - uint8 *filedata; - char filename[32], type[4]; - int length; - int offset, sectlen; - - Unload(); - filedata = new uint8[0x40000]; - - CFileMgr::SetDir("TEXT"); - switch(CMenuManager::m_PrefsLanguage){ - case LANGUAGE_AMERICAN: - sprintf(filename, "AMERICAN.GXT"); - break; - case LANGUAGE_FRENCH: - sprintf(filename, "FRENCH.GXT"); - break; - case LANGUAGE_GERMAN: - sprintf(filename, "GERMAN.GXT"); - break; - case LANGUAGE_ITALIAN: - sprintf(filename, "ITALIAN.GXT"); - break; - case LANGUAGE_SPANISH: - sprintf(filename, "SPANISH.GXT"); - break; - } - - length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb"); - CFileMgr::SetDir(""); - - offset = 0; - while(offset < length){ - type[0] = filedata[offset++]; - type[1] = filedata[offset++]; - type[2] = filedata[offset++]; - type[3] = filedata[offset++]; - sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 | - (int)filedata[offset+1]<<8 | (int)filedata[offset+0]; - offset += 4; - if(sectlen != 0){ - if(strncmp(type, "TKEY", 4) == 0) - keyArray.Load(sectlen, filedata, &offset); - else if(strncmp(type, "TDAT", 4) == 0) - data.Load(sectlen, filedata, &offset); - else - offset += sectlen; - } - } - - keyArray.Update(data.chars); - - delete[] filedata; -} - -void -CText::Unload(void) -{ - CMessages::ClearAllMessagesDisplayedByGame(); - data.Unload(); - keyArray.Unload(); -} - -wchar* -CText::Get(const char *key) -{ - return keyArray.Search(key); -} - -wchar -CText::GetUpperCase(wchar c) -{ - // TODO: do this depending on encoding - if(islower(c)) - return toupper(c); - return c; -} - -void -CText::UpperCase(wchar *s) -{ - while(*s){ - *s = GetUpperCase(*s); - s++; - } -} - - -void -CKeyArray::Load(uint32 length, uint8 *data, int *offset) -{ - uint32 i; - uint8 *rawbytes; - - numEntries = length / sizeof(CKeyEntry); - entries = new CKeyEntry[numEntries]; - rawbytes = (uint8*)entries; - - for(i = 0; i < length; i++) - rawbytes[i] = data[(*offset)++]; -} - -void -CKeyArray::Unload(void) -{ - delete[] entries; - entries = nil; - numEntries = 0; -} - -void -CKeyArray::Update(wchar *chars) -{ - int i; - for(i = 0; i < numEntries; i++) - entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value); -} - -CKeyEntry* -CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) -{ - int mid; - int diff; - - if(low > high) - return nil; - - mid = (low + high)/2; - diff = strcmp(key, entries[mid].key); - if(diff == 0) - return &entries[mid]; - if(diff < 0) - return BinarySearch(key, entries, low, mid-1); - if(diff > 0) - return BinarySearch(key, entries, mid+1, high); - return nil; -} - -wchar* -CKeyArray::Search(const char *key) -{ - CKeyEntry *found; - char errstr[25]; - int i; - - found = BinarySearch(key, entries, 0, numEntries-1); - if(found) - return found->value; - sprintf(errstr, "%s missing", key); - for(i = 0; i < 25; i++) - WideErrorString[i] = errstr[i]; - return WideErrorString; -} - - -void -CData::Load(uint32 length, uint8 *data, int *offset) -{ - uint32 i; - uint8 *rawbytes; - - numChars = length / sizeof(wchar); - chars = new wchar[numChars]; - rawbytes = (uint8*)chars; - - for(i = 0; i < length; i++) - rawbytes[i] = data[(*offset)++]; -} - -void -CData::Unload(void) -{ - delete[] chars; - chars = nil; - numChars = 0; -} - -void -AsciiToUnicode(const char *src, uint16 *dst) -{ - while((*dst++ = *src++) != '\0'); -} - -void -TextCopy(wchar *dst, const wchar *src) -{ - while((*dst++ = *src++) != '\0'); -} - -STARTPATCHES - InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP); - InjectHook(0x52C580, &CText::Unload, PATCH_JUMP); - InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP); - - InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP); - InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP); - InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP); - InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP); - InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP); - - InjectHook(0x52C120, &CData::Load, PATCH_JUMP); - InjectHook(0x52C200, &CData::Unload, PATCH_JUMP); -ENDPATCHES diff --git a/src/Text.h b/src/Text.h deleted file mode 100644 index 2592e6b8..00000000 --- a/src/Text.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -void AsciiToUnicode(const char *src, wchar *dst); -void TextCopy(wchar *dst, const wchar *src); - -struct CKeyEntry -{ - wchar *value; - char key[8]; -}; -// If this fails, CKeyArray::Load will have to be fixed -static_assert(sizeof(CKeyEntry) == 12, "CKeyEntry: error"); - -class CKeyArray -{ -public: - CKeyEntry *entries; - int numEntries; - - void Load(uint32 length, uint8 *data, int *offset); - void Unload(void); - void Update(wchar *chars); - CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high); - wchar *Search(const char *key); -}; - -class CData -{ -public: - wchar *chars; - int numChars; - - void Load(uint32 length, uint8 *data, int *offset); - void Unload(void); -}; - -class CText -{ - CKeyArray keyArray; - CData data; - int8 encoding; -public: - CText(void); - ~CText(void); - void Load(void); - void Unload(void); - wchar *Get(const char *key); - wchar GetUpperCase(wchar c); - void UpperCase(wchar *s); -}; - -extern CText &TheText; diff --git a/src/Timecycle.cpp b/src/Timecycle.cpp deleted file mode 100644 index c04295dd..00000000 --- a/src/Timecycle.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Clock.h" -#include "Weather.h" -#include "Camera.h" -#include "Shadows.h" -#include "CullZones.h" -#include "CutsceneMgr.h" -#include "FileMgr.h" -#include "Timecycle.h" - -int (*CTimeCycle::m_nAmbientRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86AF78; -int (*CTimeCycle::m_nAmbientGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x665308; -int (*CTimeCycle::m_nAmbientBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72CF88; -int (*CTimeCycle::m_nDirectionalRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FAB78; -int (*CTimeCycle::m_nDirectionalGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F4528; -int (*CTimeCycle::m_nDirectionalBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83CE58; -int (*CTimeCycle::m_nSkyTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FB90; -int (*CTimeCycle::m_nSkyTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x8460A8; -int (*CTimeCycle::m_nSkyTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87B158; -int (*CTimeCycle::m_nSkyBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FA960; -int (*CTimeCycle::m_nSkyBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70D6A8; -int (*CTimeCycle::m_nSkyBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83D288; -int (*CTimeCycle::m_nSunCoreRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x878360; -int (*CTimeCycle::m_nSunCoreGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE088; -int (*CTimeCycle::m_nSunCoreBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x773A68; -int (*CTimeCycle::m_nSunCoronaRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x664B60; -int (*CTimeCycle::m_nSunCoronaGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F01E0; -int (*CTimeCycle::m_nSunCoronaBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E6340; -float (*CTimeCycle::m_fSunSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733510; -float (*CTimeCycle::m_fSpriteSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87F820; -float (*CTimeCycle::m_fSpriteBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x6E96F0; -short (*CTimeCycle::m_nShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x83CFD8; -short (*CTimeCycle::m_nLightShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x72B0F8; -short (*CTimeCycle::m_nTreeShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x733450; -float (*CTimeCycle::m_fFogStart)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8806C8; -float (*CTimeCycle::m_fFarClip)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8804E0; -float (*CTimeCycle::m_fLightsOnGroundBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x83D108; -int (*CTimeCycle::m_nLowCloudsRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x726770; -int (*CTimeCycle::m_nLowCloudsGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87BF08; -int (*CTimeCycle::m_nLowCloudsBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FA10; -int (*CTimeCycle::m_nFluffyCloudsTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70F2B0; -int (*CTimeCycle::m_nFluffyCloudsTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72D288; -int (*CTimeCycle::m_nFluffyCloudsTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86B108; -int (*CTimeCycle::m_nFluffyCloudsBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E8DA8; -int (*CTimeCycle::m_nFluffyCloudsBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x715AA8; -int (*CTimeCycle::m_nFluffyCloudsBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE2D0; -float (*CTimeCycle::m_fBlurRed)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87C7E0; -float (*CTimeCycle::m_fBlurGreen)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x774C10; -float (*CTimeCycle::m_fBlurBlue)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8784E0; -float (*CTimeCycle::m_fBlurAlpha)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733690; - -float &CTimeCycle::m_fCurrentAmbientRed = *(float*)0x8F29B4; -float &CTimeCycle::m_fCurrentAmbientGreen = *(float*)0x94144C; -float &CTimeCycle::m_fCurrentAmbientBlue = *(float*)0x942FC0; -float &CTimeCycle::m_fCurrentDirectionalRed = *(float*)0x8F29D8; -float &CTimeCycle::m_fCurrentDirectionalGreen = *(float*)0x940594; -float &CTimeCycle::m_fCurrentDirectionalBlue = *(float*)0x942FAC; -int &CTimeCycle::m_nCurrentSkyTopRed = *(int*)0x9403C0; -int &CTimeCycle::m_nCurrentSkyTopGreen = *(int*)0x943074; -int &CTimeCycle::m_nCurrentSkyTopBlue = *(int*)0x8F29B8; -int &CTimeCycle::m_nCurrentSkyBottomRed = *(int*)0x9414D0; -int &CTimeCycle::m_nCurrentSkyBottomGreen = *(int*)0x8F2BD0; -int &CTimeCycle::m_nCurrentSkyBottomBlue = *(int*)0x8F625C; -int &CTimeCycle::m_nCurrentSunCoreRed = *(int*)0x8F2534; -int &CTimeCycle::m_nCurrentSunCoreGreen = *(int*)0x8F6264; -int &CTimeCycle::m_nCurrentSunCoreBlue = *(int*)0x94149C; -int &CTimeCycle::m_nCurrentSunCoronaRed = *(int*)0x8F2C1C; -int &CTimeCycle::m_nCurrentSunCoronaGreen = *(int*)0x885B54; -int &CTimeCycle::m_nCurrentSunCoronaBlue = *(int*)0x880F60; -float &CTimeCycle::m_fCurrentSunSize = *(float*)0x940588; -float &CTimeCycle::m_fCurrentSpriteSize = *(float*)0x8F1AA8; -float &CTimeCycle::m_fCurrentSpriteBrightness = *(float*)0x8F5FDC; -int &CTimeCycle::m_nCurrentShadowStrength = *(int*)0x95CC76; -int &CTimeCycle::m_nCurrentLightShadowStrength = *(int*)0x95CC66; -int &CTimeCycle::m_nCurrentTreeShadowStrength = *(int*)0x95CC86; -float &CTimeCycle::m_fCurrentFogStart = *(float*)0x8F1AE0; -float &CTimeCycle::m_fCurrentFarClip = *(float*)0x8F5FD8; -float &CTimeCycle::m_fCurrentLightsOnGroundBrightness = *(float*)0x8F1B60; -int &CTimeCycle::m_nCurrentLowCloudsRed = *(int*)0x95CB54; -int &CTimeCycle::m_nCurrentLowCloudsGreen = *(int*)0x95CB48; -int &CTimeCycle::m_nCurrentLowCloudsBlue = *(int*)0x95CC1C; -int &CTimeCycle::m_nCurrentFluffyCloudsTopRed = *(int*)0x8F2550; -int &CTimeCycle::m_nCurrentFluffyCloudsTopGreen = *(int*)0x8F59CC; -int &CTimeCycle::m_nCurrentFluffyCloudsTopBlue = *(int*)0x941434; -int &CTimeCycle::m_nCurrentFluffyCloudsBottomRed = *(int*)0x8F1A38; -int &CTimeCycle::m_nCurrentFluffyCloudsBottomGreen = *(int*)0x8E28B8; -int &CTimeCycle::m_nCurrentFluffyCloudsBottomBlue = *(int*)0x8F3960; -float &CTimeCycle::m_fCurrentBlurRed = *(float*)0x8F6000; -float &CTimeCycle::m_fCurrentBlurGreen = *(float*)0x9405A0; -float &CTimeCycle::m_fCurrentBlurBlue = *(float*)0x8F250C; -float &CTimeCycle::m_fCurrentBlurAlpha = *(float*)0x940728; -int &CTimeCycle::m_nCurrentFogColourRed = *(int*)0x940714; -int &CTimeCycle::m_nCurrentFogColourGreen = *(int*)0x8E2A60; -int &CTimeCycle::m_nCurrentFogColourBlue = *(int*)0x8F57EC; - -int &CTimeCycle::m_FogReduction = *(int*)0x880FB8; - -int &CTimeCycle::m_CurrentStoredValue = *(int*)0x94057C; -CVector *CTimeCycle::m_VectorToSun = (CVector*)0x665548; // [16] -float *CTimeCycle::m_fShadowFrontX = (float*)0x72CE90; -float *CTimeCycle::m_fShadowFrontY = (float*)0x72CE50; -float *CTimeCycle::m_fShadowSideX = (float*)0x87C708; -float *CTimeCycle::m_fShadowSideY = (float*)0x87C6C8; -float *CTimeCycle::m_fShadowDisplacementX = (float*)0x6F0748; -float *CTimeCycle::m_fShadowDisplacementY = (float*)0x6F0788; - - -void -CTimeCycle::Initialise(void) -{ - int w, h; - int li, bi; - char line[1040]; - - int ambR, ambG, ambB; - int dirR, dirG, dirB; - int skyTopR, skyTopG, skyTopB; - int skyBotR, skyBotG, skyBotB; - int sunCoreR, sunCoreG, sunCoreB; - int sunCoronaR, sunCoronaG, sunCoronaB; - float sunSz, sprSz, sprBght; - int shad, lightShad, treeShad; - float farClp, fogSt, lightGnd; - int cloudR, cloudG, cloudB; - int fluffyTopR, fluffyTopG, fluffyTopB; - int fluffyBotR, fluffyBotG, fluffyBotB; - float blurR, blurG, blurB, blurA; - - debug("Intialising CTimeCycle...\n"); - - CFileMgr::SetDir("DATA"); - CFileMgr::LoadFile("TIMECYC.DAT", work_buff, sizeof(work_buff), "rb"); - CFileMgr::SetDir(""); - - line[0] = '\0'; - bi = 0; - for(w = 0; w < NUMWEATHERS; w++) - for(h = 0; h < NUMHOURS; h++){ - li = 0; - while(work_buff[bi] == '/'){ - while(work_buff[bi] != '\n') - bi++; - bi++; - } - while(work_buff[bi] != '\n') - line[li++] = work_buff[bi++]; - line[li] = '\0'; - bi++; - - sscanf(line, "%d %d %d %d %d %d %d %d %d %d %d %d " - "%d %d %d %d %d %d %f %f %f %d %d %d %f %f %f " - "%d %d %d %d %d %d %d %d %d %f %f %f %f", - &ambR, &ambG, &ambB, - &dirR, &dirG, &dirB, - &skyTopR, &skyTopG, &skyTopB, - &skyBotR, &skyBotG, &skyBotB, - &sunCoreR, &sunCoreG, &sunCoreB, - &sunCoronaR, &sunCoronaG, &sunCoronaB, - &sunSz, &sprSz, &sprBght, - &shad, &lightShad, &treeShad, - &farClp, &fogSt, &lightGnd, - &cloudR, &cloudG, &cloudB, - &fluffyTopR, &fluffyTopG, &fluffyTopB, - &fluffyBotR, &fluffyBotG, &fluffyBotB, - &blurR, &blurG, &blurB, &blurA); - - m_nAmbientRed[h][w] = ambR; - m_nAmbientGreen[h][w] = ambG; - m_nAmbientBlue[h][w] = ambB; - m_nDirectionalRed[h][w] = dirR; - m_nDirectionalGreen[h][w] = dirG; - m_nDirectionalBlue[h][w] = dirB; - m_nSkyTopRed[h][w] = skyTopR; - m_nSkyTopGreen[h][w] = skyTopG; - m_nSkyTopBlue[h][w] = skyTopB; - m_nSkyBottomRed[h][w] = skyBotR; - m_nSkyBottomGreen[h][w] = skyBotG; - m_nSkyBottomBlue[h][w] = skyBotB; - m_nSunCoreRed[h][w] = sunCoreR; - m_nSunCoreGreen[h][w] = sunCoreG; - m_nSunCoreBlue[h][w] = sunCoreB; - m_nSunCoronaRed[h][w] = sunCoronaR; - m_nSunCoronaGreen[h][w] = sunCoronaG; - m_nSunCoronaBlue[h][w] = sunCoronaB; - m_fSunSize[h][w] = sunSz; - m_fSpriteSize[h][w] = sprSz; - m_fSpriteBrightness[h][w] = sprBght; - m_nShadowStrength[h][w] = shad; - m_nLightShadowStrength[h][w] = lightShad; - m_nTreeShadowStrength[h][w] = treeShad; - m_fFarClip[h][w] = farClp; - m_fFogStart[h][w] = fogSt; - m_fLightsOnGroundBrightness[h][w] = lightGnd; - m_nLowCloudsRed[h][w] = cloudR; - m_nLowCloudsGreen[h][w] = cloudG; - m_nLowCloudsBlue[h][w] = cloudB; - m_nFluffyCloudsTopRed[h][w] = fluffyTopR; - m_nFluffyCloudsTopGreen[h][w] = fluffyTopG; - m_nFluffyCloudsTopBlue[h][w] = fluffyTopB; - m_nFluffyCloudsBottomRed[h][w] = fluffyBotR; - m_nFluffyCloudsBottomGreen[h][w] = fluffyBotG; - m_nFluffyCloudsBottomBlue[h][w] = fluffyBotB; - m_fBlurRed[h][w] = blurR; - m_fBlurGreen[h][w] = blurG; - m_fBlurBlue[h][w] = blurB; - m_fBlurAlpha[h][w] = blurA; - } - - m_FogReduction = 0; - - debug("CTimeCycle ready\n"); -} - -void -CTimeCycle::Update(void) -{ - int h1 = CClock::GetHours(); - int h2 = (h1+1)%24; - int w1 = CWeather::OldWeatherType; - int w2 = CWeather::NewWeatherType; - float timeInterp = CClock::GetMinutes()/60.0f; - // coefficients for a bilinear interpolation - float c0 = (1.0f-timeInterp) * (1.0f-CWeather::InterpolationValue); - float c1 = timeInterp * (1.0f-CWeather::InterpolationValue); - float c2 = (1.0f-timeInterp) * CWeather::InterpolationValue; - float c3 = timeInterp * CWeather::InterpolationValue; - -#define INTERP(v) v[h1][w1]*c0 + v[h2][w1]*c1 + v[h1][w2]*c2 + v[h2][w2]*c3; - - m_nCurrentSkyTopRed = INTERP(m_nSkyTopRed); - m_nCurrentSkyTopGreen = INTERP(m_nSkyTopGreen); - m_nCurrentSkyTopBlue = INTERP(m_nSkyTopBlue); - - m_nCurrentSkyBottomRed = INTERP(m_nSkyBottomRed); - m_nCurrentSkyBottomGreen = INTERP(m_nSkyBottomGreen); - m_nCurrentSkyBottomBlue = INTERP(m_nSkyBottomBlue); - - m_fCurrentAmbientRed = INTERP(m_nAmbientRed); - m_fCurrentAmbientGreen = INTERP(m_nAmbientGreen); - m_fCurrentAmbientBlue = INTERP(m_nAmbientBlue); - m_fCurrentAmbientRed /= 255.0f; - m_fCurrentAmbientGreen /= 255.0f; - m_fCurrentAmbientBlue /= 255.0f; - - m_fCurrentDirectionalRed = INTERP(m_nDirectionalRed); - m_fCurrentDirectionalGreen = INTERP(m_nDirectionalGreen); - m_fCurrentDirectionalBlue = INTERP(m_nDirectionalBlue); - m_fCurrentDirectionalRed /= 255.0f; - m_fCurrentDirectionalGreen /= 255.0f; - m_fCurrentDirectionalBlue /= 255.0f; - - m_nCurrentSunCoreRed = INTERP(m_nSunCoreRed); - m_nCurrentSunCoreGreen = INTERP(m_nSunCoreGreen); - m_nCurrentSunCoreBlue = INTERP(m_nSunCoreBlue); - - m_nCurrentSunCoronaRed = INTERP(m_nSunCoronaRed); - m_nCurrentSunCoronaGreen = INTERP(m_nSunCoronaGreen); - m_nCurrentSunCoronaBlue = INTERP(m_nSunCoronaBlue); - - m_fCurrentSunSize = INTERP(m_fSunSize); - m_fCurrentSpriteSize = INTERP(m_fSpriteSize); - m_fCurrentSpriteBrightness = INTERP(m_fSpriteBrightness); - m_nCurrentShadowStrength = INTERP(m_nShadowStrength); - m_nCurrentLightShadowStrength = INTERP(m_nLightShadowStrength); - m_nCurrentTreeShadowStrength = INTERP(m_nTreeShadowStrength); - m_fCurrentFarClip = INTERP(m_fFarClip); - m_fCurrentFogStart = INTERP(m_fFogStart); - m_fCurrentLightsOnGroundBrightness = INTERP(m_fLightsOnGroundBrightness); - - m_nCurrentLowCloudsRed = INTERP(m_nLowCloudsRed); - m_nCurrentLowCloudsGreen = INTERP(m_nLowCloudsGreen); - m_nCurrentLowCloudsBlue = INTERP(m_nLowCloudsBlue); - - m_nCurrentFluffyCloudsTopRed = INTERP(m_nFluffyCloudsTopRed); - m_nCurrentFluffyCloudsTopGreen = INTERP(m_nFluffyCloudsTopGreen); - m_nCurrentFluffyCloudsTopBlue = INTERP(m_nFluffyCloudsTopBlue); - - m_nCurrentFluffyCloudsBottomRed = INTERP(m_nFluffyCloudsBottomRed); - m_nCurrentFluffyCloudsBottomGreen = INTERP(m_nFluffyCloudsBottomGreen); - m_nCurrentFluffyCloudsBottomBlue = INTERP(m_nFluffyCloudsBottomBlue); - - m_fCurrentBlurRed = INTERP(m_fBlurRed); - m_fCurrentBlurGreen = INTERP(m_fBlurGreen); - m_fCurrentBlurBlue = INTERP(m_fBlurBlue); - m_fCurrentBlurAlpha = INTERP(m_fBlurAlpha); - - if(TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) - TheCamera.SetMotionBlur(m_fCurrentBlurRed, m_fCurrentBlurGreen, m_fCurrentBlurBlue, m_fCurrentBlurAlpha, MBLUR_NORMAL); - - if(m_FogReduction != 0) - m_fCurrentFarClip = max(m_fCurrentFarClip, m_FogReduction/64.0f * 650.0f); - m_nCurrentFogColourRed = (m_nCurrentSkyTopRed + 2*m_nCurrentSkyBottomRed) / 3; - m_nCurrentFogColourGreen = (m_nCurrentSkyTopGreen + 2*m_nCurrentSkyBottomGreen) / 3; - m_nCurrentFogColourBlue = (m_nCurrentSkyTopBlue + 2*m_nCurrentSkyBottomBlue) / 3; - - m_CurrentStoredValue = (m_CurrentStoredValue+1)&0xF; - - float sunAngle = 2*PI*(CClock::GetMinutes() + CClock::GetHours()*60)/(24*60); - CVector &sunPos = GetSunPosition(); - sunPos.x = sinf(sunAngle); - sunPos.y = 1.0f; - sunPos.z = 0.2f - cosf(sunAngle); - sunPos.Normalise(); - - CShadows::CalcPedShadowValues(sunPos, - &m_fShadowFrontX[m_CurrentStoredValue], &m_fShadowFrontY[m_CurrentStoredValue], - &m_fShadowSideX[m_CurrentStoredValue], &m_fShadowSideY[m_CurrentStoredValue], - &m_fShadowDisplacementX[m_CurrentStoredValue], &m_fShadowDisplacementY[m_CurrentStoredValue]); - - if(TheCamera.GetForward().z < -0.9f || - !CWeather::bScriptsForceRain && (CCullZones::PlayerNoRain() || CCullZones::CamNoRain() || CCutsceneMgr::IsRunning())) - m_FogReduction = min(m_FogReduction+1, 64); - else - m_FogReduction = max(m_FogReduction-1, 0); -} - -STARTPATCHES - InjectHook(0x4ABAE0, CTimeCycle::Initialise, PATCH_JUMP); - InjectHook(0x4ABF40, CTimeCycle::Update, PATCH_JUMP); -ENDPATCHES diff --git a/src/Timecycle.h b/src/Timecycle.h deleted file mode 100644 index 71ddedb7..00000000 --- a/src/Timecycle.h +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -class CTimeCycle -{ - static int (*m_nAmbientRed)[NUMWEATHERS]; - static int (*m_nAmbientGreen)[NUMWEATHERS]; - static int (*m_nAmbientBlue)[NUMWEATHERS]; - static int (*m_nDirectionalRed)[NUMWEATHERS]; - static int (*m_nDirectionalGreen)[NUMWEATHERS]; - static int (*m_nDirectionalBlue)[NUMWEATHERS]; - static int (*m_nSkyTopRed)[NUMWEATHERS]; - static int (*m_nSkyTopGreen)[NUMWEATHERS]; - static int (*m_nSkyTopBlue)[NUMWEATHERS]; - static int (*m_nSkyBottomRed)[NUMWEATHERS]; - static int (*m_nSkyBottomGreen)[NUMWEATHERS]; - static int (*m_nSkyBottomBlue)[NUMWEATHERS]; - static int (*m_nSunCoreRed)[NUMWEATHERS]; - static int (*m_nSunCoreGreen)[NUMWEATHERS]; - static int (*m_nSunCoreBlue)[NUMWEATHERS]; - static int (*m_nSunCoronaRed)[NUMWEATHERS]; - static int (*m_nSunCoronaGreen)[NUMWEATHERS]; - static int (*m_nSunCoronaBlue)[NUMWEATHERS]; - static float (*m_fSunSize)[NUMWEATHERS]; - static float (*m_fSpriteSize)[NUMWEATHERS]; - static float (*m_fSpriteBrightness)[NUMWEATHERS]; - static short (*m_nShadowStrength)[NUMWEATHERS]; - static short (*m_nLightShadowStrength)[NUMWEATHERS]; - static short (*m_nTreeShadowStrength)[NUMWEATHERS]; - static float (*m_fFogStart)[NUMWEATHERS]; - static float (*m_fFarClip)[NUMWEATHERS]; - static float (*m_fLightsOnGroundBrightness)[NUMWEATHERS]; - static int (*m_nLowCloudsRed)[NUMWEATHERS]; - static int (*m_nLowCloudsGreen)[NUMWEATHERS]; - static int (*m_nLowCloudsBlue)[NUMWEATHERS]; - static int (*m_nFluffyCloudsTopRed)[NUMWEATHERS]; - static int (*m_nFluffyCloudsTopGreen)[NUMWEATHERS]; - static int (*m_nFluffyCloudsTopBlue)[NUMWEATHERS]; - static int (*m_nFluffyCloudsBottomRed)[NUMWEATHERS]; - static int (*m_nFluffyCloudsBottomGreen)[NUMWEATHERS]; - static int (*m_nFluffyCloudsBottomBlue)[NUMWEATHERS]; - static float (*m_fBlurRed)[NUMWEATHERS]; - static float (*m_fBlurGreen)[NUMWEATHERS]; - static float (*m_fBlurBlue)[NUMWEATHERS]; - static float (*m_fBlurAlpha)[NUMWEATHERS]; - - static float &m_fCurrentAmbientRed; - static float &m_fCurrentAmbientGreen; - static float &m_fCurrentAmbientBlue; - static float &m_fCurrentDirectionalRed; - static float &m_fCurrentDirectionalGreen; - static float &m_fCurrentDirectionalBlue; - static int &m_nCurrentSkyTopRed; - static int &m_nCurrentSkyTopGreen; - static int &m_nCurrentSkyTopBlue; - static int &m_nCurrentSkyBottomRed; - static int &m_nCurrentSkyBottomGreen; - static int &m_nCurrentSkyBottomBlue; - static int &m_nCurrentSunCoreRed; - static int &m_nCurrentSunCoreGreen; - static int &m_nCurrentSunCoreBlue; - static int &m_nCurrentSunCoronaRed; - static int &m_nCurrentSunCoronaGreen; - static int &m_nCurrentSunCoronaBlue; - static float &m_fCurrentSunSize; - static float &m_fCurrentSpriteSize; - static float &m_fCurrentSpriteBrightness; - static int &m_nCurrentShadowStrength; - static int &m_nCurrentLightShadowStrength; - static int &m_nCurrentTreeShadowStrength; - static float &m_fCurrentFogStart; - static float &m_fCurrentFarClip; - static float &m_fCurrentLightsOnGroundBrightness; - static int &m_nCurrentLowCloudsRed; - static int &m_nCurrentLowCloudsGreen; - static int &m_nCurrentLowCloudsBlue; - static int &m_nCurrentFluffyCloudsTopRed; - static int &m_nCurrentFluffyCloudsTopGreen; - static int &m_nCurrentFluffyCloudsTopBlue; - static int &m_nCurrentFluffyCloudsBottomRed; - static int &m_nCurrentFluffyCloudsBottomGreen; - static int &m_nCurrentFluffyCloudsBottomBlue; - static float &m_fCurrentBlurRed; - static float &m_fCurrentBlurGreen; - static float &m_fCurrentBlurBlue; - static float &m_fCurrentBlurAlpha; - static int &m_nCurrentFogColourRed; - static int &m_nCurrentFogColourGreen; - static int &m_nCurrentFogColourBlue; - - static int &m_FogReduction; - -public: - static int &m_CurrentStoredValue; - static CVector *m_VectorToSun; // [16] - static float *m_fShadowFrontX; // [16] - static float *m_fShadowFrontY; // [16] - static float *m_fShadowSideX; // [16] - static float *m_fShadowSideY; // [16] - static float *m_fShadowDisplacementX; // [16] - static float *m_fShadowDisplacementY; // [16] - - static float GetAmbientRed(void) { return m_fCurrentAmbientRed; } - static float GetAmbientGreen(void) { return m_fCurrentAmbientGreen; } - static float GetAmbientBlue(void) { return m_fCurrentAmbientBlue; } - static float GetDirectionalRed(void) { return m_fCurrentDirectionalRed; } - static float GetDirectionalGreen(void) { return m_fCurrentDirectionalGreen; } - static float GetDirectionalBlue(void) { return m_fCurrentDirectionalBlue; } - static int GetSkyTopRed(void) { return m_nCurrentSkyTopRed; } - static int GetSkyTopGreen(void) { return m_nCurrentSkyTopGreen; } - static int GetSkyTopBlue(void) { return m_nCurrentSkyTopBlue; } - static int GetSkyBottomRed(void) { return m_nCurrentSkyBottomRed; } - static int GetSkyBottomGreen(void) { return m_nCurrentSkyBottomGreen; } - static int GetSkyBottomBlue(void) { return m_nCurrentSkyBottomBlue; } - static int GetSunCoreRed(void) { return m_nCurrentSunCoreRed; } - static int GetSunCoreGreen(void) { return m_nCurrentSunCoreGreen; } - static int GetSunCoreBlue(void) { return m_nCurrentSunCoreBlue; } - static int GetSunCoronaRed(void) { return m_nCurrentSunCoronaRed; } - static int GetSunCoronaGreen(void) { return m_nCurrentSunCoronaGreen; } - static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; } - static float GetSunSize(void) { return m_fCurrentSunSize; } - static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; } - static float GetFarClip(void) { return m_fCurrentFarClip; } - static float GetFogStart(void) { return m_fCurrentFogStart; } - - static int GetLowCloudsRed(void) { return m_nCurrentLowCloudsRed; } - static int GetLowCloudsGreen(void) { return m_nCurrentLowCloudsGreen; } - static int GetLowCloudsBlue(void) { return m_nCurrentLowCloudsBlue; } - static int GetFluffyCloudsTopRed(void) { return m_nCurrentFluffyCloudsTopRed; } - static int GetFluffyCloudsTopGreen(void) { return m_nCurrentFluffyCloudsTopGreen; } - static int GetFluffyCloudsTopBlue(void) { return m_nCurrentFluffyCloudsTopBlue; } - static int GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; } - static int GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; } - static int GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; } - static int GetFogRed(void) { return m_nCurrentFogColourRed; } - static int GetFogGreen(void) { return m_nCurrentFogColourGreen; } - static int GetFogBlue(void) { return m_nCurrentFogColourBlue; } - - static void Initialise(void); - static void Update(void); - static CVector &GetSunPosition(void) { return m_VectorToSun[m_CurrentStoredValue]; } -}; diff --git a/src/Timer.cpp b/src/Timer.cpp deleted file mode 100644 index 543f582b..00000000 --- a/src/Timer.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include -#include "common.h" -#include "patcher.h" -#include "DMAudio.h" -#include "Record.h" -#include "Timer.h" - -uint32 &CTimer::m_snTimeInMilliseconds = *(uint32*)0x885B48; -uint32 &CTimer::m_snTimeInMillisecondsPauseMode = *(uint32*)0x5F7614; -uint32 &CTimer::m_snTimeInMillisecondsNonClipped = *(uint32*)0x9412E8; -uint32 &CTimer::m_snPreviousTimeInMilliseconds = *(uint32*)0x8F29E4; -uint32 &CTimer::m_FrameCounter = *(uint32*)0x9412EC; -float &CTimer::ms_fTimeScale = *(float*)0x8F2C20; -float &CTimer::ms_fTimeStep = *(float*)0x8E2CB4; -float &CTimer::ms_fTimeStepNonClipped = *(float*)0x8E2C4C; -bool &CTimer::m_UserPause = *(bool*)0x95CD7C; -bool &CTimer::m_CodePause = *(bool*)0x95CDB1; - -//UInt32 oldPcTimer; -uint32 &oldPcTimer = *(uint32*)0x9434F4; - -//UInt32 suspendPcTimer; -uint32 &suspendPcTimer = *(uint32*)0x62A308; - -//UInt32 _nCyclesPerMS = 1; -uint32 &_nCyclesPerMS = *(uint32*)0x5F7610; - -//LARGE_INTEGER _oldPerfCounter; -LARGE_INTEGER &_oldPerfCounter = *(LARGE_INTEGER*)0x62A310; - -//LARGE_INTEGER perfSuspendCounter; -LARGE_INTEGER &perfSuspendCounter = *(LARGE_INTEGER*)0x62A318; - -//UInt32 suspendDepth; -uint32 &suspendDepth = *(uint32*)0x62A320; - -void CTimer::Initialise(void) -{ - debug("Initialising CTimer...\n"); - - ms_fTimeScale = 1.0f; - ms_fTimeStep = 1.0f; - suspendDepth = 0; - m_UserPause = false; - m_CodePause = false; - m_snTimeInMillisecondsNonClipped = 0; - m_snPreviousTimeInMilliseconds = 0; - m_snTimeInMilliseconds = 1; - - LARGE_INTEGER perfFreq; - if ( QueryPerformanceFrequency(&perfFreq) ) - { - OutputDebugString("Performance counter available\n"); - _nCyclesPerMS = uint32(perfFreq.QuadPart / 1000); - QueryPerformanceCounter(&_oldPerfCounter); - } - else - { - OutputDebugString("Performance counter not available, using millesecond timer\n"); - _nCyclesPerMS = 0; - oldPcTimer = RsTimer(); - } - - m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds; - - m_FrameCounter = 0; - - DMAudio.ResetTimers(m_snPreviousTimeInMilliseconds); - - debug("CTimer ready\n"); -} - -void CTimer::Shutdown(void) -{ - ; -} - -#if 1 -WRAPPER void CTimer::Update(void) { EAXJMP(0x4ACF70); } -#else -void CTimer::Update(void) -{ - m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; - - if ( (double)_nCyclesPerMS != 0.0 ) - { - LARGE_INTEGER pc; - QueryPerformanceCounter(&pc); - - int32 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; - - _oldPerfCounter = pc; - - double updInCyclesScaled = (double)updInCycles * ms_fTimeScale; - - double upd = updInCyclesScaled / (double)_nCyclesPerMS; - - m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd); - - if ( GetIsPaused() ) - ms_fTimeStep = 0.0f; - else - { - m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd); - m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd); - ms_fTimeStep = updInCyclesScaled / (double)_nCyclesPerMS / 20.0; - } - } - else - { - uint32 timer = RsTimer(); - - uint32 updInMs = timer - oldPcTimer; - - double upd = (double)updInMs * ms_fTimeScale; - - oldPcTimer = timer; - - m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd); - - if ( GetIsPaused() ) - ms_fTimeStep = 0.0f; - else - { - m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd); - m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd); - ms_fTimeStep = upd / 1000.0f * 50.0f; - } - } - - if ( ms_fTimeStep < 0.01f && !GetIsPaused() ) - ms_fTimeStep = 0.01f; - - ms_fTimeStepNonClipped = ms_fTimeStep; - - if ( CRecordDataForGame::RecordingState != RECORDSTATE_2 ) - { - ms_fTimeStep = min(3.0f, ms_fTimeStep); - - if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 ) - m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60; - } - - if ( CRecordDataForChase::Status == RECORDSTATE_1 ) - { - ms_fTimeStep = 1.0f; - m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16; - } - - m_FrameCounter++; -} -#endif - -void CTimer::Suspend(void) -{ - if ( ++suspendDepth > 1 ) - return; - - if ( (double)_nCyclesPerMS != 0.0 ) - QueryPerformanceCounter(&perfSuspendCounter); - else - suspendPcTimer = RsTimer(); -} - -void CTimer::Resume(void) -{ - if ( --suspendDepth != 0 ) - return; - - if ( (double)_nCyclesPerMS != 0.0 ) - { - LARGE_INTEGER pc; - QueryPerformanceCounter(&pc); - - _oldPerfCounter.LowPart += pc.LowPart - perfSuspendCounter.LowPart; - } - else - oldPcTimer += RsTimer() - suspendPcTimer; -} - -uint32 CTimer::GetCyclesPerMillisecond(void) -{ - if (_nCyclesPerMS != 0) - return _nCyclesPerMS; - else - return 1; -} - -uint32 CTimer::GetCurrentTimeInCycles(void) -{ - if ( _nCyclesPerMS != 0 ) - { - LARGE_INTEGER pc; - QueryPerformanceCounter(&pc); - return (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; - } - else - return RsTimer() - oldPcTimer; -} - -bool CTimer::GetIsSlowMotionActive(void) -{ - return ms_fTimeScale < 1.0f; -} - -void CTimer::Stop(void) -{ - m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; -} - -void CTimer::StartUserPause(void) -{ - m_UserPause = true; -} - -void CTimer::EndUserPause(void) -{ - m_UserPause = false; -} - -#if 0 -STARTPATCHES - InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP); - InjectHook(0x4ACF60, CTimer::Shutdown, PATCH_JUMP); - InjectHook(0x4ACF70, CTimer::Update, PATCH_JUMP); - InjectHook(0x4AD310, CTimer::Suspend, PATCH_JUMP); - InjectHook(0x4AD370, CTimer::Resume, PATCH_JUMP); - InjectHook(0x4AD3F0, CTimer::GetCyclesPerMillisecond, PATCH_JUMP); - InjectHook(0x4AD410, CTimer::GetCurrentTimeInCycles, PATCH_JUMP); - InjectHook(0x4AD450, CTimer::GetIsSlowMotionActive, PATCH_JUMP); - InjectHook(0x4AD480, CTimer::Stop, PATCH_JUMP); - InjectHook(0x4AD490, CTimer::StartUserPause, PATCH_JUMP); - InjectHook(0x4AD4A0, CTimer::EndUserPause, PATCH_JUMP); -ENDPATCHES -#endif diff --git a/src/Timer.h b/src/Timer.h deleted file mode 100644 index 9e6d447e..00000000 --- a/src/Timer.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -class CTimer -{ - static uint32 &m_snTimeInMilliseconds; - static uint32 &m_snTimeInMillisecondsPauseMode; - static uint32 &m_snTimeInMillisecondsNonClipped; - static uint32 &m_snPreviousTimeInMilliseconds; - static uint32 &m_FrameCounter; - static float &ms_fTimeScale; - static float &ms_fTimeStep; - static float &ms_fTimeStepNonClipped; - static bool &m_UserPause; - static bool &m_CodePause; -public: - static float GetTimeStep(void) { return ms_fTimeStep; } - static void SetTimeStep(float ts) { ms_fTimeStep = ts; } - static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; } - static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; } - static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; } - static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; } - static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; } - static uint32 GetFrameCounter(void) { return m_FrameCounter; } - static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; } - static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } - static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; } - static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; } - static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; } - static uint32 GetTimeInMillisecondsPauseMode(void) { return m_snTimeInMillisecondsPauseMode; } - static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; } - static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; } - static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; } - static float GetTimeScale(void) { return ms_fTimeScale; } - static void SetTimeScale(float ts) { ms_fTimeScale = ts; } - - static bool GetIsPaused() { return m_UserPause || m_CodePause; } - static bool GetIsUserPaused() { return m_UserPause; } - static void SetCodePause(bool pause) { m_CodePause = pause; } - - static void Initialise(void); - static void Shutdown(void); - static void Update(void); - static void Suspend(void); - static void Resume(void); - static uint32 GetCyclesPerMillisecond(void); - static uint32 GetCurrentTimeInCycles(void); - static bool GetIsSlowMotionActive(void); - static void Stop(void); - static void StartUserPause(void); - static void EndUserPause(void); -}; diff --git a/src/TxdStore.cpp b/src/TxdStore.cpp deleted file mode 100644 index 5085c7e4..00000000 --- a/src/TxdStore.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "templates.h" -#include "Streaming.h" -#include "RwHelper.h" -#include "TxdStore.h" - -CPool *&CTxdStore::ms_pTxdPool = *(CPool**)0x8F5FB8; -RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC; - -void -CTxdStore::Initialize(void) -{ - if(ms_pTxdPool == nil) - ms_pTxdPool = new CPool(TXDSTORESIZE); -} - -void -CTxdStore::Shutdown(void) -{ - if(ms_pTxdPool) - delete ms_pTxdPool; -} - -void -CTxdStore::GameShutdown(void) -{ - int i; - - for(i = 0; i < TXDSTORESIZE; i++){ - TxdDef *def = GetSlot(i); - if(def && GetNumRefs(i) == 0) - RemoveTxdSlot(i); - } -} - -int -CTxdStore::AddTxdSlot(const char *name) -{ - TxdDef *def = ms_pTxdPool->New(); - assert(def); - def->texDict = nil; - def->refCount = 0; - strcpy(def->name, name); - return ms_pTxdPool->GetJustIndex(def); -} - -void -CTxdStore::RemoveTxdSlot(int slot) -{ - TxdDef *def = GetSlot(slot); - if(def->texDict) - RwTexDictionaryDestroy(def->texDict); - ms_pTxdPool->Delete(def); -} - -int -CTxdStore::FindTxdSlot(const char *name) -{ - char *defname; - int size = ms_pTxdPool->GetSize(); - for(int i = 0; i < size; i++){ - defname = GetTxdName(i); - if(defname && _strcmpi(defname, name) == 0) - return i; - } - return -1; -} - -char* -CTxdStore::GetTxdName(int slot) -{ - TxdDef *def = GetSlot(slot); - return def ? def->name : nil; -} - -void -CTxdStore::PushCurrentTxd(void) -{ - ms_pStoredTxd = RwTexDictionaryGetCurrent(); -} - -void -CTxdStore::PopCurrentTxd(void) -{ - RwTexDictionarySetCurrent(ms_pStoredTxd); - ms_pStoredTxd = nil; -} - -void -CTxdStore::SetCurrentTxd(int slot) -{ - TxdDef *def = GetSlot(slot); - if(def) - RwTexDictionarySetCurrent(def->texDict); -} - -void -CTxdStore::Create(int slot) -{ - GetSlot(slot)->texDict = RwTexDictionaryCreate(); -} - -int -CTxdStore::GetNumRefs(int slot) -{ - return GetSlot(slot)->refCount; -} - -void -CTxdStore::AddRef(int slot) -{ - GetSlot(slot)->refCount++; -} - -void -CTxdStore::RemoveRef(int slot) -{ - if(--GetSlot(slot)->refCount <= 0) - CStreaming::RemoveModel(slot + STREAM_OFFSET_TXD); -} - -void -CTxdStore::RemoveRefWithoutDelete(int slot) -{ - GetSlot(slot)->refCount--; -} - -bool -CTxdStore::LoadTxd(int slot, RwStream *stream) -{ - TxdDef *def = GetSlot(slot); - - if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){ - def->texDict = RwTexDictionaryGtaStreamRead(stream); - return def->texDict != nil; - } - printf("Failed to load TXD\n"); - return false; -} - -bool -CTxdStore::LoadTxd(int slot, const char *filename) -{ - RwStream *stream; - bool ret; - - ret = false; - _rwD3D8TexDictionaryEnableRasterFormatConversion(true); - do - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); - while(stream == nil); - ret = LoadTxd(slot, stream); - RwStreamClose(stream, nil); - return ret; -} - -bool -CTxdStore::StartLoadTxd(int slot, RwStream *stream) -{ - TxdDef *def = GetSlot(slot); - if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){ - def->texDict = RwTexDictionaryGtaStreamRead1(stream); - return def->texDict != nil; - }else{ - printf("Failed to load TXD\n"); - return false; - } -} - -bool -CTxdStore::FinishLoadTxd(int slot, RwStream *stream) -{ - TxdDef *def = GetSlot(slot); - def->texDict = RwTexDictionaryGtaStreamRead2(stream, def->texDict); - return def->texDict != nil; -} - -void -CTxdStore::RemoveTxd(int slot) -{ - TxdDef *def = GetSlot(slot); - if(def->texDict) - RwTexDictionaryDestroy(def->texDict); - def->texDict = nil; -} - -STARTPATCHES - InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP); - InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP); - InjectHook(0x527490, CTxdStore::GameShutdown, PATCH_JUMP); - InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP); - InjectHook(0x5275D0, CTxdStore::FindTxdSlot, PATCH_JUMP); - InjectHook(0x527590, CTxdStore::GetTxdName, PATCH_JUMP); - InjectHook(0x527900, CTxdStore::PushCurrentTxd, PATCH_JUMP); - InjectHook(0x527910, CTxdStore::PopCurrentTxd, PATCH_JUMP); - InjectHook(0x5278C0, CTxdStore::SetCurrentTxd, PATCH_JUMP); - InjectHook(0x527830, CTxdStore::Create, PATCH_JUMP); - InjectHook(0x527A00, CTxdStore::GetNumRefs, PATCH_JUMP); - InjectHook(0x527930, CTxdStore::AddRef, PATCH_JUMP); - InjectHook(0x527970, CTxdStore::RemoveRef, PATCH_JUMP); - InjectHook(0x5279C0, CTxdStore::RemoveRefWithoutDelete, PATCH_JUMP); - InjectHook(0x527700, (bool (*)(int, RwStream*))CTxdStore::LoadTxd, PATCH_JUMP); - InjectHook(0x5276B0, (bool (*)(int, const char*))CTxdStore::LoadTxd, PATCH_JUMP); - InjectHook(0x527770, CTxdStore::StartLoadTxd, PATCH_JUMP); - InjectHook(0x5277E0, CTxdStore::FinishLoadTxd, PATCH_JUMP); - InjectHook(0x527870, CTxdStore::RemoveTxd, PATCH_JUMP); -ENDPATCHES diff --git a/src/TxdStore.h b/src/TxdStore.h deleted file mode 100644 index a9e57d31..00000000 --- a/src/TxdStore.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "templates.h" - -struct TxdDef { - RwTexDictionary *texDict; - int refCount; - char name[20]; -}; - -class CTxdStore -{ - static CPool *&ms_pTxdPool; - static RwTexDictionary *&ms_pStoredTxd; -public: - static void Initialize(void); - static void Shutdown(void); - static void GameShutdown(void); - static int AddTxdSlot(const char *name); - static void RemoveTxdSlot(int slot); - static int FindTxdSlot(const char *name); - static char *GetTxdName(int slot); - static void PushCurrentTxd(void); - static void PopCurrentTxd(void); - static void SetCurrentTxd(int slot); - static void Create(int slot); - static int GetNumRefs(int slot); - static void AddRef(int slot); - static void RemoveRef(int slot); - static void RemoveRefWithoutDelete(int slot); - static bool LoadTxd(int slot, RwStream *stream); - static bool LoadTxd(int slot, const char *filename); - static bool StartLoadTxd(int slot, RwStream *stream); - static bool FinishLoadTxd(int slot, RwStream *stream); - static void RemoveTxd(int slot); - - static TxdDef *GetSlot(int slot) { - assert(slot >= 0); - assert(ms_pTxdPool); - assert(slot < ms_pTxdPool->GetSize()); - return ms_pTxdPool->GetSlot(slot); - } - static bool isTxdLoaded(int slot); -}; diff --git a/src/User.cpp b/src/User.cpp deleted file mode 100644 index c9cb97cc..00000000 --- a/src/User.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "common.h" -#include "patcher.h" - -#include "DMAudio.h" -#include "Hud.h" -#include "Replay.h" -#include "Timer.h" -#include "Script.h" -#include "User.h" - -CPlaceName& CUserDisplay::PlaceName = *(CPlaceName*)0x8F29BC; -COnscreenTimer& CUserDisplay::OnscnTimer = *(COnscreenTimer*)0x862238; -CPager& CUserDisplay::Pager = *(CPager*)0x8F2744; -CCurrentVehicle& CUserDisplay::CurrentVehicle = *(CCurrentVehicle*)0x8F5FE8; - -void COnscreenTimer::Init() { - m_bDisabled = false; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - m_sEntries[i].m_nTimerOffset = 0; - m_sEntries[i].m_nCounterOffset = 0; - - for(uint32 j = 0; j < 10; j++) { - m_sEntries[i].m_aTimerText[j] = 0; - m_sEntries[i].m_aCounterText[j] = 0; - } - - m_sEntries[i].m_nType = 0; - m_sEntries[i].m_bTimerProcessed = 0; - m_sEntries[i].m_bCounterProcessed = 0; - } -} - -void COnscreenTimer::Process() { - if(!CReplay::IsPlayingBack() && !m_bDisabled) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - m_sEntries[i].Process(); - } - } -} - -void COnscreenTimer::ProcessForDisplay() { - if(CHud::m_Wants_To_Draw_Hud) { - m_bProcessed = false; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(m_sEntries[i].ProcessForDisplay()) { - m_bProcessed = true; - } - } - } -} - -void COnscreenTimer::ClearCounter(uint32 offset) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(offset == m_sEntries[i].m_nCounterOffset) { - m_sEntries[i].m_nCounterOffset = 0; - m_sEntries[i].m_aCounterText[0] = 0; - m_sEntries[i].m_nType = 0; - m_sEntries[i].m_bCounterProcessed = 0; - } - } -} - -void COnscreenTimer::ClearClock(uint32 offset) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(offset == m_sEntries[i].m_nTimerOffset) { - m_sEntries[i].m_nTimerOffset = 0; - m_sEntries[i].m_aTimerText[0] = 0; - m_sEntries[i].m_bTimerProcessed = 0; - } - } -} - -void COnscreenTimer::AddCounter(uint32 offset, uint16 type, char* text) { - uint32 i = 0; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(m_sEntries[i].m_nCounterOffset == 0) { - break; - } - return; - } - - m_sEntries[i].m_nCounterOffset = offset; - if(text) { - strncpy(m_sEntries[i].m_aCounterText, text, 10); - } else { - m_sEntries[i].m_aCounterText[0] = 0; - } - - m_sEntries[i].m_nType = type; -} - -void COnscreenTimer::AddClock(uint32 offset, char* text) { - uint32 i = 0; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(m_sEntries[i].m_nTimerOffset == 0) { - break; - } - return; - } - - m_sEntries[i].m_nTimerOffset = offset; - if(text) { - strncpy(m_sEntries[i].m_aTimerText, text, 10); - } else { - m_sEntries[i].m_aTimerText[0] = 0; - } -} - -void COnscreenTimerEntry::Process() { - if(m_nTimerOffset == 0) { - return; - } - - uint32* timerPtr = (uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset]; - uint32 oldTime = *timerPtr; - int32 newTime = int32(oldTime - uint32(20.0f * CTimer::GetTimeStep())); - if(newTime < 0) { - *timerPtr = 0; - m_bTimerProcessed = 0; - m_nTimerOffset = 0; - m_aTimerText[0] = 0; - } else { - *timerPtr = (uint32)newTime; - uint32 oldTimeSeconds = oldTime / 1000; - if(oldTimeSeconds <= 11 && newTime / 1000 != oldTimeSeconds) { - // TODO: use an enum here - DMAudio.PlayFrontEndSound(0x93, newTime / 1000); - } - } -} - -bool COnscreenTimerEntry::ProcessForDisplay() { - m_bTimerProcessed = false; - m_bCounterProcessed = false; - - if(m_nTimerOffset == 0 && m_nCounterOffset == 0) { - return false; - } - - if(m_nTimerOffset != 0) { - m_bTimerProcessed = true; - ProcessForDisplayTimer(); - } - - if(m_nCounterOffset != 0) { - m_bCounterProcessed = true; - ProcessForDisplayCounter(); - } - return true; -} - -int COnscreenTimerEntry::ProcessForDisplayTimer() { - uint32 time = *(uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset]; - return sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60, - time / 1000 % 60); -} - -int COnscreenTimerEntry::ProcessForDisplayCounter() { - uint32 counter = *(uint32*)&CTheScripts::ScriptSpace[m_nCounterOffset]; - return sprintf(m_bCounterBuffer, "%d", counter); -} - -STARTPATCHES - InjectHook(0x429160, &COnscreenTimerEntry::Process, PATCH_JUMP); - InjectHook(0x429110, &COnscreenTimerEntry::ProcessForDisplay, PATCH_JUMP); - InjectHook(0x429080, &COnscreenTimerEntry::ProcessForDisplayTimer, PATCH_JUMP); - InjectHook(0x4290F0, &COnscreenTimerEntry::ProcessForDisplayCounter, PATCH_JUMP); - - InjectHook(0x429220, &COnscreenTimer::Init, PATCH_JUMP); - InjectHook(0x429320, &COnscreenTimer::Process, PATCH_JUMP); - InjectHook(0x4292E0, &COnscreenTimer::ProcessForDisplay, PATCH_JUMP); - InjectHook(0x429450, &COnscreenTimer::ClearCounter, PATCH_JUMP); - InjectHook(0x429410, &COnscreenTimer::ClearClock, PATCH_JUMP); - InjectHook(0x4293B0, &COnscreenTimer::AddCounter, PATCH_JUMP); - InjectHook(0x429350, &COnscreenTimer::AddClock, PATCH_JUMP); -ENDPATCHES diff --git a/src/User.h b/src/User.h deleted file mode 100644 index 8b744c7e..00000000 --- a/src/User.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -class COnscreenTimerEntry -{ -public: - uint32 m_nTimerOffset; - uint32 m_nCounterOffset; - char m_aTimerText[10]; - char m_aCounterText[10]; - uint16 m_nType; - char m_bCounterBuffer[42]; - char m_bTimerBuffer[42]; - bool m_bTimerProcessed; - bool m_bCounterProcessed; - - void Process(); - bool ProcessForDisplay(); - - int ProcessForDisplayTimer(); - int ProcessForDisplayCounter(); -}; - -static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error"); - -class COnscreenTimer -{ -public: - COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES]; - bool m_bProcessed; - bool m_bDisabled; - - void Init(); - void Process(); - void ProcessForDisplay(); - - void ClearCounter(uint32 offset); - void ClearClock(uint32 offset); - - void AddCounter(uint32 offset, uint16 type, char* text); - void AddClock(uint32 offset, char* text); -}; - -static_assert(sizeof(COnscreenTimer) == 0x78, "COnscreenTimer: error"); - -class CPlaceName -{ -}; - -class CCurrentVehicle -{ -}; - -class CPager -{ -}; - -class CUserDisplay -{ -public: - static CPlaceName &PlaceName; - static COnscreenTimer &OnscnTimer; - static CPager &Pager; - static CCurrentVehicle &CurrentVehicle; -}; diff --git a/src/Wanted.cpp b/src/Wanted.cpp deleted file mode 100644 index ece68e64..00000000 --- a/src/Wanted.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Wanted.h" - -bool CWanted::AreSwatRequired() -{ - return m_nWantedLevel >= 4; -} - -bool CWanted::AreFbiRequired() -{ - return m_nWantedLevel >= 5; -} - -bool CWanted::AreArmyRequired() -{ - return m_nWantedLevel >= 6; -} - -int CWanted::NumOfHelisRequired() -{ - if (m_IsIgnoredByCops) - return 0; - - // Return value is number of helicopters, no need to name them. - switch (m_nWantedLevel) { - case WANTEDLEVEL_3: - case WANTEDLEVEL_4: - return 1; - case WANTEDLEVEL_5: - case WANTEDLEVEL_6: - return 2; - default: - return 0; - }; -} \ No newline at end of file diff --git a/src/Wanted.h b/src/Wanted.h deleted file mode 100644 index aafa9ac0..00000000 --- a/src/Wanted.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once -#include "Entity.h" -#include "math/Vector.h" -#include "CopPed.h" - -enum eWantedLevel { - NOTWANTED, - WANTEDLEVEL_1, - WANTEDLEVEL_2, - WANTEDLEVEL_3, - WANTEDLEVEL_4, - WANTEDLEVEL_5, - WANTEDLEVEL_6, -}; - -class CWanted -{ -public: - int32 m_nChaos; - int32 m_nLastUpdateTime; - int32 m_nLastWantedLevelChange; - float m_fCrimeSensitivity; - uint8 m_bCurrentCops; - uint8 m_bMaxCops; - uint8 m_bMaximumLawEnforcerVehicles; - int8 field_19; - int16 m_wRoadblockDensity; - uint8 m_IsIgnoredByCops : 1; - uint8 m_IsIgnoredByEveryOne : 1; - uint8 m_IsSwatRequired : 1; - uint8 m_IsFbiRequired : 1; - uint8 m_IdArmyRequired : 1; - int8 field_23; - int32 m_nWantedLevel; - CCrime m_sCrimes[16]; - CCopPed *m_pCops[10]; - -public: - bool AreSwatRequired(); - bool AreFbiRequired(); - bool AreArmyRequired(); - int NumOfHelisRequired(); -}; - -static_assert(sizeof(CWanted) == 0x204, "CWanted: error"); diff --git a/src/Weather.cpp b/src/Weather.cpp deleted file mode 100644 index 460deeac..00000000 --- a/src/Weather.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Weather.h" - -int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4; - -int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C; -int16 &CWeather::OldWeatherType = *(int16*)0x95CCEC; -int16 &CWeather::NewWeatherType = *(int16*)0x95CC70; -int16 &CWeather::ForcedWeatherType = *(int16*)0x95CC80; - -bool &CWeather::LightningFlash = *(bool*)0x95CDA3; -bool &CWeather::LightningBurst = *(bool*)0x95CDAC; -uint32 &CWeather::LightningStart = *(uint32*)0x8F5F84; -uint32 &CWeather::LightningFlashLastChange = *(uint32*)0x8E2C0C; -uint32 &CWeather::WhenToPlayLightningSound = *(uint32*)0x8F57E4; -uint32 &CWeather::LightningDuration = *(uint32*)0x940578; - -float &CWeather::Foggyness = *(float*)0x885AF4; -float &CWeather::CloudCoverage = *(float*)0x8E2818; -float &CWeather::Wind = *(float*)0x8E2BF8; -float &CWeather::Rain = *(float*)0x8E2BFC; -float &CWeather::InterpolationValue = *(float*)0x8F2520; -float &CWeather::WetRoads = *(float*)0x8F5FF8; -float &CWeather::Rainbow = *(float*)0x940598; - -bool &CWeather::bScriptsForceRain = *(bool*)0x95CD7D; -bool &CWeather::Stored_StateStored = *(bool*)0x95CDC1; - -WRAPPER void CWeather::RenderRainStreaks(void) { EAXJMP(0x524550); } - -void CWeather::ReleaseWeather() -{ - ForcedWeatherType = -1; -} diff --git a/src/Weather.h b/src/Weather.h deleted file mode 100644 index a9c15fd9..00000000 --- a/src/Weather.h +++ /dev/null @@ -1,39 +0,0 @@ -enum { - WEATHER_SUNNY, - WEATHER_CLOUDY, - WEATHER_RAINY, - WEATHER_FOGGY -}; - -class CWeather -{ -public: - static int32 &SoundHandle; - - static int32 &WeatherTypeInList; - static int16 &OldWeatherType; - static int16 &NewWeatherType; - static int16 &ForcedWeatherType; - - static bool &LightningFlash; - static bool &LightningBurst; - static uint32 &LightningStart; - static uint32 &LightningFlashLastChange; - static uint32 &WhenToPlayLightningSound; - static uint32 &LightningDuration; - - static float &Foggyness; - static float &CloudCoverage; - static float &Wind; - static float &Rain; - static float &InterpolationValue; - static float &WetRoads; - static float &Rainbow; - - static bool &bScriptsForceRain; - static bool &Stored_StateStored; - - static void RenderRainStreaks(void); - - static void ReleaseWeather(); -}; diff --git a/src/World.cpp b/src/World.cpp deleted file mode 100644 index 538e15c5..00000000 --- a/src/World.cpp +++ /dev/null @@ -1,718 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Entity.h" -#include "Ped.h" -#include "PlayerPed.h" -#include "Vehicle.h" -#include "Object.h" -#include "Camera.h" -#include "DMAudio.h" -#include "CarCtrl.h" -#include "Garages.h" -#include "TempColModels.h" -#include "World.h" - -CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; -CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; -CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; -uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64; - -uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61; -CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0; -bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC; -CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494; -bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F; -bool &CWorld::bSecondShift = *(bool*)0x95CD54; -bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C; -bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; - -void -CWorld::Add(CEntity *ent) -{ - if(ent->IsVehicle() || ent->IsPed()) - DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, true); - - if(ent->bIsBIGBuilding) - ms_bigBuildingsList[ent->m_level].InsertItem(ent); - else - ent->Add(); - - if(ent->IsBuilding() || ent->IsDummy()) - return; - - if(!ent->bIsStatic) - ((CPhysical*)ent)->AddToMovingList(); -} - -void -CWorld::Remove(CEntity *ent) -{ - if(ent->IsVehicle() || ent->IsPed()) - DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, false); - - if(ent->bIsBIGBuilding) - ms_bigBuildingsList[ent->m_level].RemoveItem(ent); - else - ent->Remove(); - - if(ent->IsBuilding() || ent->IsDummy()) - return; - - if(!ent->bIsStatic) - ((CPhysical*)ent)->RemoveFromMovingList(); -} - -void -CWorld::ClearScanCodes(void) -{ - CPtrNode *node; - for(int i = 0; i < NUMSECTORS_Y; i++) - for(int j = 0; j < NUMSECTORS_X; j++){ - CSector *s = &ms_aSectors[i][j]; - for(node = s->m_lists[ENTITYLIST_BUILDINGS].first; node; node = node->next) - ((CEntity*)node->item)->m_scanCode = 0; - for(node = s->m_lists[ENTITYLIST_VEHICLES].first; node; node = node->next) - ((CEntity*)node->item)->m_scanCode = 0; - for(node = s->m_lists[ENTITYLIST_PEDS].first; node; node = node->next) - ((CEntity*)node->item)->m_scanCode = 0; - for(node = s->m_lists[ENTITYLIST_OBJECTS].first; node; node = node->next) - ((CEntity*)node->item)->m_scanCode = 0; - for(node = s->m_lists[ENTITYLIST_DUMMIES].first; node; node = node->next) - ((CEntity*)node->item)->m_scanCode = 0; - } -} - -bool -CWorld::CameraToIgnoreThisObject(CEntity *ent) -{ - if(CGarages::IsModelIndexADoor(ent->GetModelIndex())) - return false; - return ((CObject*)ent)->m_bCameraToAvoidThisObject != 1; -} - -bool -CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - int x, xstart, xend; - int y, ystart, yend; - int y1, y2; - float dist; - - AdvanceCurrentScanCode(); - - entity = nil; - dist = 1.0f; - - xstart = GetSectorIndexX(point1.x); - ystart = GetSectorIndexX(point1.y); - xend = GetSectorIndexX(point2.x); - yend = GetSectorIndexX(point2.y); - -#define LOSARGS CColLine(point1, point2), point, dist, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects - - if(xstart == xend && ystart == yend){ - // Only one sector - return ProcessLineOfSightSector(*GetSector(xstart, ystart), LOSARGS); - }else if(xstart == xend){ - // Only step in y - if(ystart < yend) - for(y = ystart; y <= yend; y++) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - else - for(y = ystart; y >= yend; y--) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - return dist < 1.0f; - }else if(ystart == yend){ - // Only step in x - if(xstart < xend) - for(x = xstart; x <= xend; x++) - ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS); - else - for(x = xstart; x >= xend; x--) - ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS); - return dist < 1.0f; - }else{ - if(point1.x < point2.x){ - // Step from left to right - float m = (point2.y - point1.y) / (point2.x - point1.x); - - y1 = ystart; - y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y); - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - - for(x = xstart+1; x < xend; x++){ - y1 = y2; - y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y); - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); - } - - y1 = y2; - y2 = yend; - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); - }else{ - // Step from right to left - float m = (point2.y - point1.y) / (point2.x - point1.x); - - y1 = ystart; - y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y); - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); - - for(x = xstart-1; x > xend; x--){ - y1 = y2; - y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y); - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); - } - - y1 = y2; - y2 = yend; - if(y1 < y2) - for(y = y1; y <= y2; y++) - ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); - else - for(y = y1; y >= y2; y--) - ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); - } - return dist < 1.0f; - } - -#undef LOSARGS -} - -bool -CWorld::ProcessLineOfSightSector(CSector §or, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - float mindist = dist; - bool deadPeds = !!bIncludeDeadPeds; - bIncludeDeadPeds = false; - - if(checkBuildings){ - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough); - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); - } - - if(checkVehicles){ - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough); - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); - } - - if(checkPeds){ - if(deadPeds) - bIncludeDeadPeds = true; - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough); - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); - bIncludeDeadPeds = false; - } - - if(checkObjects){ - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects); - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects); - } - - if(checkDummies){ - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough); - ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); - } - - bIncludeDeadPeds = deadPeds; - - if(mindist < dist){ - dist = mindist; - return true; - }else - return false; -} - -bool -CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - bool deadPeds = false; - float mindist = dist; - CPtrNode *node; - CEntity *e; - CColModel *colmodel; - - if(list.first && bIncludeDeadPeds && ((CEntity*)list.first->item)->IsPed()) - deadPeds = true; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(e->m_scanCode != GetCurrentScanCode() && - e != pIgnoreEntity && - (e->bUsesCollision || deadPeds) && - !(ignoreSomeObjects && CameraToIgnoreThisObject(e))){ - colmodel = nil; - e->m_scanCode = GetCurrentScanCode(); - - if(e->IsPed()){ - if(e->bUsesCollision || - deadPeds && ((CPed*)e)->m_nPedState == PED_DEAD){ - if(((CPed*)e)->UseGroundColModel()) - colmodel = &CTempColModels::ms_colModelPedGroundHit; - else - colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(); - }else - colmodel = nil; - }else if(e->bUsesCollision) - colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); - - if(colmodel && - CCollision::ProcessLineOfSight(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough)) - entity = e; - } - } - - if(mindist < dist){ - dist = mindist; - return true; - }else - return false; -} - -bool -CWorld::ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ - AdvanceCurrentScanCode(); - CVector point2(point1.x, point1.y, z2); - return CWorld::ProcessVerticalLineSector(*GetSector(GetSectorIndexX(point1.x), GetSectorIndexX(point1.y)), - CColLine(point1, point2), point, entity, - checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, poly); -} - -bool -CWorld::ProcessVerticalLineSector(CSector §or, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ - float mindist = 1.0f; - - if(checkBuildings){ - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough, poly); - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); - } - - if(checkVehicles){ - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough, poly); - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); - } - - if(checkPeds){ - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough, poly); - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); - } - - if(checkObjects){ - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, poly); - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); - } - - if(checkDummies){ - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough, poly); - ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); - } - - return mindist < 1.0f; -} - -bool -CWorld::ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ - float mindist = dist; - CPtrNode *node; - CEntity *e; - CColModel *colmodel; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(e->m_scanCode != GetCurrentScanCode() && - e->bUsesCollision){ - e->m_scanCode = GetCurrentScanCode(); - - colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); - if(CCollision::ProcessVerticalLine(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough, poly)) - entity = e; - } - } - - if(mindist < dist){ - dist = mindist; - return true; - }else - return false; -} - -bool -CWorld::GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - int x, xstart, xend; - int y, ystart, yend; - int y1, y2; - - AdvanceCurrentScanCode(); - - xstart = GetSectorIndexX(point1.x); - ystart = GetSectorIndexX(point1.y); - xend = GetSectorIndexX(point2.x); - yend = GetSectorIndexX(point2.y); - -#define LOSARGS CColLine(point1, point2), checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects - - if(xstart == xend && ystart == yend){ - // Only one sector - return GetIsLineOfSightSectorClear(*GetSector(xstart, ystart), LOSARGS); - }else if(xstart == xend){ - // Only step in y - if(ystart < yend){ - for(y = ystart; y <= yend; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - }else{ - for(y = ystart; y >= yend; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - } - }else if(ystart == yend){ - // Only step in x - if(xstart < xend){ - for(x = xstart; x <= xend; x++) - if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS)) - return false; - }else{ - for(x = xstart; x >= xend; x--) - if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS)) - return false; - } - }else{ - if(point1.x < point2.x){ - // Step from left to right - float m = (point2.y - point1.y) / (point2.x - point1.x); - - y1 = ystart; - y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y); - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - } - - for(x = xstart+1; x < xend; x++){ - y1 = y2; - y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y); - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) - return false; - } - } - - y1 = y2; - y2 = yend; - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) - return false; - } - }else{ - // Step from right to left - float m = (point2.y - point1.y) / (point2.x - point1.x); - - y1 = ystart; - y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y); - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) - return false; - } - - for(x = xstart-1; x > xend; x--){ - y1 = y2; - y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y); - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) - return false; - } - } - - y1 = y2; - y2 = yend; - if(y1 < y2){ - for(y = y1; y <= y2; y++) - if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) - return false; - }else{ - for(y = y1; y >= y2; y--) - if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) - return false; - } - } - } - - return true; - -#undef LOSARGS -} - -bool -CWorld::GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - if(checkBuildings){ - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS], line, ignoreSeeThrough)) - return false; - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, ignoreSeeThrough)) - return false; - } - - if(checkVehicles){ - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES], line, ignoreSeeThrough)) - return false; - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, ignoreSeeThrough)) - return false; - } - - if(checkPeds){ - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS], line, ignoreSeeThrough)) - return false; - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, ignoreSeeThrough)) - return false; - } - - if(checkObjects){ - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS], line, ignoreSeeThrough, ignoreSomeObjects)) - return false; - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, ignoreSeeThrough, ignoreSomeObjects)) - return false; - } - - if(checkDummies){ - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES], line, ignoreSeeThrough)) - return false; - if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, ignoreSeeThrough)) - return false; - } - - return true; -} - -bool -CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects) -{ - CPtrNode *node; - CEntity *e; - CColModel *colmodel; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - if(e->m_scanCode != GetCurrentScanCode() && - e->bUsesCollision){ - - e->m_scanCode = GetCurrentScanCode(); - - if(e != pIgnoreEntity && - !(ignoreSomeObjects && CameraToIgnoreThisObject(e))){ - - colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); - - if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough)) - return false; - } - } - } - - return true; -} - -float -CWorld::FindGroundZForCoord(float x, float y) -{ - CColPoint point; - CEntity *ent; - if(ProcessVerticalLine(CVector(x, y, 1000.0f), -1000.0f, point, ent, true, false, false, false, true, false, nil)) - return point.point.z; - else - return 20.0f; -} - -float -CWorld::FindGroundZFor3DCoord(float x, float y, float z, bool *found) -{ - CColPoint point; - CEntity *ent; - if(ProcessVerticalLine(CVector(x, y, z), -1000.0f, point, ent, true, false, false, false, false, false, nil)){ - if(found) - *found = true; - return point.point.z; - }else{ - if(found) - *found = false; - return 0.0f; - } -} - -float -CWorld::FindRoofZFor3DCoord(float x, float y, float z, bool *found) -{ - CColPoint point; - CEntity *ent; - if(ProcessVerticalLine(CVector(x, y, z), 1000.0f, point, ent, true, false, false, false, true, false, nil)){ - if(found) - *found = true; - return point.point.z; - }else{ - if(found == nil) - printf("THERE IS NO MAP BELOW THE FOLLOWING COORS:%f %f %f. (FindGroundZFor3DCoord)\n", x, y, z); - if(found) - *found = false; - return 20.0f; - } -} - -CPlayerPed* -FindPlayerPed(void) -{ - return CWorld::Players[CWorld::PlayerInFocus].m_pPed; -} - -CVehicle* -FindPlayerVehicle(void) -{ - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) - return ped->m_pMyVehicle; - else - return nil; -} - -CVehicle* -FindPlayerTrain(void) -{ - if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain()) - return FindPlayerVehicle(); - else - return nil; -} - -CEntity* -FindPlayerEntity(void) -{ - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) - return ped->m_pMyVehicle; - else - return ped; -} - -CVector -FindPlayerCoors(void) -{ - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) - return ped->m_pMyVehicle->GetPosition(); - else - return ped->GetPosition(); -} - -CVector& -FindPlayerSpeed(void) -{ - CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - if(ped->bInVehicle && ped->m_pMyVehicle) - return ped->m_pMyVehicle->m_vecMoveSpeed; - else - return ped->m_vecMoveSpeed; -} - -CVector& -FindPlayerCentreOfWorld(int32 player) -{ - if(CCarCtrl::bCarsGeneratedAroundCamera) - return TheCamera.GetPosition(); - if(CWorld::Players[player].m_pRemoteVehicle) - return CWorld::Players[player].m_pRemoteVehicle->GetPosition(); - if(FindPlayerVehicle()) - return FindPlayerVehicle()->GetPosition(); - return CWorld::Players[player].m_pPed->GetPosition(); -} - -CVector& -FindPlayerCentreOfWorld_NoSniperShift(void) -{ - if(CCarCtrl::bCarsGeneratedAroundCamera) - return TheCamera.GetPosition(); - if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) - return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition(); - if(FindPlayerVehicle()) - return FindPlayerVehicle()->GetPosition(); - return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition(); -} - -float -FindPlayerHeading(void) -{ - if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) - return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading(); - if(FindPlayerVehicle()) - return FindPlayerVehicle()->GetForward().Heading(); - return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetForward().Heading(); -} - -STARTPATCHES - InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP); - InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP); - InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP); - InjectHook(0x4AF970, CWorld::ProcessLineOfSight, PATCH_JUMP); - InjectHook(0x4B0A80, CWorld::ProcessLineOfSightSector, PATCH_JUMP); - InjectHook(0x4B0C70, CWorld::ProcessLineOfSightSectorList, PATCH_JUMP); - InjectHook(0x4B0DE0, CWorld::ProcessVerticalLine, PATCH_JUMP); - InjectHook(0x4B0EF0, CWorld::ProcessVerticalLineSector, PATCH_JUMP); - InjectHook(0x4B1090, CWorld::ProcessVerticalLineSectorList, PATCH_JUMP); - InjectHook(0x4AEAA0, CWorld::GetIsLineOfSightClear, PATCH_JUMP); - InjectHook(0x4B2000, CWorld::GetIsLineOfSightSectorClear, PATCH_JUMP); - InjectHook(0x4B2160, CWorld::GetIsLineOfSightSectorListClear, PATCH_JUMP); - - InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP); - InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); - InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); -ENDPATCHES diff --git a/src/World.h b/src/World.h deleted file mode 100644 index 3b7090da..00000000 --- a/src/World.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include "Game.h" -#include "Lists.h" -#include "PlayerInfo.h" - -/* Sectors span from -2000 to 2000 in x and y. - * With 100x100 sectors, each is 40x40 units. */ - -#define SECTOR_SIZE_X (40.0f) -#define SECTOR_SIZE_Y (40.0f) - -#define NUMSECTORS_X (100) -#define NUMSECTORS_Y (100) - -#define WORLD_SIZE_X (NUMSECTORS_X * SECTOR_SIZE_X) -#define WORLD_SIZE_Y (NUMSECTORS_Y * SECTOR_SIZE_Y) - -#define WORLD_MIN_X (-2000.0f) -#define WORLD_MIN_Y (-2000.0f) - -#define WORLD_MAX_X (WORLD_MIN_X + WORLD_SIZE_X) -#define WORLD_MAX_Y (WORLD_MIN_Y + WORLD_SIZE_Y) - -enum -{ - ENTITYLIST_BUILDINGS, - ENTITYLIST_BUILDINGS_OVERLAP, - ENTITYLIST_OBJECTS, - ENTITYLIST_OBJECTS_OVERLAP, - ENTITYLIST_VEHICLES, - ENTITYLIST_VEHICLES_OVERLAP, - ENTITYLIST_PEDS, - ENTITYLIST_PEDS_OVERLAP, - ENTITYLIST_DUMMIES, - ENTITYLIST_DUMMIES_OVERLAP, - - NUMSECTORENTITYLISTS -}; - -class CSector -{ -public: - CPtrList m_lists[NUMSECTORENTITYLISTS]; -}; -static_assert(sizeof(CSector) == 0x28, "CSector: error"); - -class CEntity; -struct CColPoint; -struct CColLine; -struct CStoredCollPoly; - -class CWorld -{ - static CPtrList *ms_bigBuildingsList; // [4]; - static CPtrList &ms_listMovingEntityPtrs; - static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; - static uint16 &ms_nCurrentScanCode; - -public: - static uint8 &PlayerInFocus; - static CPlayerInfo *Players; - static CEntity *&pIgnoreEntity; - static bool &bIncludeDeadPeds; - static bool &bNoMoreCollisionTorque; - static bool &bSecondShift; - static bool &bForceProcessControl; - static bool &bProcessCutsceneOnly; - - static void Remove(CEntity *entity); - static void Add(CEntity *entity); - - static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } - static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; } - static CPtrList &GetMovingEntityList(void) { return ms_listMovingEntityPtrs; } - static uint16 GetCurrentScanCode(void) { return ms_nCurrentScanCode; } - static void AdvanceCurrentScanCode(void){ - if(++CWorld::ms_nCurrentScanCode == 0){ - CWorld::ClearScanCodes(); - CWorld::ms_nCurrentScanCode = 1; - } - } - static void ClearScanCodes(void); - - static bool CameraToIgnoreThisObject(CEntity *ent); - - static bool ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static bool ProcessLineOfSightSector(CSector §or, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static bool ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly); - static bool ProcessVerticalLineSector(CSector §or, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly); - static bool ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly); - static bool GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static bool GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false); - - static float FindGroundZForCoord(float x, float y); - static float FindGroundZFor3DCoord(float x, float y, float z, bool *found); - static float FindRoofZFor3DCoord(float x, float y, float z, bool *found); - - static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); } - static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); } - static int GetSectorIndexX(float f) { return (int)GetSectorX(f); } - static int GetSectorIndexY(float f) { return (int)GetSectorY(f); } - static float GetWorldX(int x) { return x*SECTOR_SIZE_X + WORLD_MIN_X; } - static float GetWorldY(int y) { return y*SECTOR_SIZE_Y + WORLD_MIN_Y; } -}; - -class CPlayerPed; -class CVehicle; -CPlayerPed *FindPlayerPed(void); -CVehicle *FindPlayerVehicle(void); -CVehicle *FindPlayerTrain(void); -CEntity *FindPlayerEntity(void); -CVector FindPlayerCoors(void); -CVector &FindPlayerSpeed(void); -CVector &FindPlayerCentreOfWorld(int32 player); -CVector &FindPlayerCentreOfWorld_NoSniperShift(void); -float FindPlayerHeading(void); diff --git a/src/Zones.cpp b/src/Zones.cpp deleted file mode 100644 index 363fc3d9..00000000 --- a/src/Zones.cpp +++ /dev/null @@ -1,874 +0,0 @@ -#include "common.h" -#include "patcher.h" - -#include "Zones.h" - -#include "Clock.h" -#include "Text.h" -#include "World.h" - -eLevelName &CTheZones::m_CurrLevel = *(eLevelName*)0x8F2BC8; -CZone *&CTheZones::m_pPlayersZone = *(CZone**)0x8F254C; -int16 &CTheZones::FindIndex = *(int16*)0x95CC40; - -uint16 &CTheZones::NumberOfAudioZones = *(uint16*)0x95CC84; -int16 *CTheZones::AudioZoneArray = (int16*)0x713BC0; -uint16 &CTheZones::TotalNumberOfMapZones = *(uint16*)0x95CC74; -uint16 &CTheZones::TotalNumberOfZones = *(uint16*)0x95CC36; -CZone *CTheZones::ZoneArray = (CZone*)0x86BEE0; -CZone *CTheZones::MapZoneArray = (CZone*)0x663EC0; -uint16 &CTheZones::TotalNumberOfZoneInfos = *(uint16*)0x95CC3C; -CZoneInfo *CTheZones::ZoneInfoArray = (CZoneInfo*)0x714400; - -#define SWAPF(a, b) { float t; t = a; a = b; b = t; } - -static void -CheckZoneInfo(CZoneInfo *info) -{ - assert(info->carThreshold[0] >= 0); - assert(info->carThreshold[0] <= info->carThreshold[1]); - assert(info->carThreshold[1] <= info->carThreshold[2]); - assert(info->carThreshold[2] <= info->carThreshold[3]); - assert(info->carThreshold[3] <= info->carThreshold[4]); - assert(info->carThreshold[4] <= info->carThreshold[5]); - assert(info->carThreshold[5] <= info->copThreshold); - assert(info->copThreshold <= info->gangThreshold[0]); - assert(info->gangThreshold[0] <= info->gangThreshold[1]); - assert(info->gangThreshold[1] <= info->gangThreshold[2]); - assert(info->gangThreshold[2] <= info->gangThreshold[3]); - assert(info->gangThreshold[3] <= info->gangThreshold[4]); - assert(info->gangThreshold[4] <= info->gangThreshold[5]); - assert(info->gangThreshold[5] <= info->gangThreshold[6]); - assert(info->gangThreshold[6] <= info->gangThreshold[7]); - assert(info->gangThreshold[7] <= info->gangThreshold[8]); -} - -wchar* -CZone::GetTranslatedName(void) -{ - return TheText.Get(name); -} - -void -CTheZones::Init(void) -{ - int i; - for(i = 0; i < NUMAUDIOZONES; i++) - AudioZoneArray[i] = -1; - NumberOfAudioZones = 0; - - CZoneInfo *zonei; - int x = 1000/6; - for(i = 0; i < 2*NUMZONES; i++){ - zonei = &ZoneInfoArray[i]; - zonei->carDensity = 10; - zonei->carThreshold[0] = x; - zonei->carThreshold[1] = zonei->carThreshold[0] + x; - zonei->carThreshold[2] = zonei->carThreshold[1] + x; - zonei->carThreshold[3] = zonei->carThreshold[2] + x; - zonei->carThreshold[4] = zonei->carThreshold[3]; - zonei->carThreshold[5] = zonei->carThreshold[4]; - zonei->copThreshold = zonei->carThreshold[5] + x; - zonei->gangThreshold[0] = zonei->copThreshold; - zonei->gangThreshold[1] = zonei->gangThreshold[0]; - zonei->gangThreshold[2] = zonei->gangThreshold[1]; - zonei->gangThreshold[3] = zonei->gangThreshold[2]; - zonei->gangThreshold[4] = zonei->gangThreshold[3]; - zonei->gangThreshold[5] = zonei->gangThreshold[4]; - zonei->gangThreshold[6] = zonei->gangThreshold[5]; - zonei->gangThreshold[7] = zonei->gangThreshold[6]; - zonei->gangThreshold[8] = zonei->gangThreshold[7]; - CheckZoneInfo(zonei); - } - TotalNumberOfZoneInfos = 1; // why 1? - - for(i = 0; i < NUMZONES; i++) - memset(&ZoneArray[i], 0, sizeof(CZone)); - strcpy(ZoneArray[0].name, "CITYZON"); - ZoneArray[0].minx = -4000.0f; - ZoneArray[0].miny = -4000.0f; - ZoneArray[0].minz = -500.0f; - ZoneArray[0].maxx = 4000.0f; - ZoneArray[0].maxy = 4000.0f; - ZoneArray[0].maxz = 500.0f; - ZoneArray[0].level = LEVEL_NONE; - TotalNumberOfZones = 1; - - m_CurrLevel = LEVEL_NONE; - m_pPlayersZone = &ZoneArray[0]; - - for(i = 0; i < NUMMAPZONES; i++){ - memset(&MapZoneArray[i], 0, sizeof(CZone)); - MapZoneArray[i].type = ZONE_MAPZONE; - } - strcpy(MapZoneArray[0].name, "THEMAP"); - MapZoneArray[0].minx = -4000.0f; - MapZoneArray[0].miny = -4000.0f; - MapZoneArray[0].minz = -500.0f; - MapZoneArray[0].maxx = 4000.0f; - MapZoneArray[0].maxy = 4000.0f; - MapZoneArray[0].maxz = 500.0f; - MapZoneArray[0].level = LEVEL_NONE; - TotalNumberOfMapZones = 1; -} - -void -CTheZones::Update(void) -{ - CVector pos; - pos = FindPlayerCoors(); - m_pPlayersZone = FindSmallestZonePosition(&pos); - m_CurrLevel = GetLevelFromPosition(pos); -} - -void -CTheZones::CreateZone(char *name, eZoneType type, - float minx, float miny, float minz, - float maxx, float maxy, float maxz, - eLevelName level) -{ - CZone *zone; - char *p; - - if(minx > maxx) SWAPF(minx, maxx); - if(miny > maxy) SWAPF(miny, maxy); - if(minz > maxz) SWAPF(minz, maxz); - - // make upper case - for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); - - // add zone - zone = &ZoneArray[TotalNumberOfZones++]; - strncpy(zone->name, name, 7); - zone->name[7] = '\0'; - zone->type = type; - zone->minx = minx; - zone->miny = miny; - zone->minz = minz; - zone->maxx = maxx; - zone->maxy = maxy; - zone->maxz = maxz; - zone->level = level; - if(type == ZONE_AUDIO || type == ZONE_TYPE1 || type == ZONE_TYPE2){ - zone->zoneinfoDay = TotalNumberOfZoneInfos++; - zone->zoneinfoNight = TotalNumberOfZoneInfos++; - } -} - -void -CTheZones::CreateMapZone(char *name, eZoneType type, - float minx, float miny, float minz, - float maxx, float maxy, float maxz, - eLevelName level) -{ - CZone *zone; - char *p; - - if(minx > maxx) SWAPF(minx, maxx); - if(miny > maxy) SWAPF(miny, maxy); - if(minz > maxz) SWAPF(minz, maxz); - - // make upper case - for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); - - // add zone - zone = &MapZoneArray[TotalNumberOfMapZones++]; - strncpy(zone->name, name, 7); - zone->name[7] = '\0'; - zone->type = type; - zone->minx = minx; - zone->miny = miny; - zone->minz = minz; - zone->maxx = maxx; - zone->maxy = maxy; - zone->maxz = maxz; - zone->level = level; -} - -void -CTheZones::PostZoneCreation(void) -{ - int i; - for(i = 1; i < TotalNumberOfZones; i++) - InsertZoneIntoZoneHierarchy(&ZoneArray[i]); - InitialiseAudioZoneArray(); -} - -void -CTheZones::InsertZoneIntoZoneHierarchy(CZone *zone) -{ - zone->child = nil; - zone->parent = nil; - zone->next = nil; - InsertZoneIntoZoneHierRecursive(zone, &ZoneArray[0]); -} - -bool -CTheZones::InsertZoneIntoZoneHierRecursive(CZone *inner, CZone *outer) -{ - int n; - CZone *child, *next, *insert; - - // return false if inner was not inserted into outer - if(outer == nil || - !ZoneIsEntirelyContainedWithinOtherZone(inner, outer)) - return false; - - // try to insert inner into children of outer - for(child = outer->child; child; child = child->next) - if(InsertZoneIntoZoneHierRecursive(inner, child)) - return true; - - // insert inner as child of outer - // count number of outer's children contained within inner - n = 0; - for(child = outer->child; child; child = child->next) - if(ZoneIsEntirelyContainedWithinOtherZone(child, inner)) - n++; - inner->next = outer->child; - inner->parent = outer; - outer->child = inner; - // move children from outer to inner - if(n){ - insert = inner; - for(child = inner->next; child; child = next){ - next = child->next; - if(ZoneIsEntirelyContainedWithinOtherZone(child,inner)){ - insert->next = child->next; - child->parent = inner; - child->next = inner->child; - inner->child = child; - }else - insert = child; - } - } - - return true; -} - -bool -CTheZones::ZoneIsEntirelyContainedWithinOtherZone(CZone *inner, CZone *outer) -{ - char tmp[100]; - - if(inner->minx < outer->minx || - inner->maxx > outer->maxx || - inner->miny < outer->miny || - inner->maxy > outer->maxy || - inner->minz < outer->minz || - inner->maxz > outer->maxz){ - CVector vmin(inner->minx, inner->miny, inner->minz); - if(PointLiesWithinZone(vmin, outer)) - sprintf(tmp, "Overlapping zones %s and %s\n", - inner->name, outer->name); - CVector vmax(inner->maxx, inner->maxy, inner->maxz); - if(PointLiesWithinZone(vmax, outer)) - sprintf(tmp, "Overlapping zones %s and %s\n", - inner->name, outer->name); - return false; - } - return true; -} - -bool -CTheZones::PointLiesWithinZone(const CVector &v, CZone *zone) -{ - return zone->minx <= v.x && v.x <= zone->maxx && - zone->miny <= v.y && v.y <= zone->maxy && - zone->minz <= v.z && v.z <= zone->maxz; -} - -eLevelName -CTheZones::GetLevelFromPosition(CVector const &v) -{ - int i; -// char tmp[116]; -// if(!PointLiesWithinZone(v, &MapZoneArray[0])) -// sprintf(tmp, "x = %.3f y= %.3f z = %.3f\n", v.x, v.y, v.z); - for(i = 1; i < TotalNumberOfMapZones; i++) - if(PointLiesWithinZone(v, &MapZoneArray[i])) - return MapZoneArray[i].level; - return MapZoneArray[0].level; -} - -CZone* -CTheZones::FindSmallestZonePosition(const CVector *v) -{ - CZone *best = &ZoneArray[0]; - // zone to test next - CZone *zone = ZoneArray[0].child; - while(zone) - // if in zone, descent into children - if(PointLiesWithinZone(*v, zone)){ - best = zone; - zone = zone->child; - // otherwise try next zone - }else - zone = zone->next; - return best; -} - -CZone* -CTheZones::FindSmallestZonePositionType(const CVector *v, eZoneType type) -{ - CZone *best = nil; - if(ZoneArray[0].type == type) - best = &ZoneArray[0]; - // zone to test next - CZone *zone = ZoneArray[0].child; - while(zone) - // if in zone, descent into children - if(PointLiesWithinZone(*v, zone)){ - if(zone->type == type) - best = zone; - zone = zone->child; - // otherwise try next zone - }else - zone = zone->next; - return best; -} - -CZone* -CTheZones::FindSmallestZonePositionILN(const CVector *v) -{ - CZone *best = nil; - if(ZoneArray[0].type == ZONE_AUDIO || - ZoneArray[0].type == ZONE_TYPE1 || - ZoneArray[0].type == ZONE_TYPE2) - best = &ZoneArray[0]; - // zone to test next - CZone *zone = ZoneArray[0].child; - while(zone) - // if in zone, descent into children - if(PointLiesWithinZone(*v, zone)){ - if(zone->type == ZONE_AUDIO || - zone->type == ZONE_TYPE1 || - zone->type == ZONE_TYPE2) - best = zone; - zone = zone->child; - // otherwise try next zone - }else - zone = zone->next; - return best; -} - -int16 -CTheZones::FindZoneByLabelAndReturnIndex(char *name) -{ - char str[8]; - memset(str, 0, 8); - strncpy(str, name, 8); - for(FindIndex = 0; FindIndex < TotalNumberOfZones; FindIndex++) - if(strcmp(GetZone(FindIndex)->name, name) == 0) - return FindIndex; - return -1; -} - -CZoneInfo* -CTheZones::GetZoneInfo(const CVector *v, uint8 day) -{ - CZone *zone; - zone = FindSmallestZonePositionILN(v); - if(zone == nil) - return &ZoneInfoArray[0]; - return &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; -} - -void -CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info) -{ - CZoneInfo *day, *night; - float d, n; - - day = GetZoneInfo(pos, 1); - night = GetZoneInfo(pos, 0); - - if(CClock::GetIsTimeInRange(8, 19)) - *info = *day; - else if(CClock::GetIsTimeInRange(22, 5)) - *info = *night; - else{ - if(CClock::GetIsTimeInRange(19, 22)){ - n = (CClock::GetHours() - 19) / 3.0f; - assert(n >= 0.0f && n <= 1.0f); - d = 1.0f - n; - }else{ - d = (CClock::GetHours() - 5) / 3.0f; - assert(d >= 0.0f && d <= 1.0f); - n = 1.0f - d; - } - info->carDensity = day->carDensity * d + night->carDensity * n; - info->carThreshold[0] = day->carThreshold[0] * d + night->carThreshold[0] * n; - info->carThreshold[1] = day->carThreshold[1] * d + night->carThreshold[1] * n; - info->carThreshold[2] = day->carThreshold[2] * d + night->carThreshold[2] * n; - info->carThreshold[3] = day->carThreshold[3] * d + night->carThreshold[3] * n; - info->carThreshold[4] = day->carThreshold[4] * d + night->carThreshold[4] * n; - info->carThreshold[5] = day->carThreshold[5] * d + night->carThreshold[5] * n; - info->copThreshold = day->copThreshold * d + night->copThreshold * n; - info->gangThreshold[0] = day->gangThreshold[0] * d + night->gangThreshold[0] * n; - info->gangThreshold[1] = day->gangThreshold[1] * d + night->gangThreshold[1] * n; - info->gangThreshold[2] = day->gangThreshold[2] * d + night->gangThreshold[2] * n; - info->gangThreshold[3] = day->gangThreshold[3] * d + night->gangThreshold[3] * n; - info->gangThreshold[4] = day->gangThreshold[4] * d + night->gangThreshold[4] * n; - info->gangThreshold[5] = day->gangThreshold[5] * d + night->gangThreshold[5] * n; - info->gangThreshold[6] = day->gangThreshold[6] * d + night->gangThreshold[6] * n; - info->gangThreshold[7] = day->gangThreshold[7] * d + night->gangThreshold[7] * n; - info->gangThreshold[8] = day->gangThreshold[8] * d + night->gangThreshold[8] * n; - - info->pedDensity = day->pedDensity * d + night->pedDensity * n; - info->copDensity = day->copDensity * d + night->copDensity * n; - info->gangDensity[0] = day->gangDensity[0] * d + night->gangDensity[0] * n; - info->gangDensity[1] = day->gangDensity[1] * d + night->gangDensity[1] * n; - info->gangDensity[2] = day->gangDensity[2] * d + night->gangDensity[2] * n; - info->gangDensity[3] = day->gangDensity[3] * d + night->gangDensity[3] * n; - info->gangDensity[4] = day->gangDensity[4] * d + night->gangDensity[4] * n; - info->gangDensity[5] = day->gangDensity[5] * d + night->gangDensity[5] * n; - info->gangDensity[6] = day->gangDensity[6] * d + night->gangDensity[6] * n; - info->gangDensity[7] = day->gangDensity[7] * d + night->gangDensity[7] * n; - info->gangDensity[8] = day->gangDensity[8] * d + night->gangDensity[8] * n; - } - if(CClock::GetIsTimeInRange(5, 19)) - info->pedGroup = day->pedGroup; - else - info->pedGroup = night->pedGroup; - - CheckZoneInfo(info); -} - -void -CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, - int16 gang0Num, int16 gang1Num, int16 gang2Num, - int16 gang3Num, int16 gang4Num, int16 gang5Num, - int16 gang6Num, int16 gang7Num, int16 gang8Num, - int16 copNum, - int16 car0Num, int16 car1Num, int16 car2Num, - int16 car3Num, int16 car4Num, int16 car5Num) -{ - CZone *zone; - CZoneInfo *info; - zone = GetZone(zoneid); - info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; - - CheckZoneInfo(info); - - if(carDensity != -1) info->carDensity = carDensity; - int16 oldCar1Num = info->carThreshold[1] - info->carThreshold[0]; - int16 oldCar2Num = info->carThreshold[2] - info->carThreshold[1]; - int16 oldCar3Num = info->carThreshold[3] - info->carThreshold[2]; - int16 oldCar4Num = info->carThreshold[4] - info->carThreshold[3]; - int16 oldCar5Num = info->carThreshold[5] - info->carThreshold[4]; - int16 oldCopNum = info->copThreshold - info->carThreshold[5]; - int16 oldGang0Num = info->gangThreshold[0] - info->copThreshold; - int16 oldGang1Num = info->gangThreshold[1] - info->gangThreshold[0]; - int16 oldGang2Num = info->gangThreshold[2] - info->gangThreshold[1]; - int16 oldGang3Num = info->gangThreshold[3] - info->gangThreshold[2]; - int16 oldGang4Num = info->gangThreshold[4] - info->gangThreshold[3]; - int16 oldGang5Num = info->gangThreshold[5] - info->gangThreshold[4]; - int16 oldGang6Num = info->gangThreshold[6] - info->gangThreshold[5]; - int16 oldGang7Num = info->gangThreshold[7] - info->gangThreshold[6]; - int16 oldGang8Num = info->gangThreshold[8] - info->gangThreshold[7]; - - if(car0Num != -1) info->carThreshold[0] = car0Num; - if(car1Num != -1) info->carThreshold[1] = info->carThreshold[0] + car1Num; - else info->carThreshold[1] = info->carThreshold[0] + oldCar1Num; - if(car2Num != -1) info->carThreshold[2] = info->carThreshold[1] + car2Num; - else info->carThreshold[2] = info->carThreshold[1] + oldCar2Num; - if(car3Num != -1) info->carThreshold[3] = info->carThreshold[2] + car3Num; - else info->carThreshold[3] = info->carThreshold[2] + oldCar3Num; - if(car4Num != -1) info->carThreshold[4] = info->carThreshold[3] + car4Num; - else info->carThreshold[4] = info->carThreshold[3] + oldCar4Num; - if(car5Num != -1) info->carThreshold[5] = info->carThreshold[4] + car5Num; - else info->carThreshold[5] = info->carThreshold[4] + oldCar5Num; - if(copNum != -1) info->copThreshold = info->carThreshold[5] + copNum; - else info->copThreshold = info->carThreshold[5] + oldCopNum; - if(gang0Num != -1) info->gangThreshold[0] = info->copThreshold + gang0Num; - else info->gangThreshold[0] = info->copThreshold + oldGang0Num; - if(gang1Num != -1) info->gangThreshold[1] = info->gangThreshold[0] + gang1Num; - else info->gangThreshold[1] = info->gangThreshold[0] + oldGang1Num; - if(gang2Num != -1) info->gangThreshold[2] = info->gangThreshold[1] + gang2Num; - else info->gangThreshold[2] = info->gangThreshold[1] + oldGang2Num; - if(gang3Num != -1) info->gangThreshold[3] = info->gangThreshold[2] + gang3Num; - else info->gangThreshold[3] = info->gangThreshold[2] + oldGang3Num; - if(gang4Num != -1) info->gangThreshold[4] = info->gangThreshold[3] + gang4Num; - else info->gangThreshold[4] = info->gangThreshold[3] + oldGang4Num; - if(gang5Num != -1) info->gangThreshold[5] = info->gangThreshold[4] + gang5Num; - else info->gangThreshold[5] = info->gangThreshold[4] + oldGang5Num; - if(gang6Num != -1) info->gangThreshold[6] = info->gangThreshold[5] + gang6Num; - else info->gangThreshold[6] = info->gangThreshold[5] + oldGang6Num; - if(gang7Num != -1) info->gangThreshold[7] = info->gangThreshold[6] + gang7Num; - else info->gangThreshold[7] = info->gangThreshold[6] + oldGang7Num; - if(gang8Num != -1) info->gangThreshold[8] = info->gangThreshold[7] + gang8Num; - else info->gangThreshold[8] = info->gangThreshold[7] + oldGang8Num; - - CheckZoneInfo(info); -} - -void -CTheZones::SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, - int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, - int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, - int16 gang8Density, int16 copDensity) -{ - CZone *zone; - CZoneInfo *info; - zone = GetZone(zoneid); - info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; - if(pedDensity != -1) info->pedDensity = pedDensity; - if(copDensity != -1) info->copDensity = copDensity; - if(gang0Density != -1) info->gangDensity[0] = gang0Density; - if(gang1Density != -1) info->gangDensity[1] = gang1Density; - if(gang2Density != -1) info->gangDensity[2] = gang2Density; - if(gang3Density != -1) info->gangDensity[3] = gang3Density; - if(gang4Density != -1) info->gangDensity[4] = gang4Density; - if(gang5Density != -1) info->gangDensity[5] = gang5Density; - if(gang6Density != -1) info->gangDensity[6] = gang6Density; - if(gang7Density != -1) info->gangDensity[7] = gang7Density; - if(gang8Density != -1) info->gangDensity[8] = gang8Density; -} - -void -CTheZones::SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity) -{ - CZone *zone; - zone = GetZone(zoneid); - if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) - ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].carDensity = cardensity; -} - -void -CTheZones::SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity) -{ - CZone *zone; - zone = GetZone(zoneid); - if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) - ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedDensity = peddensity; -} - -void -CTheZones::SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup) -{ - CZone *zone; - zone = GetZone(zoneid); - if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) - ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedGroup = pedgroup; -} - -int16 -CTheZones::FindAudioZone(CVector *pos) -{ - int i; - - for(i = 0; i < NumberOfAudioZones; i++) - if(PointLiesWithinZone(*pos, GetZone(AudioZoneArray[i]))) - return i; - return -1; -} - -eLevelName -CTheZones::FindZoneForPoint(const CVector &pos) -{ - if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("IND_ZON")))) - return LEVEL_INDUSTRIAL; - if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("COM_ZON")))) - return LEVEL_COMMERCIAL; - if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("SUB_ZON")))) - return LEVEL_SUBURBAN; - return LEVEL_NONE; -} - -void -CTheZones::AddZoneToAudioZoneArray(CZone *zone) -{ - int i, z; - - if(zone->type != ZONE_AUDIO) - return; - - /* This is a bit stupid */ - z = -1; - for(i = 0; i < NUMZONES; i++) - if(&ZoneArray[i] == zone) - z = i; - AudioZoneArray[NumberOfAudioZones++] = z; -} - -void -CTheZones::InitialiseAudioZoneArray(void) -{ - bool gonext; - CZone *zone; - - gonext = false; - zone = &ZoneArray[0]; - // Go deep first, - // set gonext when backing up a level to visit the next child - while(zone) - if(gonext){ - AddZoneToAudioZoneArray(zone); - if(zone->next){ - gonext = false; - zone = zone->next; - }else - zone = zone->parent; - }else if(zone->child) - zone = zone->child; - else{ - AddZoneToAudioZoneArray(zone); - if(zone->next) - zone = zone->next; - else{ - gonext = true; - zone = zone->parent; - } - } -} - -void -CTheZones::SaveAllZones(uint8 *buffer, uint32 *length) -{ - int i; - - *length = 8 + 12 + - NUMZONES*56 + 2*NUMZONES*58 + 4 + - NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4; - - buffer[0] = 'Z'; - buffer[1] = 'N'; - buffer[2] = 'S'; - buffer[3] = '\0'; - *(uint32*)(buffer+4) = *length - 8; - buffer += 8; - - *(int32*)(buffer) = GetIndexForZonePointer(m_pPlayersZone); - *(int32*)(buffer+4) = m_CurrLevel; - *(int16*)(buffer+8) = FindIndex; - *(int16*)(buffer+10) = 0; - buffer += 12; - - for(i = 0; i < NUMZONES; i++){ - memcpy(buffer, ZoneArray[i].name, 8); - *(float*)(buffer+8) = ZoneArray[i].minx; - *(float*)(buffer+12) = ZoneArray[i].miny; - *(float*)(buffer+16) = ZoneArray[i].minz; - *(float*)(buffer+20) = ZoneArray[i].maxx; - *(float*)(buffer+24) = ZoneArray[i].maxy; - *(float*)(buffer+28) = ZoneArray[i].maxz; - *(int32*)(buffer+32) = ZoneArray[i].type; - *(int32*)(buffer+36) = ZoneArray[i].level; - *(int16*)(buffer+40) = ZoneArray[i].zoneinfoDay; - *(int16*)(buffer+42) = ZoneArray[i].zoneinfoNight; - *(int32*)(buffer+44) = GetIndexForZonePointer(ZoneArray[i].child); - *(int32*)(buffer+48) = GetIndexForZonePointer(ZoneArray[i].parent); - *(int32*)(buffer+52) = GetIndexForZonePointer(ZoneArray[i].next); - buffer += 56; - } - - for(i = 0; i < 2*NUMZONES; i++){ - *(int16*)(buffer) = ZoneInfoArray[i].carDensity; - *(int16*)(buffer+2) = ZoneInfoArray[i].carThreshold[0]; - *(int16*)(buffer+4) = ZoneInfoArray[i].carThreshold[1]; - *(int16*)(buffer+6) = ZoneInfoArray[i].carThreshold[2]; - *(int16*)(buffer+8) = ZoneInfoArray[i].carThreshold[3]; - *(int16*)(buffer+10) = ZoneInfoArray[i].carThreshold[4]; - *(int16*)(buffer+12) = ZoneInfoArray[i].carThreshold[5]; - *(int16*)(buffer+14) = ZoneInfoArray[i].copThreshold; - *(int16*)(buffer+16) = ZoneInfoArray[i].gangThreshold[0]; - *(int16*)(buffer+18) = ZoneInfoArray[i].gangThreshold[1]; - *(int16*)(buffer+20) = ZoneInfoArray[i].gangThreshold[2]; - *(int16*)(buffer+22) = ZoneInfoArray[i].gangThreshold[3]; - *(int16*)(buffer+24) = ZoneInfoArray[i].gangThreshold[4]; - *(int16*)(buffer+26) = ZoneInfoArray[i].gangThreshold[5]; - *(int16*)(buffer+28) = ZoneInfoArray[i].gangThreshold[6]; - *(int16*)(buffer+30) = ZoneInfoArray[i].gangThreshold[7]; - *(int16*)(buffer+32) = ZoneInfoArray[i].gangThreshold[8]; - *(uint16*)(buffer+34) = ZoneInfoArray[i].pedDensity; - *(uint16*)(buffer+36) = ZoneInfoArray[i].copDensity; - *(uint16*)(buffer+38) = ZoneInfoArray[i].gangDensity[0]; - *(uint16*)(buffer+40) = ZoneInfoArray[i].gangDensity[1]; - *(uint16*)(buffer+42) = ZoneInfoArray[i].gangDensity[2]; - *(uint16*)(buffer+44) = ZoneInfoArray[i].gangDensity[3]; - *(uint16*)(buffer+46) = ZoneInfoArray[i].gangDensity[4]; - *(uint16*)(buffer+48) = ZoneInfoArray[i].gangDensity[5]; - *(uint16*)(buffer+50) = ZoneInfoArray[i].gangDensity[6]; - *(uint16*)(buffer+52) = ZoneInfoArray[i].gangDensity[7]; - *(uint16*)(buffer+54) = ZoneInfoArray[i].gangDensity[8]; - *(uint16*)(buffer+56) = ZoneInfoArray[i].pedGroup; - buffer += 58; - } - - *(uint16*)(buffer) = TotalNumberOfZones; - *(uint16*)(buffer+2) = TotalNumberOfZoneInfos; - buffer += 4; - - for(i = 0; i < NUMMAPZONES; i++){ - memcpy(buffer, MapZoneArray[i].name, 8); - *(float*)(buffer+8) = MapZoneArray[i].minx; - *(float*)(buffer+12) = MapZoneArray[i].miny; - *(float*)(buffer+16) = MapZoneArray[i].minz; - *(float*)(buffer+20) = MapZoneArray[i].maxx; - *(float*)(buffer+24) = MapZoneArray[i].maxy; - *(float*)(buffer+28) = MapZoneArray[i].maxz; - *(int32*)(buffer+32) = MapZoneArray[i].type; - *(int32*)(buffer+36) = MapZoneArray[i].level; - *(int16*)(buffer+40) = MapZoneArray[i].zoneinfoDay; - *(int16*)(buffer+42) = MapZoneArray[i].zoneinfoNight; -#ifdef STANDALONE - // BUG: GetIndexForZonePointer uses ZoneArray - // so indices will be unpredictable with different memory layout - assert(0); -#endif - *(int32*)(buffer+44) = GetIndexForZonePointer(MapZoneArray[i].child); - *(int32*)(buffer+48) = GetIndexForZonePointer(MapZoneArray[i].parent); - *(int32*)(buffer+52) = GetIndexForZonePointer(MapZoneArray[i].next); - buffer += 56; - } - - for(i = 0; i < NUMAUDIOZONES; i++){ - *(int16*)buffer = AudioZoneArray[i]; - buffer += 2; - } - - *(uint16*)(buffer) = TotalNumberOfMapZones; - *(uint16*)(buffer+2) = NumberOfAudioZones; -} - -void -CTheZones::LoadAllZones(uint8 *buffer, uint32 length) -{ - int i; - - assert(length == 8 + 12 + - NUMZONES*56 + 2*NUMZONES*58 + 4 + - NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4); - assert(buffer[0] == 'Z'); - assert(buffer[1] == 'N'); - assert(buffer[2] == 'S'); - assert(buffer[3] == '\0'); - assert(*(uint32*)(buffer+4) == length - 8); - buffer += 8; - - m_pPlayersZone = GetPointerForZoneIndex(*(int32*)(buffer)); - m_CurrLevel = (eLevelName)*(int32*)(buffer+4); - FindIndex = *(int16*)(buffer+8); - assert(*(int16*)(buffer+10) == 0); - buffer += 12; - - for(i = 0; i < NUMZONES; i++){ - memcpy(ZoneArray[i].name, buffer, 8); - ZoneArray[i].minx = *(float*)(buffer+8); - ZoneArray[i].miny = *(float*)(buffer+12); - ZoneArray[i].minz = *(float*)(buffer+16); - ZoneArray[i].maxx = *(float*)(buffer+20); - ZoneArray[i].maxy = *(float*)(buffer+24); - ZoneArray[i].maxz = *(float*)(buffer+28); - ZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); - ZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); - ZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); - ZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); - ZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); - ZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); - ZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); - buffer += 56; - } - - for(i = 0; i < 2*NUMZONES; i++){ - ZoneInfoArray[i].carDensity = *(int16*)(buffer); - ZoneInfoArray[i].carThreshold[0] = *(int16*)(buffer+2); - ZoneInfoArray[i].carThreshold[1] = *(int16*)(buffer+4); - ZoneInfoArray[i].carThreshold[2] = *(int16*)(buffer+6); - ZoneInfoArray[i].carThreshold[3] = *(int16*)(buffer+8); - ZoneInfoArray[i].carThreshold[4] = *(int16*)(buffer+10); - ZoneInfoArray[i].carThreshold[5] = *(int16*)(buffer+12); - ZoneInfoArray[i].copThreshold = *(int16*)(buffer+14); - ZoneInfoArray[i].gangThreshold[0] = *(int16*)(buffer+16); - ZoneInfoArray[i].gangThreshold[1] = *(int16*)(buffer+18); - ZoneInfoArray[i].gangThreshold[2] = *(int16*)(buffer+20); - ZoneInfoArray[i].gangThreshold[3] = *(int16*)(buffer+22); - ZoneInfoArray[i].gangThreshold[4] = *(int16*)(buffer+24); - ZoneInfoArray[i].gangThreshold[5] = *(int16*)(buffer+26); - ZoneInfoArray[i].gangThreshold[6] = *(int16*)(buffer+28); - ZoneInfoArray[i].gangThreshold[7] = *(int16*)(buffer+30); - ZoneInfoArray[i].gangThreshold[8] = *(int16*)(buffer+32); - ZoneInfoArray[i].pedDensity = *(uint16*)(buffer+34); - ZoneInfoArray[i].copDensity = *(uint16*)(buffer+36); - ZoneInfoArray[i].gangDensity[0] = *(uint16*)(buffer+38); - ZoneInfoArray[i].gangDensity[1] = *(uint16*)(buffer+40); - ZoneInfoArray[i].gangDensity[2] = *(uint16*)(buffer+42); - ZoneInfoArray[i].gangDensity[3] = *(uint16*)(buffer+44); - ZoneInfoArray[i].gangDensity[4] = *(uint16*)(buffer+46); - ZoneInfoArray[i].gangDensity[5] = *(uint16*)(buffer+48); - ZoneInfoArray[i].gangDensity[6] = *(uint16*)(buffer+50); - ZoneInfoArray[i].gangDensity[7] = *(uint16*)(buffer+52); - ZoneInfoArray[i].gangDensity[8] = *(uint16*)(buffer+54); - ZoneInfoArray[i].pedGroup = *(uint16*)(buffer+56); - buffer += 58; - } - - TotalNumberOfZones = *(uint16*)(buffer); - TotalNumberOfZoneInfos = *(uint16*)(buffer+2); - buffer += 4; - - for(i = 0; i < NUMMAPZONES; i++){ - memcpy(MapZoneArray[i].name, buffer, 8); - MapZoneArray[i].minx = *(float*)(buffer+8); - MapZoneArray[i].miny = *(float*)(buffer+12); - MapZoneArray[i].minz = *(float*)(buffer+16); - MapZoneArray[i].maxx = *(float*)(buffer+20); - MapZoneArray[i].maxy = *(float*)(buffer+24); - MapZoneArray[i].maxz = *(float*)(buffer+28); - MapZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); - MapZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); - MapZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); - MapZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); -#ifdef STANDALONE - // BUG: GetPointerForZoneIndex uses ZoneArray - // so pointers will be unpredictable with different memory layout - assert(0); -#endif - MapZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); - MapZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); - MapZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); - buffer += 56; - } - - for(i = 0; i < NUMAUDIOZONES; i++){ - AudioZoneArray[i] = *(int16*)buffer; - buffer += 2; - } - - TotalNumberOfMapZones = *(uint16*)(buffer); - NumberOfAudioZones = *(uint16*)(buffer+2); -} - - -STARTPATCHES - InjectHook(0x4B5DD0, &CZone::GetTranslatedName, PATCH_JUMP); - InjectHook(0x4B5DE0, CTheZones::Init, PATCH_JUMP); - InjectHook(0x4B61D0, CTheZones::Update, PATCH_JUMP); - InjectHook(0x4B6210, CTheZones::CreateZone, PATCH_JUMP); - InjectHook(0x4B6380, CTheZones::CreateMapZone, PATCH_JUMP); - InjectHook(0x4B64C0, CTheZones::PostZoneCreation, PATCH_JUMP); - InjectHook(0x4B6500, CTheZones::InsertZoneIntoZoneHierarchy, PATCH_JUMP); - InjectHook(0x4B6530, CTheZones::InsertZoneIntoZoneHierRecursive, PATCH_JUMP); - InjectHook(0x4B65F0, CTheZones::ZoneIsEntirelyContainedWithinOtherZone, PATCH_JUMP); - InjectHook(0x4B6710, CTheZones::PointLiesWithinZone, PATCH_JUMP); - InjectHook(0x4B6910, CTheZones::GetLevelFromPosition, PATCH_JUMP); - InjectHook(0x4B69B0, CTheZones::FindSmallestZonePosition, PATCH_JUMP); - InjectHook(0x4B6790, CTheZones::FindSmallestZonePositionType, PATCH_JUMP); - InjectHook(0x4B6890, CTheZones::FindSmallestZonePositionILN, PATCH_JUMP); - InjectHook(0x4B6800, CTheZones::FindZoneByLabelAndReturnIndex, PATCH_JUMP); - InjectHook(0x4B6FA0, CTheZones::GetZone, PATCH_JUMP); - InjectHook(0x4B84F0, CTheZones::GetPointerForZoneIndex, PATCH_JUMP); - InjectHook(0x4B6A10, CTheZones::GetZoneInfo, PATCH_JUMP); - InjectHook(0x4B6FB0, CTheZones::GetZoneInfoForTimeOfDay, PATCH_JUMP); - InjectHook(0x4B6A50, CTheZones::SetZoneCarInfo, PATCH_JUMP); - InjectHook(0x4B6DC0, CTheZones::SetZonePedInfo, PATCH_JUMP); - InjectHook(0x4B6EB0, CTheZones::SetCarDensity, PATCH_JUMP); - InjectHook(0x4B6F00, CTheZones::SetPedDensity, PATCH_JUMP); - InjectHook(0x4B6F50, CTheZones::SetPedGroup, PATCH_JUMP); - InjectHook(0x4B83E0, CTheZones::FindAudioZone, PATCH_JUMP); - InjectHook(0x4B8430, CTheZones::FindZoneForPoint, PATCH_JUMP); - InjectHook(0x4B8340, CTheZones::AddZoneToAudioZoneArray, PATCH_JUMP); - InjectHook(0x4B8510, CTheZones::SaveAllZones, PATCH_JUMP); - InjectHook(0x4B8950, CTheZones::LoadAllZones, PATCH_JUMP); -ENDPATCHES diff --git a/src/Zones.h b/src/Zones.h deleted file mode 100644 index bf3957de..00000000 --- a/src/Zones.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include "Game.h" - -enum eZoneType -{ - ZONE_AUDIO, - ZONE_TYPE1, // this should be NAVIG - ZONE_TYPE2, // this should be INFO...but all except MAPINFO get zoneinfo?? - ZONE_MAPZONE, -}; - -class CZone -{ -public: - char name[8]; - float minx; - float miny; - float minz; - float maxx; - float maxy; - float maxz; - eZoneType type; - eLevelName level; - int16 zoneinfoDay; - int16 zoneinfoNight; - CZone *child; - CZone *parent; - CZone *next; - - wchar *GetTranslatedName(void); -}; - -class CZoneInfo -{ -public: - // Car data - int16 carDensity; - int16 carThreshold[6]; - int16 copThreshold; - int16 gangThreshold[9]; - - // Ped data - uint16 pedDensity; - uint16 copDensity; - uint16 gangDensity[9]; - uint16 pedGroup; -}; - - -class CTheZones -{ -public: - static eLevelName &m_CurrLevel; - static CZone *&m_pPlayersZone; - static int16 &FindIndex; - - static uint16 &NumberOfAudioZones; - static int16 *AudioZoneArray; //[NUMAUDIOZONES]; - static uint16 &TotalNumberOfMapZones; - static uint16 &TotalNumberOfZones; - static CZone *ZoneArray; //[NUMZONES]; - static CZone *MapZoneArray; //[NUMMAPZONES]; - static uint16 &TotalNumberOfZoneInfos; - static CZoneInfo *ZoneInfoArray; //[2*NUMZONES]; - - static void Init(void); - static void Update(void); - static void CreateZone(char *name, eZoneType type, - float minx, float miny, float minz, - float maxx, float maxy, float maxz, - eLevelName level); - static void CreateMapZone(char *name, eZoneType type, - float minx, float miny, float minz, - float maxx, float maxy, float maxz, - eLevelName level); - static CZone *GetZone(uint16 i) { return &ZoneArray[i]; } - static void PostZoneCreation(void); - static void InsertZoneIntoZoneHierarchy(CZone *zone); - static bool InsertZoneIntoZoneHierRecursive(CZone *z1, CZone *z2); - static bool ZoneIsEntirelyContainedWithinOtherZone(CZone *z1, CZone *z2); - static bool PointLiesWithinZone(const CVector &v, CZone *zone); - static eLevelName GetLevelFromPosition(CVector const &v); - static CZone *FindSmallestZonePosition(const CVector *v); - static CZone *FindSmallestZonePositionType(const CVector *v, eZoneType type); - static CZone *FindSmallestZonePositionILN(const CVector *v); - static int16 FindZoneByLabelAndReturnIndex(char *name); - static CZoneInfo *GetZoneInfo(const CVector *v, uint8 day); - static void GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info); - static void SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, - int16 gang0Num, int16 gang1Num, int16 gang2Num, - int16 gang3Num, int16 gang4Num, int16 gang5Num, - int16 gang6Num, int16 gang7Num, int16 gang8Num, - int16 copNum, - int16 car0Num, int16 car1Num, int16 car2Num, - int16 car3Num, int16 car4Num, int16 car5Num); - static void SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, - int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, - int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, - int16 gang8Density, int16 copDensity); - static void SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity); - static void SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity); - static void SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup); - static int16 FindAudioZone(CVector *pos); - static eLevelName FindZoneForPoint(const CVector &pos); - static CZone *GetPointerForZoneIndex(int32 i) { return i == -1 ? nil : &ZoneArray[i]; } - static int32 GetIndexForZonePointer(CZone *zone) { return zone == nil ? -1 : zone - ZoneArray; } - static void AddZoneToAudioZoneArray(CZone *zone); - static void InitialiseAudioZoneArray(void); - static void SaveAllZones(uint8 *buffer, uint32 *length); - static void LoadAllZones(uint8 *buffer, uint32 length); -}; diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 79626acb..00000000 --- a/src/common.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once - -#define _CRT_SECURE_NO_WARNINGS -#define _USE_MATH_DEFINES -#pragma warning(disable: 4244) // int to float -#pragma warning(disable: 4800) // int to bool -#pragma warning(disable: 4305) // double to float -#pragma warning(disable: 4838) // narrowing conversion -#pragma warning(disable: 4996) // POSIX names - -#include -#include -//#include -#include - -#ifdef WITHD3D -#include -#include -#endif - -#include -#include - -#define rwVENDORID_ROCKSTAR 0x0253F2 - -// Get rid of bullshit windows definitions, we're not running on an 8086 -#ifdef far -#undef far -#endif -#ifdef near -#undef near -#endif - -typedef uint8_t uint8; -typedef int8_t int8; -typedef uint16_t uint16; -typedef int16_t int16; -typedef uint32_t uint32; -typedef int32_t int32; -typedef uintptr_t uintptr; -typedef uint64_t uint64; -typedef int64_t int64; -// hardcode ucs-2 -typedef uint16_t wchar; - -#define nil nullptr - -#include "config.h" - -#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1)) - -// PDP-10 like byte functions -#define MASK(p, s) (((1<<(s))-1) << (p)) -inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w) -{ - uint32 m = MASK(p,s); - return w & ~m | b<

>p & (1<(high) ? (high) : (v)) - -inline float sq(float x) { return x*x; } -#define SQR(x) ((x) * (x)) - -#define PI M_PI -#define DEGTORAD(x) ((x) * PI / 180.0f) -#define RADTODEG(x) ((x) * 180.0f / PI) - -#ifdef USE_PS2_RAND -#define MYRAND_MAX 65535 -#else -#define MYRAND_MAX 32767 -#endif - -int myrand(void); -void mysrand(unsigned int seed); - -void re3_debug(char *format, ...); -void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...); -void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func); - -#define DEBUGBREAK() __debugbreak(); - -#define debug(f, ...) re3_debug("[DBG]: " f, __VA_ARGS__) -#define DEV(f, ...) re3_debug("[DEV]: " f, __VA_ARGS__) -#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, __VA_ARGS__) -#define Error(f, ...) re3_debug("[ERROR]: " f, __VA_ARGS__) - -#define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) ) -#define ASSERT assert - -#define _TODO(x) -#define _TODOCONST(x) (x) - -#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) -#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") - -#define PERCENT(x, p) ((float(x) * (float(p) / 100.0f))) -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) -#define BIT(num) (1<<(num)) - -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#define min(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/config.h b/src/config.h deleted file mode 100644 index 8cb02190..00000000 --- a/src/config.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -enum Config { - NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC) - MAX_CDIMAGES = 8, // additional cdimages - - MODELINFOSIZE = 5500, - TXDSTORESIZE = 850, - EXTRADIRSIZE = 128, - - SIMPLEMODELSIZE = 5000, - TIMEMODELSIZE = 30, - CLUMPMODELSIZE = 5, - PEDMODELSIZE = 90, - VEHICLEMODELSIZE = 120, - TWODFXSIZE = 2000, - - MAXVEHICLESLOADED = 50, // 70 on mobile - - NUMOBJECTINFO = 168, // object.dat - - // Pool sizes - NUMPTRNODES = 30000, // 26000 on PS2 - NUMENTRYINFOS = 5400, // 3200 on PS2 - NUMPEDS = 140, // 90 on PS2 - NUMVEHICLES = 110, // 70 on PS2 - NUMBUILDINGS = 5500, // 4915 on PS2 - NUMTREADABLES = 1214, - NUMOBJECTS = 450, - NUMDUMMIES = 2802, // 2368 on PS2 - NUMAUDIOSCRIPTOBJECTS = 256, - - // Link list lengths - // TODO: alpha list - NUMCOLCACHELINKS = 200, - NUMREFERENCES = 800, - - // Zones - NUMAUDIOZONES = 36, - NUMZONES = 50, - NUMMAPZONES = 25, - - // Cull zones - NUMCULLZONES = 512, - NUMATTRIBZONES = 288, - NUMZONEINDICES = 55000, - - NUMHANDLINGS = 57, - - PATHNODESIZE = 4500, - - NUMWEATHERS = 4, - NUMHOURS = 24, - - NUMEXTRADIRECTIONALS = 4, - NUMANTENNAS = 8, - NUMCORONAS = 56, - NUMPOINTLIGHTS = 32, - - NUMONSCREENTIMERENTRIES = 1, - NUMRADARBLIPS = 32, - NUMPICKUPS = 336, -}; - -// We'll use this once we're ready to become independent of the game -// Use it to mark bugs in the code that will prevent the game from working then -//#define STANDALONE - -// We don't expect to compile for PS2 or Xbox -// but it might be interesting for documentation purposes -#define GTA_PC -//#define GTA_PS2 -//#define GTA_XBOX - -// This enables things from the PS2 version on PC -#define GTA_PS2_STUFF - -// This is enabled for all released games. -// any debug stuff that isn't left in any game is not in FINAL -//#define FINAL - -// This is enabled for all released games except mobile -// any debug stuff that is only left in mobile, is not in MASTER -//#define MASTER - -#if defined GTA_PS2 -# define RANDOMSPLASH -#elif defined GTA_PC -# define GTA3_1_1_PATCH -# ifdef GTA_PS2_STUFF -//# define USE_PS2_RAND // this is unsafe until we have the game reversed -# define RANDOMSPLASH // use random splash as on PS2 -# define PS2_MATFX -# endif -#elif defined GTA_XBOX -#endif - -#ifdef MASTER - // only in master builds -#else - // not in master builds -#endif - -#ifdef FINAL - // in all games -# define USE_MY_DOCUMENTS // use my documents directory for user files -#else - // not in any game -# define NASTY_GAME // nasty game for all languages -# define NO_MOVIES // disable intro videos -# define CHATTYSPLASH // print what the game is loading -#endif - -#define FIX_BUGS // fix bugs in the game, TODO: use this more -#define KANGAROO_CHEAT -#define ASPECT_RATIO_SCALE diff --git a/src/control/HandlingMgr.cpp b/src/control/HandlingMgr.cpp deleted file mode 100644 index 47d0564c..00000000 --- a/src/control/HandlingMgr.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "FileMgr.h" -#include "HandlingMgr.h" - -cHandlingDataMgr &mod_HandlingManager = *(cHandlingDataMgr*)0x728060; - -char *HandlingFilename = "HANDLING.CFG"; - -char VehicleNames[NUMHANDLINGS][14] = { - "LANDSTAL", - "IDAHO", - "STINGER", - "LINERUN", - "PEREN", - "SENTINEL", - "PATRIOT", - "FIRETRUK", - "TRASH", - "STRETCH", - "MANANA", - "INFERNUS", - "BLISTA", - "PONY", - "MULE", - "CHEETAH", - "AMBULAN", - "FBICAR", - "MOONBEAM", - "ESPERANT", - "TAXI", - "KURUMA", - "BOBCAT", - "MRWHOOP", - "BFINJECT", - "POLICE", - "ENFORCER", - "SECURICA", - "BANSHEE", - "PREDATOR", - "BUS", - "RHINO", - "BARRACKS", - "TRAIN", - "HELI", - "DODO", - "COACH", - "CABBIE", - "STALLION", - "RUMPO", - "RCBANDIT", - "BELLYUP", - "MRWONGS", - "MAFIA", - "YARDIE", - "YAKUZA", - "DIABLOS", - "COLUMB", - "HOODS", - "AIRTRAIN", - "DEADDODO", - "SPEEDER", - "REEFER", - "PANLANT", - "FLATBED", - "YANKEE", - "BORGNINE" -}; - -cHandlingDataMgr::cHandlingDataMgr(void) -{ - memset(this, 0, sizeof(this)); -} - -void -cHandlingDataMgr::Initialise(void) -{ - LoadHandlingData(); - field_0 = 0.1f; - field_4 = 0.9f; - field_8 = 1.0f; - field_C = 0.8f; - field_10 = 0.98f; -} - -void -cHandlingDataMgr::LoadHandlingData(void) -{ - char *start, *end; - char line[201]; // weird value - char delim[4]; // not sure - char *word; - int field, handlingId; - int keepGoing; - tHandlingData *handling; - - CFileMgr::SetDir("DATA"); - CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r"); - CFileMgr::SetDir(""); - - start = (char*)work_buff; - end = start+1; - handling = nil; - keepGoing = 1; - - while(keepGoing){ - // find end of line - while(*end != '\n') end++; - - // get line - strncpy(line, start, end - start); - line[end - start] = '\0'; - start = end+1; - end = start+1; - - // yeah, this is kinda crappy - if(strncmp(line, ";the end", 9) == 0) - keepGoing = 0; - else if(line[0] != ';'){ - field = 0; - strcpy(delim, " \t"); - // FIX: game seems to use a do-while loop here - for(word = strtok(line, delim); word; word = strtok(nil, delim)){ - switch(field){ - case 0: - handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS); - assert(handlingId >= 0 && handlingId < NUMHANDLINGS); - handling = &HandlingData[handlingId]; - handling->nIdentifier = handlingId; - break; - case 1: handling->fMass = strtod(word, nil); break; - case 2: handling->Dimension.x = strtod(word, nil); break; - case 3: handling->Dimension.y = strtod(word, nil); break; - case 4: handling->Dimension.z = strtod(word, nil); break; - case 5: handling->CentreOfMass.x = strtod(word, nil); break; - case 6: handling->CentreOfMass.y = strtod(word, nil); break; - case 7: handling->CentreOfMass.z = strtod(word, nil); break; - case 8: handling->nPercentSubmerged = atoi(word); break; - case 9: handling->fTractionMultiplier = strtod(word, nil); break; - case 10: handling->fTractionLoss = strtod(word, nil); break; - case 11: handling->fTractionBias = strtod(word, nil); break; - case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break; - case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break; - case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break; - case 15: handling->TransmissionData.nDriveType = word[0]; break; - case 16: handling->TransmissionData.nEngineType = word[0]; break; - case 17: handling->fBrakeDeceleration = strtod(word, nil); break; - case 18: handling->fBrakeBias = strtod(word, nil); break; - case 19: handling->bABS = !!atoi(word); break; - case 20: handling->fSteeringLock = strtod(word, nil); break; - case 21: handling->fSuspensionForceLevel = strtod(word, nil); break; - case 22: handling->fSuspensionDampingLevel = strtod(word, nil); break; - case 23: handling->fSeatOffsetDistance = strtod(word, nil); break; - case 24: handling->fCollisionDamageMultiplier = strtod(word, nil); break; - case 25: handling->nMonetaryValue = atoi(word); break; - case 26: handling->fSuspensionUpperLimit = strtod(word, nil); break; - case 27: handling->fSuspensionLowerLimit = strtod(word, nil); break; - case 28: handling->fSuspensionBias = strtod(word, nil); break; - case 29: - sscanf(word, "%x", &handling->Flags); - handling->TransmissionData.Flags = handling->Flags; - break; - case 30: handling->FrontLights = atoi(word); break; - case 31: handling->RearLights = atoi(word); break; - } - field++; - } - ConvertDataToGameUnits(handling); - } - } -} - -int -cHandlingDataMgr::FindExactWord(const char *word, const char *words, int wordLen, int numWords) -{ - int i; - - for(i = 0; i < numWords; i++){ - // BUG: the game does something really stupid here, it's fixed here - if(strncmp(word, words, wordLen) == 0) - return i; - words += wordLen; - } - return numWords; -} - - -void -cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) -{ - // TODO: figure out what exactly is being converted here - float velocity, a, b, specificVolume; - - handling->TransmissionData.fEngineAcceleration /= 2500.0f; - handling->TransmissionData.fMaxVelocity /= 180.0f; - handling->fBrakeDeceleration /= 2500.0f; - handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f; - if(handling->fTurnMass < 10.0f) - handling->fTurnMass *= 5.0f; - handling->fInvMass = 1.0f/handling->fMass; - handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * 0.008*handling->fMass; - - // What the hell is going on here? - specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ? - a = 0.0f; - b = 100.0f; - velocity = handling->TransmissionData.fMaxVelocity; - while(a < b && velocity > 0.0f){ - velocity -= 0.01; - a = handling->TransmissionData.fEngineAcceleration/6.0f; - b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f); - } - - if(handling->nIdentifier == HANDLING_RCBANDIT){ - handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity; - }else{ - handling->TransmissionData.fUnkMaxVelocity = velocity; - handling->TransmissionData.fMaxVelocity = velocity * 1.2f; - } - handling->TransmissionData.fMaxReverseVelocity = -0.2f; - - if(handling->TransmissionData.nDriveType == '4') - handling->TransmissionData.fEngineAcceleration /= 4.0f; - else - handling->TransmissionData.fEngineAcceleration /= 2.0f; - - handling->TransmissionData.InitGearRatios(); -} - -int32 -cHandlingDataMgr::GetHandlingId(const char *name) -{ - int i; - for(i = 0; i < NUMHANDLINGS; i++) - if(strncmp(VehicleNames[i], name, 14) == 0) - break; - return i; -} - -STARTPATCHES - InjectHook(0x546D80, &cHandlingDataMgr::Initialise, PATCH_JUMP); - InjectHook(0x546DB0, &cHandlingDataMgr::LoadHandlingData, PATCH_JUMP); - InjectHook(0x546BB0, &cHandlingDataMgr::ConvertDataToGameUnits, PATCH_JUMP); - InjectHook(0x546AA0, &cHandlingDataMgr::FindExactWord, PATCH_JUMP); - InjectHook(0x546B70, &cHandlingDataMgr::GetHandlingId, PATCH_JUMP); -ENDPATCHES diff --git a/src/control/HandlingMgr.h b/src/control/HandlingMgr.h deleted file mode 100644 index 958e2351..00000000 --- a/src/control/HandlingMgr.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once - -#include "Transmission.h" - -enum eHandlingId -{ - HANDLING_LANDSTAL, - HANDLING_IDAHO, - HANDLING_STINGER, - HANDLING_LINERUN, - HANDLING_PEREN, - HANDLING_SENTINEL, - HANDLING_PATRIOT, - HANDLING_FIRETRUK, - HANDLING_TRASH, - HANDLING_STRETCH, - HANDLING_MANANA, - HANDLING_INFERNUS, - HANDLING_BLISTA, - HANDLING_PONY, - HANDLING_MULE, - HANDLING_CHEETAH, - HANDLING_AMBULAN, - HANDLING_FBICAR, - HANDLING_MOONBEAM, - HANDLING_ESPERANT, - HANDLING_TAXI, - HANDLING_KURUMA, - HANDLING_BOBCAT, - HANDLING_MRWHOOP, - HANDLING_BFINJECT, - HANDLING_POLICE, - HANDLING_ENFORCER, - HANDLING_SECURICA, - HANDLING_BANSHEE, - HANDLING_PREDATOR, - HANDLING_BUS, - HANDLING_RHINO, - HANDLING_BARRACKS, - HANDLING_TRAIN, - HANDLING_HELI, - HANDLING_DODO, - HANDLING_COACH, - HANDLING_CABBIE, - HANDLING_STALLION, - HANDLING_RUMPO, - HANDLING_RCBANDIT, - HANDLING_BELLYUP, - HANDLING_MRWONGS, - HANDLING_MAFIA, - HANDLING_YARDIE, - HANDLING_YAKUZA, - HANDLING_DIABLOS, - HANDLING_COLUMB, - HANDLING_HOODS, - HANDLING_AIRTRAIN, - HANDLING_DEADDODO, - HANDLING_SPEEDER, - HANDLING_REEFER, - HANDLING_PANLANT, - HANDLING_FLATBED, - HANDLING_YANKEE, - HANDLING_BORGNINE -}; - -enum -{ - HANDLING_1G_BOOST = 1, - HANDLING_2G_BOOST = 2, - HANDLING_REV_BONNET = 4, - HANDLING_HANGING_BOOT = 8, - HANDLING_NO_DOORS = 0x10, - HANDLING_IS_VAN = 0x20, - HANDLING_IS_BUS = 0x40, - HANDLING_IS_LOW = 0x80, - HANDLING_DBL_EXHAUST = 0x100, - HANDLING_TAILGATE_BOOT = 0x200, - HANDLING_NOSWING_BOOT = 0x400, - HANDLING_NONPLAYER_STABILISER = 0x800, - HANDLING_NEUTRALHANDLING = 0x1000, - HANDLING_HAS_NO_ROOF = 0x2000, - HANDLING_IS_BIG = 0x4000, - HANDLING_HALOGEN_LIGHTS = 0x8000, -}; - -struct tHandlingData -{ - int32 nIdentifier; - float fMass; - float fInvMass; - float fTurnMass; - CVector Dimension; - CVector CentreOfMass; - int8 nPercentSubmerged; - float fBuoyancy; - float fTractionMultiplier; - cTransmission TransmissionData; - float fBrakeDeceleration; - float fBrakeBias; - int8 bABS; - float fSteeringLock; - float fTractionLoss; - float fTractionBias; - uint32 field_AC; - float fSuspensionForceLevel; - float fSuspensionDampingLevel; - float fSuspensionUpperLimit; - float fSuspensionLowerLimit; - float fSuspensionBias; - float fCollisionDamageMultiplier; - uint32 Flags; - float fSeatOffsetDistance; - int32 nMonetaryValue; - int8 FrontLights; - int8 RearLights; -}; -VALIDATE_SIZE(tHandlingData, 0xD8); - -class cHandlingDataMgr -{ - float field_0; // unused it seems - float field_4; // wheel related - float field_8; // - float field_C; // unused it seems - float field_10; // - tHandlingData HandlingData[NUMHANDLINGS]; - uint32 field_302C; // unused it seems, padding? - -public: - cHandlingDataMgr(void); - void Initialise(void); - void LoadHandlingData(void); - int FindExactWord(const char *word, const char *words, int wordLen, int numWords); - void ConvertDataToGameUnits(tHandlingData *handling); - int32 GetHandlingId(const char *name); - tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; } -}; -VALIDATE_SIZE(cHandlingDataMgr, 0x3030); -extern cHandlingDataMgr &mod_HandlingManager; diff --git a/src/control/ObjectData.cpp b/src/control/ObjectData.cpp deleted file mode 100644 index ef5bcc5e..00000000 --- a/src/control/ObjectData.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "ModelInfo.h" -#include "Object.h" -#include "FileMgr.h" -#include "ObjectData.h" - -CObjectInfo CObjectData::ms_aObjectInfo[NUMOBJECTINFO]; - -// Another ugly file reader -void -CObjectData::Initialise(const char *filename) -{ - char *p, *lp; - char line[1024], name[256]; - int id; - float percentSubmerged; - int damageEffect, responseCase, camAvoid; - CBaseModelInfo *mi; - - CFileMgr::SetDir(""); - CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r"); - - id = 0; - p = (char*)work_buff; - while(*p != '*'){ - // skip over white space and comments - while(*p == ' ' || *p == '\n' || *p == '\r' || *p == ';') - if(*p == ';') - while(*p != '\n' && *p != '*') - p++; - else - p++; - - if(*p == '*') - break; - - // read one line - lp = line; - while(*p != '\n' && *p != '*'){ - *lp++ = *p == ',' ? ' ' : *p; - p++; - } - if(*p == '\n') - p++; - *lp = '\0'; // FIX: game wrote '\n' here - - assert(id < NUMOBJECTINFO); - sscanf(line, "%s %f %f %f %f %f %f %f %d %d %d", name, - &ms_aObjectInfo[id].m_fMass, - &ms_aObjectInfo[id].m_fTurnMass, - &ms_aObjectInfo[id].m_fAirResistance, - &ms_aObjectInfo[id].m_fElasticity, - &percentSubmerged, - &ms_aObjectInfo[id].m_fUprootLimit, - &ms_aObjectInfo[id].m_fCollisionDamageMultiplier, - &damageEffect, &responseCase, &camAvoid); - - ms_aObjectInfo[id].m_fBuoyancy = 100.0f/percentSubmerged * 0.008*ms_aObjectInfo[id].m_fMass; - ms_aObjectInfo[id].m_nCollisionDamageEffect = damageEffect; - ms_aObjectInfo[id].m_nSpecialCollisionResponseCases = responseCase; - ms_aObjectInfo[id].m_bCameraToAvoidThisObject = camAvoid; - - mi = CModelInfo::GetModelInfo(name, nil); - if(mi) - mi->SetObjectID(id++); - else - debug("CObjectData: Cannot find object %s\n", name); - } -} - -void -CObjectData::SetObjectData(int32 modelId, CObject &object) -{ - CObjectInfo *objinfo; - - if(CModelInfo::GetModelInfo(modelId)->GetObjectID() == -1) - return; - - objinfo = &ms_aObjectInfo[CModelInfo::GetModelInfo(modelId)->GetObjectID()]; - - object.m_fMass = objinfo->m_fMass; - object.m_fTurnMass = objinfo->m_fTurnMass; - object.m_fAirResistance = objinfo->m_fAirResistance; - object.m_fElasticity = objinfo->m_fElasticity; - object.m_fBuoyancy = objinfo->m_fBuoyancy; - object.m_fUprootLimit = objinfo->m_fUprootLimit; - object.m_fCollisionDamageMultiplier = objinfo->m_fCollisionDamageMultiplier; - object.m_nCollisionDamageEffect = objinfo->m_nCollisionDamageEffect; - object.m_nSpecialCollisionResponseCases = objinfo->m_nSpecialCollisionResponseCases; - object.m_bCameraToAvoidThisObject = objinfo->m_bCameraToAvoidThisObject; - if(object.m_fMass >= 99998.0){ - object.bInfiniteMass = true; - object.bAffectedByGravity = false; - object.m_flagB2 = true; - } -} - -STARTPATCHES - InjectHook(0x4BC0E0, CObjectData::Initialise, PATCH_JUMP); - InjectHook(0x4BC270, CObjectData::SetObjectData, PATCH_JUMP); -ENDPATCHES diff --git a/src/control/ObjectData.h b/src/control/ObjectData.h deleted file mode 100644 index e3a5c1bd..00000000 --- a/src/control/ObjectData.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -class CObject; - -class CObjectInfo -{ -public: - float m_fMass; - float m_fTurnMass; - float m_fAirResistance; - float m_fElasticity; - float m_fBuoyancy; - float m_fUprootLimit; - float m_fCollisionDamageMultiplier; - uint8 m_nCollisionDamageEffect; - uint8 m_nSpecialCollisionResponseCases; - bool m_bCameraToAvoidThisObject; -}; -static_assert(sizeof(CObjectInfo) == 0x20, "CObjectInfo: error"); - -class CObjectData -{ - static CObjectInfo ms_aObjectInfo[NUMOBJECTINFO]; -public: - static void Initialise(const char *filename); - static void SetObjectData(int32 modelId, CObject &object); -}; diff --git a/src/control/PedPlacement.cpp b/src/control/PedPlacement.cpp deleted file mode 100644 index e9a3f7d9..00000000 --- a/src/control/PedPlacement.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PedPlacement.h" -#include "World.h" - -void -CPedPlacement::FindZCoorForPed(CVector* pos) -{ - float zForPed; - float startZ = pos->z - 100.0f; - float foundColZ = -100.0f; - float foundColZ2 = -100.0f; - CColPoint foundCol; - CEntity* foundEnt; - - CVector vec( - pos->x, - pos->y, - pos->z + 1.0f - ); - - if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil)) - foundColZ = foundCol.point.z; - - // Adjust coords and do a second test - vec.x += 0.1f; - vec.y += 0.1f; - - if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil)) - foundColZ2 = foundCol.point.z; - - zForPed = max(foundColZ, foundColZ2); - - if (zForPed > -99.0f) - pos->z = 1.04f + zForPed; -} - -STARTPATCHES - InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP); -ENDPATCHES diff --git a/src/control/PedPlacement.h b/src/control/PedPlacement.h deleted file mode 100644 index 4bd48b62..00000000 --- a/src/control/PedPlacement.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class CVector; - -class CPedPlacement { -public: - static void FindZCoorForPed(CVector* pos); -}; \ No newline at end of file diff --git a/src/control/PedStats.cpp b/src/control/PedStats.cpp deleted file mode 100644 index f6508580..00000000 --- a/src/control/PedStats.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" -#include "PedStats.h" - -CPedStats *(&CPedStats::ms_apPedStats)[NUM_PEDSTATS] = *(CPedStats *(*)[NUM_PEDSTATS]) *(uintptr*)0x9404D4; - -void -CPedStats::Initialise(void) -{ - int i; - - debug("Initialising CPedStats...\n"); - for(i = 0; i < NUM_PEDSTATS; i++){ - ms_apPedStats[i] = new CPedStats; - ms_apPedStats[i]->m_type = PEDSTAT_PLAYER; - ms_apPedStats[i]->m_name[8] = 'R'; // WHAT? - ms_apPedStats[i]->m_fleeDistance = 20.0f; - ms_apPedStats[i]->m_headingChangeRate = 15.0f; - ms_apPedStats[i]->m_fear = 50; - ms_apPedStats[i]->m_temper = 50; - ms_apPedStats[i]->m_lawfulness = 50; - ms_apPedStats[i]->m_sexiness = 50; - ms_apPedStats[i]->m_attackStrength = 1.0f; - ms_apPedStats[i]->m_defendWeakness = 1.0f; - ms_apPedStats[i]->m_flags = 0; - } - debug("Loading pedstats data...\n"); - CPedStats::LoadPedStats(); - debug("CPedStats ready\n"); -} - -void -CPedStats::Shutdown(void) -{ - int i; - debug("Shutting down CPedStats...\n"); - for(i = 0; i < NUM_PEDSTATS; i++) - delete ms_apPedStats[i]; - debug("CPedStats shut down\n"); -} - -void -CPedStats::LoadPedStats(void) -{ - char *buf; - char line[256]; - char name[32]; - int bp, buflen; - int lp, linelen; - int type; - float fleeDist, headingChangeRate, attackStrength, defendWeakness; - int fear, temper, lawfullness, sexiness, flags; - - - type = 0; - buf = new char[16 * 1024]; - - CFileMgr::SetDir("DATA"); - buflen = CFileMgr::LoadFile("PEDSTATS.DAT", (uint8*)buf, 16 * 1024, "r"); - CFileMgr::SetDir(""); - - for(bp = 0; bp < buflen; ){ - // read file line by line - for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ - if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') - line[linelen++] = ' '; - else - line[linelen++] = buf[bp]; - line[linelen] = '\0'; - } - bp++; - - // skip white space - for(lp = 0; line[lp] <= ' '; lp++); - - if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines - line[lp] == '#') - continue; - - sscanf(&line[lp], "%s %f %f %d %d %d %d %f %f %d", - name, - &fleeDist, - &headingChangeRate, - &fear, - &temper, - &lawfullness, - &sexiness, - &attackStrength, - &defendWeakness, - &flags); - ms_apPedStats[type]->m_type = (ePedStats)type; - strncpy(ms_apPedStats[type]->m_name, name, 24); // FIX: game uses strcpy - ms_apPedStats[type]->m_fleeDistance = fleeDist; - ms_apPedStats[type]->m_headingChangeRate = headingChangeRate; - ms_apPedStats[type]->m_fear = fear; - ms_apPedStats[type]->m_temper = temper; - ms_apPedStats[type]->m_lawfulness = lawfullness; - ms_apPedStats[type]->m_sexiness = sexiness; - ms_apPedStats[type]->m_attackStrength = attackStrength; - ms_apPedStats[type]->m_defendWeakness = defendWeakness; - ms_apPedStats[type]->m_flags = flags; - type++; - } - - delete[] buf; -} - -int32 -CPedStats::GetPedStatType(char *name) -{ - int type; - - for(type = 0; type < NUM_PEDSTATS; type++) - if(strcmp(ms_apPedStats[type]->m_name, name) == 0) - return type; - return NUM_PEDSTATS; -} - -STARTPATCHES - InjectHook(0x4EF460, &CPedStats::Initialise, PATCH_JUMP); - InjectHook(0x4EF540, &CPedStats::Shutdown, PATCH_JUMP); - InjectHook(0x4EF580, &CPedStats::LoadPedStats, PATCH_JUMP); - InjectHook(0x4EF780, &CPedStats::GetPedStatType, PATCH_JUMP); -ENDPATCHES diff --git a/src/control/PedStats.h b/src/control/PedStats.h deleted file mode 100644 index ce92d4da..00000000 --- a/src/control/PedStats.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -enum ePedStats -{ - PEDSTAT_PLAYER, - PEDSTAT_COP, - PEDSTAT_MEDIC, - PEDSTAT_FIREMAN, - PEDSTAT_GANG1, - PEDSTAT_GANG2, - PEDSTAT_GANG3, - PEDSTAT_GANG4, - PEDSTAT_GANG5, - PEDSTAT_GANG6, - PEDSTAT_GANG7, - PEDSTAT_STREET_GUY, - PEDSTAT_SUIT_GUY, - PEDSTAT_SENSIBLE_GUY, - PEDSTAT_GEEK_GUY, - PEDSTAT_OLD_GUY, - PEDSTAT_TOUGH_GUY, - PEDSTAT_STREET_GIRL, - PEDSTAT_SUIT_GIRL, - PEDSTAT_SENSIBLE_GIRL, - PEDSTAT_GEEK_GIRL, - PEDSTAT_OLD_GIRL, - PEDSTAT_TOUGH_GIRL, - PEDSTAT_TRAMP_MALE, - PEDSTAT_TRAMP_FEMALE, - PEDSTAT_TOURIST, - PEDSTAT_PROSTITUTE, - PEDSTAT_CRIMINAL, - PEDSTAT_BUSKER, - PEDSTAT_TAXIDRIVER, - PEDSTAT_PSYCHO, - PEDSTAT_STEWARD, - PEDSTAT_SPORTSFAN, - PEDSTAT_SHOPPER, - PEDSTAT_OLDSHOPPER, - - NUM_PEDSTATS -}; - -// flags -enum -{ - STAT_PUNCH_ONLY = 1, - STAT_CAN_KNEE_HEAD = 2, - STAT_CAN_KICK = 4, - STAT_CAN_ROUNDHOUSE = 8, - STAT_NO_DIVE = 0x10, - STAT_ONE_HIT_KNOCKDOWN = 0x20, - STAT_SHOPPING_BAGS = 0x40, - STAT_GUN_PANIC = 0x80 -}; - -class CPedStats -{ -public: - ePedStats m_type; - char m_name[24]; - float m_fleeDistance; - float m_headingChangeRate; - int8 m_fear; - int8 m_temper; - int8 m_lawfulness; - int8 m_sexiness; - float m_attackStrength; - float m_defendWeakness; - int16 m_flags; - - static CPedStats* (&ms_apPedStats)[NUM_PEDSTATS]; - - static void Initialise(void); - static void Shutdown(void); - static void LoadPedStats(void); - static int32 GetPedStatType(char *name); -}; -static_assert(sizeof(CPedStats) == 0x34, "CPedStats: error"); diff --git a/src/control/PedType.cpp b/src/control/PedType.cpp deleted file mode 100644 index 66eb49a1..00000000 --- a/src/control/PedType.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "FileMgr.h" -#include "PedType.h" - -CPedType *(&CPedType::ms_apPedType)[NUM_PEDTYPES] = *(CPedType *(*)[NUM_PEDTYPES]) *(uintptr*)0x941594; - -void -CPedType::Initialise(void) -{ - int i; - - debug("Initialising CPedType...\n"); - for(i = 0; i < NUM_PEDTYPES; i++){ - ms_apPedType[i] = new CPedType; - ms_apPedType[i]->m_flag = PED_FLAG_PLAYER1; - ms_apPedType[i]->unknown1 = 0.0f; - ms_apPedType[i]->unknown2 = 0.0f; - // unknown3 not initialized - ms_apPedType[i]->unknown4 = 0.0f; - ms_apPedType[i]->unknown5 = 0.0f; - ms_apPedType[i]->m_threats = 0; - ms_apPedType[i]->m_avoid = 0; - } - debug("Loading ped data...\n"); - LoadPedData(); - debug("CPedType ready\n"); -} - -void -CPedType::Shutdown(void) -{ - int i; - debug("Shutting down CPedType...\n"); - for(i = 0; i < NUM_PEDTYPES; i++) - delete ms_apPedType[i]; - debug("CPedType shut down\n"); -} - -void -CPedType::LoadPedData(void) -{ - char *buf; - char line[256]; - char word[32]; - int bp, buflen; - int lp, linelen; - int type; - uint32 flags; - float f1, f2, f3, f4, f5; - - type = NUM_PEDTYPES; - buf = new char[16 * 1024]; - - CFileMgr::SetDir("DATA"); - buflen = CFileMgr::LoadFile("PED.DAT", (uint8*)buf, 16 * 1024, "r"); - CFileMgr::SetDir(""); - - for(bp = 0; bp < buflen; ){ - // read file line by line - for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ - if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') - line[linelen++] = ' '; - else - line[linelen++] = buf[bp]; - line[linelen] = '\0'; - } - bp++; - - // skip white space - for(lp = 0; line[lp] <= ' '; lp++); - - if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines - line[lp] == '#') - continue; - - // FIX: game just uses line here - sscanf(&line[lp], "%s", word); - - if(strncmp(word, "Threat", 7) == 0){ - flags = 0; - lp += 7; - while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){ - flags |= FindPedFlag(word); - // skip word - while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0') - lp++; - // skip white space - while(line[lp] == ' ') - lp++; - } - ms_apPedType[type]->m_threats = flags; - }else if(strncmp(word, "Avoid", 6) == 0){ - flags = 0; - lp += 6; - while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){ - flags |= FindPedFlag(word); - // skip word - while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0') - lp++; - // skip white space - while(line[lp] == ' ') - lp++; - } - ms_apPedType[type]->m_avoid = flags; - }else{ - sscanf(line, "%s %f %f %f %f %f", word, &f1, &f2, &f3, &f4, &f5); - type = FindPedType(word); - ms_apPedType[type]->m_flag = FindPedFlag(word); - // unknown values - ms_apPedType[type]->unknown1 = f1 / 50.0f; - ms_apPedType[type]->unknown2 = f2 / 50.0f; - ms_apPedType[type]->unknown3 = f3 / 50.0f; - ms_apPedType[type]->unknown4 = f4; - ms_apPedType[type]->unknown5 = f5; - - } - } - - delete[] buf; -} - -int32 -CPedType::FindPedType(char *type) -{ - if(strcmp(type, "PLAYER1") == 0) return PEDTYPE_PLAYER1; - if(strcmp(type, "PLAYER2") == 0) return PEDTYPE_PLAYER2; - if(strcmp(type, "PLAYER3") == 0) return PEDTYPE_PLAYER3; - if(strcmp(type, "PLAYER4") == 0) return PEDTYPE_PLAYER4; - if(strcmp(type, "CIVMALE") == 0) return PEDTYPE_CIVMALE; - if(strcmp(type, "CIVFEMALE") == 0) return PEDTYPE_CIVFEMALE; - if(strcmp(type, "COP") == 0) return PEDTYPE_COP; - if(strcmp(type, "GANG1") == 0) return PEDTYPE_GANG1; - if(strcmp(type, "GANG2") == 0) return PEDTYPE_GANG2; - if(strcmp(type, "GANG3") == 0) return PEDTYPE_GANG3; - if(strcmp(type, "GANG4") == 0) return PEDTYPE_GANG4; - if(strcmp(type, "GANG5") == 0) return PEDTYPE_GANG5; - if(strcmp(type, "GANG6") == 0) return PEDTYPE_GANG6; - if(strcmp(type, "GANG7") == 0) return PEDTYPE_GANG7; - if(strcmp(type, "GANG8") == 0) return PEDTYPE_GANG8; - if(strcmp(type, "GANG9") == 0) return PEDTYPE_GANG9; - if(strcmp(type, "EMERGENCY") == 0) return PEDTYPE_EMERGENCY; - if(strcmp(type, "FIREMAN") == 0) return PEDTYPE_FIREMAN; - if(strcmp(type, "CRIMINAL") == 0) return PEDTYPE_CRIMINAL; - if(strcmp(type, "SPECIAL") == 0) return PEDTYPE_SPECIAL; - if(strcmp(type, "PROSTITUTE") == 0) return PEDTYPE_PROSTITUTE; - Error("Unknown ped type, Pedtype.cpp"); - return NUM_PEDTYPES; -} - -uint32 -CPedType::FindPedFlag(char *type) -{ - if(strcmp(type, "PLAYER1") == 0) return PED_FLAG_PLAYER1; - if(strcmp(type, "PLAYER2") == 0) return PED_FLAG_PLAYER2; - if(strcmp(type, "PLAYER3") == 0) return PED_FLAG_PLAYER3; - if(strcmp(type, "PLAYER4") == 0) return PED_FLAG_PLAYER4; - if(strcmp(type, "CIVMALE") == 0) return PED_FLAG_CIVMALE; - if(strcmp(type, "CIVFEMALE") == 0) return PED_FLAG_CIVFEMALE; - if(strcmp(type, "COP") == 0) return PED_FLAG_COP; - if(strcmp(type, "GANG1") == 0) return PED_FLAG_GANG1; - if(strcmp(type, "GANG2") == 0) return PED_FLAG_GANG2; - if(strcmp(type, "GANG3") == 0) return PED_FLAG_GANG3; - if(strcmp(type, "GANG4") == 0) return PED_FLAG_GANG4; - if(strcmp(type, "GANG5") == 0) return PED_FLAG_GANG5; - if(strcmp(type, "GANG6") == 0) return PED_FLAG_GANG6; - if(strcmp(type, "GANG7") == 0) return PED_FLAG_GANG7; - if(strcmp(type, "GANG8") == 0) return PED_FLAG_GANG8; - if(strcmp(type, "GANG9") == 0) return PED_FLAG_GANG9; - if(strcmp(type, "EMERGENCY") == 0) return PED_FLAG_EMERGENCY; - if(strcmp(type, "FIREMAN") == 0) return PED_FLAG_FIREMAN; - if(strcmp(type, "CRIMINAL") == 0) return PED_FLAG_CRIMINAL; - if(strcmp(type, "SPECIAL") == 0) return PED_FLAG_SPECIAL; - if(strcmp(type, "GUN") == 0) return PED_FLAG_GUN; - if(strcmp(type, "COP_CAR") == 0) return PED_FLAG_COP_CAR; - if(strcmp(type, "FAST_CAR") == 0) return PED_FLAG_FAST_CAR; - if(strcmp(type, "EXPLOSION") == 0) return PED_FLAG_EXPLOSION; - if(strcmp(type, "PROSTITUTE") == 0) return PED_FLAG_PROSTITUTE; - if(strcmp(type, "DEADPEDS") == 0) return PED_FLAG_DEADPEDS; - return 0; -} - -void -CPedType::Save(uint8 *buffer, uint32 *length) -{ - int i; - - *length = 8 + NUM_PEDTYPES*32; - - buffer[0] = 'P'; - buffer[1] = 'T'; - buffer[2] = 'P'; - buffer[3] = '\0'; - *(uint32*)(buffer+4) = *length - 8; - buffer += 8; - - for(i = 0; i < NUM_PEDTYPES; i++){ - *(uint32*)(buffer) = ms_apPedType[i]->m_flag; - *(float*)(buffer+4) = ms_apPedType[i]->unknown1; - *(float*)(buffer+8) = ms_apPedType[i]->unknown2; - *(float*)(buffer+12) = ms_apPedType[i]->unknown3; - *(float*)(buffer+16) = ms_apPedType[i]->unknown4; - *(float*)(buffer+20) = ms_apPedType[i]->unknown5; - *(uint32*)(buffer+24) = ms_apPedType[i]->m_threats; - *(uint32*)(buffer+28) = ms_apPedType[i]->m_avoid; - buffer += 32; - } -} - -void -CPedType::Load(uint8 *buffer, uint32 length) -{ - int i; - - assert(length == 8 + NUM_PEDTYPES*32); - assert(buffer[0] == 'P'); - assert(buffer[1] == 'T'); - assert(buffer[2] == 'P'); - assert(buffer[3] == '\0'); - assert(*(uint32*)(buffer+4) == length - 8); - buffer += 8; - - for(i = 0; i < NUM_PEDTYPES; i++){ - ms_apPedType[i]->m_flag = *(uint32*)(buffer); - ms_apPedType[i]->unknown1 = *(float*)(buffer+4); - ms_apPedType[i]->unknown2 = *(float*)(buffer+8); - ms_apPedType[i]->unknown3 = *(float*)(buffer+12); - ms_apPedType[i]->unknown4 = *(float*)(buffer+16); - ms_apPedType[i]->unknown5 = *(float*)(buffer+20); - ms_apPedType[i]->m_threats = *(uint32*)(buffer+24); - ms_apPedType[i]->m_avoid = *(uint32*)(buffer+28); - buffer += 32; - } -} - -STARTPATCHES - InjectHook(0x4EE7E0, &CPedType::Initialise, PATCH_JUMP); - InjectHook(0x4EE890, &CPedType::Shutdown, PATCH_JUMP); - InjectHook(0x4EEC10, &CPedType::FindPedType, PATCH_JUMP); - InjectHook(0x4EEF40, &CPedType::FindPedFlag, PATCH_JUMP); - InjectHook(0x4EF320, &CPedType::Save, PATCH_JUMP); - InjectHook(0x4EF3D0, &CPedType::Load, PATCH_JUMP); -ENDPATCHES diff --git a/src/control/PedType.h b/src/control/PedType.h deleted file mode 100644 index 455d8d8d..00000000 --- a/src/control/PedType.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -// Index into the PedType array -enum -{ - PEDTYPE_PLAYER1, - PEDTYPE_PLAYER2, - PEDTYPE_PLAYER3, - PEDTYPE_PLAYER4, - PEDTYPE_CIVMALE, - PEDTYPE_CIVFEMALE, - PEDTYPE_COP, - PEDTYPE_GANG1, - PEDTYPE_GANG2, - PEDTYPE_GANG3, - PEDTYPE_GANG4, - PEDTYPE_GANG5, - PEDTYPE_GANG6, - PEDTYPE_GANG7, - PEDTYPE_GANG8, - PEDTYPE_GANG9, - PEDTYPE_EMERGENCY, - PEDTYPE_FIREMAN, - PEDTYPE_CRIMINAL, - PEDTYPE_UNUSED1, - PEDTYPE_PROSTITUTE, - PEDTYPE_SPECIAL, - PEDTYPE_UNUSED2, - - NUM_PEDTYPES -}; - -enum -{ - PED_FLAG_PLAYER1 = 1 << 0, - PED_FLAG_PLAYER2 = 1 << 1, - PED_FLAG_PLAYER3 = 1 << 2, - PED_FLAG_PLAYER4 = 1 << 3, - PED_FLAG_CIVMALE = 1 << 4, - PED_FLAG_CIVFEMALE = 1 << 5, - PED_FLAG_COP = 1 << 6, - PED_FLAG_GANG1 = 1 << 7, - PED_FLAG_GANG2 = 1 << 8, - PED_FLAG_GANG3 = 1 << 9, - PED_FLAG_GANG4 = 1 << 10, - PED_FLAG_GANG5 = 1 << 11, - PED_FLAG_GANG6 = 1 << 12, - PED_FLAG_GANG7 = 1 << 13, - PED_FLAG_GANG8 = 1 << 14, - PED_FLAG_GANG9 = 1 << 15, - PED_FLAG_EMERGENCY = 1 << 16, - PED_FLAG_PROSTITUTE = 1 << 17, - PED_FLAG_CRIMINAL = 1 << 18, - PED_FLAG_SPECIAL = 1 << 19, - PED_FLAG_GUN = 1 << 20, - PED_FLAG_COP_CAR = 1 << 21, - PED_FLAG_FAST_CAR = 1 << 22, - PED_FLAG_EXPLOSION = 1 << 23, - PED_FLAG_FIREMAN = 1 << 24, - PED_FLAG_DEADPEDS = 1 << 25, -}; - -class CPedType -{ - uint32 m_flag; - float unknown1; - float unknown2; - float unknown3; - float unknown4; - float unknown5; - uint32 m_threats; - uint32 m_avoid; - - static CPedType *(&ms_apPedType)[NUM_PEDTYPES]; -public: - - static void Initialise(void); - static void Shutdown(void); - static void LoadPedData(void); - static int32 FindPedType(char *type); - static uint32 FindPedFlag(char *type); - static void Save(uint8 *buffer, uint32 *length); - static void Load(uint8 *buffer, uint32 length); - - static uint32 GetFlag(int type) { return ms_apPedType[type]->m_flag; } - static uint32 GetAvoid(int type) { return ms_apPedType[type]->m_avoid; } - static uint32 GetThreats(int type) { return ms_apPedType[type]->m_threats; } -}; - -static_assert(sizeof(CPedType) == 0x20, "CPedType: error"); diff --git a/src/control/PhoneInfo.cpp b/src/control/PhoneInfo.cpp deleted file mode 100644 index dbb7acc5..00000000 --- a/src/control/PhoneInfo.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PhoneInfo.h" - -WRAPPER void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F570); } -WRAPPER void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F470); } \ No newline at end of file diff --git a/src/control/PhoneInfo.h b/src/control/PhoneInfo.h deleted file mode 100644 index a29043ed..00000000 --- a/src/control/PhoneInfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "AnimBlendAssociation.h" - -void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg); -void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg); \ No newline at end of file diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp new file mode 100644 index 00000000..fa4f83e5 --- /dev/null +++ b/src/control/Phones.cpp @@ -0,0 +1,6 @@ +#include "common.h" +#include "patcher.h" +#include "Phones.h" + +WRAPPER void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F570); } +WRAPPER void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x42F470); } diff --git a/src/control/Phones.h b/src/control/Phones.h new file mode 100644 index 00000000..a29043ed --- /dev/null +++ b/src/control/Phones.h @@ -0,0 +1,6 @@ +#pragma once + +#include "AnimBlendAssociation.h" + +void PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg); +void PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg); \ No newline at end of file diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index e166e6b5..06995663 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -16,7 +16,7 @@ #include "ModelInfo.h" #include "Object.h" #include "Pad.h" -#include "PhoneInfo.h" +#include "Phones.h" #include "Pickups.h" #include "Plane.h" #include "Pools.h" @@ -638,7 +638,7 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) if (vehicle->IsCar()){ CAutomobile* car = (CAutomobile*)vehicle; for (int i = 0; i < 4; i++){ - vp->wheel_susp_dist[i] = 50.0f * car->m_aWheelDist[i]; + vp->wheel_susp_dist[i] = 50.0f * car->m_aSuspensionSpringRatio[i]; vp->wheel_rotation[i] = 128.0f / M_PI * car->m_aWheelRotation[i]; } vp->door_angles[0] = 127.0f / M_PI * car->Doors[2].m_fAngle; @@ -683,7 +683,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI if (vehicle->IsCar()) { CAutomobile* car = (CAutomobile*)vehicle; for (int i = 0; i < 4; i++) { - car->m_aWheelDist[i] = vp->wheel_susp_dist[i] / 50.0f; + car->m_aSuspensionSpringRatio[i] = vp->wheel_susp_dist[i] / 50.0f; car->m_aWheelRotation[i] = vp->wheel_rotation[i] * M_PI / 128.0f; } car->Doors[2].m_fAngle = car->Doors[2].m_fPreviousAngle = vp->door_angles[0] * M_PI / 127.0f; diff --git a/src/control/Transmission.cpp b/src/control/Transmission.cpp deleted file mode 100644 index 2be25cbb..00000000 --- a/src/control/Transmission.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Transmission.h" - -void -cTransmission::InitGearRatios(void) -{ - static tGear *pGearRatio0 = nil; - static tGear *pGearRatio1 = nil; - int i; - float velocityDiff; - - memset(Gears, 0, sizeof(Gears)); - - for(i = 1; i <= nNumberOfGears; i++){ - pGearRatio0 = &Gears[i-1]; - pGearRatio1 = &Gears[i]; - - pGearRatio1->fMaxVelocity = (float)i / nNumberOfGears * fMaxVelocity; - - velocityDiff = pGearRatio1->fMaxVelocity - pGearRatio0->fMaxVelocity; - - if(i >= nNumberOfGears){ - pGearRatio1->fShiftUpVelocity = fMaxVelocity; - }else{ - Gears[i+1].fShiftDownVelocity = velocityDiff*0.42f + pGearRatio0->fMaxVelocity; - pGearRatio1->fShiftUpVelocity = velocityDiff*0.6667f + pGearRatio0->fMaxVelocity; - } - } - - // Reverse gear - Gears[0].fMaxVelocity = fMaxReverseVelocity; - Gears[0].fShiftUpVelocity = -0.01f; - Gears[0].fShiftDownVelocity = fMaxReverseVelocity; - - Gears[1].fShiftDownVelocity = -0.01f; -} diff --git a/src/control/Transmission.h b/src/control/Transmission.h deleted file mode 100644 index 686e0aca..00000000 --- a/src/control/Transmission.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -struct tGear -{ - float fMaxVelocity; - float fShiftUpVelocity; - float fShiftDownVelocity; -}; - -class cTransmission -{ -public: - // Gear 0 is reverse, 1-5 are forward - tGear Gears[6]; - char nDriveType; - char nEngineType; - int8 nNumberOfGears; - uint8 Flags; - float fEngineAcceleration; - float fMaxVelocity; - float fUnkMaxVelocity; - float fMaxReverseVelocity; - float field_5C; - - void InitGearRatios(void); -}; diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp new file mode 100644 index 00000000..660be333 --- /dev/null +++ b/src/core/Camera.cpp @@ -0,0 +1,1301 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Draw.h" +#include "World.h" +#include "Vehicle.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "Pad.h" +#include "General.h" +#include "ZoneCull.h" +#include "SurfaceTable.h" +#include "MBlur.h" +#include "Camera.h" + +const float DefaultFOV = 70.0f; // beta: 80.0f + +CCamera &TheCamera = *(CCamera*)0x6FACF8; +bool &CCamera::m_bUseMouse3rdPerson = *(bool *)0x5F03D8; + +WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); } +WRAPPER void CCamera::CalculateDerivedValues(void) { EAXJMP(0x46EEA0); } +WRAPPER void CCamera::Restore(void) { EAXJMP(0x46F990); } +WRAPPER void CCamera::SetWidescreenOff(void) { EAXJMP(0x46FF10); } + +bool +CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat) +{ + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y + radius < CDraw::GetNearClipZ()) return false; + if(c.y - radius > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false; + return true; +} + +bool +CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat) +{ + RwV3d c; + c = *(RwV3d*)¢er; + RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix); + if(c.y < CDraw::GetNearClipZ()) return false; + if(c.y > CDraw::GetFarClipZ()) return false; + if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false; + if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false; + if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false; + if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false; + return true; +} + +bool +CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat) +{ + int i; + int frustumTests[6] = { 0 }; + RwV3dTransformPoints(box, box, 8, &mat->m_matrix); + + for(i = 0; i < 8; i++){ + if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++; + if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++; + if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++; + if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++; +// Why not test z? +// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++; +// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++; + } + for(i = 0; i < 6; i++) + if(frustumTests[i] == 8) + return false; // Box is completely outside of one plane + return true; +} + +int +CCamera::GetLookDirection(void) +{ + if(Cams[ActiveCam].Mode == CCam::MODE_CAMONASTRING || + Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON || + Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT || + Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED) + return Cams[ActiveCam].DirectionWasLooking; + return LOOKING_FORWARD;; +} + +WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); } +WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); } +WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); } + +int +CCamera::GetScreenFadeStatus(void) +{ + if(m_fFLOATingFade == 0.0f) + return FADE_0; + if(m_fFLOATingFade == 255.0f) + return FADE_2; + return FADE_1; +} + +void +CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b) +{ + m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0; + CDraw::FadeRed = r; + CDraw::FadeGreen = g; + CDraw::FadeBlue = b; +} + +void +CCamera::SetMotionBlur(int r, int g, int b, int a, int type) +{ + m_BlurRed = r; + m_BlurGreen = g; + m_BlurBlue = b; + m_motionBlur = a; + m_BlurType = type; +} + +void +CCamera::SetMotionBlurAlpha(int a) +{ + m_imotionBlurAddAlpha = a; +} + +void +CCamera::RenderMotionBlur(void) +{ + if(m_BlurType == 0) + return; + + CMBlur::MotionBlurRender(m_pRwCamera, + m_BlurRed, m_BlurGreen, m_BlurBlue, + m_motionBlur, m_BlurType, m_imotionBlurAddAlpha); +} + + +/* + * + * CCam + * + */ + + +// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms +// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms +void +WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle) +{ + float Delta = Target - *CurrentValue; + + if(IsAngle){ + while(Delta >= PI) Delta -= 2*PI; + while(Delta < -PI) Delta += 2*PI; + } + + float TargetSpeed = Delta * MaxSpeed; + // Add or subtract absolute depending on sign, genius! +// if(TargetSpeed - *CurrentSpeed > 0.0f) +// *CurrentSpeed += Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); +// else +// *CurrentSpeed -= Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); + // this is simpler: + *CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep(); + + // Clamp speed if we overshot + if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed) + *CurrentSpeed = TargetSpeed; + else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed) + *CurrentSpeed = TargetSpeed; + + *CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep()); +} + +void +CCam::GetVectorsReadyForRW(void) +{ + CVector right; + Up = CVector(0.0f, 0.0f, 1.0f); + Front.Normalise(); + if(Front.x == 0.0f && Front.y == 0.0f){ + Front.x = 0.0001f; + Front.y = 0.0001f; + } + right = CrossProduct(Front, Up); + right.Normalise(); + Up = CrossProduct(right, Front); +} + +// This code is really bad. wtf R*? +CVector +CCam::DoAverageOnVector(const CVector &vec) +{ + int i; + CVector Average = { 0.0f, 0.0f, 0.0f }; + + if(ResetStatics){ + m_iRunningVectorArrayPos = 0; + m_iRunningVectorCounter = 1; + } + + // TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2 + if(m_iRunningVectorCounter == 3){ + m_arrPreviousVectors[0] = m_arrPreviousVectors[1]; + m_arrPreviousVectors[1] = vec; + }else + m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec; + + for(i = 0; i <= m_iRunningVectorArrayPos; i++) + Average += m_arrPreviousVectors[i]; + Average /= i; + + m_iRunningVectorArrayPos++; + m_iRunningVectorCounter++; + if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE) + m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1; + if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1) + m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1; + + return Average; +} + +// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps. +// Return the first angle for which Beta + BetaOffset + Angle has a clear view. +// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear. +// If BetaOffset == 0, try both directions. +float +CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies) +{ + CColPoint point; + CEntity *ent = nil; + CVector ToSource; + float a; + + // This would be so much nicer if we just got the step variable before the loop...R* + + for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){ + if(BetaOffset <= 0.0f){ + ToSource = CVector(cos(Beta + BetaOffset + a), sin(Beta + BetaOffset + a), 0.0f)*Dist; + if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, + point, ent, checkBuildings, checkVehicles, checkPeds, + checkObjects, checkDummies, true, true)) + return a; + } + if(BetaOffset >= 0.0f){ + ToSource = CVector(cos(Beta + BetaOffset - a), sin(Beta + BetaOffset - a), 0.0f)*Dist; + if(!CWorld::ProcessLineOfSight(Target, Target + ToSource, + point, ent, checkBuildings, checkVehicles, checkPeds, + checkObjects, checkDummies, true, true)) + return -a; + } + } + return 0.0f; +} + +static float DefaultAcceleration = 0.045f; +static float DefaultMaxStep = 0.15f; + +void +CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + const float GroundDist = 1.85f; + + CVector TargetCoors, Dist, IdealSource; + float Length = 0.0f; + float LateralLeft = 0.0f; + float LateralRight = 0.0f; + float Center = 0.0f; + static bool PreviouslyObscured; + static bool PickedASide; + static float FixedTargetOrientation = 0.0f; + float AngleToGoTo = 0.0f; + float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg + float BetaOffsetGoingBehind = 0.45f; + bool GoingBehind = false; + bool Obscured = false; + bool BuildingCheckObscured = false; + bool HackPlayerOnStoppingTrain = false; + static int TimeIndicatedWantedToGoDown = 0; + static bool StartedCountingForGoDown = false; + float DeltaBeta; + + m_bFixingBeta = false; + bBelowMinDist = false; + bBehindPlayerDesired = false; + + assert(CamTargetEntity->IsPed()); + + // CenterDist should be > LateralDist because we don't have an angle for safety in this case + float CenterDist, LateralDist; + float AngleToGoToSpeed; + if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){ + LateralDist = 0.55f; + CenterDist = 1.25f; + BetaOffsetAvoidBuildings = 0.9f; // ~50 deg + BetaOffsetGoingBehind = 0.9f; + AngleToGoToSpeed = 0.88254666f; + }else{ + LateralDist = 0.8f; + CenterDist = 1.35f; + if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){ + LateralDist = 1.25f; + CenterDist = 1.6f; + } + AngleToGoToSpeed = 0.43254671f; + } + + FOV = DefaultFOV; + + if(ResetStatics){ + Rotating = false; + m_bCollisionChecksOn = true; + FixedTargetOrientation = 0.0f; + PreviouslyObscured = false; + PickedASide = false; + StartedCountingForGoDown = false; + AngleToGoTo = 0.0f; + // unused LastAngleWithNoPickedASide + } + + + TargetCoors = CameraTarget; + IdealSource = Source; + TargetCoors.z += m_fSyphonModeTargetZOffSet; + + CVector TempTargetCoors; + TempTargetCoors = DoAverageOnVector(TargetCoors); + TargetCoors = TempTargetCoors; + // Add this unknown offset, but later it's removed again + TargetCoors.z += m_fUnknownZOffSet; + + Dist.x = IdealSource.x - TargetCoors.x; + Dist.y = IdealSource.y - TargetCoors.y; + Length = Dist.Magnitude2D(); + + // Cam on a string. With a fixed distance. Zoom in/out is done later. + if(Length != 0.0f) + IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist; + else + IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f); + + // TODO: what's transition beta? + if(TheCamera.m_bUseTransitionBeta && ResetStatics){ + CVector VecDistance; + IdealSource.x = TargetCoors.x + GroundDist*cos(m_fTransitionBeta); + IdealSource.y = TargetCoors.y + GroundDist*sin(m_fTransitionBeta); + Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y); + }else + Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y); + + if(TheCamera.m_bCamDirectlyBehind){ + m_bCollisionChecksOn = true; + Beta = TargetOrientation + PI; + } + + if(FindPlayerVehicle()) + if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN) + HackPlayerOnStoppingTrain = true; + + if(TheCamera.m_bCamDirectlyInFront){ + m_bCollisionChecksOn = true; + Beta = TargetOrientation; + } + + while(Beta >= PI) Beta -= 2.0f * PI; + while(Beta < -PI) Beta += 2.0f * PI; + + // BUG? is this ever used? + // The values seem to be roughly m_fPedZoomValueSmooth + 1.85 + if(ResetStatics){ + if(TheCamera.PedZoomIndicator == 1.0) m_fRealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == 2.0) m_fRealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == 3.0) m_fRealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == 4.0) m_fRealGroundDist = 2.090556f; + } + // And what is this? It's only used for collision and rotation it seems + float RealGroundDist; + if(TheCamera.PedZoomIndicator == 1.0) RealGroundDist = 2.090556f; + if(TheCamera.PedZoomIndicator == 2.0) RealGroundDist = 3.34973f; + if(TheCamera.PedZoomIndicator == 3.0) RealGroundDist = 4.704914f; + if(TheCamera.PedZoomIndicator == 4.0) RealGroundDist = 2.090556f; + if(m_fCloseInPedHeightOffset > 0.00001f) + RealGroundDist = 1.7016; + + + bool Shooting = false; + CPed *ped = (CPed*)CamTargetEntity; + if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) + if(CPad::GetPad(0)->GetWeapon()) + Shooting = true; + if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR || + ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT) + Shooting = false; + + + if(m_fCloseInPedHeightOffset > 0.00001f) + TargetCoors.z -= m_fUnknownZOffSet; + + // Figure out if and where we want to rotate + + if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ + + // Center cam behind player + + GoingBehind = true; + m_bCollisionChecksOn = true; + float OriginalBeta = Beta; + // Set Beta behind player + Beta = TargetOrientation + PI; + TargetCoors.z -= 0.1f; + + AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); + if(AngleToGoTo != 0.0f){ + if(AngleToGoTo < 0.0f) + AngleToGoTo -= AngleToGoToSpeed; + else + AngleToGoTo += AngleToGoToSpeed; + }else{ + float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false); + float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false); + if(LateralLeft == 0.0f && LateralRight != 0.0f) + AngleToGoTo += LateralRight; + else if(LateralLeft != 0.0f && LateralRight == 0.0f) + AngleToGoTo += LateralLeft; + } + + TargetCoors.z += 0.1f; + Beta = OriginalBeta; + + if(PickedASide){ + if(AngleToGoTo == 0.0f) + FixedTargetOrientation = TargetOrientation + PI; + Rotating = true; + }else{ + FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo; + Rotating = true; + PickedASide = true; + } + }else{ + + // Rotate cam to avoid clipping into buildings + + TargetCoors.z -= 0.1f; + + Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false); + if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){ + if(Center != 0.0f){ + AngleToGoTo = Center; + }else{ + LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false); + LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false); + if(LateralLeft == 0.0f && LateralRight != 0.0f){ + AngleToGoTo += LateralRight; + if(m_fCloseInPedHeightOffset > 0.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.7f); + }else if(LateralLeft != 0.0f && LateralRight == 0.0f){ + AngleToGoTo += LateralLeft; + if(m_fCloseInPedHeightOffset > 0.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.7f); + } + } + if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f) + BuildingCheckObscured = true; + } + + TargetCoors.z += 0.1f; + } + + if(m_fCloseInPedHeightOffset > 0.00001f) + TargetCoors.z += m_fUnknownZOffSet; + + + // Have to fix to avoid collision + + if(AngleToGoTo != 0.0f){ + Obscured = true; + Rotating = true; + if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){ + if(!PickedASide) + FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen? + }else + FixedTargetOrientation = Beta + AngleToGoTo; + + // This calculation is only really used to figure out how fast to rotate out of collision + + m_fAmountFractionObscured = 1.0f; + CVector PlayerPos = FindPlayerPed()->GetPosition(); + float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist; + // What's going on here? - AngleToGoTo? + CVector RotatedSource = PlayerPos + CVector(cos(Beta - AngleToGoTo), sin(Beta - AngleToGoTo), 0.0f) * RotationDist; + + CColPoint colpoint; + CEntity *entity; + if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){ + if((PlayerPos - RotatedSource).Magnitude() != 0.0f) + m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude(); + else + m_fAmountFractionObscured = 1.0f; + } + } + if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f; + if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f; + + + + // Figure out speed values for Beta rotation + + float Acceleration, MaxSpeed; + static float AccelerationMult = 0.35f; + static float MaxSpeedMult = 0.85f; + static float AccelerationMultClose = 0.7f; + static float MaxSpeedMultClose = 1.6f; + float BaseAcceleration = 0.025f; + float BaseMaxSpeed = 0.09f; + if(m_fCloseInPedHeightOffset > 0.00001f){ + if(AngleToGoTo == 0.0f){ + BaseAcceleration = 0.022f; + BaseMaxSpeed = 0.04f; + }else{ + BaseAcceleration = DefaultAcceleration; + BaseMaxSpeed = DefaultMaxStep; + } + } + if(AngleToGoTo == 0.0f){ + Acceleration = BaseAcceleration; + MaxSpeed = BaseMaxSpeed; + }else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){ + Acceleration = 0.051f; + MaxSpeed = 0.18f; + }else if(m_fCloseInPedHeightOffset > 0.00001f){ + Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f); + MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f); + }else{ + Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f); + MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f); + } + static float AccelerationLimit = 0.3f; + static float MaxSpeedLimit = 0.65f; + if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit; + if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit; + + + int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState; + if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL && + !CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){ + Rotating = false; + BetaSpeed = 0.0f; + } + + // Now do the Beta rotation + + float Distance = (IdealSource - TargetCoors).Magnitude2D(); + m_fDistanceBeforeChanges = Distance; + + if(Rotating){ + m_bFixingBeta = true; + + while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI; + while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI; + + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + +/* + // This is inlined WellBufferMe + DeltaBeta = FixedTargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + + float ReqSpeed = DeltaBeta * MaxSpeed; + // Add or subtract absolute depending on sign, genius! + if(ReqSpeed - BetaSpeed > 0.0f) + BetaSpeed += SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + else + BetaSpeed -= SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep(); + // this would be simpler: + // BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep; + + if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed) + BetaSpeed = ReqSpeed; + else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed) + BetaSpeed = ReqSpeed; + + Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep()); +*/ + WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true); + + if(ResetStatics){ + Beta = FixedTargetOrientation; + BetaSpeed = 0.0f; + } + + Source.x = TargetCoors.x + Distance * cos(Beta); + Source.y = TargetCoors.y + Distance * sin(Beta); + + // Check if we can stop rotating + DeltaBeta = FixedTargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(fabs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){ + // Stop rotation + PickedASide = false; + Rotating = false; + BetaSpeed = 0.0f; + } + } + + + if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || + HackPlayerOnStoppingTrain || Rotating){ + if(TheCamera.m_bCamDirectlyBehind){ + Beta = TargetOrientation + PI; + Source.x = TargetCoors.x + Distance * cos(Beta); + Source.y = TargetCoors.y + Distance * sin(Beta); + } + if(TheCamera.m_bCamDirectlyInFront){ + Beta = TargetOrientation; + Source.x = TargetCoors.x + Distance * cos(Beta); + Source.y = TargetCoors.y + Distance * sin(Beta); + } + if(HackPlayerOnStoppingTrain){ + Beta = TargetOrientation + PI; + Source.x = TargetCoors.x + Distance * cos(Beta); + Source.y = TargetCoors.y + Distance * sin(Beta); + m_fDimensionOfHighestNearCar = 0.0f; + m_fCamBufferedHeight = 0.0f; + m_fCamBufferedHeightSpeed = 0.0f; + } + // Beta and Source already set in the rotation code + }else{ + Source = IdealSource; + BetaSpeed = 0.0f; + } + + // Subtract m_fUnknownZOffSet from both? + TargetCoors.z -= m_fUnknownZOffSet; + Source.z = IdealSource.z - m_fUnknownZOffSet; + + // Apply zoom now + // m_fPedZoomValueSmooth makes the cam go down the further out it is + // 0.25 -> 0.20 for nearest dist + // 1.50 -> -0.05 for mid dist + // 2.90 -> -0.33 for far dist + Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f; + // Zoom out camera + Front = TargetCoors - Source; + Front.Normalise(); + Source -= Front * TheCamera.m_fPedZoomValueSmooth; + // and then we move up again + // -0.375 + // 0.25 + // 0.95 + Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset; + + + // Process height offset to avoid peds and cars + + float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar; + TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset); + float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z; + + if(TargetHeight > m_fCamBufferedHeight){ + // Have to go up + if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false); + else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){ + // TODO: figure this out + bool foo = false; + switch(((CPhysical*)CamTargetEntity)->m_nLastCollType) + case 2: case 3: case 5: + case 11: case 23: case 26: + foo = true; + if(foo) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false); + else + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); + }else + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false); + StartedCountingForGoDown = false; + }else{ + // Have to go down + if(StartedCountingForGoDown){ + if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){ + if(TargetHeight > 0.0f) + WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); + else + WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false); + } + }else{ + StartedCountingForGoDown = true; + TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds(); + } + } + + Source.z += m_fCamBufferedHeight; + + + // Clip Source if necessary + + bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f; + if(GoingBehind || ResetStatics || ClipSource){ + CColPoint colpoint; + CEntity *entity; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){ + Source = colpoint.point; + if((TargetCoors - Source).Magnitude2D() < 1.0f) + RwCameraSetNearClipPlane(Scene.camera, 0.05f); + } + } + + TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f); + m_cvecTargetCoorsForFudgeInter = TargetCoors; + + Front = TargetCoors - Source; + m_fRealGroundDist = Front.Magnitude2D(); + m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist; + Front.Normalise(); + GetVectorsReadyForRW(); + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + PreviouslyObscured = BuildingCheckObscured; + + ResetStatics = false; +} + +void +CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + FOV = DefaultFOV; + + if(!CamTargetEntity->IsVehicle()) + return; + + CVector TargetCoors = CameraTarget; + TargetCoors.z -= 0.2f; + CA_MAX_DISTANCE = 9.95f; + CA_MIN_DISTANCE = 8.5f; + + CVector Dist = Source - TargetCoors; + float Length = Dist.Magnitude2D(); + m_fDistanceBeforeChanges = Length; + if(Length < 0.002f) + Length = 0.002f; + Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); + if(Length > CA_MAX_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; + }else if(Length < CA_MIN_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; + } + TargetCoors.z += 0.8f; + + WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation); + RotCamIfInFrontCar(TargetCoors, TargetOrientation); + FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation); + + Front = TargetCoors - Source; + m_cvecTargetCoorsForFudgeInter = TargetCoors; + ResetStatics = false; + GetVectorsReadyForRW(); +} + +void +CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation) +{ + CColPoint colpoint; + CEntity *ent; + float TargetZOffSet = 0.0f; + static bool PreviouslyFailedRoadHeightCheck = false; + static float RoadHeightFix = 0.0f; + static float RoadHeightFixSpeed = 0.0f; + + if(ResetStatics){ + RoadHeightFix = 0.0f; + RoadHeightFixSpeed = 0.0f; + Alpha = DEGTORAD(25.0f); + AlphaSpeed = 0.0f; + } + float AlphaTarget = DEGTORAD(25.0f); + if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) + AlphaTarget = DEGTORAD(14.0f); + WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true); + Source.z = TargetCoors.z + CA_MAX_DISTANCE*sin(Alpha); + + if(FindPlayerVehicle()){ + m_fUnknownZOffSet = 0.0f; + bool FoundRoad = false; + bool FoundRoof = false; + float RoadZ = 0.0f; + float RoofZ = 0.0f; + + if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && + ent->IsBuilding()){ + FoundRoad = true; + RoadZ = colpoint.point.z; + } + + if(FoundRoad){ + if(Source.z - RoadZ < 0.9f){ + PreviouslyFailedRoadHeightCheck = true; + TargetZOffSet = RoadZ + 0.9f - Source.z; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + TargetZOffSet = 0.0f; + } + }else{ + if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, nil) && + ent->IsBuilding()){ + FoundRoof = true; + RoofZ = colpoint.point.z; + } + if(FoundRoof){ + if(Source.z - RoofZ < 0.9f){ + PreviouslyFailedRoadHeightCheck = true; + TargetZOffSet = RoofZ + 0.9f - Source.z; + }else{ + if(m_bCollisionChecksOn) + PreviouslyFailedRoadHeightCheck = false; + else + TargetZOffSet = 0.0f; + } + } + } + } + + if(TargetZOffSet > RoadHeightFix) + RoadHeightFix = TargetZOffSet; + else + WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false); + + if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) && + colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE && + RoadHeightFix > 1.4f) + RoadHeightFix = 1.4f; + + Source.z += RoadHeightFix; +} + +void +CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight) +{ + static float LastTargetAlphaWithCollisionOn = 0.0f; + static float LastTopAlphaSpeed = 0.0f; + static float LastAlphaSpeedStep = 0.0f; + static bool PreviousNearCheckNearClipSmall = false; + + bool CamClear = true; + float ModeAlpha = 0.0f; + + if(ResetStatics){ + LastTargetAlphaWithCollisionOn = 0.0f; + LastTopAlphaSpeed = 0.0f; + LastAlphaSpeedStep = 0.0f; + PreviousNearCheckNearClipSmall = false; + } + + float TopAlphaSpeed = 0.15f; + float AlphaSpeedStep = 0.015f; + + float zoomvalue = TheCamera.CarZoomValueSmooth; + if(zoomvalue < 0.1f) + zoomvalue = 0.1f; + if(TheCamera.CarZoomIndicator == 1.0f) + ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near + else if(TheCamera.CarZoomIndicator == 2.0f) + ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid + else if(TheCamera.CarZoomIndicator == 3.0f) + ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far + + + float Length = (Source - TargetCoors).Magnitude2D(); + if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised + CVector Forward = CamTargetEntity->GetForward(); + float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z); + // this shouldn't be necessary.... + while(CarAlpha >= PI) CarAlpha -= 2*PI; + while(CarAlpha < -PI) CarAlpha += 2*PI; + + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + float deltaBeta = Beta - TargetOrientation; + while(deltaBeta >= PI) deltaBeta -= 2*PI; + while(deltaBeta < -PI) deltaBeta += 2*PI; + + float BehindCarNess = cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front + CarAlpha = -CarAlpha * BehindCarNess; + if(CarAlpha < -0.01f) + CarAlpha = -0.01f; + + float DeltaAlpha = CarAlpha - Alpha; + while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; + while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; + // What's this?? wouldn't it make more sense to clamp? + float AngleLimit = DEGTORAD(1.8f); + if(DeltaAlpha < -AngleLimit) + DeltaAlpha += AngleLimit; + else if(DeltaAlpha > AngleLimit) + DeltaAlpha -= AngleLimit; + else + DeltaAlpha = 0.0f; + + // Now the collision + + float TargetAlpha = 0.0f; + bool FoundRoofCenter = false; + bool FoundRoofSide1 = false; + bool FoundRoofSide2 = false; + bool FoundCamRoof = false; + bool FoundCamGround = false; + float CamRoof = 0.0f; + float CarBottom = TargetCoors.z - TargetHeight/2.0f; + + // Check car center + float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter); + + // Check sides of the car + Forward = CamTargetEntity->GetForward(); // we actually still have that... + Forward.Normalise(); // shouldn't be necessary + float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f; + float SideX = 2.5f * cos(CarSideAngle); + float SideY = 2.5f * sin(CarSideAngle); + CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1); + CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2); + + // Now find out at what height we'd like to place the camera + float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround); + float CamTargetZ = 0.0f; + if(FoundCamGround){ + // This is the normal case + CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof); + CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f; + }else{ + FoundCamRoof = false; + CamTargetZ = TargetCoors.z; + } + + if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){ + // Car is under something but camera isn't + // This seems weird... + TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f); + CamClear = false; + } + if(FoundCamRoof){ + // Camera is under something + float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof; + // Same weirdness again? + TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f); + CamClear = false; + } + while(TargetAlpha >= PI) TargetAlpha -= 2*PI; + while(TargetAlpha < -PI) TargetAlpha += 2*PI; + if(TargetAlpha < DEGTORAD(-7.0f)) + TargetAlpha = DEGTORAD(-7.0f); + + // huh? + if(TargetAlpha > ModeAlpha) + CamClear = true; + // Camera is contrained by collision in some way + PreviousNearCheckNearClipSmall = false; + if(!CamClear){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha); + while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI; + while(DeltaAlpha < -PI) DeltaAlpha += 2*PI; + + TopAlphaSpeed = 0.3f; + AlphaSpeedStep = 0.03f; + } + + // Now do things if CamClear...but what is that anyway? + float CamZ = TargetCoors.z + Length*sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset; + bool FoundGround, FoundRoof; + float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround); + if(FoundGround){ + if(CamClear) + if(CamZ - CamGround2 < 1.5f){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + float a; + if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f) + a = Alpha; + else + a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z); + while(a > PI) a -= 2*PI; + while(a < -PI) a += 2*PI; + DeltaAlpha = a - Alpha; + } + }else{ + if(CamClear){ + float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof); + if(FoundRoof && CamZ - CamRoof2 < 1.5f){ + PreviousNearCheckNearClipSmall = true; + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + + if(CamRoof2 > TargetCoors.z + 3.5f) + CamRoof2 = TargetCoors.z + 3.5f; + + float a; + if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f) + a = Alpha; + else + a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z); + while(a > PI) a -= 2*PI; + while(a < -PI) a += 2*PI; + DeltaAlpha = a - Alpha; + } + } + } + + LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha; + LastTopAlphaSpeed = TopAlphaSpeed; + LastAlphaSpeedStep = AlphaSpeedStep; + }else{ + if(PreviousNearCheckNearClipSmall) + RwCameraSetNearClipPlane(Scene.camera, 0.9f); + } + + WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true); + + Source.z = TargetCoors.z + sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset; +} + +// Rotate cam behind the car when the car is moving forward +bool +CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation) +{ + bool MovingForward = false; + CPhysical *phys = (CPhysical*)CamTargetEntity; + + float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f))); + if(ForwardSpeed > 0.02f) + MovingForward = true; + + float Dist = (Source - TargetCoors).Magnitude2D(); + + float DeltaBeta = TargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + + if(fabs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0) + m_bFixingBeta = true; + + CPad *pad = CPad::GetPad(0); + if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight())) + if(DirectionWasLooking != LOOKING_FORWARD) + TheCamera.m_bCamDirectlyBehind = true; + + if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront) + return false; + + bool SetBeta = false; + if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta) + if(&TheCamera.Cams[TheCamera.ActiveCam] == this) + SetBeta = true; + + if(m_bFixingBeta || SetBeta){ + WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true); + + if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = TargetOrientation; + if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = TargetOrientation + PI; + if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this) + Beta = m_fTransitionBeta; + + Source.x = TargetCoors.x - cos(Beta)*Dist; + Source.y = TargetCoors.y - sin(Beta)*Dist; + + // Check if we're done + DeltaBeta = TargetOrientation - Beta; + while(DeltaBeta >= PI) DeltaBeta -= 2*PI; + while(DeltaBeta < -PI) DeltaBeta += 2*PI; + if(fabs(DeltaBeta) < DEGTORAD(2.0f)) + m_bFixingBeta = false; + } + TheCamera.m_bCamDirectlyBehind = false; + TheCamera.m_bCamDirectlyInFront = false; + return true; +} + +// Move the cam to avoid clipping through buildings +bool +CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation) +{ + CVector Target = TargetCoors; + bool UseEntityPos = false; + CVector EntityPos; + static CColPoint colPoint; + static bool LastObscured = false; + + if(Mode == MODE_BEHINDCAR) + Target.z += TargetHeight/2.0f; + if(Mode == MODE_CAMONASTRING){ + UseEntityPos = true; + Target.z += TargetHeight/2.0f; + EntityPos = CamTargetEntity->GetPosition(); + } + + CVector TempSource = Source; + + bool Obscured1 = false; + bool Obscured2 = false; + bool Fix1 = false; + float Dist1 = 0.0f; + float Dist2 = 0.0f; + CEntity *ent; + if(m_bCollisionChecksOn || LastObscured){ + Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); + if(Obscured1){ + Dist1 = (Target - colPoint.point).Magnitude2D(); + Fix1 = true; + if(UseEntityPos) + Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); + }else if(m_bFixingBeta){ + float d = (TempSource - Target).Magnitude(); + TempSource.x = Target.x - d*cos(TargetOrientation); + TempSource.y = Target.y - d*sin(TargetOrientation); + + // same check again + Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true); + if(Obscured2){ + Dist2 = (Target - colPoint.point).Magnitude2D(); + if(UseEntityPos) + Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true); + } + } + LastObscured = Obscured1 || Obscured2; + } + + // nothing to do + if(!LastObscured) + return false; + + if(Fix1){ + Source.x = Target.x - cos(Beta)*Dist1; + Source.y = Target.y - sin(Beta)*Dist1; + if(Mode == MODE_BEHINDCAR) + Source = colPoint.point; + }else{ + WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false); + Source.x = Target.x - cos(Beta)*m_fDistanceBeforeChanges; + Source.y = Target.y - sin(Beta)*m_fDistanceBeforeChanges; + } + + if(ResetStatics){ + m_fDistanceBeforeChanges = (Source - Target).Magnitude2D(); + DistanceSpeed = 0.0f; + Source.x = colPoint.point.x; + Source.y = colPoint.point.y; + } + return true; +} + +void +CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float) +{ + if(!CamTargetEntity->IsVehicle()) + return; + + FOV = DefaultFOV; + + if(ResetStatics){ + AlphaSpeed = 0.0f; + if(TheCamera.m_bIdleOn) + TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds(); + } + + CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex()); + CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min; + float BaseDist = Dimensions.Magnitude2D(); + + CVector TargetCoors = CameraTarget; + TargetCoors.z += Dimensions.z - 0.1f; // final + Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y); + while(Alpha >= PI) Alpha -= 2*PI; + while(Alpha < -PI) Alpha += 2*PI; + while(Beta >= PI) Beta -= 2*PI; + while(Beta < -PI) Beta += 2*PI; + + m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D(); + + Cam_On_A_String_Unobscured(TargetCoors, BaseDist); + WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z); + RotCamIfInFrontCar(TargetCoors, TargetOrientation); + FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation); + FixCamWhenObscuredByVehicle(TargetCoors); + + m_cvecTargetCoorsForFudgeInter = TargetCoors; + Front = TargetCoors - Source; + Front.Normalise(); + GetVectorsReadyForRW(); + ResetStatics = false; +} + +// Basic Cam on a string algorithm +void +CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist) +{ + CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth; + CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f); + + CVector Dist = Source - TargetCoors; + + if(ResetStatics) + Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f); + + float Length = Dist.Magnitude2D(); + if(Length < 0.001f){ + // This probably shouldn't happen. reset view + CVector Forward = CamTargetEntity->GetForward(); + Forward.z = 0.0f; + Forward.Normalise(); + Source = TargetCoors - Forward*CA_MAX_DISTANCE; + Dist = Source - TargetCoors; + Length = Dist.Magnitude2D(); + } + + if(Length > CA_MAX_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE; + }else if(Length < CA_MIN_DISTANCE){ + Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE; + Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE; + } +} + +void +CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) +{ + // BUG? is this never reset + static float HeightFixerCarsObscuring = 0.0f; + static float HeightFixerCarsObscuringSpeed = 0.0f; + CColPoint colPoint; + CEntity *entity; + + float HeightTarget = 0.0f; + if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex()); + HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z; + if(HeightTarget < 0.0f) + HeightTarget = 0.0f; + } + WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false); + Source.z += HeightFixerCarsObscuring; +} + +bool +CCam::Using3rdPersonMouseCam() +{ + return CCamera::m_bUseMouse3rdPerson && + (Mode == MODE_FOLLOWPED || + TheCamera.m_bPlayerIsInGarage && + FindPlayerPed() && FindPlayerPed()->m_nPedState != PED_DRIVING && + Mode != MODE_TOPDOWN1 && this->CamTargetEntity == FindPlayerPed()); +} + +bool +CCam::GetWeaponFirstPersonOn() +{ + CEntity *target = this->CamTargetEntity; + if (target && target->IsPed()) + return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; + + return false; +} + +STARTPATCHES + InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP); + InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP); + + InjectHook(0x46FD40, &CCamera::SetMotionBlur, PATCH_JUMP); + InjectHook(0x46FD80, &CCamera::SetMotionBlurAlpha, PATCH_JUMP); + InjectHook(0x46F940, &CCamera::RenderMotionBlur, PATCH_JUMP); + + InjectHook(0x456F40, WellBufferMe, PATCH_JUMP); + InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP); + InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP); + InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP); + InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP); + InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP); + InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP); + InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP); + InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP); + InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP); + + InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP); + InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP); + InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP); + + InjectHook(0x473250, &CCamera::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Camera.h b/src/core/Camera.h new file mode 100644 index 00000000..84c3060b --- /dev/null +++ b/src/core/Camera.h @@ -0,0 +1,476 @@ +#pragma once +#include "Placeable.h" + +class CEntity; +class CPed; +class CAutomobile; + +#define NUMBER_OF_VECTORS_FOR_AVERAGE 2 + +struct CCam +{ + enum + { + MODE_TOPDOWN1 = 1, + MODE_TOPDOWN2, + MODE_BEHINDCAR, + MODE_FOLLOWPED, + MODE_AIMING, + MODE_DEBUG, + MODE_SNIPER, + MODE_ROCKET, + MODE_MODELVIEW, + MODE_BILL, + MODE_SYPHON, + MODE_CIRCLE, + MODE_CHEESYZOOM, + MODE_WHEELCAM, + MODE_FIXED, + MODE_FIRSTPERSON, + MODE_FLYBY, + MODE_CAMONASTRING, + MODE_REACTIONCAM, + MODE_FOLLOWPEDWITHBINDING, + MODE_CHRISWITHBINDINGPLUSROTATION, + MODE_BEHINDBOAT, + MODE_PLAYERFALLENWATER, + MODE_CAMONTRAINROOF, + MODE_CAMRUNNINGSIDETRAIN, + MODE_BLOODONTHETRACKS, + MODE_IMTHEPASSENGERWOOWOO, + MODE_SYPHONCRIMINFRONT, + MODE_PEDSDEADBABY, + MODE_CUSHYPILLOWSARSE, + MODE_LOOKATCARS, + MODE_ARRESTCAMONE, + MODE_ARRESTCAMTWO, + MODE_M16FIRSTPERSON_34, + MODE_SPECIALFIXEDFORSYPHON, + MODE_FIGHT, + MODE_TOPDOWNPED, + MODE_SNIPER_RUN_AROUND, + MODE_ROCKET_RUN_AROUND, + MODE_FIRSTPERSONPEDONPC_40, + MODE_FIRSTPERSONPEDONPC_41, + MODE_FIRSTPERSONPEDONPC_42, + MODE_EDITOR, + MODE_M16FIRSTPERSON_44 + }; + + bool bBelowMinDist; //used for follow ped mode + bool bBehindPlayerDesired; //used for follow ped mode + bool m_bCamLookingAtVector; + bool m_bCollisionChecksOn; + bool m_bFixingBeta; //used for camera on a string + bool m_bTheHeightFixerVehicleIsATrain; + bool LookBehindCamWasInFront; + bool LookingBehind; + bool LookingLeft; // 32 + bool LookingRight; + bool ResetStatics; //for interpolation type stuff to work + bool Rotating; + + int16 Mode; // CameraMode + uint32 m_uiFinishTime; // 52 + + int m_iDoCollisionChecksOnFrameNum; + int m_iDoCollisionCheckEveryNumOfFrames; + int m_iFrameNumWereAt; // 64 + int m_iRunningVectorArrayPos; + int m_iRunningVectorCounter; + int DirectionWasLooking; + + float f_max_role_angle; //=DEGTORAD(5.0f); + float f_Roll; //used for adding a slight roll to the camera in the + float f_rollSpeed; + float m_fSyphonModeTargetZOffSet; + float m_fUnknownZOffSet; + float m_fAmountFractionObscured; + float m_fAlphaSpeedOverOneFrame; // 100 + float m_fBetaSpeedOverOneFrame; + float m_fBufferedTargetBeta; + float m_fBufferedTargetOrientation; + float m_fBufferedTargetOrientationSpeed; + float m_fCamBufferedHeight; + float m_fCamBufferedHeightSpeed; + float m_fCloseInPedHeightOffset; + float m_fCloseInPedHeightOffsetSpeed; // 132 + float m_fCloseInCarHeightOffset; + float m_fCloseInCarHeightOffsetSpeed; + float m_fDimensionOfHighestNearCar; + float m_fDistanceBeforeChanges; + float m_fFovSpeedOverOneFrame; + float m_fMinDistAwayFromCamWhenInterPolating; + float m_fPedBetweenCameraHeightOffset; + float m_fPlayerInFrontSyphonAngleOffSet; // 164 + float m_fRadiusForDead; + float m_fRealGroundDist; //used for follow ped mode + float m_fTargetBeta; + float m_fTimeElapsedFloat; + + float m_fTransitionBeta; + float m_fTrueBeta; + float m_fTrueAlpha; // 200 + float m_fInitialPlayerOrientation; //used for first person + + float Alpha; + float AlphaSpeed; + float FOV; + float FOVSpeed; + float Beta; + float BetaSpeed; + float Distance; // 232 + float DistanceSpeed; + float CA_MIN_DISTANCE; + float CA_MAX_DISTANCE; + float SpeedVar; + + // ped onfoot zoom distance + float m_fTargetZoomGroundOne; + float m_fTargetZoomGroundTwo; // 256 + float m_fTargetZoomGroundThree; + // ped onfoot alpha angle offset + float m_fTargetZoomOneZExtra; + float m_fTargetZoomTwoZExtra; + float m_fTargetZoomThreeZExtra; + + float m_fTargetZoomZCloseIn; + float m_fMinRealGroundDist; + float m_fTargetCloseInDist; + + CVector m_cvecTargetCoorsForFudgeInter; // 360 + CVector m_cvecCamFixedModeVector; // 372 + CVector m_cvecCamFixedModeSource; // 384 + CVector m_cvecCamFixedModeUpOffSet; // 396 + CVector m_vecLastAboveWaterCamPosition; //408 //helper for when the player has gone under the water + CVector m_vecBufferedPlayerBodyOffset; // 420 + + // The three vectors that determine this camera for this frame + CVector Front; // 432 // Direction of looking in + CVector Source; // Coors in world space + CVector SourceBeforeLookBehind; + CVector Up; // Just that + CVector m_arrPreviousVectors[NUMBER_OF_VECTORS_FOR_AVERAGE]; // used to average stuff + CEntity *CamTargetEntity; + + float m_fCameraDistance; + float m_fIdealAlpha; + float m_fPlayerVelocity; + CAutomobile *m_pLastCarEntered; // So interpolation works + CPed *m_pLastPedLookedAt;// So interpolation works + bool m_bFirstPersonRunAboutActive; + + + void GetVectorsReadyForRW(void); + CVector DoAverageOnVector(const CVector &vec); + float GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies); + void WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation); + void WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight); + bool RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation); + bool FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation); + void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist); + void FixCamWhenObscuredByVehicle(const CVector &TargetCoors); + bool Using3rdPersonMouseCam(); + bool GetWeaponFirstPersonOn(); + + void Process_Debug(float *vec, float a, float b, float c); + void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float); + void Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float); +}; +static_assert(sizeof(CCam) == 0x1A4, "CCam: wrong size"); +static_assert(offsetof(CCam, Alpha) == 0xA8, "CCam: error"); +static_assert(offsetof(CCam, Front) == 0x140, "CCam: error"); + +struct CCamPathSplines +{ + float m_arr_PathData[800]; +}; + +struct CTrainCamNode +{ + CVector m_cvecCamPosition; + CVector m_cvecPointToLookAt; + CVector m_cvecMinPointInRange; + CVector m_cvecMaxPointInRange; + float m_fDesiredFOV; + float m_fNearClip; +}; + +struct CQueuedMode +{ + int16 Mode; + float Duration; + int16 MinZoom; + int16 MaxZoom; +}; + +enum +{ + LOOKING_BEHIND, + LOOKING_LEFT, + LOOKING_RIGHT, + LOOKING_FORWARD, +}; + +enum +{ + // TODO: figure out + FADE_0, + FADE_1, // mid fade + FADE_2, + + FADE_OUT = 0, + FADE_IN, +}; + +enum +{ + MBLUR_NONE, + MBLUR_SNIPER, + MBLUR_NORMAL, + MBLUR_INTRO1, // green camera + MBLUR_INTRO2, // unused + MBLUR_INTRO3, // bank scene + MBLUR_INTRO4, // jail break scene + MBLUR_INTRO5, // explosion + MBLUR_INTRO6, // player shot + MBLUR_UNUSED, // pinkish +}; + +struct CCamera : public CPlaceable +{ + bool m_bAboveGroundTrainNodesLoaded; + bool m_bBelowGroundTrainNodesLoaded; + bool m_bCamDirectlyBehind; + bool m_bCamDirectlyInFront; + bool m_bCameraJustRestored; + bool m_bcutsceneFinished; + bool m_bCullZoneChecksOn; + bool m_bFirstPersonBeingUsed; + bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; + bool m_bIdleOn; + bool m_bInATunnelAndABigVehicle; + bool m_bInitialNodeFound; + bool m_bInitialNoNodeStaticsSet; + bool m_bIgnoreFadingStuffForMusic; + bool m_bPlayerIsInGarage; + bool m_bJustCameOutOfGarage; + bool m_bJustInitalised; + bool m_bJust_Switched; + bool m_bLookingAtPlayer; + bool m_bLookingAtVector; + bool m_bMoveCamToAvoidGeom; + bool m_bObbeCinematicPedCamOn; + bool m_bObbeCinematicCarCamOn; + bool m_bRestoreByJumpCut; + bool m_bUseNearClipScript; + bool m_bStartInterScript; + bool m_bStartingSpline; + bool m_bTargetJustBeenOnTrain; + bool m_bTargetJustCameOffTrain; + bool m_bUseSpecialFovTrain; + bool m_bUseTransitionBeta; + bool m_bUseScriptZoomValuePed; + bool m_bUseScriptZoomValueCar; + bool m_bWaitForInterpolToFinish; + bool m_bItsOkToLookJustAtThePlayer; + bool m_bWantsToSwitchWidescreenOff; + bool m_WideScreenOn; + bool m_1rstPersonRunCloseToAWall; + bool m_bHeadBob; + bool m_bFailedCullZoneTestPreviously; + +bool m_FadeTargetIsSplashScreen; + + bool WorldViewerBeingUsed; + uint8 ActiveCam; + uint32 m_uiCamShakeStart; + uint32 m_uiFirstPersonCamLastInputTime; +// where are those? +//bool m_bVehicleSuspenHigh; +//bool m_bEnable1rstPersonCamCntrlsScript; +//bool m_bAllow1rstPersonWeaponsCamera; + + uint32 m_uiLongestTimeInMill; + uint32 m_uiNumberOfTrainCamNodes; + uint8 m_uiTransitionJUSTStarted; + uint8 m_uiTransitionState; // 0:one mode 1:transition + + uint32 m_uiTimeLastChange; + uint32 m_uiTimeWeEnteredIdle; + uint32 m_uiTimeTransitionStart; + uint32 m_uiTransitionDuration; + int m_BlurBlue; + int m_BlurGreen; + int m_BlurRed; + int m_BlurType; + +uint32 unknown; + int m_iWorkOutSpeedThisNumFrames; + int m_iNumFramesSoFar; + + + int m_iCurrentTrainCamNode; + int m_motionBlur; + int m_imotionBlurAddAlpha; + int m_iCheckCullZoneThisNumFrames; + int m_iZoneCullFrameNumWereAt; + int WhoIsInControlOfTheCamera; + + float CamFrontXNorm; + float CamFrontYNorm; + float CarZoomIndicator; + float CarZoomValue; + float CarZoomValueSmooth; + + float DistanceToWater; + float FOVDuringInter; + float LODDistMultiplier; + float GenerationDistMultiplier; + float m_fAlphaSpeedAtStartInter; + float m_fAlphaWhenInterPol; + float m_fAlphaDuringInterPol; + float m_fBetaDuringInterPol; + float m_fBetaSpeedAtStartInter; + float m_fBetaWhenInterPol; + float m_fFOVWhenInterPol; + float m_fFOVSpeedAtStartInter; + float m_fStartingBetaForInterPol; + float m_fStartingAlphaForInterPol; + float m_PedOrientForBehindOrInFront; + float m_CameraAverageSpeed; + float m_CameraSpeedSoFar; + float m_fCamShakeForce; + float m_fCarZoomValueScript; + float m_fFovForTrain; + float m_fFOV_Wide_Screen; + float m_fNearClipScript; + float m_fOldBetaDiff; + float m_fPedZoomValue; + + float m_fPedZoomValueScript; + float m_fPedZoomValueSmooth; + float m_fPositionAlongSpline; + float m_ScreenReductionPercentage; + float m_ScreenReductionSpeed; + float m_AlphaForPlayerAnim1rstPerson; + float Orientation; + float PedZoomIndicator; + float PlayerExhaustion; + float SoundDistUp, SoundDistLeft, SoundDistRight; + float SoundDistUpAsRead, SoundDistLeftAsRead, SoundDistRightAsRead; + float SoundDistUpAsReadOld, SoundDistLeftAsReadOld, SoundDistRightAsReadOld; + float m_fWideScreenReductionAmount; + float m_fStartingFOVForInterPol; + + // not static yet + float m_fMouseAccelHorzntl;// acceleration multiplier for 1st person controls + float m_fMouseAccelVertical;// acceleration multiplier for 1st person controls + float m_f3rdPersonCHairMultX; + float m_f3rdPersonCHairMultY; + + + CCam Cams[3]; + void *pToGarageWeAreIn; + void *pToGarageWeAreInForHackAvoidFirstPerson; + CQueuedMode m_PlayerMode; + CQueuedMode PlayerWeaponMode; + CVector m_PreviousCameraPosition; + CVector m_RealPreviousCameraPosition; + CVector m_cvecAimingTargetCoors; + CVector m_vecFixedModeVector; + + // one of those has to go + CVector m_vecFixedModeSource; + CVector m_vecFixedModeUpOffSet; +// CVector m_vecCutSceneOffset; + CVector m_cvecStartingSourceForInterPol; + CVector m_cvecStartingTargetForInterPol; + CVector m_cvecStartingUpForInterPol; + CVector m_cvecSourceSpeedAtStartInter; + CVector m_cvecTargetSpeedAtStartInter; + CVector m_cvecUpSpeedAtStartInter; + CVector m_vecSourceWhenInterPol; + CVector m_vecTargetWhenInterPol; + CVector m_vecUpWhenInterPol; + CVector m_vecClearGeometryVec; + + CVector m_vecGameCamPos; + CVector SourceDuringInter; + CVector TargetDuringInter; + CVector UpDuringInter; + RwCamera *m_pRwCamera; + CEntity *pTargetEntity; + CCamPathSplines m_arrPathArray[4]; + CTrainCamNode m_arrTrainCamNode[800]; + CMatrix m_cameraMatrix; + bool m_bGarageFixedCamPositionSet; + bool m_vecDoingSpecialInterPolation; + bool m_bScriptParametersSetForInterPol; + bool m_bFading; + bool m_bMusicFading; + CMatrix m_viewMatrix; + CVector m_vecFrustumNormals[4]; + CVector m_vecOldSourceForInter; + CVector m_vecOldFrontForInter; + CVector m_vecOldUpForInter; + + float m_vecOldFOVForInter; + float m_fFLOATingFade; + float m_fFLOATingFadeMusic; + float m_fTimeToFadeOut; + float m_fTimeToFadeMusic; + float m_fFractionInterToStopMovingTarget; + float m_fFractionInterToStopCatchUpTarget; + float m_fGaitSwayBuffer; + float m_fScriptPercentageInterToStopMoving; + float m_fScriptPercentageInterToCatchUp; + +uint32 m_fScriptTimeForInterPolation; + + +int16 m_iFadingDirection; +int m_iModeObbeCamIsInForCar; + int16 m_iModeToGoTo; + int16 m_iMusicFadingDirection; + int16 m_iTypeOfSwitch; + + uint32 m_uiFadeTimeStarted; + uint32 m_uiFadeTimeStartedMusic; + + static bool &m_bUseMouse3rdPerson; + + CMatrix &GetCameraMatrix(void) { return m_cameraMatrix; } + CVector &GetGameCamPosition(void) { return m_vecGameCamPos; } + bool IsPointVisible(const CVector ¢er, const CMatrix *mat); + bool IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat); + bool IsBoxVisible(RwV3d *box, const CMatrix *mat); + int GetLookDirection(void); + + void Fade(float timeout, int16 direction); + int GetScreenFadeStatus(void); + void ProcessFade(void); + void ProcessMusicFade(void); + void SetFadeColour(uint8 r, uint8 g, uint8 b); + + void SetMotionBlur(int r, int g, int b, int a, int type); + void SetMotionBlurAlpha(int a); + void RenderMotionBlur(void); + void CalculateDerivedValues(void); + + void DrawBordersForWideScreen(void); + void Restore(void); + void SetWidescreenOff(void); + + void dtor(void) { this->CCamera::~CCamera(); } +}; +static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error"); +static_assert(offsetof(CCamera, WorldViewerBeingUsed) == 0x75, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiNumberOfTrainCamNodes) == 0x84, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiTransitionState) == 0x89, "CCamera: error"); +static_assert(offsetof(CCamera, m_uiTimeTransitionStart) == 0x94, "CCamera: error"); +static_assert(offsetof(CCamera, m_BlurBlue) == 0x9C, "CCamera: error"); +static_assert(offsetof(CCamera, Cams) == 0x1A4, "CCamera: error"); +static_assert(sizeof(CCamera) == 0xE9D8, "CCamera: wrong size"); +extern CCamera &TheCamera; diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp new file mode 100644 index 00000000..255e46bb --- /dev/null +++ b/src/core/CdStream.cpp @@ -0,0 +1,529 @@ +#include +#include "common.h" +#include "patcher.h" +#include "CdStream.h" +#include "rwcore.h" +#include "RwHelper.h" + +#define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", __VA_ARGS__) +#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", __VA_ARGS__) + +struct CdReadInfo +{ + uint32 nSectorOffset; + uint32 nSectorsToRead; + void *pBuffer; + char field_C; + bool bLocked; + bool bInUse; + char _pad0; + int32 nStatus; + HANDLE hSemaphore; + HANDLE hFile; + OVERLAPPED Overlapped; +}; +VALIDATE_SIZE(CdReadInfo, 0x30); + +char gCdImageNames[MAX_CDIMAGES+1][64]; +int32 gNumImages; +int32 gNumChannels; + +HANDLE gImgFiles[MAX_CDIMAGES]; + +HANDLE _gCdStreamThread; +HANDLE gCdStreamSema; +DWORD _gCdStreamThreadId; + +CdReadInfo *gpReadInfo; +Queue gChannelRequestQ; + +int32 lastPosnRead; + +BOOL _gbCdStreamOverlapped; +BOOL _gbCdStreamAsync; +DWORD _gdwCdStreamFlags; + + +void +CdStreamInitThread(void) +{ + SetLastError(0); + + if ( gNumChannels > 0 ) + { + for ( int32 i = 0; i < gNumChannels; i++ ) + { + gpReadInfo[i].hSemaphore = CreateSemaphore(nil, 0, 2, nil); + + if ( gpReadInfo[i].hSemaphore == nil ) + { + CDTRACE("failed to create sync semaphore"); + ASSERT(0); + return; + } + } + } + + gChannelRequestQ.items = (int32 *)LocalAlloc(LMEM_ZEROINIT, sizeof(int32) * (gNumChannels + 1)); + gChannelRequestQ.head = 0; + gChannelRequestQ.tail = 0; + gChannelRequestQ.size = gNumChannels + 1; + ASSERT(gChannelRequestQ.items != nil ); + + gCdStreamSema = CreateSemaphore(nil, 0, 5, "CdStream"); + + if ( gCdStreamSema == nil ) + { + CDTRACE("failed to create stream semaphore"); + ASSERT(0); + return; + } + + _gCdStreamThread = CreateThread(nil, 64*1024/*64KB*/, CdStreamThread, nil, CREATE_SUSPENDED, &_gCdStreamThreadId); + + if ( _gCdStreamThread == nil ) + { + CDTRACE("failed to create streaming thread"); + ASSERT(0); + return; + } + + SetThreadPriority(_gCdStreamThread, GetThreadPriority(GetCurrentThread()) - 1); + + ResumeThread(_gCdStreamThread); +} + +void +CdStreamInit(int32 numChannels) +{ + DWORD SectorsPerCluster; + DWORD BytesPerSector; + DWORD NumberOfFreeClusters; + DWORD TotalNumberOfClusters; + + GetDiskFreeSpace(nil, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters); + + _gdwCdStreamFlags = 0; + + if ( BytesPerSector <= CDSTREAM_SECTOR_SIZE ) + { + _gdwCdStreamFlags |= FILE_FLAG_NO_BUFFERING; + debug("Using no buffered loading for streaming\n"); + } + + _gbCdStreamOverlapped = TRUE; + + _gdwCdStreamFlags |= FILE_FLAG_OVERLAPPED; + + _gbCdStreamAsync = FALSE; + + void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, BytesPerSector); + ASSERT( pBuffer != nil ); + + SetLastError(0); + + gNumImages = 0; + + gNumChannels = numChannels; + + gpReadInfo = (CdReadInfo *)LocalAlloc(LMEM_ZEROINIT, sizeof(CdReadInfo) * numChannels); + ASSERT( gpReadInfo != nil ); + + CDDEBUG("read info %p", gpReadInfo); + + CdStreamAddImage("MODELS\\GTA3.IMG"); + + int32 nStatus = CdStreamRead(0, pBuffer, 0, 1); + + CdStreamRemoveImages(); + + if ( nStatus == STREAM_SUCCESS ) + { + _gbCdStreamAsync = TRUE; + + debug("Using async loading for streaming\n"); + } + else + { + _gdwCdStreamFlags &= ~FILE_FLAG_OVERLAPPED; + + _gbCdStreamOverlapped = FALSE; + + _gbCdStreamAsync = TRUE; + + debug("Using sync loading for streaming\n"); + } + + CdStreamInitThread(); + + ASSERT( pBuffer != nil ); + RwFreeAlign(pBuffer); +} + +uint32 +GetGTA3ImgSize(void) +{ + ASSERT( gImgFiles[0] != nil ); + return (uint32)GetFileSize(gImgFiles[0], nil); +} + +void +CdStreamShutdown(void) +{ + if ( _gbCdStreamAsync ) + { + LocalFree(gChannelRequestQ.items); + CloseHandle(gCdStreamSema); + CloseHandle(_gCdStreamThread); + + for ( int32 i = 0; i < gNumChannels; i++ ) + CloseHandle(gpReadInfo[i].hSemaphore); + } + + LocalFree(gpReadInfo); +} + + + +int32 +CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) +{ + ASSERT( channel < gNumChannels ); + ASSERT( buffer != nil ); + + lastPosnRead = size + offset; + + ASSERT( _GET_INDEX(offset) < MAX_CDIMAGES ); + HANDLE hImage = gImgFiles[_GET_INDEX(offset)]; + ASSERT( hImage != nil ); + + + CdReadInfo *pChannel = &gpReadInfo[channel]; + ASSERT( pChannel != nil ); + + pChannel->hFile = hImage; + + SetLastError(0); + + if ( _gbCdStreamAsync ) + { + if ( pChannel->nSectorsToRead != 0 || pChannel->bInUse ) + return STREAM_NONE; + + pChannel->nStatus = STREAM_NONE; + pChannel->nSectorOffset = _GET_OFFSET(offset); + pChannel->nSectorsToRead = size; + pChannel->pBuffer = buffer; + pChannel->bLocked = 0; + + AddToQueue(&gChannelRequestQ, channel); + + if ( !ReleaseSemaphore(gCdStreamSema, 1, nil) ) + printf("Signal Sema Error\n"); + + return STREAM_SUCCESS; + } + + if ( _gbCdStreamOverlapped ) + { + ASSERT( channel < gNumChannels ); + CdReadInfo *pChannel = &gpReadInfo[channel]; + ASSERT( pChannel != nil ); + + pChannel->Overlapped.Offset = _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE; + + if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, NULL, &pChannel->Overlapped) + && GetLastError() != ERROR_IO_PENDING ) + return STREAM_NONE; + else + return STREAM_SUCCESS; + } + + SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN); + + DWORD NumberOfBytesRead; + + if ( !ReadFile(hImage, buffer, size * CDSTREAM_SECTOR_SIZE, &NumberOfBytesRead, nil) ) + return STREAM_NONE; + else + return STREAM_SUCCESS; +} + +int32 +CdStreamGetStatus(int32 channel) +{ + ASSERT( channel < gNumChannels ); + CdReadInfo *pChannel = &gpReadInfo[channel]; + ASSERT( pChannel != nil ); + + if ( _gbCdStreamAsync ) + { + if ( pChannel->bInUse ) + return STREAM_READING; + + if ( pChannel->nSectorsToRead != 0 ) + return STREAM_WAITING; + + if ( pChannel->nStatus != STREAM_NONE ) + { + int32 status = pChannel->nStatus; + + pChannel->nStatus = STREAM_NONE; + + return status; + } + + return STREAM_NONE; + } + + if ( _gbCdStreamOverlapped ) + { + ASSERT( pChannel->hFile != nil ); + if ( WaitForSingleObjectEx(pChannel->hFile, 0, TRUE) == WAIT_OBJECT_0 ) + return STREAM_NONE; + else + return STREAM_READING; + } + + return STREAM_NONE; +} + +int32 +CdStreamGetLastPosn(void) +{ + return lastPosnRead; +} + +int32 +CdStreamSync(int32 channel) +{ + ASSERT( channel < gNumChannels ); + CdReadInfo *pChannel = &gpReadInfo[channel]; + ASSERT( pChannel != nil ); + + if ( _gbCdStreamAsync ) + { + if ( pChannel->nSectorsToRead != 0 ) + { + pChannel->bLocked = true; + + ASSERT( pChannel->hSemaphore != nil ); + + WaitForSingleObject(pChannel->hSemaphore, INFINITE); + } + + pChannel->bInUse = false; + + return pChannel->nStatus; + } + + DWORD NumberOfBytesTransferred; + + if ( _gbCdStreamOverlapped && pChannel->hFile ) + { + ASSERT(pChannel->hFile != nil ); + if ( GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) ) + return STREAM_NONE; + else + return STREAM_ERROR; + } + + return STREAM_NONE; +} + +void +AddToQueue(Queue *queue, int32 item) +{ + ASSERT( queue != nil ); + ASSERT( queue->items != nil ); + queue->items[queue->tail] = item; + + queue->tail = (queue->tail + 1) % queue->size; + + if ( queue->head == queue->tail ) + debug("Queue is full\n"); +} + +int32 +GetFirstInQueue(Queue *queue) +{ + ASSERT( queue != nil ); + if ( queue->head == queue->tail ) + return -1; + + ASSERT( queue->items != nil ); + return queue->items[queue->head]; +} + +void +RemoveFirstInQueue(Queue *queue) +{ + ASSERT( queue != nil ); + if ( queue->head == queue->tail ) + { + debug("Queue is empty\n"); + return; + } + + queue->head = (queue->head + 1) % queue->size; +} + +DWORD +WINAPI CdStreamThread(LPVOID lpThreadParameter) +{ + debug("Created cdstream thread\n"); + + while ( true ) + { + WaitForSingleObject(gCdStreamSema, INFINITE); + + int32 channel = GetFirstInQueue(&gChannelRequestQ); + ASSERT( channel < gNumChannels ); + + CdReadInfo *pChannel = &gpReadInfo[channel]; + ASSERT( pChannel != nil ); + + pChannel->bInUse = true; + + if ( pChannel->nStatus == STREAM_NONE ) + { + if ( _gbCdStreamOverlapped ) + { + pChannel->Overlapped.Offset = pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE; + + ASSERT(pChannel->hFile != nil ); + ASSERT(pChannel->pBuffer != nil ); + + DWORD NumberOfBytesTransferred; + + if ( ReadFile(pChannel->hFile, + pChannel->pBuffer, + pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE, + NULL, + &pChannel->Overlapped) ) + { + pChannel->nStatus = STREAM_NONE; + } + else if ( GetLastError() == ERROR_IO_PENDING + && GetOverlappedResult(pChannel->hFile, &pChannel->Overlapped, &NumberOfBytesTransferred, TRUE) ) + { + pChannel->nStatus = STREAM_NONE; + } + else + { + pChannel->nStatus = STREAM_ERROR; + } + } + else + { + ASSERT(pChannel->hFile != nil ); + ASSERT(pChannel->pBuffer != nil ); + + SetFilePointer(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN); + + DWORD NumberOfBytesRead; + if ( ReadFile(pChannel->hFile, + pChannel->pBuffer, + pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE, + &NumberOfBytesRead, + NULL) ) + { + pChannel->nStatus = STREAM_NONE; + } + } + } + + RemoveFirstInQueue(&gChannelRequestQ); + + pChannel->nSectorsToRead = 0; + + if ( pChannel->bLocked ) + { + ASSERT( pChannel->hSemaphore != nil ); + ReleaseSemaphore(pChannel->hSemaphore, 1, NULL); + } + + pChannel->bInUse = false; + } +} + +bool +CdStreamAddImage(char const *path) +{ + ASSERT(path != nil); + ASSERT(gNumImages < MAX_CDIMAGES); + + SetLastError(0); + + gImgFiles[gNumImages] = CreateFile(path, + GENERIC_READ, + FILE_SHARE_READ, + nil, + OPEN_EXISTING, + _gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY, + nil); + + ASSERT( gImgFiles[gNumImages] != nil ); + if ( gImgFiles[gNumImages] == NULL ) + return false; + + strcpy(gCdImageNames[gNumImages], path); + + gNumImages++; + + return true; +} + +char * +CdStreamGetImageName(int32 cd) +{ + ASSERT(cd < MAX_CDIMAGES); + if ( gImgFiles[cd] != nil ) + return gCdImageNames[cd]; + + return nil; +} + +void +CdStreamRemoveImages(void) +{ + for ( int32 i = 0; i < gNumChannels; i++ ) + CdStreamSync(i); + + for ( int32 i = 0; i < gNumImages; i++ ) + { + SetLastError(0); + + CloseHandle(gImgFiles[i]); + gImgFiles[i] = nil; + } + + gNumImages = 0; +} + +int32 +CdStreamGetNumImages(void) +{ + return gNumImages; +} + + +STARTPATCHES + InjectHook(0x405B50, CdStreamInitThread, PATCH_JUMP); + InjectHook(0x405C80, CdStreamInit, PATCH_JUMP); + //InjectHook(0x405DB0, debug, PATCH_JUMP); + InjectHook(0x405DC0, GetGTA3ImgSize, PATCH_JUMP); + InjectHook(0x405DD0, CdStreamShutdown, PATCH_JUMP); + InjectHook(0x405E40, CdStreamRead, PATCH_JUMP); + InjectHook(0x405F90, CdStreamGetStatus, PATCH_JUMP); + InjectHook(0x406000, CdStreamGetLastPosn, PATCH_JUMP); + InjectHook(0x406010, CdStreamSync, PATCH_JUMP); + InjectHook(0x4060B0, AddToQueue, PATCH_JUMP); + InjectHook(0x4060F0, GetFirstInQueue, PATCH_JUMP); + InjectHook(0x406110, RemoveFirstInQueue, PATCH_JUMP); + InjectHook(0x406140, CdStreamThread, PATCH_JUMP); + InjectHook(0x406270, CdStreamAddImage, PATCH_JUMP); + InjectHook(0x4062E0, CdStreamGetImageName, PATCH_JUMP); + InjectHook(0x406300, CdStreamRemoveImages, PATCH_JUMP); + InjectHook(0x406370, CdStreamGetNumImages, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/core/CdStream.h b/src/core/CdStream.h new file mode 100644 index 00000000..55507aa8 --- /dev/null +++ b/src/core/CdStream.h @@ -0,0 +1,46 @@ +#pragma once + +#define CDSTREAM_SECTOR_SIZE 2048 + +#define _GET_INDEX(a) (a >> 24) +#define _GET_OFFSET(a) (a & 0xFFFFFF) + +enum +{ + STREAM_NONE = uint8( 0), + STREAM_SUCCESS = uint8( 1), + STREAM_READING = uint8(-1), // 0xFF, + STREAM_ERROR = uint8(-2), // 0xFE, + STREAM_ERROR_NOCD = uint8(-3), // 0xFD, + STREAM_ERROR_WRONGCD = uint8(-4), // 0xFC, + STREAM_ERROR_OPENCD = uint8(-5), // 0xFB, + STREAM_WAITING = uint8(-6) // 0xFA, +}; + +struct Queue +{ + int32 *items; + int32 head; + int32 tail; + int32 size; +}; + +VALIDATE_SIZE(Queue, 0x10); + + +void CdStreamInitThread(void); +void CdStreamInit(int32 numChannels); +uint32 GetGTA3ImgSize(void); +void CdStreamShutdown(void); +int32 CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size); +int32 CdStreamGetStatus(int32 channel); +int32 CdStreamGetLastPosn(void); +int32 CdStreamSync(int32 channel); +void AddToQueue(Queue *queue, int32 item); +int32 GetFirstInQueue(Queue *queue); +void RemoveFirstInQueue(Queue *queue); +DWORD WINAPI CdStreamThread(LPVOID lpThreadParameter); +bool CdStreamAddImage(char const *path); +char *CdStreamGetImageName(int32 cd); +void CdStreamRemoveImages(void); +int32 CdStreamGetNumImages(void); \ No newline at end of file diff --git a/src/core/Clock.cpp b/src/core/Clock.cpp new file mode 100644 index 00000000..707b0e57 --- /dev/null +++ b/src/core/Clock.cpp @@ -0,0 +1,131 @@ +#include "common.h" +#include "patcher.h" +#include "Timer.h" +#include "Pad.h" +#include "Clock.h" +#include "Stats.h" + +_TODO("gbFastTime"); +bool &gbFastTime = *(bool*)0x95CDBB; + +uint8 &CClock::ms_nGameClockHours = *(uint8*)0x95CDA6; +uint8 &CClock::ms_nGameClockMinutes = *(uint8*)0x95CDC8; +uint16 &CClock::ms_nGameClockSeconds = *(uint16*)0x95CC7C; +uint8 &CClock::ms_Stored_nGameClockHours = *(uint8*)0x95CD7B; +uint8 &CClock::ms_Stored_nGameClockMinutes = *(uint8*)0x95CD9B; +uint16 &CClock::ms_Stored_nGameClockSeconds = *(uint16*)0x95CC9C; +uint32 &CClock::ms_nMillisecondsPerGameMinute = *(uint32*)0x8F2C64; +int32 &CClock::ms_nLastClockTick = *(int32*)0x9430E4; +bool &CClock::ms_bClockHasBeenStored = *(bool*)0x95CD82; + +void +CClock::Initialise(uint32 scale) +{ + debug("Initialising CClock...\n"); + ms_nGameClockHours = 12; + ms_nGameClockMinutes = 0; + ms_nGameClockSeconds = 0; + ms_nMillisecondsPerGameMinute = scale; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); + ms_bClockHasBeenStored = false; + debug("CClock ready\n"); +} + +void +CClock::Update(void) +{ + if(CPad::GetPad(1)->GetRightShoulder1()) + { + ms_nGameClockMinutes += 8; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); + + if(ms_nGameClockMinutes >= 60) + { + ms_nGameClockHours++; + ms_nGameClockMinutes = 0; + if(ms_nGameClockHours >= 24) + ms_nGameClockHours = 0; + } + + } + else if(CTimer::GetTimeInMilliseconds() - ms_nLastClockTick > ms_nMillisecondsPerGameMinute || gbFastTime) + { + ms_nGameClockMinutes++; + ms_nLastClockTick += ms_nMillisecondsPerGameMinute; + + if ( gbFastTime ) + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); + + if(ms_nGameClockMinutes >= 60) + { + ms_nGameClockHours++; + ms_nGameClockMinutes = 0; + if(ms_nGameClockHours >= 24) + { + CStats::DaysPassed++; + ms_nGameClockHours = 0; + } + } + } + ms_nGameClockSeconds += + 60 + * (CTimer::GetTimeInMilliseconds() - ms_nLastClockTick) + / ms_nMillisecondsPerGameMinute; +} + +void +CClock::SetGameClock(uint8 h, uint8 m) +{ + ms_nGameClockHours = h; + ms_nGameClockMinutes = m; + ms_nGameClockSeconds = 0; + ms_nLastClockTick = CTimer::GetTimeInMilliseconds(); +} + +int32 +CClock::GetGameClockMinutesUntil(uint8 h, uint8 m) +{ + int32 now, then; + now = ms_nGameClockHours*60 + ms_nGameClockMinutes; + then = h*60 + m; + if(then < now) + then += 24*60; + return then-now; +} + +bool +CClock::GetIsTimeInRange(uint8 h1, uint8 h2) +{ + if(h1 > h2) + return ms_nGameClockHours >= h1 || ms_nGameClockHours < h2; + else + return ms_nGameClockHours >= h1 && ms_nGameClockHours < h2; +} + +void +CClock::StoreClock(void) +{ + ms_Stored_nGameClockHours = ms_nGameClockHours; + ms_Stored_nGameClockMinutes = ms_nGameClockMinutes; + ms_Stored_nGameClockSeconds = ms_nGameClockSeconds; + ms_bClockHasBeenStored = true; +} + +void +CClock::RestoreClock(void) +{ + ms_nGameClockHours = ms_Stored_nGameClockHours; + ms_nGameClockMinutes = ms_Stored_nGameClockMinutes; + ms_nGameClockSeconds = ms_Stored_nGameClockSeconds; +} + + +STARTPATCHES + InjectHook(0x473370, CClock::Initialise, PATCH_JUMP); + InjectHook(0x473460, CClock::Update, PATCH_JUMP); + InjectHook(0x4733C0, CClock::SetGameClock, PATCH_JUMP); + InjectHook(0x4733F0, CClock::GetGameClockMinutesUntil, PATCH_JUMP); + InjectHook(0x473420, CClock::GetIsTimeInRange, PATCH_JUMP); + InjectHook(0x473540, CClock::StoreClock, PATCH_JUMP); + InjectHook(0x473570, CClock::RestoreClock, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Clock.h b/src/core/Clock.h new file mode 100644 index 00000000..e11b2293 --- /dev/null +++ b/src/core/Clock.h @@ -0,0 +1,31 @@ +#pragma once + +class CClock +{ + static uint8 &ms_nGameClockHours; + static uint8 &ms_nGameClockMinutes; + static uint16 &ms_nGameClockSeconds; + static uint8 &ms_Stored_nGameClockHours; + static uint8 &ms_Stored_nGameClockMinutes; + static uint16 &ms_Stored_nGameClockSeconds; + static uint32 &ms_nMillisecondsPerGameMinute; + static int32 &ms_nLastClockTick; + static bool &ms_bClockHasBeenStored; +public: + + static void Initialise(uint32 scale); + static void Update(void); + static void SetGameClock(uint8 h, uint8 m); + static int32 GetGameClockMinutesUntil(uint8 h, uint8 m); + static bool GetIsTimeInRange(uint8 h1, uint8 h2); + static void StoreClock(void); + static void RestoreClock(void); + + static uint8 GetHours(void) { return ms_nGameClockHours; } + static uint8 GetMinutes(void) { return ms_nGameClockMinutes; } + static int16 GetSeconds(void) { return ms_nGameClockSeconds; } + + + static uint8 &GetHoursRef(void) { return ms_nGameClockHours; } + static uint8 &GetMinutesRef(void) { return ms_nGameClockMinutes; } +}; diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp new file mode 100644 index 00000000..d15ccca5 --- /dev/null +++ b/src/core/Collision.cpp @@ -0,0 +1,1887 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Lists.h" +#include "Game.h" +#include "Zones.h" +#include "General.h" +#include "ZoneCull.h" +#include "World.h" +#include "Entity.h" +#include "Train.h" +#include "Streaming.h" +#include "Pad.h" +#include "DMAudio.h" +#include "Population.h" +#include "FileLoader.h" +#include "Replay.h" +#include "CutsceneMgr.h" +#include "RenderBuffer.h" +#include "SurfaceTable.h" +#include "Collision.h" + +enum Direction +{ + DIR_X_POS, + DIR_X_NEG, + DIR_Y_POS, + DIR_Y_NEG, + DIR_Z_POS, + DIR_Z_NEG, +}; + +eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250; +CLinkList &CCollision::ms_colModelCache = *(CLinkList*)0x95CB58; + +void +CCollision::Init(void) +{ + ms_colModelCache.Init(NUMCOLCACHELINKS); + ms_collisionInMemory = LEVEL_NONE; +} + +void +CCollision::Shutdown(void) +{ + ms_colModelCache.Shutdown(); +} + +void +CCollision::Update(void) +{ + CVector playerCoors; + playerCoors = FindPlayerCoors(); + eLevelName level = CTheZones::m_CurrLevel; + bool forceLevelChange = false; + + if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) + return; + + // hardcode a level if there are no zones + if(level == LEVEL_NONE){ + if(CGame::currLevel == LEVEL_INDUSTRIAL && + playerCoors.x < 400.0f){ + level = LEVEL_COMMERCIAL; + forceLevelChange = true; + }else if(CGame::currLevel == LEVEL_SUBURBAN && + playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ + level = LEVEL_COMMERCIAL; + forceLevelChange = true; + }else{ + if(playerCoors.x > 800.0f){ + level = LEVEL_INDUSTRIAL; + forceLevelChange = true; + }else if(playerCoors.x < -800.0f){ + level = LEVEL_SUBURBAN; + forceLevelChange = true; + } + } + } + if(level != LEVEL_NONE && level != CGame::currLevel) + CGame::currLevel = level; + if(ms_collisionInMemory != CGame::currLevel) + LoadCollisionWhenINeedIt(forceLevelChange); + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); +} + +eLevelName +GetCollisionInSectorList(CPtrList &list) +{ + CPtrNode *node; + CEntity *e; + int level; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; + if(level != LEVEL_NONE) + return (eLevelName)level; + } + return LEVEL_NONE; +} + +// Get a level this sector is in based on collision models +eLevelName +GetCollisionInSector(CSector §) +{ + int level; + + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + return (eLevelName)level; +} + +void +CCollision::LoadCollisionWhenINeedIt(bool forceChange) +{ + eLevelName level, l; + bool multipleLevels; + CVector playerCoors; + CVehicle *veh; + CEntryInfoNode *ei; + int sx, sy; + int xmin, xmax, ymin, ymax; + int x, y; + + level = LEVEL_NONE; + + playerCoors = FindPlayerCoors(); + sx = CWorld::GetSectorIndexX(playerCoors.x); + sy = CWorld::GetSectorIndexY(playerCoors.y); + multipleLevels = false; + + veh = FindPlayerVehicle(); + if(veh && veh->IsTrain()){ + if(((CTrain*)veh)->m_doorState != TRAIN_DOOR_STATE2) + return ; + }else if(playerCoors.z < 4.0f && !CCullZones::DoINeedToLoadCollision()) + return; + + // Figure out whose level's collisions we're most likely to be interested in + if(!forceChange){ + if(veh && veh->IsBoat()){ + // on water we expect to be between levels + multipleLevels = true; + }else{ + xmin = max(sx - 1, 0); + xmax = min(sx + 1, NUMSECTORS_X-1); + ymin = max(sy - 1, 0); + ymax = min(sy + 1, NUMSECTORS_Y-1); + + for(x = xmin; x <= xmax; x++) + for(y = ymin; y <= ymax; y++){ + l = GetCollisionInSector(*CWorld::GetSector(x, y)); + if(l != LEVEL_NONE){ + if(level == LEVEL_NONE) + level = l; + if(level != l) + multipleLevels = true; + } + } + } + + if(multipleLevels && veh && veh->IsBoat()) + for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ + level = GetCollisionInSector(*ei->sector); + if(level != LEVEL_NONE) + break; + } + } + + if(level == CGame::currLevel || forceChange){ + CTimer::Stop(); + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + CStreaming::RemoveUnusedModelsInLoadedList(); + CGame::TidyUpMemory(true, true); + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + ms_collisionInMemory = CGame::currLevel; + CReplay::EmptyReplayBuffer(); + if(CGame::currLevel != LEVEL_NONE) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestBigBuildings(CGame::currLevel); + CStreaming::LoadAllRequestedModels(true); + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); + CGame::TidyUpMemory(true, true); + CTimer::Update(); + DMAudio.SetEffectsFadeVol(127); + } +} + +void +CCollision::SortOutCollisionAfterLoad(void) +{ + if(ms_collisionInMemory == CGame::currLevel) + return; + + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + if(CGame::currLevel != LEVEL_NONE){ + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + if(!CGame::playingIntro) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + } + ms_collisionInMemory = CGame::currLevel; + CGame::TidyUpMemory(true, false); +} + +void +CCollision::LoadCollisionScreen(eLevelName level) +{ + static char *levelNames[4] = { + "", + "IND_ZON", + "COM_ZON", + "SUB_ZON" + }; + + // Why twice? + LoadingIslandScreen(levelNames[level]); + LoadingIslandScreen(levelNames[level]); +} + +// +// Test +// + + +bool +CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) +{ + float d = s1.radius + s2.radius; + return (s1.center - s2.center).MagnitudeSqr() < d*d; +} + +bool +CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) +{ + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + return true; +} + +bool +CCollision::TestLineBox(const CColLine &line, const CColBox &box) +{ + float t, x, y, z; + // If either line point is in the box, we have a collision + if(line.p0.x > box.min.x && line.p0.x < box.max.x && + line.p0.y > box.min.y && line.p0.y < box.max.y && + line.p0.z > box.min.z && line.p0.z < box.max.z) + return true; + if(line.p1.x > box.min.x && line.p1.x < box.max.x && + line.p1.y > box.min.y && line.p1.y < box.max.y && + line.p1.z > box.min.z && line.p1.z < box.max.z) + return true; + + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // same test with max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + return false; +} + +bool +CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) +{ + if(line.p0.x <= box.min.x) return false; + if(line.p0.y <= box.min.y) return false; + if(line.p0.x >= box.max.x) return false; + if(line.p0.y >= box.max.y) return false; + if(line.p0.z < line.p1.z){ + if(line.p0.z > box.max.z) return false; + if(line.p1.z < box.min.z) return false; + }else{ + if(line.p1.z > box.max.z) return false; + if(line.p0.z < box.min.z) return false; + } + return true; +} + +bool +CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + CVector2D vec1, vec2, vec3, vect; + + // We do the test in 2D. With the plane direction we + // can figure out how to project the vectors. + // normal = (c-a) x (b-a) + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + // This is our triangle: + // 3-------2 + // \ P / + // \ / + // \ / + // 1 + // We can use the "2d cross product" to check on which side + // a vector is of another. Test is true if point is inside of all edges. + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + return true; +} + +// Test if line segment intersects with sphere. +// If the first point is inside the sphere this test does not register a collision! +// The code is reversed from the original code and rather ugly, see Process for a clear version. +// TODO: actually rewrite this mess +bool +CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) +{ + CVector v01 = line.p1 - line.p0; // vector from p0 to p1 + CVector v0c = sph.center - line.p0; // vector from p0 to center + float linesq = v01.MagnitudeSqr(); + // I leave in the strange -2 factors even though they serve no real purpose + float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line + // Square of tangent from p0 multiplied by line length so we can compare with projline. + // The length of the tangent would be this: sqrt((c-p0)^2 - r^2). + // Negative if p0 is inside the sphere! This breaks the test! + float tansq = 4.0f * linesq * + (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); + float diffsq = projline*projline - tansq; + // if diffsq < 0 that means the line is a passant, so no intersection + if(diffsq < 0.0f) + return false; + // projline (negative in GTA for some reason) is the point on the line + // in the middle of the two intersection points (startin from p0). + // sqrt(diffsq) somehow works out to be the distance from that + // midpoint to the intersection points. + // So subtract that and get rid of the awkward scaling: + float f = (-projline - sqrt(diffsq)) / (2.0f*linesq); + // f should now be in range [0, 1] for [p0, p1] + return f >= 0.0f && f <= 1.0f; +} + +bool +CCollision::TestSphereTriangle(const CColSphere &sphere, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ + // If sphere and plane don't intersect, no collision + if(fabs(plane.CalcPoint(sphere.center)) > sphere.radius) + return false; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // calculate two orthogonal basis vectors for the triangle + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, plane.normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + if(testcase == 1){ + // closest to a vertex + if(insideAB) dist = (sphere.center - vc).Magnitude(); + else if(insideAC) dist = (sphere.center - vb).Magnitude(); + else if(insideBC) dist = (sphere.center - va).Magnitude(); + else assert(0); + }else if(testcase == 2){ + // closest to an edge + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); + else assert(0); + }else if(testcase == 3){ + // center is in triangle + return true; + }else + assert(0); // front fell off + + return dist < sphere.radius; +} + +bool +CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) +{ + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) + if(TestLineSphere(newline, model.spheres[i])) + return true; + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) + if(TestLineBox(newline, model.boxes[i])) + return true; + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) + if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) + return true; + + return false; +} + + +// +// Process +// + +// For Spheres mindist is the squared distance to its center +// For Lines mindist is between [0,1] + +bool +CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) +{ + CVector dist = s1.center - s2.center; + float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 + float dc = d < 0.0f ? 0.0f : d; // clamp to zero, i.e. if s1's center is inside s2 + // no collision if sphere is not close enough + if(mindistsq <= dc*dc || s1.radius <= dc) + return false; + dist.Normalise(); + point.point = s1.center - dist*dc; + point.normal = dist; + point.surfaceA = s1.surface; + point.pieceA = s1.piece; + point.surfaceB = s2.surface; + point.pieceB = s2.piece; + point.depth = s1.radius - d; // sphere overlap + mindistsq = dc*dc; // collision radius + return true; +} + +bool +CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) +{ + CVector p; + CVector dist; + + // GTA's code is too complicated, uses a huge 3x3x3 if statement + // we can simplify the structure a lot + + // first make sure we have a collision at all + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + + // Now find out where the sphere center lies in relation to all the sides + int xpos = sph.center.x < box.min.x ? 1 : + sph.center.x > box.max.x ? 2 : + 0; + int ypos = sph.center.y < box.min.y ? 1 : + sph.center.y > box.max.y ? 2 : + 0; + int zpos = sph.center.z < box.min.z ? 1 : + sph.center.z > box.max.z ? 2 : + 0; + + if(xpos == 0 && ypos == 0 && zpos == 0){ + // sphere is inside the box + p = (box.min + box.max)*0.5f; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + point.normal = dist * (1.0f/sqrt(lensq)); + point.point = sph.center - point.normal; + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; + + // find absolute distance to the closer side in each dimension + float dx = dist.x > 0.0f ? + box.max.x - sph.center.x : + sph.center.x - box.min.x; + float dy = dist.y > 0.0f ? + box.max.y - sph.center.y : + sph.center.y - box.min.y; + float dz = dist.z > 0.0f ? + box.max.z - sph.center.z : + sph.center.z - box.min.z; + // collision depth is maximum of that: + if(dx > dy && dx > dz) + point.depth = dx; + else if(dy > dz) + point.depth = dy; + else + point.depth = dz; + return true; + } + }else{ + // sphere is outside. + // closest point on box: + p.x = xpos == 1 ? box.min.x : + xpos == 2 ? box.max.x : + sph.center.x; + p.y = ypos == 1 ? box.min.y : + ypos == 2 ? box.max.y : + sph.center.y; + p.z = zpos == 1 ? box.min.z : + zpos == 2 ? box.max.z : + sph.center.z; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + float len = sqrt(lensq); + point.point = p; + point.normal = dist * (1.0f/len); + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; + point.depth = sph.radius - len; + mindistsq = lensq; + return true; + } + } + return false; +} + +bool +CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) +{ + float mint, t, x, y, z; + CVector normal; + CVector p; + + mint = 1.0f; + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.min.x, y, z); + normal = CVector(-1.0f, 0.0f, 0.0f); + } + } + } + + // max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.max.x, y, z); + normal = CVector(1.0f, 0.0f, 0.0f); + } + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.min.y, z); + normal = CVector(0.0f, -1.0f, 0.0f); + } + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.max.y, z); + normal = CVector(0.0f, 1.0f, 0.0f); + } + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.min.z); + normal = CVector(0.0f, 0.0f, -1.0f); + } + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.max.z); + normal = CVector(0.0f, 0.0f, 1.0f); + } + } + } + + if(mint >= mindist) + return false; + + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = box.surface; + point.pieceB = box.piece; + mindist = mint; + + return true; +} + +// If line.p0 lies inside sphere, no collision is registered. +bool +CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) +{ + CVector v01 = line.p1 - line.p0; + CVector v0c = sphere.center - line.p0; + float linesq = v01.MagnitudeSqr(); + // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections + float projline = DotProduct(v01, v0c); + // tangent of p0 to sphere, scaled by linesq just like projline^2 + float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; + // this works out to be the square of the distance between the midpoint and the intersections + float diffsq = projline*projline - tansq; + // no intersection + if(diffsq < 0.0f) + return false; + // point of first intersection, in range [0,1] between p0 and p1 + float t = (projline - sqrt(diffsq)) / linesq; + // if not on line or beyond mindist, no intersection + if(t < 0.0f || t > 1.0f || t >= mindist) + return false; + point.point = line.p0 + v01*t; + point.normal = point.point - sphere.center; + point.normal.Normalise(); + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = sphere.surface; + point.pieceB = sphere.piece; + mindist = t; + return true; +} + +bool +CCollision::ProcessVerticalLineTriangle(const CColLine &line, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist, CStoredCollPoly *poly) +{ + float t; + CVector normal; + + const CVector &p0 = line.p0; + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // early out bound rect test + if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; + if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; + if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; + if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; + + plane.GetNormal(normal); + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + float h = (line.p1 - p0).z; + t = -plane.CalcPoint(p0) / (h * normal.z); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + CVector p(p0.x, p0.y, p0.z + h*t); + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + if(poly){ + poly->verts[0] = va; + poly->verts[1] = vb; + poly->verts[2] = vc; + poly->valid = true; + } + mindist = t; + return true; +} + +bool +CCollision::ProcessLineTriangle(const CColLine &line , + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist) +{ + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + CVector2D vec1, vec2, vec3, vect; + + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + mindist = t; + return true; +} + +bool +CCollision::ProcessSphereTriangle(const CColSphere &sphere, + const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindistsq) +{ + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + float distsq = planedist*planedist; + if(fabs(planedist) > sphere.radius || distsq > mindistsq) + return false; + + const CVector &va = verts[tri.a]; + const CVector &vb = verts[tri.b]; + const CVector &vc = verts[tri.c]; + + // calculate two orthogonal basis vectors for the triangle + CVector normal; + plane.GetNormal(normal); + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + CVector p; + if(testcase == 1){ + // closest to a vertex + if(insideAB) p = vc; + else if(insideAC) p = vb; + else if(insideBC) p = va; + else assert(0); + dist = (sphere.center - p).Magnitude(); + }else if(testcase == 2){ + // closest to an edge + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); + else assert(0); + }else if(testcase == 3){ + // center is in triangle + dist = fabs(planedist); + p = sphere.center - normal*planedist; + }else + assert(0); // front fell off + + if(dist >= sphere.radius || dist*dist >= mindistsq) + return false; + + point.point = p; + point.normal = sphere.center - p; + point.normal.Normalise(); + point.surfaceA = sphere.surface; + point.pieceA = sphere.piece; + point.surfaceB = tri.surface; + point.pieceB = 0; + point.depth = sphere.radius - dist; + mindistsq = dist*dist; + return true; +} + +bool +CCollision::ProcessLineOfSight(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough) +{ + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) + ProcessLineSphere(newline, model.spheres[i], point, coldist); + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) + ProcessLineBox(newline, model.boxes[i], point, coldist); + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) + ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist = coldist; + return true; + } + return false; +} + +bool +CCollision::ProcessVerticalLine(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ + static CStoredCollPoly TempStoredPoly; + int i; + + // transform line to model space + // Why does the game seem to do this differently than above? + CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); + newline.p1.x = newline.p0.x; + newline.p1.y = newline.p0.y; + + if(!TestVerticalLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++) + if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD) + ProcessLineSphere(newline, model.spheres[i], point, coldist); + + for(i = 0; i < model.numBoxes; i++) + if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD) + ProcessLineBox(newline, model.boxes[i], point, coldist); + + CalculateTrianglePlanes(&model); + TempStoredPoly.valid = false; + for(i = 0; i < model.numTriangles; i++) + if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD) + ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + if(poly && TempStoredPoly.valid){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * poly->verts[0]; + poly->verts[1] = matrix * poly->verts[1]; + poly->verts[2] = matrix * poly->verts[2]; + } + mindist = coldist; + return true; + } + return false; +} + +enum { + MAXNUMSPHERES = 128, + MAXNUMBOXES = 32, + MAXNUMLINES = 16, + MAXNUMTRIS = 600 +}; + +// This checks model A's spheres and lines against model B's spheres, boxes and triangles. +// Returns the number of A's spheres that collide. +// Returned ColPoints are in world space. +// NB: lines do not seem to be supported very well, use with caution +int32 +CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, + const CMatrix &matrixB, CColModel &modelB, + CColPoint *spherepoints, CColPoint *linepoints, float *linedists) +{ + static int aSphereIndicesA[MAXNUMSPHERES]; + static int aLineIndicesA[MAXNUMLINES]; + static int aSphereIndicesB[MAXNUMSPHERES]; + static int aBoxIndicesB[MAXNUMBOXES]; + static int aTriangleIndicesB[MAXNUMTRIS]; + static bool aCollided[MAXNUMLINES]; + static CColSphere aSpheresA[MAXNUMSPHERES]; + static CColLine aLinesA[MAXNUMLINES]; + static CMatrix matAB, matBA; + CColSphere s; + int i, j; + + assert(modelA.numSpheres <= MAXNUMSPHERES); + assert(modelA.numLines <= MAXNUMLINES); + + // From model A space to model B space + matAB = Invert(matrixB, matAB) * matrixA; + + CColSphere bsphereAB; // bounding sphere of A in B space + bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); + if(!TestSphereBox(bsphereAB, modelB.boundingBox)) + return 0; + // B to A space + matBA = Invert(matrixA, matBA) * matrixB; + + // transform modelA's spheres and lines to B space + for(i = 0; i < modelA.numSpheres; i++){ + CColSphere &s = modelA.spheres[i]; + aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); + } + for(i = 0; i < modelA.numLines; i++) + aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + int numLinesA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // no actual check??? + for(i = 0; i < modelA.numLines; i++) + aLineIndicesA[numLinesA++] = i; + // No collision + if(numSpheresA == 0 && numLinesA == 0) + return 0; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++){ + s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); + if(TestSphereBox(s, modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + } + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + for(i = 0; i < modelB.numTriangles; i++) + if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) + aTriangleIndicesB[numTrianglesB++] = i; + assert(numSpheresB <= MAXNUMSPHERES); + assert(numBoxesB <= MAXNUMBOXES); + assert(numTrianglesB <= MAXNUMTRIS); + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + + for(j = 0; j < numSpheresB; j++) + hasCollided |= ProcessSphereSphere( + aSpheresA[aSphereIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numBoxesB; j++) + hasCollided |= ProcessSphereBox( + aSpheresA[aSphereIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numTrianglesB; j++) + hasCollided |= ProcessSphereTriangle( + aSpheresA[aSphereIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + spherepoints[numCollisions], coldist); + if(hasCollided) + numCollisions++; + } + for(i = 0; i < numCollisions; i++){ + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < numLinesA; i++){ + aCollided[i] = false; + + for(j = 0; j < numSpheresB; j++) + aCollided[i] |= ProcessLineSphere( + aLinesA[aLineIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numBoxesB; j++) + aCollided[i] |= ProcessLineBox( + aLinesA[aLineIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numTrianglesB; j++) + aCollided[i] |= ProcessLineTriangle( + aLinesA[aLineIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + } + for(i = 0; i < numLinesA; i++) + if(aCollided[i]){ + j = aLineIndicesA[i]; + linepoints[j].point = matrixB * linepoints[j].point; + linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); + } + + return numCollisions; // sphere collisions +} + + +// +// Misc +// + +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // Between 0 and len we're above the line. + // if not, calculate distance to endpoint + if(dot <= 0.0f) + return (*point - *l0).Magnitude(); + if(dot >= lensq) + return (*point - *l1).Magnitude(); + // distance to line + return sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); +} + +// same as above but also return the point on the line +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // find out which point we're closest to + if(dot <= 0.0f) + closest = *l0; + else if(dot >= lensq) + closest = *l1; + else + closest = *l0 + (*l1 - *l0)*(dot/lensq); + // this is the distance + return (*point - closest).Magnitude(); +} + +void +CCollision::CalculateTrianglePlanes(CColModel *model) +{ + if(model->numTriangles == 0) + return; + + CLink *lptr; + if(model->trianglePlanes){ + // re-insert at front so it's not removed again soon + lptr = model->GetLinkPtr(); + lptr->Remove(); + ms_colModelCache.head.Insert(lptr); + }else{ + assert(model); + lptr = ms_colModelCache.Insert(model); + if(lptr == nil){ + // make room if we have to, remove last in list + lptr = ms_colModelCache.tail.prev; + assert(lptr); + assert(lptr->item); + lptr->item->RemoveTrianglePlanes(); + ms_colModelCache.Remove(lptr); + // now this cannot fail + lptr = ms_colModelCache.Insert(model); + assert(lptr); + } + model->CalculateTrianglePlanes(); + model->SetLinkPtr(lptr); + } +} + +void +CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) +{ +} + +void +CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) +{ + int i; + int s; + float f; + CVector verts[8]; + CVector min, max; + int r, g, b; + RwImVertexIndex *iptr; + RwIm3DVertex *vptr; + + RenderBuffer::ClearRenderBuffer(); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); +extern int gDbgSurf; + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + + // TODO: surface + r = 255; + g = 128; + b = 0; + + s = colModel.triangles[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + // TODO: make some surface types flicker? +//if(s != gDbgSurf) continue; + + if(s > SURFACE_32){ + r = CGeneral::GetRandomNumber(); + g = CGeneral::GetRandomNumber(); + b = CGeneral::GetRandomNumber(); + printf("Illegal surfacetype:%d on MI:%d\n", s, id); + } + + RenderBuffer::StartStoring(6, 3, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; + RenderBuffer::StopStoring(); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + s = colModel.boxes[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + // TODO: make some surface types flicker? +//if(s != gDbgSurf) continue; + + RenderBuffer::StartStoring(36, 8, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetU(&vptr[3], 0.0f); + RwIm3DVertexSetV(&vptr[3], 0.0f); + RwIm3DVertexSetU(&vptr[4], 0.0f); + RwIm3DVertexSetV(&vptr[4], 1.0f); + RwIm3DVertexSetU(&vptr[5], 1.0f); + RwIm3DVertexSetV(&vptr[5], 1.0f); + RwIm3DVertexSetU(&vptr[6], 0.0f); + RwIm3DVertexSetV(&vptr[6], 1.0f); + RwIm3DVertexSetU(&vptr[7], 1.0f); + RwIm3DVertexSetV(&vptr[7], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); + RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); + RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); + RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); + RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; + iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; + iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; + iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; + iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; + iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; + iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; + iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; + iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; + iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; + iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; + RenderBuffer::StopStoring(); + } + + RenderBuffer::RenderStuffInBuffer(); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} + + +/* + * ColModel code + */ + +void +CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) +{ + this->radius = radius; + this->center = center; + this->surface = surf; + this->piece = piece; +} + +void +CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) +{ + this->min = min; + this->max = max; + this->surface = surf; + this->piece = piece; +} + +void +CColLine::Set(const CVector &p0, const CVector &p1) +{ + this->p0 = p0; + this->p1 = p1; +} + +void +CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece) +{ + this->a = a; + this->b = b; + this->c = c; + this->surface = surf; +} + +void +CColTrianglePlane::Set(const CVector *v, CColTriangle &tri) +{ + const CVector &va = v[tri.a]; + const CVector &vb = v[tri.b]; + const CVector &vc = v[tri.c]; + + normal = CrossProduct(vc-va, vb-va); + normal.Normalise(); + dist = DotProduct(normal, va); + CVector an(fabs(normal.x), fabs(normal.y), fabs(normal.z)); + // find out largest component and its direction + if(an.x > an.y && an.x > an.z) + dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; + else if(an.y > an.z) + dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; + else + dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; +} + +CColModel::CColModel(void) +{ + numSpheres = 0; + spheres = nil; + numLines = 0; + lines = nil; + numBoxes = 0; + boxes = nil; + numTriangles = 0; + vertices = nil; + triangles = nil; + trianglePlanes = nil; + level = CGame::currLevel; + ownsCollisionVolumes = true; +} + +CColModel::~CColModel(void) +{ + RemoveCollisionVolumes(); + RemoveTrianglePlanes(); +} + +void +CColModel::RemoveCollisionVolumes(void) +{ + if(ownsCollisionVolumes){ + RwFree(spheres); + RwFree(lines); + RwFree(boxes); + RwFree(vertices); + RwFree(triangles); + } + numSpheres = 0; + numLines = 0; + numBoxes = 0; + numTriangles = 0; + spheres = nil; + lines = nil; + boxes = nil; + vertices = nil; + triangles = nil; +} + +void +CColModel::CalculateTrianglePlanes(void) +{ + // HACK: allocate space for one more element to stuff the link pointer into + trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); + for(int i = 0; i < numTriangles; i++) + trianglePlanes[i].Set(vertices, triangles[i]); +} + +void +CColModel::RemoveTrianglePlanes(void) +{ + RwFree(trianglePlanes); + trianglePlanes = nil; +} + +void +CColModel::SetLinkPtr(CLink *lptr) +{ + assert(trianglePlanes); + *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; +} + +CLink* +CColModel::GetLinkPtr(void) +{ + assert(trianglePlanes); + return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); +} + +void +CColModel::GetTrianglePoint(CVector &v, int i) const +{ + v = vertices[i]; +} + +CColModel& +CColModel::operator=(const CColModel &other) +{ + int i; + int numVerts; + + boundingSphere = other.boundingSphere; + boundingBox = other.boundingBox; + + // copy spheres + if(other.numSpheres){ + if(numSpheres != other.numSpheres){ + numSpheres = other.numSpheres; + if(spheres) + RwFree(spheres); + spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); + } + for(i = 0; i < numSpheres; i++) + spheres[i] = other.spheres[i]; + }else{ + numSpheres = 0; + if(spheres) + RwFree(spheres); + spheres = nil; + } + + // copy lines + if(other.numLines){ + if(numLines != other.numLines){ + numLines = other.numLines; + if(lines) + RwFree(lines); + lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); + } + for(i = 0; i < numLines; i++) + lines[i] = other.lines[i]; + }else{ + numLines = 0; + if(lines) + RwFree(lines); + lines = nil; + } + + // copy boxes + if(other.numBoxes){ + if(numBoxes != other.numBoxes){ + numBoxes = other.numBoxes; + if(boxes) + RwFree(boxes); + boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); + } + for(i = 0; i < numBoxes; i++) + boxes[i] = other.boxes[i]; + }else{ + numBoxes = 0; + if(boxes) + RwFree(boxes); + boxes = nil; + } + + // copy mesh + if(other.numTriangles){ + // copy vertices + numVerts = 0; + for(i = 0; i < other.numTriangles; i++){ + if(other.triangles[i].a > numVerts) + other.triangles[i].a = numVerts; + if(other.triangles[i].b > numVerts) + other.triangles[i].b = numVerts; + if(other.triangles[i].c > numVerts) + other.triangles[i].c = numVerts; + } + numVerts++; + if(vertices) + RwFree(vertices); + if(numVerts){ + vertices = (CVector*)RwMalloc(numVerts*sizeof(CVector)); + for(i = 0; i < numVerts; i++) + vertices[i] = other.vertices[i]; + } + + // copy triangles + if(numTriangles != other.numTriangles){ + numTriangles = other.numTriangles; + if(triangles) + RwFree(triangles); + triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); + } + for(i = 0; i < numTriangles; i++) + triangles[i] = other.triangles[i]; + }else{ + numTriangles = 0; + if(triangles) + RwFree(triangles); + triangles = nil; + if(vertices) + RwFree(vertices); + vertices = nil; + } + return *this; +} + +STARTPATCHES + InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP); + + InjectHook(0x40B380, CCollision::Init, PATCH_JUMP); + InjectHook(0x40B3A0, CCollision::Shutdown, PATCH_JUMP); + InjectHook(0x40B3B0, CCollision::Update, PATCH_JUMP); + InjectHook(0x40B5B0, CCollision::LoadCollisionWhenINeedIt, PATCH_JUMP); + InjectHook(0x40B900, CCollision::SortOutCollisionAfterLoad, PATCH_JUMP); + + InjectHook(0x40BB70, CCollision::TestSphereBox, PATCH_JUMP); + InjectHook(0x40E130, CCollision::TestLineBox, PATCH_JUMP); + InjectHook(0x40E5C0, CCollision::TestVerticalLineBox, PATCH_JUMP); + InjectHook(0x40EC10, CCollision::TestLineTriangle, PATCH_JUMP); + InjectHook(0x40DAA0, CCollision::TestLineSphere, PATCH_JUMP); + InjectHook(0x40C580, CCollision::TestSphereTriangle, PATCH_JUMP); + InjectHook(0x40F720, CCollision::TestLineOfSight, PATCH_JUMP); + + InjectHook(0x40B9F0, CCollision::ProcessSphereSphere, PATCH_JUMP); + InjectHook(0x40BC00, CCollision::ProcessSphereBox, PATCH_JUMP); + InjectHook(0x40E670, CCollision::ProcessLineBox, PATCH_JUMP); + InjectHook(0x40DE80, CCollision::ProcessLineSphere, PATCH_JUMP); + InjectHook(0x40FB50, CCollision::ProcessVerticalLineTriangle, PATCH_JUMP); + InjectHook(0x40F140, CCollision::ProcessLineTriangle, PATCH_JUMP); + InjectHook(0x40CE30, CCollision::ProcessSphereTriangle, PATCH_JUMP); + + InjectHook(0x40F910, CCollision::ProcessLineOfSight, PATCH_JUMP); + InjectHook(0x410120, CCollision::ProcessVerticalLine, PATCH_JUMP); + InjectHook(0x410BE0, CCollision::ProcessColModels, PATCH_JUMP); + + InjectHook(0x40B960, CCollision::CalculateTrianglePlanes, PATCH_JUMP); + InjectHook(0x411640, &CLink::Remove, PATCH_JUMP); + InjectHook(0x411620, &CLink::Insert, PATCH_JUMP); + InjectHook(0x4115C0, &CLinkList::Insert, PATCH_JUMP); + InjectHook(0x411600, &CLinkList::Remove, PATCH_JUMP); +// InjectHook(0x411530, &CLinkList::Init, PATCH_JUMP); + + InjectHook(0x411E40, (void (CColSphere::*)(float, const CVector&, uint8, uint8))&CColSphere::Set, PATCH_JUMP); + InjectHook(0x40B2A0, &CColBox::Set, PATCH_JUMP); + InjectHook(0x40B320, &CColLine::ctor, PATCH_JUMP); + InjectHook(0x40B350, &CColLine::Set, PATCH_JUMP); + InjectHook(0x411E70, &CColTriangle::Set, PATCH_JUMP); + + InjectHook(0x411EA0, &CColTrianglePlane::Set, PATCH_JUMP); + InjectHook(0x412140, &CColTrianglePlane::GetNormal, PATCH_JUMP); + + InjectHook(0x411680, &CColModel::ctor, PATCH_JUMP); + InjectHook(0x4116E0, &CColModel::dtor, PATCH_JUMP); + InjectHook(0x411D80, &CColModel::RemoveCollisionVolumes, PATCH_JUMP); + InjectHook(0x411CB0, &CColModel::CalculateTrianglePlanes, PATCH_JUMP); + InjectHook(0x411D10, &CColModel::RemoveTrianglePlanes, PATCH_JUMP); + InjectHook(0x411D40, &CColModel::SetLinkPtr, PATCH_JUMP); + InjectHook(0x411D60, &CColModel::GetLinkPtr, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Collision.h b/src/core/Collision.h new file mode 100644 index 00000000..5a9058d3 --- /dev/null +++ b/src/core/Collision.h @@ -0,0 +1,157 @@ +#pragma once + +#include "templates.h" +#include "Game.h" // for eLevelName + +struct CColSphere +{ + CVector center; + float radius; + uint8 surface; + uint8 piece; + + void Set(float radius, const CVector ¢er, uint8 surf, uint8 piece); + void Set(float radius, const CVector ¢er) { this->center = center; this->radius = radius; } +}; + +struct CColBox +{ + CVector min; + CVector max; + uint8 surface; + uint8 piece; + + void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece); + CVector GetSize(void) { return max - min; } +}; + +struct CColLine +{ + CVector p0; + int pad0; + CVector p1; + int pad1; + + CColLine(void) { }; + CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; + void Set(const CVector &p0, const CVector &p1); + + CColLine *ctor(CVector *p0, CVector *p1) { return ::new (this) CColLine(*p0, *p1); } +}; + +struct CColTriangle +{ + uint16 a; + uint16 b; + uint16 c; + uint8 surface; + + void Set(const CVector *v, int a, int b, int c, uint8 surf, uint8 piece); +}; + +struct CColTrianglePlane +{ + CVector normal; + float dist; + uint8 dir; + + void Set(const CVector *v, CColTriangle &tri); + void GetNormal(CVector &n) const { n = normal; } + float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; +}; + +struct CColPoint +{ + CVector point; + int pad1; + // the surface normal on the surface of point + CVector normal; + int pad2; + uint8 surfaceA; + uint8 pieceA; + uint8 surfaceB; + uint8 pieceB; + float depth; +}; + +struct CStoredCollPoly +{ + CVector verts[3]; + bool valid; +}; + +struct CColModel +{ + CColSphere boundingSphere; + CColBox boundingBox; + short numSpheres; + short numLines; + short numBoxes; + short numTriangles; + int level; + bool ownsCollisionVolumes; + CColSphere *spheres; + CColLine *lines; + CColBox *boxes; + CVector *vertices; + CColTriangle *triangles; + CColTrianglePlane *trianglePlanes; + + CColModel(void); + ~CColModel(void); + void RemoveCollisionVolumes(void); + void CalculateTrianglePlanes(void); + void RemoveTrianglePlanes(void); + CLink *GetLinkPtr(void); + void SetLinkPtr(CLink*); + void GetTrianglePoint(CVector &v, int i) const; + + CColModel *ctor(void) { return ::new (this) CColModel(); } + void dtor(void) { this->CColModel::~CColModel(); } + CColModel& operator=(const CColModel& other); +}; + +class CCollision +{ +public: + static eLevelName &ms_collisionInMemory; + static CLinkList &ms_colModelCache; + + static void Init(void); + static void Shutdown(void); + static void Update(void); + static void LoadCollisionWhenINeedIt(bool changeLevel); + static void SortOutCollisionAfterLoad(void); + static void LoadCollisionScreen(eLevelName level); + static void DrawColModel(const CMatrix &mat, const CColModel &colModel); + static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); + + static void CalculateTrianglePlanes(CColModel *model); + + // all these return true if there's a collision + static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); + static bool TestSphereBox(const CColSphere &sph, const CColBox &box); + static bool TestLineBox(const CColLine &line, const CColBox &box); + static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); + static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineSphere(const CColLine &line, const CColSphere &sph); + static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); + + static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); + static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); + static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); + static bool ProcessVerticalLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); + static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); + static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); + static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); + static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); + static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); + static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists); + + // TODO: + // CCollision::IsStoredPolyStillValidVerticalLine + + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); +}; diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp new file mode 100644 index 00000000..d7567ac4 --- /dev/null +++ b/src/core/ControllerConfig.cpp @@ -0,0 +1,57 @@ + #define DIRECTINPUT_VERSION 0x0800 + #include +#include "common.h" +#include "patcher.h" +#include "ControllerConfig.h" +#include "Pad.h" +#include "FileMgr.h" + +CControllerConfigManager &ControlsManager = *(CControllerConfigManager*)0x8F43A4; + +WRAPPER void CControllerConfigManager::UpdateJoyButtonState(int padnumber) { EAXJMP(0x58F5B0); } +WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber) { EAXJMP(0x58C5E0); } +WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonDown(int button, eControllerType type) { EAXJMP(0x58C730); } +WRAPPER void CControllerConfigManager::UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber) { EAXJMP(0x58CE80); } +WRAPPER void CControllerConfigManager::AffectControllerStateOn_ButtonUp(int button, int padnumber) { EAXJMP(0x58CFD0); } +WRAPPER void CControllerConfigManager::MakeControllerActionsBlank() { EAXJMP(0x58B7A0); } +WRAPPER void CControllerConfigManager::InitDefaultControlConfiguration() { EAXJMP(0x58B930); } +WRAPPER void CControllerConfigManager::InitDefaultControlConfigMouse(CMouseControllerState const &mousestate) { EAXJMP(0x58BD00); } +WRAPPER int32 CControllerConfigManager::GetJoyButtonJustDown() { EAXJMP(0x58B7D0); } +WRAPPER void CControllerConfigManager::InitDefaultControlConfigJoyPad(unsigned int buttons) { EAXJMP(0x58BD90); } +WRAPPER void CControllerConfigManager::ClearSimButtonPressCheckers() { EAXJMP(0x58D220); } +WRAPPER void CControllerConfigManager::AffectPadFromKeyBoard() { EAXJMP(0x58D0C0); } +WRAPPER void CControllerConfigManager::AffectPadFromMouse() { EAXJMP(0x58D1A0); } + +void CControllerConfigManager::LoadSettings(int32 file) +{ + bool bValid = true; + + if ( file ) + { + char buff[29]; + CFileMgr::Read(file, buff, sizeof(buff)); + + if ( !strncmp(buff, "THIS FILE IS NOT VALID YET", sizeof(buff) - 3) ) + bValid = false; + else + CFileMgr::Seek(file, 0, 0); + } + + if ( bValid ) + { + ControlsManager.MakeControllerActionsBlank(); + + for ( int i = 0; i < 4; i++ ) + { + for ( int j = 0; j < 41; j++ ) + { + CFileMgr::Read(file, (char *)&ControlsManager.m_aSettings[j][i], sizeof(tControllerConfigBind)); + } + } + } +} + +WRAPPER void CControllerConfigManager::SaveSettings(int32 file) +{ + EAXJMP(0x58B800); +} diff --git a/src/core/ControllerConfig.h b/src/core/ControllerConfig.h new file mode 100644 index 00000000..581efe05 --- /dev/null +++ b/src/core/ControllerConfig.h @@ -0,0 +1,58 @@ +#pragma once + + +// based on x-gtasa + +enum eControllerType +{ + KEYBOARD, + OPTIONAL_EXTRA, + MOUSE, + JOYSTICK, +}; + +class CMouseControllerState; + +class CControllerConfigManager +{ +public: + struct tControllerConfigBind + { + RsKeyCodes m_Key; + int32 m_ContSetOrder; + }; + + bool field_0; + char _pad0[3]; + DIJOYSTATE2 m_OldState; + DIJOYSTATE2 m_NewState; + wchar m_aActionNames[41][40]; + bool m_aButtonStates[17]; + char _pad1[3]; + tControllerConfigBind m_aSettings[41][4]; + uint8 m_aSimCheckers[4][4]; + bool m_bMouseAssociated; + char _pad2[3]; + + void UpdateJoyButtonState(int padnumber); + void UpdateJoyInConfigMenus_ButtonDown(int button, int padnumber); + void AffectControllerStateOn_ButtonDown(int button, eControllerType type); + void UpdateJoyInConfigMenus_ButtonUp(int button, int padnumber); + void AffectControllerStateOn_ButtonUp(int button, int padnumber); + + int32 GetJoyButtonJustDown(); + void LoadSettings(int32 file); + void SaveSettings(int32 file); + void MakeControllerActionsBlank(); + void InitDefaultControlConfiguration(); + void InitDefaultControlConfigMouse(CMouseControllerState const &mousestate); + void InitDefaultControlConfigJoyPad(unsigned int buttons); + void ClearSimButtonPressCheckers(); + void AffectPadFromKeyBoard(); + void AffectPadFromMouse(); + +}; + +VALIDATE_SIZE(CControllerConfigManager, 0x143C); + +extern CControllerConfigManager &ControlsManager; \ No newline at end of file diff --git a/src/core/CutsceneMgr.cpp b/src/core/CutsceneMgr.cpp new file mode 100644 index 00000000..744ef53d --- /dev/null +++ b/src/core/CutsceneMgr.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "patcher.h" +#include "CutsceneMgr.h" + +bool &CCutsceneMgr::ms_running = *(bool*)0x95CCF5; +bool &CCutsceneMgr::ms_cutsceneProcessing = *(bool*)0x95CD9F; +CDirectory *&CCutsceneMgr::ms_pCutsceneDir = *(CDirectory**)0x8F5F88; diff --git a/src/core/CutsceneMgr.h b/src/core/CutsceneMgr.h new file mode 100644 index 00000000..89f6ab8d --- /dev/null +++ b/src/core/CutsceneMgr.h @@ -0,0 +1,15 @@ +#pragma once + +class CDirectory; + +class CCutsceneMgr +{ + static bool &ms_running; + static bool &ms_cutsceneProcessing; + +public: + static CDirectory *&ms_pCutsceneDir; + + static bool IsRunning(void) { return ms_running; } + static bool IsCutsceneProcessing(void) { return ms_cutsceneProcessing; } +}; diff --git a/src/core/Directory.cpp b/src/core/Directory.cpp new file mode 100644 index 00000000..3e0d5382 --- /dev/null +++ b/src/core/Directory.cpp @@ -0,0 +1,65 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "Directory.h" + +CDirectory::CDirectory(int32 maxEntries) + : numEntries(0), maxEntries(maxEntries) +{ + entries = new DirectoryInfo[maxEntries]; +} + +CDirectory::~CDirectory(void) +{ + delete[] entries; +} + +void +CDirectory::ReadDirFile(const char *filename) +{ + int fd; + DirectoryInfo dirinfo; + + fd = CFileMgr::OpenFile(filename, "rb"); + while(CFileMgr::Read(fd, (char*)&dirinfo, sizeof(dirinfo))) + AddItem(dirinfo); + CFileMgr::CloseFile(fd); +} + +bool +CDirectory::WriteDirFile(const char *filename) +{ + int fd, n; + fd = CFileMgr::OpenFileForWriting(filename); + n = CFileMgr::Write(fd, (char*)entries, numEntries*sizeof(DirectoryInfo)); + CFileMgr::CloseFile(fd); + return n == numEntries*sizeof(DirectoryInfo); +} + +void +CDirectory::AddItem(const DirectoryInfo &dirinfo) +{ + assert(numEntries < maxEntries); + entries[numEntries++] = dirinfo; +} + +bool +CDirectory::FindItem(const char *name, uint32 &offset, uint32 &size) +{ + int i; + + for(i = 0; i < numEntries; i++) + if(strcmpi(entries[i].name, name) == 0){ + offset = entries[i].offset; + size = entries[i].size; + return true; + } + return false; +} + +STARTPATCHES + InjectHook(0x473630, &CDirectory::ReadDirFile, PATCH_JUMP); + InjectHook(0x473690, &CDirectory::WriteDirFile, PATCH_JUMP); + InjectHook(0x473600, &CDirectory::AddItem, PATCH_JUMP); + InjectHook(0x4736E0, &CDirectory::FindItem, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Directory.h b/src/core/Directory.h new file mode 100644 index 00000000..06e6bba4 --- /dev/null +++ b/src/core/Directory.h @@ -0,0 +1,22 @@ +#pragma once + +class CDirectory +{ +public: + struct DirectoryInfo { + uint32 offset; + uint32 size; + char name[24]; + }; + DirectoryInfo *entries; + int32 maxEntries; + int32 numEntries; + + CDirectory(int32 maxEntries); + ~CDirectory(void); + + void ReadDirFile(const char *filename); + bool WriteDirFile(const char *filename); + void AddItem(const DirectoryInfo &dirinfo); + bool FindItem(const char *name, uint32 &offset, uint32 &size); +}; diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp new file mode 100644 index 00000000..fdc3b9d7 --- /dev/null +++ b/src/core/FileLoader.cpp @@ -0,0 +1,1182 @@ +#include "common.h" +#include "main.h" +#include "patcher.h" +#include "math/Quaternion.h" +#include "ModelInfo.h" +#include "ModelIndices.h" +#include "TempColModels.h" +#include "VisibilityPlugins.h" +#include "FileMgr.h" +#include "HandlingMgr.h" +#include "CarCtrl.h" +#include "PedType.h" +#include "PedStats.h" +#include "AnimManager.h" +#include "Game.h" +#include "RwHelper.h" +#include "NodeName.h" +#include "TxdStore.h" +#include "PathFind.h" +#include "ObjectData.h" +#include "DummyObject.h" +#include "World.h" +#include "Zones.h" +#include "ZoneCull.h" +#include "CdStream.h" +#include "FileLoader.h" + +char CFileLoader::ms_line[256]; + +const char* +GetFilename(const char *filename) +{ + char *s = strrchr((char*)filename, '\\'); + return s ? s+1 : filename; +} + +void +LoadingScreenLoadingFile(const char *filename) +{ + sprintf(gString, "Loading %s", GetFilename(filename)); + LoadingScreen("Loading the Game", gString, nil); +} + +void +CFileLoader::LoadLevel(const char *filename) +{ + int fd; + RwTexDictionary *savedTxd; + eLevelName savedLevel; + bool objectsLoaded; + char *line; + char txdname[64]; + + savedTxd = RwTexDictionaryGetCurrent(); + objectsLoaded = false; + savedLevel = CGame::currLevel; + if(savedTxd == nil){ + savedTxd = RwTexDictionaryCreate(); + RwTexDictionarySetCurrent(savedTxd); + } + fd = CFileMgr::OpenFile(filename, "r"); + assert(fd > 0); + + for(line = LoadLine(fd); line; line = LoadLine(fd)){ + if(*line == '#') + continue; + + if(strncmp(line, "EXIT", 9) == 0) // BUG: 9? + break; + + if(strncmp(line, "IMAGEPATH", 9) == 0){ + RwImageSetPath(line + 10); + }else if(strncmp(line, "TEXDICTION", 10) == 0){ + strcpy(txdname, line+11); + LoadingScreenLoadingFile(txdname); + RwTexDictionary *txd = LoadTexDictionary(txdname); + AddTexDictionaries(savedTxd, txd); + RwTexDictionaryDestroy(txd); + }else if(strncmp(line, "COLFILE", 7) == 0){ + int level; + sscanf(line+8, "%d", &level); + CGame::currLevel = (eLevelName)level; + LoadingScreenLoadingFile(line+10); + LoadCollisionFile(line+10); + CGame::currLevel = savedLevel; + }else if(strncmp(line, "MODELFILE", 9) == 0){ + LoadingScreenLoadingFile(line + 10); + LoadModelFile(line + 10); + }else if(strncmp(line, "HIERFILE", 8) == 0){ + LoadingScreenLoadingFile(line + 9); + LoadClumpFile(line + 9); + }else if(strncmp(line, "IDE", 3) == 0){ + LoadingScreenLoadingFile(line + 4); + LoadObjectTypes(line + 4); + }else if(strncmp(line, "IPL", 3) == 0){ + if(!objectsLoaded){ + // CModelInfo::ConstructMloClumps(); + CObjectData::Initialise("DATA\\OBJECT.DAT"); + objectsLoaded = true; + } + LoadingScreenLoadingFile(line + 4); + LoadScene(line + 4); + }else if(strncmp(line, "MAPZONE", 7) == 0){ + LoadingScreenLoadingFile(line + 8); + LoadMapZones(line + 8); + }else if(strncmp(line, "SPLASH", 6) == 0){ + LoadSplash(GetRandomSplashScreen()); + }else if(strncmp(line, "CDIMAGE", 7) == 0){ + CdStreamAddImage(line + 8); + } + } + + CFileMgr::CloseFile(fd); + RwTexDictionarySetCurrent(savedTxd); +} + +void +CFileLoader::LoadCollisionFromDatFile(int currlevel) +{ + int fd; + char *line; + + fd = CFileMgr::OpenFile(CGame::aDatFile, "r"); + assert(fd > 0); + + for(line = LoadLine(fd); line; line = LoadLine(fd)){ + if(*line == '#') + continue; + + if(strncmp(line, "COLFILE", 7) == 0){ + int level; + sscanf(line+8, "%d", &level); + if(currlevel == level) + LoadCollisionFile(line+10); + } + } + + CFileMgr::CloseFile(fd); +} + +char* +CFileLoader::LoadLine(int fd) +{ + int i; + char *line; + + if(CFileMgr::ReadLine(fd, ms_line, 256) == false) + return nil; + for(i = 0; ms_line[i] != '\0'; i++) + if(ms_line[i] < ' ' || ms_line[i] == ',') + ms_line[i] = ' '; + for(line = ms_line; *line <= ' ' && *line != '\0'; line++); + return line; +} + +RwTexDictionary* +CFileLoader::LoadTexDictionary(const char *filename) +{ + RwTexDictionary *txd; + RwStream *stream; + + txd = nil; + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); + debug("Loading texture dictionary file %s\n", filename); + if(stream){ + if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)) + txd = RwTexDictionaryGtaStreamRead(stream); + RwStreamClose(stream, nil); + } + if(txd == nil) + txd = RwTexDictionaryCreate(); + return txd; +} + +void +CFileLoader::LoadCollisionFile(const char *filename) +{ + int fd; + char modelname[24]; + CBaseModelInfo *mi; + struct { + char ident[4]; + uint32 size; + } header; + + debug("Loading collision file %s\n", filename); + fd = CFileMgr::OpenFile(filename, "rb"); + + while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){ + assert(strncmp(header.ident, "COLL", 4) == 0); + CFileMgr::Read(fd, (char*)work_buff, header.size); + memcpy(modelname, work_buff, 24); + + mi = CModelInfo::GetModelInfo(modelname, nil); + if(mi){ + if(mi->GetColModel()){ + LoadCollisionModel(work_buff+24, *mi->GetColModel(), modelname); + }else{ + CColModel *model = new CColModel; + LoadCollisionModel(work_buff+24, *model, modelname); + mi->SetColModel(model, true); + } + }else{ + debug("colmodel %s can't find a modelinfo\n", modelname); + } + } + + CFileMgr::CloseFile(fd); +} + +void +CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) +{ + int i; + + model.boundingSphere.radius = *(float*)(buf); + model.boundingSphere.center.x = *(float*)(buf+4); + model.boundingSphere.center.y = *(float*)(buf+8); + model.boundingSphere.center.z = *(float*)(buf+12); + model.boundingBox.min.x = *(float*)(buf+16); + model.boundingBox.min.y = *(float*)(buf+20); + model.boundingBox.min.z = *(float*)(buf+24); + model.boundingBox.max.x = *(float*)(buf+28); + model.boundingBox.max.y = *(float*)(buf+32); + model.boundingBox.max.z = *(float*)(buf+36); + model.numSpheres = *(int16*)(buf+40); + buf += 44; + if(model.numSpheres > 0){ + model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere)); + for(i = 0; i < model.numSpheres; i++){ + model.spheres[i].Set(*(float*)buf, *(CVector*)(buf+4), buf[16], buf[17]); + buf += 20; + } + }else + model.spheres = nil; + + model.numLines = *(int16*)buf; + buf += 4; + if(model.numLines > 0){ + model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine)); + for(i = 0; i < model.numLines; i++){ + model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12)); + buf += 24; + } + }else + model.lines = nil; + + model.numBoxes = *(int16*)buf; + buf += 4; + if(model.numBoxes > 0){ + model.boxes = (CColBox*)RwMalloc(model.numBoxes*sizeof(CColBox)); + for(i = 0; i < model.numBoxes; i++){ + model.boxes[i].Set(*(CVector*)buf, *(CVector*)(buf+12), buf[24], buf[25]); + buf += 28; + } + }else + model.boxes = nil; + + int32 numVertices = *(int16*)buf; + buf += 4; + if(numVertices > 0){ + model.vertices = (CVector*)RwMalloc(numVertices*sizeof(CVector)); + for(i = 0; i < numVertices; i++){ + model.vertices[i] = *(CVector*)buf; + if(fabs(model.vertices[i].x) >= 256.0f || + fabs(model.vertices[i].y) >= 256.0f || + fabs(model.vertices[i].z) >= 256.0f) + printf("%s:Collision volume too big\n", modelname); + buf += 12; + } + }else + model.vertices = nil; + + model.numTriangles = *(int16*)buf; + buf += 4; + if(model.numTriangles > 0){ + model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle)); + for(i = 0; i < model.numTriangles; i++){ + model.triangles[i].Set(model.vertices, *(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12], buf[13]); + buf += 16; + } + }else + model.triangles = nil; +} + +static void +GetNameAndLOD(char *nodename, char *name, int *n) +{ + char *underscore = nil; + for(char *s = nodename; *s != '\0'; s++){ + if(s[0] == '_' && (s[1] == 'l' || s[1] == 'L')) + underscore = s; + } + if(underscore){ + strncpy(name, nodename, underscore - nodename); + name[underscore - nodename] = '\0'; + *n = atoi(underscore + 2); + }else{ + strncpy(name, nodename, 24); + *n = 0; + } +} + +RpAtomic* +CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data) +{ + CSimpleModelInfo *mi; + char *nodename, name[24]; + int n; + RpClump *clump = (RpClump*)data; + + nodename = GetFrameNodeName(RpClumpGetFrame(atomic)); + GetNameAndLOD(nodename, name, &n); + mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(name, nil); + if(mi){ + assert(mi->IsSimple()); + mi->SetAtomic(n, atomic); + RpClumpRemoveAtomic(clump, atomic); + RpAtomicSetFrame(atomic, RwFrameCreate()); + CVisibilityPlugins::SetAtomicModelInfo(atomic, mi); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + }else{ + debug("Can't find Atomic %s\n", name); + } + + return atomic; +} + +void +CFileLoader::LoadModelFile(const char *filename) +{ + RwStream *stream; + RpClump *clump; + + debug("Loading model file %s\n", filename); + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); + if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ + clump = RpClumpStreamRead(stream); + if(clump){ + RpClumpForAllAtomics(clump, FindRelatedModelInfoCB, clump); + RpClumpDestroy(clump); + } + } + RwStreamClose(stream, nil); +} + +void +CFileLoader::LoadClumpFile(const char *filename) +{ + RwStream *stream; + RpClump *clump; + char *nodename, name[24]; + int n; + CClumpModelInfo *mi; + + debug("Loading model file %s\n", filename); + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); + while(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ + clump = RpClumpStreamRead(stream); + if(clump){ + nodename = GetFrameNodeName(RpClumpGetFrame(clump)); + GetNameAndLOD(nodename, name, &n); + mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil); + assert(mi->IsClump()); + if(mi) + mi->SetClump(clump); + else + RpClumpDestroy(clump); + } + } + RwStreamClose(stream, nil); +} + +bool +CFileLoader::LoadClumpFile(RwStream *stream, uint32 id) +{ + RpClump *clump; + CClumpModelInfo *mi; + + if(!RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) + return false; + clump = RpClumpStreamRead(stream); + if(clump == nil) + return false; + mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); + mi->SetClump(clump); + if(mi->m_type == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ + // Read LOD ped + clump = RpClumpStreamRead(stream); + if(clump){ + ((CPedModelInfo*)mi)->SetLowDetailClump(clump); + RpClumpDestroy(clump); + } + } + return true; +} + +bool +CFileLoader::StartLoadClumpFile(RwStream *stream, uint32 id) +{ + if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ + printf("Start loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); + return RpClumpGtaStreamRead1(stream); + }else{ + printf("FAILED\n"); + return false; + } +} + +bool +CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id) +{ + RpClump *clump; + CClumpModelInfo *mi; + + printf("Finish loading %s\n", CModelInfo::GetModelInfo(id)->GetName()); + clump = RpClumpGtaStreamRead2(stream); + + if(clump){ + mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); + mi->SetClump(clump); + return true; + }else{ + printf("FAILED\n"); + return false; + } +} + +CSimpleModelInfo *gpRelatedModelInfo; + +bool +CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id) +{ + RpClump *clump; + + if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ + clump = RpClumpStreamRead(stream); + if(clump == nil) + return false; + gpRelatedModelInfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); + RpClumpForAllAtomics(clump, SetRelatedModelInfoCB, clump); + RpClumpDestroy(clump); + } + return true; +} + +RpAtomic* +CFileLoader::SetRelatedModelInfoCB(RpAtomic *atomic, void *data) +{ + char *nodename, name[24]; + int n; + RpClump *clump = (RpClump*)data; + + nodename = GetFrameNodeName(RpAtomicGetFrame(atomic)); + GetNameAndLOD(nodename, name, &n); + gpRelatedModelInfo->SetAtomic(n, atomic); + RpClumpRemoveAtomic(clump, atomic); + RpAtomicSetFrame(atomic, RwFrameCreate()); + CVisibilityPlugins::SetAtomicModelInfo(atomic, gpRelatedModelInfo); + CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil); + return atomic; +} + +RpClump* +CFileLoader::LoadAtomicFile2Return(const char *filename) +{ + RwStream *stream; + RpClump *clump; + + clump = nil; + debug("Loading model file %s\n", filename); + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); + if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) + clump = RpClumpStreamRead(stream); + RwStreamClose(stream, nil); + return clump; +} + +static RwTexture* +MoveTexturesCB(RwTexture *texture, void *pData) +{ + RwTexDictionaryAddTexture((RwTexDictionary*)pData, texture); + return texture; +} + +void +CFileLoader::AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src) +{ + RwTexDictionaryForAllTextures(src, MoveTexturesCB, dst); +} + +void +CFileLoader::LoadObjectTypes(const char *filename) +{ + enum { + NONE, + OBJS, + MLO, + TOBJ, + HIER, + CARS, + PEDS, + PATH, + TWODFX + }; + char *line; + int fd; + int section; + int pathIndex; + char pathTypeStr[20]; + int id, pathType; +// int mlo; + + section = NONE; + pathIndex = -1; +// mlo = 0; + debug("Loading object types from %s...\n", filename); + + fd = CFileMgr::OpenFile(filename, "rb"); + for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ + if(*line == '\0' || *line == '#') + continue; + + if(section == NONE){ + if(strncmp(line, "objs", 4) == 0) section = OBJS; + else if(strncmp(line, "tobj", 4) == 0) section = TOBJ; + else if(strncmp(line, "hier", 4) == 0) section = HIER; + else if(strncmp(line, "cars", 4) == 0) section = CARS; + else if(strncmp(line, "peds", 4) == 0) section = PEDS; + else if(strncmp(line, "path", 4) == 0) section = PATH; + else if(strncmp(line, "2dfx", 4) == 0) section = TWODFX; + }else if(strncmp(line, "end", 3) == 0){ + section = section == MLO ? OBJS : NONE; + }else switch(section){ + case OBJS: + if(strncmp(line, "sta", 3) == 0) + assert(0); // LoadMLO + else + LoadObject(line); + break; + case MLO: + assert(0); // LoadMLOInstance + break; + case TOBJ: + LoadTimeObject(line); + break; + case HIER: + LoadClumpObject(line); + break; + case CARS: + LoadVehicleObject(line); + break; + case PEDS: + LoadPedObject(line); + break; + case PATH: + if(pathIndex == -1){ + id = LoadPathHeader(line, pathTypeStr); + if(strncmp(pathTypeStr, "ped", 4) == 0) + pathType = 1; + else if(strncmp(pathTypeStr, "car", 4) == 0) + pathType = 0; + pathIndex = 0; + }else{ + if(pathType == 1) + LoadPedPathNode(line, id, pathIndex); + else if(pathType == 0) + LoadCarPathNode(line, id, pathIndex); + pathIndex++; + if(pathIndex == 12) + pathIndex = -1; + } + break; + case TWODFX: + Load2dEffect(line); + break; + } + } + CFileMgr::CloseFile(fd); + + for(id = 0; id < MODELINFOSIZE; id++){ + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); + if(mi && mi->IsSimple()) + mi->SetupBigBuilding(); + } +} + +void +SetModelInfoFlags(CSimpleModelInfo *mi, uint32 flags) +{ + mi->m_normalCull = !!(flags & 1); + mi->m_noFade = !!(flags & 2); + mi->m_drawLast = !!(flags & (4|8)); + mi->m_additive = !!(flags & 8); + mi->m_isSubway = !!(flags & 0x10); + mi->m_ignoreLight = !!(flags & 0x20); + mi->m_noZwrite = !!(flags & 0x40); +} + +void +CFileLoader::LoadObject(const char *line) +{ + int id, numObjs; + char model[24], txd[24]; + float dist[3]; + uint32 flags; + int damaged; + CSimpleModelInfo *mi; + + if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) + return; + + switch(numObjs){ + case 1: + sscanf(line, "%d %s %s %d %f %d", + &id, model, txd, &numObjs, &dist[0], &flags); + damaged = 0; + break; + case 2: + sscanf(line, "%d %s %s %d %f %f %d", + &id, model, txd, &numObjs, &dist[0], &dist[1], &flags); + damaged = dist[0] < dist[1] ? // Are distances increasing? + 0 : // Yes, no damage model + 1; // No, 1 is damaged + break; + case 3: + sscanf(line, "%d %s %s %d %f %f %f %d", + &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags); + damaged = dist[0] < dist[1] ? // Are distances increasing? + (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model + 1; // No, 1 and 2 are damaged + break; + } + + mi = CModelInfo::AddSimpleModel(id); + mi->SetName(model); + mi->SetNumAtomics(numObjs); + mi->SetLodDistances(dist); + SetModelInfoFlags(mi, flags); + mi->m_firstDamaged = damaged; + mi->SetTexDictionary(txd); + MatchModelString(model, id); +} + +void +CFileLoader::LoadTimeObject(const char *line) +{ + int id, numObjs; + char model[24], txd[24]; + float dist[3]; + uint32 flags; + int timeOn, timeOff; + int damaged; + CTimeModelInfo *mi, *other; + + if(sscanf(line, "%d %s %s %d", &id, model, txd, &numObjs) != 4) + return; + + switch(numObjs){ + case 1: + sscanf(line, "%d %s %s %d %f %d %d %d", + &id, model, txd, &numObjs, &dist[0], &flags, &timeOn, &timeOff); + damaged = 0; + break; + case 2: + sscanf(line, "%d %s %s %d %f %f %d %d %d", + &id, model, txd, &numObjs, &dist[0], &dist[1], &flags, &timeOn, &timeOff); + damaged = dist[0] < dist[1] ? // Are distances increasing? + 0 : // Yes, no damage model + 1; // No, 1 is damaged + break; + case 3: + sscanf(line, "%d %s %s %d %f %f %f %d %d %d", + &id, model, txd, &numObjs, &dist[0], &dist[1], &dist[2], &flags, &timeOn, &timeOff); + damaged = dist[0] < dist[1] ? // Are distances increasing? + (dist[1] < dist[2] ? 0 : 2) : // Yes, only 2 can still be a damage model + 1; // No, 1 and 2 are damaged + break; + } + + mi = CModelInfo::AddTimeModel(id); + mi->SetName(model); + mi->SetNumAtomics(numObjs); + mi->SetLodDistances(dist); + SetModelInfoFlags(mi, flags); + mi->m_firstDamaged = damaged; + mi->SetTimes(timeOn, timeOff); + mi->SetTexDictionary(txd); + other = mi->FindOtherTimeModel(); + if(other) + other->SetOtherTimeModel(id); + MatchModelString(model, id); +} + +void +CFileLoader::LoadClumpObject(const char *line) +{ + int id; + char model[24], txd[24]; + CClumpModelInfo *mi; + + if(sscanf(line, "%d %s %s", &id, &model, &txd) == 3){ + mi = CModelInfo::AddClumpModel(id); + mi->SetName(model); + mi->SetTexDictionary(txd); + mi->SetColModel(&CTempColModels::ms_colModelBBox); + } +} + +void +CFileLoader::LoadVehicleObject(const char *line) +{ + int id; + char model[24], txd[24]; + char type[8], handlingId[16], gamename[32], vehclass[12]; + uint32 frequency, comprules; + int32 level, misc; + float wheelScale; + CVehicleModelInfo *mi; + char *p; + + sscanf(line, "%d %s %s %s %s %s %s %d %d %x %d %f", + &id, model, txd, + type, handlingId, gamename, vehclass, + &frequency, &level, &comprules, &misc, &wheelScale); + + mi = CModelInfo::AddVehicleModel(id); + mi->SetName(model); + mi->SetTexDictionary(txd); + for(p = gamename; *p; p++) + if(*p == '_') *p = ' '; + strncpy(mi->m_gameName, gamename, 32); + mi->m_level = level; + mi->m_compRules = comprules; + + if(strncmp(type, "car", 4) == 0){ + mi->m_wheelId = misc; + mi->m_wheelScale = wheelScale; + mi->m_vehicleType = VEHICLE_TYPE_CAR; + }else if(strncmp(type, "boat", 5) == 0){ + mi->m_vehicleType = VEHICLE_TYPE_BOAT; + }else if(strncmp(type, "train", 6) == 0){ + mi->m_vehicleType = VEHICLE_TYPE_TRAIN; + }else if(strncmp(type, "heli", 5) == 0){ + mi->m_vehicleType = VEHICLE_TYPE_HELI; + }else if(strncmp(type, "plane", 6) == 0){ + mi->m_wheelId = misc; + mi->m_wheelScale = 1.0f; + mi->m_vehicleType = VEHICLE_TYPE_PLANE; + }else if(strncmp(type, "bike", 5) == 0){ + mi->m_bikeSteerAngle = misc; + mi->m_wheelScale = wheelScale; + mi->m_vehicleType = VEHICLE_TYPE_BIKE; + }else + assert(0); + + mi->m_handlingId = mod_HandlingManager.GetHandlingId(handlingId); + + // Well this is kinda dumb.... + if(strncmp(vehclass, "poorfamily", 11) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_POOR; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_POOR); + }else if(strncmp(vehclass, "richfamily", 11) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_RICH; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_RICH); + }else if(strncmp(vehclass, "executive", 10) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_EXECUTIVE; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_EXECUTIVE); + }else if(strncmp(vehclass, "worker", 7) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_WORKER; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_WORKER); + }else if(strncmp(vehclass, "special", 8) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_SPECIAL; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_SPECIAL); + }else if(strncmp(vehclass, "big", 4) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_BIG; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_BIG); + }else if(strncmp(vehclass, "taxi", 5) == 0){ + mi->m_vehicleClass = VEHICLE_CLASS_TAXI; + while(frequency-- > 0) + CCarCtrl::AddToCarArray(id, VEHICLE_CLASS_TAXI); + } +} + +void +CFileLoader::LoadPedObject(const char *line) +{ + int id; + char model[24], txd[24]; + char pedType[24], pedStats[24], animGroup[24]; + int carsCanDrive; + CPedModelInfo *mi; + int animGroupId; + + if(sscanf(line, "%d %s %s %s %s %s %x", + &id, model, txd, + pedType, pedStats, animGroup, &carsCanDrive) != 7) + return; + + mi = CModelInfo::AddPedModel(id); + mi->SetName(model); + mi->SetTexDictionary(txd); + mi->SetColModel(&CTempColModels::ms_colModelPed1); + mi->m_pedType = CPedType::FindPedType(pedType); + mi->m_pedStatType = CPedStats::GetPedStatType(pedStats); + for(animGroupId = 0; animGroupId < NUM_ANIM_ASSOC_GROUPS; animGroupId++) + if(strcmp(animGroup, CAnimManager::GetAnimGroupName((AssocGroupId)animGroupId)) == 0) + break; + mi->m_animGroup = animGroupId; + + // ??? + CModelInfo::GetModelInfo(MI_LOPOLYGUY)->SetColModel(&CTempColModels::ms_colModelPed1); +} + +int +CFileLoader::LoadPathHeader(const char *line, char *type) +{ + int id; + char modelname[32]; + + sscanf(line, "%s %d %s", type, &id, modelname); + return id; +} + +void +CFileLoader::LoadPedPathNode(const char *line, int id, int node) +{ + int type, next, cross; + float x, y, z, width; + + sscanf(line, "%d %d %d %f %f %f %f", &type, &next, &cross, &x, &y, &z, &width); + ThePaths.StoreNodeInfoPed(id, node, type, next, x, y, z, 0, !!cross); +} + +void +CFileLoader::LoadCarPathNode(const char *line, int id, int node) +{ + int type, next, cross, numLeft, numRight; + float x, y, z, width; + + sscanf(line, "%d %d %d %f %f %f %f %d %d", &type, &next, &cross, &x, &y, &z, &width, &numLeft, &numRight); + ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight); +} + + +void +CFileLoader::Load2dEffect(const char *line) +{ + int id, r, g, b, a, type; + float x, y, z; + char corona[32], shadow[32]; + int shadowIntens, lightType, roadReflection, flare, flags, probability; + CBaseModelInfo *mi; + C2dEffect *effect; + char *p; + + sscanf(line, "%d %f %f %f %d %d %d %d %d", &id, &x, &y, &z, &r, &g, &b, &a, &type); + + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(CTxdStore::FindTxdSlot("particle")); + + mi = CModelInfo::GetModelInfo(id); + effect = CModelInfo::Get2dEffectStore().alloc(); + mi->Add2dEffect(effect); + effect->pos = CVector(x, y, z); + effect->col = CRGBA(r, g, b, a); + effect->type = type; + + switch(effect->type){ + case EFFECT_LIGHT: + while(*line++ != '"'); + p = corona; + while(*line != '"') *p++ = *line++; + *p = '\0'; + line++; + + while(*line++ != '"'); + p = shadow; + while(*line != '"') *p++ = *line++; + *p = '\0'; + line++; + + sscanf(line, "%f %f %f %f %d %d %d %d %d", + &effect->light.dist, + &effect->light.range, + &effect->light.size, + &effect->light.shadowRange, + &shadowIntens, &lightType, &roadReflection, &flare, &flags); + effect->light.corona = RwTextureRead(corona, nil); + effect->light.shadow = RwTextureRead(shadow, nil); + effect->light.shadowIntensity = shadowIntens; + effect->light.lightType = lightType; + effect->light.roadReflection = roadReflection; + effect->light.flareType = flare; + // TODO: check out the flags + if(flags & 4) + flags &= ~2; + effect->light.flags = flags; + break; + + case EFFECT_PARTICLE: + sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f", + &id, &x, &y, &z, &r, &g, &b, &a, &type, + &effect->particle.particleType, + &effect->particle.dir.x, + &effect->particle.dir.y, + &effect->particle.dir.z, + &effect->particle.scale); + break; + + case EFFECT_ATTRACTOR: + sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %d", + &id, &x, &y, &z, &r, &g, &b, &a, &type, + &flags, + &effect->attractor.dir.x, + &effect->attractor.dir.y, + &effect->attractor.dir.z, + &probability); + effect->attractor.flags = flags; + effect->attractor.probability = probability; + break; + } + + CTxdStore::PopCurrentTxd(); +} + +void +CFileLoader::LoadScene(const char *filename) +{ + enum { + NONE, + INST, + ZONE, + CULL, + PICK, + PATH, + }; + char *line; + int fd; + int section; + int pathIndex; + char pathTypeStr[20]; + + section = NONE; + pathIndex = -1; + debug("Creating objects from %s...\n", filename); + + fd = CFileMgr::OpenFile(filename, "rb"); + for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ + if(*line == '\0' || *line == '#') + continue; + + if(section == NONE){ + if(strncmp(line, "inst", 4) == 0) section = INST; + else if(strncmp(line, "zone", 4) == 0) section = ZONE; + else if(strncmp(line, "cull", 4) == 0) section = CULL; + else if(strncmp(line, "pick", 4) == 0) section = PICK; + else if(strncmp(line, "path", 4) == 0) section = PATH; + }else if(strncmp(line, "end", 3) == 0){ + section = NONE; + }else switch(section){ + case INST: + LoadObjectInstance(line); + break; + case ZONE: + LoadZone(line); + break; + case CULL: + LoadCullZone(line); + break; + case PICK: + // unused + LoadPickup(line); + break; + case PATH: + // unfinished in the game + if(pathIndex == -1){ + LoadPathHeader(line, pathTypeStr); + // type not set + pathIndex = 0; + }else{ + // nodes not loaded + pathIndex++; + if(pathIndex == 12) + pathIndex = -1; + } + break; + } + } + CFileMgr::CloseFile(fd); + + debug("Finished loading IPL\n"); +} + +void +CFileLoader::LoadObjectInstance(const char *line) +{ + int id; + char name[24]; + RwV3d trans, scale, axis; + float angle; + CSimpleModelInfo *mi; + RwMatrix *xform; + CEntity *entity; + + if(sscanf(line, "%d %s %f %f %f %f %f %f %f %f %f %f", + &id, name, + &trans.x, &trans.y, &trans.z, + &scale.x, &scale.y, &scale.z, + &axis.x, &axis.y, &axis.z, &angle) != 12) + return; + + mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); + if(mi == nil) + return; + assert(mi->IsSimple()); + + angle = -RADTODEG(2.0f * acosf(angle)); + xform = RwMatrixCreate(); + RwMatrixRotate(xform, &axis, angle, rwCOMBINEREPLACE); + RwMatrixTranslate(xform, &trans, rwCOMBINEPOSTCONCAT); + + if(mi->GetObjectID() == -1){ + if(ThePaths.IsPathObject(id)){ + entity = new CTreadable; + ThePaths.RegisterMapObject((CTreadable*)entity); + }else + entity = new CBuilding; + entity->SetModelIndexNoCreate(id); + entity->GetMatrix() = CMatrix(xform); + entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); + if(mi->IsSimple()){ + if(mi->m_isBigBuilding) + entity->SetupBigBuilding(); + if(mi->m_isSubway) + entity->bIsSubway = true; + } + if(mi->GetLargestLodDistance() < 2.0f) + entity->bIsVisible = false; + CWorld::Add(entity); + }else{ + entity = new CDummyObject; + entity->SetModelIndexNoCreate(id); + entity->GetMatrix() = CMatrix(xform); + CWorld::Add(entity); + if(IsGlass(entity->GetModelIndex())) + entity->bIsVisible = false; + entity->m_level = CTheZones::GetLevelFromPosition(entity->GetPosition()); + } + + RwMatrixDestroy(xform); +} + +void +CFileLoader::LoadZone(const char *line) +{ + char name[24]; + int type, level; + float minx, miny, minz; + float maxx, maxy, maxz; + + if(sscanf(line, "%s %d %f %f %f %f %f %f %d", name, &type, &minx, &miny, &minz, &maxx, &maxy, &maxz, &level) == 9) + CTheZones::CreateZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level); +} + +void +CFileLoader::LoadCullZone(const char *line) +{ + CVector pos; + float minx, miny, minz; + float maxx, maxy, maxz; + int flags; + int wantedLevelDrop = 0; + + sscanf(line, "%f %f %f %f %f %f %f %f %f %d %d", + &pos.x, &pos.y, &pos.z, + &minx, &miny, &minz, + &maxx, &maxy, &maxz, + &flags, &wantedLevelDrop); + CCullZones::AddCullZone(pos, minx, maxx, miny, maxy, minz, maxz, flags, wantedLevelDrop); +} + +// unused +void +CFileLoader::LoadPickup(const char *line) +{ + int id; + float x, y, z; + + sscanf(line, "%d %f %f %f", &id, &x, &y, &z); +} + +void +CFileLoader::LoadMapZones(const char *filename) +{ + enum { + NONE, + INST, + ZONE, + CULL, + PICK, + PATH, + }; + char *line; + int fd; + int section; + + section = NONE; + debug("Creating zones from %s...\n", filename); + + fd = CFileMgr::OpenFile(filename, "rb"); + for(line = CFileLoader::LoadLine(fd); line; line = CFileLoader::LoadLine(fd)){ + if(*line == '\0' || *line == '#') + continue; + + if(section == NONE){ + if(strncmp(line, "zone", 4) == 0) section = ZONE; + }else if(strncmp(line, "end", 3) == 0){ + section = NONE; + }else switch(section){ + case ZONE: { + char name[24]; + int type, level; + float minx, miny, minz; + float maxx, maxy, maxz; + if(sscanf(line, "%s %d %f %f %f %f %f %f %d", + &name, &type, + &minx, &miny, &minz, + &maxx, &maxy, &maxz, + &level) == 9) + CTheZones::CreateMapZone(name, (eZoneType)type, minx, miny, minz, maxx, maxy, maxz, (eLevelName)level); + } + break; + } + } + CFileMgr::CloseFile(fd); + + debug("Finished loading IPL\n"); +} + + +STARTPATCHES + InjectHook(0x476290, CFileLoader::LoadLevel, PATCH_JUMP); + + InjectHook(0x476520, CFileLoader::LoadCollisionFromDatFile, PATCH_JUMP); + InjectHook(0x4761D0, CFileLoader::LoadLine, PATCH_JUMP); + InjectHook(0x4765B0, CFileLoader::LoadTexDictionary, PATCH_JUMP); + InjectHook(0x478B20, CFileLoader::LoadCollisionFile, PATCH_JUMP); + InjectHook(0x478C20, CFileLoader::LoadCollisionModel, PATCH_JUMP); + InjectHook(0x476750, CFileLoader::LoadModelFile, PATCH_JUMP); + InjectHook(0x476810, (void (*)(const char*))CFileLoader::LoadClumpFile, PATCH_JUMP); + InjectHook(0x476990, (bool (*)(RwStream*,uint32))CFileLoader::LoadClumpFile, PATCH_JUMP); + InjectHook(0x476A20, CFileLoader::StartLoadClumpFile, PATCH_JUMP); + InjectHook(0x476A70, CFileLoader::FinishLoadClumpFile, PATCH_JUMP); + InjectHook(0x476930, CFileLoader::LoadAtomicFile, PATCH_JUMP); + InjectHook(0x4767C0, CFileLoader::LoadAtomicFile2Return, PATCH_JUMP); + InjectHook(0x476630, CFileLoader::AddTexDictionaries, PATCH_JUMP); + + InjectHook(0x476AC0, CFileLoader::LoadObjectTypes, PATCH_JUMP); + InjectHook(0x477040, CFileLoader::LoadObject, PATCH_JUMP); + InjectHook(0x4774B0, CFileLoader::LoadTimeObject, PATCH_JUMP); + InjectHook(0x477920, CFileLoader::LoadClumpObject, PATCH_JUMP); + InjectHook(0x477990, CFileLoader::LoadVehicleObject, PATCH_JUMP); + InjectHook(0x477DE0, CFileLoader::LoadPedObject, PATCH_JUMP); + InjectHook(0x477ED0, CFileLoader::LoadPathHeader, PATCH_JUMP); + InjectHook(0x477FF0, CFileLoader::LoadCarPathNode, PATCH_JUMP); + InjectHook(0x477F00, CFileLoader::LoadPedPathNode, PATCH_JUMP); + InjectHook(0x4780E0, CFileLoader::Load2dEffect, PATCH_JUMP); + + InjectHook(0x478370, CFileLoader::LoadScene, PATCH_JUMP); + InjectHook(0x4786B0, CFileLoader::LoadObjectInstance, PATCH_JUMP); + InjectHook(0x478A00, CFileLoader::LoadZone, PATCH_JUMP); + InjectHook(0x478A90, CFileLoader::LoadCullZone, PATCH_JUMP); + + InjectHook(0x478550, CFileLoader::LoadMapZones, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/FileLoader.h b/src/core/FileLoader.h new file mode 100644 index 00000000..f9121ace --- /dev/null +++ b/src/core/FileLoader.h @@ -0,0 +1,42 @@ +#pragma once + +class CFileLoader +{ + static char ms_line[256]; +public: + static void LoadLevel(const char *filename); + static void LoadCollisionFromDatFile(int currlevel); + static char *LoadLine(int fd); + static RwTexDictionary *LoadTexDictionary(const char *filename); + static void LoadCollisionFile(const char *filename); + static void LoadCollisionModel(uint8 *buf, CColModel &model, char *name); + static void LoadModelFile(const char *filename); + static RpAtomic *FindRelatedModelInfoCB(RpAtomic *atomic, void *data); + static void LoadClumpFile(const char *filename); + static bool LoadClumpFile(RwStream *stream, uint32 id); + static bool StartLoadClumpFile(RwStream *stream, uint32 id); + static bool FinishLoadClumpFile(RwStream *stream, uint32 id); + static bool LoadAtomicFile(RwStream *stream, uint32 id); + static RpAtomic *SetRelatedModelInfoCB(RpAtomic *atomic, void *data); + static RpClump *LoadAtomicFile2Return(const char *filename); + static void AddTexDictionaries(RwTexDictionary *dst, RwTexDictionary *src); + + static void LoadObjectTypes(const char *filename); + static void LoadObject(const char *line); + static void LoadTimeObject(const char *line); + static void LoadClumpObject(const char *line); + static void LoadVehicleObject(const char *line); + static void LoadPedObject(const char *line); + static int LoadPathHeader(const char *line, char *type); + static void LoadPedPathNode(const char *line, int id, int node); + static void LoadCarPathNode(const char *line, int id, int node); + static void Load2dEffect(const char *line); + + static void LoadScene(const char *filename); + static void LoadObjectInstance(const char *line); + static void LoadZone(const char *line); + static void LoadCullZone(const char *line); + static void LoadPickup(const char *line); + + static void LoadMapZones(const char *filename); +}; diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp new file mode 100644 index 00000000..954fcdef --- /dev/null +++ b/src/core/FileMgr.cpp @@ -0,0 +1,300 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" + +const char *_psGetUserFilesFolder(); + +/* + * Windows FILE is BROKEN for GTA. + * + * We need to support mapping between LF and CRLF for text files + * but we do NOT want to end the file at the first sight of a SUB character. + * So here is a simple implementation of a FILE interface that works like GTA expects. + */ + +struct myFILE +{ + bool isText; + FILE *file; +}; + +#define NUMFILES 20 +static myFILE myfiles[NUMFILES]; + +/* Force file to open as binary but remember if it was text mode */ +static int +myfopen(const char *filename, const char *mode) +{ + int fd; + char realmode[10], *p; + + for(fd = 1; fd < NUMFILES; fd++) + if(myfiles[fd].file == nil) + goto found; + return 0; // no free fd +found: + myfiles[fd].isText = strchr(mode, 'b') == nil; + p = realmode; + while(*mode) + if(*mode != 't' && *mode != 'b') + *p++ = *mode++; + else + mode++; + *p++ = 'b'; + *p = '\0'; + myfiles[fd].file = fopen(filename, realmode); + if(myfiles[fd].file == nil) + return 0; + return fd; +} + +static int +myfclose(int fd) +{ + int ret; + assert(fd < NUMFILES); + if(myfiles[fd].file){ + ret = fclose(myfiles[fd].file); + myfiles[fd].file = nil; + return ret; + } + return EOF; +} + +static int +myfgetc(int fd) +{ + int c; + c = fgetc(myfiles[fd].file); + if(myfiles[fd].isText && c == 015){ + /* translate CRLF to LF */ + c = fgetc(myfiles[fd].file); + if(c == 012) + return c; + ungetc(c, myfiles[fd].file); + return 015; + } + return c; +} + +static int +myfputc(int c, int fd) +{ + /* translate LF to CRLF */ + if(myfiles[fd].isText && c == 012) + fputc(015, myfiles[fd].file); + return fputc(c, myfiles[fd].file); +} + +static char* +myfgets(char *buf, int len, int fd) +{ + int c; + char *p; + + p = buf; + len--; // NUL byte + while(len--){ + c = myfgetc(fd); + if(c == EOF){ + if(p == buf) + return nil; + break; + } + *p++ = c; + if(c == '\n') + break; + } + *p = '\0'; + return buf; +} + +static int +myfread(void *buf, size_t elt, size_t n, int fd) +{ + if(myfiles[fd].isText){ + char *p; + size_t i; + int c; + + n *= elt; + p = (char*)buf; + for(i = 0; i < n; i++){ + c = myfgetc(fd); + if(c == EOF) + break; + *p++ = c; + } + return i / elt; + } + return fread(buf, elt, n, myfiles[fd].file); +} + +static int +myfwrite(void *buf, size_t elt, size_t n, int fd) +{ + if(myfiles[fd].isText){ + char *p; + size_t i; + int c; + + n *= elt; + p = (char*)buf; + for(i = 0; i < n; i++){ + c = *p++; + myfputc(c, fd); + if(feof(myfiles[fd].file)) // is this right? + break; + } + return i / elt; + } + return fwrite(buf, elt, n, myfiles[fd].file); +} + +static int +myfseek(int fd, long offset, int whence) +{ + return fseek(myfiles[fd].file, offset, whence); +} + +static int +myfeof(int fd) +{ + return feof(myfiles[fd].file); +// return ferror(myfiles[fd].file); +} + + +char *CFileMgr::ms_rootDirName = (char*)0x5F18F8; +char *CFileMgr::ms_dirName = (char*)0x713CA8; + +void +CFileMgr::Initialise(void) +{ + _getcwd(ms_rootDirName, 128); + strcat(ms_rootDirName, "\\"); +} + +void +CFileMgr::ChangeDir(const char *dir) +{ + if(*dir == '\\'){ + strcpy(ms_dirName, ms_rootDirName); + dir++; + } + if(*dir != '\0'){ + strcat(ms_dirName, dir); + // BUG in the game it seems, it's off by one + if(dir[strlen(dir)-1] != '\\') + strcat(ms_dirName, "\\"); + } + chdir(ms_dirName); +} + +void +CFileMgr::SetDir(const char *dir) +{ + strcpy(ms_dirName, ms_rootDirName); + if(*dir != '\0'){ + strcat(ms_dirName, dir); + // BUG in the game it seems, it's off by one + if(dir[strlen(dir)-1] != '\\') + strcat(ms_dirName, "\\"); + } + chdir(ms_dirName); +} + +void +CFileMgr::SetDirMyDocuments(void) +{ + SetDir(""); // better start at the root if user directory is relative + chdir(_psGetUserFilesFolder()); +} + +int +CFileMgr::LoadFile(const char *file, uint8 *buf, int unused, const char *mode) +{ + int fd; + int n, len; + + fd = myfopen(file, mode); + if(fd == 0) + return 0; + len = 0; + do{ + n = myfread(buf + len, 1, 0x4000, fd); + if(n < 0) + return -1; + len += n; + }while(n == 0x4000); + buf[len] = 0; + myfclose(fd); + return len; +} + +int +CFileMgr::OpenFile(const char *file, const char *mode) +{ + return myfopen(file, mode); +} + +int +CFileMgr::OpenFileForWriting(const char *file) +{ + return OpenFile(file, "wb"); +} + +int +CFileMgr::Read(int fd, char *buf, int len) +{ + return myfread(buf, 1, len, fd); +} + +int +CFileMgr::Write(int fd, char *buf, int len) +{ + return myfwrite(buf, 1, len, fd); +} + +bool +CFileMgr::Seek(int fd, int offset, int whence) +{ + return !!myfseek(fd, offset, whence); +} + +bool +CFileMgr::ReadLine(int fd, char *buf, int len) +{ + return myfgets(buf, len, fd) != nil; +} + +int +CFileMgr::CloseFile(int fd) +{ + return myfclose(fd); +} + +int +CFileMgr::GetErrorReadWrite(int fd) +{ + return myfeof(fd); +} + +STARTPATCHES + InjectHook(0x478F80, CFileMgr::Initialise, PATCH_JUMP); + InjectHook(0x478FB0, CFileMgr::ChangeDir, PATCH_JUMP); + InjectHook(0x479020, CFileMgr::SetDir, PATCH_JUMP); + InjectHook(0x479080, CFileMgr::SetDirMyDocuments, PATCH_JUMP); + InjectHook(0x479090, CFileMgr::LoadFile, PATCH_JUMP); + InjectHook(0x479100, CFileMgr::OpenFile, PATCH_JUMP); + InjectHook(0x479120, CFileMgr::OpenFileForWriting, PATCH_JUMP); + InjectHook(0x479140, CFileMgr::Read, PATCH_JUMP); + InjectHook(0x479160, CFileMgr::Write, PATCH_JUMP); + InjectHook(0x479180, CFileMgr::Seek, PATCH_JUMP); + InjectHook(0x4791D0, CFileMgr::ReadLine, PATCH_JUMP); + InjectHook(0x479200, CFileMgr::CloseFile, PATCH_JUMP); + InjectHook(0x479210, CFileMgr::GetErrorReadWrite, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/FileMgr.h b/src/core/FileMgr.h new file mode 100644 index 00000000..bab86e38 --- /dev/null +++ b/src/core/FileMgr.h @@ -0,0 +1,21 @@ +#pragma once + +class CFileMgr +{ + static char *ms_rootDirName; //[128]; + static char *ms_dirName; //[128]; +public: + static void Initialise(void); + static void ChangeDir(const char *dir); + static void SetDir(const char *dir); + static void SetDirMyDocuments(void); + static int LoadFile(const char *file, uint8 *buf, int unused, const char *mode); + static int OpenFile(const char *file, const char *mode); + static int OpenFileForWriting(const char *file); + static int Read(int fd, char *buf, int len); + static int Write(int fd, char *buf, int len); + static bool Seek(int fd, int offset, int whence); + static bool ReadLine(int fd, char *buf, int len); + static int CloseFile(int fd); + static int GetErrorReadWrite(int fd); +}; diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp new file mode 100644 index 00000000..05d72199 --- /dev/null +++ b/src/core/Fire.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "Fire.h" + +WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); } \ No newline at end of file diff --git a/src/core/Fire.h b/src/core/Fire.h new file mode 100644 index 00000000..c7f83fd8 --- /dev/null +++ b/src/core/Fire.h @@ -0,0 +1,23 @@ +#pragma once +#include "common.h" +#include "Entity.h" + +class CFire +{ + char m_bIsOngoing; + char m_bExists; + char m_bPropogationFlag; + char m_bAudioSet; + CVector m_vecPos; + CEntity *m_pEntity; + CEntity *m_pSource; + int m_nExtinguishTime; + int m_nStartTime; + int field_20; + int field_24; + int field_28; + float field_2C; + +public: + void Extinguish(void); +}; \ No newline at end of file diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp new file mode 100644 index 00000000..fdb2420b --- /dev/null +++ b/src/core/Frontend.cpp @@ -0,0 +1,2353 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include "common.h" +#include "patcher.h" +#include "win.h" +#include "Frontend.h" +#include "Font.h" +#include "Pad.h" +#include "Text.h" +#include "main.h" +#include "Timer.h" +#include "Game.h" +#include "DMAudio.h" +#include "MusicManager.h" +#include "FileMgr.h" +#include "Streaming.h" +#include "TxdStore.h" +#include "General.h" +#include "PCSave.h" +#include "Script.h" +#include "Camera.h" +#include "MenuScreens.h" +#include "ControllerConfig.h" +#include "Vehicle.h" +#include "MBlur.h" +#include "PlayerSkin.h" + +int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78; +int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92; +int8 &CMenuManager::m_DisplayControllerOnFoot = *(int8*)0x95CD8D; +int8 &CMenuManager::m_PrefsVsync = *(int8*)0x5F2E58; +int8 &CMenuManager::m_PrefsVsyncDisp = *(int8*)0x5F2E5C; +int8 &CMenuManager::m_PrefsFrameLimiter = *(int8*)0x5F2E60; +int8 &CMenuManager::m_PrefsShowSubtitles = *(int8*)0x5F2E54; +int8 &CMenuManager::m_PrefsSpeakers = *(int8*)0x95CD7E; +int8 &CMenuManager::m_ControlMethod = *(int8*)0x8F5F7C; +int8 &CMenuManager::m_PrefsDMA = *(int8*)0x5F2F74; +int8 &CMenuManager::m_PrefsLanguage = *(int8*)0x941238; + +bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64; +bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4; +bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A; + +int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23; +int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4; +int8 &CMenuManager::m_bDisableMouseSteering = *(int8*)0x60252C; +int32 &CMenuManager::m_PrefsBrightness = *(int32*)0x5F2E50; +float &CMenuManager::m_PrefsLOD = *(float*)0x8F42C4; +int8 &CMenuManager::m_bFrontEnd_ReloadObrTxtGxt = *(int8*)0x628CFC; +int32 &CMenuManager::m_PrefsMusicVolume = *(int32*)0x5F2E4C; +int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48; + +uint8 *CMenuManager::m_PrefsSkinFile = (uint8*)0x5F2E74; + +CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8; + +// Move this somewhere else. +float lodMultiplier = *(float*)0x5F726C; + +// Stuff not in CMenuManager: +int VibrationTime; +char* pEditString; +int32 pControlEdit; +int8 DisplayComboButtonErrMsg; +bool MouseButtonJustClicked; +bool JoyButtonJustClicked; + +// Frontend inputs. +bool GetPadBack(); +bool GetPadExitEnter(); +bool GetPadForward(); +bool GetPadMoveUp(); +bool GetPadMoveDown(); +bool GetPadMoveLeft(); +bool GetPadMoveRight(); +bool GetMouseForward(); +bool GetMouseBack(); +bool GetMousePos(); +bool GetMouseMoveLeft(); +bool GetMouseMoveRight(); +bool GetPadInput(); +bool GetMouseInput(); + +char *FrontendFilenames[] = { + "fe2_mainpanel_ul", + "fe2_mainpanel_ur", + "fe2_mainpanel_dl", + "fe2_mainpanel_dr", + "fe2_mainpanel_dr2", + "fe2_tabactive", + "fe_iconbrief", + "fe_iconstats", + "fe_iconcontrols", + "fe_iconsave", + "fe_iconaudio", + "fe_icondisplay", + "fe_iconlanguage", + "fe_controller", + "fe_controllersh", + "fe_arrows1", + "fe_arrows2", + "fe_arrows3", + "fe_arrows4", + "fe_radio1", // HEAD_RADIO + "fe_radio2", // DOUBLE_CLEF + "fe_radio5", // JAH_RADIO + "fe_radio7", // RISE_FM + "fe_radio8", // LIPS_106 + "fe_radio3", // GAME_FM + "fe_radio4", // MSX_FM + "fe_radio6", // FLASHBACK + "fe_radio9", // CHATTERBOX +}; + +char *MenuFilenames[] = { + "connection24", "", + "findgame24", "", + "hostgame24", "", + "mainmenu24", "", + "Playersetup24", "", + "singleplayer24", "", + "multiplayer24", "", + "dmalogo128", "dmalogo128m", + "gtaLogo128", "gtaLogo128", + "rockstarLogo128", "rockstarlogo128m", + "gamespy256", "gamespy256a", + "mouse", "mousetimera", + "mousetimer", "mousetimera", + "mp3logo", "mp3logoA", + "downOFF", "buttonA", + "downON", "buttonA", + "upOFF", "buttonA", + "upON", "buttonA", + "gta3logo256", "gta3logo256m", + nil, nil +}; + +#if 1 +WRAPPER void CMenuManager::BuildStatLine(char *, void *, uint16, void *) { EAXJMP(0x483870); } +#else +void CMenuManager::BuildStatLine(char *, void *, uint16, void *) +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); } +#else +void CMenuManager::CentreMousePointer() +{ + tagPOINT Point; + + if (SCREEN_WIDTH * 0.5f == 0.0f && 0.0f == SCREEN_HEIGHT * 0.5f) { + Point.x = SCREEN_WIDTH / 2; + Point.y = SCREEN_HEIGHT / 2; + ClientToScreen(PSGLOBAL(window), &Point); + SetCursorPos(Point.x, Point.y); + + PSGLOBAL(lastMousePos.x) = SCREEN_WIDTH / 2; + PSGLOBAL(lastMousePos.y) = SCREEN_HEIGHT / 2; + } +} +#endif + +#if 1 +WRAPPER void CMenuManager::CheckCodesForControls(int, int) { EAXJMP(0x48A950); } +#else +void CMenuManager::CheckCodesForControls() +{ + +} +#endif + +#if 0 +WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); } +#else +bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2) +{ + return m_nMousePosX > x1 && m_nMousePosX < x2 && + m_nMousePosY > y1 && m_nMousePosY < y2; +} +#endif + +void CMenuManager::CheckSliderMovement(int value) +{ + float fBrightness = 0.0f; + float fDrawDistance = 0.0f; + float fRadioVolume = 0.0f; + float fSfxVolume = 0.0f; + float fMouseSens = 0.0f; + + switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) { + case MENUACTION_BRIGHTNESS: + fBrightness = m_PrefsBrightness + (value * (512.0f) / 16.0f); + + if (fBrightness > 511.0f) + fBrightness = 511.0f; + else if (fBrightness < 0.0f) + fBrightness = 0.0f; + + m_PrefsBrightness = fBrightness; + SaveSettings(); + break; + case MENUACTION_DRAWDIST: + fDrawDistance = m_PrefsLOD + (value * (1.8f - 0.8f) / 16.0f); + + if (fDrawDistance > 1.8f) + fDrawDistance = 1.8f; + else if (fDrawDistance < 0.8f) + fDrawDistance = 0.8f; + + m_PrefsLOD = fDrawDistance; + SaveSettings(); + break; + case MENUACTION_MUSICVOLUME: + fRadioVolume = m_PrefsMusicVolume + (value * (128.0f) / 16.0f); + + if (fRadioVolume > 127.0f) + fRadioVolume = 127.0f; + else if (fRadioVolume < 0.0f) + fRadioVolume = 0.0f; + + m_PrefsMusicVolume = fRadioVolume; + DMAudio.SetMusicMasterVolume(fRadioVolume); + SaveSettings(); + break; + case MENUACTION_SFXVOLUME: + fSfxVolume = m_PrefsSfxVolume + (value * (128.0f) / 16.0f); + + if (fSfxVolume > 127) + fSfxVolume = 127; + else if (fSfxVolume < 0.0f) + fSfxVolume = 0.0f; + + m_PrefsSfxVolume = fSfxVolume; + DMAudio.SetEffectsMasterVolume(fSfxVolume); + SaveSettings(); + break; + case MENUACTION_MOUSESENS: + fMouseSens = TheCamera.m_fMouseAccelHorzntl + (value * (0.005f - 0.0003125f) / 16.0f); + + if (fMouseSens > 0.005f) + fMouseSens = 0.005f; + else if (fMouseSens < 0.0003125f) + fMouseSens = 0.0003125f; + + TheCamera.m_fMouseAccelHorzntl = fMouseSens; + + // BUG: game doesn't set Y Axis. + TheCamera.m_fMouseAccelVertical = fMouseSens; + SaveSettings(); + break; + }; +} + +#if 1 +WRAPPER int CMenuManager::CostructStatLine(int) { EAXJMP(0x482800); } +#else +int CMenuManager::CostructStatLine(int) +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); } +#else +void CMenuManager::DisplayHelperText() +{ + static int32 AlphaText = 255; + static int32 Time = 0; + + if (m_nHelperTextMsgId && m_nHelperTextMsgId != 1) { + if (CTimer::GetTimeInMillisecondsPauseMode() - Time > 10) { + Time = CTimer::GetTimeInMillisecondsPauseMode(); + m_nHelperTextAlpha -= 2; + + if (AlphaText < 1) + ResetHelperText(); + + AlphaText = m_nHelperTextAlpha > 255 ? 255 : m_nHelperTextAlpha; + } + } + + wchar *HelperTextToPrint = nil; + // TODO: name this cases? + switch (m_nHelperTextMsgId) { + case 0: + HelperTextToPrint = TheText.Get("FET_MIG"); + break; + case 1: + HelperTextToPrint = TheText.Get("FET_APP"); + break; + case 2: + HelperTextToPrint = TheText.Get("FET_HRD"); + break; + case 3: + HelperTextToPrint = TheText.Get("FET_RSO"); + break; + case 4: + HelperTextToPrint = TheText.Get("FET_RSC"); + break; + default: + break; + }; + + CFont::SetAlignment(ALIGN_CENTER); + CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f)); + CFont::SetFontStyle(FONT_HEADING); + CFont::SetDropColor(CRGBA(0, 0, 0, AlphaText)); + CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); + CFont::SetColor(CRGBA(255, 255, 255, AlphaText)); + + CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_SCALE_FROM_BOTTOM(120.0f), HelperTextToPrint); +} +#endif + +#if 0 +WRAPPER float CMenuManager::DisplaySlider(float, float, float, float, float, float) { EAXJMP(0x488420); } +#else +float CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightSize, float rectSize, float progress) +{ + CRGBA color; + float sizeRange; + + float input = 0.0f; + for (int i = 0; i < 16; i++) { + input = i * rectSize/16.0f + x; + + if (i/16.0f + 1/32.0f < progress) + color = CRGBA(255, 217, 106, FadeIn(255)); + else + color = CRGBA(185, 120, 0, FadeIn(255)); + + sizeRange = max(leftSize, rightSize); + + float _x = i * rectSize/16.0f + x; + float _y = y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f; + float _w = SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x; + float _h = y + sizeRange; + float _s = SCREEN_SCALE_X(2.0f); + CSprite2d::DrawRect(CRect(_x + _s, _y + _s, _w + _s, _h + _s), CRGBA(0, 0, 0, FadeIn(255))); // Shadow + CSprite2d::DrawRect(CRect(i * rectSize/16.0f + x, y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f, SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x, y + sizeRange), color); + }; + return input; +} +#endif + +#if 0 +WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); } +#else +void CMenuManager::DoSettingsBeforeStartingAGame() +{ + CCamera::m_bUseMouse3rdPerson = m_ControlMethod == 0; + if (m_PrefsVsyncDisp != m_PrefsVsync) + m_PrefsVsync = m_PrefsVsyncDisp; + + m_bStartGameLoading = true; + + ShutdownJustMenu(); + UnloadTextures(); + DMAudio.SetEffectsFadeVol(0); + DMAudio.SetMusicFadeVol(0); + DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); +} +#endif + +#if 0 +WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); } +#else +void CMenuManager::Draw() +{ + CFont::SetBackgroundOff(); + CFont::SetPropOn(); + CFont::SetCentreOff(); + CFont::SetJustifyOn(); + CFont::SetBackGroundOnlyTextOn(); + CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f)); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); + + switch (m_nCurrScreen) { + case MENUPAGE_STATS: + PrintStats(); + break; + case MENUPAGE_BRIEFS: + PrintBriefs(); + break; + case MENUPAGE_CONTROLLER_DEBUG: + DrawControllerScreenExtraText(0, 350, 20); + break; + } + + // Header. + if (aScreens[m_nCurrScreen].m_ScreenName[0]) { + CFont::SetDropShadowPosition(0); + CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255))); + CFont::SetRightJustifyOn(); + CFont::SetFontStyle(FONT_HEADING); + CFont::SetScale(SCREEN_SCALE_X(MENUHEADER_WIDTH), SCREEN_SCALE_Y(MENUHEADER_HEIGHT)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName)); + } + + // Action text. + wchar *str; + if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { + switch (m_nCurrScreen) { + case MENUPAGE_LOAD_SLOT_CONFIRM: + if (m_bGameNotLoaded) + str = TheText.Get("FES_LCG"); + else + str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); + break; + case MENUPAGE_SAVE_OVERWRITE_CONFIRM: + if (Slots[m_nCurrSaveSlot] == 1) + str = TheText.Get("FESZ_QZ"); + else + str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); + break; + case MENUPAGE_EXIT: + if (m_bGameNotLoaded) + str = TheText.Get("FEQ_SRW"); + else + str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); + break; + default: + str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); + break; + }; + + CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); + CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); + CFont::SetFontStyle(FONT_BANK); + CFont::SetScale(SCREEN_SCALE_X(MENUACTION_WIDTH), SCREEN_SCALE_Y(MENUACTION_HEIGHT)); + CFont::SetAlignment(ALIGN_LEFT); + CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); + CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str); + } + + for (int i = 0; i < MENUROWS; ++i) { + if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0]) { + wchar *textToPrint[MENUCOLUMNS] = { nil, nil }; + bool Locked = false; + + if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot <= SAVESLOT_8) { + textToPrint[MENUCOLUMN_LEFT] = GetNameOfSavedGame(i - 1); + textToPrint[MENUCOLUMN_RIGHT] = GetSavedGameDateAndTime(i - 1); + + if (!textToPrint[MENUCOLUMN_LEFT][0]) { + sprintf(gString, "FEM_SL%d", i); + textToPrint[MENUCOLUMN_LEFT] = TheText.Get(gString); + } + } + else { + textToPrint[MENUCOLUMN_LEFT] = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName); + + if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_SCREENRES) { + if (m_bGameNotLoaded) + Locked = false; + else + Locked = true; + } + } + + switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { + case MENUACTION_CTRLVIBRATION: + break; + case MENUACTION_CTRLCONFIG: + switch (CPad::GetPad(0)->Mode) { + case 0: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF1"); + break; + case 1: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF2"); + break; + case 2: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF3"); + break; + case 3: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF4"); + break; + }; + break; + case MENUACTION_CTRLDISPLAY: + break; + case MENUACTION_FRAMESYNC: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsVsyncDisp ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_FRAMELIMIT: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsFrameLimiter ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_TRAILS: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CMBlur::BlurOn ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_SUBTITLES: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsShowSubtitles ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_WIDESCREEN: +#ifndef ASPECT_RATIO_SCALE + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsUseWideScreen ? "FEM_ON" : "FEM_OFF"); +#else + switch (m_PrefsUseWideScreen) { + case AR_AUTO: + textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"AUTO"; + break; + case AR_4_3: + textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"4:3"; + break; + case AR_16_9: + textToPrint[MENUCOLUMN_RIGHT] = (wchar*)L"16:9"; + break; + }; +#endif + break; + case MENUACTION_RADIO: + sprintf(gString, "FEA_FM%d", m_PrefsRadioStation); + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gString); + break; + case MENUACTION_SETDBGFLAG: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_SWITCHBIGWHITEDEBUGLIGHT: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_INVVERT: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(MousePointerStateHelper.bInvertVertically ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_SCREENRES: + { + char *res = _psGetVideoModeList()[m_nDisplayVideoMode]; + + if (!res) + res = ""; + + AsciiToUnicode(res, gUString); + textToPrint[MENUCOLUMN_RIGHT] = gUString; + } + break; + case MENUACTION_AUDIOHW: + if (m_nPrefsAudio3DProviderIndex == -1) + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH"); + else { + char *provider = MusicManager.Get3DProviderName(m_nPrefsAudio3DProviderIndex); + AsciiToUnicode(provider, gUString); + textToPrint[MENUCOLUMN_RIGHT] = gUString; + } + break; + case MENUACTION_SPEAKERCONF: + if (m_nPrefsAudio3DProviderIndex == -1) + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH"); + else { + switch (m_PrefsSpeakers) { + case 0: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_2SP"); + break; + case 1: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_EAR"); + break; + case 2: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_4SP"); + break; + }; + } + break; + case MENUACTION_CTRLMETHOD: + switch (m_ControlMethod) { + case 0: + textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_SCN"); + break; + case 1: + textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_CCN"); + break; + }; + break; + case MENUACTION_DYNAMICACOUSTIC: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF"); + break; + case MENUACTION_MOUSESTEER: + textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF"); + break; + }; + + CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE); + CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A))); + CFont::SetCentreSize(SCREEN_WIDTH); + CFont::SetWrapx(SCREEN_WIDTH); + CFont::SetRightJustifyWrap(-SCREEN_WIDTH); + + // Set alignment. + CVector2D vecPositions = { 0.0f, 0.0f }; + float fVerticalSpacing; + float fBarSize; + + int SavePageSlot = + m_nCurrScreen == MENUPAGE_CHOOSE_LOAD_SLOT || + m_nCurrScreen == MENUPAGE_CHOOSE_DELETE_SLOT || + m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT; + + if (SavePageSlot) { + CFont::SetFontStyle(FONT_BANK); + CFont::SetAlignment(ALIGN_LEFT); + CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f)); + fVerticalSpacing = MENUCOLUMN_SPACING_MIN; + fBarSize = MENUSELECT_BOX_MIN; + + vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_SAVE_X); + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_SAVE_Y); + } + else { + CFont::SetFontStyle(FONT_HEADING); + + int LeftMenuColumn = + m_nCurrScreen == MENUPAGE_SOUND_SETTINGS || + m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS || + m_nCurrScreen == MENUPAGE_MOUSE_CONTROLS; + + if (LeftMenuColumn) { + CFont::SetAlignment(ALIGN_LEFT); + CFont::SetScale(SCREEN_SCALE_X(0.55f), SCREEN_SCALE_Y(0.8f)); + fVerticalSpacing = MENUCOLUMN_SPACING_MIN; + fBarSize = MENUSELECT_BOX_MIN; + } + else { + CFont::SetAlignment(ALIGN_CENTER); + CFont::SetScale(SCREEN_SCALE_X(0.75f), SCREEN_SCALE_Y(0.9f)); + fVerticalSpacing = MENUCOLUMN_SPACING_MAX; + fBarSize = MENUSELECT_BOX_MAX; + } + + // Set positions. + if (CFont::GetDetails().centre) + vecPositions.x = SCREEN_WIDTH / 2; + else + vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_POS_X); + + switch (m_nCurrScreen) { + case MENUPAGE_BRIEFS: + case MENUPAGE_STATS: + vecPositions.y = SCREEN_SCALE_FROM_BOTTOM(MENUCOLUMN_FEDS); + break; + case MENUPAGE_SOUND_SETTINGS: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y); + + if (i > 5) + vecPositions.y += SCREEN_SCALE_Y(MENURADIO_ICON_H * 1.16f); + break; + case MENUPAGE_LANGUAGE_SETTINGS: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MIN_Y); + break; + case MENUPAGE_MOUSE_CONTROLS: + case MENUPAGE_GRAPHICS_SETTINGS: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y); + break; + case MENUPAGE_OPTIONS: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); + break; + case MENUPAGE_PAUSE_MENU: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_PAUSE_Y); + break; + case MENUPAGE_NEW_GAME: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); + break; + case MENUPAGE_START_MENU: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_START_Y); + break; + default: + vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y); + break; + }; + } + + if (i > 0) + vecPositions.y += SCREEN_SCALE_Y(fVerticalSpacing * i); + + // Set color and draw selection bar. + if (i == m_nCurrOption && m_nMenuFadeAlpha >= 255) { + CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255))); + CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(11.0f), vecPositions.y - SCREEN_STRETCH_Y(fBarSize * 0.13f), SCREEN_STRETCH_FROM_RIGHT(11.0f), vecPositions.y + SCREEN_STRETCH_Y(fBarSize)), CRGBA(100, 200, 50, 50)); + } + else + CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); + + // Draw + if (textToPrint[MENUCOLUMN_LEFT]) + CFont::PrintString(vecPositions.x, vecPositions.y, textToPrint[MENUCOLUMN_LEFT]); + + if (textToPrint[MENUCOLUMN_RIGHT]) { + if (Locked) + CFont::SetColor(CRGBA(190, 130, 40, FadeIn(255))); + + CFont::SetAlignment(ALIGN_RIGHT); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(SavePageSlot ? MENUCOLUMN_SAVE_X : MENUCOLUMN_POS_X), vecPositions.y, textToPrint[MENUCOLUMN_RIGHT]); + } + + // Mouse support. + // TODO: inputs for these pages. + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { + } + else if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { + + } + else { + static bool bIsMouseInPosition = false; + if (m_nMenuFadeAlpha >= 255 && GetMouseInput()) { + CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) }; + if (m_bShowMouse && + ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f))))) + bIsMouseInPosition = true; + else + bIsMouseInPosition = false; + + if (bIsMouseInPosition) { + if (m_nCurrOption != i) { + m_nCurrOption = i; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + } + + m_nPrevOption = m_nCurrOption; + + if (GetMouseForward()) + m_nHoverOption = IGNORE_OPTION; + else + m_nHoverOption = ACTIVATE_OPTION; + } + } + } + + // Sliders + // TODO: CheckHover + switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) { + case MENUACTION_BRIGHTNESS: + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness/512.0f); + break; + case MENUACTION_DRAWDIST: + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), (m_PrefsLOD - 0.8f) * 1.0f); + break; + case MENUACTION_MUSICVOLUME: + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume/128.0f); + break; + case MENUACTION_SFXVOLUME: + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume/128.0f); + break; + case MENUACTION_MOUSESENS: + DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), TheCamera.m_fMouseAccelHorzntl * 200.0f); + break; + }; + + // Radio icons. + float fIconSpacing = 59.52f; + if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { + for (int i = 0; i < POLICE_RADIO; i++) { +#ifndef ASPECT_RATIO_SCALE + if (i < USERTRACK) + m_aFrontEndSprites[i + FE_RADIO1].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); + if (i > CHATTERBOX && DMAudio.IsMP3RadioChannelAvailable()) + m_aMenuSprites[MENUSPRITE_MP3LOGO].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); +#else + float fMp3Pos = 0.0f; + if (DMAudio.IsMP3RadioChannelAvailable()) + fMp3Pos = 34.0f; + + if (i < USERTRACK) + m_aFrontEndSprites[i + FE_RADIO1].Draw((SCREEN_WIDTH * 0.5) + SCREEN_SCALE_X(-fMp3Pos + MENURADIO_ICON_X + (fIconSpacing * i)), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); + if (i > CHATTERBOX && DMAudio.IsMP3RadioChannelAvailable()) + m_aMenuSprites[MENUSPRITE_MP3LOGO].Draw((SCREEN_WIDTH * 0.5) + SCREEN_SCALE_X(-fMp3Pos + MENURADIO_ICON_X + (fIconSpacing * i)), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170)); +#endif + } + } + + // Helpers + if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FED_RES")) { + if (m_nDisplayVideoMode == m_nPrefsVideoMode) { + if (m_nHelperTextMsgId == 1) + ResetHelperText(); + } + else + SetHelperText(1); + } + else { + if (m_nDisplayVideoMode != m_nPrefsVideoMode) { + m_nDisplayVideoMode = m_nPrefsVideoMode; + SetHelperText(3); + } + } + + switch (m_nCurrScreen) { + case MENUPAGE_CONTROLLER_SETTINGS: + case MENUPAGE_SOUND_SETTINGS: + case MENUPAGE_GRAPHICS_SETTINGS: + case MENUPAGE_SKIN_SELECT: + case MENUPAGE_CONTROLLER_PC: + case MENUPAGE_MOUSE_CONTROLS: + DisplayHelperText(); + break; + }; + } + }; +} +#endif + +#if 1 +WRAPPER void CMenuManager::DrawControllerBound(int, int, int, uint8) { EAXJMP(0x489710); } +#else +void CMenuManager::DrawControllerBound(int, int, int, uint8) +{ + +} +#endif + +#if 1 +WRAPPER void CMenuManager::DrawControllerScreenExtraText(int, int, int) { EAXJMP(0x4892F0); } +#else +void CMenuManager::DrawControllerScreenExtraText(int, int, int) +{ + +} +#endif + +#if 1 +WRAPPER void CMenuManager::DrawControllerSetupScreen() { EAXJMP(0x481210); } +#else +void CMenuManager::DrawControllerSetupScreen() +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); } +#else +void CMenuManager::DrawFrontEnd() +{ + CFont::SetAlphaFade(255.0f); + + if (m_nCurrScreen == MENUPAGE_NONE) { + m_nMenuFadeAlpha = 0; + + if (m_bGameNotLoaded) + m_nCurrScreen = MENUPAGE_START_MENU; + else + m_nCurrScreen = MENUPAGE_PAUSE_MENU; + } + + if (!m_nCurrOption && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) + m_nCurrOption = MENUROW_1; + + CMenuManager::DrawFrontEndNormal(); + CMenuManager::PrintErrorMessage(); +} +#endif + +#if 0 +WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); } +#else +void CMenuManager::DrawFrontEndNormal() +{ + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSCLAMP); + + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + + eMenuSprites previousSprite = MENUSPRITE_MAINMENU; + if (m_nMenuFadeAlpha < 255) { + switch (m_nPrevScreen) { + case MENUPAGE_STATS: + case MENUPAGE_START_MENU: + case MENUPAGE_PAUSE_MENU: + previousSprite = MENUSPRITE_MAINMENU; + break; + case MENUPAGE_NEW_GAME: + case MENUPAGE_CHOOSE_LOAD_SLOT: + case MENUPAGE_CHOOSE_DELETE_SLOT: + case MENUPAGE_NEW_GAME_RELOAD: + case MENUPAGE_LOAD_SLOT_CONFIRM: + case MENUPAGE_DELETE_SLOT_CONFIRM: + case MENUPAGE_EXIT: + previousSprite = MENUSPRITE_SINGLEPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAIN: + previousSprite = MENUSPRITE_MULTIPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAP: + case MENUPAGE_MULTIPLAYER_FIND_GAME: + case MENUPAGE_SKIN_SELECT: + case MENUPAGE_KEYBOARD_CONTROLS: + case MENUPAGE_MOUSE_CONTROLS: + previousSprite = MENUSPRITE_FINDGAME; + break; + case MENUPAGE_MULTIPLAYER_CONNECTION: + case MENUPAGE_MULTIPLAYER_MODE: + previousSprite = MENUSPRITE_CONNECTION; + break; + case MENUPAGE_MULTIPLAYER_CREATE: + previousSprite = MENUSPRITE_HOSTGAME; + break; + case MENUPAGE_SKIN_SELECT_OLD: + case MENUPAGE_OPTIONS: + previousSprite = MENUSPRITE_PLAYERSET; + break; + }; + + if (m_nPrevScreen == MENUPAGE_NONE) + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(0, 0, 0, 255)); + else + m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + } + + eMenuSprites currentSprite = MENUSPRITE_MAINMENU; + switch (m_nCurrScreen) { + case MENUPAGE_STATS: + case MENUPAGE_START_MENU: + case MENUPAGE_PAUSE_MENU: + currentSprite = MENUSPRITE_MAINMENU; + break; + case MENUPAGE_NEW_GAME: + case MENUPAGE_CHOOSE_LOAD_SLOT: + case MENUPAGE_CHOOSE_DELETE_SLOT: + case MENUPAGE_NEW_GAME_RELOAD: + case MENUPAGE_LOAD_SLOT_CONFIRM: + case MENUPAGE_DELETE_SLOT_CONFIRM: + case MENUPAGE_EXIT: + currentSprite = MENUSPRITE_SINGLEPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAIN: + currentSprite = MENUSPRITE_MULTIPLAYER; + break; + case MENUPAGE_MULTIPLAYER_MAP: + case MENUPAGE_MULTIPLAYER_FIND_GAME: + case MENUPAGE_SKIN_SELECT: + case MENUPAGE_KEYBOARD_CONTROLS: + case MENUPAGE_MOUSE_CONTROLS: + currentSprite = MENUSPRITE_FINDGAME; + break; + case MENUPAGE_MULTIPLAYER_CONNECTION: + case MENUPAGE_MULTIPLAYER_MODE: + currentSprite = MENUSPRITE_CONNECTION; + break; + case MENUPAGE_MULTIPLAYER_CREATE: + currentSprite = MENUSPRITE_HOSTGAME; + break; + case MENUPAGE_SKIN_SELECT_OLD: + case MENUPAGE_OPTIONS: + currentSprite = MENUSPRITE_PLAYERSET; + break; + }; + + uint32 savedShade; + uint32 savedAlpha; + RwRenderStateGet(rwRENDERSTATESHADEMODE, &savedShade); + RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast(rwSHADEMODEGOURAUD)); + RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &savedAlpha); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(TRUE)); + if (m_nMenuFadeAlpha >= 255) { + m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + } + else { + if (m_nMenuFadeAlpha < 255) { + m_nMenuFadeAlpha += 0.1f * 255.0f; + + if (m_nMenuFadeAlpha >= 255) + m_nMenuFadeAlpha = 255; + + m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, m_nMenuFadeAlpha)); + } + else + m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + } + + // GTA LOGO + if (m_nCurrScreen == MENUPAGE_START_MENU || m_nCurrScreen == MENUPAGE_PAUSE_MENU) { + if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) + m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(70.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(180.0f)), CRGBA(255, 255, 255, FadeIn(255))); + else + m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(40.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(210.0f)), CRGBA(255, 255, 255, FadeIn(255))); + } + RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast(savedShade)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(savedAlpha)); + + switch (m_nCurrScreen) { + case MENUPAGE_SKIN_SELECT: + CMenuManager::DrawPlayerSetupScreen(); + break; + case MENUPAGE_KEYBOARD_CONTROLS: + CMenuManager::DrawControllerSetupScreen(); + break; + default: + CMenuManager::Draw(); + break; + }; + + CFont::DrawFonts(); + + // Draw mouse + if (m_bShowMouse) + m_aMenuSprites[MENUSPRITE_MOUSE].Draw(m_nMousePosX, m_nMousePosY, SCREEN_SCALE_X(60.0f), SCREEN_SCALE_Y(60.0f), CRGBA(255, 255, 255, 255)); +} +#endif + +#if 1 +WRAPPER void CMenuManager::DrawPlayerSetupScreen() { EAXJMP(0x47F2B0); } +#else +void CMenuManager::DrawPlayerSetupScreen() +{ + +} +#endif + +#if 0 +WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); } +#else +int CMenuManager::FadeIn(int alpha) +{ + if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS || + m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS || + m_nCurrScreen == MENUPAGE_DELETING) + return alpha; + + if (m_nMenuFadeAlpha >= alpha) + return alpha; + + return m_nMenuFadeAlpha; +} +#endif + +#if 1 +WRAPPER void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) { EAXJMP(0x4889C0); } +#else +void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) +{ + +} +#endif + +#if 1 +WRAPPER int CMenuManager::GetStartOptionsCntrlConfigScreens() { EAXJMP(0x489270); } +#else +int CMenuManager::GetStartOptionsCntrlConfigScreens() +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); } +#else +void CMenuManager::InitialiseChangedLanguageSettings() +{ + if (m_bFrontEnd_ReloadObrTxtGxt) { + m_bFrontEnd_ReloadObrTxtGxt = false; + CTimer::Stop(); + TheText.Unload(); + TheText.Load(); + CTimer::Update(); + CGame::frenchGame = false; + CGame::germanGame = false; + switch (CMenuManager::m_PrefsLanguage) { + case LANGUAGE_FRENCH: + CGame::frenchGame = true; + break; + case LANGUAGE_GERMAN: + CGame::germanGame = true; + break; + default: + break; + }; + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::LoadAllTextures() { EAXJMP(0x47A230); } +#else +void CMenuManager::LoadAllTextures() +{ + if (!m_bSpritesLoaded) { + CMenuManager::CentreMousePointer(); + DMAudio.ChangeMusicMode(0); + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0); + m_nCurrOption = MENUROW_0; + m_PrefsRadioStation = DMAudio.GetRadioInCar(); + + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CMenuManager::m_PrefsRadioStation > USERTRACK) + CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10; + } + else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX) + CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9; + + CFileMgr::SetDir(""); + CTimer::Stop(); + CStreaming::MakeSpaceFor(700 * 1024); + CStreaming::ImGonnaUseStreamingMemory(); + CTxdStore::PushCurrentTxd(); + + int frontend = CTxdStore::AddTxdSlot("frontend"); + CTxdStore::LoadTxd(frontend, "MODELS/FRONTEND.TXD"); + CTxdStore::AddRef(frontend); + CTxdStore::SetCurrentTxd(frontend); + CStreaming::IHaveUsedStreamingMemory(); + CTimer::Update(); + + debug("LOAD frontend\n"); + for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) { + m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i]); + m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); + }; + + CTxdStore::PopCurrentTxd(); + + int menu = CTxdStore::AddTxdSlot("menu"); + CTxdStore::LoadTxd(menu, "MODELS/MENU.TXD"); + CTxdStore::AddRef(menu); + CTxdStore::SetCurrentTxd(menu); + + debug("LOAD sprite\n"); + for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; i++) { + m_aMenuSprites[i].SetTexture(MenuFilenames[i*2], MenuFilenames[i*2+1]); + m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); + }; + + CTxdStore::PopCurrentTxd(); + + m_bSpritesLoaded = true; + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); } +#else +void CMenuManager::LoadSettings() +{ + + CFileMgr::SetDirMyDocuments(); + + uint8 prevLang = m_PrefsLanguage; + MousePointerStateHelper.bInvertVertically = true; + + static char Ver; + int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); + if (fileHandle) { + CFileMgr::Read(fileHandle, buf(&Ver), sizeof(Ver)); + + if (strncmp(&Ver, "THIS FILE IS NOT VALID YET", 26)) { + CFileMgr::Seek(fileHandle, 0, 0); + ControlsManager.LoadSettings(fileHandle); + CFileMgr::Read(fileHandle, buf(&gString), 20); + CFileMgr::Read(fileHandle, buf(&gString), 20); + CFileMgr::Read(fileHandle, buf(&gString), 4); + CFileMgr::Read(fileHandle, buf(&gString), 4); + CFileMgr::Read(fileHandle, buf(&gString), 1); + CFileMgr::Read(fileHandle, buf(&gString), 1); + CFileMgr::Read(fileHandle, buf(&gString), 1); + CFileMgr::Read(fileHandle, buf(&TheCamera.m_bHeadBob), 1); + CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); + CFileMgr::Read(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); + CFileMgr::Read(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); + CFileMgr::Read(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsSfxVolume), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsMusicVolume), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsRadioStation), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsSpeakers), 1); + CFileMgr::Read(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsDMA), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsBrightness), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsLOD), 4); + CFileMgr::Read(fileHandle, buf(&m_PrefsShowSubtitles), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsUseWideScreen), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsVsyncDisp), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsFrameLimiter), 1); + CFileMgr::Read(fileHandle, buf(&m_nDisplayVideoMode), 1); + CFileMgr::Read(fileHandle, buf(&CMBlur::BlurOn), 1); + CFileMgr::Read(fileHandle, buf(m_PrefsSkinFile), 256); + CFileMgr::Read(fileHandle, buf(&m_ControlMethod), 1); + CFileMgr::Read(fileHandle, buf(&m_PrefsLanguage), 1); + } + } + + CFileMgr::CloseFile(fileHandle); + CFileMgr::SetDir(""); + + m_PrefsVsync = m_PrefsVsyncDisp; + lodMultiplier = m_PrefsLOD; + + if (m_nPrefsAudio3DProviderIndex == -1) + m_nPrefsAudio3DProviderIndex = -2; + + if (m_PrefsLanguage == prevLang) + m_bLanguageLoaded = false; + else { + m_bLanguageLoaded = true; + TheText.Unload(); + TheText.Load(); + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + + debug("The previously saved language is now in use"); + } + + /*struct _WIN32_FIND_DATAA FindFileData; + HANDLE H = FindFirstFileA("skins\*.bmp", &FindFileData); + char Dest; + bool SkinFound = false; + + for (int i = 1; H != (HANDLE)-1 && i; i = FindNextFileA(H, &FindFileData)) { + strcpy(&Dest, buf(m_PrefsSkinFile)); + strcat(&Dest, ".bmp"); + if (!strcmp(FindFileData.cFileName, &Dest)) + SkinFound = true; + } + + FindClose(H); + + if (!SkinFound) { + debug("Default skin set as no other skins are available OR saved skin not found!"); + strcpy((char *)CMenuManager::m_PrefsSkinFile, "$$\"\""); + strcpy(m_aSkinName, "$$\"\""); + }*/ +} +#endif + +#if 1 +WRAPPER void CMenuManager::MessageScreen(char *) { EAXJMP(0x48B7E0); } +#else +void CMenuManager::MessageScreen(char *) +{ + +} +#endif + +#if 1 +WRAPPER void CMenuManager::PickNewPlayerColour() { EAXJMP(0x488C40); } +#else +void CMenuManager::PickNewPlayerColour() +{ + +} +#endif + +#if 1 +WRAPPER void CMenuManager::PrintBriefs() { EAXJMP(0x484D60); } +#else +void CMenuManager::PrintBriefs() +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); } +#else +void CMenuManager::PrintErrorMessage() +{ + if (!CPad::bDisplayNoControllerMessage && !CPad::bObsoleteControllerMessage) + return; + + CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(20.0f), SCREEN_SCALE_Y(140.0f), SCREEN_WIDTH - SCREEN_SCALE_X(20.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(140.0f)), CRGBA(64, 16, 16, 224)); + CFont::SetFontStyle(FONT_BANK); + CFont::SetBackgroundOff(); + CFont::SetPropOn(); + CFont::SetCentreOff(); + CFont::SetJustifyOn(); + CFont::SetRightJustifyOff(); + CFont::SetBackGroundOnlyTextOn(); + CFont::SetWrapx(SCREEN_WIDTH - 40.0f); + CFont::SetColor(CRGBA(165, 165, 165, 255)); + CFont::SetScale(SCREEN_SCALE_X(0.9f), SCREEN_SCALE_Y(0.9f)); + CFont::PrintString(SCREEN_SCALE_X(40.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(60.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT")); + CFont::DrawFonts(); +} +#endif + +#if 1 +WRAPPER void CMenuManager::PrintStats() { EAXJMP(0x482100); } +#else +void CMenuManager::PrintStats() +{ + +} +#endif + +#if 0 +WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); } +#else +void CMenuManager::Process(void) +{ + if (m_bSaveMenuActive && TheCamera.GetScreenFadeStatus()) + return; + + field_113 = 0; + InitialiseChangedLanguageSettings(); + + SwitchMenuOnAndOff(); + + if (m_bMenuActive) { + LoadAllTextures(); + + if (m_nCurrScreen == MENUPAGE_DELETING) { + bool SlotPopulated = false; + + if (PcSaveHelper.DeleteSlot(m_nCurrSaveSlot)) { + PcSaveHelper.PopulateSlotInfo(); + SlotPopulated = true; + } + + if (SlotPopulated) { + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_DELETE_SUCCESS; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + } + else + SaveLoadFileError_SetUpErrorScreen(); + } + if (m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS) { + int8 SaveSlot = PcSaveHelper.SaveSlot(m_nCurrSaveSlot); + PcSaveHelper.PopulateSlotInfo(); + if (SaveSlot) { + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_SAVE_SUCCESSFUL; + m_nCurrOption = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + } + else + SaveLoadFileError_SetUpErrorScreen(); + } + if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS) { + if (CheckSlotDataValid(m_nCurrSaveSlot)) { + TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == 0; + if (m_PrefsVsyncDisp != m_PrefsVsync) + m_PrefsVsync = m_PrefsVsyncDisp; + DMAudio.Service(); + m_bStartGameLoading = 1; + RequestFrontEndShutdown(); + m_bLoadingSavedGame = 1; + b_FoundRecentSavedGameWantToLoad = 1; + DMAudio.SetEffectsFadeVol(0); + DMAudio.SetMusicFadeVol(0); + DMAudio.ResetTimers(CTimer::GetTimeInMilliseconds()); + } + else + SaveLoadFileError_SetUpErrorScreen(); + } + + ProcessButtonPresses(); + } + else { + if (GetPadExitEnter()) + RequestFrontEndStartUp(); + + UnloadTextures(); + m_nPrevScreen = MENUPAGE_NONE; + m_nCurrScreen = m_nPrevScreen; + m_nCurrOption = MENUROW_0; + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); } +#else +void CMenuManager::ProcessButtonPresses() +{ + // Update Mouse Position + m_nMouseOldPosX = m_nMousePosX; + m_nMouseOldPosY = m_nMousePosY; + + m_nMousePosX = m_nMouseTempPosX; + m_nMousePosY = m_nMouseTempPosY; + + if (m_nMousePosX < 0) + m_nMousePosX = 0; + if (m_nMousePosX > SCREEN_WIDTH) + m_nMousePosX = SCREEN_WIDTH; + if (m_nMousePosY < 0) + m_nMousePosY = 0; + if (m_nMousePosY > SCREEN_HEIGHT) + m_nMousePosY = SCREEN_HEIGHT; + + // Show/hide mouse cursor. + if (GetMouseInput()) + m_bShowMouse = true; + else if (GetPadInput()) + m_bShowMouse = false; + + // Get number of menu options. + uint8 NumberOfMenuOptions = GetNumberOfMenuOptions(); + + // Select next/previous option with pad. Mouse is done in drawing function. + if (GetPadMoveUp()) { + m_nPrevOption = m_nCurrOption; + m_nCurrOption -= 1; + + if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { + if (m_nCurrOption < MENUROW_1) + m_nCurrOption = NumberOfMenuOptions; + } + else { + if (m_nCurrOption < MENUROW_0) + m_nCurrOption = NumberOfMenuOptions; + } + + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + } + else if (GetPadMoveDown()) { + m_nPrevOption = m_nCurrOption; + m_nCurrOption += 1; + + if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) { + if (m_nCurrOption > NumberOfMenuOptions) + m_nCurrOption = MENUROW_1; + } + else { + if (m_nCurrOption > NumberOfMenuOptions) + m_nCurrOption = MENUROW_0; + } + + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0); + } + + // Set what happens if ESC is pressed. + if (GetPadBack()) { + bool PlayEscSound = false; + switch (m_nCurrScreen) { + case MENUPAGE_START_MENU: + break; + case MENUPAGE_CHOOSE_SAVE_SLOT: + case MENUPAGE_PAUSE_MENU: + RequestFrontEndShutdown(); + PlayEscSound = true; + break; + default: + SwitchToNewScreen(aScreens[m_nCurrScreen].m_PreviousPage[0]); + PlayEscSound = true; + break; + }; + + if (PlayEscSound) + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); + } + + // TODO: finish hover options. + // Set mouse buttons. + if (GetMouseForward()) { + switch (m_nHoverOption) { + case ACTIVATE_OPTION: + if (m_nCurrOption || m_nCurrScreen != MENUPAGE_PAUSE_MENU) + m_nCurrOption = m_nPrevOption; + + m_nHoverOption = ACTIVATE_OPTION; + break; + default: + break; + }; + } + + // Process all menu options here, but first check if it's an option or a redirect. + int32 CurrAction = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action; + if ((GetPadForward() || GetMouseForward()) || + ((GetPadMoveLeft() || GetMouseMoveRight()) || (GetPadMoveRight() || GetMouseMoveLeft())) && + (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu == m_nCurrScreen && + CurrAction != MENUACTION_CHANGEMENU && + CurrAction != MENUACTION_LOADRADIO && + CurrAction != MENUACTION_RESTOREDEF && + CurrAction != MENUACTION_PLAYERSETUP)) { + + if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB")) + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_EXIT, 0); + else + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SUCCESS, 0); + + ProcessOnOffMenuOptions(); + } + + // Process screens that may redirect you somewhere, or may not. + switch (m_nCurrScreen) { + case MENUPAGE_LOAD_SLOT_CONFIRM: + break; + case MENUPAGE_NEW_GAME_RELOAD: + if (m_bGameNotLoaded) + DoSettingsBeforeStartingAGame(); + break; + case MENUPAGE_CHOOSE_DELETE_SLOT: + case MENUPAGE_CHOOSE_SAVE_SLOT: + case MENUPAGE_CHOOSE_LOAD_SLOT: + PcSaveHelper.PopulateSlotInfo(); + break; + default: + break; + }; + + // Reset pad shaking. + if (VibrationTime != 0) { + if (CTimer::GetTimeInMillisecondsPauseMode() > VibrationTime) { + CPad::GetPad(0)->StopShaking(0); + VibrationTime = 0; + } + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::ProcessOnOffMenuOptions() { EAXJMP(0x48AE60); } +#else +void CMenuManager::ProcessOnOffMenuOptions() +{ + int8 InputDirection = (GetPadMoveLeft() || GetMouseMoveLeft()) && (!GetPadForward() && !GetMouseForward()) ? -1 : 1; + int8 InputEnter = GetPadForward(); + + uint8 NumberOfMenuOptions = GetNumberOfMenuOptions(); + + // In numerical order. + switch (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action) { + case MENUACTION_CHANGEMENU: + SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); + break; + case MENUACTION_CTRLVIBRATION: + if (!m_PrefsUseVibration) + m_PrefsUseVibration = true; + + if (m_PrefsUseVibration) { + CPad::GetPad(0)->StartShake(350, 150); + VibrationTime = CTimer::GetTimeInMillisecondsPauseMode() + 500; + } + SaveSettings(); + break; + case MENUACTION_FRAMESYNC: + m_PrefsVsync = m_PrefsVsync == false; + SaveSettings(); + break; + case MENUACTION_FRAMELIMIT: + m_PrefsFrameLimiter = m_PrefsFrameLimiter == false; + SaveSettings(); + break; + case MENUACTION_TRAILS: + CMBlur::BlurOn = CMBlur::BlurOn == false; + if (CMBlur::BlurOn) + CMBlur::MotionBlurOpen(Scene.camera); + else + CMBlur::MotionBlurClose(); + + SaveSettings(); + break; + case MENUACTION_SUBTITLES: + m_PrefsShowSubtitles = m_PrefsShowSubtitles == false; + SaveSettings(); + break; + case MENUACTION_WIDESCREEN: +#ifndef ASPECT_RATIO_SCALE + m_PrefsUseWideScreen = m_PrefsUseWideScreen == false; +#else + if (InputDirection > 0) { + switch (m_PrefsUseWideScreen) { + case AR_AUTO: + m_PrefsUseWideScreen = AR_4_3; + break; + case AR_4_3: + m_PrefsUseWideScreen = AR_16_9; + break; + case AR_16_9: + m_PrefsUseWideScreen = AR_AUTO; + break; + }; + } + else { + switch (m_PrefsUseWideScreen) { + case AR_AUTO: + m_PrefsUseWideScreen = AR_16_9; + break; + case AR_4_3: + m_PrefsUseWideScreen = AR_AUTO; + break; + case AR_16_9: + m_PrefsUseWideScreen = AR_4_3; + break; + }; + } +#endif + SaveSettings(); + break; + case MENUACTION_BRIGHTNESS: + case MENUACTION_DRAWDIST: + case MENUACTION_MUSICVOLUME: + case MENUACTION_SFXVOLUME: + case MENUACTION_MOUSESENS: + if (InputDirection > 0) + CheckSliderMovement(1.0f); + else + CheckSliderMovement(-1.0f); + break; + case MENUACTION_RADIO: + if (InputDirection < 0) + m_PrefsRadioStation -= 1; + else + m_PrefsRadioStation += 1; + + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (m_PrefsRadioStation > USERTRACK) + m_PrefsRadioStation = HEAD_RADIO; + else if (m_PrefsRadioStation < HEAD_RADIO) + m_PrefsRadioStation = USERTRACK; + } + else { + if (m_PrefsRadioStation > CHATTERBOX) + m_PrefsRadioStation = HEAD_RADIO; + else if (m_PrefsRadioStation < HEAD_RADIO) + m_PrefsRadioStation = CHATTERBOX; + } + + SaveSettings(); + DMAudio.SetRadioInCar(m_PrefsRadioStation); + DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); + break; + case MENUACTION_LANG_ENG: + if (m_PrefsLanguage != LANGUAGE_AMERICAN) { + m_PrefsLanguage = LANGUAGE_AMERICAN; + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + SaveSettings(); + } + break; + case MENUACTION_LANG_FRE: + if (m_PrefsLanguage != LANGUAGE_FRENCH) { + m_PrefsLanguage = LANGUAGE_FRENCH; + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + SaveSettings(); + } + break; + case MENUACTION_LANG_GER: + if (m_PrefsLanguage != LANGUAGE_GERMAN) { + m_PrefsLanguage = LANGUAGE_GERMAN; + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + SaveSettings(); + } + break; + case MENUACTION_LANG_ITA: + if (m_PrefsLanguage != LANGUAGE_ITALIAN) { + m_PrefsLanguage = LANGUAGE_ITALIAN; + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + SaveSettings(); + } + break; + case MENUACTION_LANG_SPA: + if (m_PrefsLanguage != LANGUAGE_SPANISH) { + m_PrefsLanguage = LANGUAGE_SPANISH; + m_bFrontEnd_ReloadObrTxtGxt = true; + InitialiseChangedLanguageSettings(); + SaveSettings(); + } + break; + case MENUACTION_UPDATESAVE: + PcSaveHelper.PopulateSlotInfo(); + if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { + m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; + + SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); + } + break; + case MENUACTION_CHECKSAVE: + if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrOption].m_aEntries[m_nCurrOption].m_SaveSlot <= SAVESLOT_8) { + m_nCurrSaveSlot = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot - 2; + + if (Slots[m_nCurrSaveSlot] != 1 && Slots[m_nCurrSaveSlot] != 2) + SwitchToNewScreen(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu); + } + break; + case MENUACTION_NEWGAME: + DoSettingsBeforeStartingAGame(); + break; + case MENUACTION_SETDBGFLAG: + CTheScripts::DbgFlag = CTheScripts::DbgFlag == false; + break; + case MENUACTION_UPDATEMEMCARDSAVE: + RequestFrontEndShutdown(); + break; + case MENUACTION_INVVERT: + MousePointerStateHelper.bInvertVertically = MousePointerStateHelper.bInvertVertically == false; + return; + case MENUACTION_CANCLEGAME: + DMAudio.Service(); + RsEventHandler(rsQUITAPP, 0); + break; + case MENUACTION_RESUME: + RequestFrontEndShutdown(); + break; + case MENUACTION_SCREENRES: + if (m_bGameNotLoaded) { + if (InputEnter) { + if (m_nDisplayVideoMode != m_nPrefsVideoMode) { + m_nPrefsVideoMode = m_nDisplayVideoMode; + _psSelectScreenVM(m_nPrefsVideoMode); + CentreMousePointer(); + m_PrefsUseWideScreen = false; + SaveSettings(); + } + } + else { + char** VideoModeList = _psGetVideoModeList(); + int NumVideoModes = _psGetNumVideModes(); + + if (InputDirection > 0) { + int nCurrentVidMode = m_nDisplayVideoMode + 1; + + if (nCurrentVidMode >= NumVideoModes) + nCurrentVidMode = 0; + + while (!VideoModeList[nCurrentVidMode]) { + ++nCurrentVidMode; + + if (nCurrentVidMode >= NumVideoModes) + nCurrentVidMode = 0; + } + + m_nDisplayVideoMode = nCurrentVidMode; + } + else { + int nCurrentVidMode = m_nDisplayVideoMode - 1; + + if (nCurrentVidMode < 0) + nCurrentVidMode = NumVideoModes - 1; + + while (!VideoModeList[nCurrentVidMode]) { + --nCurrentVidMode; + + if (nCurrentVidMode < 0) + nCurrentVidMode = NumVideoModes - 1; + } + + m_nDisplayVideoMode = nCurrentVidMode; + } + } + } + break; + case MENUACTION_AUDIOHW: + { + int8 AudioHardware = m_nPrefsAudio3DProviderIndex; + if (m_nPrefsAudio3DProviderIndex == -1) + break; + + if (InputDirection > 0) { + switch (m_nPrefsAudio3DProviderIndex) { + case 0: + m_nPrefsAudio3DProviderIndex = 1; + break; + case 1: + m_nPrefsAudio3DProviderIndex = 2; + break; + case 2: + m_nPrefsAudio3DProviderIndex = 3; + break; + case 3: + m_nPrefsAudio3DProviderIndex = 4; + break; + case 4: + m_nPrefsAudio3DProviderIndex = 5; + break; + case 5: + m_nPrefsAudio3DProviderIndex = 6; + break; + case 6: + m_nPrefsAudio3DProviderIndex = 0; + break; + } + } + else { + switch (m_nPrefsAudio3DProviderIndex) { + case 0: + m_nPrefsAudio3DProviderIndex = 6; + break; + case 1: + m_nPrefsAudio3DProviderIndex = 0; + break; + case 2: + m_nPrefsAudio3DProviderIndex = 1; + break; + case 3: + m_nPrefsAudio3DProviderIndex = 2; + break; + case 4: + m_nPrefsAudio3DProviderIndex = 3; + break; + case 5: + m_nPrefsAudio3DProviderIndex = 4; + break; + case 6: + m_nPrefsAudio3DProviderIndex = 5; + break; + } + } + + DMAudio.SetCurrent3DProvider(m_nPrefsAudio3DProviderIndex); + + if (AudioHardware == m_nPrefsAudio3DProviderIndex) + SetHelperText(0); + else + SetHelperText(4); + + SaveSettings(); + break; + } + case MENUACTION_SPEAKERCONF: + if (m_nPrefsAudio3DProviderIndex == -1) + break; + + if (InputDirection > 0) { + switch (m_PrefsSpeakers) { + case 0: + m_PrefsSpeakers = 1; + break; + case 1: + m_PrefsSpeakers = 2; + break; + case 2: + m_PrefsSpeakers = 0; + break; + }; + } + else { + switch (m_PrefsSpeakers) { + case 0: + m_PrefsSpeakers = 2; + break; + case 1: + m_PrefsSpeakers = 0; + break; + case 2: + m_PrefsSpeakers = 1; + break; + }; + } + + DMAudio.SetSpeakerConfig(m_PrefsSpeakers); + SaveSettings(); + break; + case MENUACTION_RESTOREDEF: + SetDefaultPreferences(m_nCurrScreen); + SetHelperText(2); + SaveSettings(); + break; + case MENUACTION_CTRLMETHOD: + if (m_ControlMethod) { + TheCamera.m_bUseMouse3rdPerson = 1; + m_ControlMethod = 0; + } + else { + TheCamera.m_bUseMouse3rdPerson = 0; + m_ControlMethod = 1; + } + SaveSettings(); + break; + case MENUACTION_DYNAMICACOUSTIC: + m_PrefsDMA = m_PrefsDMA == false; + break; + case MENUACTION_MOUSESTEER: + m_bDisableMouseSteering = m_bDisableMouseSteering == false; + return; + }; +} +#endif + +#if 0 +WRAPPER void CMenuManager::RequestFrontEndShutdown() { EAXJMP(0x488750); } +#else +void CMenuManager::RequestFrontEndShutdown() +{ + m_bShutDownFrontEndRequested = true; + DMAudio.ChangeMusicMode(1); +} +#endif + +#if 0 +WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); } +#else +void CMenuManager::RequestFrontEndStartUp() +{ + m_bStartUpFrontEndRequested = 1; +} +#endif + +#if 0 +WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); } +#else +void CMenuManager::ResetHelperText() +{ + m_nHelperTextMsgId = 0; + m_nHelperTextAlpha = 300; +} +#endif + +#if 0 +WRAPPER void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { EAXJMP(0x488930); } +#else +void CMenuManager::SaveLoadFileError_SetUpErrorScreen() +{ + switch (PcSaveHelper.m_nHelper) { + case 1: + case 2: + case 3: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_SAVE_FAILED; + m_nCurrOption = MENUROW_0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + break; + case 4: + case 5: + case 6: + this->m_nPrevScreen = m_nCurrScreen; + this->m_nCurrScreen = MENUPAGE_LOAD_FAILED; + m_nCurrOption = MENUROW_0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + case 7: + this->m_nPrevScreen = m_nCurrScreen; + this->m_nCurrScreen = MENUPAGE_LOAD_FAILED_2; + m_nCurrOption = MENUROW_0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + case 8: + case 9: + case 10: + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = MENUPAGE_DELETE_FAILED; + m_nCurrOption = MENUROW_0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + break; + default: + return; + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::SetHelperText() { EAXJMP(0x48B450); } +#else +void CMenuManager::SetHelperText(int text) +{ + m_nHelperTextMsgId = text; + m_nHelperTextAlpha = 300; +} +#endif + +#if 0 +WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); } +#else +void CMenuManager::SaveSettings() +{ + CFileMgr::SetDirMyDocuments(); + + int fileHandle = CFileMgr::OpenFile("gta3.set", "w"); + if (fileHandle) { + + ControlsManager.SaveSettings(fileHandle); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 20); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 4); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); + CFileMgr::Write(fileHandle, buf("stuffmorestuffevenmorestuff etc"), 1); + CFileMgr::Write(fileHandle, buf(&TheCamera.m_bHeadBob), 1); + CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelHorzntl), 4); + CFileMgr::Write(fileHandle, buf(&TheCamera.m_fMouseAccelVertical), 4); + CFileMgr::Write(fileHandle, buf(&MousePointerStateHelper.bInvertVertically), 1); + CFileMgr::Write(fileHandle, buf(&CVehicle::m_bDisableMouseSteering), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsSfxVolume), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsMusicVolume), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsRadioStation), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsSpeakers), 1); + CFileMgr::Write(fileHandle, buf(&m_nPrefsAudio3DProviderIndex), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsDMA), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsBrightness), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsLOD), sizeof(m_PrefsLOD)); + CFileMgr::Write(fileHandle, buf(&m_PrefsShowSubtitles), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsUseWideScreen), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsVsyncDisp), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsFrameLimiter), 1); + CFileMgr::Write(fileHandle, buf(&m_nDisplayVideoMode), 1); + CFileMgr::Write(fileHandle, buf(&CMBlur::BlurOn), 1); + CFileMgr::Write(fileHandle, buf(m_PrefsSkinFile), 256); + CFileMgr::Write(fileHandle, buf(&m_ControlMethod), 1); + CFileMgr::Write(fileHandle, buf(&m_PrefsLanguage), 1); + } + + CFileMgr::CloseFile(fileHandle); + CFileMgr::SetDir(""); +} +#endif + +#if 0 +WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); } +#else +void CMenuManager::ShutdownJustMenu() +{ + m_bMenuActive = false; + CTimer::EndUserPause(); +} +#endif + +// We won't ever use this again. +#if 0 +WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); } +#else +float CMenuManager::StretchX(float x) +{ + if (SCREEN_WIDTH == 640) + return x; + else + return SCREEN_WIDTH * x * 0.0015625f; +} +#endif + +#if 0 +WRAPPER float CMenuManager::StretchY(float) { EAXJMP(0x48AC20); } +#else +float CMenuManager::StretchY(float y) +{ + if (SCREEN_HEIGHT == 448) + return y; + else + return SCREEN_HEIGHT * y * 0.002232143f; +} +#endif + +#if 0 +WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); } +#else +void CMenuManager::SwitchMenuOnAndOff() +{ + // Just what the function name says. + if (m_bShutDownFrontEndRequested || m_bStartUpFrontEndRequested) { + if (!m_bMenuActive) + m_bMenuActive = true; + + if (m_bShutDownFrontEndRequested) + m_bMenuActive = false; + if (m_bStartUpFrontEndRequested) + m_bMenuActive = true; + + if (m_bMenuActive) { + CTimer::StartUserPause(); + } + else { + ShutdownJustMenu(); + SaveSettings(); + m_bStartUpFrontEndRequested = false; + pControlEdit = 0; + m_bShutDownFrontEndRequested = false; + DisplayComboButtonErrMsg = 0; + CPad::GetPad(0)->Clear(0); + CPad::GetPad(1)->Clear(0); + SwitchToNewScreen(0); + } + } + if (m_bSaveMenuActive && !m_bQuitGameNoCD) { + m_bSaveMenuActive = false; + m_bMenuActive = true; + CTimer::StartUserPause(); + SwitchToNewScreen(MENUPAGE_CHOOSE_SAVE_SLOT); + PcSaveHelper.PopulateSlotInfo(); + } + + if (!m_bMenuActive) + field_112 = 1; + + m_bStartUpFrontEndRequested = false; + m_bShutDownFrontEndRequested = false; +} +#endif + +#if 0 +WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); } +#else +void CMenuManager::UnloadTextures() +{ + if (m_bSpritesLoaded) { + debug("Remove frontend\n"); + for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); ++i) + m_aFrontEndSprites[i].Delete(); + + int frontend = CTxdStore::FindTxdSlot("frontend"); + CTxdStore::RemoveTxdSlot(frontend); + + debug("Remove menu textures\n"); + for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; ++i) + m_aMenuSprites[i].Delete(); + + int menu = CTxdStore::FindTxdSlot("menu"); + CTxdStore::RemoveTxdSlot(menu); + + m_bSpritesLoaded = false; + } +} +#endif + +#if 0 +WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); } +#else +void CMenuManager::WaitForUserCD() +{ + LoadSplash(0); + if (!RsGlobal.quit) { + HandleExit(); + CPad::UpdatePads(); + MessageScreen("NO_PCCD"); + + if (GetPadBack()) { + m_bQuitGameNoCD = true; + RsEventHandler(rsQUITAPP, 0); + } + } +} +#endif + +// New content: +uint8 CMenuManager::GetNumberOfMenuOptions() +{ + uint8 Rows = MENUROW_NONE; + for (int i = 0; i < MENUROWS; i++) { + if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action == MENUACTION_NOTHING) + break; + + ++Rows; + }; + return Rows; +} + +void CMenuManager::SwitchToNewScreen(int8 screen) +{ + ResetHelperText(); + + // Return to - behaviour. + if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB") || + (screen == aScreens[m_nCurrScreen].m_PreviousPage[0])) { + if (m_bGameNotLoaded) { + m_nCurrOption = aScreens[m_nCurrScreen].m_ParentEntry[0]; + m_nCurrScreen = aScreens[m_nCurrScreen].m_PreviousPage[0]; + } + else { + m_nCurrOption = aScreens[m_nCurrScreen].m_ParentEntry[1]; + m_nCurrScreen = aScreens[m_nCurrScreen].m_PreviousPage[1]; + } + + m_nMenuFadeAlpha = 0; + } + else { + // Go through - behaviour. + if (screen) { + m_nPrevScreen = m_nCurrScreen; + m_nCurrScreen = screen; + m_nCurrOption = MENUROW_0; + m_nMenuFadeAlpha = 0; + m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); + } + else { + m_nPrevScreen = MENUPAGE_NONE; + m_nCurrScreen = MENUPAGE_NONE; + m_nCurrOption = MENUROW_0; + } + } + + // Set player skin. + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { + CPlayerSkin::BeginFrontEndSkinEdit(); + field_535 = 19; + m_bSkinsFound = false; + } + + // Set radio station. + if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) { + DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); + OutputDebugStringA("FRONTEND AUDIO TRACK STOPPED"); + } + else + DMAudio.StopFrontEndTrack(); +} + +void CMenuManager::SetDefaultPreferences(int8 screen) +{ + switch (screen) { + case MENUPAGE_SOUND_SETTINGS: + m_PrefsMusicVolume = 102; + m_PrefsSfxVolume = 102; + m_PrefsSpeakers = 0; + m_nPrefsAudio3DProviderIndex = 6; + m_PrefsDMA = true; + DMAudio.SetMusicMasterVolume(m_PrefsMusicVolume); + DMAudio.SetEffectsMasterVolume(m_PrefsSfxVolume); + DMAudio.SetCurrent3DProvider(m_nPrefsAudio3DProviderIndex); + break; + case MENUPAGE_GRAPHICS_SETTINGS: + m_PrefsBrightness = 256; + m_PrefsFrameLimiter = true; + m_PrefsVsync = true; + m_PrefsLOD = 1.2f; + m_PrefsVsyncDisp = true; + lodMultiplier = 1.2; + CMBlur::BlurOn = true; + CMBlur::MotionBlurOpen(Scene.camera); + m_PrefsUseVibration = false; + m_PrefsShowSubtitles = true; + m_nDisplayVideoMode = m_nPrefsVideoMode; + m_PrefsUseWideScreen = false; + break; + case MENUPAGE_CONTROLLER_PC: + ControlsManager.MakeControllerActionsBlank(); + ControlsManager.InitDefaultControlConfiguration(); + + CMouseControllerState state = MousePointerStateHelper.GetMouseSetUp(); + ControlsManager.InitDefaultControlConfigMouse(state); + + if (1) { + //TODO: JoyPad stuff. + } + TheCamera.m_bUseMouse3rdPerson = 1; + m_ControlMethod = 0; + MousePointerStateHelper.bInvertVertically = true; + TheCamera.m_fMouseAccelHorzntl = 0.0025f; + TheCamera.m_fMouseAccelVertical = 0.0025f; + CVehicle::m_bDisableMouseSteering = true; + TheCamera.m_bHeadBob = false; + break; + }; +} + +// Frontend inputs. +bool GetPadBack() +{ + return + (CPad::GetPad(0)->NewKeyState.ESC && !CPad::GetPad(0)->OldKeyState.ESC) || + (CPad::GetPad(0)->NewState.Triangle && !CPad::GetPad(0)->OldState.Triangle); +} + +bool GetPadExitEnter() +{ + return + (CPad::GetPad(0)->NewKeyState.ESC && !CPad::GetPad(0)->OldKeyState.ESC) || + (CPad::GetPad(0)->NewState.Start && !CPad::GetPad(0)->OldState.Start); +} + +bool GetPadForward() +{ + return + (CPad::GetPad(0)->NewKeyState.EXTENTER && !CPad::GetPad(0)->OldKeyState.EXTENTER) || + (CPad::GetPad(0)->NewKeyState.ENTER && !CPad::GetPad(0)->OldKeyState.ENTER) || + (CPad::GetPad(0)->NewState.Cross && !CPad::GetPad(0)->OldState.Cross); +} + +bool GetPadMoveUp() +{ + return + (CPad::GetPad(0)->NewState.DPadUp && !CPad::GetPad(0)->OldState.DPadUp) || + (CPad::GetPad(0)->NewKeyState.UP && !CPad::GetPad(0)->OldKeyState.UP) || + (CPad::GetPad(0)->NewState.LeftStickY < 0 && !CPad::GetPad(0)->OldState.LeftStickY < 0); +} + +bool GetPadMoveDown() +{ + return + (CPad::GetPad(0)->NewState.DPadDown && !CPad::GetPad(0)->OldState.DPadDown) || + (CPad::GetPad(0)->NewKeyState.DOWN && !CPad::GetPad(0)->OldKeyState.DOWN) || + (CPad::GetPad(0)->NewState.LeftStickY > 0 && !CPad::GetPad(0)->OldState.LeftStickY > 0); +} + +bool GetPadMoveLeft() +{ + return + (CPad::GetPad(0)->NewState.DPadLeft && !CPad::GetPad(0)->OldState.DPadLeft) || + (CPad::GetPad(0)->NewKeyState.LEFT && !CPad::GetPad(0)->OldKeyState.LEFT) || + (CPad::GetPad(0)->NewState.LeftStickX < 0 && !CPad::GetPad(0)->OldState.LeftStickX < 0); +} + +bool GetPadMoveRight() +{ + return + (CPad::GetPad(0)->NewState.DPadRight && !CPad::GetPad(0)->OldState.DPadRight) || + (CPad::GetPad(0)->NewKeyState.RIGHT && !CPad::GetPad(0)->OldKeyState.RIGHT) || + (CPad::GetPad(0)->NewState.LeftStickX > 0 && !CPad::GetPad(0)->OldState.LeftStickX > 0); +} + +bool GetMouseForward() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.LMB && !CPad::GetPad(0)->OldMouseControllerState.LMB); +} + +bool GetMouseBack() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.RMB && !CPad::GetPad(0)->OldMouseControllerState.RMB); +} + +bool GetMousePos() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.x != 0.0f || CPad::GetPad(0)->OldMouseControllerState.y != 0.0f); +} + +bool GetMouseMoveLeft() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.WHEELDN && !CPad::GetPad(0)->OldMouseControllerState.WHEELDN != 0.0f); +} + +bool GetMouseMoveRight() +{ + return + (CPad::GetPad(0)->NewMouseControllerState.WHEELUP && !CPad::GetPad(0)->OldMouseControllerState.WHEELUP != 0.0f); +} + +bool GetPadInput() +{ + return + GetPadBack() || + GetPadForward() || + GetPadMoveUp() || + GetPadMoveDown() || + GetPadMoveLeft() || + GetPadMoveRight(); +} + +bool GetMouseInput() +{ + return + GetMouseForward() || + GetMouseBack() || + GetMousePos() || + GetMouseMoveLeft() || + GetMouseMoveRight(); +} + +STARTPATCHES + InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP); + InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP); + InjectHook(0x485100, &CMenuManager::Process, PATCH_JUMP); + InjectHook(0x4856F0, &CMenuManager::ProcessButtonPresses, PATCH_JUMP); + InjectHook(0x48AE60, &CMenuManager::ProcessOnOffMenuOptions, PATCH_JUMP); + InjectHook(0x488EE0, &CMenuManager::LoadSettings, PATCH_JUMP); + InjectHook(0x488CC0, &CMenuManager::SaveSettings, PATCH_JUMP); + + for (int i = 1; i < ARRAY_SIZE(aScreens); i++) + Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]); +ENDPATCHES \ No newline at end of file diff --git a/src/core/Frontend.h b/src/core/Frontend.h new file mode 100644 index 00000000..9b9377da --- /dev/null +++ b/src/core/Frontend.h @@ -0,0 +1,512 @@ +#pragma + +#include "Sprite2d.h" + +#define MENUHEADER_POS_X 35.0f +#define MENUHEADER_POS_Y 93.0f +#define MENUHEADER_WIDTH 0.84f +#define MENUHEADER_HEIGHT 1.6f + +#define MENUACTION_POS_X 20.0f +#define MENUACTION_POS_Y 37.5f +#define MENUACTION_WIDTH 0.675f +#define MENUACTION_HEIGHT 0.81f + +#define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f +#define MENUCOLUMN_MAX_Y 149.0f +#define MENUCOLUMN_MID_Y 100.0f +#define MENUCOLUMN_MIN_Y 110.0f +#define MENUCOLUMN_PAUSE_Y 25.0f +#define MENUCOLUMN_START_Y 9.0f +#define MENUCOLUMN_FEDS 139.0f + +#define MENUCOLUMN_SAVE_X 121.0f +#define MENUCOLUMN_SAVE_Y 111.0f + +#define MENUCOLUMN_SPACING_MAX 24.0f +#define MENUCOLUMN_SPACING_MIN 20.0f + +#define MENUSELECT_BOX_MAX 20.5f +#define MENUSELECT_BOX_MIN 17.0f + +#ifndef ASPECT_RATIO_SCALE +#define MENURADIO_ICON_X 31.5f +#else +#define MENURADIO_ICON_X -262.0f +#endif +#define MENURADIO_ICON_Y 29.5f +#define MENURADIO_ICON_W 60.0f +#define MENURADIO_ICON_H 60.0f + +#define MENUDROP_COLOR_A 150 +#define MENUDROP_COLOR_SIZE -1 + +#define MENUSLIDER_X 306.0f + +#define buf(a) (char*)(a) + +enum eLanguages +{ + LANGUAGE_AMERICAN, + LANGUAGE_FRENCH, + LANGUAGE_GERMAN, + LANGUAGE_ITALIAN, + LANGUAGE_SPANISH, +}; + +enum eFrontendSprites +{ + FE2_MAINPANEL_UL, + FE2_MAINPANEL_UR, + FE2_MAINPANEL_DL, + FE2_MAINPANEL_DR, + FE2_MAINPANEL_DR2, + FE2_TABACTIVE, + FE_ICONBRIEF, + FE_ICONSTATS, + FE_ICONCONTROLS, + FE_ICONSAVE, + FE_ICONAUDIO, + FE_ICONDISPLAY, + FE_ICONLANGUAGE, + FE_CONTROLLER, + FE_CONTROLLERSH, + FE_ARROWS1, + FE_ARROWS2, + FE_ARROWS3, + FE_ARROWS4, + FE_RADIO1, + FE_RADIO2, + FE_RADIO3, + FE_RADIO4, + FE_RADIO5, + FE_RADIO6, + FE_RADIO7, + FE_RADIO8, + FE_RADIO9, +}; + +enum eMenuSprites +{ + MENUSPRITE_CONNECTION, + MENUSPRITE_FINDGAME, + MENUSPRITE_HOSTGAME, + MENUSPRITE_MAINMENU, + MENUSPRITE_PLAYERSET, + MENUSPRITE_SINGLEPLAYER, + MENUSPRITE_MULTIPLAYER, + MENUSPRITE_DMALOGO, + MENUSPRITE_GTALOGO, + MENUSPRITE_RSTARLOGO, + MENUSPRITE_GAMESPY, + MENUSPRITE_MOUSE, + MENUSPRITE_MOUSET, + MENUSPRITE_MP3LOGO, + MENUSPRITE_DOWNOFF, + MENUSPRITE_DOWNON, + MENUSPRITE_UPOFF, + MENUSPRITE_UPON, + MENUSPRITE_GTA3LOGO, +}; + +enum eSaveSlot +{ + SAVESLOT_NONE, + SAVESLOT_0, + SAVESLOT_1, + SAVESLOT_2, + SAVESLOT_3, + SAVESLOT_4, + SAVESLOT_5, + SAVESLOT_6, + SAVESLOT_7, + SAVESLOT_8, + SAVESLOT_LABEL = 36 +}; + +enum eMenuScreen +{ + MENUPAGE_DISABLED = -1, + MENUPAGE_NONE = 0, + MENUPAGE_STATS = 1, + MENUPAGE_NEW_GAME = 2, + MENUPAGE_BRIEFS = 3, + MENUPAGE_CONTROLLER_SETTINGS = 4, + MENUPAGE_SOUND_SETTINGS = 5, + MENUPAGE_GRAPHICS_SETTINGS = 6, + MENUPAGE_LANGUAGE_SETTINGS = 7, + MENUPAGE_CHOOSE_LOAD_SLOT = 8, + MENUPAGE_CHOOSE_DELETE_SLOT = 9, + MENUPAGE_NEW_GAME_RELOAD = 10, + MENUPAGE_LOAD_SLOT_CONFIRM = 11, + MENUPAGE_DELETE_SLOT_CONFIRM = 12, + MENUPAGE_13 = 13, + MENUPAGE_LOADING_IN_PROGRESS = 14, + MENUPAGE_DELETING_IN_PROGRESS = 15, + MENUPAGE_16 = 16, + MENUPAGE_DELETE_FAILED = 17, + MENUPAGE_DEBUG_MENU = 18, + MENUPAGE_MEMORY_CARD_1 = 19, + MENUPAGE_MEMORY_CARD_2 = 20, + MENUPAGE_MULTIPLAYER_MAIN = 21, + MENUPAGE_SAVE_FAILED_1 = 22, + MENUPAGE_SAVE_FAILED_2 = 23, + MENUPAGE_SAVE = 24, + MENUPAGE_NO_MEMORY_CARD = 25, + MENUPAGE_CHOOSE_SAVE_SLOT = 26, + MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27, + MENUPAGE_MULTIPLAYER_MAP = 28, + MENUPAGE_MULTIPLAYER_CONNECTION = 29, + MENUPAGE_MULTIPLAYER_FIND_GAME = 30, + MENUPAGE_MULTIPLAYER_MODE = 31, + MENUPAGE_MULTIPLAYER_CREATE = 32, + MENUPAGE_MULTIPLAYER_START = 33, + MENUPAGE_SKIN_SELECT_OLD = 34, + MENUPAGE_CONTROLLER_PC = 35, + MENUPAGE_CONTROLLER_PC_OLD1 = 36, + MENUPAGE_CONTROLLER_PC_OLD2 = 37, + MENUPAGE_CONTROLLER_PC_OLD3 = 38, + MENUPAGE_CONTROLLER_PC_OLD4 = 39, + MENUPAGE_CONTROLLER_DEBUG = 40, + MENUPAGE_OPTIONS = 41, + MENUPAGE_EXIT = 42, + MENUPAGE_SAVING_IN_PROGRESS = 43, + MENUPAGE_SAVE_SUCCESSFUL = 44, + MENUPAGE_DELETING = 45, + MENUPAGE_DELETE_SUCCESS = 46, + MENUPAGE_SAVE_FAILED = 47, + MENUPAGE_LOAD_FAILED = 48, + MENUPAGE_LOAD_FAILED_2 = 49, + MENUPAGE_FILTER_GAME = 50, + MENUPAGE_START_MENU = 51, + MENUPAGE_PAUSE_MENU = 52, + MENUPAGE_CHOOSE_MODE = 53, + MENUPAGE_SKIN_SELECT = 54, + MENUPAGE_KEYBOARD_CONTROLS = 55, + MENUPAGE_MOUSE_CONTROLS = 56, + MENUPAGE_57 = 57, + MENUPAGE_58 = 58, + MENUPAGES +}; + +enum eMenuAction +{ + MENUACTION_NOTHING, + MENUACTION_LABEL, + MENUACTION_CHANGEMENU, + MENUACTION_CTRLVIBRATION, + MENUACTION_CTRLCONFIG, + MENUACTION_CTRLDISPLAY, + MENUACTION_FRAMESYNC, + MENUACTION_FRAMELIMIT, + MENUACTION_TRAILS, + MENUACTION_SUBTITLES, + MENUACTION_WIDESCREEN, + MENUACTION_BRIGHTNESS, + MENUACTION_DRAWDIST, + MENUACTION_MUSICVOLUME, + MENUACTION_SFXVOLUME, + MENUACTION_UNK15, + MENUACTION_RADIO, + MENUACTION_LANG_ENG, + MENUACTION_LANG_FRE, + MENUACTION_LANG_GER, + MENUACTION_LANG_ITA, + MENUACTION_LANG_SPA, + MENUACTION_UPDATESAVE, + MENUACTION_CHECKSAVE, + MENUACTION_UNK24, + MENUACTION_NEWGAME, + MENUACTION_RELOADIDE, + MENUACTION_RELOADIPL, + MENUACTION_SETDBGFLAG, + MENUACTION_SWITCHBIGWHITEDEBUGLIGHT, + MENUACTION_PEDROADGROUPS, + MENUACTION_CARROADGROUPS, + MENUACTION_COLLISIONPOLYS, + MENUACTION_REGMEMCARD1, + MENUACTION_TESTFORMATMEMCARD1, + MENUACTION_TESTUNFORMATMEMCARD1, + MENUACTION_CREATEROOTDIR, + MENUACTION_CREATELOADICONS, + MENUACTION_FILLWITHGUFF, + MENUACTION_SAVEONLYTHEGAME, + MENUACTION_SAVEGAME, + MENUACTION_SAVEGAMEUNDERGTA, + MENUACTION_CREATECOPYPROTECTED, + MENUACTION_TESTSAVE, + MENUACTION_TESTLOAD, + MENUACTION_TESTDELETE, + MENUACTION_PARSEHEAP, + MENUACTION_SHOWCULL, + MENUACTION_MEMCARDSAVECONFIRM, + MENUACTION_UPDATEMEMCARDSAVE, + MENUACTION_UNK50, + MENUACTION_DEBUGSTREAM, + MENUACTION_MPMAP_LIBERTY, + MENUACTION_MPMAP_REDLIGHT, + MENUACTION_MPMAP_CHINATOWN, + MENUACTION_MPMAP_TOWER, + MENUACTION_MPMAP_SEWER, + MENUACTION_MPMAP_INDUSTPARK, + MENUACTION_MPMAP_DOCKS, + MENUACTION_MPMAP_STAUNTON, + MENUACTION_MPMAP_DEATHMATCH1, + MENUACTION_MPMAP_DEATHMATCH2, + MENUACTION_MPMAP_TEAMDEATH1, + MENUACTION_MPMAP_TEAMDEATH2, + MENUACTION_MPMAP_STASH, + MENUACTION_MPMAP_CAPTURE, + MENUACTION_MPMAP_RATRACE, + MENUACTION_MPMAP_DOMINATION, + MENUACTION_STARTMP, + MENUACTION_UNK69, + MENUACTION_UNK70, + MENUACTION_FINDMP, + MENUACTION_REDEFCTRL, + MENUACTION_UNK73, + MENUACTION_INITMP, + MENUACTION_MP_PLAYERCOLOR, + MENUACTION_MP_PLAYERNAME, + MENUACTION_MP_GAMENAME, + MENUACTION_GETKEY, + MENUACTION_SHOWHEADBOB, + MENUACTION_UNK80, + MENUACTION_INVVERT, + MENUACTION_CANCLEGAME, + MENUACTION_MP_PLAYERNUMBER, + MENUACTION_MOUSESENS, + MENUACTION_CHECKMPGAMES, + MENUACTION_CHECKMPPING, + MENUACTION_MP_SERVER, + MENUACTION_MP_MAP, + MENUACTION_MP_GAMETYPE, + MENUACTION_MP_LAN, + MENUACTION_MP_INTERNET, + MENUACTION_RESUME, + MENUACTION_DONTCANCLE, + MENUACTION_SCREENRES, + MENUACTION_AUDIOHW, + MENUACTION_SPEAKERCONF, + MENUACTION_PLAYERSETUP, + MENUACTION_RESTOREDEF, + MENUACTION_CTRLMETHOD, + MENUACTION_DYNAMICACOUSTIC, + MENUACTION_LOADRADIO, + MENUACTION_MOUSESTEER, + MENUACTION_UNK103, + MENUACTION_UNK104, + MENUACTION_UNK105, + MENUACTION_UNK106, + MENUACTION_UNK107, + MENUACTION_UNK108, + MENUACTION_UNK109, + MENUACTION_UNK110, +}; + +enum eCheckHover +{ + ACTIVATE_OPTION = 2, + IGNORE_OPTION = 42, +}; + +enum eMenuColumns +{ + MENUCOLUMN_LEFT, + MENUCOLUMN_CENTER, + MENUCOLUMN_RIGHT, + MENUCOLUMNS, +}; + +enum eMenuRow +{ + MENUROW_NONE = -1, + MENUROW_0, + MENUROW_1, + MENUROW_2, + MENUROW_3, + MENUROW_4, + MENUROW_5, + MENUROW_6, + MENUROW_7, + MENUROW_8, + MENUROW_9, + MENUROW_10, + MENUROW_11, + MENUROW_12, + MENUROW_13, + MENUROW_14, + MENUROW_15, + MENUROW_16, + MENUROW_17, + MENUROWS, +}; + +struct tSkinInfo +{ + int field_0; + char skinName[256]; + char currSkinName[256]; + char date[256]; + int field_304; +}; + +struct CMenuScreen +{ + char m_ScreenName[8]; + int32 unk; + int32 m_PreviousPage[2]; // eMenuScreen + int32 m_ParentEntry[2]; // eMenuRow + + struct CMenuEntry + { + int32 m_Action; // eMenuAction + char m_EntryName[8]; + int32 m_SaveSlot; // eSaveSlot + int32 m_TargetMenu; // eMenuScreen + } m_aEntries[MENUROWS]; +}; + +class CMenuManager +{ +public: + int32 m_nPrefsVideoMode; + int32 m_nDisplayVideoMode; + int8 m_nPrefsAudio3DProviderIndex; + bool m_bKeyChangeNotProcessed; + char m_aSkinName[256]; + int32 m_nHelperTextMsgId; + bool m_bLanguageLoaded; + bool m_bMenuActive; + char field_112; + char field_113; + bool m_bStartGameLoading; + bool m_bFirstTime; + bool m_bGameNotLoaded; + int32 m_nMousePosX; + int32 m_nMousePosY; + int32 m_nMouseTempPosX; + int32 m_nMouseTempPosY; + bool m_bShowMouse; + tSkinInfo field_12C; + tSkinInfo *m_pSelectedSkin; + tSkinInfo *field_438; + float field_43C; + int field_440; + int m_nSkinsTotal; + char _unk0[4]; + int field_44C; + bool m_bSkinsFound; + bool m_bQuitGameNoCD; + char field_452; + bool m_bSaveMenuActive; + bool m_bLoadingSavedGame; + char field_455; + char field_456; + bool m_bSpritesLoaded; + CSprite2d m_aFrontEndSprites[28]; + CSprite2d m_aMenuSprites[20]; + int field_518; + int m_nMenuFadeAlpha; + char field_520; + char field_521; + char field_522; + char field_523; + char field_524; + int m_CurrCntrlAction; + char _unk1[4]; + int field_530; + char field_534; + char field_535; + int8 field_536; + int m_nHelperTextAlpha; + int m_nMouseOldPosX; + int m_nMouseOldPosY; + int m_nHoverOption; + int m_nCurrScreen; + int m_nCurrOption; + int m_nPrevOption; + int m_nPrevScreen; + int field_558; + int m_nCurrSaveSlot; + int m_nScreenChangeDelayTimer; + + static int32 &OS_Language; + static int8 &m_PrefsUseVibration; + static int8 &m_DisplayControllerOnFoot; + static int8 &m_PrefsUseWideScreen; + static int8 &m_PrefsRadioStation; + static int8 &m_PrefsVsync; + static int8 &m_PrefsVsyncDisp; + static int8 &m_PrefsFrameLimiter; + static int8 &m_PrefsShowSubtitles; + static int8 &m_PrefsSpeakers; + static int8 &m_ControlMethod; + static int8 &m_PrefsDMA; + static int8 &m_PrefsLanguage; + static int8 &m_bDisableMouseSteering; + static int32 &m_PrefsBrightness; + static float &m_PrefsLOD; + static int8 &m_bFrontEnd_ReloadObrTxtGxt; + static int32 &m_PrefsMusicVolume; + static int32 &m_PrefsSfxVolume; + static uint8 *m_PrefsSkinFile; + + static bool &m_bStartUpFrontEndRequested; + static bool &m_bShutDownFrontEndRequested; + static bool &m_PrefsAllowNastyGame; + +public: + void BuildStatLine(char *, void *, uint16, void *); + static void CentreMousePointer(); + void CheckCodesForControls(int, int); + bool CheckHover(int x1, int x2, int y1, int y2); + void CheckSliderMovement(int); + int CostructStatLine(int); + void DisplayHelperText(); + float DisplaySlider(float, float, float, float, float, float); + void DoSettingsBeforeStartingAGame(); + void Draw(); + void DrawControllerBound(int, int, int, uint8); + void DrawControllerScreenExtraText(int, int, int); + void DrawControllerSetupScreen(); + void DrawFrontEnd(); + void DrawFrontEndNormal(); + void DrawPlayerSetupScreen(); + int FadeIn(int alpha); + void FilterOutColorMarkersFromString(uint16, CRGBA &); + int GetStartOptionsCntrlConfigScreens(); + static void InitialiseChangedLanguageSettings(); + void LoadAllTextures(); + void LoadSettings(); + static void MessageScreen(char *); + static void PickNewPlayerColour(); + void PrintBriefs(); + static void PrintErrorMessage(); + void PrintStats(); + void Process(); + void ProcessButtonPresses(); + void ProcessOnOffMenuOptions(); + static void RequestFrontEndShutdown(); + static void RequestFrontEndStartUp(); + void ResetHelperText(); + void SaveLoadFileError_SetUpErrorScreen(); + void SaveSettings(); + void SetHelperText(int text); + void ShutdownJustMenu(); + static float StretchX(float); + static float StretchY(float); + void SwitchMenuOnAndOff(); + void UnloadTextures(); + void WaitForUserCD(); + + // New content: + uint8 GetNumberOfMenuOptions(); + void SwitchToNewScreen(int8 screen); + void SetDefaultPreferences(int8 screen); + +}; + +static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error"); + +extern CMenuManager &FrontEndMenuManager; diff --git a/src/core/Game.cpp b/src/core/Game.cpp new file mode 100644 index 00000000..cbd55c48 --- /dev/null +++ b/src/core/Game.cpp @@ -0,0 +1,23 @@ +#include "common.h" +#include "patcher.h" +#include "Game.h" + +eLevelName &CGame::currLevel = *(eLevelName*)0x941514; +bool &CGame::bDemoMode = *(bool*)0x5F4DD0; +bool &CGame::nastyGame = *(bool*)0x5F4DD4; +bool &CGame::frenchGame = *(bool*)0x95CDCB; +bool &CGame::germanGame = *(bool*)0x95CD1E; +bool &CGame::noProstitutes = *(bool*)0x95CDCF; +bool &CGame::playingIntro = *(bool*)0x95CDC2; +char *CGame::aDatFile = (char*)0x773A48; + +WRAPPER void CGame::Initialise(const char *datFile) { EAXJMP(0x48BED0); } +WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); } +WRAPPER bool CGame::InitialiseOnceBeforeRW(void) { EAXJMP(0x48BB80); } +WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); } +WRAPPER void CGame::ShutdownRenderWare(void) { EAXJMP(0x48BCB0); } +WRAPPER void CGame::FinalShutdown(void) { EAXJMP(0x48BEC0); } +WRAPPER void CGame::ShutDown(void) { EAXJMP(0x48C3A0); } +WRAPPER void CGame::ShutDownForRestart(void) { EAXJMP(0x48C6B0); } +WRAPPER void CGame::InitialiseWhenRestarting(void) { EAXJMP(0x48C740); } +WRAPPER bool CGame::InitialiseOnceAfterRW(void) { EAXJMP(0x48BD50); } diff --git a/src/core/Game.h b/src/core/Game.h new file mode 100644 index 00000000..3bc3e633 --- /dev/null +++ b/src/core/Game.h @@ -0,0 +1,37 @@ +#pragma once + +enum eLevelName +{ + LEVEL_NONE = 0, + LEVEL_INDUSTRIAL, + LEVEL_COMMERCIAL, + LEVEL_SUBURBAN +}; + +class CGame +{ +public: + static eLevelName &currLevel; + static bool &bDemoMode; + static bool &nastyGame; + static bool &frenchGame; + static bool &germanGame; + static bool &noProstitutes; + static bool &playingIntro; + static char *aDatFile; //[32]; + + static void Initialise(const char *datFile); + static bool InitialiseOnceBeforeRW(void); + static bool InitialiseRenderWare(void); + static bool InitialiseOnceAfterRW(void); + static void InitialiseWhenRestarting(void); + static void ShutDown(void); + static void ShutdownRenderWare(void); + static void FinalShutdown(void); + static void ShutDownForRestart(void); + static void Process(void); + + // NB: these do something on PS2 + static void TidyUpMemory(bool, bool) {} + static void DrasticTidyUpMemory(void) {} +}; diff --git a/src/core/General.h b/src/core/General.h new file mode 100644 index 00000000..cae1caa0 --- /dev/null +++ b/src/core/General.h @@ -0,0 +1,91 @@ +#pragma once + +class CGeneral +{ +public: + static float GetATanOfXY(float x, float y){ + if(x == 0.0f && y == 0.0f) + return 0.0f; + float xabs = fabs(x); + float yabs = fabs(y); + + if(xabs < yabs){ + if(y > 0.0f){ + if(x > 0.0f) + return 0.5f*PI - atan2(x / y, 1.0f); + else + return 0.5f*PI + atan2(-x / y, 1.0f); + }else{ + if(x > 0.0f) + return 1.5f*PI + atan2(x / -y, 1.0f); + else + return 1.5f*PI - atan2(-x / -y, 1.0f); + } + }else{ + if(y > 0.0f){ + if(x > 0.0f) + return atan2(y / x, 1.0f); + else + return PI - atan2(y / -x, 1.0f); + }else{ + if(x > 0.0f) + return 2.0f*PI - atan2(-y / x, 1.0f); + else + return PI + atan2(-y / -x, 1.0f); + } + } + } + + static float LimitRadianAngle(float angle) + { + float result; + + if (angle < -25.0f) + result = -25.0f; + else if (angle > 25.0f) + result = 25.0f; + else + result = angle; + + while (result >= PI) { + result -= 2 * PI; + } + + while (result < -PI) { + result += 2 * PI; + } + + return result; + } + + static float GetRadianAngleBetweenPoints(float x1, float y1, float x2, float y2) + { + float x = x2 - x1; + float y = y2 - y1; + + if (y == 0.0f) + y = 0.0001f; + + if (x > 0.0f) { + if (y > 0.0f) + return PI - atan2(x / y, 1.0f); + else + return -atan2(x / y, 1.0f); + } else { + if (y > 0.0f) + return -(PI + atan2(x / y, 1.0f)); + else + return -atan2(x / y, 1.0f); + } + } + + // not too sure about all these... + static uint16 GetRandomNumber(void) + { return myrand() & MYRAND_MAX; } + // Probably don't want to ever reach high + static float GetRandomNumberInRange(float low, float high) + { return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); } + + static int32 GetRandomNumberInRange(int32 low, int32 high) + { return low + (high - low)*(GetRandomNumber()/float(MYRAND_MAX + 1)); } +}; diff --git a/src/core/Lists.cpp b/src/core/Lists.cpp new file mode 100644 index 00000000..448a0ff1 --- /dev/null +++ b/src/core/Lists.cpp @@ -0,0 +1,26 @@ +#include "common.h" +#include "Pools.h" +#include "Lists.h" + +void* +CPtrNode::operator new(size_t){ + CPtrNode *node = CPools::GetPtrNodePool()->New(); + assert(node); + return node; +} + +void +CPtrNode::operator delete(void *p, size_t){ + CPools::GetPtrNodePool()->Delete((CPtrNode*)p); +} + +void* +CEntryInfoNode::operator new(size_t){ + CEntryInfoNode *node = CPools::GetEntryInfoNodePool()->New(); + assert(node); + return node; +} +void +CEntryInfoNode::operator delete(void *p, size_t){ + CPools::GetEntryInfoNodePool()->Delete((CEntryInfoNode*)p); +} diff --git a/src/core/Lists.h b/src/core/Lists.h new file mode 100644 index 00000000..7572e882 --- /dev/null +++ b/src/core/Lists.h @@ -0,0 +1,130 @@ +#pragma once + +class CPtrNode +{ +public: + void *item; + CPtrNode *prev; + CPtrNode *next; + + void *operator new(size_t); + void operator delete(void *p, size_t); +}; + +class CPtrList +{ +public: + CPtrNode *first; + + CPtrList(void) { first = nil; } + ~CPtrList(void) { Flush(); } + CPtrNode *FindItem(void *item){ + CPtrNode *node; + for(node = first; node; node = node->next) + if(node->item == item) + return node; + return nil; + } + CPtrNode *InsertNode(CPtrNode *node){ + node->prev = nil; + node->next = first; + if(first) + first->prev = node; + first = node; + return node; + } + CPtrNode *InsertItem(void *item){ + CPtrNode *node = new CPtrNode; + node->item = item; + InsertNode(node); + return node; + } + void RemoveNode(CPtrNode *node){ + if(node == first) + first = node->next; + if(node->prev) + node->prev->next = node->next; + if(node->next) + node->next->prev = node->prev; + } + void DeleteNode(CPtrNode *node){ + RemoveNode(node); + delete node; + } + void RemoveItem(void *item){ + CPtrNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + if(node->item == item) + DeleteNode(node); + } + } + void Flush(void){ + CPtrNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + DeleteNode(node); + } + } +}; + +class CSector; + +// This records in which sector list a Physical is +class CEntryInfoNode +{ +public: + CPtrList *list; // list in sector + CPtrNode *listnode; // node in list + CSector *sector; + + CEntryInfoNode *prev; + CEntryInfoNode *next; + + void *operator new(size_t); + void operator delete(void *p, size_t); +}; + +class CEntryInfoList +{ +public: + CEntryInfoNode *first; + + CEntryInfoList(void) { first = nil; } + ~CEntryInfoList(void) { Flush(); } + CEntryInfoNode *InsertNode(CEntryInfoNode *node){ + node->prev = nil; + node->next = first; + if(first) + first->prev = node; + first = node; + return node; + } + CEntryInfoNode *InsertItem(CPtrList *list, CPtrNode *listnode, CSector *sect){ + CEntryInfoNode *node = new CEntryInfoNode; + node->list = list; + node->listnode = listnode; + node->sector = sect; + InsertNode(node); + return node; + } + void RemoveNode(CEntryInfoNode *node){ + if(node == first) + first = node->next; + if(node->prev) + node->prev->next = node->next; + if(node->next) + node->next->prev = node->prev; + } + void DeleteNode(CEntryInfoNode *node){ + RemoveNode(node); + delete node; + } + void Flush(void){ + CEntryInfoNode *node, *next; + for(node = first; node; node = next){ + next = node->next; + DeleteNode(node); + } + } +}; diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h new file mode 100644 index 00000000..2da81f1d --- /dev/null +++ b/src/core/MenuScreens.h @@ -0,0 +1,380 @@ +#pragma once + +const CMenuScreen aScreens[] = { + // MENUPAGE_NONE = 0 + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, }, + + // MENUPAGE_STATS = 1 + { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_NEW_GAME = 2 + { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1, + MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD, + MENUACTION_CHANGEMENU, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, + MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_BRIEFS = 3 + { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENU_CONTROLLER_SETTINGS = 4 + { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_SOUND_SETTINGS = 5 + { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1, + MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_SPEAKERCONF, "FEA_SPK", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_DYNAMICACOUSTIC, "FET_DAM", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_RADIO, "FEA_RSS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + }, + + // MENUPAGE_GRAPHICS_SETTINGS = 6 + { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2, + MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + //MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_WIDESCREEN, "FED_WIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_SCREENRES, "FED_RES", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_LANGUAGE_SETTINGS = 7 + { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3, + MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_CHOOSE_LOAD_SLOT = 8 + { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1, + MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, + MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM, + }, + + // MENUPAGE_CHOOSE_DELETE_SLOT = 9 + { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2, + MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, + MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM, + MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM, + }, + + // MENUPAGE_NEW_GAME_RELOAD = 10 + { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME, + MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_LOAD_SLOT_CONFIRM = 11 + { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, + MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS, + }, + + // MENUPAGE_DELETE_SLOT_CONFIRM = 12 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, + MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING, + }, + + // MENUPAGE_13 = 13 + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_LOADING_IN_PROGRESS = 14 + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM, + }, + + // MENUPAGE_DELETING_IN_PROGRESS = 15 + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_16 = 16 + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_DELETE_FAILED = 17 + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, + }, + + // MENUPAGE_DEBUG_MENU = 18 + { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MEMORY_CARD_1 = 19 + { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MEMORY_CARD_2 = 20 + { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_MAIN = 21 + { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_SAVE_FAILED_1 = 22 + { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_SAVE_FAILED_2 = 23 + { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_SAVE = 24 + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, + MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_NO_MEMORY_CARD = 25 + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CHOOSE_SAVE_SLOT = 26 + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_UPDATESAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + MENUACTION_UPDATESAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM, + }, + + // MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS, + MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, + }, + + // MENUPAGE_MULTIPLAYER_MAP = 28 + { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_CONNECTION = 29 + { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_FIND_GAME = 30 + { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_MODE = 31 + { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_CREATE = 32 + { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_MULTIPLAYER_START = 33 + { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_SKIN_SELECT_OLD = 34 + { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CONTROLLER_PC = 35 + { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0, + MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, + MENUACTION_CHANGEMENU, "FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS, + MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, + MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_CONTROLLER_PC_OLD1 = 36 + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CONTROLLER_PC_OLD2 = 37 + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CONTROLLER_PC_OLD3 = 38 + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CONTROLLER_PC_OLD4 = 39 + { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_CONTROLLER_DEBUG = 40 + { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_OPTIONS = 41 + { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4, + MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, + MENUACTION_CHANGEMENU, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS, + MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS, + MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS, + //MENUACTION_CHANGEMENU, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_EXIT = 42 + { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5, + MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_SAVING_IN_PROGRESS = 43 + { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_SAVE_SUCCESSFUL = 44 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE, + MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, + }, + + // MENUPAGE_DELETING = 45 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_DELETE_SUCCESS = 46 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT, + }, + + // MENUPAGE_SAVE_FAILED = 47 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT, + }, + + // MENUPAGE_LOAD_FAILED = 48 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_LOAD_FAILED_2 = 49 + { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0, + MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT, + }, + + // MENUPAGE_FILTER_GAME = 50 + { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_START_MENU = 51 + { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, + MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, + MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT, + }, + + // MENUPAGE_PAUSE_MENU = 52 + { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, + MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS, + MENUACTION_CHANGEMENU, "FEP_BRI", SAVESLOT_NONE, MENUPAGE_BRIEFS, + MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, + MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT, + }, + + // MENUPAGE_CHOOSE_MODE = 53 + { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_SKIN_SELECT = 54 + { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4, + //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN, + }, + + // MENUPAGE_KEYBOARD_CONTROLS = 55 + { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1, + //MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC, + }, + + // MENUPAGE_MOUSE_CONTROLS = 56 + { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_2, + MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, + MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, + MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, + + // MENUPAGE_57 = 57 + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, + + // MENUPAGE_58 = 58 + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, + + }, +}; diff --git a/src/core/Messages.cpp b/src/core/Messages.cpp new file mode 100644 index 00000000..7fc23593 --- /dev/null +++ b/src/core/Messages.cpp @@ -0,0 +1,15 @@ +#include "common.h" +#include "patcher.h" +#include "Messages.h" + +WRAPPER void CMessages::Display(void) { EAXJMP(0x529800); } +WRAPPER void CMessages::ClearAllMessagesDisplayedByGame(void) { EAXJMP(0x52B670); } +WRAPPER int CMessages::WideStringCopy(wchar* dst, wchar* src, unsigned short size) { EAXJMP(0x5294B0); } +WRAPPER char CMessages::WideStringCompare(wchar* str1, wchar* str2, unsigned short size) { EAXJMP(0x529510); } +WRAPPER void CMessages::InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst) { EAXJMP(0x52A1A0); } +WRAPPER void CMessages::InsertPlayerControlKeysInString(wchar* src) { EAXJMP(0x52A490); } +WRAPPER int CMessages::GetWideStringLength(wchar* src) { EAXJMP(0x529490); } + +tPreviousBrief *CMessages::PreviousBriefs = (tPreviousBrief *)0x713C08; +tMessage *CMessages::BriefMessages = (tMessage *)0x8786E0; +tBigMessage *CMessages::BIGMessages = (tBigMessage *)0x773628; diff --git a/src/core/Messages.h b/src/core/Messages.h new file mode 100644 index 00000000..69cf117c --- /dev/null +++ b/src/core/Messages.h @@ -0,0 +1,44 @@ +#pragma once + +struct tMessage +{ + wchar *m_pText; + uint16 m_nFlag; +private: + int8 _pad6[2]; +public: + uint32 m_nTime; + uint32 m_nStartTime; + int32 m_nNumber[6]; + wchar *m_pString; +}; + +struct tBigMessage +{ + tMessage m_Current; + tMessage m_Stack[3]; +}; + +struct tPreviousBrief +{ + wchar *m_pText; + int32 m_nNumber[6]; + wchar *m_pString; +}; + +class CMessages +{ +public: + static tPreviousBrief *PreviousBriefs; + static tMessage *BriefMessages; + static tBigMessage *BIGMessages; + +public: + static void Display(void); + static void ClearAllMessagesDisplayedByGame(void); + static int WideStringCopy(wchar* dst, wchar* src, unsigned short size); + static char WideStringCompare(wchar* str1, wchar* str2, unsigned short size); + static void InsertNumberInString(wchar* src, int n1, int n2, int n3, int n4, int n5, int n6, wchar* dst); + static void InsertPlayerControlKeysInString(wchar* src); + static int GetWideStringLength(wchar *src); +}; diff --git a/src/core/NodeName.cpp b/src/core/NodeName.cpp new file mode 100644 index 00000000..2aea3c83 --- /dev/null +++ b/src/core/NodeName.cpp @@ -0,0 +1,77 @@ +#include "common.h" +#include "patcher.h" +#include "NodeName.h" + +static int32 &gPluginOffset = *(int32*)0x64C610; + +enum +{ + ID_NODENAME = MAKECHUNKID(rwVENDORID_ROCKSTAR, 0xFE), +}; + +#define NODENAMEEXT(o) (RWPLUGINOFFSET(char, o, gPluginOffset)) + +void* +NodeNameConstructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + if(gPluginOffset > 0) + NODENAMEEXT(object)[0] = '\0'; + return object; +} + +void* +NodeNameDestructor(void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + return object; +} + +void* +NodeNameCopy(void *dstObject, const void *srcObject, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + strncpy(NODENAMEEXT(dstObject), NODENAMEEXT(srcObject), 23); + return nil; +} + +RwStream* +NodeNameStreamRead(RwStream *stream, RwInt32 binaryLength, void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + RwStreamRead(stream, NODENAMEEXT(object), binaryLength); + NODENAMEEXT(object)[binaryLength] = '\0'; + return stream; +} + +RwStream* +NodeNameStreamWrite(RwStream *stream, RwInt32 binaryLength, const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + RwStreamWrite(stream, NODENAMEEXT(object), binaryLength); + return stream; +} + +RwInt32 +NodeNameStreamGetSize(const void *object, RwInt32 offsetInObject, RwInt32 sizeInObject) +{ + // game checks for null pointer on node name extension but that really happen + return rwstrlen(NODENAMEEXT(object)); +} + +bool +NodeNamePluginAttach(void) +{ + gPluginOffset = RwFrameRegisterPlugin(24, ID_NODENAME, + NodeNameConstructor, + NodeNameDestructor, + NodeNameCopy); + RwFrameRegisterPluginStream(ID_NODENAME, + NodeNameStreamRead, + NodeNameStreamWrite, + NodeNameStreamGetSize); + return gPluginOffset != -1; +} + +char* +GetFrameNodeName(RwFrame *frame) +{ + if(gPluginOffset < 0) + return nil; + return NODENAMEEXT(frame); +} diff --git a/src/core/NodeName.h b/src/core/NodeName.h new file mode 100644 index 00000000..1a3e057b --- /dev/null +++ b/src/core/NodeName.h @@ -0,0 +1,4 @@ +#pragma once + +bool NodeNamePluginAttach(void); +char *GetFrameNodeName(RwFrame *frame); diff --git a/src/core/PCSave.cpp b/src/core/PCSave.cpp new file mode 100644 index 00000000..628e1218 --- /dev/null +++ b/src/core/PCSave.cpp @@ -0,0 +1,20 @@ +#include "common.h" +#include "patcher.h" +#include "Frontend.h" +#include "PCSave.h" + +WRAPPER void C_PcSave::SetSaveDirectory(const char *path) { EAXJMP(0x591EA0); } +WRAPPER int8 C_PcSave::PopulateSlotInfo() { EAXJMP(0x592090); } +WRAPPER int8 C_PcSave::DeleteSlot(int) { EAXJMP(0x5922F0); } +WRAPPER int8 C_PcSave::SaveSlot(int) { EAXJMP(0x591EC0); } + +WRAPPER int8 CheckSlotDataValid(int) { EAXJMP(0x591A40); } + +WRAPPER wchar *GetNameOfSavedGame(int counter) { EAXJMP(0x591B60); } +WRAPPER wchar *GetSavedGameDateAndTime(int counter) { EAXJMP(0x591B50); } + + +C_PcSave PcSaveHelper = *(C_PcSave*)0x8E2C60; +int *Slots = (int*)0x728040; +int *SlotFileName = (int*)0x6F07C8; +int *SlotSaveDate = (int*)0x72B858; diff --git a/src/core/PCSave.h b/src/core/PCSave.h new file mode 100644 index 00000000..696e158a --- /dev/null +++ b/src/core/PCSave.h @@ -0,0 +1,21 @@ +#pragma once + +class C_PcSave +{ +public: + int32 m_nHelper; + + static void SetSaveDirectory(const char *path); + int8 PopulateSlotInfo(); + int8 DeleteSlot(int); + int8 SaveSlot(int); +}; + +extern int8 CheckSlotDataValid(int); +extern wchar *GetNameOfSavedGame(int counter); +extern wchar *GetSavedGameDateAndTime(int counter); + +extern C_PcSave PcSaveHelper; +extern int *Slots; +extern int *SlotFileName; +extern int *SlotSaveDate; diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp new file mode 100644 index 00000000..002e7180 --- /dev/null +++ b/src/core/Pad.cpp @@ -0,0 +1,2091 @@ +#pragma warning( push ) +#pragma warning( disable : 4005) +#define DIRECTINPUT_VERSION 0x0800 +#include +#pragma warning( pop ) + +#include "common.h" +#include "patcher.h" +#include "Pad.h" +#include "ControllerConfig.h" +#include "Timer.h" +#include "Frontend.h" +#include "Camera.h" +#include "Game.h" +#include "CutsceneMgr.h" +#include "Font.h" +#include "Hud.h" +#include "Text.h" +#include "Timer.h" +#include "World.h" +#include "Vehicle.h" +#include "Ped.h" +#include "Population.h" +#include "Replay.h" +#include "Weather.h" +#include "win.h" + +CPad *Pads = (CPad*)0x6F0360; // [2] +CMousePointerStateHelper &MousePointerStateHelper = *(CMousePointerStateHelper*)0x95CC8C; + +bool &CPad::bDisplayNoControllerMessage = *(bool *)0x95CD52; +bool &CPad::bObsoleteControllerMessage = *(bool *)0x95CDB8; +bool &CPad::m_bMapPadOneToPadTwo = *(bool *)0x95CD48; + +CKeyboardState &CPad::OldKeyState = *(CKeyboardState*)0x6F1E70; +CKeyboardState &CPad::NewKeyState = *(CKeyboardState*)0x6E60D0; +CKeyboardState &CPad::TempKeyState = *(CKeyboardState*)0x774DE8; + +char CPad::KeyBoardCheatString[18]; + +CMouseControllerState &CPad::OldMouseControllerState = *(CMouseControllerState*)0x8472A0; +CMouseControllerState &CPad::NewMouseControllerState = *(CMouseControllerState*)0x8809F0; +CMouseControllerState &CPad::PCTempMouseControllerState = *(CMouseControllerState*)0x6F1E60; + +_TODO("gbFastTime"); +extern bool &gbFastTime; + +WRAPPER void WeaponCheat() { EAXJMP(0x490D90); } +WRAPPER void HealthCheat() { EAXJMP(0x490E70); } +WRAPPER void TankCheat() { EAXJMP(0x490EE0); } +WRAPPER void BlowUpCarsCheat() { EAXJMP(0x491040); } +WRAPPER void ChangePlayerCheat() { EAXJMP(0x4910B0); } +WRAPPER void MayhemCheat() { EAXJMP(0x4911C0); } +WRAPPER void EverybodyAttacksPlayerCheat() { EAXJMP(0x491270); } +WRAPPER void WeaponsForAllCheat() { EAXJMP(0x491370); } +WRAPPER void FastTimeCheat() { EAXJMP(0x4913A0); } +WRAPPER void SlowTimeCheat() { EAXJMP(0x4913F0); } +WRAPPER void MoneyCheat() { EAXJMP(0x491430); } +WRAPPER void ArmourCheat() { EAXJMP(0x491460); } +WRAPPER void WantedLevelUpCheat() { EAXJMP(0x491490); } +WRAPPER void WantedLevelDownCheat() { EAXJMP(0x4914F0); } +WRAPPER void SunnyWeatherCheat() { EAXJMP(0x491520); } +WRAPPER void CloudyWeatherCheat() { EAXJMP(0x491550); } +WRAPPER void RainyWeatherCheat() { EAXJMP(0x491580); } +WRAPPER void FoggyWeatherCheat() { EAXJMP(0x4915B0); } +WRAPPER void FastWeatherCheat() { EAXJMP(0x4915E0); } +WRAPPER void OnlyRenderWheelsCheat() { EAXJMP(0x491610); } +WRAPPER void ChittyChittyBangBangCheat() { EAXJMP(0x491640); } +WRAPPER void StrongGripCheat() { EAXJMP(0x491670); } +WRAPPER void NastyLimbsCheat() { EAXJMP(0x4916A0); } +////////////////////////////////////////////////////////////////////////// + +#ifdef KANGAROO_CHEAT +void KangarooCheat() +{ + wchar *string; + CPed *playerPed = FindPlayerPed(); + int m_fMass; + + if (playerPed->m_ped_flagI80) { + string = TheText.Get("CHEATOF"); + m_fMass = 70.0f; + } else { + string = TheText.Get("CHEAT1"); + m_fMass = 15.0f; + } + CHud::SetHelpMessage(string, 1); + playerPed->m_ped_flagI80 = !playerPed->m_ped_flagI80; + + playerPed->m_fMass = m_fMass; + playerPed->m_fAirResistance = 0.4f / m_fMass; +} +#endif + +void +CControllerState::Clear(void) +{ + LeftStickX = LeftStickY = RightStickX = RightStickY = 0; + LeftShoulder1 = LeftShoulder2 = RightShoulder1 = RightShoulder2 = 0; + DPadUp = DPadDown = DPadLeft = DPadRight = 0; + Start = Select = 0; + Square = Triangle = Cross = Circle = 0; + LeftShock = RightShock = 0; + NetworkTalk = 0; +} + +void CKeyboardState::Clear() +{ + for ( int32 i = 0; i < 12; i++ ) + F[i] = 0; + + for ( int32 i = 0; i < 256; i++ ) + VK_KEYS[i] = 0; + + ESC = INS = DEL = HOME = END = PGUP = PGDN = 0; + + UP = DOWN = LEFT = RIGHT = 0; + + NUMLOCK = 0; + + DIV = MUL = SUB = ADD = 0; + + DECIMAL = NUM1 = NUM2 = NUM3 = NUM4 = 0; + + NUM5 = NUM6 = NUM7 = NUM8 = 0; + + NUM9 = NUM0 = SCROLLLOCK = PAUSE = 0; + + BACKSP = TAB = CAPSLOCK = EXTENTER = 0; + + LSHIFT = SHIFT = RSHIFT = LCTRL = RCTRL = LALT = RALT = 0; + + LWIN = RWIN = APPS = 0; +} + +void CPad::Clear(bool bResetPlayerControls) +{ + NewState.Clear(); + OldState.Clear(); + + PCTempKeyState.Clear(); + PCTempJoyState.Clear(); + PCTempMouseState.Clear(); + + NewKeyState.Clear(); + OldKeyState.Clear(); + TempKeyState.Clear(); + + NewMouseControllerState.Clear(); + OldMouseControllerState.Clear(); + PCTempMouseControllerState.Clear(); + + Phase = 0; + ShakeFreq = 0; + ShakeDur = 0; + + if ( bResetPlayerControls ) + DisablePlayerControls = false; + + bApplyBrakes = false; + + + for ( int32 i = 0; i < _TODOCONST(5); i++ ) + bHornHistory[i] = false; + + iCurrHornHistory = 0; + + for ( int32 i = 0; i < _TODOCONST(12); i++ ) + _unk[i] = ' '; + + LastTimeTouched = CTimer::GetTimeInMilliseconds(); + AverageWeapon = 0; + AverageEntries = 0; +} + +void CPad::ClearMouseHistory() +{ + PCTempMouseControllerState.Clear(); + NewMouseControllerState.Clear(); + OldMouseControllerState.Clear(); +} + +CMouseControllerState::CMouseControllerState() +{ + LMB = 0; + RMB = 0; + MMB = 0; + WHEELUP = 0; + WHEELDN = 0; + MXB1 = 0; + MXB2 = 0; + + x = 0.0f; + y = 0.0f; +} + +void CMouseControllerState::Clear() +{ + LMB = 0; + RMB = 0; + MMB = 0; + WHEELUP = 0; + WHEELDN = 0; + MXB1 = 0; + MXB2 = 0; +} + +CMouseControllerState CMousePointerStateHelper::GetMouseSetUp() +{ + CMouseControllerState state; + + if ( PSGLOBAL(mouse) == nil ) + _InputInitialiseMouse(); + + if ( PSGLOBAL(mouse) != nil ) + { + DIDEVCAPS devCaps; + devCaps.dwSize = sizeof(DIDEVCAPS); + + PSGLOBAL(mouse)->GetCapabilities(&devCaps); + + switch ( devCaps.dwButtons ) + { + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + state.MMB = true; + + case 2: + state.RMB = true; + + case 1: + state.LMB = true; + } + + if ( devCaps.dwAxes == 3 ) + { + state.WHEELDN = true; + state.WHEELUP = true; + } + } + + return state; +} + +void CPad::UpdateMouse() +{ + if ( IsForegroundApp() ) + { + if ( PSGLOBAL(mouse) == nil ) + _InputInitialiseMouse(); + + DIMOUSESTATE2 state; + + if ( PSGLOBAL(mouse) != nil && SUCCEEDED(_InputGetMouseState(&state)) ) + { + int32 signX = 1; + int32 signy = 1; + + if ( !FrontEndMenuManager.m_bMenuActive ) + { + if ( MousePointerStateHelper.bInvertVertically ) + signy = -1; + if ( MousePointerStateHelper.bInvertHorizontally ) + signX = -1; + } + + PCTempMouseControllerState.Clear(); + + PCTempMouseControllerState.x = (float)(signX * state.lX); + PCTempMouseControllerState.y = (float)(signy * state.lY); + PCTempMouseControllerState.LMB = state.rgbButtons[0] & 128; + PCTempMouseControllerState.RMB = state.rgbButtons[1] & 128; + PCTempMouseControllerState.MMB = state.rgbButtons[2] & 128; + PCTempMouseControllerState.MXB1 = state.rgbButtons[3] & 128; + PCTempMouseControllerState.MXB2 = state.rgbButtons[4] & 128; + + if ( state.lZ > 0 ) + PCTempMouseControllerState.WHEELUP = 1; + else if ( state.lZ < 0 ) + PCTempMouseControllerState.WHEELDN = 1; + + OldMouseControllerState = NewMouseControllerState; + NewMouseControllerState = PCTempMouseControllerState; + } + } +} + +CControllerState CPad::ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2) +{ + static CControllerState ReconState; + + ReconState.Clear(); + +#define _RECONCILE_BUTTON(button) \ + { if ( State1.button || State2.button ) ReconState.button = 255; } + +#define _RECONCILE_AXIS_POSITIVE(axis) \ + { if ( State1.axis >= 0 && State2.axis >= 0 ) ReconState.axis = max(State1.axis, State2.axis); } + +#define _RECONCILE_AXIS_NEGATIVE(axis) \ + { if ( State1.axis <= 0 && State2.axis <= 0 ) ReconState.axis = min(State1.axis, State2.axis); } + +#define _RECONCILE_AXIS(axis) \ + { _RECONCILE_AXIS_POSITIVE(axis); _RECONCILE_AXIS_NEGATIVE(axis); } + +#define _FIX_AXIS_DIR(axis) \ + { if ( State1.axis > 0 && State2.axis < 0 || State1.axis < 0 && State2.axis > 0 ) ReconState.axis = 0; } + +#define _FIX_RECON_DIR(pos, neg, axis) \ + { if ( (ReconState.pos || ReconState.axis < 0) && (ReconState.neg || ReconState.axis > 0) ) { ReconState.pos = 0; ReconState.neg = 0; ReconState.axis = 0; } } + + _RECONCILE_BUTTON(LeftShoulder1); + _RECONCILE_BUTTON(LeftShoulder2); + _RECONCILE_BUTTON(RightShoulder1); + _RECONCILE_BUTTON(RightShoulder2); + _RECONCILE_BUTTON(Start); + _RECONCILE_BUTTON(Select); + _RECONCILE_BUTTON(Square); + _RECONCILE_BUTTON(Triangle); + _RECONCILE_BUTTON(Cross); + _RECONCILE_BUTTON(Circle); + _RECONCILE_BUTTON(LeftShock); + _RECONCILE_BUTTON(RightShock); + _RECONCILE_BUTTON(NetworkTalk); + _RECONCILE_AXIS(LeftStickX); + _RECONCILE_AXIS(LeftStickY); + _FIX_AXIS_DIR(LeftStickX); + _FIX_AXIS_DIR(LeftStickY); + _RECONCILE_AXIS(RightStickX); + _RECONCILE_AXIS(RightStickY); + _FIX_AXIS_DIR(RightStickX); + _FIX_AXIS_DIR(RightStickY); + _RECONCILE_BUTTON(DPadUp); + _RECONCILE_BUTTON(DPadDown); + _RECONCILE_BUTTON(DPadLeft); + _RECONCILE_BUTTON(DPadRight); + _FIX_RECON_DIR(DPadUp, DPadDown, LeftStickY); + _FIX_RECON_DIR(DPadLeft, DPadRight, LeftStickX); + + return ReconState; + +#undef _RECONCILE_BUTTON +#undef _RECONCILE_AXIS_POSITIVE +#undef _RECONCILE_AXIS_NEGATIVE +#undef _RECONCILE_AXIS +#undef _FIX_AXIS_DIR +#undef _FIX_RECON_DIR +} + +void CPad::StartShake(int16 nDur, uint8 nFreq) +{ + if ( !CMenuManager::m_PrefsUseVibration ) + return; + + if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) + return; + + if ( nFreq == 0 ) + { + ShakeDur = 0; + ShakeFreq = 0; + return; + } + + if ( nDur > ShakeDur ) + { + ShakeDur = nDur; + ShakeFreq = nFreq; + } +} + +void CPad::StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fZ) +{ + if ( !CMenuManager::m_PrefsUseVibration ) + return; + + if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) + return; + + float fDist = ( TheCamera.GetPosition() - CVector(fX, fY, fZ) ).Magnitude(); + + if ( fDist < 70.0f ) + { + if ( nFreq == 0 ) + { + ShakeDur = 0; + ShakeFreq = 0; + return; + } + + if ( nDur > ShakeDur ) + { + ShakeDur = nDur; + ShakeFreq = nFreq; + } + } +} + +void CPad::StartShake_Train(float fX, float fY) +{ + if ( !CMenuManager::m_PrefsUseVibration ) + return; + + if ( CCutsceneMgr::IsRunning() || CGame::playingIntro ) + return; + + if (FindPlayerVehicle() != nil && FindPlayerVehicle()->IsTrain() ) + return; + + float fDist = ( TheCamera.GetPosition() - CVector(fX, fY, 0.0f) ).Magnitude2D(); + + if ( fDist < 70.0f ) + { + int32 freq = (int32)((70.0f - fDist) * 70.0f / 70.0f + 30.0f); + + if ( ShakeDur < 100 ) + { + ShakeDur = 100; + ShakeFreq = freq; + } + } +} + +void CPad::AddToPCCheatString(char c) +{ + for ( int32 i = ARRAY_SIZE(KeyBoardCheatString); i >= 0; i-- ) + KeyBoardCheatString[i + 1] = KeyBoardCheatString[i]; + + KeyBoardCheatString[0] = c; + + #define _CHEATCMP(str) strncmp(str, KeyBoardCheatString, sizeof(str)-1) + + // "GUNSGUNSGUNS" + if ( !_CHEATCMP("SNUGSNUGSNUG") ) + WeaponCheat(); + + // "IFIWEREARICHMAN" + if ( !_CHEATCMP("NAMHCIRAEREWIFI") ) + MoneyCheat(); + + // "GESUNDHEIT" + if ( !_CHEATCMP("TIEHDNUSEG") ) + HealthCheat(); + + // "MOREPOLICEPLEASE" + if ( !_CHEATCMP("ESAELPECILOPEROM") ) + WantedLevelUpCheat(); + + // "NOPOLICEPLEASE" + if ( !_CHEATCMP("ESAELPECILOPON") ) + WantedLevelDownCheat(); + + // "GIVEUSATANK" + if ( !_CHEATCMP("KNATASUEVIG") ) + TankCheat(); + + // "BANGBANGBANG" + if ( !_CHEATCMP("GNABGNABGNAB") ) + BlowUpCarsCheat(); + + // "ILIKEDRESSINGUP" + if ( !_CHEATCMP("PUGNISSERDEKILI") ) + ChangePlayerCheat(); + + // "ITSALLGOINGMAAAD" + if ( !_CHEATCMP("DAAAMGNIOGLLASTI") ) + MayhemCheat(); + + // "NOBODYLIKESME" + if ( !_CHEATCMP("EMSEKILYDOBON") ) + EverybodyAttacksPlayerCheat(); + + // "WEAPONSFORALL" + if ( !_CHEATCMP("LLAROFSNOPAEW") ) + WeaponsForAllCheat(); + + // "TIMEFLIESWHENYOU" + if ( !_CHEATCMP("UOYNEHWSEILFEMIT") ) + FastTimeCheat(); + + // "BOOOOORING" + if ( !_CHEATCMP("GNIROOOOOB") ) + SlowTimeCheat(); + +#ifndef GTA3_1_1_PATCH + // "TURTOISE" + if ( !_CHEATCMP("ESIOTRUT") ) + ArmourCheat(); +#else + // "TORTOISE" + if ( !_CHEATCMP("ESIOTROT") ) + ArmourCheat(); +#endif + + // "SKINCANCERFORME" + if ( !_CHEATCMP("EMROFRECNACNIKS") ) + SunnyWeatherCheat(); + + // "ILIKESCOTLAND" + if ( !_CHEATCMP("DNALTOCSEKILI") ) + CloudyWeatherCheat(); + + // "ILOVESCOTLAND" + if ( !_CHEATCMP("DNALTOCSEVOLI") ) + RainyWeatherCheat(); + + // "PEASOUP" + if ( !_CHEATCMP("PUOSAEP") ) + FoggyWeatherCheat(); + + // "MADWEATHER" + if ( !_CHEATCMP("REHTAEWDAM") ) + FastWeatherCheat(); + + // "ANICESETOFWHEELS" + if ( !_CHEATCMP("SLEEHWFOTESECINA") ) + OnlyRenderWheelsCheat(); + + // "CHITTYCHITTYBB" + if ( !_CHEATCMP("BBYTTIHCYTTIHC") ) + ChittyChittyBangBangCheat(); + + // "CORNERSLIKEMAD" + if ( !_CHEATCMP("DAMEKILSRENROC") ) + StrongGripCheat(); + + // "NASTYLIMBSCHEAT" + if ( !_CHEATCMP("TAEHCSBMILYTSAN") ) + NastyLimbsCheat(); + +#ifdef KANGAROO_CHEAT + // "KANGAROO" + if (!_CHEATCMP("OORAGNAK")) + KangarooCheat(); +#endif + + #undef _CHEATCMP +} + +void CPad::UpdatePads(void) +{ + bool bUpdate = true; + + GetPad(0)->UpdateMouse(); + CapturePad(0); + + + ControlsManager.ClearSimButtonPressCheckers(); + ControlsManager.AffectPadFromKeyBoard(); + ControlsManager.AffectPadFromMouse(); + + if ( CReplay::IsPlayingBackFromFile() ) + bUpdate = false; + + if ( bUpdate ) + { + GetPad(0)->Update(0); + } + + GetPad(1)->NewState.Clear(); + GetPad(1)->OldState.Clear(); + + OldKeyState = NewKeyState; + NewKeyState = TempKeyState; +} + +void CPad::ProcessPCSpecificStuff(void) +{ + ; +} + +void CPad::Update(int16 unk) +{ + OldState = NewState; + + NewState = ReconcileTwoControllersInput(PCTempKeyState, PCTempJoyState); + NewState = ReconcileTwoControllersInput(PCTempMouseState, NewState); + + PCTempJoyState.Clear(); + PCTempKeyState.Clear(); + PCTempMouseState.Clear(); + + ProcessPCSpecificStuff(); + + if ( ++iCurrHornHistory >= _TODOCONST(5) ) + iCurrHornHistory = 0; + + bHornHistory[iCurrHornHistory] = GetHorn(); + + + if ( !bDisplayNoControllerMessage ) + CGame::bDemoMode = false; +} + +void CPad::DoCheats(void) +{ + GetPad(0)->DoCheats(0); +} + +void CPad::DoCheats(int16 unk) +{ +#ifdef PS2 + if ( GetTriangleJustDown() ) + AddToCheatString('T'); + + if ( GetCircleJustDown() ) + AddToCheatString('C'); + + if ( GetCrossJustDown() ) + AddToCheatString('X'); + + if ( GetSquareJustDown() ) + AddToCheatString('S'); + + if ( GetDPadUpJustDown() ) + AddToCheatString('U'); + + if ( GetDPadDownJustDown() ) + AddToCheatString('D'); + + if ( GetDPadLeftJustDown() ) + AddToCheatString('L'); + + if ( GetDPadRightJustDown() ) + AddToCheatString('R'); + + if ( GetLeftShoulder1JustDown() ) + AddToCheatString('1'); + + if ( GetLeftShoulder2JustDown() ) + AddToCheatString('2'); + + if ( GetRightShoulder1JustDown() ) + AddToCheatString('3'); + + if ( GetRightShoulder2JustDown() ) + AddToCheatString('4'); +#endif +} + +void CPad::StopPadsShaking(void) +{ + GetPad(0)->StopShaking(0); +} + +void CPad::StopShaking(int16 unk) +{ + ; +} + +CPad *CPad::GetPad(int32 pad) +{ + return &Pads[pad]; +} + +int16 CPad::GetSteeringLeftRight(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + int16 axis = NewState.LeftStickX; + int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; + + break; + } + + case 1: + case 3: + { + return NewState.LeftStickX; + + break; + } + } + + return 0; +} + +int16 CPad::GetSteeringUpDown(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + int16 axis = NewState.LeftStickY; + int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; + + break; + } + + case 1: + case 3: + { + return NewState.LeftStickY; + + break; + } + } + + return 0; +} + +int16 CPad::GetCarGunUpDown(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return NewState.RightStickY; + + break; + } + + case 3: + { + return (NewState.DPadUp - NewState.DPadDown) / 2; + + break; + } + } + + return 0; +} + +int16 CPad::GetCarGunLeftRight(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return NewState.RightStickX; + + break; + } + + case 3: + { + return (NewState.DPadRight - NewState.DPadLeft) / 2; + + break; + } + } + + return 0; +} + +int16 CPad::GetPedWalkLeftRight(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + int16 axis = NewState.LeftStickX; + int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; + + break; + } + + case 1: + case 3: + { + return NewState.LeftStickX; + + break; + } + } + + return 0; +} + + +int16 CPad::GetPedWalkUpDown(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + int16 axis = NewState.LeftStickY; + int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; + + break; + } + + case 1: + case 3: + { + return NewState.LeftStickY; + + break; + } + } + + return 0; +} + +int16 CPad::GetAnalogueUpDown(void) +{ + switch ( Mode ) + { + case 0: + case 2: + { + int16 axis = NewState.LeftStickY; + int16 dpad = (NewState.DPadDown - NewState.DPadUp) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; + + break; + } + + case 1: + case 3: + { + return NewState.LeftStickY; + + break; + } + } + + return 0; +} + +bool CPad::GetLookLeft(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.LeftShoulder2 && !NewState.RightShoulder2); +} + +bool CPad::GetLookRight(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.RightShoulder2 && !NewState.LeftShoulder2); +} + + +bool CPad::GetLookBehindForCar(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.RightShoulder2 && NewState.LeftShoulder2); +} + +bool CPad::GetLookBehindForPed(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!NewState.RightShock; +} + +bool CPad::GetHorn(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + { + return !!NewState.LeftShock; + + break; + } + + case 1: + { + return !!NewState.LeftShoulder1; + + break; + } + + case 2: + { + return !!NewState.RightShoulder1; + + break; + } + + case 3: + { + return !!NewState.LeftShock; + + break; + } + } + + return false; +} + +bool CPad::HornJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + { + return !!(NewState.LeftShock && !OldState.LeftShock); + + break; + } + + case 1: + { + return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); + + break; + } + + case 2: + { + return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); + + break; + } + + case 3: + { + return !!(NewState.LeftShock && !OldState.LeftShock); + + break; + } + } + + return false; +} + + +bool CPad::GetCarGunFired(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return !!NewState.Circle; + + break; + } + + case 3: + { + return !!NewState.RightShoulder1; + + break; + } + } + + return false; +} + +bool CPad::CarGunJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return !!(NewState.Circle && !OldState.Circle); + + break; + } + + case 3: + { + return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); + + break; + } + } + + return false; +} + +int16 CPad::GetHandBrake(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 1: + { + return NewState.RightShoulder1; + + break; + } + + case 2: + { + return NewState.Triangle; + + break; + } + + case 3: + { + return NewState.LeftShoulder1; + + break; + } + } + + return 0; +} + +int16 CPad::GetBrake(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + return NewState.Square; + + break; + } + + case 1: + { + return NewState.Square; + + break; + } + + case 3: + { + int16 axis = 2 * NewState.RightStickY; + + if ( axis < 0 ) + return 0; + else + return axis; + + break; + } + } + + return 0; +} + +bool CPad::GetExitVehicle(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 3: + { + return !!NewState.Triangle; + + break; + } + + case 2: + { + return !!NewState.LeftShoulder1; + + break; + } + } + + return false; +} + +bool CPad::ExitVehicleJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 3: + { + return !!(NewState.Triangle && !OldState.Triangle); + + break; + } + + case 2: + { + return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); + + break; + } + } + + return false; +} + +int32 CPad::GetWeapon(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + { + return NewState.Circle; + + break; + } + + case 2: + { + return NewState.Cross; + + break; + } + + case 3: + { + return NewState.RightShoulder1; + + break; + } + } + + return false; +} + +bool CPad::WeaponJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + { + return !!(NewState.Circle && !OldState.Circle); + + break; + } + + case 2: + { + return !!(NewState.Cross && !OldState.Cross); + + break; + } + + case 3: + { + return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); + + break; + } + } + + return false; +} + +int16 CPad::GetAccelerate(void) +{ + if ( DisablePlayerControls ) + return 0; + + switch ( Mode ) + { + case 0: + case 2: + { + return NewState.Cross; + + break; + } + + case 1: + { + return NewState.Cross; + + break; + } + + case 3: + { + int16 axis = -2 * NewState.RightStickY; + + if ( axis < 0 ) + return 0; + else + return axis; + + break; + } + } + + return 0; +} + +bool CPad::CycleCameraModeUpJustDown(void) +{ + switch ( Mode ) + { + case 0: + case 2: + case 3: + { + return !!(NewState.Select && !OldState.Select); + + break; + } + + case 1: + { + return !!(NewState.DPadUp && !OldState.DPadUp); + + break; + } + } + + return false; +} + +bool CPad::CycleCameraModeDownJustDown(void) +{ + switch ( Mode ) + { + case 0: + case 2: + case 3: + { + return false; + + break; + } + + case 1: + { + return !!(NewState.DPadDown && !OldState.DPadDown); + + break; + } + } + + return false; +} + +bool CPad::ChangeStationJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + { + return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); + + break; + } + + case 1: + { + return !!(NewState.Select && !OldState.Select); + + break; + } + + case 2: + { + return !!(NewState.LeftShock && !OldState.LeftShock); + + break; + } + + case 3: + { + return !!(NewState.Circle && !OldState.Circle); + + break; + } + } + + return false; +} + + +bool CPad::CycleWeaponLeftJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); +} + +bool CPad::CycleWeaponRightJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); +} + +bool CPad::GetTarget(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return !!NewState.RightShoulder1; + + break; + } + + case 3: + { + return !!NewState.LeftShoulder1; + + break; + } + } + + return false; +} + +bool CPad::TargetJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 2: + { + return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); + + break; + } + + case 3: + { + return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); + + break; + } + } + + return false; +} + +bool CPad::JumpJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.Square && !OldState.Square); +} + +bool CPad::GetSprint(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 3: + { + return !!NewState.Cross; + + break; + } + + case 2: + { + return !!NewState.Circle; + + break; + } + } + + return false; +} + +bool CPad::ShiftTargetLeftJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); +} + +bool CPad::ShiftTargetRightJustDown(void) +{ + if ( DisablePlayerControls ) + return false; + + return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); +} + +bool CPad::GetAnaloguePadUp(void) +{ + static int16 oldfStickY = 0; + + int16 Y = CPad::GetPad(0)->GetAnalogueUpDown(); + + if ( Y < 0 && oldfStickY >= 0 ) + { + oldfStickY = Y; + return true; + } + else + { + oldfStickY = Y; + return false; + } +} + +bool CPad::GetAnaloguePadDown(void) +{ + static int16 oldfStickY = 0; + + int16 Y = CPad::GetPad(0)->GetAnalogueUpDown(); + + if ( Y > 0 && oldfStickY <= 0 ) + { + oldfStickY = Y; + return true; + } + else + { + oldfStickY = Y; + return false; + } +} + +bool CPad::GetAnaloguePadLeft(void) +{ + static int16 oldfStickX = 0; + + int16 X = CPad::GetPad(0)->GetPedWalkLeftRight(); + + if ( X < 0 && oldfStickX >= 0 ) + { + oldfStickX = X; + return true; + } + else + { + oldfStickX = X; + return false; + } +} + +bool CPad::GetAnaloguePadRight(void) +{ + static int16 oldfStickX = 0; + + int16 X = CPad::GetPad(0)->GetPedWalkLeftRight(); + + if ( X > 0 && oldfStickX <= 0 ) + { + oldfStickX = X; + return true; + } + else + { + oldfStickX = X; + return false; + } +} + +bool CPad::GetAnaloguePadLeftJustUp(void) +{ + static int16 oldfStickX = 0; + + int16 X = GetPad(0)->GetPedWalkLeftRight(); + + if ( X == 0 && oldfStickX < 0 ) + { + oldfStickX = X; + + return true; + } + else + { + oldfStickX = X; + + return false; + } +} + +bool CPad::GetAnaloguePadRightJustUp(void) +{ + static int16 oldfStickX = 0; + + int16 X = GetPad(0)->GetPedWalkLeftRight(); + + if ( X == 0 && oldfStickX > 0 ) + { + oldfStickX = X; + + return true; + } + else + { + oldfStickX = X; + + return false; + } +} + +bool CPad::ForceCameraBehindPlayer(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + { + return !!NewState.LeftShoulder1; + + break; + } + + case 2: + { + return !!NewState.Triangle; + + break; + } + + case 3: + { + return !!NewState.Circle; + + break; + } + } + + return false; +} + +bool CPad::SniperZoomIn(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 3: + { + return !!NewState.Square; + + break; + } + + case 2: + { + return !!NewState.Triangle; + + break; + } + } + + return false; +} + +bool CPad::SniperZoomOut(void) +{ + if ( DisablePlayerControls ) + return false; + + switch ( Mode ) + { + case 0: + case 1: + case 3: + { + return !!NewState.Cross; + + break; + } + + case 2: + { + return !!NewState.Square; + + break; + } + } + + return false; +} + + +int16 CPad::SniperModeLookLeftRight(void) +{ + int16 axis = NewState.LeftStickX; + int16 dpad = (NewState.DPadRight - NewState.DPadLeft) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; +} + +int16 CPad::SniperModeLookUpDown(void) +{ + int16 axis = NewState.LeftStickY; + int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; + + if ( abs(axis) > abs(dpad) ) + return axis; + else + return dpad; +} + +int16 CPad::LookAroundLeftRight(void) +{ + float axis = GetPad(0)->NewState.RightStickX; + + if ( fabs(axis) > 85 && !GetLookBehindForPed() ) + return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) + * (127.0f / 32.0f) ); // 3.96875f + + else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && fabs(axis) > 10 ) + return (int16) ( (axis + ( ( axis > 0 ) ? -10 : 10) ) + * (127.0f / 64.0f) ); // 1.984375f + + return 0; +} + +int16 CPad::LookAroundUpDown(void) +{ + int16 axis = GetPad(0)->NewState.RightStickY; + + if ( abs(axis) > 85 && !GetLookBehindForPed() ) + return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) + * (127.0f / 32.0f) ); // 3.96875f + + else if ( TheCamera.Cams[0].Using3rdPersonMouseCam() && abs(axis) > 40 ) + return (int16) ( (axis + ( ( axis > 0 ) ? -40 : 40) ) + * (127.0f / 64.0f) ); // 1.984375f + + return 0; +} + + +void CPad::ResetAverageWeapon(void) +{ + AverageWeapon = GetWeapon(); + AverageEntries = 1; +} + +void CPad::PrintErrorMessage(void) +{ + if ( bDisplayNoControllerMessage && !CGame::playingIntro && !FrontEndMenuManager.m_bMenuActive ) + { + CFont::SetScale(0.85f, 1.0f); + CFont::SetJustifyOff(); + CFont::SetBackgroundOff(); + CFont::SetCentreSize(SCREEN_WIDTH - 20); + CFont::SetCentreOn(); + CFont::SetPropOn(); + CFont::SetColor(CRGBA(255, 255, 200, 200)); + CFont::SetFontStyle(FONT_BANK); + CFont::PrintString + ( + SCREEN_WIDTH / 2, + SCREEN_HEIGHT / 2, + TheText.Get("NOCONT") // Please reconnect an analog controller (DUALSHOCK@) or analog controller (DUALSHOCK@2). to controller port 1 to continue + ); + } + else if ( bObsoleteControllerMessage ) + { + CFont::SetScale(0.85f, 1.0f); + CFont::SetJustifyOff(); + CFont::SetBackgroundOff(); + CFont::SetCentreSize(SCREEN_WIDTH - 20); + CFont::SetCentreOn(); + CFont::SetPropOn(); + CFont::SetColor(CRGBA(255, 255, 200, 200)); + CFont::SetFontStyle(FONT_BANK); + CFont::PrintString + ( + SCREEN_WIDTH / 2, + SCREEN_HEIGHT / 2, + TheText.Get("WRCONT") // The controller connected to controller port 1 is an unsupported controller. Grand Theft Auto III requires an analog controller (DUALSHOCK@) or analog controller (DUALSHOCK@2). + ); + } + +} + +void LittleTest(void) +{ + static int32 Cunt = 0; + + Cunt++; // ??? +} + +void CPad::ResetCheats(void) +{ + CWeather::ReleaseWeather(); + + CPopulation::ms_bGivePedsWeapons = false; + + CPed::bNastyLimbsCheat = false; + CPed::bPedCheat2 = false; + CPed::bPedCheat3 = false; + + CVehicle::bWheelsOnlyCheat = false; + CVehicle::bAllDodosCheat = false; + CVehicle::bCheat3 = false; + CVehicle::bCheat4 = false; + CVehicle::bCheat5 = false; + + gbFastTime = false; + CTimer::SetTimeScale(1.0f); +} + +char *CPad::EditString(char *pStr, int32 nSize) +{ + int32 pos = strlen(pStr); + + // letters + for ( int32 i = 0; i < ('Z' - 'A' + 1); i++ ) + { + if ( GetPad(0)->GetCharJustDown(i + 'A') && pos < nSize - 1 ) + { + pStr[pos++] = i + 'A'; + pStr[pos] = '\0'; + } + + if ( GetPad(0)->GetCharJustDown(i + 'a') && pos < nSize - 1 ) + { + pStr[pos++] = i + 'a'; + pStr[pos] = '\0'; + } + } + + // numbers + for ( int32 i = 0; i < ('0' - '9' + 1); i++ ) + { + if ( GetPad(0)->GetCharJustDown(i + '0') && pos < nSize - 1 ) + { + pStr[pos++] = i + '0'; + pStr[pos] = '\0'; + } + } + + // space + if ( GetPad(0)->GetCharJustDown(' ') && pos < nSize - 1 ) + { + pStr[pos++] = ' '; + pStr[pos] = '\0'; + } + + + // del + if ( GetPad(0)->GetDeleteJustDown() || GetPad(0)->GetBackspaceJustDown() ) + { + if ( pos > 0 ) + pStr[pos - 1] = '\0'; + } + + // extenter/up/down + if ( GetPad(0)->GetEnterJustDown() || GetPad(0)->GetUpJustDown() || GetPad(0)->GetDownJustDown() ) + return nil; + + return pStr; +} + +int32 *CPad::EditCodesForControls(int32 *pRsKeys, int32 nSize) +{ + *pRsKeys = rsNULL; + + for ( int32 i = 0; i < 255; i++ ) + { + if ( GetPad(0)->GetCharJustDown(i) ) + *pRsKeys = i; + } + + for ( int32 i = 0; i < 12; i++ ) + { + if ( GetPad(0)->GetFJustDown(i) ) + *pRsKeys = i + rsF1; + } + + if ( GetPad(0)->GetEscapeJustDown() ) + *pRsKeys = rsESC; + + if ( GetPad(0)->GetInsertJustDown() ) + *pRsKeys = rsINS; + + if ( GetPad(0)->GetDeleteJustDown() ) + *pRsKeys = rsDEL; + + if ( GetPad(0)->GetHomeJustDown() ) + *pRsKeys = rsHOME; + + if ( GetPad(0)->GetEndJustDown() ) + *pRsKeys = rsEND; + + if ( GetPad(0)->GetPageUpJustDown() ) + *pRsKeys = rsPGUP; + + if ( GetPad(0)->GetPageDownJustDown() ) + *pRsKeys = rsPGDN; + + if ( GetPad(0)->GetUpJustDown() ) + *pRsKeys = rsUP; + + if ( GetPad(0)->GetDownJustDown() ) + *pRsKeys = rsDOWN; + + if ( GetPad(0)->GetLeftJustDown() ) + *pRsKeys = rsLEFT; + + if ( GetPad(0)->GetRightJustDown() ) + *pRsKeys = rsRIGHT; + + if ( GetPad(0)->GetScrollLockJustDown() ) + *pRsKeys = rsSCROLL; + + if ( GetPad(0)->GetPauseJustDown() ) + *pRsKeys = rsPAUSE; + + if ( GetPad(0)->GetNumLockJustDown() ) + *pRsKeys = rsNUMLOCK; + + if ( GetPad(0)->GetDivideJustDown() ) + *pRsKeys = rsDIVIDE; + + if ( GetPad(0)->GetTimesJustDown() ) + *pRsKeys = rsTIMES; + + if ( GetPad(0)->GetMinusJustDown() ) + *pRsKeys = rsMINUS; + + if ( GetPad(0)->GetPlusJustDown() ) + *pRsKeys = rsPLUS; + + if ( GetPad(0)->GetPadEnterJustDown() ) + *pRsKeys = rsPADENTER; + + if ( GetPad(0)->GetPadDelJustDown() ) + *pRsKeys = rsPADDEL; + + if ( GetPad(0)->GetPad1JustDown() ) + *pRsKeys = rsPADEND; + + if ( GetPad(0)->GetPad2JustDown() ) + *pRsKeys = rsPADDOWN; + + if ( GetPad(0)->GetPad3JustDown() ) + *pRsKeys = rsPADPGDN; + + if ( GetPad(0)->GetPad4JustDown() ) + *pRsKeys = rsPADLEFT; + + if ( GetPad(0)->GetPad5JustDown() ) + *pRsKeys = rsPAD5; + + if ( GetPad(0)->GetPad6JustDown() ) + *pRsKeys = rsPADRIGHT; + + if ( GetPad(0)->GetPad7JustDown() ) + *pRsKeys = rsPADHOME; + + if ( GetPad(0)->GetPad8JustDown() ) + *pRsKeys = rsPADUP; + + if ( GetPad(0)->GetPad9JustDown() ) + *pRsKeys = rsPADPGUP; + + if ( GetPad(0)->GetPad0JustDown() ) + *pRsKeys = rsPADINS; + + if ( GetPad(0)->GetBackspaceJustDown() ) + *pRsKeys = rsBACKSP; + + if ( GetPad(0)->GetTabJustDown() ) + *pRsKeys = rsTAB; + + if ( GetPad(0)->GetCapsLockJustDown() ) + *pRsKeys = rsCAPSLK; + + if ( GetPad(0)->GetEnterJustDown() ) + *pRsKeys = rsENTER; + + if ( GetPad(0)->GetLeftShiftJustDown() ) + *pRsKeys = rsLSHIFT; + + if ( GetPad(0)->GetShiftJustDown() ) + *pRsKeys = rsSHIFT; + + if ( GetPad(0)->GetRightShiftJustDown() ) + *pRsKeys = rsRSHIFT; + + if ( GetPad(0)->GetLeftCtrlJustDown() ) + *pRsKeys = rsLCTRL; + + if ( GetPad(0)->GetRightCtrlJustDown() ) + *pRsKeys = rsRCTRL; + + if ( GetPad(0)->GetLeftAltJustDown() ) + *pRsKeys = rsLALT; + + if ( GetPad(0)->GetRightAltJustDown() ) + *pRsKeys = rsRALT; + + if ( GetPad(0)->GetLeftWinJustDown() ) + *pRsKeys = rsLWIN; + + if ( GetPad(0)->GetRightWinJustDown() ) + *pRsKeys = rsRWIN; + + if ( GetPad(0)->GetAppsJustDown() ) + *pRsKeys = rsAPPS; + + return pRsKeys; +} + +STARTPATCHES + InjectHook(0x4916C0, &CControllerState::Clear, PATCH_JUMP); + InjectHook(0x491760, &CKeyboardState::Clear, PATCH_JUMP); + InjectHook(0x491A10, &CPad::Clear, PATCH_JUMP); + InjectHook(0x491B50, &CPad::ClearMouseHistory, PATCH_JUMP); + //InjectHook(0x491B80, &CMouseControllerState::CMouseControllerState, PATCH_JUMP); + InjectHook(0x491BB0, &CMouseControllerState::Clear, PATCH_JUMP); + InjectHook(0x491BD0, &CMousePointerStateHelper::GetMouseSetUp, PATCH_JUMP); + InjectHook(0x491CA0, &CPad::UpdateMouse, PATCH_JUMP); + InjectHook(0x491E60, &CPad::ReconcileTwoControllersInput, PATCH_JUMP); + InjectHook(0x492230, &CPad::StartShake, PATCH_JUMP); + InjectHook(0x492290, &CPad::StartShake_Distance, PATCH_JUMP); + InjectHook(0x492360, &CPad::StartShake_Train, PATCH_JUMP); + InjectHook(0x492450, &CPad::AddToPCCheatString, PATCH_JUMP); + InjectHook(0x492720, CPad::UpdatePads, PATCH_JUMP); + InjectHook(0x492C60, &CPad::ProcessPCSpecificStuff, PATCH_JUMP); + InjectHook(0x492C70, &CPad::Update, PATCH_JUMP); +#pragma warning( push ) +#pragma warning( disable : 4573) + InjectHook(0x492F00, (void (*)())CPad::DoCheats, PATCH_JUMP); +#pragma warning( pop ) + InjectHook(0x492F20, (void (CPad::*)(int16))&CPad::DoCheats, PATCH_JUMP); + InjectHook(0x492F30, CPad::StopPadsShaking, PATCH_JUMP); + InjectHook(0x492F50, &CPad::StopShaking, PATCH_JUMP); + InjectHook(0x492F60, CPad::GetPad, PATCH_JUMP); + InjectHook(0x492F70, &CPad::GetSteeringLeftRight, PATCH_JUMP); + InjectHook(0x492FF0, &CPad::GetSteeringUpDown, PATCH_JUMP); + InjectHook(0x493070, &CPad::GetCarGunUpDown, PATCH_JUMP); + InjectHook(0x4930C0, &CPad::GetCarGunLeftRight, PATCH_JUMP); + InjectHook(0x493110, &CPad::GetPedWalkLeftRight, PATCH_JUMP); + InjectHook(0x493190, &CPad::GetPedWalkUpDown, PATCH_JUMP); + InjectHook(0x493210, &CPad::GetAnalogueUpDown, PATCH_JUMP); + InjectHook(0x493290, &CPad::GetLookLeft, PATCH_JUMP); + InjectHook(0x4932C0, &CPad::GetLookRight, PATCH_JUMP); + InjectHook(0x4932F0, &CPad::GetLookBehindForCar, PATCH_JUMP); + InjectHook(0x493320, &CPad::GetLookBehindForPed, PATCH_JUMP); + InjectHook(0x493350, &CPad::GetHorn, PATCH_JUMP); + InjectHook(0x4933F0, &CPad::HornJustDown, PATCH_JUMP); + InjectHook(0x493490, &CPad::GetCarGunFired, PATCH_JUMP); + InjectHook(0x4934F0, &CPad::CarGunJustDown, PATCH_JUMP); + InjectHook(0x493560, &CPad::GetHandBrake, PATCH_JUMP); + InjectHook(0x4935A0, &CPad::GetBrake, PATCH_JUMP); + InjectHook(0x4935F0, &CPad::GetExitVehicle, PATCH_JUMP); + InjectHook(0x493650, &CPad::ExitVehicleJustDown, PATCH_JUMP); + InjectHook(0x4936C0, &CPad::GetWeapon, PATCH_JUMP); + InjectHook(0x493700, &CPad::WeaponJustDown, PATCH_JUMP); + InjectHook(0x493780, &CPad::GetAccelerate, PATCH_JUMP); + InjectHook(0x4937D0, &CPad::CycleCameraModeUpJustDown, PATCH_JUMP); + InjectHook(0x493830, &CPad::CycleCameraModeDownJustDown, PATCH_JUMP); + InjectHook(0x493870, &CPad::ChangeStationJustDown, PATCH_JUMP); + InjectHook(0x493910, &CPad::CycleWeaponLeftJustDown, PATCH_JUMP); + InjectHook(0x493940, &CPad::CycleWeaponRightJustDown, PATCH_JUMP); + InjectHook(0x493970, &CPad::GetTarget, PATCH_JUMP); + InjectHook(0x4939D0, &CPad::TargetJustDown, PATCH_JUMP); + InjectHook(0x493A40, &CPad::JumpJustDown, PATCH_JUMP); + InjectHook(0x493A70, &CPad::GetSprint, PATCH_JUMP); + InjectHook(0x493AE0, &CPad::ShiftTargetLeftJustDown, PATCH_JUMP); + InjectHook(0x493B10, &CPad::ShiftTargetRightJustDown, PATCH_JUMP); + InjectHook(0x493B40, &CPad::GetAnaloguePadUp, PATCH_JUMP); + InjectHook(0x493BA0, &CPad::GetAnaloguePadDown, PATCH_JUMP); + InjectHook(0x493C00, &CPad::GetAnaloguePadLeft, PATCH_JUMP); + InjectHook(0x493C60, &CPad::GetAnaloguePadRight, PATCH_JUMP); + InjectHook(0x493CC0, &CPad::GetAnaloguePadLeftJustUp, PATCH_JUMP); + InjectHook(0x493D20, &CPad::GetAnaloguePadRightJustUp, PATCH_JUMP); + InjectHook(0x493D80, &CPad::ForceCameraBehindPlayer, PATCH_JUMP); + InjectHook(0x493E00, &CPad::SniperZoomIn, PATCH_JUMP); + InjectHook(0x493E70, &CPad::SniperZoomOut, PATCH_JUMP); + InjectHook(0x493EE0, &CPad::SniperModeLookLeftRight, PATCH_JUMP); + InjectHook(0x493F30, &CPad::SniperModeLookUpDown, PATCH_JUMP); + InjectHook(0x493F80, &CPad::LookAroundLeftRight, PATCH_JUMP); + InjectHook(0x494130, &CPad::LookAroundUpDown, PATCH_JUMP); + InjectHook(0x494290, &CPad::ResetAverageWeapon, PATCH_JUMP); + InjectHook(0x4942B0, CPad::PrintErrorMessage, PATCH_JUMP); + InjectHook(0x494420, LittleTest, PATCH_JUMP); + InjectHook(0x494450, CPad::ResetCheats, PATCH_JUMP); + InjectHook(0x4944B0, CPad::EditString, PATCH_JUMP); + InjectHook(0x494690, CPad::EditCodesForControls, PATCH_JUMP); + + //InjectHook(0x494E50, `global constructor keyed to'Pad.cpp, PATCH_JUMP); + //InjectHook(0x494EB0, sub_494EB0, PATCH_JUMP); + //InjectHook(0x494ED0, &CPad::~CPad, PATCH_JUMP); + //InjectHook(0x494EE0, &CPad::CPad, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Pad.h b/src/core/Pad.h new file mode 100644 index 00000000..30cdb8df --- /dev/null +++ b/src/core/Pad.h @@ -0,0 +1,367 @@ +#pragma once + +// same as RW skeleton +/* +enum Key +{ + // ascii... + + KEY_ESC = 128, + + KEY_F1 = 129, + KEY_F2 = 130, + KEY_F3 = 131, + KEY_F4 = 132, + KEY_F5 = 133, + KEY_F6 = 134, + KEY_F7 = 135, + KEY_F8 = 136, + KEY_F9 = 137, + KEY_F10 = 138, + KEY_F11 = 139, + KEY_F12 = 140, + + KEY_INS = 141, + KEY_DEL = 142, + KEY_HOME = 143, + KEY_END = 144, + KEY_PGUP = 145, + KEY_PGDN = 146, + + KEY_UP = 147, + KEY_DOWN = 148, + KEY_LEFT = 149, + KEY_RIGHT = 150, + + // some stuff ommitted + + KEY_BACKSP = 168, + KEY_TAB = 169, + KEY_CAPSLK = 170, + KEY_ENTER = 171, + KEY_LSHIFT = 172, + KEY_RSHIFT = 173, + KEY_LCTRL = 174, + KEY_RCTRL = 175, + KEY_LALT = 176, + KEY_RALT = 177, + + KEY_NULL, // unused + KEY_NUMKEYS +}; +*/ + + +class CControllerState +{ +public: + int16 LeftStickX, LeftStickY; + int16 RightStickX, RightStickY; + int16 LeftShoulder1, LeftShoulder2; + int16 RightShoulder1, RightShoulder2; + int16 DPadUp, DPadDown, DPadLeft, DPadRight; + int16 Start, Select; + int16 Square, Triangle, Cross, Circle; + int16 LeftShock, RightShock; + int16 NetworkTalk; + float GetLeftStickX(void) { return LeftStickX/32767.0f; }; + float GetLeftStickY(void) { return LeftStickY/32767.0f; }; + float GetRightStickX(void) { return RightStickX/32767.0f; }; + float GetRightStickY(void) { return RightStickY/32767.0f; }; + + void Clear(void); +}; +VALIDATE_SIZE(CControllerState, 0x2A); + +class CMouseControllerState +{ +public: + //uint32 btns; // bit 0-2 button 1-3 + + bool LMB; + bool RMB; + bool MMB; + bool WHEELUP; + bool WHEELDN; + bool MXB1; + bool MXB2; + char _pad0; + + float x, y; + + CMouseControllerState(); + void Clear(); +}; + +VALIDATE_SIZE(CMouseControllerState, 0x10); + +class CMousePointerStateHelper +{ +public: + bool bInvertHorizontally; + bool bInvertVertically; + + CMouseControllerState GetMouseSetUp(); +}; + +VALIDATE_SIZE(CMousePointerStateHelper, 0x2); + +extern CMousePointerStateHelper &MousePointerStateHelper; + + +class CKeyboardState +{ +public: + int16 F[12]; + int16 VK_KEYS[256]; + int16 ESC; + int16 INS; + int16 DEL; + int16 HOME; + int16 END; + int16 PGUP; + int16 PGDN; + int16 UP; + int16 DOWN; + int16 LEFT; + int16 RIGHT; + int16 SCROLLLOCK; + int16 PAUSE; + int16 NUMLOCK; + int16 DIV; + int16 MUL; + int16 SUB; + int16 ADD; + int16 ENTER; + int16 DECIMAL; + int16 NUM1; + int16 NUM2; + int16 NUM3; + int16 NUM4; + int16 NUM5; + int16 NUM6; + int16 NUM7; + int16 NUM8; + int16 NUM9; + int16 NUM0; + int16 BACKSP; + int16 TAB; + int16 CAPSLOCK; + int16 EXTENTER; + int16 LSHIFT; + int16 RSHIFT; + int16 SHIFT; + int16 LCTRL; + int16 RCTRL; + int16 LALT; + int16 RALT; + int16 LWIN; + int16 RWIN; + int16 APPS; + + void Clear(); +}; + +VALIDATE_SIZE(CKeyboardState, 0x270); + +enum +{ + // taken from miss2 + PAD1 = 0, + PAD2, + + MAX_PADS +}; + +class CPad +{ +public: + CControllerState NewState; + CControllerState OldState; + CControllerState PCTempKeyState; + CControllerState PCTempJoyState; + CControllerState PCTempMouseState; + // straight out of my IDB + int16 Phase; + int16 Mode; + int16 ShakeDur; + uint8 ShakeFreq; + int8 bHornHistory[5]; + uint8 iCurrHornHistory; + bool DisablePlayerControls; + int8 bApplyBrakes; + char _unk[12]; //int32 unk[3]; + char _pad0[3]; + int32 LastTimeTouched; + int32 AverageWeapon; + int32 AverageEntries; + + CPad() { } + ~CPad() { } + + static bool &bDisplayNoControllerMessage; + static bool &bObsoleteControllerMessage; + static bool &m_bMapPadOneToPadTwo; + + static CKeyboardState &OldKeyState; + static CKeyboardState &NewKeyState; + static CKeyboardState &TempKeyState; + static char KeyBoardCheatString[18]; + static CMouseControllerState &OldMouseControllerState; + static CMouseControllerState &NewMouseControllerState; + static CMouseControllerState &PCTempMouseControllerState; + + + + + void Clear(bool bResetPlayerControls); + void ClearMouseHistory(); + void UpdateMouse(); + CControllerState ReconcileTwoControllersInput(CControllerState const &State1, CControllerState const &State2); + void StartShake(int16 nDur, uint8 nFreq); + void StartShake_Distance(int16 nDur, uint8 nFreq, float fX, float fY, float fz); + void StartShake_Train(float fX, float fY); + void AddToPCCheatString(char c); + + static void UpdatePads(void); + void ProcessPCSpecificStuff(void); + void Update(int16 unk); + + static void DoCheats(void); + void DoCheats(int16 unk); + + static void StopPadsShaking(void); + void StopShaking(int16 unk); + + static CPad *GetPad(int32 pad); + + int16 GetSteeringLeftRight(void); + int16 GetSteeringUpDown(void); + int16 GetCarGunUpDown(void); + int16 GetCarGunLeftRight(void); + int16 GetPedWalkLeftRight(void); + int16 GetPedWalkUpDown(void); + int16 GetAnalogueUpDown(void); + bool GetLookLeft(void); + bool GetLookRight(void); + bool GetLookBehindForCar(void); + bool GetLookBehindForPed(void); + bool GetHorn(void); + bool HornJustDown(void); + bool GetCarGunFired(void); + bool CarGunJustDown(void); + int16 GetHandBrake(void); + int16 GetBrake(void); + bool GetExitVehicle(void); + bool ExitVehicleJustDown(void); + int32 GetWeapon(void); + bool WeaponJustDown(void); + int16 GetAccelerate(void); + bool CycleCameraModeUpJustDown(void); + bool CycleCameraModeDownJustDown(void); + bool ChangeStationJustDown(void); + bool CycleWeaponLeftJustDown(void); + bool CycleWeaponRightJustDown(void); + bool GetTarget(void); + bool TargetJustDown(void); + bool JumpJustDown(void); + bool GetSprint(void); + bool ShiftTargetLeftJustDown(void); + bool ShiftTargetRightJustDown(void); + bool GetAnaloguePadUp(void); + bool GetAnaloguePadDown(void); + bool GetAnaloguePadLeft(void); + bool GetAnaloguePadRight(void); + bool GetAnaloguePadLeftJustUp(void); + bool GetAnaloguePadRightJustUp(void); + bool ForceCameraBehindPlayer(void); + bool SniperZoomIn(void); + bool SniperZoomOut(void); + int16 SniperModeLookLeftRight(void); + int16 SniperModeLookUpDown(void); + int16 LookAroundLeftRight(void); + int16 LookAroundUpDown(void); + void ResetAverageWeapon(void); + static void PrintErrorMessage(void); + static void ResetCheats(void); + static char *EditString(char *pStr, int32 nSize); + static int32 *EditCodesForControls(int32 *pRsKeys, int32 nSize); + + // mouse + bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); } + + // keyboard + + bool GetCharJustDown(int32 c) { return !!(NewKeyState.VK_KEYS[c] && !OldKeyState.VK_KEYS[c]); } + bool GetFJustDown(int32 n) { return !!(NewKeyState.F[n] && !OldKeyState.F[n]); } + bool GetEscapeJustDown() { return !!(NewKeyState.ESC && !OldKeyState.ESC); } + bool GetInsertJustDown() { return !!(NewKeyState.INS && !OldKeyState.INS); } + bool GetDeleteJustDown() { return !!(NewKeyState.DEL && !OldKeyState.DEL); } + bool GetHomeJustDown() { return !!(NewKeyState.HOME && !OldKeyState.HOME); } + bool GetEndJustDown() { return !!(NewKeyState.END && !OldKeyState.END); } + bool GetPageUpJustDown() { return !!(NewKeyState.PGUP && !OldKeyState.PGUP); } + bool GetPageDownJustDown() { return !!(NewKeyState.PGDN && !OldKeyState.PGDN); } + bool GetUpJustDown() { return !!(NewKeyState.UP && !OldKeyState.UP); } + bool GetDownJustDown() { return !!(NewKeyState.DOWN && !OldKeyState.DOWN); } + bool GetLeftJustDown() { return !!(NewKeyState.LEFT && !OldKeyState.LEFT); } + bool GetRightJustDown() { return !!(NewKeyState.RIGHT && !OldKeyState.RIGHT); } + bool GetScrollLockJustDown() { return !!(NewKeyState.SCROLLLOCK && !OldKeyState.SCROLLLOCK); } + bool GetPauseJustDown() { return !!(NewKeyState.PAUSE && !OldKeyState.PAUSE); } + bool GetNumLockJustDown() { return !!(NewKeyState.NUMLOCK && !OldKeyState.NUMLOCK); } + bool GetDivideJustDown() { return !!(NewKeyState.DIV && !OldKeyState.DIV); } + bool GetTimesJustDown() { return !!(NewKeyState.MUL && !OldKeyState.MUL); } + bool GetMinusJustDown() { return !!(NewKeyState.SUB && !OldKeyState.SUB); } + bool GetPlusJustDown() { return !!(NewKeyState.ADD && !OldKeyState.ADD); } + bool GetPadEnterJustDown() { return !!(NewKeyState.ENTER && !OldKeyState.ENTER); } // GetEnterJustDown + bool GetPadDelJustDown() { return !!(NewKeyState.DECIMAL && !OldKeyState.DECIMAL); } + bool GetPad1JustDown() { return !!(NewKeyState.NUM1 && !OldKeyState.NUM1); } + bool GetPad2JustDown() { return !!(NewKeyState.NUM2 && !OldKeyState.NUM2); } + bool GetPad3JustDown() { return !!(NewKeyState.NUM3 && !OldKeyState.NUM3); } + bool GetPad4JustDown() { return !!(NewKeyState.NUM4 && !OldKeyState.NUM4); } + bool GetPad5JustDown() { return !!(NewKeyState.NUM5 && !OldKeyState.NUM5); } + bool GetPad6JustDown() { return !!(NewKeyState.NUM6 && !OldKeyState.NUM6); } + bool GetPad7JustDown() { return !!(NewKeyState.NUM7 && !OldKeyState.NUM7); } + bool GetPad8JustDown() { return !!(NewKeyState.NUM8 && !OldKeyState.NUM8); } + bool GetPad9JustDown() { return !!(NewKeyState.NUM9 && !OldKeyState.NUM9); } + bool GetPad0JustDown() { return !!(NewKeyState.NUM0 && !OldKeyState.NUM0); } + bool GetBackspaceJustDown() { return !!(NewKeyState.BACKSP && !OldKeyState.BACKSP); } + bool GetTabJustDown() { return !!(NewKeyState.TAB && !OldKeyState.TAB); } + bool GetCapsLockJustDown() { return !!(NewKeyState.CAPSLOCK && !OldKeyState.CAPSLOCK); } + bool GetEnterJustDown() { return !!(NewKeyState.EXTENTER && !OldKeyState.EXTENTER); } + bool GetLeftShiftJustDown() { return !!(NewKeyState.LSHIFT && !OldKeyState.LSHIFT); } + bool GetShiftJustDown() { return !!(NewKeyState.SHIFT && !OldKeyState.SHIFT); } + bool GetRightShiftJustDown() { return !!(NewKeyState.RSHIFT && !OldKeyState.RSHIFT); } + bool GetLeftCtrlJustDown() { return !!(NewKeyState.LCTRL && !OldKeyState.LCTRL); } + bool GetRightCtrlJustDown() { return !!(NewKeyState.RCTRL && !OldKeyState.RCTRL); } + bool GetLeftAltJustDown() { return !!(NewKeyState.LALT && !OldKeyState.LALT); } + bool GetRightAltJustDown() { return !!(NewKeyState.RALT && !OldKeyState.RALT); } + bool GetLeftWinJustDown() { return !!(NewKeyState.LWIN && !OldKeyState.LWIN); } + bool GetRightWinJustDown() { return !!(NewKeyState.RWIN && !OldKeyState.RWIN); } + bool GetAppsJustDown() { return !!(NewKeyState.APPS && !OldKeyState.APPS); } + + // pad + + bool GetTriangleJustDown() { return !!(NewState.Triangle && !OldState.Triangle); } + bool GetCircleJustDown() { return !!(NewState.Circle && !OldState.Circle); } + bool GetCrossJustDown() { return !!(NewState.Cross && !OldState.Cross); } + bool GetSquareJustDown() { return !!(NewState.Square && !OldState.Square); } + bool GetDPadUpJustDown() { return !!(NewState.DPadUp && !OldState.DPadUp); } + bool GetDPadDownJustDown() { return !!(NewState.DPadDown && !OldState.DPadDown); } + bool GetDPadLeftJustDown() { return !!(NewState.DPadLeft && !OldState.DPadLeft); } + bool GetDPadRightJustDown() { return !!(NewState.DPadRight && !OldState.DPadRight); } + bool GetLeftShoulder1JustDown() { return !!(NewState.LeftShoulder1 && !OldState.LeftShoulder1); } + bool GetLeftShoulder2JustDown() { return !!(NewState.LeftShoulder2 && !OldState.LeftShoulder2); } + bool GetRightShoulder1JustDown() { return !!(NewState.RightShoulder1 && !OldState.RightShoulder1); } + bool GetRightShoulder2JustDown() { return !!(NewState.RightShoulder2 && !OldState.RightShoulder2); } + + int32 GetLeftShoulder1(void) { return NewState.LeftShoulder1; } + int32 GetLeftShoulder2(void) { return NewState.LeftShoulder2; } + int32 GetRightShoulder1(void) { return NewState.RightShoulder1; } + int32 GetRightShoulder2(void) { return NewState.RightShoulder2; } +}; +VALIDATE_SIZE(CPad, 0xFC); + +#define IsButtonJustDown(pad, btn) \ + (!(pad)->OldState.btn && (pad)->NewState.btn) + +void LittleTest(void); diff --git a/src/core/Placeable.cpp b/src/core/Placeable.cpp new file mode 100644 index 00000000..b4b2a37b --- /dev/null +++ b/src/core/Placeable.cpp @@ -0,0 +1,72 @@ +#include "common.h" +#include "Placeable.h" +#include "patcher.h" + +CPlaceable::CPlaceable(void) +{ + m_matrix.SetScale(1.0f); +} + +CPlaceable::~CPlaceable(void) { } + +void +CPlaceable::SetHeading(float angle) +{ + CVector pos = GetPosition(); + m_matrix.SetRotateZ(angle); + GetPosition() += pos; +} + +bool +CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2) +{ + float tmp; + + if(x1 > x2){ + tmp = x1; + x1 = x2; + x2 = tmp; + } + if(y1 > y2){ + tmp = y1; + y1 = y2; + y2 = tmp; + } + + return x1 <= GetPosition().x && GetPosition().x <= x2 && + y1 <= GetPosition().y && GetPosition().y <= y2; +} + +bool +CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2) +{ + float tmp; + + if(x1 > x2){ + tmp = x1; + x1 = x2; + x2 = tmp; + } + if(y1 > y2){ + tmp = y1; + y1 = y2; + y2 = tmp; + } + if(z1 > z2){ + tmp = z1; + z1 = z2; + z2 = tmp; + } + + return x1 <= GetPosition().x && GetPosition().x <= x2 && + y1 <= GetPosition().y && GetPosition().y <= y2 && + z1 <= GetPosition().z && GetPosition().z <= z2; +} + +STARTPATCHES + InjectHook(0x49F9A0, &CPlaceable::ctor, PATCH_JUMP); + InjectHook(0x49F9E0, &CPlaceable::dtor, PATCH_JUMP); + InjectHook(0x49FA00, &CPlaceable::SetHeading, PATCH_JUMP); + InjectHook(0x49FA50, (bool (CPlaceable::*)(float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); + InjectHook(0x49FAF0, (bool (CPlaceable::*)(float, float, float, float, float, float))&CPlaceable::IsWithinArea, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Placeable.h b/src/core/Placeable.h new file mode 100644 index 00000000..868ca9e7 --- /dev/null +++ b/src/core/Placeable.h @@ -0,0 +1,26 @@ +#pragma once + +class CPlaceable +{ +public: + // disable allocation + static void *operator new(size_t) = delete; + + CMatrix m_matrix; + + CPlaceable(void); + virtual ~CPlaceable(void); + CVector &GetPosition(void) { return *m_matrix.GetPosition(); } + CVector &GetRight(void) { return *m_matrix.GetRight(); } + CVector &GetForward(void) { return *m_matrix.GetForward(); } + CVector &GetUp(void) { return *m_matrix.GetUp(); } + CMatrix &GetMatrix(void) { return m_matrix; } + void SetTransform(RwMatrix *m) { m_matrix = CMatrix(m, false); } + void SetHeading(float angle); + bool IsWithinArea(float x1, float y1, float x2, float y2); + bool IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2); + + CPlaceable *ctor(void) { return ::new (this) CPlaceable(); } + void dtor(void) { this->CPlaceable::~CPlaceable(); } +}; +static_assert(sizeof(CPlaceable) == 0x4C, "CPlaceable: error"); diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp new file mode 100644 index 00000000..59efe2ae --- /dev/null +++ b/src/core/PlayerInfo.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "PlayerInfo.h" + +WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); } \ No newline at end of file diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h new file mode 100644 index 00000000..e2b42fe7 --- /dev/null +++ b/src/core/PlayerInfo.h @@ -0,0 +1,72 @@ +#pragma once + +#include "Collision.h" + +enum eWastedBustedState +{ + WBSTATE_PLAYING, + WBSTATE_WASTED, + WBSTATE_BUSTED, + WBSTATE_FAILED_CRITICAL_MISSION, +}; + +class CVehicle; +class CPlayerPed; +class CCivilianPed; + +class CPlayerInfo +{ +public: + CPlayerPed *m_pPed; + CVehicle *m_pRemoteVehicle; + CColModel m_ColModel; + CVehicle *m_pVehicleEx; + char m_aPlayerName[70]; + int32 m_nMoney; + int32 m_nVisibleMoney; + int32 m_nCollectedPackages; + int32 m_nTotalPackages; + int32 field_188; + int32 m_nSwitchTaxiTime; + bool m_bSwitchTaxi; + int8 field_197; + int8 field_198; + int8 field_199; + int32 m_nNextSexFrequencyUpdateTime; + int32 m_nNextSexMoneyUpdateTime; + int32 m_nSexFrequency; + CCivilianPed *m_pHooker; + int8 m_WBState; // eWastedBustedState + int8 field_217; + int8 field_218; + int8 field_219; + int32 m_nWBTime; + bool m_bInRemoteMode; + int8 field_225; + int8 field_226; + int8 field_227; + int32 m_nTimeLostRemoteCar; + int32 m_nTimeLastHealthLoss; + int32 m_nTimeLastArmourLoss; + int32 field_240; + int32 m_nUpsideDownCounter; + int32 field_248; + int16 m_nTrafficMultiplier; + int8 field_254; + int8 field_255; + float m_fRoadDensity; + int32 m_nPreviousTimeRewardedForExplosion; + int32 m_nExplosionsSinceLastReward; + int32 field_268; + int32 field_272; + bool m_bInfiniteSprint; + bool m_bFastReload; + bool m_bGetOutOfJailFree; + bool m_bGetOutOfHospitalFree; + uint8 m_aSkinName[32]; + RwTexture *m_pSkinTexture; + + void MakePlayerSafe(bool); +}; + +static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/core/PlayerSkin.cpp b/src/core/PlayerSkin.cpp new file mode 100644 index 00000000..1c9ca2c6 --- /dev/null +++ b/src/core/PlayerSkin.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "PlayerSkin.h" + +WRAPPER void CPlayerSkin::BeginFrontEndSkinEdit() { EAXJMP(0x59BC70); } diff --git a/src/core/PlayerSkin.h b/src/core/PlayerSkin.h new file mode 100644 index 00000000..61e09cdf --- /dev/null +++ b/src/core/PlayerSkin.h @@ -0,0 +1,7 @@ +#pragma once + +class CPlayerSkin +{ +public: + static void BeginFrontEndSkinEdit(); +}; \ No newline at end of file diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp new file mode 100644 index 00000000..f7f93292 --- /dev/null +++ b/src/core/Pools.cpp @@ -0,0 +1,25 @@ +#include "common.h" +#include "Pools.h" + +CCPtrNodePool *&CPools::ms_pPtrNodePool = *(CCPtrNodePool**)0x943044; +CEntryInfoNodePool *&CPools::ms_pEntryInfoNodePool = *(CEntryInfoNodePool**)0x941448; +CPedPool *&CPools::ms_pPedPool = *(CPedPool**)0x8F2C60; +CVehiclePool *&CPools::ms_pVehiclePool = *(CVehiclePool**)0x9430DC; +CBuildingPool *&CPools::ms_pBuildingPool = *(CBuildingPool**)0x8F2C04; +CTreadablePool *&CPools::ms_pTreadablePool = *(CTreadablePool**)0x8F2568; +CObjectPool *&CPools::ms_pObjectPool = *(CObjectPool**)0x880E28; +CDummyPool *&CPools::ms_pDummyPool = *(CDummyPool**)0x8F2C18; + +void +CPools::Initialise(void) +{ + // TODO: unused right now + ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES); + ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS); + ms_pPedPool = new CPedPool(NUMPEDS); + ms_pVehiclePool = new CVehiclePool(NUMVEHICLES); + ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS); + ms_pTreadablePool = new CTreadablePool(NUMTREADABLES); + ms_pObjectPool = new CObjectPool(NUMOBJECTS); + ms_pDummyPool = new CDummyPool(NUMDUMMIES); +} diff --git a/src/core/Pools.h b/src/core/Pools.h new file mode 100644 index 00000000..3496064c --- /dev/null +++ b/src/core/Pools.h @@ -0,0 +1,43 @@ +#pragma once + +#include "templates.h" +#include "Lists.h" +#include "Treadable.h" +#include "Object.h" +#include "CutsceneHead.h" +#include "PlayerPed.h" +#include "Automobile.h" +#include "DummyPed.h" + +typedef CPool CCPtrNodePool; +typedef CPool CEntryInfoNodePool; +typedef CPool CPedPool; +typedef CPool CVehiclePool; +typedef CPool CBuildingPool; +typedef CPool CTreadablePool; +typedef CPool CObjectPool; +typedef CPool CDummyPool; + +class CPools +{ + static CCPtrNodePool *&ms_pPtrNodePool; + static CEntryInfoNodePool *&ms_pEntryInfoNodePool; + static CPedPool *&ms_pPedPool; + static CVehiclePool *&ms_pVehiclePool; + static CBuildingPool *&ms_pBuildingPool; + static CTreadablePool *&ms_pTreadablePool; + static CObjectPool *&ms_pObjectPool; + static CDummyPool *&ms_pDummyPool; + // ms_pAudioScriptObjectPool +public: + static CCPtrNodePool *GetPtrNodePool(void) { return ms_pPtrNodePool; } + static CEntryInfoNodePool *GetEntryInfoNodePool(void) { return ms_pEntryInfoNodePool; } + static CPedPool *GetPedPool(void) { return ms_pPedPool; } + static CVehiclePool *GetVehiclePool(void) { return ms_pVehiclePool; } + static CBuildingPool *GetBuildingPool(void) { return ms_pBuildingPool; } + static CTreadablePool *GetTreadablePool(void) { return ms_pTreadablePool; } + static CObjectPool *GetObjectPool(void) { return ms_pObjectPool; } + static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; } + + static void Initialise(void); +}; diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp new file mode 100644 index 00000000..a071b96b --- /dev/null +++ b/src/core/Radar.cpp @@ -0,0 +1,1117 @@ +#include "config.h" +#include "common.h" +#include "patcher.h" +#include "RwHelper.h" +#include "Radar.h" +#include "Camera.h" +#include "Hud.h" +#include "World.h" +#include "Frontend.h" +#include "General.h" +#include "Vehicle.h" +#include "Pools.h" +#include "Script.h" +#include "TxdStore.h" +#include "World.h" +#include "Streaming.h" + +float &CRadar::m_RadarRange = *(float*)0x8E281C; +CBlip *CRadar::ms_RadarTrace = (CBlip*)0x6ED5E0; + +CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8; +int *gRadarTxdIds = (int*)0x6299C0; + +CSprite2d *CRadar::AsukaSprite = (CSprite2d*)0x8F1A40; +CSprite2d *CRadar::BombSprite = (CSprite2d*)0x8F5FB4; +CSprite2d *CRadar::CatSprite = (CSprite2d*)0x885B24; +CSprite2d *CRadar::CentreSprite = (CSprite2d*)0x8F6268; +CSprite2d *CRadar::CopcarSprite = (CSprite2d*)0x8F1A2C; +CSprite2d *CRadar::DonSprite = (CSprite2d*)0x8F2BE0; +CSprite2d *CRadar::EightSprite = (CSprite2d*)0x8F2BCC; +CSprite2d *CRadar::ElSprite = (CSprite2d*)0x8F1B80; +CSprite2d *CRadar::IceSprite = (CSprite2d*)0x9415FC; +CSprite2d *CRadar::JoeySprite = (CSprite2d*)0x8F2C00; +CSprite2d *CRadar::KenjiSprite = (CSprite2d*)0x8F2C68; +CSprite2d *CRadar::LizSprite = (CSprite2d*)0x8F5830; +CSprite2d *CRadar::LuigiSprite = (CSprite2d*)0x8F1A3C; +CSprite2d *CRadar::NorthSprite = (CSprite2d*)0x8F6274; +CSprite2d *CRadar::RaySprite = (CSprite2d*)0x8E2A7C; +CSprite2d *CRadar::SalSprite = (CSprite2d*)0x8F29EC; +CSprite2d *CRadar::SaveSprite = (CSprite2d*)0x8F5F74; +CSprite2d *CRadar::SpraySprite = (CSprite2d*)0x94307C; +CSprite2d *CRadar::TonySprite = (CSprite2d*)0x885B58; +CSprite2d *CRadar::WeaponSprite = (CSprite2d*)0x941534; + +CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = { + nil, + AsukaSprite, + BombSprite, + CatSprite, + CentreSprite, + CopcarSprite, + DonSprite, + EightSprite, + ElSprite, + IceSprite, + JoeySprite, + KenjiSprite, + LizSprite, + LuigiSprite, + NorthSprite, + RaySprite, + SalSprite, + SaveSprite, + SpraySprite, + TonySprite, + WeaponSprite +}; + +#define RADAR_NUM_TILES (8) +#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES) +static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square"); + +#define RADAR_MIN_RANGE (120.0f) +#define RADAR_MAX_RANGE (350.0f) +#define RADAR_MIN_SPEED (0.3f) +#define RADAR_MAX_SPEED (0.9f) + +#if 0 +WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); } +#else +int CRadar::CalculateBlipAlpha(float dist) +{ + if (dist <= 1.0f) + return 255; + + if (dist <= 5.0f) + return (((1.0f - ((dist * 0.25f) - 0.25f)) * 255.0f) + (((dist * 0.25f) - 0.25f) * 128.0f)); + + return 128; +} +#endif + +#if 1 +WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); } +#else +void CRadar::ChangeBlipBrightness(int32 i, int32 bright) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::ChangeBlipColour(int32) { EAXJMP(0x4A5770); } +#else +void CRadar::ChangeBlipColour(int32 i) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::ChangeBlipDisplay(int32, int16) { EAXJMP(0x4A5810); } +#else +void CRadar::ChangeBlipDisplay(int32 i, int16 flag) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::ChangeBlipScale(int32, int16) { EAXJMP(0x4A57E0); } +#else +void CRadar::ChangeBlipScale(int32 i, int16 scale) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); } +#else +void CRadar::ClearBlip(int32 i) +{ + +} +#endif + +#if 0 +WRAPPER void CRadar::ClearBlipForEntity(int16, int32) { EAXJMP(0x4A56C0); } +#else +void CRadar::ClearBlipForEntity(int16 type, int32 id) +{ + for (int i = 0; i < NUMRADARBLIPS; i++) { + if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) { + SetRadarMarkerState(i, 0); + ms_RadarTrace[i].m_bInUse = 0; + ms_RadarTrace[i].m_eBlipType = 0; + ms_RadarTrace[i].m_eBlipDisplay = 0; + ms_RadarTrace[i].m_IconID = 0; + } + }; +} +#endif + +#if 0 +WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); } +#else +// Why not a proper clipping algorithm? +int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect) +{ + CVector2D corners[4] = { + { 1.0f, -1.0f }, // top right + { 1.0f, 1.0f }, // bottom right + { -1.0f, 1.0f }, // bottom left + { -1.0f, -1.0f }, // top left + }; + CVector2D tmp; + int i, j, n; + int laste, e, e1, e2;; + bool inside[4]; + + for (i = 0; i < 4; i++) + inside[i] = IsPointInsideRadar(rect[i]); + + laste = -1; + n = 0; + for (i = 0; i < 4; i++) + if (inside[i]) { + // point is inside, just add + poly[n++] = rect[i]; + } + else { + // point is outside but line to this point might be clipped + e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]); + if (e1 != -1) { + laste = e1; + n++; + } + // and line from this point might be clipped as well + e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]); + if (e2 != -1) { + if (e1 == -1) { + // if other line wasn't clipped, i.e. it was complete outside, + // we may have to insert another vertex if last clipped line + // was on a different edge + + // find the last intersection if we haven't seen it yet + if (laste == -1) + for (j = 3; j >= i; j--) { + // game uses an if here for j == 0 + e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]); + if (e != -1) { + laste = e; + break; + } + } + assert(laste != -1); + + // insert corners that were skipped + tmp = poly[n]; + for (e = laste; e != e2; e = (e + 1) % 4) + poly[n++] = corners[e]; + poly[n] = tmp; + } + n++; + } + } + + if (n == 0) { + // If no points, either the rectangle is completely outside or completely surrounds the radar + // no idea what's going on here... + float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x); + if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) { + m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x); + if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) { + poly[0] = corners[0]; + poly[1] = corners[1]; + poly[2] = corners[2]; + poly[3] = corners[3]; + n = 4; + } + } + } + + return n; +} +#endif + +bool CRadar::DisplayThisBlip(int32 counter) +{ + switch (ms_RadarTrace[counter].m_IconID) { + case RADAR_SPRITE_BOMB: + case RADAR_SPRITE_SPRAY: + case RADAR_SPRITE_WEAPON: + return true; + default: + return false; + } +} + +#if 1 +WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); } +#else +void CRadar::Draw3dMarkers() +{ + +} +#endif + + +#if 0 +WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); } +#else +void CRadar::DrawBlips() +{ + if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) { + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + + CVector2D out; + CVector2D in = CVector2D(0.0f, 0.0f); + TransformRadarPointToScreenSpace(out, in); + + float angle; + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1) + angle = PI + FindPlayerHeading(); + else + angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading()); + + DrawRotatingRadarSprite(CentreSprite, out.x, out.y, angle, 255); + + CVector2D vec2d; + vec2d.x = vec2DRadarOrigin.x; + vec2d.y = M_SQRT2 * m_RadarRange + vec2DRadarOrigin.y; + TransformRealWorldPointToRadarSpace(in, vec2d); + LimitRadarPoint(in); + TransformRadarPointToScreenSpace(out, in); + DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255); + + /* + DrawEntityBlip + */ + for (int i = 0; i < NUMRADARBLIPS; i++) { + if (ms_RadarTrace[i].m_bInUse) { + if (ms_RadarTrace[i].m_eBlipType <= BLIP_OBJECT) { + CEntity *e = nil; + switch (ms_RadarTrace[i].m_eBlipType) { + case BLIP_CAR: + e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); + break; + case BLIP_CHAR: + e = CPools::GetPedPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); + break; + case BLIP_OBJECT: + e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[i].m_nEntityHandle); + break; + }; + + if (e) { + if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) { + if (CTheScripts::DbgFlag) { + ShowRadarMarker(e->GetPosition(), GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius); + + ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f; + if (ms_RadarTrace[i].m_Radius >= 1.0f) + ms_RadarTrace[i].m_Radius = 5.0; + } + } + if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) { + vec2d = e->GetPosition(); + TransformRealWorldPointToRadarSpace(in, vec2d); + float dist = LimitRadarPoint(in); + int a = CalculateBlipAlpha(dist); + TransformRadarPointToScreenSpace(out, in); + + int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim); + + if (ms_RadarTrace[i].m_IconID) + DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a); + else + ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255); + } + } + } + + /* + DrawCoordBlip + */ + if (ms_RadarTrace[i].m_eBlipType >= BLIP_COORD) { + if (ms_RadarTrace[i].m_eBlipType != BLIP_CONTACT_POINT || ms_RadarTrace[i].m_eBlipType == BLIP_CONTACT_POINT && DisplayThisBlip(i) || !CTheScripts::IsPlayerOnAMission()) { + if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) { + if (CTheScripts::DbgFlag) { + ShowRadarMarker(ms_RadarTrace[i].m_vecPos, GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius); + ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f; + if (ms_RadarTrace[i].m_Radius >= 1.0f) + ms_RadarTrace[i].m_Radius = 5.0f; + } + } + + if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) { + TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[i].m_vec2DPos); + float dist = LimitRadarPoint(in); + int a = CalculateBlipAlpha(dist); + TransformRadarPointToScreenSpace(out, in); + + int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim); + + if (ms_RadarTrace[i].m_IconID) + DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a); + else + ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255); + } + } + } + }; + } + } +} +#endif + + +#if 0 +WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); } +#else +void CRadar::DrawMap() +{ + if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) { + if (FindPlayerVehicle()) { + float speed = FindPlayerSpeed().Magnitude(); + if (speed < RADAR_MIN_SPEED) + m_RadarRange = RADAR_MIN_RANGE; + else if (speed < RADAR_MAX_SPEED) + m_RadarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE; + else + m_RadarRange = RADAR_MAX_RANGE; + } + else + m_RadarRange = RADAR_MIN_RANGE; + + vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift()); + DrawRadarMap(); + } +} +#endif + +#if 0 +WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); } +#else +void CRadar::DrawRadarMap() +{ + // Game calculates an unused CRect here + + DrawRadarMask(); + + // top left ist (0, 0) + int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE); + int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE); + StreamRadarSections(x, y); + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); + RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE); + + DrawRadarSection(x - 1, y - 1); + DrawRadarSection(x, y - 1); + DrawRadarSection(x + 1, y - 1); + DrawRadarSection(x - 1, y); + DrawRadarSection(x, y); + DrawRadarSection(x + 1, y); + DrawRadarSection(x - 1, y + 1); + DrawRadarSection(x, y + 1); + DrawRadarSection(x + 1, y + 1); +} +#endif + +#if 0 +WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); } +#else +void CRadar::DrawRadarMask() +{ + CVector2D corners[4] = { + CVector2D(1.0f, -1.0f), + CVector2D(1.0f, 1.0f), + CVector2D(-1.0f, 1.0f), + CVector2D(-1.0, -1.0f) + }; + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS); + + CVector2D out[8]; + CVector2D in; + + // Draw the shape we want to mask out from the radar in four segments + for (int i = 0; i < 4; i++) { + // First point is always the corner itself + in.x = corners[i].x; + in.y = corners[i].y; + TransformRadarPointToScreenSpace(out[0], in); + + // Then generate a quarter of the circle + for (int j = 0; j < 7; j++) { + in.x = corners[i].x * cos(j * (PI / 2.0f / 6.0f)); + in.y = corners[i].y * sin(j * (PI / 2.0f / 6.0f)); + TransformRadarPointToScreenSpace(out[j + 1], in); + }; + + CSprite2d::SetMaskVertices(8, (float *)out); + RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8); + }; + + RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER); +} +#endif + +#if 0 +WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); } +#else +void CRadar::DrawRadarSection(int32 x, int32 y) +{ + int i; + RwTexDictionary *txd; + CVector2D worldPoly[8]; + CVector2D radarCorners[4]; + CVector2D radarPoly[8]; + CVector2D texCoords[8]; + CVector2D screenPoly[8]; + int numVertices; + RwTexture *texture = nil; + + GetTextureCorners(x, y, worldPoly); + ClipRadarTileCoords(x, y); + + assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])); + txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict; + if (txd) + texture = GetFirstTexture(txd); + if (texture == nil) + return; + + for (i = 0; i < 4; i++) + TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]); + + numVertices = ClipRadarPoly(radarPoly, radarCorners); + + // FIX: can return earlier here +// if(numVertices == 0) + if (numVertices < 3) + return; + + for (i = 0; i < numVertices; i++) { + TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]); + TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y); + TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]); + } + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture)); + CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255)); + // check done above now +// if(numVertices > 2) + RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices); +} +#endif + +#if 0 +WRAPPER void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha) { EAXJMP(0x4A5EF0); } +#else +void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha) +{ + RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha)); +} +#endif + +#if 0 +WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); } +#else +void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) +{ + CVector curPosn[4]; + CVector oldPosn[4]; + + curPosn[0].x = x - SCREEN_SCALE_X(5.6f); + curPosn[0].y = y + SCREEN_SCALE_Y(5.6f); + + curPosn[1].x = x + SCREEN_SCALE_X(5.6f); + curPosn[1].y = y + SCREEN_SCALE_Y(5.6f); + + curPosn[2].x = x - SCREEN_SCALE_X(5.6f); + curPosn[2].y = y - SCREEN_SCALE_Y(5.6f); + + curPosn[3].x = x + SCREEN_SCALE_X(5.6f); + curPosn[3].y = y - SCREEN_SCALE_Y(5.6f); + + for (uint32 i = 0; i < 4; i++) { + oldPosn[i] = curPosn[i]; + + curPosn[i].x = x + (oldPosn[i].x - x) * cosf(angle) + (oldPosn[i].y - y) * sinf(angle); + curPosn[i].y = y - (oldPosn[i].x - x) * sinf(angle) + (oldPosn[i].y - y) * cosf(angle); + } + + sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha)); +} +#endif + +#if 1 +WRAPPER int32 CRadar::GetActualBlipArray(int32) { EAXJMP(0x4A41C0); } +#else +int32 CRadar::GetActualBlipArray(int32 i) +{ + return int32(); +} +#endif + +#if 1 +WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); } +#else +int32 CRadar::GetNewUniqueBlipIndex(int32 i) +{ + return int32(); +} +#endif + +#if 0 +WRAPPER int32 CRadar::GetRadarTraceColour(int32 color, bool bright) { EAXJMP(0x4A5BB0); } +#else +int32 CRadar::GetRadarTraceColour(int32 color, bool bright) +{ + int32 c; + switch (color) { + case 0: + if (bright) + c = 0x712B49FF; + else + c = 0x7F0000FF; + break; + case 1: + if (bright) + c = 0x5FA06AFF; + else + c = 0x7F00FF; + break; + case 2: + if (bright) + c = 0x80A7F3FF; + else + c = 0x007FFF; + break; + case 3: + if (bright) + c = 0xE1E1E1FF; + else + c = 0x7F7F7FFF; + break; + case 4: + if (bright) + c = 0xFFFF00FF; + else + c = 0x7F7F00FF; + break; + case 5: + if (bright) + c = 0xFF00FFFF; + else + c = 0x7F007FFF; + break; + case 6: + if (bright) + c = 0xFFFFFF; + else + c = 0x7F7FFF; + break; + default: + c = color; + break; + }; + return c; +} +#endif + +#if 1 +WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); } +#else +void CRadar::Initialise() +{ + +} +#endif + +#if 0 +WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); } +#else +float CRadar::LimitRadarPoint(CVector2D &point) +{ + float dist, invdist; + + dist = point.Magnitude(); + if (dist > 1.0f) { + invdist = 1.0f / dist; + point.x *= invdist; + point.y *= invdist; + } + return dist; +} +#endif + +#if 1 +WRAPPER void CRadar::LoadAllRadarBlips(int32) { EAXJMP(0x4A6F30); } +#else +void CRadar::LoadAllRadarBlips(int32) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); } +#else +void CRadar::LoadTextures() +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x4A60E0); } +#else +void CRadar::RemoveRadarSections() +{ + +} +#endif + +#if 0 +WRAPPER void CRadar::RemoveMapSection(int32, int32) { EAXJMP(0x00); } +#else +void CRadar::RemoveMapSection(int32 x, int32 y) +{ + if (x >= 0 && x <= 7 && y >= 0 && y <= 7) + CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]); +} +#endif + +#if 0 +WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); } +#else +void CRadar::RequestMapSection(int32 x, int32 y) +{ + ClipRadarTileCoords(x, y); + CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY); +} +#endif + +#if 1 +WRAPPER void CRadar::SaveAllRadarBlips(int32) { EAXJMP(0x4A6E30); } +#else +void CRadar::SaveAllRadarBlips(int32) +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x4A5840); } +#else +void CRadar::SetBlipSprite(int32 i, int32 icon) +{ + +} +#endif + +#if 1 +WRAPPER int CRadar::SetCoordBlip(int32, CVector, int32) { EAXJMP(0x4A5590); } +#else +int CRadar::SetCoordBlip(int32 type, CVector pos, int32 flag) +{ + return 0; +} +#endif + +#if 1 +WRAPPER int CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag) { EAXJMP(0x4A5640); } +#else +int CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag) +{ + return 0; +} +#endif + +#if 0 +WRAPPER void CRadar::SetRadarMarkerState(int32, int32) { EAXJMP(0x4A5C60); } +#else +void CRadar::SetRadarMarkerState(int32 counter, int32 flag) +{ + CEntity *e; + switch (ms_RadarTrace[counter].m_eBlipType) { + case BLIP_CAR: + e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + case BLIP_CHAR: + e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + case BLIP_OBJECT: + e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle); + break; + default: + return; + } + + if (e) + e->bHasBlip = flag; +} +#endif + +#if 0 +WRAPPER void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) { EAXJMP(0x4A59C0); } +#else +void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) { + float f1 = radius * 0.5f; + float f2 = radius * 1.4f; + CVector p1, p2; + + p1 = pos + TheCamera.GetUp()*f1; + p2 = pos + TheCamera.GetUp()*f2; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); + + p1 = pos - TheCamera.GetUp()*f1; + p2 = pos - TheCamera.GetUp()*f2; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); + + p1 = pos + TheCamera.GetRight()*f1; + p2 = pos + TheCamera.GetRight()*f2; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); + + p1 = pos - TheCamera.GetRight()*f1; + p2 = pos - TheCamera.GetRight()*f2; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color); +} +#endif + +#if 0 +WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); } +#else +void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) +{ + CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha)); + CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha)); +} +#endif + +#if 1 +WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); } +#else +void CRadar::Shutdown() +{ + +} +#endif + +#if 1 +WRAPPER void CRadar::StreamRadarSections(const CVector &posn) { EAXJMP(0x4A6B60); } +#else +void CRadar::StreamRadarSections(const CVector &posn) +{ + +} +#endif + +#if 0 +WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); } +#else +void CRadar::StreamRadarSections(int32 x, int32 y) +{ + for (int i = 0; i < RADAR_NUM_TILES; ++i) { + for (int j = 0; j < RADAR_NUM_TILES; ++j) { + if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1)) + RequestMapSection(i, j); + else + RemoveMapSection(i, j); + }; + }; +} +#endif + +#if 0 +WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); } +#else +void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) +{ + out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X); + out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y)); + out.x /= RADAR_TILE_SIZE; + out.y /= RADAR_TILE_SIZE; +} +#endif + +#if 0 +WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); } +#else +void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) +{ + float s, c; + + s = -sin(TheCamera.GetForward().Heading()); + c = cos(TheCamera.GetForward().Heading()); + + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { + s = 0.0f; + c = 1.0f; + } + else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) { + CVector forward; + + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) { + forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward(); + forward.Normalise(); // a bit useless... + } + else + forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; + + s = -sin(forward.Heading()); + c = cos(forward.Heading()); + } + + out.x = s * in.y + c * in.x; + out.y = c * in.y - s * in.x; + + out = out * m_RadarRange + vec2DRadarOrigin; +} +#endif + +// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0) +void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in) +{ + // FIX? scale RADAR_LEFT here somehow + out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT; + out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT); +} + +#if 0 +WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); } +#else +void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) +{ + float s, c; + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { + s = 0.0f; + c = 1.0f; + } + else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) { + s = sin(TheCamera.GetForward().Heading()); + c = cos(TheCamera.GetForward().Heading()); + } + else { + CVector forward; + + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) { + forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward(); + forward.Normalise(); // a bit useless... + } + else + forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; + + s = sin(forward.Heading()); + c = cos(forward.Heading()); + } + + float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange); + float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_RadarRange); + + out.x = s * y + c * x; + out.y = c * y - s * x; +} +#endif + +#if 0 +WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); }; +#else +// Transform from section indices to world coordinates +void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) +{ + x = x - RADAR_NUM_TILES/2; + y = -(y - RADAR_NUM_TILES/2); + + // bottom left + out[0].x = RADAR_TILE_SIZE * (x); + out[0].y = RADAR_TILE_SIZE * (y - 1); + + // bottom right + out[1].x = RADAR_TILE_SIZE * (x + 1); + out[1].y = RADAR_TILE_SIZE * (y - 1); + + // top right + out[2].x = RADAR_TILE_SIZE * (x + 1); + out[2].y = RADAR_TILE_SIZE * (y); + + // top left + out[3].x = RADAR_TILE_SIZE * (x); + out[3].y = RADAR_TILE_SIZE * (y); +} +#endif + +#if 0 +WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); }; +#else +void CRadar::ClipRadarTileCoords(int32 &x, int32 &y) +{ + if (x < 0) + x = 0; + if (x > RADAR_NUM_TILES-1) + x = RADAR_NUM_TILES-1; + if (y < 0) + y = 0; + if (y > RADAR_NUM_TILES-1) + y = RADAR_NUM_TILES-1; +} +#endif + + +#if 0 +WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); } +#else +bool CRadar::IsPointInsideRadar(const CVector2D &point) +{ + if (point.x < -1.0f || point.x > 1.0f) return false; + if (point.y < -1.0f || point.y > 1.0f) return false; + return true; +} +#endif + +// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1 +#if 0 +WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); } +#else +int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2) +{ + float d1, d2; + float t; + float x, y; + float shortest = 1.0f; + int edge = -1; + + // clip against left edge, x = -1.0 + d1 = -1.0f - p1.x; + d2 = -1.0f - p2.x; + if (d1 * d2 < 0.0f) { + // they are on opposite sides, get point of intersection + t = d1 / (d1 - d2); + y = (p2.y - p1.y)*t + p1.y; + if (y >= -1.0f && y <= 1.0f && t <= shortest) { + out.x = -1.0f; + out.y = y; + edge = 3; + shortest = t; + } + } + + // clip against right edge, x = 1.0 + d1 = p1.x - 1.0f; + d2 = p2.x - 1.0f; + if (d1 * d2 < 0.0f) { + // they are on opposite sides, get point of intersection + t = d1 / (d1 - d2); + y = (p2.y - p1.y)*t + p1.y; + if (y >= -1.0f && y <= 1.0f && t <= shortest) { + out.x = 1.0f; + out.y = y; + edge = 1; + shortest = t; + } + } + + // clip against top edge, y = -1.0 + d1 = -1.0f - p1.y; + d2 = -1.0f - p2.y; + if (d1 * d2 < 0.0f) { + // they are on opposite sides, get point of intersection + t = d1 / (d1 - d2); + x = (p2.x - p1.x)*t + p1.x; + if (x >= -1.0f && x <= 1.0f && t <= shortest) { + out.y = -1.0f; + out.x = x; + edge = 0; + shortest = t; + } + } + + // clip against bottom edge, y = 1.0 + d1 = p1.y - 1.0f; + d2 = p2.y - 1.0f; + if (d1 * d2 < 0.0f) { + // they are on opposite sides, get point of intersection + t = d1 / (d1 - d2); + x = (p2.x - p1.x)*t + p1.x; + if (x >= -1.0f && x <= 1.0f && t <= shortest) { + out.y = 1.0f; + out.x = x; + edge = 2; + shortest = t; + } + } + + return edge; +} +#endif + +STARTPATCHES +// InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP); +// InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP); +// InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP); +// InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP); +// InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP); + InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP); + InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP); +// InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP); + InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP); + InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP); + InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP); + InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP); + InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP); + InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP); +// InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP); +// InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP); + InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP); +// InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP); +// InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP); +// InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP); +// InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP); +// InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP); +// InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP); + InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP); + InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP); + //InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP); + InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP); + InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP); + InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP); +// InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP); +// InjectHook(0x4A6100, CRadar::StreamRadarSections, PATCH_JUMP); + InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP); + InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP); + InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP); +// InjectHook(0x4A6B60, CRadar::StreamRadarSections, PATCH_JUMP); + InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP); +// InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP); +// InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP); + + InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP); + InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP); + InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Radar.h b/src/core/Radar.h new file mode 100644 index 00000000..e5396a50 --- /dev/null +++ b/src/core/Radar.h @@ -0,0 +1,146 @@ +#pragma once +#include "Sprite2d.h" + +enum eBlipType +{ + BLIP_NONE, + BLIP_CAR, + BLIP_CHAR, + BLIP_OBJECT, + BLIP_COORD, + BLIP_CONTACT_POINT +}; + +enum eBlipDisplay +{ + BLIP_DISPLAY_NEITHER = 0, + BLIP_DISPLAY_MARKER_ONLY = 1, + BLIP_DISPLAY_BLIP_ONLY = 2, + BLIP_DISPLAY_BOTH = 3, +}; + +enum eRadarSprite +{ + RADAR_SPRITE_NONE = 0, + RADAR_SPRITE_ASUKA = 1, + RADAR_SPRITE_BOMB = 2, + RADAR_SPRITE_CAT = 3, + RADAR_SPRITE_CENTRE = 4, + RADAR_SPRITE_COPCAR = 5, + RADAR_SPRITE_DON = 6, + RADAR_SPRITE_EIGHT = 7, + RADAR_SPRITE_EL = 8, + RADAR_SPRITE_ICE = 9, + RADAR_SPRITE_JOEY = 10, + RADAR_SPRITE_KENJI = 11, + RADAR_SPRITE_LIZ = 12, + RADAR_SPRITE_LUIGI = 13, + RADAR_SPRITE_NORTH = 14, + RADAR_SPRITE_RAY = 15, + RADAR_SPRITE_SAL = 16, + RADAR_SPRITE_SAVE = 17, + RADAR_SPRITE_SPRAY = 18, + RADAR_SPRITE_TONY = 19, + RADAR_SPRITE_WEAPON = 20, + RADAR_SPRITE_COUNT = 21, +}; + +struct CBlip +{ + int32 m_nColor; + int16 m_eBlipType; // eBlipType + int32 m_nEntityHandle; + CVector2D m_vec2DPos; + CVector m_vecPos; + int16 m_BlipIndex; + bool m_bDim; + bool m_bInUse; + float m_Radius; + int16 m_wScale; + int16 m_eBlipDisplay; // eBlipDisplay + int16 m_IconID; // eRadarSprite +}; +static_assert(sizeof(CBlip) == 0x30, "CBlip: error"); + +// Values for screen space +#define RADAR_LEFT (40.0f) +#define RADAR_BOTTOM (47.0f) +#define RADAR_WIDTH (94.0f) +#define RADAR_HEIGHT (76.0f) + +class CRadar +{ +public: + static float &m_RadarRange; + static CBlip *ms_RadarTrace; //[NUMRADARBLIPS] + static CSprite2d *AsukaSprite; + static CSprite2d *BombSprite; + static CSprite2d *CatSprite; + static CSprite2d *CentreSprite; + static CSprite2d *CopcarSprite; + static CSprite2d *DonSprite; + static CSprite2d *EightSprite; + static CSprite2d *ElSprite; + static CSprite2d *IceSprite; + static CSprite2d *JoeySprite; + static CSprite2d *KenjiSprite; + static CSprite2d *LizSprite; + static CSprite2d *LuigiSprite; + static CSprite2d *NorthSprite; + static CSprite2d *RaySprite; + static CSprite2d *SalSprite; + static CSprite2d *SaveSprite; + static CSprite2d *SpraySprite; + static CSprite2d *TonySprite; + static CSprite2d *WeaponSprite; + static CSprite2d *RadarSprites[21]; + +public: + static int CalculateBlipAlpha(float dist); + static void ChangeBlipBrightness(int32 i, int32 bright); + static void ChangeBlipColour(int32 i); + static void ChangeBlipDisplay(int32 i, int16 flag); + static void ChangeBlipScale(int32 i, int16 scale); + static void ClearBlip(int32 i); + static void ClearBlipForEntity(int16 type, int32 id); + static int ClipRadarPoly(CVector2D *out, const CVector2D *in); + static bool DisplayThisBlip(int32 i); + static void Draw3dMarkers(); + static void DrawBlips(); + static void DrawMap(); + static void DrawRadarMap(); + static void DrawRadarMask(); + static void DrawRadarSection(int32 x, int32 y); + static void DrawRadarSprite(int32 sprite, float x, float y, int32 alpha); + static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha); + static int32 GetActualBlipArray(int32 i); + static int32 GetNewUniqueBlipIndex(int32 i); + static int32 GetRadarTraceColour(int32 color, bool bright); + static void Initialise(); + static float LimitRadarPoint(CVector2D &point); + static void LoadAllRadarBlips(int32); + static void LoadTextures(); + static void RemoveRadarSections(); + static void RemoveMapSection(int32 x, int32 y); + static void RequestMapSection(int32 x, int32 y); + static void SaveAllRadarBlips(int32); + static void SetBlipSprite(int32 i, int32 icon); + static int SetCoordBlip(int32 type, CVector pos, int32 flag); + static int SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag); + static void SetRadarMarkerState(int32 i, int32 flag); + static void ShowRadarMarker(CVector pos, int16 color, float radius); + static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha); + static void Shutdown(); + static void StreamRadarSections(const CVector &posn); + static void StreamRadarSections(int32 x, int32 y); + static void TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y); + static void TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in); + static void TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in); + static void TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in); + + // no in CRadar in the game: + static void GetTextureCorners(int32 x, int32 y, CVector2D *out); + static void ClipRadarTileCoords(int32 &x, int32 &y); + static bool IsPointInsideRadar(const CVector2D &); + static int LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &); +}; diff --git a/src/core/References.cpp b/src/core/References.cpp new file mode 100644 index 00000000..e87f0fd5 --- /dev/null +++ b/src/core/References.cpp @@ -0,0 +1,65 @@ +#include "common.h" +#include "patcher.h" +#include "World.h" +#include "Vehicle.h" +#include "PlayerPed.h" +#include "Pools.h" +#include "References.h" + +CReference *CReferences::aRefs = (CReference*)0x70BBE0; //[NUMREFERENCES]; +CReference *&CReferences::pEmptyList = *(CReference**)0x8F1AF8; + +void +CReferences::Init(void) +{ + int i; + pEmptyList = &aRefs[0]; + for(i = 0; i < NUMREFERENCES; i++){ + aRefs[i].pentity = nil; + aRefs[i].next = &aRefs[i+1]; + } + aRefs[NUMREFERENCES-1].next = nil; +} + +void +CReferences::RemoveReferencesToPlayer(void) +{ + if(FindPlayerVehicle()) + FindPlayerVehicle()->ResolveReferences(); + if(FindPlayerPed()) + FindPlayerPed()->ResolveReferences(); +} + +void +CReferences::PruneAllReferencesInWorld(void) +{ + int i; + CEntity *e; + + i = CPools::GetPedPool()->GetSize(); + while(--i >= 0){ + e = CPools::GetPedPool()->GetSlot(i); + if(e) + e->PruneReferences(); + } + + i = CPools::GetVehiclePool()->GetSize(); + while(--i >= 0){ + e = CPools::GetVehiclePool()->GetSlot(i); + if(e) + e->PruneReferences(); + } + + i = CPools::GetObjectPool()->GetSize(); + while(--i >= 0){ + e = CPools::GetObjectPool()->GetSlot(i); + if(e) + e->PruneReferences(); + } +} + +STARTPATCHES + InjectHook(0x4A7350, CReferences::Init, PATCH_JUMP); + InjectHook(0x4A7570, CReferences::RemoveReferencesToPlayer, PATCH_JUMP); + InjectHook(0x4A75A0, CReferences::PruneAllReferencesInWorld, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/References.h b/src/core/References.h new file mode 100644 index 00000000..6476e243 --- /dev/null +++ b/src/core/References.h @@ -0,0 +1,20 @@ +#pragma once + +class CEntity; + +struct CReference +{ + CReference *next; + CEntity **pentity; +}; + +class CReferences +{ +public: + static CReference *aRefs; //[NUMREFERENCES]; + static CReference *&pEmptyList; + + static void Init(void); + static void RemoveReferencesToPlayer(void); + static void PruneAllReferencesInWorld(void); +}; diff --git a/src/core/RwClumpRead.cpp b/src/core/RwClumpRead.cpp new file mode 100644 index 00000000..c9f027e7 --- /dev/null +++ b/src/core/RwClumpRead.cpp @@ -0,0 +1,230 @@ +#include "common.h" +#include "patcher.h" + +struct rpGeometryList +{ + RpGeometry **geometries; + int32 numGeoms; +}; + +struct rpAtomicBinary +{ + RwInt32 frameIndex; + RwInt32 geomIndex; + RwInt32 flags; + RwInt32 unused; +}; + +static int32 numberGeometrys; +static int32 streamPosition; +static rpGeometryList gGeomList; +static rwFrameList gFrameList; +static RpClumpChunkInfo gClumpInfo; + +rpGeometryList* +GeometryListStreamRead1(RwStream *stream, rpGeometryList *geomlist) +{ + int i; + RwUInt32 size, version; + RwInt32 numGeoms; + + numberGeometrys = 0; + if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) + return nil; + assert(size == 4); + if(RwStreamRead(stream, &numGeoms, 4) != 4) + return nil; + + numberGeometrys = numGeoms/2; + geomlist->numGeoms = numGeoms; + if(geomlist->numGeoms > 0){ + geomlist->geometries = (RpGeometry**)RwMalloc(geomlist->numGeoms * sizeof(RpGeometry*)); + if(geomlist->geometries == nil) + return nil; + memset(geomlist->geometries, 0, geomlist->numGeoms * sizeof(RpGeometry*)); + }else + geomlist->geometries = nil; + + for(i = 0; i < numberGeometrys; i++){ + if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) + return nil; + geomlist->geometries[i] = RpGeometryStreamRead(stream); + if(geomlist->geometries[i] == nil) + return nil; + } + + return geomlist; +} + +rpGeometryList* +GeometryListStreamRead2(RwStream *stream, rpGeometryList *geomlist) +{ + int i; + RwUInt32 version; + + for(i = numberGeometrys; i < geomlist->numGeoms; i++){ + if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)) + return nil; + geomlist->geometries[i] = RpGeometryStreamRead(stream); + if(geomlist->geometries[i] == nil) + return nil; + } + + return geomlist; +} + +void +GeometryListDeinitialize(rpGeometryList *geomlist) +{ + int i; + + for(i = 0; i < geomlist->numGeoms; i++) + if(geomlist->geometries[i]) + RpGeometryDestroy(geomlist->geometries[i]); + + if(geomlist->numGeoms){ + RwFree(geomlist->geometries); + geomlist->numGeoms = 0; + } +} + +RpAtomic* +ClumpAtomicStreamRead(RwStream *stream, rwFrameList *frmList, rpGeometryList *geomList) +{ + RwUInt32 size, version; + rpAtomicBinary a; + RpAtomic *atomic; + + numberGeometrys = 0; + if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) + return nil; + assert(size <= sizeof(rpAtomicBinary)); + if(RwStreamRead(stream, &a, size) != size) + return nil; + + atomic = RpAtomicCreate(); + if(atomic == nil) + return nil; + + RpAtomicSetFlags(atomic, a.flags); + + if(frmList->numFrames){ + assert(a.frameIndex < frmList->numFrames); + RpAtomicSetFrame(atomic, frmList->frames[a.frameIndex]); + } + + if(geomList->numGeoms){ + assert(a.geomIndex < geomList->numGeoms); + RpAtomicSetGeometry(atomic, geomList->geometries[a.geomIndex], 0); + }else{ + RpGeometry *geom; + if(!RwStreamFindChunk(stream, rwID_GEOMETRY, nil, &version)){ + RpAtomicDestroy(atomic); + return nil; + } + geom = RpGeometryStreamRead(stream); + if(geom == nil){ + RpAtomicDestroy(atomic); + return nil; + } + RpAtomicSetGeometry(atomic, geom, 0); + RpGeometryDestroy(geom); + } + + return atomic; +} + +bool +RpClumpGtaStreamRead1(RwStream *stream) +{ + RwUInt32 size, version; + + if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) + return false; + if(version >= 0x33000){ + assert(size == 12); + if(RwStreamRead(stream, &gClumpInfo, 12) != 12) + return false; + }else{ + assert(size == 4); + if(RwStreamRead(stream, &gClumpInfo, 4) != 4) + return false; + } + + if(!RwStreamFindChunk(stream, rwID_FRAMELIST, nil, &version)) + return false; + if(_rwFrameListStreamRead(stream, &gFrameList) == nil) + return false; + + if(!RwStreamFindChunk(stream, rwID_GEOMETRYLIST, nil, &version)){ + rwFrameListDeinitialize(&gFrameList); + return false; + } + if(GeometryListStreamRead1(stream, &gGeomList) == nil){ + rwFrameListDeinitialize(&gFrameList); + return false; + } + streamPosition = stream->Type.memory.position; + return true; +} + +RpClump* +RpClumpGtaStreamRead2(RwStream *stream) +{ + int i; + RwUInt32 version; + RpAtomic *atomic; + RpClump *clump; + + clump = RpClumpCreate(); + if(clump == nil) + return nil; + + RwStreamSkip(stream, streamPosition - stream->Type.memory.position); + + if(GeometryListStreamRead2(stream, &gGeomList) == nil){ + GeometryListDeinitialize(&gGeomList); + rwFrameListDeinitialize(&gFrameList); + RpClumpDestroy(clump); + return nil; + } + + RpClumpSetFrame(clump, gFrameList.frames[0]); + + for(i = 0; i < gClumpInfo.numAtomics; i++){ + if(!RwStreamFindChunk(stream, rwID_ATOMIC, nil, &version)){ + GeometryListDeinitialize(&gGeomList); + rwFrameListDeinitialize(&gFrameList); + RpClumpDestroy(clump); + return nil; + } + + atomic = ClumpAtomicStreamRead(stream, &gFrameList, &gGeomList); + if(atomic == nil){ + GeometryListDeinitialize(&gGeomList); + rwFrameListDeinitialize(&gFrameList); + RpClumpDestroy(clump); + return nil; + } + + RpClumpAddAtomic(clump, atomic); + } + + GeometryListDeinitialize(&gGeomList); + rwFrameListDeinitialize(&gFrameList); + return clump; +} + +void +RpClumpGtaCancelStream(void) +{ + GeometryListDeinitialize(&gGeomList); + rwFrameListDeinitialize(&gFrameList); + gFrameList.numFrames = 0; +} + +STARTPATCHES + InjectHook(0x526060, RpClumpGtaStreamRead1, PATCH_JUMP); + InjectHook(0x526180, RpClumpGtaStreamRead2, PATCH_JUMP); + InjectHook(0x5262D0, RpClumpGtaCancelStream, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/RwHelper.cpp b/src/core/RwHelper.cpp new file mode 100644 index 00000000..8dade266 --- /dev/null +++ b/src/core/RwHelper.cpp @@ -0,0 +1,356 @@ +#define WITHD3D +#include "common.h" +#include "patcher.h" +#include "Timecycle.h" +#include "skeleton.h" + +void * +RwMallocAlign(RwUInt32 size, RwUInt32 align) +{ + void *mem = (void *)malloc(size + align); + + ASSERT(mem != nil); + + void *addr = (void *)((((RwUInt32)mem) + align) & ~(align - 1)); + + ASSERT(addr != nil); + + *(((void **)addr) - 1) = mem; + + return addr; +} + +void +RwFreeAlign(void *mem) +{ + ASSERT(mem != nil); + + void *addr = *(((void **)mem) - 1); + + ASSERT(addr != nil); + + free(addr); +} + +void +DefinedState(void) +{ + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSWRAP); + RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEGOURAUD); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEALPHAPRIMITIVEBUFFER, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEBORDERCOLOR, (void*)RWRGBALONG(0, 0, 0, 255)); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEFOGCOLOR, + (void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255)); + RwRenderStateSet(rwRENDERSTATEFOGTYPE, (void*)rwFOGTYPELINEAR); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE); + + // D3D stuff + RwD3D8SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); + RwD3D8SetRenderState(D3DRS_ALPHAREF, 2); +} + +RwFrame* +GetFirstFrameCallback(RwFrame *child, void *data) +{ + *(RwFrame**)data = child; + return nil; +} + +RwFrame* +GetFirstChild(RwFrame *frame) +{ + RwFrame *child; + + child = nil; + RwFrameForAllChildren(frame, GetFirstFrameCallback, &child); + return child; +} + +RwObject* +GetFirstObjectCallback(RwObject *object, void *data) +{ + *(RwObject**)data = object; + return nil; +} + +RwObject* +GetFirstObject(RwFrame *frame) +{ + RwObject *obj; + + obj = nil; + RwFrameForAllObjects(frame, GetFirstObjectCallback, &obj); + return obj; +} + +RpAtomic* +GetFirstAtomicCallback(RpAtomic *atm, void *data) +{ + *(RpAtomic**)data = atm; + return nil; +} + +RpAtomic* +GetFirstAtomic(RpClump *clump) +{ + RpAtomic *atm; + + atm = nil; + RpClumpForAllAtomics(clump, GetFirstAtomicCallback, &atm); + return atm; +} + +RwTexture* +GetFirstTextureCallback(RwTexture *tex, void *data) +{ + *(RwTexture**)data = tex; + return nil; +} + +RwTexture* +GetFirstTexture(RwTexDictionary *txd) +{ + RwTexture *tex; + + tex = nil; + RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex); + return tex; +} + +void +CameraSize(RwCamera * camera, RwRect * rect, + RwReal viewWindow, RwReal aspectRatio) +{ + if (camera) + { + RwVideoMode videoMode; + RwRect r; + RwRect origSize = { 0, 0, 0, 0 }; // FIX just to make the compier happy + RwV2d vw; + + RwEngineGetVideoModeInfo(&videoMode, + RwEngineGetCurrentVideoMode()); + + origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera)); + origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera)); + + if (!rect) + { + if (videoMode.flags & rwVIDEOMODEEXCLUSIVE) + { + /* For full screen applications, resizing the camera just doesn't + * make sense, use the video mode size. + */ + + r.x = r.y = 0; + r.w = videoMode.width; + r.h = videoMode.height; + rect = &r; + } + else + { + /* + rect not specified - reuse current values + */ + r.w = RwRasterGetWidth(RwCameraGetRaster(camera)); + r.h = RwRasterGetHeight(RwCameraGetRaster(camera)); + r.x = r.y = 0; + rect = &r; + } + } + + if (( origSize.w != rect->w ) && ( origSize.h != rect->h )) + { + RwRaster *raster; + RwRaster *zRaster; + + /* + * Destroy rasters... + */ + + raster = RwCameraGetRaster(camera); + if( raster ) + { + RwRasterDestroy(raster); + } + + zRaster = RwCameraGetZRaster(camera); + if( zRaster ) + { + RwRasterDestroy(zRaster); + } + + /* + * Create new rasters... + */ + + raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); + zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); + + if( raster && zRaster ) + { + RwCameraSetRaster(camera, raster); + RwCameraSetZRaster(camera, zRaster); + } + else + { + if( raster ) + { + RwRasterDestroy(raster); + } + + if( zRaster ) + { + RwRasterDestroy(zRaster); + } + + rect->x = origSize.x; + rect->y = origSize.y; + rect->w = origSize.w; + rect->h = origSize.h; + + /* + * Use default values... + */ + raster = + RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); + + zRaster = + RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); + + RwCameraSetRaster(camera, raster); + RwCameraSetZRaster(camera, zRaster); + } + } + + /* Figure out the view window */ + if (videoMode.flags & rwVIDEOMODEEXCLUSIVE) + { + /* derive ratio from aspect ratio */ + vw.x = viewWindow; + vw.y = viewWindow / aspectRatio; + } + else + { + /* derive from pixel ratios */ + if (rect->w > rect->h) + { + vw.x = viewWindow; + vw.y = (rect->h * viewWindow) / rect->w; + } + else + { + vw.x = (rect->w * viewWindow) / rect->h; + vw.y = viewWindow; + } + } + + RwCameraSetViewWindow(camera, &vw); + + RsGlobal.width = rect->w; + RsGlobal.height = rect->h; + } + + return; +} + +void +CameraDestroy(RwCamera *camera) +{ + RwRaster *raster, *tmpRaster; + RwFrame *frame; + + if (camera) + { + frame = RwCameraGetFrame(camera); + if (frame) + { + RwFrameDestroy(frame); + } + + raster = RwCameraGetRaster(camera); + if (raster) + { + tmpRaster = RwRasterGetParent(raster); + + RwRasterDestroy(raster); + + if ((tmpRaster != nil) && (tmpRaster != raster)) + { + RwRasterDestroy(tmpRaster); + } + } + + raster = RwCameraGetZRaster(camera); + if (raster) + { + tmpRaster = RwRasterGetParent(raster); + + RwRasterDestroy(raster); + + if ((tmpRaster != nil) && (tmpRaster != raster)) + { + RwRasterDestroy(tmpRaster); + } + } + + RwCameraDestroy(camera); + } + + return; +} + +RwCamera * +CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) +{ + RwCamera *camera; + + camera = RwCameraCreate(); + + if (camera) + { + RwCameraSetFrame(camera, RwFrameCreate()); + RwCameraSetRaster(camera, + RwRasterCreate(0, 0, 0, rwRASTERTYPECAMERA)); + + if (zBuffer) + { + RwCameraSetZRaster(camera, + RwRasterCreate(0, 0, 0, + rwRASTERTYPEZBUFFER)); + } + + /* now check that everything is valid */ + if (RwCameraGetFrame(camera) && + RwCameraGetRaster(camera) && + RwRasterGetParent(RwCameraGetRaster(camera)) && + (!zBuffer || (RwCameraGetZRaster(camera) && + RwRasterGetParent(RwCameraGetZRaster + (camera))))) + { + /* everything OK */ + return (camera); + } + } + + /* if we're here then an error must have occurred so clean up */ + + CameraDestroy(camera); + return (nil); +} + +STARTPATCHES + //InjectHook(0x526450, GetFirstObjectCallback, PATCH_JUMP); + InjectHook(0x526460, GetFirstObject, PATCH_JUMP); + InjectHook(0x527170, CameraSize, PATCH_JUMP); + InjectHook(0x527340, CameraDestroy, PATCH_JUMP); + InjectHook(0x5273B0, CameraCreate, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/RwHelper.h b/src/core/RwHelper.h new file mode 100644 index 00000000..ef20467d --- /dev/null +++ b/src/core/RwHelper.h @@ -0,0 +1,27 @@ +#pragma once + +void *RwMallocAlign(RwUInt32 size, RwUInt32 align); +void RwFreeAlign(void *mem); + +void DefinedState(void); +RwFrame *GetFirstChild(RwFrame *frame); +RwObject *GetFirstObject(RwFrame *frame); +RpAtomic *GetFirstAtomic(RpClump *clump); +RwTexture *GetFirstTexture(RwTexDictionary *txd); + +RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream); +RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream); +RwTexDictionary *RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict); + +bool RpClumpGtaStreamRead1(RwStream *stream); +RpClump *RpClumpGtaStreamRead2(RwStream *stream); +void RpClumpGtaCancelStream(void); + +void CameraSize(RwCamera *camera, + RwRect *rect, + RwReal viewWindow, + RwReal aspectRatio); +void CameraDestroy(RwCamera *camera); +RwCamera *CameraCreate(RwInt32 width, + RwInt32 height, + RwBool zBuffer); diff --git a/src/core/RwMatFX.cpp b/src/core/RwMatFX.cpp new file mode 100644 index 00000000..5fd00c54 --- /dev/null +++ b/src/core/RwMatFX.cpp @@ -0,0 +1,212 @@ +#define WITHD3D +#include "common.h" +#include "patcher.h" + +struct MatFXNothing { int pad[5]; int effect; }; + +struct MatFXBump +{ + RwFrame *bumpFrame; + RwTexture *bumpedTex; + RwTexture *bumpTex; + float negBumpCoefficient; + int pad; + int effect; +}; + +struct MatFXEnv +{ + RwFrame *envFrame; + RwTexture *envTex; + float envCoeff; + int envFBalpha; + int pad; + int effect; +}; + +struct MatFXDual +{ + RwTexture *dualTex; + RwInt32 srcBlend; + RwInt32 dstBlend; +}; + + +struct MatFX +{ + union { + MatFXNothing n; + MatFXBump b; + MatFXEnv e; + MatFXDual d; + } fx[2]; + int effects; +}; + +int &MatFXMaterialDataOffset = *(int*)0x66188C; +int &MatFXAtomicDataOffset = *(int*)0x66189C; + +#ifdef PS2_MATFX + +void +_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture) +{ + if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) + RwD3D8SetTexture(texture, 0); + else + RwD3D8SetTexture(nil, 0); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); + RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0); + RwD3D8SetPixelShader(0); + RwD3D8SetVertexShader(inst->vertexShader); + RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); + + if(inst->indexBuffer){ + RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + }else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); +} + +// map [-1; -1] -> [0; 1], flip V +static RwMatrix scalenormal = { + { 0.5f, 0.0f, 0.0f }, 0, + { 0.0f, -0.5f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.5f, 0.5f, 0.0f }, 0, + +}; + +// flipped U for PS2 +static RwMatrix scalenormal_flipU = { + { -0.5f, 0.0f, 0.0f }, 0, + { 0.0f, -0.5f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.5f, 0.5f, 0.0f }, 0, + +}; + +void +ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame) +{ + RwD3D8SetTexture(tex, n); + RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2); + RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL); + if(frame){ + RwMatrix *envframemat = RwMatrixCreate(); + RwMatrix *tmpmat = RwMatrixCreate(); + RwMatrix *envmat = RwMatrixCreate(); + + RwMatrixInvert(envframemat, RwFrameGetLTM(frame)); + // PS2 + // can this be simplified? + *tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera))); + RwV3dNegate(&tmpmat->right, &tmpmat->right); + tmpmat->flags = 0; + tmpmat->pos.x = 0.0f; + tmpmat->pos.y = 0.0f; + tmpmat->pos.z = 0.0f; + RwMatrixMultiply(envmat, tmpmat, envframemat); + *tmpmat = *envmat; + // important because envframemat can have a translation that we don't like + tmpmat->pos.x = 0.0f; + tmpmat->pos.y = 0.0f; + tmpmat->pos.z = 0.0f; + // for some reason we flip in U as well + RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU); + + RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat); + + RwMatrixDestroy(envmat); + RwMatrixDestroy(tmpmat); + RwMatrixDestroy(envframemat); + }else + RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal); +} + +void +_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap) +{ + MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset); + MatFXEnv *env = &matfx->fx[sel].e; + + uint8 intens = (uint8)(env->envCoeff*255.0f); + + if(intens == 0 || envMap == nil){ + if(sel == 0) + _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture); + return; + } + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); + if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) + RwD3D8SetTexture(texture, 0); + else + RwD3D8SetTexture(nil, 0); + RwD3D8SetVertexShader(inst->vertexShader); + RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); + RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); + if(inst->indexBuffer) + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + + // Effect pass + + ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwUInt32 src, dst, lighting, zwrite, fog, fogcol; + RwRenderStateGet(rwRENDERSTATESRCBLEND, &src); + RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst); + + // This is of course not using framebuffer alpha, + // but if the diffuse texture had no alpha, the result should actually be rather the same + if(env->envFBalpha) + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + else + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting); + RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite); + RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog); + RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + if(fog){ + RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol); + RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0); + } + + D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens); + RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor); + RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT); + RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR); + // alpha unused + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT); + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR); + + if(inst->indexBuffer) + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + + // Reset states + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst); + RwD3D8SetRenderState(D3DRS_LIGHTING, lighting); + RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite); + if(fog) + RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol); + RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); + RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); +} + +STARTPATCHES + InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP); +ENDPATCHES + +#endif diff --git a/src/core/RwTexRead.cpp b/src/core/RwTexRead.cpp new file mode 100644 index 00000000..a1a7050a --- /dev/null +++ b/src/core/RwTexRead.cpp @@ -0,0 +1,126 @@ +#include "common.h" +#include "patcher.h" + +RwTexture* +RwTextureGtaStreamRead(RwStream *stream) +{ + RwUInt32 size, version; + RwTexture *tex; + + if(!RwStreamFindChunk(stream, rwID_TEXTURENATIVE, &size, &version)) + return nil; + + // TODO: unused timing + + if(!RWSRCGLOBAL(stdFunc[rwSTANDARDNATIVETEXTUREREAD](stream, &tex, size))) + return nil; + + return tex; +} + +RwTexture* +destroyTexture(RwTexture *texture, void *data) +{ + RwTextureDestroy(texture); + return texture; +} + +RwTexDictionary* +RwTexDictionaryGtaStreamRead(RwStream *stream) +{ + RwUInt32 size, version; + RwInt32 numTextures; + RwTexDictionary *texDict; + RwTexture *tex; + + if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) + return nil; + assert(size == 4); + if(RwStreamRead(stream, &numTextures, size) != size) + return nil; + + texDict = RwTexDictionaryCreate(); + if(texDict == nil) + return nil; + + while(numTextures--){ + tex = RwTextureGtaStreamRead(stream); + if(tex == nil){ + RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); + RwTexDictionaryDestroy(texDict); + return nil; + } + RwTexDictionaryAddTexture(texDict, tex); + } + + return texDict; +} + +static int32 numberTextures = -1; +static int32 streamPosition; + +RwTexDictionary* +RwTexDictionaryGtaStreamRead1(RwStream *stream) +{ + RwUInt32 size, version; + RwInt32 numTextures; + RwTexDictionary *texDict; + RwTexture *tex; + + numberTextures = 0; + if(!RwStreamFindChunk(stream, rwID_STRUCT, &size, &version)) + return nil; + assert(size == 4); + if(RwStreamRead(stream, &numTextures, size) != size) + return nil; + + texDict = RwTexDictionaryCreate(); + if(texDict == nil) + return nil; + + numberTextures = numTextures/2; + + while(numTextures > numberTextures){ + numTextures--; + + tex = RwTextureGtaStreamRead(stream); + if(tex == nil){ + RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); + RwTexDictionaryDestroy(texDict); + return nil; + } + RwTexDictionaryAddTexture(texDict, tex); + } + + numberTextures = numTextures; + streamPosition = stream->Type.memory.position; + + return texDict; +} + +RwTexDictionary* +RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict) +{ + RwTexture *tex; + + RwStreamSkip(stream, streamPosition - stream->Type.memory.position); + + while(numberTextures--){ + tex = RwTextureGtaStreamRead(stream); + if(tex == nil){ + RwTexDictionaryForAllTextures(texDict, destroyTexture, nil); + RwTexDictionaryDestroy(texDict); + return nil; + } + RwTexDictionaryAddTexture(texDict, tex); + } + + return texDict; +} + +STARTPATCHES + InjectHook(0x592380, RwTextureGtaStreamRead, PATCH_JUMP); + InjectHook(0x5924A0, RwTexDictionaryGtaStreamRead, PATCH_JUMP); + InjectHook(0x592550, RwTexDictionaryGtaStreamRead1, PATCH_JUMP); + InjectHook(0x592650, RwTexDictionaryGtaStreamRead2, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp new file mode 100644 index 00000000..3c5b55e4 --- /dev/null +++ b/src/core/Stats.cpp @@ -0,0 +1,6 @@ +#include "common.h" +#include "Stats.h" + +int32& CStats::DaysPassed = *(int32*)0x8F2BB8; +int32& CStats::HeadShots = *(int32*)0x8F647C; +bool& CStats::CommercialPassed = *(bool*)0x8F4334; \ No newline at end of file diff --git a/src/core/Stats.h b/src/core/Stats.h new file mode 100644 index 00000000..39b0e184 --- /dev/null +++ b/src/core/Stats.h @@ -0,0 +1,9 @@ +#pragma once + +class CStats +{ +public: + static int32& DaysPassed; + static int32& HeadShots; + static bool& CommercialPassed; +}; \ No newline at end of file diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp new file mode 100644 index 00000000..f8ab19d4 --- /dev/null +++ b/src/core/Streaming.cpp @@ -0,0 +1,2509 @@ +#include "common.h" +#include "patcher.h" +#include "Pad.h" +#include "Hud.h" +#include "Text.h" +#include "Clock.h" +#include "Renderer.h" +#include "ModelInfo.h" +#include "TxdStore.h" +#include "ModelIndices.h" +#include "Pools.h" +#include "Directory.h" +#include "RwHelper.h" +#include "World.h" +#include "Entity.h" +#include "FileMgr.h" +#include "FileLoader.h" +#include "Zones.h" +#include "ZoneCull.h" +#include "Radar.h" +#include "Camera.h" +#include "Record.h" +#include "CarCtrl.h" +#include "Population.h" +#include "Gangs.h" +#include "CutsceneMgr.h" +#include "CdStream.h" +#include "Streaming.h" + +bool &CStreaming::ms_disableStreaming = *(bool*)0x95CD6E; +bool &CStreaming::ms_bLoadingBigModel = *(bool*)0x95CDB0; +int32 &CStreaming::ms_numModelsRequested = *(int32*)0x8E2C10; +CStreamingInfo *CStreaming::ms_aInfoForModel = (CStreamingInfo*)0x6C7088; +CStreamingInfo &CStreaming::ms_startLoadedList = *(CStreamingInfo*)0x942F60; +CStreamingInfo &CStreaming::ms_endLoadedList = *(CStreamingInfo*)0x8F1AC0; +CStreamingInfo &CStreaming::ms_startRequestedList = *(CStreamingInfo*)0x8F1B3C; +CStreamingInfo &CStreaming::ms_endRequestedList = *(CStreamingInfo*)0x940738; +int32 &CStreaming::ms_oldSectorX = *(int32*)0x8F2C84; +int32 &CStreaming::ms_oldSectorY = *(int32*)0x8F2C88; +int32 &CStreaming::ms_streamingBufferSize = *(int32*)0x942FB0; +int8 **CStreaming::ms_pStreamingBuffer = (int8**)0x87F818; +int32 &CStreaming::ms_memoryUsed = *(int32*)0x940568; +CStreamingChannel *CStreaming::ms_channel = (CStreamingChannel*)0x727EE0; +int32 &CStreaming::ms_channelError = *(int32*)0x880DB8; +int32 &CStreaming::ms_numVehiclesLoaded = *(int32*)0x8F2C80; +int32 *CStreaming::ms_vehiclesLoaded = (int32*)0x773560; +int32 &CStreaming::ms_lastVehicleDeleted = *(int32*)0x95CBF8; +CDirectory *&CStreaming::ms_pExtraObjectsDir = *(CDirectory**)0x95CB90; +int32 &CStreaming::ms_numPriorityRequests = *(int32*)0x8F31C4; +bool &CStreaming::ms_hasLoadedLODs = *(bool*)0x95CD47; +int32 &CStreaming::ms_currentPedGrp = *(int32*)0x8F2BBC; +int32 CStreaming::ms_currentPedLoading; +int32 CStreaming::ms_lastCullZone; +uint16 &CStreaming::ms_loadedGangs = *(uint16*)0x95CC60; +uint16 &CStreaming::ms_loadedGangCars = *(uint16*)0x95CC2E; +int32 *CStreaming::ms_imageOffsets = (int32*)0x6E60A0; +int32 &CStreaming::ms_lastImageRead = *(int32*)0x880E2C; +int32 &CStreaming::ms_imageSize = *(int32*)0x8F1A34; +uint32 &CStreaming::ms_memoryAvailable = *(uint32*)0x880F8C; + +int32 &desiredNumVehiclesLoaded = *(int32*)0x5EC194; + +CEntity *&pIslandLODindustEntity = *(CEntity**)0x6212DC; +CEntity *&pIslandLODcomIndEntity = *(CEntity**)0x6212E0; +CEntity *&pIslandLODcomSubEntity = *(CEntity**)0x6212E4; +CEntity *&pIslandLODsubIndEntity = *(CEntity**)0x6212E8; +CEntity *&pIslandLODsubComEntity = *(CEntity**)0x6212EC; +int32 &islandLODindust = *(int32*)0x6212C8; +int32 &islandLODcomInd = *(int32*)0x6212CC; +int32 &islandLODcomSub = *(int32*)0x6212D0; +int32 &islandLODsubInd = *(int32*)0x6212D4; +int32 &islandLODsubCom = *(int32*)0x6212D8; + +bool +CStreamingInfo::GetCdPosnAndSize(uint32 &posn, uint32 &size) +{ + if(m_size == 0) + return false; + posn = m_position; + size = m_size; + return true; +} + +void +CStreamingInfo::SetCdPosnAndSize(uint32 posn, uint32 size) +{ + m_position = posn; + m_size = size; +} + +void +CStreamingInfo::AddToList(CStreamingInfo *link) +{ + // Insert this after link + m_next = link->m_next; + m_prev = link; + link->m_next = this; + m_next->m_prev = this; +} + +void +CStreamingInfo::RemoveFromList(void) +{ + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + m_next = nil; + m_prev = nil; +} + +void +CStreaming::Init(void) +{ + int i; + + for(i = 0; i < NUMSTREAMINFO; i++){ + ms_aInfoForModel[i].m_loadState = STREAMSTATE_NOTLOADED; + ms_aInfoForModel[i].m_next = nil; + ms_aInfoForModel[i].m_prev = nil; + ms_aInfoForModel[i].m_nextID = -1; + ms_aInfoForModel[i].m_size = 0; + ms_aInfoForModel[i].m_position = 0; + } + + ms_channelError = -1; + + // init lists + + ms_startLoadedList.m_next = &ms_endLoadedList; + ms_startLoadedList.m_prev = nil; + ms_endLoadedList.m_prev = &ms_startLoadedList; + ms_endLoadedList.m_next = nil; + + ms_startRequestedList.m_next = &ms_endRequestedList; + ms_startRequestedList.m_prev = nil; + ms_endRequestedList.m_prev = &ms_startRequestedList; + ms_endRequestedList.m_next = nil; + + // init misc + + ms_oldSectorX = 0; + ms_oldSectorY = 0; + ms_streamingBufferSize = 0; + ms_disableStreaming = false; + ms_memoryUsed = 0; + ms_bLoadingBigModel = false; + + // init channels + + ms_channel[0].state = CHANNELSTATE_IDLE; + ms_channel[1].state = CHANNELSTATE_IDLE; + for(i = 0; i < 4; i++){ + ms_channel[0].streamIds[i] = -1; + ms_channel[0].offsets[i] = -1; + ms_channel[1].streamIds[i] = -1; + ms_channel[1].offsets[i] = -1; + } + + // init stream info, mark things that are already loaded + + for(i = 0; i < MODELINFOSIZE; i++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); + if(mi && mi->GetRwObject()){ + ms_aInfoForModel[i].m_loadState = STREAMSTATE_LOADED; + ms_aInfoForModel[i].m_flags = STREAMFLAGS_DONT_REMOVE; + if(mi->IsSimple()) + ((CSimpleModelInfo*)mi)->m_alpha = 255; + } + } + + for(i = 0; i < TXDSTORESIZE; i++) + if(CTxdStore::GetSlot(i) && CTxdStore::GetSlot(i)->texDict) + ms_aInfoForModel[i + STREAM_OFFSET_TXD].m_loadState = STREAMSTATE_LOADED; + + + for(i = 0; i < MAXVEHICLESLOADED; i++) + ms_vehiclesLoaded[i] = -1; + ms_numVehiclesLoaded = 0; + + ms_pExtraObjectsDir = new CDirectory(EXTRADIRSIZE); + ms_numPriorityRequests = 0; + ms_hasLoadedLODs = true; + ms_currentPedGrp = -1; + ms_lastCullZone = -1; // unused because RemoveModelsNotVisibleFromCullzone is gone + ms_loadedGangs = 0; + ms_currentPedLoading = 8; // unused, whatever it is + + LoadCdDirectory(); + + // allocate streaming buffers + if(ms_streamingBufferSize & 1) ms_streamingBufferSize++; + ms_pStreamingBuffer[0] = (int8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE); + ms_streamingBufferSize /= 2; + ms_pStreamingBuffer[1] = ms_pStreamingBuffer[0] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE; + debug("Streaming buffer size is %d sectors", ms_streamingBufferSize); + + // PC only, figure out how much memory we got +#ifdef GTA_PC +#define MB (1024*1024) + extern DWORD &_dwMemAvailPhys; + ms_memoryAvailable = (_dwMemAvailPhys - 10*MB)/2; + if(ms_memoryAvailable < 50*MB) + ms_memoryAvailable = 50*MB; + desiredNumVehiclesLoaded = (ms_memoryAvailable/MB - 50)/3 + 12; + if(desiredNumVehiclesLoaded > MAXVEHICLESLOADED) + desiredNumVehiclesLoaded = MAXVEHICLESLOADED; + debug("Memory allocated to Streaming is %dMB", ms_memoryAvailable/MB); +#undef MB +#endif + + // find island LODs + + pIslandLODindustEntity = nil; + pIslandLODcomIndEntity = nil; + pIslandLODcomSubEntity = nil; + pIslandLODsubIndEntity = nil; + pIslandLODsubComEntity = nil; + islandLODindust = -1; + islandLODcomInd = -1; + islandLODcomSub = -1; + islandLODsubInd = -1; + islandLODsubCom = -1; + CModelInfo::GetModelInfo("IslandLODInd", &islandLODindust); + CModelInfo::GetModelInfo("IslandLODcomIND", &islandLODcomInd); + CModelInfo::GetModelInfo("IslandLODcomSUB", &islandLODcomSub); + CModelInfo::GetModelInfo("IslandLODsubIND", &islandLODsubInd); + CModelInfo::GetModelInfo("IslandLODsubCOM", &islandLODsubCom); + + for(i = 0; i < CPools::GetBuildingPool()->GetSize(); i++){ + CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); + if(building == nil) + continue; + if(building->GetModelIndex() == islandLODindust) pIslandLODindustEntity = building; + if(building->GetModelIndex() == islandLODcomInd) pIslandLODcomIndEntity = building; + if(building->GetModelIndex() == islandLODcomSub) pIslandLODcomSubEntity = building; + if(building->GetModelIndex() == islandLODsubInd) pIslandLODsubIndEntity = building; + if(building->GetModelIndex() == islandLODsubCom) pIslandLODsubComEntity = building; + } +} + +void +CStreaming::Shutdown(void) +{ + RwFreeAlign(ms_pStreamingBuffer[0]); + ms_streamingBufferSize = 0; + if(ms_pExtraObjectsDir) + delete ms_pExtraObjectsDir; +} + +void +CStreaming::Update(void) +{ + CEntity *train; + CStreamingInfo *si, *prev; + bool requestedSubway = false; + + UpdateMemoryUsed(); + + if(ms_channelError != -1){ + RetryLoadFile(ms_channelError); + return; + } + + if(CTimer::GetIsPaused()) + return; + + train = FindPlayerTrain(); + if(train && train->GetPosition().z < 0.0f){ + RequestSubway(); + requestedSubway = true; + }else if(!ms_disableStreaming) + AddModelsToRequestList(TheCamera.GetPosition()); + + DeleteFarAwayRwObjects(TheCamera.GetPosition()); + + if(!ms_disableStreaming && + !CCutsceneMgr::IsRunning() && + !requestedSubway && + !CGame::playingIntro && + ms_numModelsRequested < 5 && + !CRenderer::m_loadingPriority){ + StreamVehiclesAndPeds(); + StreamZoneModels(FindPlayerCoors()); + } + + LoadRequestedModels(); + + for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ + prev = si->m_prev; + if((si->m_flags & (STREAMFLAGS_KEEP_IN_MEMORY|STREAMFLAGS_PRIORITY)) == 0) + RemoveModel(si - ms_aInfoForModel); + } +} + +void +CStreaming::LoadCdDirectory(void) +{ + char dirname[132]; + int i; + +#ifdef GTA_PC + ms_imageOffsets[0] = 0; + ms_imageOffsets[1] = -1; + ms_imageOffsets[2] = -1; + ms_imageOffsets[3] = -1; + ms_imageOffsets[4] = -1; + ms_imageOffsets[5] = -1; + ms_imageOffsets[6] = -1; + ms_imageOffsets[7] = -1; + ms_imageOffsets[8] = -1; + ms_imageOffsets[9] = -1; + ms_imageOffsets[10] = -1; + ms_imageOffsets[11] = -1; + ms_imageSize = GetGTA3ImgSize(); + // PS2 uses CFileMgr::GetCdFile on all IMG files to fill the array +#endif + + i = CdStreamGetNumImages(); + while(i-- >= 1){ + strcpy(dirname, CdStreamGetImageName(i)); + strncpy(strrchr(dirname, '.') + 1, "DIR", 3); + LoadCdDirectory(dirname, i); + } + + ms_lastImageRead = 0; + ms_imageSize /= CDSTREAM_SECTOR_SIZE; +} + +void +CStreaming::LoadCdDirectory(const char *dirname, int n) +{ + int fd, lastID, imgSelector; + int modelId, txdId; + uint32 posn, size; + CDirectory::DirectoryInfo direntry; + char *dot; + + lastID = -1; + fd = CFileMgr::OpenFile(dirname, "rb"); + assert(fd > 0); + + imgSelector = n<<24; + assert(sizeof(direntry) == 32); + while(CFileMgr::Read(fd, (char*)&direntry, sizeof(direntry))){ + dot = strchr(direntry.name, '.'); + if(dot) *dot = '\0'; + if(direntry.size > (uint32)ms_streamingBufferSize) + ms_streamingBufferSize = direntry.size; + + if(strcmp(dot+1, "DFF") == 0 || strcmp(dot+1, "dff") == 0){ + if(CModelInfo::GetModelInfo(direntry.name, &modelId)){ + if(ms_aInfoForModel[modelId].GetCdPosnAndSize(posn, size)){ + debug("%s appears more than once in %s\n", direntry.name, dirname); + lastID = -1; + }else{ + direntry.offset |= imgSelector; + ms_aInfoForModel[modelId].SetCdPosnAndSize(direntry.offset, direntry.size); + if(lastID != -1) + ms_aInfoForModel[lastID].m_nextID = modelId; + lastID = modelId; + } + }else{ + // BUG: doesn't remember which cdimage this was in + ms_pExtraObjectsDir->AddItem(direntry); + lastID = -1; + } + }else if(strcmp(dot+1, "TXD") == 0 || strcmp(dot+1, "txd") == 0){ + txdId = CTxdStore::FindTxdSlot(direntry.name); + if(txdId == -1) + txdId = CTxdStore::AddTxdSlot(direntry.name); + if(ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].GetCdPosnAndSize(posn, size)){ + debug("%s appears more than once in %s\n", direntry.name, dirname); + lastID = -1; + }else{ + direntry.offset |= imgSelector; + ms_aInfoForModel[txdId + STREAM_OFFSET_TXD].SetCdPosnAndSize(direntry.offset, direntry.size); + if(lastID != -1) + ms_aInfoForModel[lastID].m_nextID = txdId + STREAM_OFFSET_TXD; + lastID = txdId + STREAM_OFFSET_TXD; + } + }else + lastID = -1; + } + + CFileMgr::CloseFile(fd); +} + +bool +CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) +{ + RwMemory mem; + RwStream *stream; + int cdsize; + uint32 startTime, endTime, timeDiff; + CBaseModelInfo *mi; + bool success; + + startTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); + + cdsize = ms_aInfoForModel[streamId].GetCdSize(); + mem.start = (uint8*)buf; + mem.length = cdsize * CDSTREAM_SECTOR_SIZE; + stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); + + if(streamId < STREAM_OFFSET_TXD){ + // Model + mi = CModelInfo::GetModelInfo(streamId); + + // Txd has to be loaded + if(CTxdStore::GetSlot(mi->GetTxdSlot())->texDict == nil){ + debug("failed to load %s because TXD %s is not in memory\n", mi->GetName(), CTxdStore::GetTxdName(mi->GetTxdSlot())); + RemoveModel(streamId); + RemoveTxd(mi->GetTxdSlot()); + ReRequestModel(streamId); + RwStreamClose(stream, &mem); + return false; + } + + // Set Txd to use + CTxdStore::AddRef(mi->GetTxdSlot()); + CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); + + if(mi->IsSimple()){ + success = CFileLoader::LoadAtomicFile(stream, streamId); + }else if(mi->m_type == MITYPE_VEHICLE){ + // load vehicles in two parts + CModelInfo::GetModelInfo(streamId)->AddRef(); + success = CFileLoader::StartLoadClumpFile(stream, streamId); + if(success) + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; + }else{ + success = CFileLoader::LoadClumpFile(stream, streamId); + } + UpdateMemoryUsed(); + + // Txd no longer needed unless we only read part of the file + if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED) + CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); + + if(!success){ + debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId)->GetName()); + RemoveModel(streamId); + ReRequestModel(streamId); + RwStreamClose(stream, &mem); + return false; + } + }else{ + // Txd + assert(streamId < NUMSTREAMINFO); + if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY) == 0 && + !IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)){ + RemoveModel(streamId); + RwStreamClose(stream, &mem); + return false; + } + + if(ms_bLoadingBigModel || cdsize > 200){ + success = CTxdStore::StartLoadTxd(streamId - STREAM_OFFSET_TXD, stream); + if(success) + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; + }else + success = CTxdStore::LoadTxd(streamId - STREAM_OFFSET_TXD, stream); + UpdateMemoryUsed(); + + if(!success){ + debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); + RemoveModel(streamId); + ReRequestModel(streamId); + RwStreamClose(stream, &mem); + return false; + } + } + + RwStreamClose(stream, &mem); + + // We shouldn't even end up here unless load was successful + if(!success){ + ReRequestModel(streamId); + if(streamId < STREAM_OFFSET_TXD) + debug("Failed to load %s.dff\n", mi->GetName()); + else + debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD)); + return false; + } + + if(streamId < STREAM_OFFSET_TXD){ + // Model + // Vehicles and Peds not in loaded list + if(mi->m_type != MITYPE_VEHICLE && mi->m_type != MITYPE_PED){ + CSimpleModelInfo *smi = (CSimpleModelInfo*)mi; + + // Set fading for some objects + if(mi->IsSimple() && !smi->m_isBigBuilding){ + if(ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOFADE) + smi->m_alpha = 255; + else + smi->m_alpha = 0; + } + + if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) + ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); + } + }else{ + // Txd + if((ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) + ms_aInfoForModel[streamId].AddToList(&ms_startLoadedList); + } + + // Mark objects as loaded + if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){ + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; + ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; + } + + endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); + timeDiff = endTime - startTime; + if(timeDiff > 5){ + if(streamId < STREAM_OFFSET_TXD) + debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); + else + debug("txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); + } + + return true; +} + + +bool +CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) +{ + RwMemory mem; + RwStream *stream; + uint32 startTime, endTime, timeDiff; + CBaseModelInfo *mi; + bool success; + + startTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); + + if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){ + if(streamId < STREAM_OFFSET_TXD) + CModelInfo::GetModelInfo(streamId)->RemoveRef(); + return false; + } + + mem.start = (uint8*)buf; + mem.length = ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; + stream = RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); + + if(streamId < STREAM_OFFSET_TXD){ + // Model + mi = CModelInfo::GetModelInfo(streamId); + CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); + success = CFileLoader::FinishLoadClumpFile(stream, streamId); + if(success) + success = AddToLoadedVehiclesList(streamId); + mi->RemoveRef(); + CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); + }else{ + // Txd + CTxdStore::AddRef(streamId - STREAM_OFFSET_TXD); + success = CTxdStore::FinishLoadTxd(streamId - STREAM_OFFSET_TXD, stream); + CTxdStore::RemoveRefWithoutDelete(streamId - STREAM_OFFSET_TXD); + } + + RwStreamClose(stream, &mem); + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; + ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; + + if(!success){ + RemoveModel(streamId); + ReRequestModel(streamId); + UpdateMemoryUsed(); + return false; + } + + UpdateMemoryUsed(); + + endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); + timeDiff = endTime - startTime; + if(timeDiff > 5){ + if(streamId < STREAM_OFFSET_TXD) + debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff); + else + debug("finish txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff); + } + + return true; +} + +void +CStreaming::RequestModel(int32 id, int32 flags) +{ + CSimpleModelInfo *mi; + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE){ + // updgrade to priority + if(flags & STREAMFLAGS_PRIORITY && !ms_aInfoForModel[id].IsPriority()){ + ms_numPriorityRequests++; + ms_aInfoForModel[id].m_flags |= STREAMFLAGS_PRIORITY; + } + }else if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_NOTLOADED){ + flags &= ~STREAMFLAGS_PRIORITY; + } + ms_aInfoForModel[id].m_flags |= flags; + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ + // Already loaded, only check changed flags + + if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOFADE && id < STREAM_OFFSET_TXD){ + mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); + if(mi->IsSimple()) + mi->m_alpha = 255; + } + + // reinsert into list + if(ms_aInfoForModel[id].m_next){ + ms_aInfoForModel[id].RemoveFromList(); + if((ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0) + ms_aInfoForModel[id].AddToList(&ms_startLoadedList); + } + }else if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED || + ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ // how can this be true again? + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED){ + if(id < STREAM_OFFSET_TXD) + RequestTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot(), flags); + ms_aInfoForModel[id].AddToList(&ms_startRequestedList); + ms_numModelsRequested++; + if(flags & STREAMFLAGS_PRIORITY) + ms_numPriorityRequests++; + } + + ms_aInfoForModel[id].m_loadState = STREAMSTATE_INQUEUE; + ms_aInfoForModel[id].m_flags = flags; + } +} + +void +CStreaming::RequestSubway(void) +{ + RequestModel(MI_SUBWAY1, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY2, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY3, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY4, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY5, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY6, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY7, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY8, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY9, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY10, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY11, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY12, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY13, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY14, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY15, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY16, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY17, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBWAY18, STREAMFLAGS_NOFADE); + + switch(CGame::currLevel){ + case LEVEL_INDUSTRIAL: + RequestModel(MI_SUBPLATFORM_IND, STREAMFLAGS_NOFADE); + break; + case LEVEL_COMMERCIAL: + if(FindPlayerTrain()->GetPosition().y < -700.0f){ + RequestModel(MI_SUBPLATFORM_COMS, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBPLATFORM_COMS2, STREAMFLAGS_NOFADE); + }else{ + RequestModel(MI_SUBPLATFORM_COMN, STREAMFLAGS_NOFADE); + } + break; + case LEVEL_SUBURBAN: + RequestModel(MI_SUBPLATFORM_SUB, STREAMFLAGS_NOFADE); + RequestModel(MI_SUBPLATFORM_SUB2, STREAMFLAGS_NOFADE); + break; + } +} + +void +CStreaming::RequestBigBuildings(eLevelName level) +{ + int i, n; + CBuilding *b; + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + b = CPools::GetBuildingPool()->GetSlot(i); + if(b && b->bIsBIGBuilding && b->m_level == level) + RequestModel(b->GetModelIndex(), STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + } + RequestIslands(level); + ms_hasLoadedLODs = false; +} + +void +CStreaming::RequestIslands(eLevelName level) +{ + switch(level){ + case LEVEL_INDUSTRIAL: + RequestModel(islandLODcomInd, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + RequestModel(islandLODsubInd, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + break; + case LEVEL_COMMERCIAL: + RequestModel(islandLODindust, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + RequestModel(islandLODsubCom, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + break; + case LEVEL_SUBURBAN: + RequestModel(islandLODindust, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + RequestModel(islandLODcomSub, STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_PRIORITY); + break; + } +} + +void +CStreaming::RequestSpecialModel(int32 modelId, const char *modelName, int32 flags) +{ + CBaseModelInfo *mi; + int txdId; + char oldName[48]; + uint32 pos, size; + + mi = CModelInfo::GetModelInfo(modelId); + if(strcmp(mi->GetName(), modelName) == 0){ + // Already have the correct name, just request it + RequestModel(modelId, flags); + return; + } + + strcpy(oldName, mi->GetName()); + mi->SetName(modelName); + + // What exactly is going on here? + if(CModelInfo::GetModelInfo(oldName, nil)){ + txdId = CTxdStore::FindTxdSlot(oldName); + if(txdId != -1 && CTxdStore::GetSlot(txdId)->texDict){ + CTxdStore::AddRef(txdId); + RemoveModel(modelId); + CTxdStore::RemoveRefWithoutDelete(txdId); + }else + RemoveModel(modelId); + }else + RemoveModel(modelId); + + ms_pExtraObjectsDir->FindItem(modelName, pos, size); + mi->ClearTexDictionary(); + if(CTxdStore::FindTxdSlot(modelName) == -1) + mi->SetTexDictionary("generic"); + else + mi->SetTexDictionary(modelName); + ms_aInfoForModel[modelId].SetCdPosnAndSize(pos, size); + RequestModel(modelId, flags); +} + +void +CStreaming::RequestSpecialChar(int32 charId, const char *modelName, int32 flags) +{ + RequestSpecialModel(charId + MI_SPECIAL01, modelName, flags); +} + +bool +CStreaming::HasSpecialCharLoaded(int32 id) +{ + return HasModelLoaded(id + MI_SPECIAL01); +} + +void +CStreaming::SetMissionDoesntRequireSpecialChar(int32 id) +{ + return SetMissionDoesntRequireModel(id + MI_SPECIAL01); +} + +void +CStreaming::DecrementRef(int32 id) +{ + ms_numModelsRequested--; + if(ms_aInfoForModel[id].IsPriority()){ + ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_PRIORITY; + ms_numPriorityRequests--; + } +} + +void +CStreaming::RemoveModel(int32 id) +{ + int i; + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED) + return; + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){ + if(id < STREAM_OFFSET_TXD) + CModelInfo::GetModelInfo(id)->DeleteRwObject(); + else + CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); + ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE; + } + + if(ms_aInfoForModel[id].m_next){ + // Remove from list, model is neither loaded nor requested + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE) + DecrementRef(id); + ms_aInfoForModel[id].RemoveFromList(); + }else if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_READING){ + for(i = 0; i < 4; i++){ + if(ms_channel[0].streamIds[i] == id) + ms_channel[0].streamIds[i] = -1; + if(ms_channel[1].streamIds[i] == id) + ms_channel[1].streamIds[i] = -1; + } + } + + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){ + if(id < STREAM_OFFSET_TXD) + RpClumpGtaCancelStream(); + else + CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); + } + + ms_aInfoForModel[id].m_loadState = STREAMSTATE_NOTLOADED; +} + +void +CStreaming::RemoveUnusedBuildings(eLevelName level) +{ + if(level != LEVEL_INDUSTRIAL) + RemoveBuildings(LEVEL_INDUSTRIAL); + if(level != LEVEL_COMMERCIAL) + RemoveBuildings(LEVEL_COMMERCIAL); + if(level != LEVEL_SUBURBAN) + RemoveBuildings(LEVEL_SUBURBAN); +} + +void +CStreaming::RemoveBuildings(eLevelName level) +{ + int i, n; + CEntity *e; + CBaseModelInfo *mi; + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetBuildingPool()->GetSlot(i); + if(e && e->m_level == level){ + mi = CModelInfo::GetModelInfo(e->GetModelIndex()); + if(!e->bImBeingRendered){ + e->DeleteRwObject(); + if(mi->m_refCount == 0) + RemoveModel(e->GetModelIndex()); + } + } + } + + n = CPools::GetTreadablePool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetTreadablePool()->GetSlot(i); + if(e && e->m_level == level){ + mi = CModelInfo::GetModelInfo(e->GetModelIndex()); + if(!e->bImBeingRendered){ + e->DeleteRwObject(); + if(mi->m_refCount == 0) + RemoveModel(e->GetModelIndex()); + } + } + } + + n = CPools::GetObjectPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetObjectPool()->GetSlot(i); + if(e && e->m_level == level){ + mi = CModelInfo::GetModelInfo(e->GetModelIndex()); + if(!e->bImBeingRendered && ((CObject*)e)->ObjectCreatedBy == GAME_OBJECT){ + e->DeleteRwObject(); + if(mi->m_refCount == 0) + RemoveModel(e->GetModelIndex()); + } + } + } + + n = CPools::GetDummyPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetDummyPool()->GetSlot(i); + if(e && e->m_level == level){ + mi = CModelInfo::GetModelInfo(e->GetModelIndex()); + if(!e->bImBeingRendered){ + e->DeleteRwObject(); + if(mi->m_refCount == 0) + RemoveModel(e->GetModelIndex()); + } + } + } +} + +void +CStreaming::RemoveUnusedBigBuildings(eLevelName level) +{ + if(level != LEVEL_INDUSTRIAL) + RemoveBigBuildings(LEVEL_INDUSTRIAL); + if(level != LEVEL_COMMERCIAL) + RemoveBigBuildings(LEVEL_COMMERCIAL); + if(level != LEVEL_SUBURBAN) + RemoveBigBuildings(LEVEL_SUBURBAN); + RemoveIslandsNotUsed(level); +} + +void +DeleteIsland(CEntity *island) +{ + if(island == nil) + return; + if(island->bImBeingRendered) + debug("Didn't delete island because it was being rendered\n"); + else{ + island->DeleteRwObject(); + CStreaming::RemoveModel(island->GetModelIndex()); + } +} + +void +CStreaming::RemoveIslandsNotUsed(eLevelName level) +{ + switch(level){ + case LEVEL_INDUSTRIAL: + DeleteIsland(pIslandLODindustEntity); + DeleteIsland(pIslandLODcomSubEntity); + DeleteIsland(pIslandLODsubComEntity); + break; + case LEVEL_COMMERCIAL: + DeleteIsland(pIslandLODcomIndEntity); + DeleteIsland(pIslandLODcomSubEntity); + DeleteIsland(pIslandLODsubIndEntity); + break; + case LEVEL_SUBURBAN: + DeleteIsland(pIslandLODsubIndEntity); + DeleteIsland(pIslandLODsubComEntity); + DeleteIsland(pIslandLODcomIndEntity); + break; + default: + DeleteIsland(pIslandLODindustEntity); + DeleteIsland(pIslandLODcomIndEntity); + DeleteIsland(pIslandLODcomSubEntity); + DeleteIsland(pIslandLODsubIndEntity); + DeleteIsland(pIslandLODsubComEntity); + break; + } +} + +void +CStreaming::RemoveBigBuildings(eLevelName level) +{ + int i, n; + CEntity *e; + CBaseModelInfo *mi; + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetBuildingPool()->GetSlot(i); + if(e && e->bIsBIGBuilding && e->m_level == level){ + mi = CModelInfo::GetModelInfo(e->GetModelIndex()); + if(!e->bImBeingRendered){ + e->DeleteRwObject(); + if(mi->m_refCount == 0) + RemoveModel(e->GetModelIndex()); + } + } + } +} + +bool +CStreaming::RemoveLoadedVehicle(void) +{ + int i, id; + + for(i = 0; i < MAXVEHICLESLOADED; i++){ + ms_lastVehicleDeleted++; + if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) + ms_lastVehicleDeleted = 0; + id = ms_vehiclesLoaded[ms_lastVehicleDeleted]; + if(id != -1 && + (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 && + CModelInfo::GetModelInfo(id)->m_refCount == 0 && + ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED) + goto found; + } + return false; +found: + RemoveModel(ms_vehiclesLoaded[ms_lastVehicleDeleted]); + ms_numVehiclesLoaded--; + ms_vehiclesLoaded[ms_lastVehicleDeleted] = -1; + return true; +} + +bool +CStreaming::RemoveLeastUsedModel(void) +{ + CStreamingInfo *si; + int streamId; + + for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){ + streamId = si - ms_aInfoForModel; + if(streamId < STREAM_OFFSET_TXD){ + if(CModelInfo::GetModelInfo(streamId)->m_refCount == 0){ + RemoveModel(streamId); + return true; + } + }else{ + if(CTxdStore::GetNumRefs(streamId - STREAM_OFFSET_TXD) == 0 && + !IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)){ + RemoveModel(streamId); + return true; + } + } + } + return ms_numVehiclesLoaded > 7 && RemoveLoadedVehicle(); +} + +void +CStreaming::RemoveAllUnusedModels(void) +{ + int i; + + for(i = 0; i < MAXVEHICLESLOADED; i++) + RemoveLoadedVehicle(); + + for(i = NUM_DEFAULT_MODELS; i < MODELINFOSIZE; i++){ + if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED && + ms_aInfoForModel[i].m_flags & STREAMFLAGS_DONT_REMOVE && + CModelInfo::GetModelInfo(i)->m_refCount == 0){ + RemoveModel(i); + ms_aInfoForModel[i].m_loadState = STREAMSTATE_NOTLOADED; + } + } +} + +bool +CStreaming::RemoveReferencedTxds(int32 mem) +{ + CStreamingInfo *si; + int streamId; + + for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){ + streamId = si - ms_aInfoForModel; + if(streamId >= STREAM_OFFSET_TXD && + CTxdStore::GetNumRefs(streamId-STREAM_OFFSET_TXD) == 0){ + RemoveModel(streamId); + if(ms_memoryUsed < mem) + return true; + } + } + return false; +} + +// TODO: RemoveCurrentZonesModels + +void +CStreaming::RemoveUnusedModelsInLoadedList(void) +{ + // empty +} + +bool +CStreaming::IsTxdUsedByRequestedModels(int32 txdId) +{ + CStreamingInfo *si; + int streamId; + int i; + + for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = si->m_next){ + streamId = si - ms_aInfoForModel; + if(streamId < STREAM_OFFSET_TXD && + CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) + return true; + } + + for(i = 0; i < 4; i++){ + streamId = ms_channel[0].streamIds[i]; + if(streamId != -1 && streamId < STREAM_OFFSET_TXD && + CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) + return true; + streamId = ms_channel[1].streamIds[i]; + if(streamId != -1 && streamId < STREAM_OFFSET_TXD && + CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId) + return true; + } + + return false; +} + +int32 +CStreaming::GetAvailableVehicleSlot(void) +{ + int i; + for(i = 0; i < MAXVEHICLESLOADED; i++) + if(ms_vehiclesLoaded[i] == -1) + return i; + return -1; +} + +bool +CStreaming::AddToLoadedVehiclesList(int32 modelId) +{ + int i; + int id; + + if(ms_numVehiclesLoaded < desiredNumVehiclesLoaded){ + // still room for vehicles + for(i = 0; i < MAXVEHICLESLOADED; i++){ + if(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1) + break; + ms_lastVehicleDeleted++; + if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) + ms_lastVehicleDeleted = 0; + } + assert(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1); + ms_numVehiclesLoaded++; + }else{ + // find vehicle we can remove + for(i = 0; i < MAXVEHICLESLOADED; i++){ + id = ms_vehiclesLoaded[ms_lastVehicleDeleted]; + if(id != -1 && + (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 && + CModelInfo::GetModelInfo(id)->m_refCount == 0) + goto found; + ms_lastVehicleDeleted++; + if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) + ms_lastVehicleDeleted = 0; + } + id = -1; +found: + if(id == -1){ + // didn't find anything, try a free slot + id = GetAvailableVehicleSlot(); + if(id == -1) + return false; // still no luck + ms_lastVehicleDeleted = id; + // this is more that we wanted actually + ms_numVehiclesLoaded++; + }else + RemoveModel(id); + } + + ms_vehiclesLoaded[ms_lastVehicleDeleted++] = modelId; + if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) + ms_lastVehicleDeleted = 0; + return true; +} + +bool +CStreaming::IsObjectInCdImage(int32 id) +{ + uint32 posn, size; + return ms_aInfoForModel[id].GetCdPosnAndSize(posn, size); +} + +void +CStreaming::HaveAllBigBuildingsLoaded(eLevelName level) +{ + int i, n; + CEntity *e; + + if(ms_hasLoadedLODs) + return; + + if(level == LEVEL_INDUSTRIAL){ + if(ms_aInfoForModel[islandLODcomInd].m_loadState != STREAMSTATE_LOADED || + ms_aInfoForModel[islandLODsubInd].m_loadState != STREAMSTATE_LOADED) + return; + }else if(level == LEVEL_COMMERCIAL){ + if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED || + ms_aInfoForModel[islandLODsubCom].m_loadState != STREAMSTATE_LOADED) + return; + }else if(level == LEVEL_SUBURBAN){ + if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED || + ms_aInfoForModel[islandLODcomSub].m_loadState != STREAMSTATE_LOADED) + return; + } + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetBuildingPool()->GetSlot(i); + if(e && e->bIsBIGBuilding && e->m_level == level && + ms_aInfoForModel[e->GetModelIndex()].m_loadState != STREAMSTATE_LOADED) + return; + } + + RemoveUnusedBigBuildings(level); + ms_hasLoadedLODs = true; +} + +void +CStreaming::SetModelIsDeletable(int32 id) +{ + ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_DONT_REMOVE; + if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) && + (ms_aInfoForModel[id].m_flags & STREAMFLAGS_SCRIPTOWNED) == 0){ + if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED) + RemoveModel(id); + else if(ms_aInfoForModel[id].m_next == nil) + ms_aInfoForModel[id].AddToList(&ms_startLoadedList); + } +} + +void +CStreaming::SetModelTxdIsDeletable(int32 id) +{ + SetModelIsDeletable(CModelInfo::GetModelInfo(id)->GetTxdSlot() + STREAM_OFFSET_TXD); +} + +void +CStreaming::SetMissionDoesntRequireModel(int32 id) +{ + ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_SCRIPTOWNED; + if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) && + (ms_aInfoForModel[id].m_flags & STREAMFLAGS_DONT_REMOVE) == 0){ + if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED) + RemoveModel(id); + else if(ms_aInfoForModel[id].m_next == nil) + ms_aInfoForModel[id].AddToList(&ms_startLoadedList); + } +} + +void +CStreaming::LoadInitialPeds(void) +{ + RequestModel(MI_COP, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_MALE01, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_TAXI_D, STREAMFLAGS_DONT_REMOVE); +} + +void +CStreaming::LoadInitialVehicles(void) +{ + int id; + + ms_numVehiclesLoaded = 0; + ms_lastVehicleDeleted = 0; + + if(CModelInfo::GetModelInfo("taxi", &id)) + RequestModel(id, STREAMFLAGS_DONT_REMOVE); + if(CModelInfo::GetModelInfo("police", &id)) + RequestModel(id, STREAMFLAGS_DONT_REMOVE); +} + +void +CStreaming::StreamVehiclesAndPeds(void) +{ + int i, model; + static int timeBeforeNextLoad = 0; + static int modelQualityClass = 0; + + if(CRecordDataForGame::RecordingState == RECORDSTATE_1 || + CRecordDataForGame::RecordingState == RECORDSTATE_2) + return; + + if(FindPlayerPed()->m_pWanted->AreSwatRequired()){ + RequestModel(MI_ENFORCER, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_SWAT, STREAMFLAGS_DONT_REMOVE); + }else{ + SetModelIsDeletable(MI_ENFORCER); + if(!HasModelLoaded(MI_ENFORCER)) + SetModelIsDeletable(MI_SWAT); + } + + if(FindPlayerPed()->m_pWanted->AreFbiRequired()){ + RequestModel(MI_FBICAR, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_FBI, STREAMFLAGS_DONT_REMOVE); + }else{ + SetModelIsDeletable(MI_FBICAR); + if(!HasModelLoaded(MI_FBICAR)) + SetModelIsDeletable(MI_FBI); + } + + if(FindPlayerPed()->m_pWanted->AreArmyRequired()){ + RequestModel(MI_RHINO, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_BARRACKS, STREAMFLAGS_DONT_REMOVE); + RequestModel(MI_ARMY, STREAMFLAGS_DONT_REMOVE); + }else{ + SetModelIsDeletable(MI_RHINO); + SetModelIsDeletable(MI_BARRACKS); + if(!HasModelLoaded(MI_RHINO) && !HasModelLoaded(MI_BARRACKS)) + SetModelIsDeletable(MI_ARMY); + } + + if(FindPlayerPed()->m_pWanted->NumOfHelisRequired() > 0) + RequestModel(MI_CHOPPER, STREAMFLAGS_DONT_REMOVE); + else + SetModelIsDeletable(MI_CHOPPER); + + if(timeBeforeNextLoad >= 0) + timeBeforeNextLoad--; + else if(ms_numVehiclesLoaded <= desiredNumVehiclesLoaded){ + for(i = 0; i <= 10; i++){ + model = CCarCtrl::ChooseCarModel(modelQualityClass); + modelQualityClass++; + if(modelQualityClass >= NUM_VEHICLE_CLASSES) + modelQualityClass = 0; + + // check if we want to load this model + if(ms_aInfoForModel[model].m_loadState == STREAMSTATE_NOTLOADED && + ((CVehicleModelInfo*)CModelInfo::GetModelInfo(model))->m_level & (1 << (CGame::currLevel-1))) + break; + } + + if(i <= 10){ + RequestModel(model, STREAMFLAGS_DEPENDENCY); + timeBeforeNextLoad = 500; + } + } +} + +void +CStreaming::StreamZoneModels(const CVector &pos) +{ + int i; + uint16 gangsToLoad, gangCarsToLoad, bit; + CZoneInfo info; + + CTheZones::GetZoneInfoForTimeOfDay(&pos, &info); + + if(info.pedGroup != ms_currentPedGrp){ + + // unload pevious group + if(ms_currentPedGrp != -1) + for(i = 0; i < 8; i++){ + if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) + break; + SetModelIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); + SetModelTxdIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); + } + + ms_currentPedGrp = info.pedGroup; + + for(i = 0; i < 8; i++){ + if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) + break; + RequestModel(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i], STREAMFLAGS_DONT_REMOVE); + } + } + RequestModel(MI_MALE01, STREAMFLAGS_DONT_REMOVE); + + gangsToLoad = 0; + gangCarsToLoad = 0; + if(info.gangDensity[0] != 0) gangsToLoad |= 1<<0; + if(info.gangDensity[1] != 0) gangsToLoad |= 1<<1; + if(info.gangDensity[2] != 0) gangsToLoad |= 1<<2; + if(info.gangDensity[3] != 0) gangsToLoad |= 1<<3; + if(info.gangDensity[4] != 0) gangsToLoad |= 1<<4; + if(info.gangDensity[5] != 0) gangsToLoad |= 1<<5; + if(info.gangDensity[6] != 0) gangsToLoad |= 1<<6; + if(info.gangDensity[7] != 0) gangsToLoad |= 1<<7; + if(info.gangDensity[8] != 0) gangsToLoad |= 1<<8; + if(info.gangThreshold[0] != info.copDensity) gangCarsToLoad |= 1<<0; + if(info.gangThreshold[1] != info.gangThreshold[0]) gangCarsToLoad |= 1<<1; + if(info.gangThreshold[2] != info.gangThreshold[1]) gangCarsToLoad |= 1<<2; + if(info.gangThreshold[3] != info.gangThreshold[2]) gangCarsToLoad |= 1<<3; + if(info.gangThreshold[4] != info.gangThreshold[3]) gangCarsToLoad |= 1<<4; + if(info.gangThreshold[5] != info.gangThreshold[4]) gangCarsToLoad |= 1<<5; + if(info.gangThreshold[6] != info.gangThreshold[5]) gangCarsToLoad |= 1<<6; + if(info.gangThreshold[7] != info.gangThreshold[6]) gangCarsToLoad |= 1<<7; + if(info.gangThreshold[8] != info.gangThreshold[7]) gangCarsToLoad |= 1<<8; + + if(gangsToLoad == ms_loadedGangs && gangCarsToLoad == ms_loadedGangCars) + return; + + // This makes things simpler than the game does it + gangsToLoad |= gangCarsToLoad; + + for(i = 0; i < NUM_GANGS; i++){ + bit = 1<m_nVehicleMI, STREAMFLAGS_DONT_REMOVE); + }else if((gangCarsToLoad & bit) == 0 && ms_loadedGangCars & bit){ + SetModelIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); + SetModelTxdIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); + } + } + ms_loadedGangCars = gangCarsToLoad; +} + +void +CStreaming::RemoveCurrentZonesModels(void) +{ + int i; + + if(ms_currentPedGrp != -1) + for(i = 0; i < 8; i++){ + if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] == -1) + break; + if(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i] != MI_MALE01) + SetModelIsDeletable(CPopulation::ms_pPedGroups[ms_currentPedGrp].models[i]); + } + + for(i = 0; i < NUM_GANGS; i++){ + SetModelIsDeletable(MI_GANG01 + i*2); + SetModelIsDeletable(MI_GANG01 + i*2 + 1); + if(CGangs::GetGangInfo(i)->m_nVehicleMI != -1) + SetModelIsDeletable(CGangs::GetGangInfo(i)->m_nVehicleMI); + } + + ms_currentPedGrp = -1; + ms_loadedGangs = 0; + ms_loadedGangCars = 0; +} + + + +// Find starting offset of the cdimage we next want to read +// Not useful at all on PC... +int32 +CStreaming::GetCdImageOffset(int32 lastPosn) +{ + int offset, off; + int i, img; + int dist, mindist; + + img = -1; + mindist = INT_MAX; + offset = ms_imageOffsets[ms_lastImageRead]; + if(lastPosn <= offset || lastPosn > offset + ms_imageSize){ + // last read position is not in last image + for(i = 0; i < NUMCDIMAGES; i++){ + off = ms_imageOffsets[i]; + if(off == -1) continue; + if((uint32)lastPosn > (uint32)off) + // after start of image, get distance from end + // negative if before end! + dist = lastPosn - (off + ms_imageSize); + else + // before image, get offset to start + // this will never be negative + dist = off - lastPosn; + if(dist < mindist){ + img = i; + mindist = dist; + } + } + assert(img >= 0); + offset = ms_imageOffsets[img]; + ms_lastImageRead = img; + } + return offset; +} + +inline bool +TxdAvailable(int32 txdId) +{ + CStreamingInfo *si = &CStreaming::ms_aInfoForModel[txdId + STREAM_OFFSET_TXD]; + return si->m_loadState == STREAMSTATE_LOADED || si->m_loadState == STREAMSTATE_READING; +} + +// Find stream id of next requested file in cdimage +int32 +CStreaming::GetNextFileOnCd(int32 lastPosn, bool priority) +{ + CStreamingInfo *si, *next; + int streamId; + uint32 posn, size; + int streamIdFirst, streamIdNext; + uint32 posnFirst, posnNext; + + streamIdFirst = -1; + streamIdNext = -1; + posnFirst = UINT_MAX; + posnNext = UINT_MAX; + + for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){ + next = si->m_next; + streamId = si - ms_aInfoForModel; + + // only priority requests if there are any + if(priority && ms_numPriorityRequests != 0 && !si->IsPriority()) + continue; + + // request Txd if necessary + if(streamId < STREAM_OFFSET_TXD && + !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot())){ + ReRequestTxd(CModelInfo::GetModelInfo(streamId)->GetTxdSlot()); + }else if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){ + if(posn < posnFirst){ + // find first requested file in image + streamIdFirst = streamId; + posnFirst = posn; + } + if(posn < posnNext && posn >= (uint32)lastPosn){ + // find first requested file after last read position + streamIdNext = streamId; + posnNext = posn; + } + }else{ + // empty file + DecrementRef(streamId); + si->RemoveFromList(); + si->m_loadState = STREAMSTATE_LOADED; + } + } + + // wrap around + if(streamIdNext == -1) + streamIdNext = streamIdFirst; + + if(streamIdNext == -1 && ms_numPriorityRequests != 0){ + // try non-priority files + ms_numPriorityRequests = 0; + streamIdNext = GetNextFileOnCd(lastPosn, false); + } + + return streamIdNext; +} + +/* + * Streaming buffer size is half of the largest file. + * Files larger than the buffer size can only be loaded by channel 0, + * which then uses both buffers, while channel 1 is idle. + * ms_bLoadingBigModel is set to true to indicate this state. + * + * TODO: two-part files + */ + +// Make channel read from disc +void +CStreaming::RequestModelStream(int32 ch) +{ + int lastPosn, imgOffset, streamId; + int totalSize; + uint32 posn, size, unused; + int i; + int haveBigFile, havePed; + + lastPosn = CdStreamGetLastPosn(); + imgOffset = GetCdImageOffset(lastPosn); + streamId = GetNextFileOnCd(lastPosn - imgOffset, true); + + if(streamId == -1) + return; + + // remove Txds that aren't requested anymore + while(streamId >= STREAM_OFFSET_TXD){ + if(ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY || + IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)) + break; + RemoveModel(streamId); + // so try next file + ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size); + streamId = GetNextFileOnCd(posn + size, true); + } + + if(streamId == -1) + return; + + ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size); + if(size > (uint32)ms_streamingBufferSize){ + // Can only load big models on channel 0, and 1 has to be idle + if(ch == 1 || ms_channel[1].state != CHANNELSTATE_IDLE) + return; + ms_bLoadingBigModel = true; + } + + // Load up to 4 adjacent files + haveBigFile = 0; + havePed = 0; + totalSize = 0; + for(i = 0; i < 4; i++){ + // no more files we can read + if(streamId == -1 || ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_INQUEUE) + break; + + // also stop at non-priority files + ms_aInfoForModel[streamId].GetCdPosnAndSize(unused, size); + if(ms_numPriorityRequests != 0 && !ms_aInfoForModel[streamId].IsPriority()) + break; + + // Can't load certain combinations of files together + if(streamId < STREAM_OFFSET_TXD){ + if(havePed && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED || + haveBigFile && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE || + !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot())) + break; + }else{ + if(haveBigFile && size > 200) + break; + } + + // Now add the file + ms_channel[ch].streamIds[i] = streamId; + ms_channel[ch].offsets[i] = totalSize; + totalSize += size; + + // To big for buffer, remove again + if(totalSize > ms_streamingBufferSize && i > 0){ + totalSize -= size; + break; + } + if(streamId < STREAM_OFFSET_TXD){ + if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED) + havePed = 1; + if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE) + haveBigFile = 1; + }else{ + if(size > 200) + haveBigFile = 1; + } + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING; + ms_aInfoForModel[streamId].RemoveFromList(); + DecrementRef(streamId); + + streamId = ms_aInfoForModel[streamId].m_nextID; + } + + // clear remaining slots + for(; i < 4; i++) + ms_channel[ch].streamIds[i] = -1; + // Now read the data + assert(!(ms_bLoadingBigModel && ch == 1)); // this would clobber the buffer + if(CdStreamRead(ch, ms_pStreamingBuffer[ch], imgOffset+posn, totalSize) == STREAM_NONE) + debug("FUCKFUCKFUCK\n"); + ms_channel[ch].state = CHANNELSTATE_READING; + ms_channel[ch].field24 = 0; + ms_channel[ch].size = totalSize; + ms_channel[ch].position = imgOffset+posn; + ms_channel[ch].numTries = 0; +} + +// Load data previously read from disc +bool +CStreaming::ProcessLoadingChannel(int32 ch) +{ + int status; + int i, id, cdsize; + + status = CdStreamGetStatus(ch); + if(status != STREAM_NONE){ + // busy + if(status != STREAM_READING && status != STREAM_WAITING){ + ms_channelError = ch; + ms_channel[ch].state = CHANNELSTATE_ERROR; + ms_channel[ch].status = status; + } + return false; + } + + if(ms_channel[ch].state == CHANNELSTATE_STARTED){ + ms_channel[ch].state = CHANNELSTATE_IDLE; + FinishLoadingLargeFile(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[0]*CDSTREAM_SECTOR_SIZE], + ms_channel[ch].streamIds[0]); + ms_channel[ch].streamIds[0] = -1; + }else{ + ms_channel[ch].state = CHANNELSTATE_IDLE; + for(i = 0; i < 4; i++){ + id = ms_channel[ch].streamIds[i]; + if(id == -1) + continue; + + cdsize = ms_aInfoForModel[id].GetCdSize(); + if(id < STREAM_OFFSET_TXD && + CModelInfo::GetModelInfo(id)->m_type == MITYPE_VEHICLE && + ms_numVehiclesLoaded >= desiredNumVehiclesLoaded && + !RemoveLoadedVehicle() && + ((ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 || GetAvailableVehicleSlot() == -1)){ + // can't load vehicle + RemoveModel(id); + if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) + ReRequestModel(id); + else if(CTxdStore::GetNumRefs(CModelInfo::GetModelInfo(id)->GetTxdSlot()) == 0) + RemoveTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot()); + }else{ + MakeSpaceFor(cdsize * CDSTREAM_SECTOR_SIZE); + ConvertBufferToObject(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[i]*CDSTREAM_SECTOR_SIZE], + id); + if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){ + // queue for second part + ms_channel[ch].state = CHANNELSTATE_STARTED; + ms_channel[ch].offsets[0] = ms_channel[ch].offsets[i]; + ms_channel[ch].streamIds[0] = id; + if(i != 0) + ms_channel[ch].streamIds[i] = -1; + }else + ms_channel[ch].streamIds[i] = -1; + } + } + } + + if(ms_bLoadingBigModel && ms_channel[ch].state != CHANNELSTATE_STARTED){ + ms_bLoadingBigModel = false; + // reset channel 1 after loading a big model + for(i = 0; i < 4; i++) + ms_channel[1].streamIds[i] = -1; + ms_channel[1].state = CHANNELSTATE_IDLE; + } + + return true; +} + +void +CStreaming::RetryLoadFile(int32 ch) +{ + char *key; + + CPad::StopPadsShaking(); + + if(ms_channel[ch].numTries >= 3){ + switch(ms_channel[ch].status){ + case STREAM_ERROR_NOCD: key = "NOCD"; break; + case STREAM_ERROR_OPENCD: key = "OPENCD"; break; + case STREAM_ERROR_WRONGCD: key = "WRONGCD"; break; + default: key = "CDERROR"; break; + } + CHud::SetMessage(TheText.Get(key)); + CTimer::SetCodePause(true); + } + + switch(ms_channel[ch].state){ + case CHANNELSTATE_IDLE: +streamread: + CdStreamRead(ch, ms_pStreamingBuffer[ch], ms_channel[ch].position, ms_channel[ch].size); + ms_channel[ch].state = CHANNELSTATE_READING; + ms_channel[ch].field24 = -600; + break; + case CHANNELSTATE_READING: + if(ProcessLoadingChannel(ch)){ + ms_channelError = -1; + CTimer::SetCodePause(false); + } + break; + case CHANNELSTATE_ERROR: + ms_channel[ch].numTries++; + if(CdStreamGetStatus(ch) != STREAM_READING && CdStreamGetStatus(ch) != STREAM_WAITING) + goto streamread; + break; + } +} + +void +CStreaming::LoadRequestedModels(void) +{ + static int currentChannel = 0; + + // We can't read with channel 1 while channel 0 is using its buffer + if(ms_bLoadingBigModel) + currentChannel = 0; + + // We have data, load + if(ms_channel[currentChannel].state == CHANNELSTATE_READING || + ms_channel[currentChannel].state == CHANNELSTATE_STARTED) + ProcessLoadingChannel(currentChannel); + + if(ms_channelError == -1){ + // Channel is idle, read more data + if(ms_channel[currentChannel].state == CHANNELSTATE_IDLE) + RequestModelStream(currentChannel); + // Switch channel + if(ms_channel[currentChannel].state != CHANNELSTATE_STARTED) + currentChannel = 1 - currentChannel; + } +} + +void +CStreaming::LoadAllRequestedModels(bool priority) +{ + static bool bInsideLoadAll = false; + int imgOffset, streamId, status; + int i; + uint32 posn, size; + + if(bInsideLoadAll) + return; + + FlushChannels(); + imgOffset = GetCdImageOffset(CdStreamGetLastPosn()); + + while(ms_endRequestedList.m_prev != &ms_startRequestedList){ + streamId = GetNextFileOnCd(0, priority); + if(streamId == -1) + break; + + ms_aInfoForModel[streamId].RemoveFromList(); + DecrementRef(streamId); + + if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){ + do + status = CdStreamRead(0, ms_pStreamingBuffer[0], imgOffset+posn, size); + while(CdStreamSync(0) || status == STREAM_NONE); + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING; + + MakeSpaceFor(size * CDSTREAM_SECTOR_SIZE); + ConvertBufferToObject(ms_pStreamingBuffer[0], streamId); + if(ms_aInfoForModel[streamId].m_loadState == STREAMSTATE_STARTED) + FinishLoadingLargeFile(ms_pStreamingBuffer[0], streamId); + + if(streamId < STREAM_OFFSET_TXD){ + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamId); + if(mi->IsSimple()) + mi->m_alpha = 255; + } + }else{ + // empty + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; + } + } + + ms_bLoadingBigModel = false; + for(i = 0; i < 4; i++){ + ms_channel[1].streamIds[i] = -1; + ms_channel[1].offsets[i] = -1; + } + ms_channel[1].state = CHANNELSTATE_IDLE; + bInsideLoadAll = false; +} + +void +CStreaming::FlushChannels(void) +{ + if(ms_channel[1].state == CHANNELSTATE_STARTED) + ProcessLoadingChannel(1); + + if(ms_channel[0].state == CHANNELSTATE_READING){ + CdStreamSync(0); + ProcessLoadingChannel(0); + } + if(ms_channel[0].state == CHANNELSTATE_STARTED) + ProcessLoadingChannel(0); + + if(ms_channel[1].state == CHANNELSTATE_READING){ + CdStreamSync(1); + ProcessLoadingChannel(1); + } + if(ms_channel[1].state == CHANNELSTATE_STARTED) + ProcessLoadingChannel(1); +} + +void +CStreaming::FlushRequestList(void) +{ + CStreamingInfo *si, *next; + + for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){ + next = si->m_next; + RemoveModel(si - ms_aInfoForModel); + } + FlushChannels(); +} + + +void +CStreaming::ImGonnaUseStreamingMemory(void) +{ + // empty +} + +void +CStreaming::IHaveUsedStreamingMemory(void) +{ + UpdateMemoryUsed(); +} + +void +CStreaming::UpdateMemoryUsed(void) +{ + // empty +} + +#define STREAM_DIST (2*SECTOR_SIZE_X) + +void +CStreaming::AddModelsToRequestList(const CVector &pos) +{ + float xmin, xmax, ymin, ymax; + int ixmin, ixmax, iymin, iymax; + int ix, iy; + int dx, dy, d; + CSector *sect; + + xmin = pos.x - STREAM_DIST; + ymin = pos.y - STREAM_DIST; + xmax = pos.x + STREAM_DIST; + ymax = pos.y + STREAM_DIST; + + ixmin = CWorld::GetSectorIndexX(xmin); + if(ixmin < 0) ixmin = 0; + ixmax = CWorld::GetSectorIndexX(xmax); + if(ixmax >= NUMSECTORS_X) ixmax = NUMSECTORS_X-1; + iymin = CWorld::GetSectorIndexY(ymin); + if(iymin < 0) iymin = 0; + iymax = CWorld::GetSectorIndexY(ymax); + if(iymax >= NUMSECTORS_Y) iymax = NUMSECTORS_Y-1; + + CWorld::AdvanceCurrentScanCode(); + + for(iy = iymin; iy < iymax; iy++){ + dy = iy - CWorld::GetSectorIndexY(pos.y); + for(ix = ixmin; ix < ixmax; ix++){ + + if(CRenderer::m_loadingPriority && ms_numModelsRequested > 5) + return; + + dx = ix - CWorld::GetSectorIndexX(pos.x); + d = dx*dx + dy*dy; + sect = CWorld::GetSector(ix, iy); + if(d <= 1){ + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + }else if(d <= 4*4){ + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], pos.x, pos.y, xmin, ymin, xmax, ymax); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], pos.x, pos.y, xmin, ymin, xmax, ymax); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], pos.x, pos.y, xmin, ymin, xmax, ymax); + ProcessEntitiesInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], pos.x, pos.y, xmin, ymin, xmax, ymax); + } + } + } +} + +void +CStreaming::ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float xmin, float ymin, float xmax, float ymax) +{ + CPtrNode *node; + CEntity *e; + float lodDistSq; + CVector2D pos; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + + if(e->m_scanCode == CWorld::GetCurrentScanCode()) + continue; + + e->m_scanCode = CWorld::GetCurrentScanCode(); + if(!e->bStreamingDontDelete && !e->bIsSubway && + (!e->IsObject() || ((CObject*)e)->ObjectCreatedBy != TEMP_OBJECT)){ + CTimeModelInfo *mi = (CTimeModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()); + if(mi->m_type != MITYPE_TIME || CClock::GetIsTimeInRange(mi->GetTimeOn(), mi->GetTimeOff())){ + lodDistSq = sq(mi->GetLargestLodDistance()); + lodDistSq = min(lodDistSq, sq(STREAM_DIST)); + pos = CVector2D(e->GetPosition()); + if(xmin < pos.x && pos.x < xmax && + ymin < pos.y && pos.y < ymax && + (CVector2D(x, y) - pos).MagnitudeSqr() < lodDistSq) + if(CRenderer::IsEntityCullZoneVisible(e)) + RequestModel(e->GetModelIndex(), 0); + } + } + } +} + +void +CStreaming::ProcessEntitiesInSectorList(CPtrList &list) +{ + CPtrNode *node; + CEntity *e; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + + if(e->m_scanCode == CWorld::GetCurrentScanCode()) + continue; + + e->m_scanCode = CWorld::GetCurrentScanCode(); + if(!e->bStreamingDontDelete && !e->bIsSubway && + (!e->IsObject() || ((CObject*)e)->ObjectCreatedBy != TEMP_OBJECT)){ + CTimeModelInfo *mi = (CTimeModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()); + if(mi->m_type != MITYPE_TIME || CClock::GetIsTimeInRange(mi->GetTimeOn(), mi->GetTimeOff())) + if(CRenderer::IsEntityCullZoneVisible(e)) + RequestModel(e->GetModelIndex(), 0); + } + } +} + +void +CStreaming::DeleteFarAwayRwObjects(const CVector &pos) +{ + int posx, posy; + int x, y; + int r, i; + CSector *sect; + + posx = CWorld::GetSectorIndexX(pos.x); + posy = CWorld::GetSectorIndexY(pos.y); + + // Move oldSectorX/Y to new sector and delete RW objects in its "wake" for every step: + // O is the old sector, <- is the direction in which we move it, + // X are the sectors we delete RW objects from (except we go up to 10) + // X + // X X + // X X X + // X X X + // <- O X X X + // X X X + // X X X + // X X + // X + + while(posx != ms_oldSectorX){ + if(posx < ms_oldSectorX){ + for(r = 2; r <= 10; r++){ + x = ms_oldSectorX + r; + if(x < 0) + continue; + if(x >= NUMSECTORS_X) + break; + + for(i = -r; i <= r; i++){ + y = ms_oldSectorY + i; + if(y < 0) + continue; + if(y >= NUMSECTORS_Y) + break; + + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + } + } + ms_oldSectorX--; + }else{ + for(r = 2; r <= 10; r++){ + x = ms_oldSectorX - r; + if(x < 0) + break; + if(x >= NUMSECTORS_X) + continue; + + for(i = -r; i <= r; i++){ + y = ms_oldSectorY + i; + if(y < 0) + continue; + if(y >= NUMSECTORS_Y) + break; + + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + } + } + ms_oldSectorX++; + } + } + + while(posy != ms_oldSectorY){ + if(posy < ms_oldSectorY){ + for(r = 2; r <= 10; r++){ + y = ms_oldSectorY + r; + if(y < 0) + continue; + if(y >= NUMSECTORS_Y) + break; + + for(i = -r; i <= r; i++){ + x = ms_oldSectorX + i; + if(x < 0) + continue; + if(x >= NUMSECTORS_X) + break; + + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + } + } + ms_oldSectorY--; + }else{ + for(r = 2; r <= 10; r++){ + y = ms_oldSectorY - r; + if(y < 0) + break; + if(y >= NUMSECTORS_Y) + continue; + + for(i = -r; i <= r; i++){ + x = ms_oldSectorX + i; + if(x < 0) + continue; + if(x >= NUMSECTORS_X) + break; + + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInOverlapSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], ms_oldSectorX, ms_oldSectorY); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + } + } + ms_oldSectorY++; + } + } +} + +void +CStreaming::DeleteAllRwObjects(void) +{ + int x, y; + CSector *sect; + + for(x = 0; x < NUMSECTORS_X; x++) + for(y = 0; y < NUMSECTORS_Y; y++){ + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + } +} + +void +CStreaming::DeleteRwObjectsAfterDeath(const CVector &pos) +{ + int ix, iy; + int x, y; + CSector *sect; + + ix = CWorld::GetSectorIndexX(pos.x); + iy = CWorld::GetSectorIndexX(pos.y); + + for(x = 0; x < NUMSECTORS_X; x++) + for(y = 0; y < NUMSECTORS_Y; y++) + if(fabs(ix - x) > 3.0f && + fabs(iy - y) > 3.0f){ + sect = CWorld::GetSector(x, y); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES]); + DeleteRwObjectsInSectorList(sect->m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + } +} + +void +CStreaming::DeleteRwObjectsBehindCamera(int32 mem) +{ + int ix, iy; + int x, y; + int xmin, xmax, ymin, ymax; + int inc; + CSector *sect; + + if(ms_memoryUsed < mem) + return; + + ix = CWorld::GetSectorIndexX(TheCamera.GetPosition().x); + iy = CWorld::GetSectorIndexX(TheCamera.GetPosition().y); + + if(fabs(TheCamera.GetForward().x) > fabs(TheCamera.GetForward().y)){ + // looking west/east + + ymin = max(iy - 10, 0); + ymax = min(iy + 10, NUMSECTORS_Y); + assert(ymin <= ymax); + + // Delete a block of sectors that we know is behind the camera + if(TheCamera.GetForward().x > 0){ + // looking east + xmax = max(ix - 2, 0); + xmin = max(ix - 10, 0); + inc = 1; + }else{ + // looking west + xmax = min(ix + 2, NUMSECTORS_X); + xmin = min(ix + 10, NUMSECTORS_X); + inc = -1; + } + for(y = ymin; y <= ymax; y++){ + for(x = xmin; x != xmax; x += inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + + // Now a block that intersects with the camera's frustum + if(TheCamera.GetForward().x > 0){ + // looking east + xmax = max(ix + 10, 0); + xmin = max(ix - 2, 0); + inc = 1; + }else{ + // looking west + xmax = min(ix - 10, NUMSECTORS_X); + xmin = min(ix + 2, NUMSECTORS_X); + inc = -1; + } + for(y = ymin; y <= ymax; y++){ + for(x = xmin; x != xmax; x += inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + + if(RemoveReferencedTxds(mem)) + return; + + // As last resort, delete objects from the last step more aggressively + for(y = ymin; y <= ymax; y++){ + for(x = xmax; x != xmin; x -= inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + }else{ + // looking north/south + + xmin = max(ix - 10, 0); + xmax = min(ix + 10, NUMSECTORS_X); + assert(xmin <= xmax); + + // Delete a block of sectors that we know is behind the camera + if(TheCamera.GetForward().y > 0){ + // looking north + ymax = max(iy - 2, 0); + ymin = max(iy - 10, 0); + inc = 1; + }else{ + // looking south + ymax = min(iy + 2, NUMSECTORS_Y); + ymin = min(iy + 10, NUMSECTORS_Y); + inc = -1; + } + for(x = xmin; x <= xmax; x++){ + for(y = ymin; y != ymax; y += inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + + // Now a block that intersects with the camera's frustum + if(TheCamera.GetForward().y > 0){ + // looking north + ymax = max(iy + 10, 0); + ymin = max(iy - 2, 0); + inc = 1; + }else{ + // looking south + ymax = min(iy - 10, NUMSECTORS_Y); + ymin = min(iy + 2, NUMSECTORS_Y); + inc = -1; + } + for(x = xmin; x <= xmax; x++){ + for(y = ymin; y != ymax; y += inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsNotInFrustumInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + + if(RemoveReferencedTxds(mem)) + return; + + // As last resort, delete objects from the last step more aggressively + for(x = xmin; x <= xmax; x++){ + for(y = ymax; y != ymin; y -= inc){ + sect = CWorld::GetSector(x, y); + if(DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_BUILDINGS], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_DUMMIES], mem) || + DeleteRwObjectsBehindCameraInSectorList(sect->m_lists[ENTITYLIST_OBJECTS], mem)) + return; + } + } + } +} + +void +CStreaming::DeleteRwObjectsInSectorList(CPtrList &list) +{ + CPtrNode *node; + CEntity *e; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(!e->bStreamingDontDelete && !e->bImBeingRendered) + e->DeleteRwObject(); + } +} + +void +CStreaming::DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y) +{ + CPtrNode *node; + CEntity *e; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(e->m_rwObject && !e->bStreamingDontDelete && !e->bImBeingRendered){ + // Now this is pretty weird... + if(fabs(CWorld::GetSectorIndexX(e->GetPosition().x) - x) >= 2.0f) +// { + e->DeleteRwObject(); +// return; // BUG? +// } + else // FIX? + if(fabs(CWorld::GetSectorIndexY(e->GetPosition().y) - y) >= 2.0f) + e->DeleteRwObject(); + } + } +} + +bool +CStreaming::DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, int32 mem) +{ + CPtrNode *node; + CEntity *e; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(!e->bStreamingDontDelete && !e->bImBeingRendered && + e->m_rwObject && ms_aInfoForModel[e->GetModelIndex()].m_next){ + e->DeleteRwObject(); + if(CModelInfo::GetModelInfo(e->GetModelIndex())->m_refCount == 0){ + RemoveModel(e->GetModelIndex()); + if(ms_memoryUsed < mem) + return true; + } + } + } + return false; +} + +bool +CStreaming::DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, int32 mem) +{ + CPtrNode *node; + CEntity *e; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(!e->bStreamingDontDelete && !e->bImBeingRendered && + e->m_rwObject && !e->IsVisible() && ms_aInfoForModel[e->GetModelIndex()].m_next){ + e->DeleteRwObject(); + if(CModelInfo::GetModelInfo(e->GetModelIndex())->m_refCount == 0){ + RemoveModel(e->GetModelIndex()); + if(ms_memoryUsed < mem) + return true; + } + } + } + return false; +} + +void +CStreaming::MakeSpaceFor(int32 size) +{ + // BUG: ms_memoryAvailable can be uninitialized + // the code still happens to work in that case because ms_memoryAvailable is unsigned + // but it's not nice.... + + while((uint32)ms_memoryUsed >= ms_memoryAvailable - size) + if(!RemoveLeastUsedModel()){ + DeleteRwObjectsBehindCamera(ms_memoryAvailable - size); + return; + } +} + +void +CStreaming::LoadScene(const CVector &pos) +{ + CStreamingInfo *si, *prev; + eLevelName level; + + level = CTheZones::GetLevelFromPosition(pos); + debug("Start load scene\n"); + for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ + prev = si->m_prev; + if((si->m_flags & (STREAMFLAGS_KEEP_IN_MEMORY|STREAMFLAGS_PRIORITY)) == 0) + RemoveModel(si - ms_aInfoForModel); + } + CRenderer::m_loadingPriority = false; + CCullZones::ForceCullZoneCoors(pos); + DeleteAllRwObjects(); + AddModelsToRequestList(pos); + CRadar::StreamRadarSections(pos); + RemoveUnusedBigBuildings(level); + RequestBigBuildings(level); + LoadAllRequestedModels(false); + debug("End load scene\n"); +} + +void +CStreaming::MemoryCardSave(uint8 *buffer, uint32 *length) +{ + int i; + + *length = NUM_DEFAULT_MODELS; + for(i = 0; i < NUM_DEFAULT_MODELS; i++) + if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED) + buffer[i] = ms_aInfoForModel[i].m_flags; + else + buffer[i] = 0xFF; +} + +void +CStreaming::MemoryCardLoad(uint8 *buffer, uint32 length) +{ + uint32 i; + + assert(length == NUM_DEFAULT_MODELS); + for(i = 0; i < length; i++) + if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED) + if(buffer[i] != 0xFF) + ms_aInfoForModel[i].m_flags = buffer[i]; +} + +STARTPATCHES + InjectHook(0x406430, CStreaming::Init, PATCH_JUMP); + InjectHook(0x406C80, CStreaming::Shutdown, PATCH_JUMP); + InjectHook(0x4076C0, CStreaming::Update, PATCH_JUMP); + InjectHook(0x406CC0, (void (*)(void))CStreaming::LoadCdDirectory, PATCH_JUMP); + InjectHook(0x406DA0, (void (*)(const char*, int))CStreaming::LoadCdDirectory, PATCH_JUMP); + InjectHook(0x409740, CStreaming::ConvertBufferToObject, PATCH_JUMP); + InjectHook(0x409580, CStreaming::FinishLoadingLargeFile, PATCH_JUMP); + InjectHook(0x407EA0, CStreaming::RequestModel, PATCH_JUMP); + InjectHook(0x407FD0, CStreaming::RequestSubway, PATCH_JUMP); + InjectHook(0x408190, CStreaming::RequestBigBuildings, PATCH_JUMP); + InjectHook(0x408210, CStreaming::RequestIslands, PATCH_JUMP); + InjectHook(0x40A890, CStreaming::RequestSpecialModel, PATCH_JUMP); + InjectHook(0x40ADA0, CStreaming::RequestSpecialChar, PATCH_JUMP); + InjectHook(0x54A5F0, CStreaming::HasModelLoaded, PATCH_JUMP); + InjectHook(0x40ADC0, CStreaming::HasSpecialCharLoaded, PATCH_JUMP); + InjectHook(0x40ADE0, CStreaming::SetMissionDoesntRequireSpecialChar, PATCH_JUMP); + + InjectHook(0x408830, CStreaming::RemoveModel, PATCH_JUMP); + InjectHook(0x4083A0, CStreaming::RemoveUnusedBuildings, PATCH_JUMP); + InjectHook(0x4083D0, CStreaming::RemoveBuildings, PATCH_JUMP); + InjectHook(0x408640, CStreaming::RemoveUnusedBigBuildings, PATCH_JUMP); + InjectHook(0x408680, CStreaming::RemoveBigBuildings, PATCH_JUMP); + InjectHook(0x408780, CStreaming::RemoveIslandsNotUsed, PATCH_JUMP); + InjectHook(0x40B180, CStreaming::RemoveLoadedVehicle, PATCH_JUMP); + InjectHook(0x4089B0, CStreaming::RemoveLeastUsedModel, PATCH_JUMP); + InjectHook(0x408940, CStreaming::RemoveAllUnusedModels, PATCH_JUMP); + InjectHook(0x409450, CStreaming::RemoveReferencedTxds, PATCH_JUMP); + + InjectHook(0x40B160, CStreaming::GetAvailableVehicleSlot, PATCH_JUMP); + InjectHook(0x40B060, CStreaming::AddToLoadedVehiclesList, PATCH_JUMP); + InjectHook(0x4094C0, CStreaming::IsTxdUsedByRequestedModels, PATCH_JUMP); + InjectHook(0x407E70, CStreaming::IsObjectInCdImage, PATCH_JUMP); + InjectHook(0x408280, CStreaming::HaveAllBigBuildingsLoaded, PATCH_JUMP); + InjectHook(0x40A790, CStreaming::SetModelIsDeletable, PATCH_JUMP); + InjectHook(0x40A800, CStreaming::SetModelTxdIsDeletable, PATCH_JUMP); + InjectHook(0x40A820, CStreaming::SetMissionDoesntRequireModel, PATCH_JUMP); + + InjectHook(0x40AA00, CStreaming::LoadInitialPeds, PATCH_JUMP); + InjectHook(0x40ADF0, CStreaming::LoadInitialVehicles, PATCH_JUMP); + InjectHook(0x40AE60, CStreaming::StreamVehiclesAndPeds, PATCH_JUMP); + InjectHook(0x40AA30, CStreaming::StreamZoneModels, PATCH_JUMP); + InjectHook(0x40AD00, CStreaming::RemoveCurrentZonesModels, PATCH_JUMP); + + InjectHook(0x409BE0, CStreaming::ProcessLoadingChannel, PATCH_JUMP); + InjectHook(0x40A610, CStreaming::FlushChannels, PATCH_JUMP); + InjectHook(0x40A680, CStreaming::FlushRequestList, PATCH_JUMP); + InjectHook(0x409FF0, CStreaming::GetCdImageOffset, PATCH_JUMP); + InjectHook(0x409E50, CStreaming::GetNextFileOnCd, PATCH_JUMP); + InjectHook(0x40A060, CStreaming::RequestModelStream, PATCH_JUMP); + InjectHook(0x4077F0, CStreaming::RetryLoadFile, PATCH_JUMP); + InjectHook(0x40A390, CStreaming::LoadRequestedModels, PATCH_JUMP); + InjectHook(0x40A440, CStreaming::LoadAllRequestedModels, PATCH_JUMP); + + InjectHook(0x4078F0, CStreaming::AddModelsToRequestList, PATCH_JUMP); + InjectHook(0x407C50, (void (*)(CPtrList&,float,float,float,float,float,float))CStreaming::ProcessEntitiesInSectorList, PATCH_JUMP); + InjectHook(0x407DD0, (void (*)(CPtrList&))CStreaming::ProcessEntitiesInSectorList, PATCH_JUMP); + + InjectHook(0x407070, CStreaming::DeleteFarAwayRwObjects, PATCH_JUMP); + InjectHook(0x407390, CStreaming::DeleteAllRwObjects, PATCH_JUMP); + InjectHook(0x407400, CStreaming::DeleteRwObjectsAfterDeath, PATCH_JUMP); + InjectHook(0x408A60, CStreaming::DeleteRwObjectsBehindCamera, PATCH_JUMP); + InjectHook(0x407560, CStreaming::DeleteRwObjectsInSectorList, PATCH_JUMP); + InjectHook(0x4075A0, CStreaming::DeleteRwObjectsInOverlapSectorList, PATCH_JUMP); + InjectHook(0x409340, CStreaming::DeleteRwObjectsBehindCameraInSectorList, PATCH_JUMP); + InjectHook(0x4093C0, CStreaming::DeleteRwObjectsNotInFrustumInSectorList, PATCH_JUMP); + InjectHook(0x409B70, CStreaming::MakeSpaceFor, PATCH_JUMP); + InjectHook(0x40A6D0, CStreaming::LoadScene, PATCH_JUMP); + + InjectHook(0x40B210, CStreaming::MemoryCardSave, PATCH_JUMP); + InjectHook(0x40B250, CStreaming::MemoryCardLoad, PATCH_JUMP); + + InjectHook(0x4063E0, &CStreamingInfo::GetCdPosnAndSize, PATCH_JUMP); + InjectHook(0x406410, &CStreamingInfo::SetCdPosnAndSize, PATCH_JUMP); + InjectHook(0x4063D0, &CStreamingInfo::GetCdSize, PATCH_JUMP); + InjectHook(0x406380, &CStreamingInfo::AddToList, PATCH_JUMP); + InjectHook(0x4063A0, &CStreamingInfo::RemoveFromList, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Streaming.h b/src/core/Streaming.h new file mode 100644 index 00000000..212a6d71 --- /dev/null +++ b/src/core/Streaming.h @@ -0,0 +1,188 @@ +#pragma once + +#include "Game.h" + +enum { + STREAM_OFFSET_MODEL = 0, + STREAM_OFFSET_TXD = STREAM_OFFSET_MODEL+MODELINFOSIZE, + NUMSTREAMINFO = STREAM_OFFSET_TXD+TXDSTORESIZE +}; + +enum StreamFlags +{ + STREAMFLAGS_DONT_REMOVE = 0x01, + STREAMFLAGS_SCRIPTOWNED = 0x02, + STREAMFLAGS_DEPENDENCY = 0x04, // Is this right? + STREAMFLAGS_PRIORITY = 0x08, + STREAMFLAGS_NOFADE = 0x10, + + // TODO: this isn't named well, maybe CANT_REMOVE? + STREAMFLAGS_NOT_IN_LIST = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED, + STREAMFLAGS_KEEP_IN_MEMORY = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED|STREAMFLAGS_DEPENDENCY, +}; + +enum StreamLoadState +{ + STREAMSTATE_NOTLOADED = 0, + STREAMSTATE_LOADED = 1, + STREAMSTATE_INQUEUE = 2, + STREAMSTATE_READING = 3, // channel is reading + STREAMSTATE_STARTED = 4, // first part loaded +}; + +enum ChannelState +{ + CHANNELSTATE_IDLE = 0, + CHANNELSTATE_READING = 1, + CHANNELSTATE_STARTED = 2, + CHANNELSTATE_ERROR = 3, +}; + +class CStreamingInfo +{ +public: + CStreamingInfo *m_next; + CStreamingInfo *m_prev; + uint8 m_loadState; + uint8 m_flags; + + int16 m_nextID; + uint32 m_position; + uint32 m_size; + + bool GetCdPosnAndSize(uint32 &posn, uint32 &size); + void SetCdPosnAndSize(uint32 posn, uint32 size); + void AddToList(CStreamingInfo *link); + void RemoveFromList(void); + uint32 GetCdSize(void) { return m_size; } + bool IsPriority(void) { return !!(m_flags & STREAMFLAGS_PRIORITY); } +}; + +struct CStreamingChannel +{ + int32 streamIds[4]; + int32 offsets[4]; + int32 state; + int32 field24; + int32 position; + int32 size; + int32 numTries; + int32 status; // from CdStream +}; + +class CDirectory; +enum eLevelName; +class CPtrList; + +class CStreaming +{ +public: + static bool &ms_disableStreaming; + static bool &ms_bLoadingBigModel; + static int32 &ms_numModelsRequested; + static CStreamingInfo *ms_aInfoForModel; //[NUMSTREAMINFO] + static CStreamingInfo &ms_startLoadedList; + static CStreamingInfo &ms_endLoadedList; + static CStreamingInfo &ms_startRequestedList; + static CStreamingInfo &ms_endRequestedList; + static int32 &ms_oldSectorX; + static int32 &ms_oldSectorY; + static int32 &ms_streamingBufferSize; + static int8 **ms_pStreamingBuffer; //[2] + static int32 &ms_memoryUsed; + static CStreamingChannel *ms_channel; //[2] + static int32 &ms_channelError; + static int32 &ms_numVehiclesLoaded; + static int32 *ms_vehiclesLoaded; //[MAXVEHICLESLOADED] + static int32 &ms_lastVehicleDeleted; + static CDirectory *&ms_pExtraObjectsDir; + static int32 &ms_numPriorityRequests; + static bool &ms_hasLoadedLODs; + static int32 &ms_currentPedGrp; + static int32 ms_lastCullZone; + static uint16 &ms_loadedGangs; + static uint16 &ms_loadedGangCars; + static int32 ms_currentPedLoading; + static int32 *ms_imageOffsets; //[NUMCDIMAGES] + static int32 &ms_lastImageRead; + static int32 &ms_imageSize; + static uint32 &ms_memoryAvailable; + + static void Init(void); + static void Shutdown(void); + static void Update(void); + static void LoadCdDirectory(void); + static void LoadCdDirectory(const char *dirname, int32 n); + static bool ConvertBufferToObject(int8 *buf, int32 streamId); + static bool FinishLoadingLargeFile(int8 *buf, int32 streamId); + static bool HasModelLoaded(int32 id) { return ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED; } + static void RequestModel(int32 model, int32 flags); + static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); } + static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); } + static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); } + static void RequestSubway(void); + static void RequestBigBuildings(eLevelName level); + static void RequestIslands(eLevelName level); + static void RequestSpecialModel(int32 modelId, const char *modelName, int32 flags); + static void RequestSpecialChar(int32 charId, const char *modelName, int32 flags); + static bool HasSpecialCharLoaded(int32 id); + static void SetMissionDoesntRequireSpecialChar(int32 id); + static void DecrementRef(int32 id); + static void RemoveModel(int32 id); + static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); } + static void RemoveUnusedBuildings(eLevelName level); + static void RemoveBuildings(eLevelName level); + static void RemoveUnusedBigBuildings(eLevelName level); + static void RemoveIslandsNotUsed(eLevelName level); + static void RemoveBigBuildings(eLevelName level); + static bool RemoveLoadedVehicle(void); + static bool RemoveLeastUsedModel(void); + static void RemoveAllUnusedModels(void); + static void RemoveUnusedModelsInLoadedList(void); + static bool RemoveReferencedTxds(int32 mem); + static int32 GetAvailableVehicleSlot(void); + static bool IsTxdUsedByRequestedModels(int32 txdId); + static bool AddToLoadedVehiclesList(int32 modelId); + static bool IsObjectInCdImage(int32 id); + static void HaveAllBigBuildingsLoaded(eLevelName level); + static void SetModelIsDeletable(int32 id); + static void SetModelTxdIsDeletable(int32 id); + static void SetMissionDoesntRequireModel(int32 id); + static void LoadInitialPeds(void); + static void LoadInitialVehicles(void); + static void StreamVehiclesAndPeds(void); + static void StreamZoneModels(const CVector &pos); + static void RemoveCurrentZonesModels(void); + + static int32 GetCdImageOffset(int32 lastPosn); + static int32 GetNextFileOnCd(int32 position, bool priority); + static void RequestModelStream(int32 ch); + static bool ProcessLoadingChannel(int32 ch); + static void RetryLoadFile(int32 ch); + static void LoadRequestedModels(void); + static void LoadAllRequestedModels(bool priority); + static void FlushChannels(void); + static void FlushRequestList(void); + + static void MakeSpaceFor(int32 size); + static void ImGonnaUseStreamingMemory(void); + static void IHaveUsedStreamingMemory(void); + static void UpdateMemoryUsed(void); + + static void AddModelsToRequestList(const CVector &pos); + static void ProcessEntitiesInSectorList(CPtrList &list, float x, float y, float xmin, float ymin, float xmax, float ymax); + static void ProcessEntitiesInSectorList(CPtrList &list); + static void DeleteFarAwayRwObjects(const CVector &pos); + static void DeleteAllRwObjects(void); + static void DeleteRwObjectsAfterDeath(const CVector &pos); + static void DeleteRwObjectsBehindCamera(int32 mem); + static void DeleteRwObjectsInSectorList(CPtrList &list); + static void DeleteRwObjectsInOverlapSectorList(CPtrList &list, int32 x, int32 y); + static bool DeleteRwObjectsBehindCameraInSectorList(CPtrList &list, int32 mem); + static bool DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, int32 mem); + + static void LoadScene(const CVector &pos); + + static void MemoryCardSave(uint8 *buffer, uint32 *length); + static void MemoryCardLoad(uint8 *buffer, uint32 length); +}; diff --git a/src/core/SurfaceTable.cpp b/src/core/SurfaceTable.cpp new file mode 100644 index 00000000..2ba884b1 --- /dev/null +++ b/src/core/SurfaceTable.cpp @@ -0,0 +1,150 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "FileMgr.h" +#include "Weather.h" +#include "Collision.h" +#include "SurfaceTable.h" + +float (*CSurfaceTable::ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS] = (float (*)[NUMADHESIVEGROUPS])0x8E29D4; + +void +CSurfaceTable::Initialise(char *filename) +{ + int lineno, fieldno; + char *line; + char surfname[256]; + float adhesiveLimit; + + CFileMgr::SetDir(""); + CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r"); + + line = (char*)work_buff; + for(lineno = 0; lineno < NUMADHESIVEGROUPS; lineno++){ + // skip white space and comments + while(*line == ' ' || *line == '\t' || *line == '\n' || *line == '\r' || *line == ';'){ + if(*line == ';'){ + while(*line != '\n' && *line != '\r') + line++; + }else + line++; + } + + sscanf(line, "%s", surfname); + // skip what we just read + while(!(*line == ' ' || *line == '\t' || *line == ',')) + line++; + + for(fieldno = 0; fieldno <= lineno; fieldno++){ + // skip white space + while(*line == ' ' || *line == '\t' || *line == ',') + line++; + adhesiveLimit = 0.0f; + if(*line != '-') + sscanf(line, "%f", &adhesiveLimit); + // skip what we just read + while(!(*line == ' ' || *line == '\t' || *line == ',' || *line == '\n')) + line++; + + ms_aAdhesiveLimitTable[lineno][fieldno] = adhesiveLimit; + ms_aAdhesiveLimitTable[fieldno][lineno] = adhesiveLimit; + } + } +} + +int +CSurfaceTable::GetAdhesionGroup(uint8 surfaceType) +{ + switch(surfaceType){ + case SURFACE_0: return ADHESIVE_ROAD; + case SURFACE_1: return ADHESIVE_ROAD; + case SURFACE_2: return ADHESIVE_LOOSE; + case SURFACE_3: return ADHESIVE_LOOSE; + case SURFACE_4: return ADHESIVE_HARD; + case SURFACE_5: return ADHESIVE_ROAD; + case SURFACE_6: return ADHESIVE_HARD; + case SURFACE_7: return ADHESIVE_HARD; + case SURFACE_8: return ADHESIVE_HARD; + case SURFACE_9: return ADHESIVE_HARD; + case SURFACE_10: return ADHESIVE_HARD; + case SURFACE_11: return ADHESIVE_HARD; + case SURFACE_12: return ADHESIVE_HARD; + case SURFACE_13: return ADHESIVE_HARD; + case SURFACE_14: return ADHESIVE_HARD; + case SURFACE_15: return ADHESIVE_HARD; + case SURFACE_16: return ADHESIVE_HARD; + case SURFACE_17: return ADHESIVE_RUBBER; + case SURFACE_18: return ADHESIVE_LOOSE; + case SURFACE_19: return ADHESIVE_WET; + case SURFACE_20: return ADHESIVE_ROAD; + case SURFACE_21: return ADHESIVE_ROAD; + case SURFACE_22: return ADHESIVE_ROAD; + case SURFACE_23: return ADHESIVE_RUBBER; + case SURFACE_24: return ADHESIVE_HARD; + case SURFACE_25: return ADHESIVE_LOOSE; + case SURFACE_26: return ADHESIVE_LOOSE; + case SURFACE_27: return ADHESIVE_HARD; + case SURFACE_28: return ADHESIVE_HARD; + case SURFACE_29: return ADHESIVE_RUBBER; + case SURFACE_30: return ADHESIVE_LOOSE; + case SURFACE_31: return ADHESIVE_HARD; + case SURFACE_32: return ADHESIVE_HARD; + default: return ADHESIVE_ROAD; + } +} + +float +CSurfaceTable::GetWetMultiplier(uint8 surfaceType) +{ + switch(surfaceType){ + case SURFACE_0: + case SURFACE_1: + case SURFACE_4: + case SURFACE_5: + case SURFACE_8: + case SURFACE_20: + case SURFACE_21: + case SURFACE_22: + case SURFACE_25: + case SURFACE_30: + case SURFACE_31: + return 1.0f - CWeather::WetRoads*0.25f; + + case SURFACE_2: + case SURFACE_6: + case SURFACE_7: + case SURFACE_9: + case SURFACE_10: + case SURFACE_11: + case SURFACE_12: + case SURFACE_13: + case SURFACE_14: + case SURFACE_15: + case SURFACE_16: + case SURFACE_17: + case SURFACE_23: + case SURFACE_24: + case SURFACE_26: + case SURFACE_27: + case SURFACE_28: + case SURFACE_29: + case SURFACE_32: + return 1.0f - CWeather::WetRoads*0.4f; + + default: + return 1.0f; + } +} + +float +CSurfaceTable::GetAdhesiveLimit(CColPoint &colpoint) +{ + return ms_aAdhesiveLimitTable[GetAdhesionGroup(colpoint.surfaceB)][GetAdhesionGroup(colpoint.surfaceA)]; +} + +STARTPATCHES + InjectHook(0x4AB8F0, CSurfaceTable::Initialise, PATCH_JUMP); + InjectHook(0x4ABA60, CSurfaceTable::GetAdhesionGroup, PATCH_JUMP); + InjectHook(0x4ABAA0, CSurfaceTable::GetWetMultiplier, PATCH_JUMP); + InjectHook(0x4ABA30, CSurfaceTable::GetAdhesiveLimit, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/SurfaceTable.h b/src/core/SurfaceTable.h new file mode 100644 index 00000000..e1882e69 --- /dev/null +++ b/src/core/SurfaceTable.h @@ -0,0 +1,106 @@ +#pragma once + + +enum +{ + SURFACE_0, + SURFACE_1, + SURFACE_2, + SURFACE_3, + SURFACE_4, + SURFACE_5, + SURFACE_6, + SURFACE_7, + SURFACE_8, + SURFACE_9, + SURFACE_10, + SURFACE_11, + SURFACE_12, + SURFACE_13, + SURFACE_14, + SURFACE_15, + SURFACE_16, + SURFACE_17, + SURFACE_18, + SURFACE_19, + SURFACE_20, + SURFACE_21, + SURFACE_22, + SURFACE_23, + SURFACE_24, + SURFACE_25, + SURFACE_26, + SURFACE_27, + SURFACE_28, + SURFACE_29, + SURFACE_30, + SURFACE_31, + SURFACE_32, + + NUMSURFACETYPES +}; + +// From nick +// TODO: check and use this +enum eSurfaceType +{ + SURFACE_DEFAULT, + SURFACE_TARMAC, + SURFACE_GRASS, + SURFACE_DIRT, + SURFACE_DIRTTRACK, + SURFACE_PAVEMENT, + SURFACE_METAL6, + SURFACE_GLASS, + SURFACE_SCAFFOLD, + SURFACE_METAL_DOOR, // garage door + SURFACE_BILLBOARD, + SURFACE_STEEL, //? + SURFACE_METAL_POLE, // ? + SURFACE_STREET_LIGHT, + SURFACE_METAL14, + SURFACE_METAL15, + SURFACE_METAL_FENCE, + SURFACE_FLESH, + SURFACE_SAND, + SURFACE_PUDDLE, + SURFACE_WOOD, + SURFACE_WOOD_BOX, + SURFACE_WOOD_PLANK, + SURFACE_TIRE, + SURFACE_HARD24, + SURFACE_HEDGE, + SURFACE_STONE, + SURFACE_METAL27, + SURFACE_METAL28, + SURFACE_RUBBER29, + SURFACE_LOOSE30, + SURFACE_BOLLARD, + SURFACE_GATE, + SURFACE_SAND33, + SURFACE_ROAD34, +}; + +enum +{ + ADHESIVE_RUBBER, + ADHESIVE_HARD, + ADHESIVE_ROAD, + ADHESIVE_LOOSE, + ADHESIVE_WET, + + NUMADHESIVEGROUPS +}; + +struct CColPoint; + +class CSurfaceTable +{ +// static float ms_aAdhesiveLimitTable[NUMADHESIVEGROUPS][NUMADHESIVEGROUPS]; + static float (*ms_aAdhesiveLimitTable)[NUMADHESIVEGROUPS]; +public: + static void Initialise(char *filename); + static int GetAdhesionGroup(uint8 surfaceType); + static float GetWetMultiplier(uint8 surfaceType); + static float GetAdhesiveLimit(CColPoint &colpoint); +}; diff --git a/src/core/TempColModels.cpp b/src/core/TempColModels.cpp new file mode 100644 index 00000000..a323d7c9 --- /dev/null +++ b/src/core/TempColModels.cpp @@ -0,0 +1,17 @@ +#include "common.h" +#include "patcher.h" +#include "TempColModels.h" + +CColModel &CTempColModels::ms_colModelPed1 = *(CColModel*)0x726CB0; +CColModel &CTempColModels::ms_colModelPed2 = *(CColModel*)0x726D08; +CColModel &CTempColModels::ms_colModelBBox = *(CColModel*)0x727FE0; +CColModel &CTempColModels::ms_colModelBumper1 = *(CColModel*)0x86BE88; +CColModel &CTempColModels::ms_colModelWheel1 = *(CColModel*)0x878C40; +CColModel &CTempColModels::ms_colModelPanel1 = *(CColModel*)0x87BDD8; +CColModel &CTempColModels::ms_colModelBodyPart2 = *(CColModel*)0x87BE30; +CColModel &CTempColModels::ms_colModelBodyPart1 = *(CColModel*)0x87BE88; +CColModel &CTempColModels::ms_colModelCutObj = *(CColModel*)0x87C960; +CColModel &CTempColModels::ms_colModelPedGroundHit = *(CColModel*)0x880480; +CColModel &CTempColModels::ms_colModelBoot1 = *(CColModel*)0x880670; +CColModel &CTempColModels::ms_colModelDoor1 = *(CColModel*)0x880850; +CColModel &CTempColModels::ms_colModelBonnet1 = *(CColModel*)0x8808A8; diff --git a/src/core/TempColModels.h b/src/core/TempColModels.h new file mode 100644 index 00000000..8ac74428 --- /dev/null +++ b/src/core/TempColModels.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Collision.h" + +class CTempColModels +{ +public: + static CColModel &ms_colModelPed1; + static CColModel &ms_colModelPed2; + static CColModel &ms_colModelBBox; + static CColModel &ms_colModelBumper1; + static CColModel &ms_colModelWheel1; + static CColModel &ms_colModelPanel1; + static CColModel &ms_colModelBodyPart2; + static CColModel &ms_colModelBodyPart1; + static CColModel &ms_colModelCutObj; + static CColModel &ms_colModelPedGroundHit; + static CColModel &ms_colModelBoot1; + static CColModel &ms_colModelDoor1; + static CColModel &ms_colModelBonnet1; +}; diff --git a/src/core/Text.cpp b/src/core/Text.cpp new file mode 100644 index 00000000..d7d63467 --- /dev/null +++ b/src/core/Text.cpp @@ -0,0 +1,232 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "Frontend.h" +#include "Messages.h" +#include "Text.h" + +static wchar WideErrorString[25]; + +CText &TheText = *(CText*)0x941520; + +CText::CText(void) +{ + keyArray.entries = nil; + keyArray.numEntries = 0; + data.chars = nil; + data.numChars = 0; + encoding = 101; + memset(WideErrorString, 0, sizeof(WideErrorString)); +} + +CText::~CText(void) +{ + data.Unload(); + keyArray.Unload(); +} + +void +CText::Load(void) +{ + uint8 *filedata; + char filename[32], type[4]; + int length; + int offset, sectlen; + + Unload(); + filedata = new uint8[0x40000]; + + CFileMgr::SetDir("TEXT"); + switch(CMenuManager::m_PrefsLanguage){ + case LANGUAGE_AMERICAN: + sprintf(filename, "AMERICAN.GXT"); + break; + case LANGUAGE_FRENCH: + sprintf(filename, "FRENCH.GXT"); + break; + case LANGUAGE_GERMAN: + sprintf(filename, "GERMAN.GXT"); + break; + case LANGUAGE_ITALIAN: + sprintf(filename, "ITALIAN.GXT"); + break; + case LANGUAGE_SPANISH: + sprintf(filename, "SPANISH.GXT"); + break; + } + + length = CFileMgr::LoadFile(filename, filedata, 0x40000, "rb"); + CFileMgr::SetDir(""); + + offset = 0; + while(offset < length){ + type[0] = filedata[offset++]; + type[1] = filedata[offset++]; + type[2] = filedata[offset++]; + type[3] = filedata[offset++]; + sectlen = (int)filedata[offset+3]<<24 | (int)filedata[offset+2]<<16 | + (int)filedata[offset+1]<<8 | (int)filedata[offset+0]; + offset += 4; + if(sectlen != 0){ + if(strncmp(type, "TKEY", 4) == 0) + keyArray.Load(sectlen, filedata, &offset); + else if(strncmp(type, "TDAT", 4) == 0) + data.Load(sectlen, filedata, &offset); + else + offset += sectlen; + } + } + + keyArray.Update(data.chars); + + delete[] filedata; +} + +void +CText::Unload(void) +{ + CMessages::ClearAllMessagesDisplayedByGame(); + data.Unload(); + keyArray.Unload(); +} + +wchar* +CText::Get(const char *key) +{ + return keyArray.Search(key); +} + +wchar +CText::GetUpperCase(wchar c) +{ + // TODO: do this depending on encoding + if(islower(c)) + return toupper(c); + return c; +} + +void +CText::UpperCase(wchar *s) +{ + while(*s){ + *s = GetUpperCase(*s); + s++; + } +} + + +void +CKeyArray::Load(uint32 length, uint8 *data, int *offset) +{ + uint32 i; + uint8 *rawbytes; + + numEntries = length / sizeof(CKeyEntry); + entries = new CKeyEntry[numEntries]; + rawbytes = (uint8*)entries; + + for(i = 0; i < length; i++) + rawbytes[i] = data[(*offset)++]; +} + +void +CKeyArray::Unload(void) +{ + delete[] entries; + entries = nil; + numEntries = 0; +} + +void +CKeyArray::Update(wchar *chars) +{ + int i; + for(i = 0; i < numEntries; i++) + entries[i].value = (wchar*)((uint8*)chars + (uintptr)entries[i].value); +} + +CKeyEntry* +CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) +{ + int mid; + int diff; + + if(low > high) + return nil; + + mid = (low + high)/2; + diff = strcmp(key, entries[mid].key); + if(diff == 0) + return &entries[mid]; + if(diff < 0) + return BinarySearch(key, entries, low, mid-1); + if(diff > 0) + return BinarySearch(key, entries, mid+1, high); + return nil; +} + +wchar* +CKeyArray::Search(const char *key) +{ + CKeyEntry *found; + char errstr[25]; + int i; + + found = BinarySearch(key, entries, 0, numEntries-1); + if(found) + return found->value; + sprintf(errstr, "%s missing", key); + for(i = 0; i < 25; i++) + WideErrorString[i] = errstr[i]; + return WideErrorString; +} + + +void +CData::Load(uint32 length, uint8 *data, int *offset) +{ + uint32 i; + uint8 *rawbytes; + + numChars = length / sizeof(wchar); + chars = new wchar[numChars]; + rawbytes = (uint8*)chars; + + for(i = 0; i < length; i++) + rawbytes[i] = data[(*offset)++]; +} + +void +CData::Unload(void) +{ + delete[] chars; + chars = nil; + numChars = 0; +} + +void +AsciiToUnicode(const char *src, uint16 *dst) +{ + while((*dst++ = *src++) != '\0'); +} + +void +TextCopy(wchar *dst, const wchar *src) +{ + while((*dst++ = *src++) != '\0'); +} + +STARTPATCHES + InjectHook(0x52C3C0, &CText::Load, PATCH_JUMP); + InjectHook(0x52C580, &CText::Unload, PATCH_JUMP); + InjectHook(0x52C5A0, &CText::Get, PATCH_JUMP); + + InjectHook(0x52BE70, &CKeyArray::Load, PATCH_JUMP); + InjectHook(0x52BF60, &CKeyArray::Unload, PATCH_JUMP); + InjectHook(0x52BF80, &CKeyArray::Update, PATCH_JUMP); + InjectHook(0x52C060, &CKeyArray::BinarySearch, PATCH_JUMP); + InjectHook(0x52BFB0, &CKeyArray::Search, PATCH_JUMP); + + InjectHook(0x52C120, &CData::Load, PATCH_JUMP); + InjectHook(0x52C200, &CData::Unload, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Text.h b/src/core/Text.h new file mode 100644 index 00000000..2592e6b8 --- /dev/null +++ b/src/core/Text.h @@ -0,0 +1,52 @@ +#pragma once + +void AsciiToUnicode(const char *src, wchar *dst); +void TextCopy(wchar *dst, const wchar *src); + +struct CKeyEntry +{ + wchar *value; + char key[8]; +}; +// If this fails, CKeyArray::Load will have to be fixed +static_assert(sizeof(CKeyEntry) == 12, "CKeyEntry: error"); + +class CKeyArray +{ +public: + CKeyEntry *entries; + int numEntries; + + void Load(uint32 length, uint8 *data, int *offset); + void Unload(void); + void Update(wchar *chars); + CKeyEntry *BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high); + wchar *Search(const char *key); +}; + +class CData +{ +public: + wchar *chars; + int numChars; + + void Load(uint32 length, uint8 *data, int *offset); + void Unload(void); +}; + +class CText +{ + CKeyArray keyArray; + CData data; + int8 encoding; +public: + CText(void); + ~CText(void); + void Load(void); + void Unload(void); + wchar *Get(const char *key); + wchar GetUpperCase(wchar c); + void UpperCase(wchar *s); +}; + +extern CText &TheText; diff --git a/src/core/Timer.cpp b/src/core/Timer.cpp new file mode 100644 index 00000000..543f582b --- /dev/null +++ b/src/core/Timer.cpp @@ -0,0 +1,235 @@ +#include +#include "common.h" +#include "patcher.h" +#include "DMAudio.h" +#include "Record.h" +#include "Timer.h" + +uint32 &CTimer::m_snTimeInMilliseconds = *(uint32*)0x885B48; +uint32 &CTimer::m_snTimeInMillisecondsPauseMode = *(uint32*)0x5F7614; +uint32 &CTimer::m_snTimeInMillisecondsNonClipped = *(uint32*)0x9412E8; +uint32 &CTimer::m_snPreviousTimeInMilliseconds = *(uint32*)0x8F29E4; +uint32 &CTimer::m_FrameCounter = *(uint32*)0x9412EC; +float &CTimer::ms_fTimeScale = *(float*)0x8F2C20; +float &CTimer::ms_fTimeStep = *(float*)0x8E2CB4; +float &CTimer::ms_fTimeStepNonClipped = *(float*)0x8E2C4C; +bool &CTimer::m_UserPause = *(bool*)0x95CD7C; +bool &CTimer::m_CodePause = *(bool*)0x95CDB1; + +//UInt32 oldPcTimer; +uint32 &oldPcTimer = *(uint32*)0x9434F4; + +//UInt32 suspendPcTimer; +uint32 &suspendPcTimer = *(uint32*)0x62A308; + +//UInt32 _nCyclesPerMS = 1; +uint32 &_nCyclesPerMS = *(uint32*)0x5F7610; + +//LARGE_INTEGER _oldPerfCounter; +LARGE_INTEGER &_oldPerfCounter = *(LARGE_INTEGER*)0x62A310; + +//LARGE_INTEGER perfSuspendCounter; +LARGE_INTEGER &perfSuspendCounter = *(LARGE_INTEGER*)0x62A318; + +//UInt32 suspendDepth; +uint32 &suspendDepth = *(uint32*)0x62A320; + +void CTimer::Initialise(void) +{ + debug("Initialising CTimer...\n"); + + ms_fTimeScale = 1.0f; + ms_fTimeStep = 1.0f; + suspendDepth = 0; + m_UserPause = false; + m_CodePause = false; + m_snTimeInMillisecondsNonClipped = 0; + m_snPreviousTimeInMilliseconds = 0; + m_snTimeInMilliseconds = 1; + + LARGE_INTEGER perfFreq; + if ( QueryPerformanceFrequency(&perfFreq) ) + { + OutputDebugString("Performance counter available\n"); + _nCyclesPerMS = uint32(perfFreq.QuadPart / 1000); + QueryPerformanceCounter(&_oldPerfCounter); + } + else + { + OutputDebugString("Performance counter not available, using millesecond timer\n"); + _nCyclesPerMS = 0; + oldPcTimer = RsTimer(); + } + + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds; + + m_FrameCounter = 0; + + DMAudio.ResetTimers(m_snPreviousTimeInMilliseconds); + + debug("CTimer ready\n"); +} + +void CTimer::Shutdown(void) +{ + ; +} + +#if 1 +WRAPPER void CTimer::Update(void) { EAXJMP(0x4ACF70); } +#else +void CTimer::Update(void) +{ + m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; + + if ( (double)_nCyclesPerMS != 0.0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + + int32 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; + + _oldPerfCounter = pc; + + double updInCyclesScaled = (double)updInCycles * ms_fTimeScale; + + double upd = updInCyclesScaled / (double)_nCyclesPerMS; + + m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd); + + if ( GetIsPaused() ) + ms_fTimeStep = 0.0f; + else + { + m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd); + m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd); + ms_fTimeStep = updInCyclesScaled / (double)_nCyclesPerMS / 20.0; + } + } + else + { + uint32 timer = RsTimer(); + + uint32 updInMs = timer - oldPcTimer; + + double upd = (double)updInMs * ms_fTimeScale; + + oldPcTimer = timer; + + m_snTimeInMillisecondsPauseMode = (Int64)(m_snTimeInMillisecondsPauseMode + upd); + + if ( GetIsPaused() ) + ms_fTimeStep = 0.0f; + else + { + m_snTimeInMilliseconds = (Int64)(m_snTimeInMilliseconds + upd); + m_snTimeInMillisecondsNonClipped = (Int64)(m_snTimeInMillisecondsNonClipped + upd); + ms_fTimeStep = upd / 1000.0f * 50.0f; + } + } + + if ( ms_fTimeStep < 0.01f && !GetIsPaused() ) + ms_fTimeStep = 0.01f; + + ms_fTimeStepNonClipped = ms_fTimeStep; + + if ( CRecordDataForGame::RecordingState != RECORDSTATE_2 ) + { + ms_fTimeStep = min(3.0f, ms_fTimeStep); + + if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 ) + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60; + } + + if ( CRecordDataForChase::Status == RECORDSTATE_1 ) + { + ms_fTimeStep = 1.0f; + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16; + } + + m_FrameCounter++; +} +#endif + +void CTimer::Suspend(void) +{ + if ( ++suspendDepth > 1 ) + return; + + if ( (double)_nCyclesPerMS != 0.0 ) + QueryPerformanceCounter(&perfSuspendCounter); + else + suspendPcTimer = RsTimer(); +} + +void CTimer::Resume(void) +{ + if ( --suspendDepth != 0 ) + return; + + if ( (double)_nCyclesPerMS != 0.0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + + _oldPerfCounter.LowPart += pc.LowPart - perfSuspendCounter.LowPart; + } + else + oldPcTimer += RsTimer() - suspendPcTimer; +} + +uint32 CTimer::GetCyclesPerMillisecond(void) +{ + if (_nCyclesPerMS != 0) + return _nCyclesPerMS; + else + return 1; +} + +uint32 CTimer::GetCurrentTimeInCycles(void) +{ + if ( _nCyclesPerMS != 0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + return (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; + } + else + return RsTimer() - oldPcTimer; +} + +bool CTimer::GetIsSlowMotionActive(void) +{ + return ms_fTimeScale < 1.0f; +} + +void CTimer::Stop(void) +{ + m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; +} + +void CTimer::StartUserPause(void) +{ + m_UserPause = true; +} + +void CTimer::EndUserPause(void) +{ + m_UserPause = false; +} + +#if 0 +STARTPATCHES + InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP); + InjectHook(0x4ACF60, CTimer::Shutdown, PATCH_JUMP); + InjectHook(0x4ACF70, CTimer::Update, PATCH_JUMP); + InjectHook(0x4AD310, CTimer::Suspend, PATCH_JUMP); + InjectHook(0x4AD370, CTimer::Resume, PATCH_JUMP); + InjectHook(0x4AD3F0, CTimer::GetCyclesPerMillisecond, PATCH_JUMP); + InjectHook(0x4AD410, CTimer::GetCurrentTimeInCycles, PATCH_JUMP); + InjectHook(0x4AD450, CTimer::GetIsSlowMotionActive, PATCH_JUMP); + InjectHook(0x4AD480, CTimer::Stop, PATCH_JUMP); + InjectHook(0x4AD490, CTimer::StartUserPause, PATCH_JUMP); + InjectHook(0x4AD4A0, CTimer::EndUserPause, PATCH_JUMP); +ENDPATCHES +#endif diff --git a/src/core/Timer.h b/src/core/Timer.h new file mode 100644 index 00000000..9e6d447e --- /dev/null +++ b/src/core/Timer.h @@ -0,0 +1,51 @@ +#pragma once + +class CTimer +{ + static uint32 &m_snTimeInMilliseconds; + static uint32 &m_snTimeInMillisecondsPauseMode; + static uint32 &m_snTimeInMillisecondsNonClipped; + static uint32 &m_snPreviousTimeInMilliseconds; + static uint32 &m_FrameCounter; + static float &ms_fTimeScale; + static float &ms_fTimeStep; + static float &ms_fTimeStepNonClipped; + static bool &m_UserPause; + static bool &m_CodePause; +public: + static float GetTimeStep(void) { return ms_fTimeStep; } + static void SetTimeStep(float ts) { ms_fTimeStep = ts; } + static float GetTimeStepInSeconds() { return ms_fTimeStep / 50.0f; } + static float GetTimeStepInMilliseconds() { return ms_fTimeStep / 50.0f * 1000.0f; } + static float GetTimeStepNonClipped(void) { return ms_fTimeStepNonClipped; } + static float GetTimeStepNonClippedInSeconds(void) { return ms_fTimeStepNonClipped / 50.0f; } + static void SetTimeStepNonClipped(float ts) { ms_fTimeStepNonClipped = ts; } + static uint32 GetFrameCounter(void) { return m_FrameCounter; } + static void SetFrameCounter(uint32 fc) { m_FrameCounter = fc; } + static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } + static void SetTimeInMilliseconds(uint32 t) { m_snTimeInMilliseconds = t; } + static uint32 GetTimeInMillisecondsNonClipped(void) { return m_snTimeInMillisecondsNonClipped; } + static void SetTimeInMillisecondsNonClipped(uint32 t) { m_snTimeInMillisecondsNonClipped = t; } + static uint32 GetTimeInMillisecondsPauseMode(void) { return m_snTimeInMillisecondsPauseMode; } + static void SetTimeInMillisecondsPauseMode(uint32 t) { m_snTimeInMillisecondsPauseMode = t; } + static uint32 GetPreviousTimeInMilliseconds(void) { return m_snPreviousTimeInMilliseconds; } + static void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; } + static float GetTimeScale(void) { return ms_fTimeScale; } + static void SetTimeScale(float ts) { ms_fTimeScale = ts; } + + static bool GetIsPaused() { return m_UserPause || m_CodePause; } + static bool GetIsUserPaused() { return m_UserPause; } + static void SetCodePause(bool pause) { m_CodePause = pause; } + + static void Initialise(void); + static void Shutdown(void); + static void Update(void); + static void Suspend(void); + static void Resume(void); + static uint32 GetCyclesPerMillisecond(void); + static uint32 GetCurrentTimeInCycles(void); + static bool GetIsSlowMotionActive(void); + static void Stop(void); + static void StartUserPause(void); + static void EndUserPause(void); +}; diff --git a/src/core/TxdStore.cpp b/src/core/TxdStore.cpp new file mode 100644 index 00000000..5085c7e4 --- /dev/null +++ b/src/core/TxdStore.cpp @@ -0,0 +1,208 @@ +#include "common.h" +#include "patcher.h" +#include "templates.h" +#include "Streaming.h" +#include "RwHelper.h" +#include "TxdStore.h" + +CPool *&CTxdStore::ms_pTxdPool = *(CPool**)0x8F5FB8; +RwTexDictionary *&CTxdStore::ms_pStoredTxd = *(RwTexDictionary**)0x9405BC; + +void +CTxdStore::Initialize(void) +{ + if(ms_pTxdPool == nil) + ms_pTxdPool = new CPool(TXDSTORESIZE); +} + +void +CTxdStore::Shutdown(void) +{ + if(ms_pTxdPool) + delete ms_pTxdPool; +} + +void +CTxdStore::GameShutdown(void) +{ + int i; + + for(i = 0; i < TXDSTORESIZE; i++){ + TxdDef *def = GetSlot(i); + if(def && GetNumRefs(i) == 0) + RemoveTxdSlot(i); + } +} + +int +CTxdStore::AddTxdSlot(const char *name) +{ + TxdDef *def = ms_pTxdPool->New(); + assert(def); + def->texDict = nil; + def->refCount = 0; + strcpy(def->name, name); + return ms_pTxdPool->GetJustIndex(def); +} + +void +CTxdStore::RemoveTxdSlot(int slot) +{ + TxdDef *def = GetSlot(slot); + if(def->texDict) + RwTexDictionaryDestroy(def->texDict); + ms_pTxdPool->Delete(def); +} + +int +CTxdStore::FindTxdSlot(const char *name) +{ + char *defname; + int size = ms_pTxdPool->GetSize(); + for(int i = 0; i < size; i++){ + defname = GetTxdName(i); + if(defname && _strcmpi(defname, name) == 0) + return i; + } + return -1; +} + +char* +CTxdStore::GetTxdName(int slot) +{ + TxdDef *def = GetSlot(slot); + return def ? def->name : nil; +} + +void +CTxdStore::PushCurrentTxd(void) +{ + ms_pStoredTxd = RwTexDictionaryGetCurrent(); +} + +void +CTxdStore::PopCurrentTxd(void) +{ + RwTexDictionarySetCurrent(ms_pStoredTxd); + ms_pStoredTxd = nil; +} + +void +CTxdStore::SetCurrentTxd(int slot) +{ + TxdDef *def = GetSlot(slot); + if(def) + RwTexDictionarySetCurrent(def->texDict); +} + +void +CTxdStore::Create(int slot) +{ + GetSlot(slot)->texDict = RwTexDictionaryCreate(); +} + +int +CTxdStore::GetNumRefs(int slot) +{ + return GetSlot(slot)->refCount; +} + +void +CTxdStore::AddRef(int slot) +{ + GetSlot(slot)->refCount++; +} + +void +CTxdStore::RemoveRef(int slot) +{ + if(--GetSlot(slot)->refCount <= 0) + CStreaming::RemoveModel(slot + STREAM_OFFSET_TXD); +} + +void +CTxdStore::RemoveRefWithoutDelete(int slot) +{ + GetSlot(slot)->refCount--; +} + +bool +CTxdStore::LoadTxd(int slot, RwStream *stream) +{ + TxdDef *def = GetSlot(slot); + + if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){ + def->texDict = RwTexDictionaryGtaStreamRead(stream); + return def->texDict != nil; + } + printf("Failed to load TXD\n"); + return false; +} + +bool +CTxdStore::LoadTxd(int slot, const char *filename) +{ + RwStream *stream; + bool ret; + + ret = false; + _rwD3D8TexDictionaryEnableRasterFormatConversion(true); + do + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); + while(stream == nil); + ret = LoadTxd(slot, stream); + RwStreamClose(stream, nil); + return ret; +} + +bool +CTxdStore::StartLoadTxd(int slot, RwStream *stream) +{ + TxdDef *def = GetSlot(slot); + if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, nil, nil)){ + def->texDict = RwTexDictionaryGtaStreamRead1(stream); + return def->texDict != nil; + }else{ + printf("Failed to load TXD\n"); + return false; + } +} + +bool +CTxdStore::FinishLoadTxd(int slot, RwStream *stream) +{ + TxdDef *def = GetSlot(slot); + def->texDict = RwTexDictionaryGtaStreamRead2(stream, def->texDict); + return def->texDict != nil; +} + +void +CTxdStore::RemoveTxd(int slot) +{ + TxdDef *def = GetSlot(slot); + if(def->texDict) + RwTexDictionaryDestroy(def->texDict); + def->texDict = nil; +} + +STARTPATCHES + InjectHook(0x527440, CTxdStore::Initialize, PATCH_JUMP); + InjectHook(0x527470, CTxdStore::Shutdown, PATCH_JUMP); + InjectHook(0x527490, CTxdStore::GameShutdown, PATCH_JUMP); + InjectHook(0x5274E0, CTxdStore::AddTxdSlot, PATCH_JUMP); + InjectHook(0x5275D0, CTxdStore::FindTxdSlot, PATCH_JUMP); + InjectHook(0x527590, CTxdStore::GetTxdName, PATCH_JUMP); + InjectHook(0x527900, CTxdStore::PushCurrentTxd, PATCH_JUMP); + InjectHook(0x527910, CTxdStore::PopCurrentTxd, PATCH_JUMP); + InjectHook(0x5278C0, CTxdStore::SetCurrentTxd, PATCH_JUMP); + InjectHook(0x527830, CTxdStore::Create, PATCH_JUMP); + InjectHook(0x527A00, CTxdStore::GetNumRefs, PATCH_JUMP); + InjectHook(0x527930, CTxdStore::AddRef, PATCH_JUMP); + InjectHook(0x527970, CTxdStore::RemoveRef, PATCH_JUMP); + InjectHook(0x5279C0, CTxdStore::RemoveRefWithoutDelete, PATCH_JUMP); + InjectHook(0x527700, (bool (*)(int, RwStream*))CTxdStore::LoadTxd, PATCH_JUMP); + InjectHook(0x5276B0, (bool (*)(int, const char*))CTxdStore::LoadTxd, PATCH_JUMP); + InjectHook(0x527770, CTxdStore::StartLoadTxd, PATCH_JUMP); + InjectHook(0x5277E0, CTxdStore::FinishLoadTxd, PATCH_JUMP); + InjectHook(0x527870, CTxdStore::RemoveTxd, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/TxdStore.h b/src/core/TxdStore.h new file mode 100644 index 00000000..a9e57d31 --- /dev/null +++ b/src/core/TxdStore.h @@ -0,0 +1,44 @@ +#pragma once + +#include "templates.h" + +struct TxdDef { + RwTexDictionary *texDict; + int refCount; + char name[20]; +}; + +class CTxdStore +{ + static CPool *&ms_pTxdPool; + static RwTexDictionary *&ms_pStoredTxd; +public: + static void Initialize(void); + static void Shutdown(void); + static void GameShutdown(void); + static int AddTxdSlot(const char *name); + static void RemoveTxdSlot(int slot); + static int FindTxdSlot(const char *name); + static char *GetTxdName(int slot); + static void PushCurrentTxd(void); + static void PopCurrentTxd(void); + static void SetCurrentTxd(int slot); + static void Create(int slot); + static int GetNumRefs(int slot); + static void AddRef(int slot); + static void RemoveRef(int slot); + static void RemoveRefWithoutDelete(int slot); + static bool LoadTxd(int slot, RwStream *stream); + static bool LoadTxd(int slot, const char *filename); + static bool StartLoadTxd(int slot, RwStream *stream); + static bool FinishLoadTxd(int slot, RwStream *stream); + static void RemoveTxd(int slot); + + static TxdDef *GetSlot(int slot) { + assert(slot >= 0); + assert(ms_pTxdPool); + assert(slot < ms_pTxdPool->GetSize()); + return ms_pTxdPool->GetSlot(slot); + } + static bool isTxdLoaded(int slot); +}; diff --git a/src/core/User.cpp b/src/core/User.cpp new file mode 100644 index 00000000..c9cb97cc --- /dev/null +++ b/src/core/User.cpp @@ -0,0 +1,176 @@ +#include "common.h" +#include "patcher.h" + +#include "DMAudio.h" +#include "Hud.h" +#include "Replay.h" +#include "Timer.h" +#include "Script.h" +#include "User.h" + +CPlaceName& CUserDisplay::PlaceName = *(CPlaceName*)0x8F29BC; +COnscreenTimer& CUserDisplay::OnscnTimer = *(COnscreenTimer*)0x862238; +CPager& CUserDisplay::Pager = *(CPager*)0x8F2744; +CCurrentVehicle& CUserDisplay::CurrentVehicle = *(CCurrentVehicle*)0x8F5FE8; + +void COnscreenTimer::Init() { + m_bDisabled = false; + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + m_sEntries[i].m_nTimerOffset = 0; + m_sEntries[i].m_nCounterOffset = 0; + + for(uint32 j = 0; j < 10; j++) { + m_sEntries[i].m_aTimerText[j] = 0; + m_sEntries[i].m_aCounterText[j] = 0; + } + + m_sEntries[i].m_nType = 0; + m_sEntries[i].m_bTimerProcessed = 0; + m_sEntries[i].m_bCounterProcessed = 0; + } +} + +void COnscreenTimer::Process() { + if(!CReplay::IsPlayingBack() && !m_bDisabled) { + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + m_sEntries[i].Process(); + } + } +} + +void COnscreenTimer::ProcessForDisplay() { + if(CHud::m_Wants_To_Draw_Hud) { + m_bProcessed = false; + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + if(m_sEntries[i].ProcessForDisplay()) { + m_bProcessed = true; + } + } + } +} + +void COnscreenTimer::ClearCounter(uint32 offset) { + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + if(offset == m_sEntries[i].m_nCounterOffset) { + m_sEntries[i].m_nCounterOffset = 0; + m_sEntries[i].m_aCounterText[0] = 0; + m_sEntries[i].m_nType = 0; + m_sEntries[i].m_bCounterProcessed = 0; + } + } +} + +void COnscreenTimer::ClearClock(uint32 offset) { + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + if(offset == m_sEntries[i].m_nTimerOffset) { + m_sEntries[i].m_nTimerOffset = 0; + m_sEntries[i].m_aTimerText[0] = 0; + m_sEntries[i].m_bTimerProcessed = 0; + } + } +} + +void COnscreenTimer::AddCounter(uint32 offset, uint16 type, char* text) { + uint32 i = 0; + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + if(m_sEntries[i].m_nCounterOffset == 0) { + break; + } + return; + } + + m_sEntries[i].m_nCounterOffset = offset; + if(text) { + strncpy(m_sEntries[i].m_aCounterText, text, 10); + } else { + m_sEntries[i].m_aCounterText[0] = 0; + } + + m_sEntries[i].m_nType = type; +} + +void COnscreenTimer::AddClock(uint32 offset, char* text) { + uint32 i = 0; + for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { + if(m_sEntries[i].m_nTimerOffset == 0) { + break; + } + return; + } + + m_sEntries[i].m_nTimerOffset = offset; + if(text) { + strncpy(m_sEntries[i].m_aTimerText, text, 10); + } else { + m_sEntries[i].m_aTimerText[0] = 0; + } +} + +void COnscreenTimerEntry::Process() { + if(m_nTimerOffset == 0) { + return; + } + + uint32* timerPtr = (uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset]; + uint32 oldTime = *timerPtr; + int32 newTime = int32(oldTime - uint32(20.0f * CTimer::GetTimeStep())); + if(newTime < 0) { + *timerPtr = 0; + m_bTimerProcessed = 0; + m_nTimerOffset = 0; + m_aTimerText[0] = 0; + } else { + *timerPtr = (uint32)newTime; + uint32 oldTimeSeconds = oldTime / 1000; + if(oldTimeSeconds <= 11 && newTime / 1000 != oldTimeSeconds) { + // TODO: use an enum here + DMAudio.PlayFrontEndSound(0x93, newTime / 1000); + } + } +} + +bool COnscreenTimerEntry::ProcessForDisplay() { + m_bTimerProcessed = false; + m_bCounterProcessed = false; + + if(m_nTimerOffset == 0 && m_nCounterOffset == 0) { + return false; + } + + if(m_nTimerOffset != 0) { + m_bTimerProcessed = true; + ProcessForDisplayTimer(); + } + + if(m_nCounterOffset != 0) { + m_bCounterProcessed = true; + ProcessForDisplayCounter(); + } + return true; +} + +int COnscreenTimerEntry::ProcessForDisplayTimer() { + uint32 time = *(uint32*)&CTheScripts::ScriptSpace[m_nTimerOffset]; + return sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60, + time / 1000 % 60); +} + +int COnscreenTimerEntry::ProcessForDisplayCounter() { + uint32 counter = *(uint32*)&CTheScripts::ScriptSpace[m_nCounterOffset]; + return sprintf(m_bCounterBuffer, "%d", counter); +} + +STARTPATCHES + InjectHook(0x429160, &COnscreenTimerEntry::Process, PATCH_JUMP); + InjectHook(0x429110, &COnscreenTimerEntry::ProcessForDisplay, PATCH_JUMP); + InjectHook(0x429080, &COnscreenTimerEntry::ProcessForDisplayTimer, PATCH_JUMP); + InjectHook(0x4290F0, &COnscreenTimerEntry::ProcessForDisplayCounter, PATCH_JUMP); + + InjectHook(0x429220, &COnscreenTimer::Init, PATCH_JUMP); + InjectHook(0x429320, &COnscreenTimer::Process, PATCH_JUMP); + InjectHook(0x4292E0, &COnscreenTimer::ProcessForDisplay, PATCH_JUMP); + InjectHook(0x429450, &COnscreenTimer::ClearCounter, PATCH_JUMP); + InjectHook(0x429410, &COnscreenTimer::ClearClock, PATCH_JUMP); + InjectHook(0x4293B0, &COnscreenTimer::AddCounter, PATCH_JUMP); + InjectHook(0x429350, &COnscreenTimer::AddClock, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/User.h b/src/core/User.h new file mode 100644 index 00000000..8b744c7e --- /dev/null +++ b/src/core/User.h @@ -0,0 +1,64 @@ +#pragma once + +class COnscreenTimerEntry +{ +public: + uint32 m_nTimerOffset; + uint32 m_nCounterOffset; + char m_aTimerText[10]; + char m_aCounterText[10]; + uint16 m_nType; + char m_bCounterBuffer[42]; + char m_bTimerBuffer[42]; + bool m_bTimerProcessed; + bool m_bCounterProcessed; + + void Process(); + bool ProcessForDisplay(); + + int ProcessForDisplayTimer(); + int ProcessForDisplayCounter(); +}; + +static_assert(sizeof(COnscreenTimerEntry) == 0x74, "COnscreenTimerEntry: error"); + +class COnscreenTimer +{ +public: + COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES]; + bool m_bProcessed; + bool m_bDisabled; + + void Init(); + void Process(); + void ProcessForDisplay(); + + void ClearCounter(uint32 offset); + void ClearClock(uint32 offset); + + void AddCounter(uint32 offset, uint16 type, char* text); + void AddClock(uint32 offset, char* text); +}; + +static_assert(sizeof(COnscreenTimer) == 0x78, "COnscreenTimer: error"); + +class CPlaceName +{ +}; + +class CCurrentVehicle +{ +}; + +class CPager +{ +}; + +class CUserDisplay +{ +public: + static CPlaceName &PlaceName; + static COnscreenTimer &OnscnTimer; + static CPager &Pager; + static CCurrentVehicle &CurrentVehicle; +}; diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp new file mode 100644 index 00000000..ece68e64 --- /dev/null +++ b/src/core/Wanted.cpp @@ -0,0 +1,36 @@ +#include "common.h" +#include "patcher.h" +#include "Wanted.h" + +bool CWanted::AreSwatRequired() +{ + return m_nWantedLevel >= 4; +} + +bool CWanted::AreFbiRequired() +{ + return m_nWantedLevel >= 5; +} + +bool CWanted::AreArmyRequired() +{ + return m_nWantedLevel >= 6; +} + +int CWanted::NumOfHelisRequired() +{ + if (m_IsIgnoredByCops) + return 0; + + // Return value is number of helicopters, no need to name them. + switch (m_nWantedLevel) { + case WANTEDLEVEL_3: + case WANTEDLEVEL_4: + return 1; + case WANTEDLEVEL_5: + case WANTEDLEVEL_6: + return 2; + default: + return 0; + }; +} \ No newline at end of file diff --git a/src/core/Wanted.h b/src/core/Wanted.h new file mode 100644 index 00000000..aafa9ac0 --- /dev/null +++ b/src/core/Wanted.h @@ -0,0 +1,45 @@ +#pragma once +#include "Entity.h" +#include "math/Vector.h" +#include "CopPed.h" + +enum eWantedLevel { + NOTWANTED, + WANTEDLEVEL_1, + WANTEDLEVEL_2, + WANTEDLEVEL_3, + WANTEDLEVEL_4, + WANTEDLEVEL_5, + WANTEDLEVEL_6, +}; + +class CWanted +{ +public: + int32 m_nChaos; + int32 m_nLastUpdateTime; + int32 m_nLastWantedLevelChange; + float m_fCrimeSensitivity; + uint8 m_bCurrentCops; + uint8 m_bMaxCops; + uint8 m_bMaximumLawEnforcerVehicles; + int8 field_19; + int16 m_wRoadblockDensity; + uint8 m_IsIgnoredByCops : 1; + uint8 m_IsIgnoredByEveryOne : 1; + uint8 m_IsSwatRequired : 1; + uint8 m_IsFbiRequired : 1; + uint8 m_IdArmyRequired : 1; + int8 field_23; + int32 m_nWantedLevel; + CCrime m_sCrimes[16]; + CCopPed *m_pCops[10]; + +public: + bool AreSwatRequired(); + bool AreFbiRequired(); + bool AreArmyRequired(); + int NumOfHelisRequired(); +}; + +static_assert(sizeof(CWanted) == 0x204, "CWanted: error"); diff --git a/src/core/World.cpp b/src/core/World.cpp new file mode 100644 index 00000000..538e15c5 --- /dev/null +++ b/src/core/World.cpp @@ -0,0 +1,718 @@ +#include "common.h" +#include "patcher.h" +#include "Entity.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "Vehicle.h" +#include "Object.h" +#include "Camera.h" +#include "DMAudio.h" +#include "CarCtrl.h" +#include "Garages.h" +#include "TempColModels.h" +#include "World.h" + +CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; +CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; +CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; +uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64; + +uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61; +CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0; +bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC; +CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494; +bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F; +bool &CWorld::bSecondShift = *(bool*)0x95CD54; +bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C; +bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; + +void +CWorld::Add(CEntity *ent) +{ + if(ent->IsVehicle() || ent->IsPed()) + DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, true); + + if(ent->bIsBIGBuilding) + ms_bigBuildingsList[ent->m_level].InsertItem(ent); + else + ent->Add(); + + if(ent->IsBuilding() || ent->IsDummy()) + return; + + if(!ent->bIsStatic) + ((CPhysical*)ent)->AddToMovingList(); +} + +void +CWorld::Remove(CEntity *ent) +{ + if(ent->IsVehicle() || ent->IsPed()) + DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, false); + + if(ent->bIsBIGBuilding) + ms_bigBuildingsList[ent->m_level].RemoveItem(ent); + else + ent->Remove(); + + if(ent->IsBuilding() || ent->IsDummy()) + return; + + if(!ent->bIsStatic) + ((CPhysical*)ent)->RemoveFromMovingList(); +} + +void +CWorld::ClearScanCodes(void) +{ + CPtrNode *node; + for(int i = 0; i < NUMSECTORS_Y; i++) + for(int j = 0; j < NUMSECTORS_X; j++){ + CSector *s = &ms_aSectors[i][j]; + for(node = s->m_lists[ENTITYLIST_BUILDINGS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_VEHICLES].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_PEDS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_OBJECTS].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + for(node = s->m_lists[ENTITYLIST_DUMMIES].first; node; node = node->next) + ((CEntity*)node->item)->m_scanCode = 0; + } +} + +bool +CWorld::CameraToIgnoreThisObject(CEntity *ent) +{ + if(CGarages::IsModelIndexADoor(ent->GetModelIndex())) + return false; + return ((CObject*)ent)->m_bCameraToAvoidThisObject != 1; +} + +bool +CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + int x, xstart, xend; + int y, ystart, yend; + int y1, y2; + float dist; + + AdvanceCurrentScanCode(); + + entity = nil; + dist = 1.0f; + + xstart = GetSectorIndexX(point1.x); + ystart = GetSectorIndexX(point1.y); + xend = GetSectorIndexX(point2.x); + yend = GetSectorIndexX(point2.y); + +#define LOSARGS CColLine(point1, point2), point, dist, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects + + if(xstart == xend && ystart == yend){ + // Only one sector + return ProcessLineOfSightSector(*GetSector(xstart, ystart), LOSARGS); + }else if(xstart == xend){ + // Only step in y + if(ystart < yend) + for(y = ystart; y <= yend; y++) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + else + for(y = ystart; y >= yend; y--) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + return dist < 1.0f; + }else if(ystart == yend){ + // Only step in x + if(xstart < xend) + for(x = xstart; x <= xend; x++) + ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS); + else + for(x = xstart; x >= xend; x--) + ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS); + return dist < 1.0f; + }else{ + if(point1.x < point2.x){ + // Step from left to right + float m = (point2.y - point1.y) / (point2.x - point1.x); + + y1 = ystart; + y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y); + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + + for(x = xstart+1; x < xend; x++){ + y1 = y2; + y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y); + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); + } + + y1 = y2; + y2 = yend; + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); + }else{ + // Step from right to left + float m = (point2.y - point1.y) / (point2.x - point1.x); + + y1 = ystart; + y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y); + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS); + + for(x = xstart-1; x > xend; x--){ + y1 = y2; + y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y); + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(x, y), LOSARGS); + } + + y1 = y2; + y2 = yend; + if(y1 < y2) + for(y = y1; y <= y2; y++) + ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); + else + for(y = y1; y >= y2; y--) + ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS); + } + return dist < 1.0f; + } + +#undef LOSARGS +} + +bool +CWorld::ProcessLineOfSightSector(CSector §or, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + float mindist = dist; + bool deadPeds = !!bIncludeDeadPeds; + bIncludeDeadPeds = false; + + if(checkBuildings){ + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough); + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); + } + + if(checkVehicles){ + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough); + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); + } + + if(checkPeds){ + if(deadPeds) + bIncludeDeadPeds = true; + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough); + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); + bIncludeDeadPeds = false; + } + + if(checkObjects){ + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects); + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects); + } + + if(checkDummies){ + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough); + ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough); + } + + bIncludeDeadPeds = deadPeds; + + if(mindist < dist){ + dist = mindist; + return true; + }else + return false; +} + +bool +CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + bool deadPeds = false; + float mindist = dist; + CPtrNode *node; + CEntity *e; + CColModel *colmodel; + + if(list.first && bIncludeDeadPeds && ((CEntity*)list.first->item)->IsPed()) + deadPeds = true; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(e->m_scanCode != GetCurrentScanCode() && + e != pIgnoreEntity && + (e->bUsesCollision || deadPeds) && + !(ignoreSomeObjects && CameraToIgnoreThisObject(e))){ + colmodel = nil; + e->m_scanCode = GetCurrentScanCode(); + + if(e->IsPed()){ + if(e->bUsesCollision || + deadPeds && ((CPed*)e)->m_nPedState == PED_DEAD){ + if(((CPed*)e)->UseGroundColModel()) + colmodel = &CTempColModels::ms_colModelPedGroundHit; + else + colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(); + }else + colmodel = nil; + }else if(e->bUsesCollision) + colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); + + if(colmodel && + CCollision::ProcessLineOfSight(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough)) + entity = e; + } + } + + if(mindist < dist){ + dist = mindist; + return true; + }else + return false; +} + +bool +CWorld::ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ + AdvanceCurrentScanCode(); + CVector point2(point1.x, point1.y, z2); + return CWorld::ProcessVerticalLineSector(*GetSector(GetSectorIndexX(point1.x), GetSectorIndexX(point1.y)), + CColLine(point1, point2), point, entity, + checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, poly); +} + +bool +CWorld::ProcessVerticalLineSector(CSector §or, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ + float mindist = 1.0f; + + if(checkBuildings){ + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough, poly); + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); + } + + if(checkVehicles){ + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough, poly); + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); + } + + if(checkPeds){ + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough, poly); + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); + } + + if(checkObjects){ + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, poly); + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); + } + + if(checkDummies){ + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough, poly); + ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly); + } + + return mindist < 1.0f; +} + +bool +CWorld::ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ + float mindist = dist; + CPtrNode *node; + CEntity *e; + CColModel *colmodel; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(e->m_scanCode != GetCurrentScanCode() && + e->bUsesCollision){ + e->m_scanCode = GetCurrentScanCode(); + + colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); + if(CCollision::ProcessVerticalLine(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough, poly)) + entity = e; + } + } + + if(mindist < dist){ + dist = mindist; + return true; + }else + return false; +} + +bool +CWorld::GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + int x, xstart, xend; + int y, ystart, yend; + int y1, y2; + + AdvanceCurrentScanCode(); + + xstart = GetSectorIndexX(point1.x); + ystart = GetSectorIndexX(point1.y); + xend = GetSectorIndexX(point2.x); + yend = GetSectorIndexX(point2.y); + +#define LOSARGS CColLine(point1, point2), checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects + + if(xstart == xend && ystart == yend){ + // Only one sector + return GetIsLineOfSightSectorClear(*GetSector(xstart, ystart), LOSARGS); + }else if(xstart == xend){ + // Only step in y + if(ystart < yend){ + for(y = ystart; y <= yend; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + }else{ + for(y = ystart; y >= yend; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + } + }else if(ystart == yend){ + // Only step in x + if(xstart < xend){ + for(x = xstart; x <= xend; x++) + if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS)) + return false; + }else{ + for(x = xstart; x >= xend; x--) + if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS)) + return false; + } + }else{ + if(point1.x < point2.x){ + // Step from left to right + float m = (point2.y - point1.y) / (point2.x - point1.x); + + y1 = ystart; + y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y); + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + } + + for(x = xstart+1; x < xend; x++){ + y1 = y2; + y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y); + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) + return false; + } + } + + y1 = y2; + y2 = yend; + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) + return false; + } + }else{ + // Step from right to left + float m = (point2.y - point1.y) / (point2.x - point1.x); + + y1 = ystart; + y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y); + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS)) + return false; + } + + for(x = xstart-1; x > xend; x--){ + y1 = y2; + y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y); + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS)) + return false; + } + } + + y1 = y2; + y2 = yend; + if(y1 < y2){ + for(y = y1; y <= y2; y++) + if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) + return false; + }else{ + for(y = y1; y >= y2; y--) + if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS)) + return false; + } + } + } + + return true; + +#undef LOSARGS +} + +bool +CWorld::GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + if(checkBuildings){ + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS], line, ignoreSeeThrough)) + return false; + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, ignoreSeeThrough)) + return false; + } + + if(checkVehicles){ + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES], line, ignoreSeeThrough)) + return false; + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, ignoreSeeThrough)) + return false; + } + + if(checkPeds){ + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS], line, ignoreSeeThrough)) + return false; + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, ignoreSeeThrough)) + return false; + } + + if(checkObjects){ + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS], line, ignoreSeeThrough, ignoreSomeObjects)) + return false; + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, ignoreSeeThrough, ignoreSomeObjects)) + return false; + } + + if(checkDummies){ + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES], line, ignoreSeeThrough)) + return false; + if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, ignoreSeeThrough)) + return false; + } + + return true; +} + +bool +CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects) +{ + CPtrNode *node; + CEntity *e; + CColModel *colmodel; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + if(e->m_scanCode != GetCurrentScanCode() && + e->bUsesCollision){ + + e->m_scanCode = GetCurrentScanCode(); + + if(e != pIgnoreEntity && + !(ignoreSomeObjects && CameraToIgnoreThisObject(e))){ + + colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); + + if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough)) + return false; + } + } + } + + return true; +} + +float +CWorld::FindGroundZForCoord(float x, float y) +{ + CColPoint point; + CEntity *ent; + if(ProcessVerticalLine(CVector(x, y, 1000.0f), -1000.0f, point, ent, true, false, false, false, true, false, nil)) + return point.point.z; + else + return 20.0f; +} + +float +CWorld::FindGroundZFor3DCoord(float x, float y, float z, bool *found) +{ + CColPoint point; + CEntity *ent; + if(ProcessVerticalLine(CVector(x, y, z), -1000.0f, point, ent, true, false, false, false, false, false, nil)){ + if(found) + *found = true; + return point.point.z; + }else{ + if(found) + *found = false; + return 0.0f; + } +} + +float +CWorld::FindRoofZFor3DCoord(float x, float y, float z, bool *found) +{ + CColPoint point; + CEntity *ent; + if(ProcessVerticalLine(CVector(x, y, z), 1000.0f, point, ent, true, false, false, false, true, false, nil)){ + if(found) + *found = true; + return point.point.z; + }else{ + if(found == nil) + printf("THERE IS NO MAP BELOW THE FOLLOWING COORS:%f %f %f. (FindGroundZFor3DCoord)\n", x, y, z); + if(found) + *found = false; + return 20.0f; + } +} + +CPlayerPed* +FindPlayerPed(void) +{ + return CWorld::Players[CWorld::PlayerInFocus].m_pPed; +} + +CVehicle* +FindPlayerVehicle(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle; + else + return nil; +} + +CVehicle* +FindPlayerTrain(void) +{ + if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain()) + return FindPlayerVehicle(); + else + return nil; +} + +CEntity* +FindPlayerEntity(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle; + else + return ped; +} + +CVector +FindPlayerCoors(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle->GetPosition(); + else + return ped->GetPosition(); +} + +CVector& +FindPlayerSpeed(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle->m_vecMoveSpeed; + else + return ped->m_vecMoveSpeed; +} + +CVector& +FindPlayerCentreOfWorld(int32 player) +{ + if(CCarCtrl::bCarsGeneratedAroundCamera) + return TheCamera.GetPosition(); + if(CWorld::Players[player].m_pRemoteVehicle) + return CWorld::Players[player].m_pRemoteVehicle->GetPosition(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetPosition(); + return CWorld::Players[player].m_pPed->GetPosition(); +} + +CVector& +FindPlayerCentreOfWorld_NoSniperShift(void) +{ + if(CCarCtrl::bCarsGeneratedAroundCamera) + return TheCamera.GetPosition(); + if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) + return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetPosition(); + return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition(); +} + +float +FindPlayerHeading(void) +{ + if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) + return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetForward().Heading(); + return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetForward().Heading(); +} + +STARTPATCHES + InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP); + InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP); + InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP); + InjectHook(0x4AF970, CWorld::ProcessLineOfSight, PATCH_JUMP); + InjectHook(0x4B0A80, CWorld::ProcessLineOfSightSector, PATCH_JUMP); + InjectHook(0x4B0C70, CWorld::ProcessLineOfSightSectorList, PATCH_JUMP); + InjectHook(0x4B0DE0, CWorld::ProcessVerticalLine, PATCH_JUMP); + InjectHook(0x4B0EF0, CWorld::ProcessVerticalLineSector, PATCH_JUMP); + InjectHook(0x4B1090, CWorld::ProcessVerticalLineSectorList, PATCH_JUMP); + InjectHook(0x4AEAA0, CWorld::GetIsLineOfSightClear, PATCH_JUMP); + InjectHook(0x4B2000, CWorld::GetIsLineOfSightSectorClear, PATCH_JUMP); + InjectHook(0x4B2160, CWorld::GetIsLineOfSightSectorListClear, PATCH_JUMP); + + InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP); + InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); + InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/World.h b/src/core/World.h new file mode 100644 index 00000000..3b7090da --- /dev/null +++ b/src/core/World.h @@ -0,0 +1,119 @@ +#pragma once + +#include "Game.h" +#include "Lists.h" +#include "PlayerInfo.h" + +/* Sectors span from -2000 to 2000 in x and y. + * With 100x100 sectors, each is 40x40 units. */ + +#define SECTOR_SIZE_X (40.0f) +#define SECTOR_SIZE_Y (40.0f) + +#define NUMSECTORS_X (100) +#define NUMSECTORS_Y (100) + +#define WORLD_SIZE_X (NUMSECTORS_X * SECTOR_SIZE_X) +#define WORLD_SIZE_Y (NUMSECTORS_Y * SECTOR_SIZE_Y) + +#define WORLD_MIN_X (-2000.0f) +#define WORLD_MIN_Y (-2000.0f) + +#define WORLD_MAX_X (WORLD_MIN_X + WORLD_SIZE_X) +#define WORLD_MAX_Y (WORLD_MIN_Y + WORLD_SIZE_Y) + +enum +{ + ENTITYLIST_BUILDINGS, + ENTITYLIST_BUILDINGS_OVERLAP, + ENTITYLIST_OBJECTS, + ENTITYLIST_OBJECTS_OVERLAP, + ENTITYLIST_VEHICLES, + ENTITYLIST_VEHICLES_OVERLAP, + ENTITYLIST_PEDS, + ENTITYLIST_PEDS_OVERLAP, + ENTITYLIST_DUMMIES, + ENTITYLIST_DUMMIES_OVERLAP, + + NUMSECTORENTITYLISTS +}; + +class CSector +{ +public: + CPtrList m_lists[NUMSECTORENTITYLISTS]; +}; +static_assert(sizeof(CSector) == 0x28, "CSector: error"); + +class CEntity; +struct CColPoint; +struct CColLine; +struct CStoredCollPoly; + +class CWorld +{ + static CPtrList *ms_bigBuildingsList; // [4]; + static CPtrList &ms_listMovingEntityPtrs; + static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; + static uint16 &ms_nCurrentScanCode; + +public: + static uint8 &PlayerInFocus; + static CPlayerInfo *Players; + static CEntity *&pIgnoreEntity; + static bool &bIncludeDeadPeds; + static bool &bNoMoreCollisionTorque; + static bool &bSecondShift; + static bool &bForceProcessControl; + static bool &bProcessCutsceneOnly; + + static void Remove(CEntity *entity); + static void Add(CEntity *entity); + + static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } + static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; } + static CPtrList &GetMovingEntityList(void) { return ms_listMovingEntityPtrs; } + static uint16 GetCurrentScanCode(void) { return ms_nCurrentScanCode; } + static void AdvanceCurrentScanCode(void){ + if(++CWorld::ms_nCurrentScanCode == 0){ + CWorld::ClearScanCodes(); + CWorld::ms_nCurrentScanCode = 1; + } + } + static void ClearScanCodes(void); + + static bool CameraToIgnoreThisObject(CEntity *ent); + + static bool ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static bool ProcessLineOfSightSector(CSector §or, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static bool ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly); + static bool ProcessVerticalLineSector(CSector §or, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly); + static bool ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly); + static bool GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static bool GetIsLineOfSightSectorClear(CSector §or, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false); + + static float FindGroundZForCoord(float x, float y); + static float FindGroundZFor3DCoord(float x, float y, float z, bool *found); + static float FindRoofZFor3DCoord(float x, float y, float z, bool *found); + + static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); } + static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); } + static int GetSectorIndexX(float f) { return (int)GetSectorX(f); } + static int GetSectorIndexY(float f) { return (int)GetSectorY(f); } + static float GetWorldX(int x) { return x*SECTOR_SIZE_X + WORLD_MIN_X; } + static float GetWorldY(int y) { return y*SECTOR_SIZE_Y + WORLD_MIN_Y; } +}; + +class CPlayerPed; +class CVehicle; +CPlayerPed *FindPlayerPed(void); +CVehicle *FindPlayerVehicle(void); +CVehicle *FindPlayerTrain(void); +CEntity *FindPlayerEntity(void); +CVector FindPlayerCoors(void); +CVector &FindPlayerSpeed(void); +CVector &FindPlayerCentreOfWorld(int32 player); +CVector &FindPlayerCentreOfWorld_NoSniperShift(void); +float FindPlayerHeading(void); diff --git a/src/core/ZoneCull.cpp b/src/core/ZoneCull.cpp new file mode 100644 index 00000000..90155bcf --- /dev/null +++ b/src/core/ZoneCull.cpp @@ -0,0 +1,370 @@ +#include "common.h" +#include "patcher.h" +#include "Building.h" +#include "Treadable.h" +#include "Train.h" +#include "Pools.h" +#include "Timer.h" +#include "Camera.h" +#include "World.h" +#include "FileMgr.h" +#include "ZoneCull.h" + +int32 &CCullZones::NumCullZones = *(int*)0x8F2564; +CCullZone *CCullZones::aZones = (CCullZone*)0x864750; // [NUMCULLZONES]; +int32 &CCullZones::NumAttributeZones = *(int*)0x8E29D0; +CAttributeZone *CCullZones::aAttributeZones = (CAttributeZone*)0x709C60; // [NUMATTRIBZONES]; +uint16 *CCullZones::aIndices = (uint16*)0x847330; // [NUMZONEINDICES]; +int16 *CCullZones::aPointersToBigBuildingsForBuildings = (int16*)0x86C9D0; // [NUMBUILDINGS]; +int16 *CCullZones::aPointersToBigBuildingsForTreadables = (int16*)0x8F1B8C; // [NUMTREADABLES]; + +int32 &CCullZones::CurrentWantedLevelDrop_Player = *(int32*)0x880DA8; +int32 &CCullZones::CurrentFlags_Camera = *(int32*)0x940718; +int32 &CCullZones::CurrentFlags_Player = *(int32*)0x9415F0; +int32 &CCullZones::OldCullZone = *(int32*)0x8E2C90; +int32 &CCullZones::EntityIndicesUsed = *(int32*)0x8F2508; +bool &CCullZones::bCurrentSubwayIsInvisible = *(bool*)0x95CDA5; +bool &CCullZones::bCullZonesDisabled = *(bool*)0x95CD4A; + + +void +CCullZones::Init(void) +{ + int i; + + NumAttributeZones = 0; + NumCullZones = 0; + CurrentWantedLevelDrop_Player = 0; + CurrentFlags_Camera = 0; + CurrentFlags_Player = 0; + OldCullZone = -1; + EntityIndicesUsed = 0; + bCurrentSubwayIsInvisible = false; + + for(i = 0; i < NUMBUILDINGS; i++) + aPointersToBigBuildingsForBuildings[i] = -1; + for(i = 0; i < NUMTREADABLES; i++) + aPointersToBigBuildingsForTreadables[i] = -1; +} + +void +CCullZones::ResolveVisibilities(void) +{ + int fd; + + CFileMgr::SetDir(""); + fd = CFileMgr::OpenFile("DATA\\cullzone.dat", "rb"); + if(fd > 0){ + CFileMgr::Read(fd, (char*)&NumCullZones, 4); + CFileMgr::Read(fd, (char*)aZones, NUMCULLZONES*sizeof(CCullZone)); + CFileMgr::Read(fd, (char*)&NumAttributeZones, 4); + CFileMgr::Read(fd, (char*)aAttributeZones, NUMATTRIBZONES*sizeof(CAttributeZone)); + CFileMgr::Read(fd, (char*)aIndices, NUMZONEINDICES*2); + CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForBuildings, NUMBUILDINGS*2); + CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForTreadables, NUMTREADABLES*2); + CFileMgr::CloseFile(fd); + }else{ + // TODO: implement code from mobile to generate data here + } +} + +void +CCullZones::Update(void) +{ + bool invisible; + + if(bCullZonesDisabled) + return; + + switch(CTimer::GetFrameCounter() & 7){ + case 0: + case 4: + /* Update Cull zone */ + ForceCullZoneCoors(TheCamera.GetGameCamPosition()); + break; + + case 2: + /* Update camera attributes */ + CurrentFlags_Camera = FindAttributesForCoors(TheCamera.GetGameCamPosition(), nil); + invisible = (CurrentFlags_Camera & ATTRZONE_SUBWAYVISIBLE) == 0; + if(invisible != bCurrentSubwayIsInvisible){ + MarkSubwayAsInvisible(!invisible); + bCurrentSubwayIsInvisible = invisible; + } + break; + + case 6: + /* Update player attributes */ + CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(), + &CurrentWantedLevelDrop_Player); + break; + } +} + +void +CCullZones::ForceCullZoneCoors(CVector coors) +{ + int32 z; + z = FindCullZoneForCoors(coors); + if(z != OldCullZone){ + if(OldCullZone >= 0) + aZones[OldCullZone].DoStuffLeavingZone(); + if(z >= 0) + aZones[z].DoStuffEnteringZone(); + OldCullZone = z; + } +} + +int32 +CCullZones::FindCullZoneForCoors(CVector coors) +{ + int i; + + for(i = 0; i < NumCullZones; i++) + if(coors.x >= aZones[i].minx && coors.x <= aZones[i].maxx && + coors.y >= aZones[i].miny && coors.y <= aZones[i].maxy && + coors.z >= aZones[i].minz && coors.z <= aZones[i].maxz) + return i; + return -1; +} + +int32 +CCullZones::FindAttributesForCoors(CVector coors, int32 *wantedLevel) +{ + int i; + int32 attribs; + + attribs = 0; + for(i = 0; i < NumAttributeZones; i++) + if(coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && + coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && + coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz){ + attribs |= aAttributeZones[i].attributes; + if(wantedLevel && *wantedLevel <= aAttributeZones[i].wantedLevel) + *wantedLevel = aAttributeZones[i].wantedLevel; + } + return attribs; +} + +CAttributeZone* +CCullZones::FindZoneWithStairsAttributeForPlayer(void) +{ + int i; + CVector coors; + + coors = FindPlayerCoors(); + for(i = 0; i < NumAttributeZones; i++) + if(aAttributeZones[i].attributes & ATTRZONE_STAIRS && + coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && + coors.y >= aAttributeZones[i].miny && coors.y <= aAttributeZones[i].maxy && + coors.z >= aAttributeZones[i].minz && coors.z <= aAttributeZones[i].maxz) + return &aAttributeZones[i]; + return nil; +} + +void +CCullZones::MarkSubwayAsInvisible(bool visible) +{ + int i, n; + CEntity *e; + CVehicle *v; + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetBuildingPool()->GetSlot(i); + if(e && e->bIsSubway) + e->bIsVisible = visible; + } + + n = CPools::GetTreadablePool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetTreadablePool()->GetSlot(i); + if(e && e->bIsSubway) + e->bIsVisible = visible; + } + + n = CPools::GetVehiclePool()->GetSize(); + for(i = 0; i < n; i++){ + v = CPools::GetVehiclePool()->GetSlot(i); + if(v && v->IsTrain() && ((CTrain*)v)->m_trackId != 0) + v->bIsVisible = visible; + } +} + +void +CCullZones::AddCullZone(CVector const &position, + float minx, float maxx, + float miny, float maxy, + float minz, float maxz, + uint16 flag, int16 wantedLevel) +{ + CCullZone *cull; + CAttributeZone *attrib; + + CVector v; + if((flag & ATTRZONE_NOTCULLZONE) == 0){ + cull = &aZones[NumCullZones++]; + v = position; + // WTF is this? + if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f) + v = CVector(1061.7f, -613.0f, 19.0f); + if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f) + v = CVector(1061.4f, -506.0f, 18.5f); + cull->position.x = clamp(v.x, minx, maxx); + cull->position.y = clamp(v.y, miny, maxy); + cull->position.z = clamp(v.z, minz, maxz); + cull->minx = minx; + cull->maxx = maxx; + cull->miny = miny; + cull->maxy = maxy; + cull->minz = minz; + cull->maxz = maxz; + cull->unk2 = 0; + cull->unk3 = 0; + cull->unk4 = 0; + cull->m_indexStart = 0; + } + if(flag & ~ATTRZONE_NOTCULLZONE){ + attrib = &aAttributeZones[NumAttributeZones++]; + attrib->minx = minx; + attrib->maxx = maxx; + attrib->miny = miny; + attrib->maxy = maxy; + attrib->minz = minz; + attrib->maxz = maxz; + attrib->attributes = flag; + attrib->wantedLevel = wantedLevel; + } +} + + + +void +CCullZone::DoStuffLeavingZone(void) +{ + int i; + + for(i = 0; i < m_numBuildings; i++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables ; i++) + DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[m_indexStart + i]); +} + +void +CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false; + bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false; + CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone(void) +{ + int i; + + for(i = 0; i < m_numBuildings; i++) + DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m; i++) + DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[m_indexStart + i]); + for(; i < m_numBuildings + m_numTreadablesPlus10m + m_numTreadables; i++) + DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[m_indexStart + i]); +} + +void +CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true; + bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;; + CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true;; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +void +CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i) +{ + int16 bb; + int j; + + if(i < 6000){ + CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true;; + bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; + if(bb != -1) + CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; + }else{ + i -= 6000; + for(j = 0; j < 3; j++) + DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); + } +} + +STARTPATCHES + InjectHook(0x524BC0, &CCullZones::Init, PATCH_JUMP); + InjectHook(0x524EC0, &CCullZones::ResolveVisibilities, PATCH_JUMP); + InjectHook(0x524F80, &CCullZones::Update, PATCH_JUMP); + InjectHook(0x525370, &CCullZones::AddCullZone, PATCH_JUMP); + InjectHook(0x5250D0, &CCullZones::ForceCullZoneCoors, PATCH_JUMP); + InjectHook(0x525130, &CCullZones::FindCullZoneForCoors, PATCH_JUMP); + InjectHook(0x5251C0, &CCullZones::FindAttributesForCoors, PATCH_JUMP); + InjectHook(0x525290, &CCullZones::FindZoneWithStairsAttributeForPlayer, PATCH_JUMP); + + InjectHook(0x525610, &CCullZone::DoStuffLeavingZone, PATCH_JUMP); + InjectHook(0x525810, &CCullZone::DoStuffEnteringZone, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/ZoneCull.h b/src/core/ZoneCull.h new file mode 100644 index 00000000..5b04b4f9 --- /dev/null +++ b/src/core/ZoneCull.h @@ -0,0 +1,94 @@ +class CCullZone +{ +public: + CVector position; + float minx; + float maxx; + float miny; + float maxy; + float minz; + float maxz; + + // TODO: figure these out: + int32 m_indexStart; + int16 unk2; + int16 unk3; + int16 unk4; + int16 m_numBuildings; + int16 m_numTreadablesPlus10m; + int16 m_numTreadables; + + void DoStuffLeavingZone(void); + static void DoStuffLeavingZone_OneBuilding(uint16 i); + static void DoStuffLeavingZone_OneTreadableBoth(uint16 i); + void DoStuffEnteringZone(void); + static void DoStuffEnteringZone_OneBuilding(uint16 i); + static void DoStuffEnteringZone_OneTreadablePlus10m(uint16 i); + static void DoStuffEnteringZone_OneTreadable(uint16 i); +}; + +enum eZoneAttribs +{ + ATTRZONE_CAMCLOSEIN = 1, + ATTRZONE_STAIRS = 2, + ATTRZONE_1STPERSON = 4, + ATTRZONE_NORAIN = 8, + ATTRZONE_NOPOLICE = 0x10, + ATTRZONE_NOTCULLZONE = 0x20, + ATTRZONE_DOINEEDCOLLISION = 0x40, + ATTRZONE_SUBWAYVISIBLE = 0x80, +}; + +struct CAttributeZone +{ + float minx; + float maxx; + float miny; + float maxy; + float minz; + float maxz; + int16 attributes; + int16 wantedLevel; +}; + +class CCullZones +{ +public: + static int32 &NumCullZones; + static CCullZone *aZones; // [NUMCULLZONES]; + static int32 &NumAttributeZones; + static CAttributeZone *aAttributeZones; // [NUMATTRIBZONES]; + static uint16 *aIndices; // [NUMZONEINDICES]; + static int16 *aPointersToBigBuildingsForBuildings; // [NUMBUILDINGS]; + static int16 *aPointersToBigBuildingsForTreadables; // [NUMTREADABLES]; + + static int32 &CurrentWantedLevelDrop_Player; + static int32 &CurrentFlags_Camera; + static int32 &CurrentFlags_Player; + static int32 &OldCullZone; + static int32 &EntityIndicesUsed; + static bool &bCurrentSubwayIsInvisible; + static bool &bCullZonesDisabled; + + static void Init(void); + static void ResolveVisibilities(void); + static void Update(void); + static void ForceCullZoneCoors(CVector coors); + static int32 FindCullZoneForCoors(CVector coors); + static int32 FindAttributesForCoors(CVector coors, int32 *wantedLevel); + static CAttributeZone *FindZoneWithStairsAttributeForPlayer(void); + static void MarkSubwayAsInvisible(bool visible); + static void AddCullZone(CVector const &position, + float minx, float maxx, + float miny, float maxy, + float minz, float maxz, + uint16 flag, int16 wantedLevel); + static bool CamCloseInForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_CAMCLOSEIN) != 0; } + static bool CamStairsForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_STAIRS) != 0; } + static bool Cam1stPersonForPlayer(void) { return (CurrentFlags_Player & ATTRZONE_1STPERSON) != 0; } + static bool NoPolice(void) { return (CurrentFlags_Player & ATTRZONE_NOPOLICE) != 0; } + static bool DoINeedToLoadCollision(void) { return (CurrentFlags_Player & ATTRZONE_DOINEEDCOLLISION) != 0; } + static bool PlayerNoRain(void) { return (CurrentFlags_Player & ATTRZONE_NORAIN) != 0; } + static bool CamNoRain(void) { return (CurrentFlags_Camera & ATTRZONE_NORAIN) != 0; } + static int32 GetWantedLevelDrop(void) { return CurrentWantedLevelDrop_Player; } +}; diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp new file mode 100644 index 00000000..363fc3d9 --- /dev/null +++ b/src/core/Zones.cpp @@ -0,0 +1,874 @@ +#include "common.h" +#include "patcher.h" + +#include "Zones.h" + +#include "Clock.h" +#include "Text.h" +#include "World.h" + +eLevelName &CTheZones::m_CurrLevel = *(eLevelName*)0x8F2BC8; +CZone *&CTheZones::m_pPlayersZone = *(CZone**)0x8F254C; +int16 &CTheZones::FindIndex = *(int16*)0x95CC40; + +uint16 &CTheZones::NumberOfAudioZones = *(uint16*)0x95CC84; +int16 *CTheZones::AudioZoneArray = (int16*)0x713BC0; +uint16 &CTheZones::TotalNumberOfMapZones = *(uint16*)0x95CC74; +uint16 &CTheZones::TotalNumberOfZones = *(uint16*)0x95CC36; +CZone *CTheZones::ZoneArray = (CZone*)0x86BEE0; +CZone *CTheZones::MapZoneArray = (CZone*)0x663EC0; +uint16 &CTheZones::TotalNumberOfZoneInfos = *(uint16*)0x95CC3C; +CZoneInfo *CTheZones::ZoneInfoArray = (CZoneInfo*)0x714400; + +#define SWAPF(a, b) { float t; t = a; a = b; b = t; } + +static void +CheckZoneInfo(CZoneInfo *info) +{ + assert(info->carThreshold[0] >= 0); + assert(info->carThreshold[0] <= info->carThreshold[1]); + assert(info->carThreshold[1] <= info->carThreshold[2]); + assert(info->carThreshold[2] <= info->carThreshold[3]); + assert(info->carThreshold[3] <= info->carThreshold[4]); + assert(info->carThreshold[4] <= info->carThreshold[5]); + assert(info->carThreshold[5] <= info->copThreshold); + assert(info->copThreshold <= info->gangThreshold[0]); + assert(info->gangThreshold[0] <= info->gangThreshold[1]); + assert(info->gangThreshold[1] <= info->gangThreshold[2]); + assert(info->gangThreshold[2] <= info->gangThreshold[3]); + assert(info->gangThreshold[3] <= info->gangThreshold[4]); + assert(info->gangThreshold[4] <= info->gangThreshold[5]); + assert(info->gangThreshold[5] <= info->gangThreshold[6]); + assert(info->gangThreshold[6] <= info->gangThreshold[7]); + assert(info->gangThreshold[7] <= info->gangThreshold[8]); +} + +wchar* +CZone::GetTranslatedName(void) +{ + return TheText.Get(name); +} + +void +CTheZones::Init(void) +{ + int i; + for(i = 0; i < NUMAUDIOZONES; i++) + AudioZoneArray[i] = -1; + NumberOfAudioZones = 0; + + CZoneInfo *zonei; + int x = 1000/6; + for(i = 0; i < 2*NUMZONES; i++){ + zonei = &ZoneInfoArray[i]; + zonei->carDensity = 10; + zonei->carThreshold[0] = x; + zonei->carThreshold[1] = zonei->carThreshold[0] + x; + zonei->carThreshold[2] = zonei->carThreshold[1] + x; + zonei->carThreshold[3] = zonei->carThreshold[2] + x; + zonei->carThreshold[4] = zonei->carThreshold[3]; + zonei->carThreshold[5] = zonei->carThreshold[4]; + zonei->copThreshold = zonei->carThreshold[5] + x; + zonei->gangThreshold[0] = zonei->copThreshold; + zonei->gangThreshold[1] = zonei->gangThreshold[0]; + zonei->gangThreshold[2] = zonei->gangThreshold[1]; + zonei->gangThreshold[3] = zonei->gangThreshold[2]; + zonei->gangThreshold[4] = zonei->gangThreshold[3]; + zonei->gangThreshold[5] = zonei->gangThreshold[4]; + zonei->gangThreshold[6] = zonei->gangThreshold[5]; + zonei->gangThreshold[7] = zonei->gangThreshold[6]; + zonei->gangThreshold[8] = zonei->gangThreshold[7]; + CheckZoneInfo(zonei); + } + TotalNumberOfZoneInfos = 1; // why 1? + + for(i = 0; i < NUMZONES; i++) + memset(&ZoneArray[i], 0, sizeof(CZone)); + strcpy(ZoneArray[0].name, "CITYZON"); + ZoneArray[0].minx = -4000.0f; + ZoneArray[0].miny = -4000.0f; + ZoneArray[0].minz = -500.0f; + ZoneArray[0].maxx = 4000.0f; + ZoneArray[0].maxy = 4000.0f; + ZoneArray[0].maxz = 500.0f; + ZoneArray[0].level = LEVEL_NONE; + TotalNumberOfZones = 1; + + m_CurrLevel = LEVEL_NONE; + m_pPlayersZone = &ZoneArray[0]; + + for(i = 0; i < NUMMAPZONES; i++){ + memset(&MapZoneArray[i], 0, sizeof(CZone)); + MapZoneArray[i].type = ZONE_MAPZONE; + } + strcpy(MapZoneArray[0].name, "THEMAP"); + MapZoneArray[0].minx = -4000.0f; + MapZoneArray[0].miny = -4000.0f; + MapZoneArray[0].minz = -500.0f; + MapZoneArray[0].maxx = 4000.0f; + MapZoneArray[0].maxy = 4000.0f; + MapZoneArray[0].maxz = 500.0f; + MapZoneArray[0].level = LEVEL_NONE; + TotalNumberOfMapZones = 1; +} + +void +CTheZones::Update(void) +{ + CVector pos; + pos = FindPlayerCoors(); + m_pPlayersZone = FindSmallestZonePosition(&pos); + m_CurrLevel = GetLevelFromPosition(pos); +} + +void +CTheZones::CreateZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level) +{ + CZone *zone; + char *p; + + if(minx > maxx) SWAPF(minx, maxx); + if(miny > maxy) SWAPF(miny, maxy); + if(minz > maxz) SWAPF(minz, maxz); + + // make upper case + for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); + + // add zone + zone = &ZoneArray[TotalNumberOfZones++]; + strncpy(zone->name, name, 7); + zone->name[7] = '\0'; + zone->type = type; + zone->minx = minx; + zone->miny = miny; + zone->minz = minz; + zone->maxx = maxx; + zone->maxy = maxy; + zone->maxz = maxz; + zone->level = level; + if(type == ZONE_AUDIO || type == ZONE_TYPE1 || type == ZONE_TYPE2){ + zone->zoneinfoDay = TotalNumberOfZoneInfos++; + zone->zoneinfoNight = TotalNumberOfZoneInfos++; + } +} + +void +CTheZones::CreateMapZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level) +{ + CZone *zone; + char *p; + + if(minx > maxx) SWAPF(minx, maxx); + if(miny > maxy) SWAPF(miny, maxy); + if(minz > maxz) SWAPF(minz, maxz); + + // make upper case + for(p = name; *p; p++) if(islower(*p)) *p = toupper(*p); + + // add zone + zone = &MapZoneArray[TotalNumberOfMapZones++]; + strncpy(zone->name, name, 7); + zone->name[7] = '\0'; + zone->type = type; + zone->minx = minx; + zone->miny = miny; + zone->minz = minz; + zone->maxx = maxx; + zone->maxy = maxy; + zone->maxz = maxz; + zone->level = level; +} + +void +CTheZones::PostZoneCreation(void) +{ + int i; + for(i = 1; i < TotalNumberOfZones; i++) + InsertZoneIntoZoneHierarchy(&ZoneArray[i]); + InitialiseAudioZoneArray(); +} + +void +CTheZones::InsertZoneIntoZoneHierarchy(CZone *zone) +{ + zone->child = nil; + zone->parent = nil; + zone->next = nil; + InsertZoneIntoZoneHierRecursive(zone, &ZoneArray[0]); +} + +bool +CTheZones::InsertZoneIntoZoneHierRecursive(CZone *inner, CZone *outer) +{ + int n; + CZone *child, *next, *insert; + + // return false if inner was not inserted into outer + if(outer == nil || + !ZoneIsEntirelyContainedWithinOtherZone(inner, outer)) + return false; + + // try to insert inner into children of outer + for(child = outer->child; child; child = child->next) + if(InsertZoneIntoZoneHierRecursive(inner, child)) + return true; + + // insert inner as child of outer + // count number of outer's children contained within inner + n = 0; + for(child = outer->child; child; child = child->next) + if(ZoneIsEntirelyContainedWithinOtherZone(child, inner)) + n++; + inner->next = outer->child; + inner->parent = outer; + outer->child = inner; + // move children from outer to inner + if(n){ + insert = inner; + for(child = inner->next; child; child = next){ + next = child->next; + if(ZoneIsEntirelyContainedWithinOtherZone(child,inner)){ + insert->next = child->next; + child->parent = inner; + child->next = inner->child; + inner->child = child; + }else + insert = child; + } + } + + return true; +} + +bool +CTheZones::ZoneIsEntirelyContainedWithinOtherZone(CZone *inner, CZone *outer) +{ + char tmp[100]; + + if(inner->minx < outer->minx || + inner->maxx > outer->maxx || + inner->miny < outer->miny || + inner->maxy > outer->maxy || + inner->minz < outer->minz || + inner->maxz > outer->maxz){ + CVector vmin(inner->minx, inner->miny, inner->minz); + if(PointLiesWithinZone(vmin, outer)) + sprintf(tmp, "Overlapping zones %s and %s\n", + inner->name, outer->name); + CVector vmax(inner->maxx, inner->maxy, inner->maxz); + if(PointLiesWithinZone(vmax, outer)) + sprintf(tmp, "Overlapping zones %s and %s\n", + inner->name, outer->name); + return false; + } + return true; +} + +bool +CTheZones::PointLiesWithinZone(const CVector &v, CZone *zone) +{ + return zone->minx <= v.x && v.x <= zone->maxx && + zone->miny <= v.y && v.y <= zone->maxy && + zone->minz <= v.z && v.z <= zone->maxz; +} + +eLevelName +CTheZones::GetLevelFromPosition(CVector const &v) +{ + int i; +// char tmp[116]; +// if(!PointLiesWithinZone(v, &MapZoneArray[0])) +// sprintf(tmp, "x = %.3f y= %.3f z = %.3f\n", v.x, v.y, v.z); + for(i = 1; i < TotalNumberOfMapZones; i++) + if(PointLiesWithinZone(v, &MapZoneArray[i])) + return MapZoneArray[i].level; + return MapZoneArray[0].level; +} + +CZone* +CTheZones::FindSmallestZonePosition(const CVector *v) +{ + CZone *best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +CZone* +CTheZones::FindSmallestZonePositionType(const CVector *v, eZoneType type) +{ + CZone *best = nil; + if(ZoneArray[0].type == type) + best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + if(zone->type == type) + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +CZone* +CTheZones::FindSmallestZonePositionILN(const CVector *v) +{ + CZone *best = nil; + if(ZoneArray[0].type == ZONE_AUDIO || + ZoneArray[0].type == ZONE_TYPE1 || + ZoneArray[0].type == ZONE_TYPE2) + best = &ZoneArray[0]; + // zone to test next + CZone *zone = ZoneArray[0].child; + while(zone) + // if in zone, descent into children + if(PointLiesWithinZone(*v, zone)){ + if(zone->type == ZONE_AUDIO || + zone->type == ZONE_TYPE1 || + zone->type == ZONE_TYPE2) + best = zone; + zone = zone->child; + // otherwise try next zone + }else + zone = zone->next; + return best; +} + +int16 +CTheZones::FindZoneByLabelAndReturnIndex(char *name) +{ + char str[8]; + memset(str, 0, 8); + strncpy(str, name, 8); + for(FindIndex = 0; FindIndex < TotalNumberOfZones; FindIndex++) + if(strcmp(GetZone(FindIndex)->name, name) == 0) + return FindIndex; + return -1; +} + +CZoneInfo* +CTheZones::GetZoneInfo(const CVector *v, uint8 day) +{ + CZone *zone; + zone = FindSmallestZonePositionILN(v); + if(zone == nil) + return &ZoneInfoArray[0]; + return &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; +} + +void +CTheZones::GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info) +{ + CZoneInfo *day, *night; + float d, n; + + day = GetZoneInfo(pos, 1); + night = GetZoneInfo(pos, 0); + + if(CClock::GetIsTimeInRange(8, 19)) + *info = *day; + else if(CClock::GetIsTimeInRange(22, 5)) + *info = *night; + else{ + if(CClock::GetIsTimeInRange(19, 22)){ + n = (CClock::GetHours() - 19) / 3.0f; + assert(n >= 0.0f && n <= 1.0f); + d = 1.0f - n; + }else{ + d = (CClock::GetHours() - 5) / 3.0f; + assert(d >= 0.0f && d <= 1.0f); + n = 1.0f - d; + } + info->carDensity = day->carDensity * d + night->carDensity * n; + info->carThreshold[0] = day->carThreshold[0] * d + night->carThreshold[0] * n; + info->carThreshold[1] = day->carThreshold[1] * d + night->carThreshold[1] * n; + info->carThreshold[2] = day->carThreshold[2] * d + night->carThreshold[2] * n; + info->carThreshold[3] = day->carThreshold[3] * d + night->carThreshold[3] * n; + info->carThreshold[4] = day->carThreshold[4] * d + night->carThreshold[4] * n; + info->carThreshold[5] = day->carThreshold[5] * d + night->carThreshold[5] * n; + info->copThreshold = day->copThreshold * d + night->copThreshold * n; + info->gangThreshold[0] = day->gangThreshold[0] * d + night->gangThreshold[0] * n; + info->gangThreshold[1] = day->gangThreshold[1] * d + night->gangThreshold[1] * n; + info->gangThreshold[2] = day->gangThreshold[2] * d + night->gangThreshold[2] * n; + info->gangThreshold[3] = day->gangThreshold[3] * d + night->gangThreshold[3] * n; + info->gangThreshold[4] = day->gangThreshold[4] * d + night->gangThreshold[4] * n; + info->gangThreshold[5] = day->gangThreshold[5] * d + night->gangThreshold[5] * n; + info->gangThreshold[6] = day->gangThreshold[6] * d + night->gangThreshold[6] * n; + info->gangThreshold[7] = day->gangThreshold[7] * d + night->gangThreshold[7] * n; + info->gangThreshold[8] = day->gangThreshold[8] * d + night->gangThreshold[8] * n; + + info->pedDensity = day->pedDensity * d + night->pedDensity * n; + info->copDensity = day->copDensity * d + night->copDensity * n; + info->gangDensity[0] = day->gangDensity[0] * d + night->gangDensity[0] * n; + info->gangDensity[1] = day->gangDensity[1] * d + night->gangDensity[1] * n; + info->gangDensity[2] = day->gangDensity[2] * d + night->gangDensity[2] * n; + info->gangDensity[3] = day->gangDensity[3] * d + night->gangDensity[3] * n; + info->gangDensity[4] = day->gangDensity[4] * d + night->gangDensity[4] * n; + info->gangDensity[5] = day->gangDensity[5] * d + night->gangDensity[5] * n; + info->gangDensity[6] = day->gangDensity[6] * d + night->gangDensity[6] * n; + info->gangDensity[7] = day->gangDensity[7] * d + night->gangDensity[7] * n; + info->gangDensity[8] = day->gangDensity[8] * d + night->gangDensity[8] * n; + } + if(CClock::GetIsTimeInRange(5, 19)) + info->pedGroup = day->pedGroup; + else + info->pedGroup = night->pedGroup; + + CheckZoneInfo(info); +} + +void +CTheZones::SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, + int16 gang0Num, int16 gang1Num, int16 gang2Num, + int16 gang3Num, int16 gang4Num, int16 gang5Num, + int16 gang6Num, int16 gang7Num, int16 gang8Num, + int16 copNum, + int16 car0Num, int16 car1Num, int16 car2Num, + int16 car3Num, int16 car4Num, int16 car5Num) +{ + CZone *zone; + CZoneInfo *info; + zone = GetZone(zoneid); + info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; + + CheckZoneInfo(info); + + if(carDensity != -1) info->carDensity = carDensity; + int16 oldCar1Num = info->carThreshold[1] - info->carThreshold[0]; + int16 oldCar2Num = info->carThreshold[2] - info->carThreshold[1]; + int16 oldCar3Num = info->carThreshold[3] - info->carThreshold[2]; + int16 oldCar4Num = info->carThreshold[4] - info->carThreshold[3]; + int16 oldCar5Num = info->carThreshold[5] - info->carThreshold[4]; + int16 oldCopNum = info->copThreshold - info->carThreshold[5]; + int16 oldGang0Num = info->gangThreshold[0] - info->copThreshold; + int16 oldGang1Num = info->gangThreshold[1] - info->gangThreshold[0]; + int16 oldGang2Num = info->gangThreshold[2] - info->gangThreshold[1]; + int16 oldGang3Num = info->gangThreshold[3] - info->gangThreshold[2]; + int16 oldGang4Num = info->gangThreshold[4] - info->gangThreshold[3]; + int16 oldGang5Num = info->gangThreshold[5] - info->gangThreshold[4]; + int16 oldGang6Num = info->gangThreshold[6] - info->gangThreshold[5]; + int16 oldGang7Num = info->gangThreshold[7] - info->gangThreshold[6]; + int16 oldGang8Num = info->gangThreshold[8] - info->gangThreshold[7]; + + if(car0Num != -1) info->carThreshold[0] = car0Num; + if(car1Num != -1) info->carThreshold[1] = info->carThreshold[0] + car1Num; + else info->carThreshold[1] = info->carThreshold[0] + oldCar1Num; + if(car2Num != -1) info->carThreshold[2] = info->carThreshold[1] + car2Num; + else info->carThreshold[2] = info->carThreshold[1] + oldCar2Num; + if(car3Num != -1) info->carThreshold[3] = info->carThreshold[2] + car3Num; + else info->carThreshold[3] = info->carThreshold[2] + oldCar3Num; + if(car4Num != -1) info->carThreshold[4] = info->carThreshold[3] + car4Num; + else info->carThreshold[4] = info->carThreshold[3] + oldCar4Num; + if(car5Num != -1) info->carThreshold[5] = info->carThreshold[4] + car5Num; + else info->carThreshold[5] = info->carThreshold[4] + oldCar5Num; + if(copNum != -1) info->copThreshold = info->carThreshold[5] + copNum; + else info->copThreshold = info->carThreshold[5] + oldCopNum; + if(gang0Num != -1) info->gangThreshold[0] = info->copThreshold + gang0Num; + else info->gangThreshold[0] = info->copThreshold + oldGang0Num; + if(gang1Num != -1) info->gangThreshold[1] = info->gangThreshold[0] + gang1Num; + else info->gangThreshold[1] = info->gangThreshold[0] + oldGang1Num; + if(gang2Num != -1) info->gangThreshold[2] = info->gangThreshold[1] + gang2Num; + else info->gangThreshold[2] = info->gangThreshold[1] + oldGang2Num; + if(gang3Num != -1) info->gangThreshold[3] = info->gangThreshold[2] + gang3Num; + else info->gangThreshold[3] = info->gangThreshold[2] + oldGang3Num; + if(gang4Num != -1) info->gangThreshold[4] = info->gangThreshold[3] + gang4Num; + else info->gangThreshold[4] = info->gangThreshold[3] + oldGang4Num; + if(gang5Num != -1) info->gangThreshold[5] = info->gangThreshold[4] + gang5Num; + else info->gangThreshold[5] = info->gangThreshold[4] + oldGang5Num; + if(gang6Num != -1) info->gangThreshold[6] = info->gangThreshold[5] + gang6Num; + else info->gangThreshold[6] = info->gangThreshold[5] + oldGang6Num; + if(gang7Num != -1) info->gangThreshold[7] = info->gangThreshold[6] + gang7Num; + else info->gangThreshold[7] = info->gangThreshold[6] + oldGang7Num; + if(gang8Num != -1) info->gangThreshold[8] = info->gangThreshold[7] + gang8Num; + else info->gangThreshold[8] = info->gangThreshold[7] + oldGang8Num; + + CheckZoneInfo(info); +} + +void +CTheZones::SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, + int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, + int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, + int16 gang8Density, int16 copDensity) +{ + CZone *zone; + CZoneInfo *info; + zone = GetZone(zoneid); + info = &ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight]; + if(pedDensity != -1) info->pedDensity = pedDensity; + if(copDensity != -1) info->copDensity = copDensity; + if(gang0Density != -1) info->gangDensity[0] = gang0Density; + if(gang1Density != -1) info->gangDensity[1] = gang1Density; + if(gang2Density != -1) info->gangDensity[2] = gang2Density; + if(gang3Density != -1) info->gangDensity[3] = gang3Density; + if(gang4Density != -1) info->gangDensity[4] = gang4Density; + if(gang5Density != -1) info->gangDensity[5] = gang5Density; + if(gang6Density != -1) info->gangDensity[6] = gang6Density; + if(gang7Density != -1) info->gangDensity[7] = gang7Density; + if(gang8Density != -1) info->gangDensity[8] = gang8Density; +} + +void +CTheZones::SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].carDensity = cardensity; +} + +void +CTheZones::SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedDensity = peddensity; +} + +void +CTheZones::SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup) +{ + CZone *zone; + zone = GetZone(zoneid); + if(zone->type == ZONE_AUDIO || zone->type == ZONE_TYPE1 || zone->type == ZONE_TYPE2) + ZoneInfoArray[day ? zone->zoneinfoDay : zone->zoneinfoNight].pedGroup = pedgroup; +} + +int16 +CTheZones::FindAudioZone(CVector *pos) +{ + int i; + + for(i = 0; i < NumberOfAudioZones; i++) + if(PointLiesWithinZone(*pos, GetZone(AudioZoneArray[i]))) + return i; + return -1; +} + +eLevelName +CTheZones::FindZoneForPoint(const CVector &pos) +{ + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("IND_ZON")))) + return LEVEL_INDUSTRIAL; + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("COM_ZON")))) + return LEVEL_COMMERCIAL; + if(PointLiesWithinZone(pos, GetZone(FindZoneByLabelAndReturnIndex("SUB_ZON")))) + return LEVEL_SUBURBAN; + return LEVEL_NONE; +} + +void +CTheZones::AddZoneToAudioZoneArray(CZone *zone) +{ + int i, z; + + if(zone->type != ZONE_AUDIO) + return; + + /* This is a bit stupid */ + z = -1; + for(i = 0; i < NUMZONES; i++) + if(&ZoneArray[i] == zone) + z = i; + AudioZoneArray[NumberOfAudioZones++] = z; +} + +void +CTheZones::InitialiseAudioZoneArray(void) +{ + bool gonext; + CZone *zone; + + gonext = false; + zone = &ZoneArray[0]; + // Go deep first, + // set gonext when backing up a level to visit the next child + while(zone) + if(gonext){ + AddZoneToAudioZoneArray(zone); + if(zone->next){ + gonext = false; + zone = zone->next; + }else + zone = zone->parent; + }else if(zone->child) + zone = zone->child; + else{ + AddZoneToAudioZoneArray(zone); + if(zone->next) + zone = zone->next; + else{ + gonext = true; + zone = zone->parent; + } + } +} + +void +CTheZones::SaveAllZones(uint8 *buffer, uint32 *length) +{ + int i; + + *length = 8 + 12 + + NUMZONES*56 + 2*NUMZONES*58 + 4 + + NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4; + + buffer[0] = 'Z'; + buffer[1] = 'N'; + buffer[2] = 'S'; + buffer[3] = '\0'; + *(uint32*)(buffer+4) = *length - 8; + buffer += 8; + + *(int32*)(buffer) = GetIndexForZonePointer(m_pPlayersZone); + *(int32*)(buffer+4) = m_CurrLevel; + *(int16*)(buffer+8) = FindIndex; + *(int16*)(buffer+10) = 0; + buffer += 12; + + for(i = 0; i < NUMZONES; i++){ + memcpy(buffer, ZoneArray[i].name, 8); + *(float*)(buffer+8) = ZoneArray[i].minx; + *(float*)(buffer+12) = ZoneArray[i].miny; + *(float*)(buffer+16) = ZoneArray[i].minz; + *(float*)(buffer+20) = ZoneArray[i].maxx; + *(float*)(buffer+24) = ZoneArray[i].maxy; + *(float*)(buffer+28) = ZoneArray[i].maxz; + *(int32*)(buffer+32) = ZoneArray[i].type; + *(int32*)(buffer+36) = ZoneArray[i].level; + *(int16*)(buffer+40) = ZoneArray[i].zoneinfoDay; + *(int16*)(buffer+42) = ZoneArray[i].zoneinfoNight; + *(int32*)(buffer+44) = GetIndexForZonePointer(ZoneArray[i].child); + *(int32*)(buffer+48) = GetIndexForZonePointer(ZoneArray[i].parent); + *(int32*)(buffer+52) = GetIndexForZonePointer(ZoneArray[i].next); + buffer += 56; + } + + for(i = 0; i < 2*NUMZONES; i++){ + *(int16*)(buffer) = ZoneInfoArray[i].carDensity; + *(int16*)(buffer+2) = ZoneInfoArray[i].carThreshold[0]; + *(int16*)(buffer+4) = ZoneInfoArray[i].carThreshold[1]; + *(int16*)(buffer+6) = ZoneInfoArray[i].carThreshold[2]; + *(int16*)(buffer+8) = ZoneInfoArray[i].carThreshold[3]; + *(int16*)(buffer+10) = ZoneInfoArray[i].carThreshold[4]; + *(int16*)(buffer+12) = ZoneInfoArray[i].carThreshold[5]; + *(int16*)(buffer+14) = ZoneInfoArray[i].copThreshold; + *(int16*)(buffer+16) = ZoneInfoArray[i].gangThreshold[0]; + *(int16*)(buffer+18) = ZoneInfoArray[i].gangThreshold[1]; + *(int16*)(buffer+20) = ZoneInfoArray[i].gangThreshold[2]; + *(int16*)(buffer+22) = ZoneInfoArray[i].gangThreshold[3]; + *(int16*)(buffer+24) = ZoneInfoArray[i].gangThreshold[4]; + *(int16*)(buffer+26) = ZoneInfoArray[i].gangThreshold[5]; + *(int16*)(buffer+28) = ZoneInfoArray[i].gangThreshold[6]; + *(int16*)(buffer+30) = ZoneInfoArray[i].gangThreshold[7]; + *(int16*)(buffer+32) = ZoneInfoArray[i].gangThreshold[8]; + *(uint16*)(buffer+34) = ZoneInfoArray[i].pedDensity; + *(uint16*)(buffer+36) = ZoneInfoArray[i].copDensity; + *(uint16*)(buffer+38) = ZoneInfoArray[i].gangDensity[0]; + *(uint16*)(buffer+40) = ZoneInfoArray[i].gangDensity[1]; + *(uint16*)(buffer+42) = ZoneInfoArray[i].gangDensity[2]; + *(uint16*)(buffer+44) = ZoneInfoArray[i].gangDensity[3]; + *(uint16*)(buffer+46) = ZoneInfoArray[i].gangDensity[4]; + *(uint16*)(buffer+48) = ZoneInfoArray[i].gangDensity[5]; + *(uint16*)(buffer+50) = ZoneInfoArray[i].gangDensity[6]; + *(uint16*)(buffer+52) = ZoneInfoArray[i].gangDensity[7]; + *(uint16*)(buffer+54) = ZoneInfoArray[i].gangDensity[8]; + *(uint16*)(buffer+56) = ZoneInfoArray[i].pedGroup; + buffer += 58; + } + + *(uint16*)(buffer) = TotalNumberOfZones; + *(uint16*)(buffer+2) = TotalNumberOfZoneInfos; + buffer += 4; + + for(i = 0; i < NUMMAPZONES; i++){ + memcpy(buffer, MapZoneArray[i].name, 8); + *(float*)(buffer+8) = MapZoneArray[i].minx; + *(float*)(buffer+12) = MapZoneArray[i].miny; + *(float*)(buffer+16) = MapZoneArray[i].minz; + *(float*)(buffer+20) = MapZoneArray[i].maxx; + *(float*)(buffer+24) = MapZoneArray[i].maxy; + *(float*)(buffer+28) = MapZoneArray[i].maxz; + *(int32*)(buffer+32) = MapZoneArray[i].type; + *(int32*)(buffer+36) = MapZoneArray[i].level; + *(int16*)(buffer+40) = MapZoneArray[i].zoneinfoDay; + *(int16*)(buffer+42) = MapZoneArray[i].zoneinfoNight; +#ifdef STANDALONE + // BUG: GetIndexForZonePointer uses ZoneArray + // so indices will be unpredictable with different memory layout + assert(0); +#endif + *(int32*)(buffer+44) = GetIndexForZonePointer(MapZoneArray[i].child); + *(int32*)(buffer+48) = GetIndexForZonePointer(MapZoneArray[i].parent); + *(int32*)(buffer+52) = GetIndexForZonePointer(MapZoneArray[i].next); + buffer += 56; + } + + for(i = 0; i < NUMAUDIOZONES; i++){ + *(int16*)buffer = AudioZoneArray[i]; + buffer += 2; + } + + *(uint16*)(buffer) = TotalNumberOfMapZones; + *(uint16*)(buffer+2) = NumberOfAudioZones; +} + +void +CTheZones::LoadAllZones(uint8 *buffer, uint32 length) +{ + int i; + + assert(length == 8 + 12 + + NUMZONES*56 + 2*NUMZONES*58 + 4 + + NUMMAPZONES*56 + NUMAUDIOZONES*2 + 4); + assert(buffer[0] == 'Z'); + assert(buffer[1] == 'N'); + assert(buffer[2] == 'S'); + assert(buffer[3] == '\0'); + assert(*(uint32*)(buffer+4) == length - 8); + buffer += 8; + + m_pPlayersZone = GetPointerForZoneIndex(*(int32*)(buffer)); + m_CurrLevel = (eLevelName)*(int32*)(buffer+4); + FindIndex = *(int16*)(buffer+8); + assert(*(int16*)(buffer+10) == 0); + buffer += 12; + + for(i = 0; i < NUMZONES; i++){ + memcpy(ZoneArray[i].name, buffer, 8); + ZoneArray[i].minx = *(float*)(buffer+8); + ZoneArray[i].miny = *(float*)(buffer+12); + ZoneArray[i].minz = *(float*)(buffer+16); + ZoneArray[i].maxx = *(float*)(buffer+20); + ZoneArray[i].maxy = *(float*)(buffer+24); + ZoneArray[i].maxz = *(float*)(buffer+28); + ZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); + ZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); + ZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); + ZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); + ZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); + ZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); + ZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); + buffer += 56; + } + + for(i = 0; i < 2*NUMZONES; i++){ + ZoneInfoArray[i].carDensity = *(int16*)(buffer); + ZoneInfoArray[i].carThreshold[0] = *(int16*)(buffer+2); + ZoneInfoArray[i].carThreshold[1] = *(int16*)(buffer+4); + ZoneInfoArray[i].carThreshold[2] = *(int16*)(buffer+6); + ZoneInfoArray[i].carThreshold[3] = *(int16*)(buffer+8); + ZoneInfoArray[i].carThreshold[4] = *(int16*)(buffer+10); + ZoneInfoArray[i].carThreshold[5] = *(int16*)(buffer+12); + ZoneInfoArray[i].copThreshold = *(int16*)(buffer+14); + ZoneInfoArray[i].gangThreshold[0] = *(int16*)(buffer+16); + ZoneInfoArray[i].gangThreshold[1] = *(int16*)(buffer+18); + ZoneInfoArray[i].gangThreshold[2] = *(int16*)(buffer+20); + ZoneInfoArray[i].gangThreshold[3] = *(int16*)(buffer+22); + ZoneInfoArray[i].gangThreshold[4] = *(int16*)(buffer+24); + ZoneInfoArray[i].gangThreshold[5] = *(int16*)(buffer+26); + ZoneInfoArray[i].gangThreshold[6] = *(int16*)(buffer+28); + ZoneInfoArray[i].gangThreshold[7] = *(int16*)(buffer+30); + ZoneInfoArray[i].gangThreshold[8] = *(int16*)(buffer+32); + ZoneInfoArray[i].pedDensity = *(uint16*)(buffer+34); + ZoneInfoArray[i].copDensity = *(uint16*)(buffer+36); + ZoneInfoArray[i].gangDensity[0] = *(uint16*)(buffer+38); + ZoneInfoArray[i].gangDensity[1] = *(uint16*)(buffer+40); + ZoneInfoArray[i].gangDensity[2] = *(uint16*)(buffer+42); + ZoneInfoArray[i].gangDensity[3] = *(uint16*)(buffer+44); + ZoneInfoArray[i].gangDensity[4] = *(uint16*)(buffer+46); + ZoneInfoArray[i].gangDensity[5] = *(uint16*)(buffer+48); + ZoneInfoArray[i].gangDensity[6] = *(uint16*)(buffer+50); + ZoneInfoArray[i].gangDensity[7] = *(uint16*)(buffer+52); + ZoneInfoArray[i].gangDensity[8] = *(uint16*)(buffer+54); + ZoneInfoArray[i].pedGroup = *(uint16*)(buffer+56); + buffer += 58; + } + + TotalNumberOfZones = *(uint16*)(buffer); + TotalNumberOfZoneInfos = *(uint16*)(buffer+2); + buffer += 4; + + for(i = 0; i < NUMMAPZONES; i++){ + memcpy(MapZoneArray[i].name, buffer, 8); + MapZoneArray[i].minx = *(float*)(buffer+8); + MapZoneArray[i].miny = *(float*)(buffer+12); + MapZoneArray[i].minz = *(float*)(buffer+16); + MapZoneArray[i].maxx = *(float*)(buffer+20); + MapZoneArray[i].maxy = *(float*)(buffer+24); + MapZoneArray[i].maxz = *(float*)(buffer+28); + MapZoneArray[i].type = (eZoneType)*(int32*)(buffer+32); + MapZoneArray[i].level = (eLevelName)*(int32*)(buffer+36); + MapZoneArray[i].zoneinfoDay = *(int16*)(buffer+40); + MapZoneArray[i].zoneinfoNight = *(int16*)(buffer+42); +#ifdef STANDALONE + // BUG: GetPointerForZoneIndex uses ZoneArray + // so pointers will be unpredictable with different memory layout + assert(0); +#endif + MapZoneArray[i].child = GetPointerForZoneIndex(*(int32*)(buffer+44)); + MapZoneArray[i].parent = GetPointerForZoneIndex(*(int32*)(buffer+48)); + MapZoneArray[i].next = GetPointerForZoneIndex(*(int32*)(buffer+52)); + buffer += 56; + } + + for(i = 0; i < NUMAUDIOZONES; i++){ + AudioZoneArray[i] = *(int16*)buffer; + buffer += 2; + } + + TotalNumberOfMapZones = *(uint16*)(buffer); + NumberOfAudioZones = *(uint16*)(buffer+2); +} + + +STARTPATCHES + InjectHook(0x4B5DD0, &CZone::GetTranslatedName, PATCH_JUMP); + InjectHook(0x4B5DE0, CTheZones::Init, PATCH_JUMP); + InjectHook(0x4B61D0, CTheZones::Update, PATCH_JUMP); + InjectHook(0x4B6210, CTheZones::CreateZone, PATCH_JUMP); + InjectHook(0x4B6380, CTheZones::CreateMapZone, PATCH_JUMP); + InjectHook(0x4B64C0, CTheZones::PostZoneCreation, PATCH_JUMP); + InjectHook(0x4B6500, CTheZones::InsertZoneIntoZoneHierarchy, PATCH_JUMP); + InjectHook(0x4B6530, CTheZones::InsertZoneIntoZoneHierRecursive, PATCH_JUMP); + InjectHook(0x4B65F0, CTheZones::ZoneIsEntirelyContainedWithinOtherZone, PATCH_JUMP); + InjectHook(0x4B6710, CTheZones::PointLiesWithinZone, PATCH_JUMP); + InjectHook(0x4B6910, CTheZones::GetLevelFromPosition, PATCH_JUMP); + InjectHook(0x4B69B0, CTheZones::FindSmallestZonePosition, PATCH_JUMP); + InjectHook(0x4B6790, CTheZones::FindSmallestZonePositionType, PATCH_JUMP); + InjectHook(0x4B6890, CTheZones::FindSmallestZonePositionILN, PATCH_JUMP); + InjectHook(0x4B6800, CTheZones::FindZoneByLabelAndReturnIndex, PATCH_JUMP); + InjectHook(0x4B6FA0, CTheZones::GetZone, PATCH_JUMP); + InjectHook(0x4B84F0, CTheZones::GetPointerForZoneIndex, PATCH_JUMP); + InjectHook(0x4B6A10, CTheZones::GetZoneInfo, PATCH_JUMP); + InjectHook(0x4B6FB0, CTheZones::GetZoneInfoForTimeOfDay, PATCH_JUMP); + InjectHook(0x4B6A50, CTheZones::SetZoneCarInfo, PATCH_JUMP); + InjectHook(0x4B6DC0, CTheZones::SetZonePedInfo, PATCH_JUMP); + InjectHook(0x4B6EB0, CTheZones::SetCarDensity, PATCH_JUMP); + InjectHook(0x4B6F00, CTheZones::SetPedDensity, PATCH_JUMP); + InjectHook(0x4B6F50, CTheZones::SetPedGroup, PATCH_JUMP); + InjectHook(0x4B83E0, CTheZones::FindAudioZone, PATCH_JUMP); + InjectHook(0x4B8430, CTheZones::FindZoneForPoint, PATCH_JUMP); + InjectHook(0x4B8340, CTheZones::AddZoneToAudioZoneArray, PATCH_JUMP); + InjectHook(0x4B8510, CTheZones::SaveAllZones, PATCH_JUMP); + InjectHook(0x4B8950, CTheZones::LoadAllZones, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/Zones.h b/src/core/Zones.h new file mode 100644 index 00000000..bf3957de --- /dev/null +++ b/src/core/Zones.h @@ -0,0 +1,112 @@ +#pragma once + +#include "Game.h" + +enum eZoneType +{ + ZONE_AUDIO, + ZONE_TYPE1, // this should be NAVIG + ZONE_TYPE2, // this should be INFO...but all except MAPINFO get zoneinfo?? + ZONE_MAPZONE, +}; + +class CZone +{ +public: + char name[8]; + float minx; + float miny; + float minz; + float maxx; + float maxy; + float maxz; + eZoneType type; + eLevelName level; + int16 zoneinfoDay; + int16 zoneinfoNight; + CZone *child; + CZone *parent; + CZone *next; + + wchar *GetTranslatedName(void); +}; + +class CZoneInfo +{ +public: + // Car data + int16 carDensity; + int16 carThreshold[6]; + int16 copThreshold; + int16 gangThreshold[9]; + + // Ped data + uint16 pedDensity; + uint16 copDensity; + uint16 gangDensity[9]; + uint16 pedGroup; +}; + + +class CTheZones +{ +public: + static eLevelName &m_CurrLevel; + static CZone *&m_pPlayersZone; + static int16 &FindIndex; + + static uint16 &NumberOfAudioZones; + static int16 *AudioZoneArray; //[NUMAUDIOZONES]; + static uint16 &TotalNumberOfMapZones; + static uint16 &TotalNumberOfZones; + static CZone *ZoneArray; //[NUMZONES]; + static CZone *MapZoneArray; //[NUMMAPZONES]; + static uint16 &TotalNumberOfZoneInfos; + static CZoneInfo *ZoneInfoArray; //[2*NUMZONES]; + + static void Init(void); + static void Update(void); + static void CreateZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level); + static void CreateMapZone(char *name, eZoneType type, + float minx, float miny, float minz, + float maxx, float maxy, float maxz, + eLevelName level); + static CZone *GetZone(uint16 i) { return &ZoneArray[i]; } + static void PostZoneCreation(void); + static void InsertZoneIntoZoneHierarchy(CZone *zone); + static bool InsertZoneIntoZoneHierRecursive(CZone *z1, CZone *z2); + static bool ZoneIsEntirelyContainedWithinOtherZone(CZone *z1, CZone *z2); + static bool PointLiesWithinZone(const CVector &v, CZone *zone); + static eLevelName GetLevelFromPosition(CVector const &v); + static CZone *FindSmallestZonePosition(const CVector *v); + static CZone *FindSmallestZonePositionType(const CVector *v, eZoneType type); + static CZone *FindSmallestZonePositionILN(const CVector *v); + static int16 FindZoneByLabelAndReturnIndex(char *name); + static CZoneInfo *GetZoneInfo(const CVector *v, uint8 day); + static void GetZoneInfoForTimeOfDay(const CVector *pos, CZoneInfo *info); + static void SetZoneCarInfo(uint16 zoneid, uint8 day, int16 carDensity, + int16 gang0Num, int16 gang1Num, int16 gang2Num, + int16 gang3Num, int16 gang4Num, int16 gang5Num, + int16 gang6Num, int16 gang7Num, int16 gang8Num, + int16 copNum, + int16 car0Num, int16 car1Num, int16 car2Num, + int16 car3Num, int16 car4Num, int16 car5Num); + static void SetZonePedInfo(uint16 zoneid, uint8 day, int16 pedDensity, + int16 gang0Density, int16 gang1Density, int16 gang2Density, int16 gang3Density, + int16 gang4Density, int16 gang5Density, int16 gang6Density, int16 gang7Density, + int16 gang8Density, int16 copDensity); + static void SetCarDensity(uint16 zoneid, uint8 day, uint16 cardensity); + static void SetPedDensity(uint16 zoneid, uint8 day, uint16 peddensity); + static void SetPedGroup(uint16 zoneid, uint8 day, uint16 pedgroup); + static int16 FindAudioZone(CVector *pos); + static eLevelName FindZoneForPoint(const CVector &pos); + static CZone *GetPointerForZoneIndex(int32 i) { return i == -1 ? nil : &ZoneArray[i]; } + static int32 GetIndexForZonePointer(CZone *zone) { return zone == nil ? -1 : zone - ZoneArray; } + static void AddZoneToAudioZoneArray(CZone *zone); + static void InitialiseAudioZoneArray(void); + static void SaveAllZones(uint8 *buffer, uint32 *length); + static void LoadAllZones(uint8 *buffer, uint32 length); +}; diff --git a/src/core/common.h b/src/core/common.h new file mode 100644 index 00000000..79626acb --- /dev/null +++ b/src/core/common.h @@ -0,0 +1,178 @@ +#pragma once + +#define _CRT_SECURE_NO_WARNINGS +#define _USE_MATH_DEFINES +#pragma warning(disable: 4244) // int to float +#pragma warning(disable: 4800) // int to bool +#pragma warning(disable: 4305) // double to float +#pragma warning(disable: 4838) // narrowing conversion +#pragma warning(disable: 4996) // POSIX names + +#include +#include +//#include +#include + +#ifdef WITHD3D +#include +#include +#endif + +#include +#include + +#define rwVENDORID_ROCKSTAR 0x0253F2 + +// Get rid of bullshit windows definitions, we're not running on an 8086 +#ifdef far +#undef far +#endif +#ifdef near +#undef near +#endif + +typedef uint8_t uint8; +typedef int8_t int8; +typedef uint16_t uint16; +typedef int16_t int16; +typedef uint32_t uint32; +typedef int32_t int32; +typedef uintptr_t uintptr; +typedef uint64_t uint64; +typedef int64_t int64; +// hardcode ucs-2 +typedef uint16_t wchar; + +#define nil nullptr + +#include "config.h" + +#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1)) + +// PDP-10 like byte functions +#define MASK(p, s) (((1<<(s))-1) << (p)) +inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w) +{ + uint32 m = MASK(p,s); + return w & ~m | b<

>p & (1<(high) ? (high) : (v)) + +inline float sq(float x) { return x*x; } +#define SQR(x) ((x) * (x)) + +#define PI M_PI +#define DEGTORAD(x) ((x) * PI / 180.0f) +#define RADTODEG(x) ((x) * 180.0f / PI) + +#ifdef USE_PS2_RAND +#define MYRAND_MAX 65535 +#else +#define MYRAND_MAX 32767 +#endif + +int myrand(void); +void mysrand(unsigned int seed); + +void re3_debug(char *format, ...); +void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...); +void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func); + +#define DEBUGBREAK() __debugbreak(); + +#define debug(f, ...) re3_debug("[DBG]: " f, __VA_ARGS__) +#define DEV(f, ...) re3_debug("[DEV]: " f, __VA_ARGS__) +#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, __VA_ARGS__) +#define Error(f, ...) re3_debug("[ERROR]: " f, __VA_ARGS__) + +#define assert(_Expression) (void)( (!!(_Expression)) || (re3_assert(#_Expression, __FILE__, __LINE__, __FUNCTION__), 0) ) +#define ASSERT assert + +#define _TODO(x) +#define _TODOCONST(x) (x) + +#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) +#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") + +#define PERCENT(x, p) ((float(x) * (float(p) / 100.0f))) +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#define BIT(num) (1<<(num)) + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/core/config.h b/src/core/config.h new file mode 100644 index 00000000..8cb02190 --- /dev/null +++ b/src/core/config.h @@ -0,0 +1,116 @@ +#pragma once + +enum Config { + NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC) + MAX_CDIMAGES = 8, // additional cdimages + + MODELINFOSIZE = 5500, + TXDSTORESIZE = 850, + EXTRADIRSIZE = 128, + + SIMPLEMODELSIZE = 5000, + TIMEMODELSIZE = 30, + CLUMPMODELSIZE = 5, + PEDMODELSIZE = 90, + VEHICLEMODELSIZE = 120, + TWODFXSIZE = 2000, + + MAXVEHICLESLOADED = 50, // 70 on mobile + + NUMOBJECTINFO = 168, // object.dat + + // Pool sizes + NUMPTRNODES = 30000, // 26000 on PS2 + NUMENTRYINFOS = 5400, // 3200 on PS2 + NUMPEDS = 140, // 90 on PS2 + NUMVEHICLES = 110, // 70 on PS2 + NUMBUILDINGS = 5500, // 4915 on PS2 + NUMTREADABLES = 1214, + NUMOBJECTS = 450, + NUMDUMMIES = 2802, // 2368 on PS2 + NUMAUDIOSCRIPTOBJECTS = 256, + + // Link list lengths + // TODO: alpha list + NUMCOLCACHELINKS = 200, + NUMREFERENCES = 800, + + // Zones + NUMAUDIOZONES = 36, + NUMZONES = 50, + NUMMAPZONES = 25, + + // Cull zones + NUMCULLZONES = 512, + NUMATTRIBZONES = 288, + NUMZONEINDICES = 55000, + + NUMHANDLINGS = 57, + + PATHNODESIZE = 4500, + + NUMWEATHERS = 4, + NUMHOURS = 24, + + NUMEXTRADIRECTIONALS = 4, + NUMANTENNAS = 8, + NUMCORONAS = 56, + NUMPOINTLIGHTS = 32, + + NUMONSCREENTIMERENTRIES = 1, + NUMRADARBLIPS = 32, + NUMPICKUPS = 336, +}; + +// We'll use this once we're ready to become independent of the game +// Use it to mark bugs in the code that will prevent the game from working then +//#define STANDALONE + +// We don't expect to compile for PS2 or Xbox +// but it might be interesting for documentation purposes +#define GTA_PC +//#define GTA_PS2 +//#define GTA_XBOX + +// This enables things from the PS2 version on PC +#define GTA_PS2_STUFF + +// This is enabled for all released games. +// any debug stuff that isn't left in any game is not in FINAL +//#define FINAL + +// This is enabled for all released games except mobile +// any debug stuff that is only left in mobile, is not in MASTER +//#define MASTER + +#if defined GTA_PS2 +# define RANDOMSPLASH +#elif defined GTA_PC +# define GTA3_1_1_PATCH +# ifdef GTA_PS2_STUFF +//# define USE_PS2_RAND // this is unsafe until we have the game reversed +# define RANDOMSPLASH // use random splash as on PS2 +# define PS2_MATFX +# endif +#elif defined GTA_XBOX +#endif + +#ifdef MASTER + // only in master builds +#else + // not in master builds +#endif + +#ifdef FINAL + // in all games +# define USE_MY_DOCUMENTS // use my documents directory for user files +#else + // not in any game +# define NASTY_GAME // nasty game for all languages +# define NO_MOVIES // disable intro videos +# define CHATTYSPLASH // print what the game is loading +#endif + +#define FIX_BUGS // fix bugs in the game, TODO: use this more +#define KANGAROO_CHEAT +#define ASPECT_RATIO_SCALE diff --git a/src/core/debugmenu_public.h b/src/core/debugmenu_public.h new file mode 100644 index 00000000..778e7afe --- /dev/null +++ b/src/core/debugmenu_public.h @@ -0,0 +1,154 @@ + +extern "C" { + +typedef void (*TriggerFunc)(void); + +struct DebugMenuEntry; + +typedef DebugMenuEntry *(*DebugMenuAddInt8_TYPE)(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt16_TYPE)(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt32_TYPE)(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddInt64_TYPE)(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt8_TYPE)(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt16_TYPE)(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt32_TYPE)(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddUInt64_TYPE)(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings); +typedef DebugMenuEntry *(*DebugMenuAddFloat32_TYPE)(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound); +typedef DebugMenuEntry *(*DebugMenuAddFloat64_TYPE)(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound); +typedef DebugMenuEntry *(*DebugMenuAddCmd_TYPE)(const char *path, const char *name, TriggerFunc triggerFunc); +typedef void (*DebugMenuEntrySetWrap_TYPE)(DebugMenuEntry *e, bool wrap); +typedef void (*DebugMenuEntrySetStrings_TYPE)(DebugMenuEntry *e, const char **strings); +typedef void (*DebugMenuEntrySetAddress_TYPE)(DebugMenuEntry *e, void *addr); + +struct DebugMenuAPI +{ + bool isLoaded; + HMODULE module; + DebugMenuAddInt8_TYPE addint8; + DebugMenuAddInt16_TYPE addint16; + DebugMenuAddInt32_TYPE addint32; + DebugMenuAddInt64_TYPE addint64; + DebugMenuAddUInt8_TYPE adduint8; + DebugMenuAddUInt16_TYPE adduint16; + DebugMenuAddUInt32_TYPE adduint32; + DebugMenuAddUInt64_TYPE adduint64; + DebugMenuAddFloat32_TYPE addfloat32; + DebugMenuAddFloat64_TYPE addfloat64; + DebugMenuAddCmd_TYPE addcmd; + DebugMenuEntrySetWrap_TYPE setwrap; + DebugMenuEntrySetStrings_TYPE setstrings; + DebugMenuEntrySetAddress_TYPE setaddress; +}; +extern DebugMenuAPI gDebugMenuAPI; + +inline DebugMenuEntry *DebugMenuAddInt8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddInt64(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt8(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt16(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt32(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddUInt64(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddFloat32(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) +{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddFloat64(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) +{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddCmd(const char *path, const char *name, TriggerFunc triggerFunc) +{ return gDebugMenuAPI.addcmd(path, name, triggerFunc); } +inline void DebugMenuEntrySetWrap(DebugMenuEntry *e, bool wrap) +{ gDebugMenuAPI.setwrap(e, wrap); } +inline void DebugMenuEntrySetStrings(DebugMenuEntry *e, const char **strings) +{ gDebugMenuAPI.setstrings(e, strings); } +inline void DebugMenuEntrySetAddress(DebugMenuEntry *e, void *addr) +{ gDebugMenuAPI.setaddress(e, addr); } + +inline bool DebugMenuLoad(void) +{ + if(gDebugMenuAPI.isLoaded) + return true; + HMODULE mod = LoadLibraryA("debugmenu"); + if(mod == nil){ + char modulePath[MAX_PATH]; + HMODULE dllModule; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&gDebugMenuAPI, &dllModule); + GetModuleFileNameA(dllModule, modulePath, MAX_PATH); + char *p = strchr(modulePath, '\\'); + if(p) p[1] = '\0'; + strcat(modulePath, "debugmenu"); + mod = LoadLibraryA(modulePath); + } + if(mod == nil) + return false; + gDebugMenuAPI.addint8 = (DebugMenuAddInt8_TYPE)GetProcAddress(mod, "DebugMenuAddInt8"); + gDebugMenuAPI.addint16 = (DebugMenuAddInt16_TYPE)GetProcAddress(mod, "DebugMenuAddInt16"); + gDebugMenuAPI.addint32 = (DebugMenuAddInt32_TYPE)GetProcAddress(mod, "DebugMenuAddInt32"); + gDebugMenuAPI.addint64 = (DebugMenuAddInt64_TYPE)GetProcAddress(mod, "DebugMenuAddInt64"); + gDebugMenuAPI.adduint8 = (DebugMenuAddUInt8_TYPE)GetProcAddress(mod, "DebugMenuAddUInt8"); + gDebugMenuAPI.adduint16 = (DebugMenuAddUInt16_TYPE)GetProcAddress(mod, "DebugMenuAddUInt16"); + gDebugMenuAPI.adduint32 = (DebugMenuAddUInt32_TYPE)GetProcAddress(mod, "DebugMenuAddUInt32"); + gDebugMenuAPI.adduint64 = (DebugMenuAddUInt64_TYPE)GetProcAddress(mod, "DebugMenuAddUInt64"); + gDebugMenuAPI.addfloat32 = (DebugMenuAddFloat32_TYPE)GetProcAddress(mod, "DebugMenuAddFloat32"); + gDebugMenuAPI.addfloat64 = (DebugMenuAddFloat64_TYPE)GetProcAddress(mod, "DebugMenuAddFloat64"); + gDebugMenuAPI.addcmd = (DebugMenuAddCmd_TYPE)GetProcAddress(mod, "DebugMenuAddCmd"); + gDebugMenuAPI.setwrap = (DebugMenuEntrySetWrap_TYPE)GetProcAddress(mod, "DebugMenuEntrySetWrap"); + gDebugMenuAPI.setstrings = (DebugMenuEntrySetStrings_TYPE)GetProcAddress(mod, "DebugMenuEntrySetStrings"); + gDebugMenuAPI.setaddress = (DebugMenuEntrySetAddress_TYPE)GetProcAddress(mod, "DebugMenuEntrySetAddress"); + gDebugMenuAPI.isLoaded = true; + gDebugMenuAPI.module = mod; + return true; +} + +} + +// Also overload them for simplicity + +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) +{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) +{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) +{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } +inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) +{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } + +inline DebugMenuEntry *DebugMenuAddVarBool32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} +inline DebugMenuEntry *DebugMenuAddVarBool16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} +inline DebugMenuEntry *DebugMenuAddVarBool8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc) +{ + static const char *boolstr[] = { "Off", "On" }; + DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); + DebugMenuEntrySetWrap(e, true); + return e; +} diff --git a/src/core/main.cpp b/src/core/main.cpp new file mode 100644 index 00000000..e7f42780 --- /dev/null +++ b/src/core/main.cpp @@ -0,0 +1,891 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "General.h" +#include "RwHelper.h" +#include "Clouds.h" +#include "Draw.h" +#include "Sprite2d.h" +#include "Renderer.h" +#include "Coronas.h" +#include "WaterLevel.h" +#include "Weather.h" +#include "Glass.h" +#include "WaterCannon.h" +#include "SpecialFX.h" +#include "Shadows.h" +#include "Skidmarks.h" +#include "Antennas.h" +#include "Rubbish.h" +#include "Particle.h" +#include "Pickups.h" +#include "WeaponEffects.h" +#include "PointLights.h" +#include "Fluff.h" +#include "Replay.h" +#include "Camera.h" +#include "World.h" +#include "Ped.h" +#include "Font.h" +#include "Pad.h" +#include "Hud.h" +#include "User.h" +#include "Messages.h" +#include "Darkel.h" +#include "Garages.h" +#include "MusicManager.h" +#include "VisibilityPlugins.h" +#include "NodeName.h" +#include "DMAudio.h" +#include "CutsceneMgr.h" +#include "Lights.h" +#include "Credits.h" +#include "ZoneCull.h" +#include "Timecycle.h" +#include "TxdStore.h" +#include "FileMgr.h" +#include "Text.h" +#include "RpAnimBlend.h" +#include "Frontend.h" + +#define DEFAULT_VIEWWINDOW (tan(DEGTORAD(CDraw::GetFOV() * 0.5f))) + + +GlobalScene &Scene = *(GlobalScene*)0x726768; + +uint8 work_buff[55000]; +char gString[256]; +wchar *gUString = (wchar*)0x74B018; + +bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8; + + +bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha); +void DoRWStuffEndOfFrame(void); + +void RenderScene(void); +void RenderDebugShit(void); +void RenderEffects(void); +void Render2dStuff(void); +void RenderMenus(void); +void DoFade(void); +void Render2dStuffAfterFade(void); + +CSprite2d *LoadSplash(const char *name); +void DestroySplashScreen(void); + + +extern void (*DebugMenuProcess)(void); +extern void (*DebugMenuRender)(void); +void DebugMenuInit(void); +void DebugMenuPopulate(void); + +void PrintGameVersion(); + +RwRGBA gColourTop; + +void +InitialiseGame(void) +{ + LoadingScreen(nil, nil, "loadsc0"); + CGame::Initialise("DATA\\GTA3.DAT"); +} + +void +Idle(void *arg) +{ +#ifdef ASPECT_RATIO_SCALE + CDraw::SetAspectRatio(CDraw::FindAspectRatio()); +#endif + + CTimer::Update(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + CPointLights::InitPerFrame(); + CGame::Process(); + DMAudio.Service(); + + if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){ + FrontEndMenuManager.m_bStartGameLoading = true; + FrontEndMenuManager.m_bLoadingSavedGame = false; + return; + } + + if(FrontEndMenuManager.m_bStartGameLoading || b_FoundRecentSavedGameWantToLoad) + return; + + SetLightsWithTimeOfDayColour(Scene.world); + + if(arg == nil) + return; + + if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.field_452 == 1) && + TheCamera.GetScreenFadeStatus() != FADE_2){ +#ifdef GTA_PC + // This is from SA, but it's nice for windowed mode + RwV2d pos; + pos.x = SCREEN_WIDTH/2.0f; + pos.y = SCREEN_HEIGHT/2.0f; + RsMouseSetPos(&pos); +#endif + CRenderer::ConstructRenderList(); + CRenderer::PreRender(); + + if(CWeather::LightningFlash && !CCullZones::CamNoRain()){ + if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255)) + return; + }else{ + if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(), + CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), + 255)) + return; + } + + DefinedState(); + + // BUG. This has to be done BEFORE RwCameraBeginUpdate + RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip()); + RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart()); + + RenderScene(); + RenderDebugShit(); + RenderEffects(); + + if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) && + TheCamera.m_ScreenReductionPercentage > 0.0) + TheCamera.SetMotionBlurAlpha(150); + TheCamera.RenderMotionBlur(); + + Render2dStuff(); + }else{ + float viewWindow = DEFAULT_VIEWWINDOW; + CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO); + CVisibilityPlugins::SetRenderWareCamera(Scene.camera); + RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + if(!RsCameraBeginUpdate(Scene.camera)) + return; + } + + RenderMenus(); +#ifndef FINAL + PrintGameVersion(); +#endif + DoFade(); + Render2dStuffAfterFade(); + CCredits::Render(); + DoRWStuffEndOfFrame(); + +// if(g_SlowMode) +// ProcessSlowMode(); +} + +void +FrontendIdle(void) +{ +#ifdef ASPECT_RATIO_SCALE + CDraw::SetAspectRatio(CDraw::FindAspectRatio()); +#endif + + CTimer::Update(); + CSprite2d::SetRecipNearClip(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + CPad::UpdatePads(); + FrontEndMenuManager.Process(); + + if(RsGlobal.quit) + return; + + float viewWindow = DEFAULT_VIEWWINDOW; + CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO); + CVisibilityPlugins::SetRenderWareCamera(Scene.camera); + RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + if(!RsCameraBeginUpdate(Scene.camera)) + return; + + DefinedState(); + RenderMenus(); +#ifndef FINAL + PrintGameVersion(); +#endif + DoFade(); + Render2dStuffAfterFade(); + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); +} + +bool +DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha) +{ + CRGBA TopColor(TopRed, TopGreen, TopBlue, Alpha); + CRGBA BottomColor(BottomRed, BottomGreen, BottomBlue, Alpha); + + CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO); + CVisibilityPlugins::SetRenderWareCamera(Scene.camera); + RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + + if(!RsCameraBeginUpdate(Scene.camera)) + return false; + + CSprite2d::InitPerFrame(); + + if(Alpha != 0) + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), BottomColor, BottomColor, TopColor, TopColor); + + return true; +} + +bool +DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha) +{ + CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO); + CVisibilityPlugins::SetRenderWareCamera(Scene.camera); + RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); + + if(!RsCameraBeginUpdate(Scene.camera)) + return false; + + TheCamera.m_viewMatrix.Update(); + CClouds::RenderBackground(TopRed, TopGreen, TopBlue, BottomRed, BottomGreen, BottomBlue, Alpha); + + return true; +} + +void +DoRWStuffEndOfFrame(void) +{ + // CDebug::DebugDisplayTextBuffer(); + // FlushObrsPrintfs(); + RwCameraEndUpdate(Scene.camera); + RsCameraShowRaster(Scene.camera); +} + + +// This is certainly a very useful function +void +DoRWRenderHorizon(void) +{ + CClouds::RenderHorizon(); +} + +void +RenderScene(void) +{ + CClouds::Render(); + DoRWRenderHorizon(); + CRenderer::RenderRoads(); + CCoronas::RenderReflections(); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); + CRenderer::RenderEverythingBarRoads(); + CRenderer::RenderBoats(); + DefinedState(); + CWaterLevel::RenderWater(); + CRenderer::RenderFadingInEntities(); + CRenderer::RenderVehiclesButNotBoats(); + CWeather::RenderRainStreaks(); +} + +void +RenderDebugShit(void) +{ + // CTheScripts::RenderTheScriptDebugLines() +} + +void +RenderEffects(void) +{ + CGlass::Render(); + CWaterCannons::Render(); + CSpecialFX::Render(); + CShadows::RenderStaticShadows(); + CShadows::RenderStoredShadows(); + CSkidmarks::Render(); + CAntennas::Render(); + CRubbish::Render(); + CCoronas::Render(); + CParticle::Render(); + CPacManPickups::Render(); + CWeaponEffects::Render(); + CPointLights::RenderFogEffect(); + CMovingThings::Render(); + CRenderer::RenderFirstPersonVehicle(); +} + +void +Render2dStuff(void) +{ + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE); + + CReplay::Display(); + CPickups::RenderPickUpText(); + + if(TheCamera.m_WideScreenOn) + TheCamera.DrawBordersForWideScreen(); + + CPed *player = FindPlayerPed(); + int weaponType = 0; + if(player) + weaponType = player->GetWeapon()->m_eWeaponType; + + bool firstPersonWeapon = false; + int cammode = TheCamera.Cams[TheCamera.ActiveCam].Mode; + if(cammode == CCam::MODE_SNIPER || + cammode == CCam::MODE_SNIPER_RUN_AROUND || + cammode == CCam::MODE_ROCKET || + cammode == CCam::MODE_ROCKET_RUN_AROUND) + firstPersonWeapon = true; + + // Draw black border for sniper and rocket launcher + if((weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) && firstPersonWeapon){ + CRGBA black(0, 0, 0, 255); + + // top and bottom strips + if (weaponType == WEAPONTYPE_ROCKETLAUNCHER) { + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(180)), black); + CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(170), SCREEN_WIDTH, SCREEN_HEIGHT), black); + } + else { + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(210)), black); + CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(210), SCREEN_WIDTH, SCREEN_HEIGHT), black); + } + CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH / 2 - SCREEN_SCALE_X(210), SCREEN_HEIGHT), black); + CSprite2d::DrawRect(CRect(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(210), 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), black); + } + + MusicManager.DisplayRadioStationName(); +// TheConsole.Display(); +/* + if(CSceneEdit::m_bEditOn) + CSceneEdit::Draw(); + else +*/ + CHud::Draw(); + CUserDisplay::OnscnTimer.ProcessForDisplay(); + CMessages::Display(); + CDarkel::DrawMessages(); + CGarages::PrintMessages(); + CPad::PrintErrorMessage(); + CFont::DrawFonts(); + + DebugMenuRender(); +} + +void +RenderMenus(void) +{ + if(FrontEndMenuManager.m_bMenuActive) + FrontEndMenuManager.DrawFrontEnd(); +} + +bool &JustLoadedDontFadeInYet = *(bool*)0x95CDB4; +bool &StillToFadeOut = *(bool*)0x95CD99; +uint32 &TimeStartedCountingForFade = *(uint32*)0x9430EC; +uint32 &TimeToStayFadedBeforeFadeOut = *(uint32*)0x611564; + +void +DoFade(void) +{ + if(CTimer::GetIsPaused()) + return; + + if(JustLoadedDontFadeInYet){ + JustLoadedDontFadeInYet = false; + TimeStartedCountingForFade = CTimer::GetTimeInMilliseconds(); + } + + if(StillToFadeOut){ + if(CTimer::GetTimeInMilliseconds() - TimeStartedCountingForFade > TimeToStayFadedBeforeFadeOut){ + StillToFadeOut = false; + TheCamera.Fade(3.0f, FADE_IN); + TheCamera.ProcessFade(); + TheCamera.ProcessMusicFade(); + }else{ + TheCamera.SetFadeColour(0, 0, 0); + TheCamera.Fade(0.0f, FADE_OUT); + TheCamera.ProcessFade(); + } + } + + if(CDraw::FadeValue != 0 || CMenuManager::m_PrefsBrightness < 256){ + CSprite2d *splash = LoadSplash(nil); + + CRGBA fadeColor; + CRect rect; + int fadeValue = CDraw::FadeValue; + float brightness = min(CMenuManager::m_PrefsBrightness, 256); + if(brightness <= 50) + brightness = 50; + if(FrontEndMenuManager.m_bMenuActive) + brightness = 256; + + if(TheCamera.m_FadeTargetIsSplashScreen) + fadeValue = 0; + + float fade = fadeValue + 256 - brightness; + if(fade == 0){ + fadeColor.r = 0; + fadeColor.g = 0; + fadeColor.b = 0; + fadeColor.a = 0; + }else{ + fadeColor.r = fadeValue * CDraw::FadeRed / fade; + fadeColor.g = fadeValue * CDraw::FadeGreen / fade; + fadeColor.b = fadeValue * CDraw::FadeBlue / fade; + int alpha = 255 - brightness*(256 - fadeValue)/256; + if(alpha < 0) + alpha = 0; + fadeColor.a = alpha; + } + + if(TheCamera.m_WideScreenOn){ + // what's this? + float y = SCREEN_HEIGHT/2 * TheCamera.m_ScreenReductionPercentage/100.0f; + rect.left = 0.0f; + rect.right = SCREEN_WIDTH; + rect.top = y - 8.0f; + rect.bottom = SCREEN_HEIGHT - y - 8.0f; + }else{ + rect.left = 0.0f; + rect.right = SCREEN_WIDTH; + rect.top = 0.0f; + rect.bottom = SCREEN_HEIGHT; + } + CSprite2d::DrawRect(rect, fadeColor); + + if(CDraw::FadeValue != 0 && TheCamera.m_FadeTargetIsSplashScreen){ + fadeColor.r = 255; + fadeColor.g = 255; + fadeColor.b = 255; + fadeColor.a = CDraw::FadeValue; + splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), fadeColor, fadeColor, fadeColor, fadeColor); + } + } +} + +void +Render2dStuffAfterFade(void) +{ + CHud::DrawAfterFade(); + CFont::DrawFonts(); +} + +CSprite2d splash; +int splashTxdId = -1; + +CSprite2d* +LoadSplash(const char *name) +{ + RwTexDictionary *txd; + char filename[140]; + RwTexture *tex = nil; + + if(name == nil) + return &splash; + if(splashTxdId == -1) + splashTxdId = CTxdStore::AddTxdSlot("splash"); + + txd = CTxdStore::GetSlot(splashTxdId)->texDict; + if(txd) + tex = RwTexDictionaryFindNamedTexture(txd, name); + // if texture is found, splash was already set up below + + if(tex == nil){ + CFileMgr::SetDir("TXD\\"); + sprintf(filename, "%s.txd", name); + if(splash.m_pTexture) + splash.Delete(); + if(txd) + CTxdStore::RemoveTxd(splashTxdId); + CTxdStore::LoadTxd(splashTxdId, filename); + CTxdStore::AddRef(splashTxdId); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(splashTxdId); + splash.SetTexture(name); + CTxdStore::PopCurrentTxd(); + CFileMgr::SetDir(""); + } + + return &splash; +} + +void +DestroySplashScreen(void) +{ + splash.Delete(); + if(splashTxdId != -1) + CTxdStore::RemoveTxdSlot(splashTxdId); + splashTxdId = -1; +} + +float NumberOfChunksLoaded; +#define TOTALNUMCHUNKS 73.0f + +// TODO: compare with PS2 +void +LoadingScreen(const char *str1, const char *str2, const char *splashscreen) +{ + CSprite2d *splash; + +#ifndef RANDOMSPLASH + if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) + splashscreen = "mainsc2"; + else + splashscreen = "mainsc1"; +#endif + + splash = LoadSplash(splashscreen); + + if(RsGlobal.quit) + return; + + if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){ + CSprite2d::SetRecipNearClip(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + DefinedState(); + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); + splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); + + if(str1){ + NumberOfChunksLoaded += 1; + + float hpos = SCREEN_SCALE_X(40); + float length = SCREEN_WIDTH - SCREEN_SCALE_X(100); + float vpos = SCREEN_HEIGHT - SCREEN_SCALE_Y(13); + float height = SCREEN_SCALE_Y(7); + CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255)); + + length *= NumberOfChunksLoaded/TOTALNUMCHUNKS; + CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255)); + + // this is done by the game but is unused + CFont::SetScale(SCREEN_SCALE_X(2), SCREEN_SCALE_Y(2)); + CFont::SetPropOn(); + CFont::SetRightJustifyOn(); + CFont::SetFontStyle(FONT_HEADING); + +#ifdef CHATTYSPLASH + // my attempt + static wchar tmpstr[80]; + float scale = SCREEN_SCALE_Y(0.8f); + vpos -= 50*scale; + CFont::SetScale(scale, scale); + CFont::SetPropOn(); + CFont::SetRightJustifyOff(); + CFont::SetFontStyle(FONT_BANK); + CFont::SetColor(CRGBA(255, 255, 255, 255)); + AsciiToUnicode(str1, tmpstr); + CFont::PrintString(hpos, vpos, tmpstr); + vpos += 25*scale; + AsciiToUnicode(str2, tmpstr); + CFont::PrintString(hpos, vpos, tmpstr); +#endif + } + + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); + } +} + +void +ResetLoadingScreenBar(void) +{ + NumberOfChunksLoaded = 0.0f; +} + +void +LoadingIslandScreen(const char *levelName) +{ + CSprite2d *splash; + wchar *name; + char str[100]; + wchar wstr[80]; + CRGBA col; + + splash = LoadSplash(nil); + name = TheText.Get(levelName); + if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)) + return; + + CSprite2d::SetRecipNearClip(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + DefinedState(); + col = CRGBA(255, 255, 255, 255); + splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col); + CFont::SetBackgroundOff(); + CFont::SetScale(1.5f, 1.5f); + CFont::SetPropOn(); + CFont::SetRightJustifyOn(); + CFont::SetRightJustifyWrap(150.0f); + CFont::SetFontStyle(FONT_HEADING); + sprintf(str, "WELCOME TO"); + AsciiToUnicode(str, wstr); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + CFont::SetDropShadowPosition(3); + CFont::SetColor(CRGBA(243, 237, 71, 255)); + CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); + CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); + TextCopy(wstr, name); + TheText.UpperCase(wstr); + CFont::SetColor(CRGBA(243, 237, 71, 255)); + CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); + CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); +} + +char* +GetLevelSplashScreen(int level) +{ + static char *splashScreens[4] = { + nil, + "splash1", + "splash2", + "splash3", + }; + + return splashScreens[level]; +} + +char* +GetRandomSplashScreen(void) +{ + int index; + static int index2 = 0; + static char splashName[128]; + static int splashIndex[24] = { + 25, 22, 4, 13, + 1, 21, 14, 16, + 10, 12, 5, 9, + 11, 18, 3, 2, + 19, 23, 7, 17, + 15, 6, 8, 20 + }; + + index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)]; + index2++; + if(index2 == 6) + index2 = 0; + sprintf(splashName, "loadsc%d", index); + return splashName; +} + +#include "rwcore.h" +#include "rpworld.h" +#include "rpmatfx.h" +#include "rpskin.h" +#include "rphanim.h" +#include "rtbmp.h" + +_TODO("temp, move this includes out of here") + +static RwBool +PluginAttach(void) +{ + if( !RpWorldPluginAttach() ) + { + printf("Couldn't attach world plugin\n"); + + return FALSE; + } + + if( !RpSkinPluginAttach() ) + { + printf("Couldn't attach RpSkin plugin\n"); + + return FALSE; + } + + if( !RpHAnimPluginAttach() ) + { + printf("Couldn't attach RpHAnim plugin\n"); + + return FALSE; + } + + if( !NodeNamePluginAttach() ) + { + printf("Couldn't attach node name plugin\n"); + + return FALSE; + } + + if( !CVisibilityPlugins::PluginAttach() ) + { + printf("Couldn't attach visibility plugins\n"); + + return FALSE; + } + + if( !RpAnimBlendPluginAttach() ) + { + printf("Couldn't attach RpAnimBlend plugin\n"); + + return FALSE; + } + + if( !RpMatFXPluginAttach() ) + { + printf("Couldn't attach RpMatFX plugin\n"); + + return FALSE; + } + + return TRUE; +} + +static RwBool +Initialise3D(void *param) +{ + if (RsRwInitialise(param)) + { + // + DebugMenuInit(); + DebugMenuPopulate(); + // + + return CGame::InitialiseRenderWare(); + } + + return (FALSE); +} + + +static void +Terminate3D(void) +{ + CGame::ShutdownRenderWare(); + + RsRwTerminate(); + + return; +} + +RsEventStatus +AppEventHandler(RsEvent event, void *param) +{ + switch( event ) + { + case rsINITIALISE: + { + CGame::InitialiseOnceBeforeRW(); + return RsInitialise() ? rsEVENTPROCESSED : rsEVENTERROR; + } + + case rsCAMERASIZE: + { + + CameraSize(Scene.camera, (RwRect *)param, + DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO); + + return rsEVENTPROCESSED; + } + + case rsRWINITIALISE: + { + return Initialise3D(param) ? rsEVENTPROCESSED : rsEVENTERROR; + } + + case rsRWTERMINATE: + { + Terminate3D(); + + return rsEVENTPROCESSED; + } + + case rsTERMINATE: + { + CGame::FinalShutdown(); + + return rsEVENTPROCESSED; + } + + case rsPLUGINATTACH: + { + return PluginAttach() ? rsEVENTPROCESSED : rsEVENTERROR; + } + + case rsINPUTDEVICEATTACH: + { + AttachInputDevices(); + + return rsEVENTPROCESSED; + } + + case rsIDLE: + { + Idle(param); + + return rsEVENTPROCESSED; + } + + case rsFRONTENDIDLE: + { + FrontendIdle(); + + return rsEVENTPROCESSED; + } + + case rsACTIVATE: + { + param ? DMAudio.ReacquireDigitalHandle() : DMAudio.ReleaseDigitalHandle(); + + return rsEVENTPROCESSED; + } + + default: + { + return rsEVENTNOTPROCESSED; + } + } +} + +void PrintGameVersion() +{ + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.5f)); + CFont::SetCentreOff(); + CFont::SetRightJustifyOff(); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetFontStyle(FONT_BANK); + CFont::SetWrapx(SCREEN_WIDTH); + CFont::SetDropShadowPosition(0); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + CFont::SetColor(CRGBA(235, 170, 50, 255)); + + strcpy(gString, "RE3"); + AsciiToUnicode(gString, gUString); + CFont::PrintString(SCREEN_SCALE_X(10.5f), SCREEN_SCALE_Y(8.0f), gUString); +} + +STARTPATCHES + InjectHook(0x48E480, Idle, PATCH_JUMP); + InjectHook(0x48E700, FrontendIdle, PATCH_JUMP); + + InjectHook(0x48CF10, DoRWStuffStartOfFrame, PATCH_JUMP); + InjectHook(0x48D040, DoRWStuffStartOfFrame_Horizon, PATCH_JUMP); + InjectHook(0x48E030, RenderScene, PATCH_JUMP); + InjectHook(0x48E080, RenderDebugShit, PATCH_JUMP); + InjectHook(0x48E090, RenderEffects, PATCH_JUMP); + InjectHook(0x48E0E0, Render2dStuff, PATCH_JUMP); + InjectHook(0x48E450, RenderMenus, PATCH_JUMP); + InjectHook(0x48D120, DoFade, PATCH_JUMP); + InjectHook(0x48E470, Render2dStuffAfterFade, PATCH_JUMP); + + InjectHook(0x48D550, LoadSplash, PATCH_JUMP); + InjectHook(0x48D670, DestroySplashScreen, PATCH_JUMP); + InjectHook(0x48D770, LoadingScreen, PATCH_JUMP); + InjectHook(0x48D760, ResetLoadingScreenBar, PATCH_JUMP); + + InjectHook(0x48D470, PluginAttach, PATCH_JUMP); + InjectHook(0x48D520, Initialise3D, PATCH_JUMP); + InjectHook(0x48D540, Terminate3D, PATCH_JUMP); + InjectHook(0x48E800, AppEventHandler, PATCH_JUMP); +ENDPATCHES diff --git a/src/core/main.h b/src/core/main.h new file mode 100644 index 00000000..bdb0e008 --- /dev/null +++ b/src/core/main.h @@ -0,0 +1,22 @@ +#pragma once + +struct GlobalScene +{ + RpWorld *world; + RwCamera *camera; +}; +extern GlobalScene &Scene; + +extern uint8 work_buff[55000]; +extern char gString[256]; +extern wchar *gUString; +extern bool &b_FoundRecentSavedGameWantToLoad; + +class CSprite2d; + +void InitialiseGame(void); +void LoadingScreen(const char *str1, const char *str2, const char *splashscreen); +void LoadingIslandScreen(const char *levelName); +CSprite2d *LoadSplash(const char *name); +char *GetLevelSplashScreen(int level); +char *GetRandomSplashScreen(void); diff --git a/src/core/patcher.cpp b/src/core/patcher.cpp new file mode 100644 index 00000000..5fdbdf8b --- /dev/null +++ b/src/core/patcher.cpp @@ -0,0 +1,22 @@ +#include "common.h" +#include "patcher.h" + +StaticPatcher *StaticPatcher::ms_head; + +StaticPatcher::StaticPatcher(Patcher func) + : m_func(func) +{ + m_next = ms_head; + ms_head = this; +} + +void +StaticPatcher::Apply() +{ + StaticPatcher *current = ms_head; + while(current){ + current->Run(); + current = current->m_next; + } + ms_head = nil; +} diff --git a/src/core/patcher.h b/src/core/patcher.h new file mode 100644 index 00000000..87a6bea4 --- /dev/null +++ b/src/core/patcher.h @@ -0,0 +1,192 @@ +#pragma once + +#define WRAPPER __declspec(naked) +#define DEPRECATED __declspec(deprecated) +#define EAXJMP(a) { _asm mov eax, a _asm jmp eax } +#define VARJMP(a) { _asm jmp a } +#define WRAPARG(a) UNREFERENCED_PARAMETER(a) + +#define NOVMT __declspec(novtable) +#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a + +#include +#include + +#include "common.h" + +enum +{ + PATCH_CALL, + PATCH_JUMP, + PATCH_NOTHING, +}; + +enum +{ + III_10 = 1, + III_11, + III_STEAM, + VC_10, + VC_11, + VC_STEAM +}; + +extern int gtaversion; + +class StaticPatcher +{ +private: + using Patcher = void(*)(); + + Patcher m_func; + StaticPatcher *m_next; + static StaticPatcher *ms_head; + + void Run() { m_func(); } +public: + StaticPatcher(Patcher func); + static void Apply(); +}; + +template +inline T AddressByVersion(uint32_t addressIII10, uint32_t addressIII11, uint32_t addressIIISteam, uint32_t addressvc10, uint32_t addressvc11, uint32_t addressvcSteam) +{ + if(gtaversion == -1){ + if(*(uint32_t*)0x5C1E75 == 0xB85548EC) gtaversion = III_10; + else if(*(uint32_t*)0x5C2135 == 0xB85548EC) gtaversion = III_11; + else if(*(uint32_t*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM; + else if(*(uint32_t*)0x667BF5 == 0xB85548EC) gtaversion = VC_10; + else if(*(uint32_t*)0x667C45 == 0xB85548EC) gtaversion = VC_11; + else if(*(uint32_t*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM; + else gtaversion = 0; + } + switch(gtaversion){ + case III_10: + return (T)addressIII10; + case III_11: + return (T)addressIII11; + case III_STEAM: + return (T)addressIIISteam; + case VC_10: + return (T)addressvc10; + case VC_11: + return (T)addressvc11; + case VC_STEAM: + return (T)addressvcSteam; + default: + return (T)0; + } +} + +inline bool +is10(void) +{ + return gtaversion == III_10 || gtaversion == VC_10; +} + +inline bool +isIII(void) +{ + return gtaversion >= III_10 && gtaversion <= III_STEAM; +} + +inline bool +isVC(void) +{ + return gtaversion >= VC_10 && gtaversion <= VC_STEAM; +} + +#define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5) +#define INTERCEPT(saved, func, a) \ +{ \ + saved = PTRFROMCALL(a); \ + InjectHook(a, func); \ +} + +template inline void +Patch(AT address, T value) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(T*)address = value; + VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); +} + +template inline void +Nop(AT address, unsigned int nCount) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + memset((void*)address, 0x90, nCount); + VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); +} + +template inline void +ClearCC(AT address, unsigned int nCount) +{ + DWORD dwProtect[2]; + VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + memset((void*)address, 0xCC, nCount); + VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); +} + +extern std::vector usedAddresses; + +template inline void +InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING) +{ + if(std::any_of(usedAddresses.begin(), usedAddresses.end(), + [address](AT value) { return (int32)value == address; })) { + debug("Used address %#06x twice when injecting hook\n", address); + } + + usedAddresses.push_back((int32)address); + + DWORD dwProtect[2]; + switch ( nType ) + { + case PATCH_JUMP: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE9; + break; + case PATCH_CALL: + VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + *(BYTE*)address = 0xE8; + break; + default: + VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); + break; + } + DWORD dwHook; + _asm + { + mov eax, hook + mov dwHook, eax + } + + *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; + if ( nType == PATCH_NOTHING ) + VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); + else + VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); +} + +inline void ExtractCall(void *dst, uint32_t a) +{ + *(uint32_t*)dst = (uint32_t)(*(uint32_t*)(a+1) + a + 5); +} +template +inline void InterceptCall(void *dst, T func, uint32_t a) +{ + ExtractCall(dst, a); + InjectHook(a, func); +} +template +inline void InterceptVmethod(void *dst, T func, uint32_t a) +{ + *(uint32_t*)dst = *(uint32_t*)a; + Patch(a, func); +} + +#define STARTPATCHES static StaticPatcher Patcher([](){ +#define ENDPATCHES }); diff --git a/src/core/re3.cpp b/src/core/re3.cpp new file mode 100644 index 00000000..9dc39d46 --- /dev/null +++ b/src/core/re3.cpp @@ -0,0 +1,381 @@ +#include +#include +#include +#include "common.h" +#include "patcher.h" +#include "Renderer.h" +#include "Credits.h" +#include "Camera.h" +#include "Weather.h" +#include "Clock.h" +#include "World.h" +#include "Vehicle.h" +#include "Streaming.h" +#include "PathFind.h" +#include "Boat.h" +#include "Automobile.h" +#include "debugmenu_public.h" + +#include + +std::vector usedAddresses; + +void **rwengine = *(void***)0x5A10E1; + +DebugMenuAPI gDebugMenuAPI; + +WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); } +WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); } + +// overload our own new/delete with GTA's functions +void *operator new(size_t sz) { return gtanew(sz); } +void operator delete(void *ptr) noexcept { gtadelete(ptr); } + +#ifdef USE_PS2_RAND +unsigned __int64 myrand_seed = 1; +#else +unsigned long int myrand_seed = 1; +#endif + +int +myrand(void) +{ +#ifdef USE_PS2_RAND + // Use our own implementation of rand, stolen from PS2 + myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1; + return ((myrand_seed >> 32) & 0x7FFFFFFF); +#else + // or original codewarrior rand + myrand_seed = myrand_seed * 1103515245 + 12345; + return((myrand_seed >> 16) & 0x7FFF); +#endif +} + +void +mysrand(unsigned int seed) +{ + myrand_seed = seed; +} + +int (*open_script_orig)(const char *path, const char *mode); +int +open_script(const char *path, const char *mode) +{ + static int scriptToLoad = 1; + + if(GetAsyncKeyState('G') & 0x8000) + scriptToLoad = 0; + if(GetAsyncKeyState('R') & 0x8000) + scriptToLoad = 1; + if(GetAsyncKeyState('D') & 0x8000) + scriptToLoad = 2; + + switch(scriptToLoad){ + case 0: return open_script_orig(path, mode); + case 1: return open_script_orig("main_freeroam.scm", mode); + case 2: return open_script_orig("main_d.scm", mode); + } + return open_script_orig(path, mode); +} + +int gDbgSurf; + +void (*DebugMenuProcess)(void); +void (*DebugMenuRender)(void); +static void stub(void) { } + +void +DebugMenuInit(void) +{ + if(DebugMenuLoad()){ + DebugMenuProcess = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuProcess"); + DebugMenuRender = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuRender"); + } + if(DebugMenuProcess == nil || DebugMenuRender == nil){ + DebugMenuProcess = stub; + DebugMenuRender = stub; + } + +} + +void WeaponCheat(); +void HealthCheat(); +void TankCheat(); +void BlowUpCarsCheat(); +void ChangePlayerCheat(); +void MayhemCheat(); +void EverybodyAttacksPlayerCheat(); +void WeaponsForAllCheat(); +void FastTimeCheat(); +void SlowTimeCheat(); +void MoneyCheat(); +void ArmourCheat(); +void WantedLevelUpCheat(); +void WantedLevelDownCheat(); +void SunnyWeatherCheat(); +void CloudyWeatherCheat(); +void RainyWeatherCheat(); +void FoggyWeatherCheat(); +void FastWeatherCheat(); +void OnlyRenderWheelsCheat(); +void ChittyChittyBangBangCheat(); +void StrongGripCheat(); +void NastyLimbsCheat(); + +// needs too much stuff for now +#if 0 +void +spawnCar(int id) +{ + CVector playerpos; + CStreaming::RequestModel(id, 0); + CStreaming::LoadAllRequestedModels(false); + if(CStreaming::HasModelLoaded(id)){ + FindPlayerCoors(playerpos); + int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false); + if(node < 0) + return; + + CVehicle *v; + if(CModelInfo::IsBoatModel(id)){ +// CBoat* boat = (CBoat*)CVehicle__new(0x484); +// boat = boat->ctor(id, 1); +// v = (CVehicle*)(boat); + }else{ +// CAutomobile *au = (CAutomobile*)CVehicle__new(0x5A8); +// au = au->ctor(id, 1); +// v = (CVehicle*)au; + } +/* + // unlock doors + FIELD(int, v, 0x224) = 1; + // set player owned + FIELD(uint8, v, 0x1F7) |= 4; + + DebugMenuEntrySetAddress(carCol1, &FIELD(uchar, v, 0x19C)); + DebugMenuEntrySetAddress(carCol2, &FIELD(uchar, v, 0x19D)); + //if(id == MODELID_ESPERANTO) + // FIELD(uchar, v, 0x19C) = 54; + + v->matrix.matrix.pos.x = ThePaths.nodes[node].x; + v->matrix.matrix.pos.y = ThePaths.nodes[node].y; + v->matrix.matrix.pos.z = ThePaths.nodes[node].z + 4.0f; + float x = v->matrix.matrix.pos.x; + float y = v->matrix.matrix.pos.y; + float z = v->matrix.matrix.pos.z; + v->matrix.SetRotate(0.0f, 0.0f, 3.49f); + v->matrix.matrix.pos.x += x; + v->matrix.matrix.pos.y += y; + v->matrix.matrix.pos.z += z; + v->bfTypeStatus = v->bfTypeStatus & 7 | 0x20; + FIELD(int, v, 0x224) = 1; +*/ + CWorld::Add(v); + } +} +#endif + +void +DebugMenuPopulate(void) +{ + if(DebugMenuLoad()){ + static const char *weathers[] = { + "Sunny", "Cloudy", "Rainy", "Foggy" + }; + DebugMenuEntry *e; + e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil); + DebugMenuEntrySetWrap(e, true); + e = DebugMenuAddVar("Time & Weather", "Current Minute", &CClock::GetMinutesRef(), + [](){ CWeather::InterpolationValue = CClock::GetMinutes()/60.0f; }, 1, 0, 59, nil); + DebugMenuEntrySetWrap(e, true); + e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 3, weathers); + DebugMenuEntrySetWrap(e, true); + e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers); + DebugMenuEntrySetWrap(e, true); + DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f); + DebugMenuAddVar("Time & Weather", "Time scale", (float*)0x8F2C20, nil, 0.1f, 0.0f, 10.0f); + + DebugMenuAddCmd("Cheats", "Weapons", WeaponCheat); + DebugMenuAddCmd("Cheats", "Money", MoneyCheat); + DebugMenuAddCmd("Cheats", "Health", HealthCheat); + DebugMenuAddCmd("Cheats", "Wanted level up", WantedLevelUpCheat); + DebugMenuAddCmd("Cheats", "Wanted level down", WantedLevelDownCheat); + DebugMenuAddCmd("Cheats", "Tank", TankCheat); + DebugMenuAddCmd("Cheats", "Blow up cars", BlowUpCarsCheat); + DebugMenuAddCmd("Cheats", "Change player", ChangePlayerCheat); + DebugMenuAddCmd("Cheats", "Mayhem", MayhemCheat); + DebugMenuAddCmd("Cheats", "Everybody attacks player", EverybodyAttacksPlayerCheat); + DebugMenuAddCmd("Cheats", "Weapons for all", WeaponsForAllCheat); + DebugMenuAddCmd("Cheats", "Fast time", FastTimeCheat); + DebugMenuAddCmd("Cheats", "Slow time", SlowTimeCheat); + DebugMenuAddCmd("Cheats", "Armour", ArmourCheat); + DebugMenuAddCmd("Cheats", "Sunny weather", SunnyWeatherCheat); + DebugMenuAddCmd("Cheats", "Cloudy weather", CloudyWeatherCheat); + DebugMenuAddCmd("Cheats", "Rainy weather", RainyWeatherCheat); + DebugMenuAddCmd("Cheats", "Foggy weather", FoggyWeatherCheat); + DebugMenuAddCmd("Cheats", "Fast weather", FastWeatherCheat); + DebugMenuAddCmd("Cheats", "Only render wheels", OnlyRenderWheelsCheat); + DebugMenuAddCmd("Cheats", "Chitty chitty bang bang", ChittyChittyBangBangCheat); + DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat); + DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat); + + DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil); + DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil); + DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil); + DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil); + DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil); + DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil); + DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); + DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil); + + DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); + DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); + } +} + +/* +int (*RsEventHandler_orig)(int a, int b); +int +delayedPatches10(int a, int b) +{ + DebugMenuInit(); + DebugMenuPopulate(); + + return RsEventHandler_orig(a, b); +} +*/ + +void __declspec(naked) HeadlightsFix() +{ + static const float fMinusOne = -1.0f; + _asm + { + fld [esp+708h-690h] + fcomp fMinusOne + fnstsw ax + and ah, 5 + cmp ah, 1 + jnz HeadlightsFix_DontLimit + fld fMinusOne + fstp [esp+708h-690h] + +HeadlightsFix_DontLimit: + fld [esp+708h-690h] + fabs + fld st + push 0x5382F2 + retn + } +} + +const int re3_buffsize = 1024; +static char re3_buff[re3_buffsize]; + +void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func) +{ + int nCode; + + strcpy_s(re3_buff, re3_buffsize, "Assertion failed!" ); + strcat_s(re3_buff, re3_buffsize, "\n" ); + + strcat_s(re3_buff, re3_buffsize, "File: "); + strcat_s(re3_buff, re3_buffsize, filename ); + strcat_s(re3_buff, re3_buffsize, "\n" ); + + strcat_s(re3_buff, re3_buffsize, "Line: " ); + _itoa_s( lineno, re3_buff + strlen(re3_buff), re3_buffsize - strlen(re3_buff), 10 ); + strcat_s(re3_buff, re3_buffsize, "\n"); + + strcat_s(re3_buff, re3_buffsize, "Function: "); + strcat_s(re3_buff, re3_buffsize, func ); + strcat_s(re3_buff, re3_buffsize, "\n" ); + + strcat_s(re3_buff, re3_buffsize, "Expression: "); + strcat_s(re3_buff, re3_buffsize, expr); + strcat_s(re3_buff, re3_buffsize, "\n"); + + strcat_s(re3_buff, re3_buffsize, "\n" ); + strcat_s(re3_buff, re3_buffsize, "(Press Retry to debug the application)"); + + + nCode = ::MessageBoxA(nil, re3_buff, "RE3 Assertion Failed!", + MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); + + if (nCode == IDABORT) + { + raise(SIGABRT); + _exit(3); + } + + if (nCode == IDRETRY) + { + __debugbreak(); + return; + } + + if (nCode == IDIGNORE) + return; + + abort(); +} + +void re3_debug(char *format, ...) +{ + va_list va; + va_start(va, format); + vsprintf_s(re3_buff, re3_buffsize, format, va); + va_end(va); + + printf("%s", re3_buff); +} + +void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...) +{ + char buff[re3_buffsize *2]; + va_list va; + va_start(va, format); + vsprintf_s(re3_buff, re3_buffsize, format, va); + va_end(va); + + sprintf_s(buff, re3_buffsize * 2, "[%s.%s:%d]: %s", filename, func, lineno, re3_buff); + + OutputDebugStringA(buff); +} + +void +patch() +{ + StaticPatcher::Apply(); + +// Patch(0x46BC61+6, 1.0f); // car distance + InjectHook(0x59E460, printf, PATCH_JUMP); + InjectHook(0x475E00, printf, PATCH_JUMP); // _Error + + + // stolen from silentpatch (sorry) + Patch(0x5382BF, 0x0EEB); + InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP); + + InterceptCall(&open_script_orig, open_script, 0x438869); + +// InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E); +} + +BOOL WINAPI +DllMain(HINSTANCE hInst, DWORD reason, LPVOID) +{ + if(reason == DLL_PROCESS_ATTACH){ + + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + + if (*(DWORD*)0x5C1E75 == 0xB85548EC) // 1.0 + patch(); + else + return FALSE; + } + + return TRUE; +} diff --git a/src/core/rw.cpp b/src/core/rw.cpp new file mode 100644 index 00000000..52bcf5bb --- /dev/null +++ b/src/core/rw.cpp @@ -0,0 +1,415 @@ +#include "common.h" +#include "patcher.h" +#include "rwcore.h" +#include "rpworld.h" +#include "rpmatfx.h" +#include "rpskin.h" +#include "rphanim.h" +#include "rtbmp.h" + +typedef RwV3d *(*rwVectorsMultFn) (RwV3d * pointsOut, + const RwV3d * pointsIn, + RwInt32 numPoints, + const RwMatrix * matrix); + + +WRAPPER void _rwObjectHasFrameSetFrame(void* object, RwFrame* frame) { EAXJMP(0x5BC950); } +WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { EAXJMP(0x59E690); } +WRAPPER void _rpAtomicResyncInterpolatedSphere(RpAtomic* atomic) { EAXJMP(0x59E6C0); } +WRAPPER RwSphere const* RpAtomicGetWorldBoundingSphere(RpAtomic* atomic) { EAXJMP(0x59E800); } +WRAPPER RwInt32 RpClumpGetNumAtomics(RpClump* clump) { EAXJMP(0x59ED50); } +WRAPPER RpClump* RpClumpRender(RpClump* clump) { EAXJMP(0x59ED80); } +WRAPPER RpClump* RpClumpForAllAtomics(RpClump* clump, RpAtomicCallBack callback, void* pData) { EAXJMP(0x59EDD0); } +WRAPPER RpClump* RpClumpForAllCameras(RpClump* clump, RwCameraCallBack callback, void* pData) { EAXJMP(0x59EE10); } +WRAPPER RpClump* RpClumpForAllLights(RpClump* clump, RpLightCallBack callback, void* pData) { EAXJMP(0x59EE60); } +WRAPPER RpAtomic* RpAtomicCreate() { EAXJMP(0x59EEB0); } +WRAPPER RpAtomic* RpAtomicSetGeometry(RpAtomic* atomic, RpGeometry* geometry, RwUInt32 flags) { EAXJMP(0x59EFA0); } +WRAPPER RwBool RpAtomicDestroy(RpAtomic* atomic) { EAXJMP(0x59F020); } +WRAPPER RpAtomic* RpAtomicClone(RpAtomic* atomic) { EAXJMP(0x59F0A0); } +WRAPPER RpClump* RpClumpClone(RpClump* clump) { EAXJMP(0x59F1B0); } +WRAPPER RpClump* RpClumpCreate() { EAXJMP(0x59F490); } +WRAPPER RwBool RpClumpDestroy(RpClump* clump) { EAXJMP(0x59F500); } +WRAPPER RpClump* RpClumpAddAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F680); } +WRAPPER RpClump* RpClumpRemoveAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F6B0); } +WRAPPER RpClump* RpClumpRemoveLight(RpClump* clump, RpLight* light) { EAXJMP(0x59F6E0); } +WRAPPER RpClump* RpClumpStreamRead(RwStream* stream) { EAXJMP(0x59FC50); } +WRAPPER RwInt32 RpAtomicRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0510); } +WRAPPER RwInt32 RpClumpRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0540); } +WRAPPER RwInt32 RpAtomicRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5A0570); } +WRAPPER RwInt32 RpAtomicSetStreamAlwaysCallBack(RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5A05A0); } +WRAPPER RwInt32 RpAtomicSetStreamRightsCallBack(RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5A05C0); } +WRAPPER RwInt32 RpAtomicGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A05E0); } +WRAPPER RpAtomic* RpAtomicSetFrame(RpAtomic* atomic, RwFrame* frame) { EAXJMP(0x5A0600); } +WRAPPER RwInt32 RwEngineRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor initCB, RwPluginObjectDestructor termCB) { EAXJMP(0x5A0DC0); } +WRAPPER RwInt32 RwEngineGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A0DF0); } +WRAPPER RwInt32 RwEngineGetNumSubSystems() { EAXJMP(0x5A0E10); } +WRAPPER RwSubSystemInfo* RwEngineGetSubSystemInfo(RwSubSystemInfo* subSystemInfo, RwInt32 subSystemIndex) { EAXJMP(0x5A0E40); } +WRAPPER RwInt32 RwEngineGetCurrentSubSystem() { EAXJMP(0x5A0E70); } +WRAPPER RwBool RwEngineSetSubSystem(RwInt32 subSystemIndex) { EAXJMP(0x5A0EA0); } +WRAPPER RwInt32 RwEngineGetNumVideoModes() { EAXJMP(0x5A0ED0); } +WRAPPER RwVideoMode* RwEngineGetVideoModeInfo(RwVideoMode* modeinfo, RwInt32 modeIndex) { EAXJMP(0x5A0F00); } +WRAPPER RwInt32 RwEngineGetCurrentVideoMode() { EAXJMP(0x5A0F30); } +WRAPPER RwBool RwEngineSetVideoMode(RwInt32 modeIndex) { EAXJMP(0x5A0F60); } +WRAPPER RwBool RwEngineStop() { EAXJMP(0x5A0F90); } +WRAPPER RwBool RwEngineStart() { EAXJMP(0x5A0FE0); } +WRAPPER RwBool RwEngineClose() { EAXJMP(0x5A1070); } +WRAPPER RwBool RwEngineOpen(RwEngineOpenParams* initParams) { EAXJMP(0x5A10E0); } +WRAPPER RwBool RwEngineTerm() { EAXJMP(0x5A1290); } +WRAPPER RwBool RwEngineInit(RwMemoryFunctions* memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) { EAXJMP(0x5A12D0); } +WRAPPER void* _rwFrameOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A15E0); } +WRAPPER void* _rwFrameClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A1650); } +WRAPPER RwFrame* _rwFrameCloneAndLinkClones(RwFrame* root) { EAXJMP(0x5A1690); } +WRAPPER RwFrame* _rwFramePurgeClone(RwFrame* root) { EAXJMP(0x5A1880); } +WRAPPER RwBool RwFrameDirty(RwFrame const* frame) { EAXJMP(0x5A1930); } +WRAPPER void _rwFrameInit(RwFrame* frame) { EAXJMP(0x5A1950); } +WRAPPER RwFrame* RwFrameCreate() { EAXJMP(0x5A1A00); } +WRAPPER RwBool RwFrameDestroy(RwFrame* frame) { EAXJMP(0x5A1A30); } +WRAPPER RwBool RwFrameDestroyHierarchy(RwFrame* frame) { EAXJMP(0x5A1BF0); } +WRAPPER RwFrame* RwFrameUpdateObjects(RwFrame* frame) { EAXJMP(0x5A1C60); } +WRAPPER RwMatrix* RwFrameGetLTM(RwFrame* frame) { EAXJMP(0x5A1CE0); } +WRAPPER RwFrame* RwFrameAddChild(RwFrame* parent, RwFrame* child) { EAXJMP(0x5A1D00); } +WRAPPER RwFrame* RwFrameRemoveChild(RwFrame* child) { EAXJMP(0x5A1ED0); } +WRAPPER RwFrame* RwFrameForAllChildren(RwFrame* frame, RwFrameCallBack callBack, void* data) { EAXJMP(0x5A1FC0); } +WRAPPER RwFrame* RwFrameTranslate(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A2000); } +WRAPPER RwFrame* RwFrameScale(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A20A0); } +WRAPPER RwFrame* RwFrameTransform(RwFrame* frame, RwMatrix const* m, RwOpCombineType combine) { EAXJMP(0x5A2140); } +WRAPPER RwFrame* RwFrameRotate(RwFrame* frame, RwV3d const* axis, RwReal angle, RwOpCombineType combine) { EAXJMP(0x5A21E0); } +WRAPPER RwFrame* RwFrameSetIdentity(RwFrame* frame) { EAXJMP(0x5A2280); } +WRAPPER RwFrame* RwFrameForAllObjects(RwFrame* frame, RwObjectCallBack callBack, void* data) { EAXJMP(0x5A2340); } +WRAPPER RwInt32 RwFrameRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A2380); } +WRAPPER RwBool _rwMatrixSetMultFn(rwMatrixMultFn multMat) { EAXJMP(0x5A23B0); } +WRAPPER RwReal _rwMatrixDeterminant(RwMatrix const* matrix) { EAXJMP(0x5A2520); } +WRAPPER RwReal _rwMatrixOrthogonalError(RwMatrix const* matrix) { EAXJMP(0x5A2570); } +WRAPPER RwReal _rwMatrixNormalError(RwMatrix const* matrix) { EAXJMP(0x5A25D0); } +WRAPPER RwReal _rwMatrixIdentityError(RwMatrix const* matrix) { EAXJMP(0x5A2660); } +WRAPPER void* _rwMatrixClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2730); } +WRAPPER void* _rwMatrixOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2770); } +WRAPPER RwMatrix* RwMatrixOptimize(RwMatrix* matrix, RwMatrixTolerance const* tolerance) { EAXJMP(0x5A2820); } +WRAPPER RwMatrix* RwMatrixUpdate(RwMatrix* matrix) { EAXJMP(0x5A28E0); } +WRAPPER RwMatrix* RwMatrixMultiply(RwMatrix* matrixOut, RwMatrix const* MatrixIn1, RwMatrix const* matrixIn2) { EAXJMP(0x5A28F0); } +WRAPPER RwMatrix* RwMatrixRotateOneMinusCosineSine(RwMatrix* matrix, RwV3d const* unitAxis, RwReal oneMinusCosine, RwReal sine, RwOpCombineType combineOp) { EAXJMP(0x5A2960); } +WRAPPER RwMatrix* RwMatrixRotate(RwMatrix* matrix, RwV3d const* axis, RwReal angle, RwOpCombineType combineOp) { EAXJMP(0x5A2BF0); } +WRAPPER RwMatrix* RwMatrixInvert(RwMatrix* matrixOut, RwMatrix const* matrixIn) { EAXJMP(0x5A2C90); } +WRAPPER RwMatrix* RwMatrixScale(RwMatrix* matrix, RwV3d const* scale, RwOpCombineType combineOp) { EAXJMP(0x5A2EE0); } +WRAPPER RwMatrix* RwMatrixTranslate(RwMatrix* matrix, RwV3d const* translation, RwOpCombineType combineOp) { EAXJMP(0x5A3070); } +WRAPPER RwMatrix* RwMatrixTransform(RwMatrix* matrix, RwMatrix const* transform, RwOpCombineType combineOp) { EAXJMP(0x5A31C0); } +WRAPPER RwBool RwMatrixDestroy(RwMatrix* mpMat) { EAXJMP(0x5A3300); } +WRAPPER RwMatrix* RwMatrixCreate() { EAXJMP(0x5A3330); } +WRAPPER RwBool _rwVectorSetMultFn(rwVectorMultFn multPoint, rwVectorsMultFn multPoints, rwVectorMultFn multVector, rwVectorsMultFn multVectors) { EAXJMP(0x5A3450); } +WRAPPER RwReal _rwV3dNormalize(RwV3d* out, RwV3d const* in) { EAXJMP(0x5A3600); } +WRAPPER RwReal RwV3dLength(RwV3d const* in) { EAXJMP(0x5A36A0); } +WRAPPER RwReal _rwSqrt(RwReal const num) { EAXJMP(0x5A3710); } +WRAPPER RwReal _rwInvSqrt(RwReal const num) { EAXJMP(0x5A3770); } +WRAPPER RwV3d* RwV3dTransformPoints(RwV3d* pointsOut, RwV3d const* pointsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37D0); } +WRAPPER RwV3d* RwV3dTransformVectors(RwV3d* vectorsOut, RwV3d const* vectorsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37E0); } +WRAPPER void* _rwVectorClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A37F0); } +WRAPPER void* _rwVectorOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A3860); } +WRAPPER RwUInt32 RwStreamRead(RwStream* stream, void* buffer, RwUInt32 length) { EAXJMP(0x5A3AD0); } +WRAPPER RwStream* RwStreamWrite(RwStream* stream, void const* buffer, RwUInt32 length) { EAXJMP(0x5A3C30); } +WRAPPER RwStream* RwStreamSkip(RwStream* stream, RwUInt32 offset) { EAXJMP(0x5A3DF0); } +WRAPPER RwBool RwStreamClose(RwStream* stream, void* pData) { EAXJMP(0x5A3F10); } +WRAPPER RwStream* RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, void const* pData) { EAXJMP(0x5A3FE0); } +WRAPPER RwReal RwIm2DGetNearScreenZ() { EAXJMP(0x5A43A0); } +WRAPPER RwReal RwIm2DGetFarScreenZ() { EAXJMP(0x5A43B0); } +WRAPPER RwBool RwRenderStateSet(RwRenderState state, void* value) { EAXJMP(0x5A43C0); } +WRAPPER RwBool RwRenderStateGet(RwRenderState state, void* value) { EAXJMP(0x5A4410); } +WRAPPER RwBool RwIm2DRenderLine(RwIm2DVertex* vertices, RwInt32 numVertices, RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5A4420); } +WRAPPER RwBool RwIm2DRenderPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices) { EAXJMP(0x5A4430); } +WRAPPER RwBool RwIm2DRenderIndexedPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5A4440); } +WRAPPER RwCamera* RwCameraEndUpdate(RwCamera* camera) { EAXJMP(0x5A5020); } +WRAPPER RwCamera* RwCameraBeginUpdate(RwCamera* camera) { EAXJMP(0x5A5030); } +WRAPPER RwCamera* RwCameraSetViewOffset(RwCamera* camera, RwV2d const* offset) { EAXJMP(0x5A5040); } +WRAPPER RwCamera* RwCameraSetNearClipPlane(RwCamera* camera, RwReal nearClip) { EAXJMP(0x5A5070); } +WRAPPER RwCamera* RwCameraSetFarClipPlane(RwCamera* camera, RwReal farClip) { EAXJMP(0x5A5140); } +WRAPPER RwFrustumTestResult RwCameraFrustumTestSphere(RwCamera const* camera, RwSphere const* sphere) { EAXJMP(0x5A5170); } +WRAPPER RwCamera* RwCameraClear(RwCamera* camera, RwRGBA* colour, RwInt32 clearMode) { EAXJMP(0x5A51E0); } +WRAPPER RwCamera* RwCameraShowRaster(RwCamera* camera, void* pDev, RwUInt32 flags) { EAXJMP(0x5A5210); } +WRAPPER RwCamera* RwCameraSetProjection(RwCamera* camera, RwCameraProjection projection) { EAXJMP(0x5A5240); } +WRAPPER RwCamera* RwCameraSetViewWindow(RwCamera* camera, RwV2d const* viewWindow) { EAXJMP(0x5A52B0); } +WRAPPER RwInt32 RwCameraRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A52F0); } +WRAPPER RwBool RwCameraDestroy(RwCamera* camera) { EAXJMP(0x5A5320); } +WRAPPER RwCamera* RwCameraCreate() { EAXJMP(0x5A5360); } +WRAPPER RwBool RwTextureSetMipmapping(RwBool enable) { EAXJMP(0x5A7100); } +WRAPPER RwBool RwTextureGetMipmapping() { EAXJMP(0x5A7120); } +WRAPPER RwBool RwTextureSetAutoMipmapping(RwBool enable) { EAXJMP(0x5A7130); } +WRAPPER RwBool RwTextureGetAutoMipmapping() { EAXJMP(0x5A7150); } +WRAPPER RwTexDictionary* RwTexDictionaryCreate() { EAXJMP(0x5A7160); } +WRAPPER RwBool RwTexDictionaryDestroy(RwTexDictionary* dict) { EAXJMP(0x5A7200); } +WRAPPER RwTexDictionary const* RwTexDictionaryForAllTextures(RwTexDictionary const* dict, RwTextureCallBack fpCallBack, void* pData) { EAXJMP(0x5A7290); } +WRAPPER RwTexture* RwTextureCreate(RwRaster* raster) { EAXJMP(0x5A72D0); } +WRAPPER RwBool RwTextureDestroy(RwTexture* texture) { EAXJMP(0x5A7330); } +WRAPPER RwTexture* RwTextureSetName(RwTexture* texture, RwChar const* name) { EAXJMP(0x5A73B0); } +WRAPPER RwTexture* RwTextureSetMaskName(RwTexture* texture, RwChar const* maskName) { EAXJMP(0x5A7420); } +WRAPPER RwTexture* RwTexDictionaryAddTexture(RwTexDictionary* dict, RwTexture* texture) { EAXJMP(0x5A7490); } +WRAPPER RwTexture* RwTexDictionaryFindNamedTexture(RwTexDictionary* dict, RwChar const* name) { EAXJMP(0x5A74D0); } +WRAPPER RwTexDictionary* RwTexDictionarySetCurrent(RwTexDictionary* dict) { EAXJMP(0x5A7550); } +WRAPPER RwTexDictionary* RwTexDictionaryGetCurrent() { EAXJMP(0x5A7570); } +WRAPPER RwTexture* RwTextureRead(RwChar const* name, RwChar const* maskName) { EAXJMP(0x5A7580); } +WRAPPER RwBool RwTextureRasterGenerateMipmaps(RwRaster* raster, RwImage* image) { EAXJMP(0x5A7780); } +WRAPPER RwImage* RwImageCreate(RwInt32 width, RwInt32 height, RwInt32 depth) { EAXJMP(0x5A9120); } +WRAPPER RwBool RwImageDestroy(RwImage* image) { EAXJMP(0x5A9180); } +WRAPPER RwImage* RwImageAllocatePixels(RwImage* image) { EAXJMP(0x5A91E0); } +WRAPPER RwImage* RwImageFreePixels(RwImage* image) { EAXJMP(0x5A92A0); } +WRAPPER RwImage* RwImageMakeMask(RwImage* image) { EAXJMP(0x5A92D0); } +WRAPPER RwImage* RwImageApplyMask(RwImage* image, RwImage const* mask) { EAXJMP(0x5A93A0); } +WRAPPER RwChar const* RwImageSetPath(RwChar const* path) { EAXJMP(0x5A9750); } +WRAPPER RwImage* RwImageRead(RwChar const* imageName) { EAXJMP(0x5A9810); } +WRAPPER RwChar const* RwImageFindFileType(RwChar const* imageName) { EAXJMP(0x5A9B40); } +WRAPPER RwImage* RwImageReadMaskedImage(RwChar const* imageName, RwChar const* maskname) { EAXJMP(0x5A9C10); } +WRAPPER RwImage* RwImageCopy(RwImage* destImage, RwImage const* sourceImage) { EAXJMP(0x5A9F50); } +WRAPPER RwImage* RwImageGammaCorrect(RwImage* image) { EAXJMP(0x5AA130); } +WRAPPER RwBool RwImageSetGamma(RwReal gammaValue) { EAXJMP(0x5AA2C0); } +WRAPPER RwStream* _rwStreamWriteVersionedChunkHeader(RwStream* stream, RwInt32 type, RwInt32 size, RwUInt32 version, RwUInt32 buildNum) { EAXJMP(0x5AA4E0); } +WRAPPER RwBool RwStreamFindChunk(RwStream* stream, RwUInt32 type, RwUInt32* lengthOut, RwUInt32* versionOut) { EAXJMP(0x5AA540); } +WRAPPER void* RwMemLittleEndian32(void* mem, RwUInt32 size) { EAXJMP(0x5AA640); } +WRAPPER void* RwMemNative32(void* mem, RwUInt32 size) { EAXJMP(0x5AA650); } +WRAPPER void* RwMemFloat32ToReal(void* mem, RwUInt32 size) { EAXJMP(0x5AA660); } +WRAPPER RwStream* RwStreamWriteReal(RwStream* stream, RwReal const* reals, RwUInt32 numBytes) { EAXJMP(0x5AA680); } +WRAPPER RwStream* RwStreamWriteInt32(RwStream* stream, RwInt32 const* ints, RwUInt32 numBytes) { EAXJMP(0x5AA720); } +WRAPPER RwStream* RwStreamReadReal(RwStream* stream, RwReal* reals, RwUInt32 numBytes) { EAXJMP(0x5AA740); } +WRAPPER RwStream* RwStreamReadInt32(RwStream* stream, RwInt32* ints, RwUInt32 numBytes) { EAXJMP(0x5AA7B0); } +WRAPPER RwUInt32 RwTextureStreamGetSize(RwTexture const* texture) { EAXJMP(0x5AA800); } +WRAPPER RwTexture const* RwTextureStreamWrite(RwTexture const* texture, RwStream* stream) { EAXJMP(0x5AA870); } +WRAPPER RwTexture* RwTextureStreamRead(RwStream* stream) { EAXJMP(0x5AAA40); } +WRAPPER RwTexDictionary const* RwTexDictionaryStreamWrite(RwTexDictionary const* texDict, RwStream* stream) { EAXJMP(0x5AB020); } +WRAPPER RpMorphTarget const* RpMorphTargetCalcBoundingSphere(RpMorphTarget const* morphTarget, RwSphere* boundingSphere) { EAXJMP(0x5AC890); } +WRAPPER RwInt32 RpGeometryAddMorphTargets(RpGeometry* geometry, RwInt32 mtcount) { EAXJMP(0x5AC9A0); } +WRAPPER RpGeometry const* RpGeometryTriangleSetVertexIndices(RpGeometry const* geometry, RpTriangle* triangle, RwUInt16 vert1, RwUInt16 vert2, RwUInt16 vert3) { EAXJMP(0x5ACB60); } +WRAPPER RpGeometry* RpGeometryTriangleSetMaterial(RpGeometry* geometry, RpTriangle* triangle, RpMaterial* material) { EAXJMP(0x5ACB90); } +WRAPPER RpGeometry* RpGeometryForAllMaterials(RpGeometry* geometry, RpMaterialCallBack fpCallBack, void* pData) { EAXJMP(0x5ACBF0); } +WRAPPER RpGeometry* RpGeometryLock(RpGeometry* geometry, RwInt32 lockMode) { EAXJMP(0x5ACC30); } +WRAPPER RpGeometry* RpGeometryUnlock(RpGeometry* geometry) { EAXJMP(0x5ACC60); } +WRAPPER RpGeometry* RpGeometryCreate(RwInt32 numVert, RwInt32 numTriangles, RwUInt32 format) { EAXJMP(0x5ACD10); } +WRAPPER RpGeometry* _rpGeometryAddRef(RpGeometry* geometry) { EAXJMP(0x5ACF40); } +WRAPPER RwBool RpGeometryDestroy(RpGeometry* geometry) { EAXJMP(0x5ACF50); } +WRAPPER RwInt32 RpGeometryRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ACFF0); } +WRAPPER RwInt32 RpGeometryRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AD020); } +WRAPPER RpGeometry* RpGeometryStreamRead(RwStream* stream) { EAXJMP(0x5AD050); } +WRAPPER RwRaster* RwRasterGetCurrentContext() { EAXJMP(0x5AD6D0); } +WRAPPER RwRaster* RwRasterUnlock(RwRaster* raster) { EAXJMP(0x5AD6F0); } +WRAPPER RwRaster* RwRasterRenderFast(RwRaster* raster, RwInt32 x, RwInt32 y) { EAXJMP(0x5AD710); } +WRAPPER RwRaster* RwRasterUnlockPalette(RwRaster* raster) { EAXJMP(0x5AD750); } +WRAPPER RwBool RwRasterDestroy(RwRaster* raster) { EAXJMP(0x5AD780); } +WRAPPER RwRaster* RwRasterPushContext(RwRaster* raster) { EAXJMP(0x5AD7C0); } +WRAPPER RwInt32 RwRasterRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AD810); } +WRAPPER RwUInt8* RwRasterLockPalette(RwRaster* raster, RwInt32 lockMode) { EAXJMP(0x5AD840); } +WRAPPER RwRaster* RwRasterPopContext() { EAXJMP(0x5AD870); } +WRAPPER RwInt32 RwRasterGetNumLevels(RwRaster* raster) { EAXJMP(0x5AD8C0); } +WRAPPER RwRaster* RwRasterShowRaster(RwRaster* raster, void* dev, RwUInt32 flags) { EAXJMP(0x5AD900); } +WRAPPER RwRaster* RwRasterCreate(RwInt32 width, RwInt32 height, RwInt32 depth, RwInt32 flags) { EAXJMP(0x5AD930); } +WRAPPER RwUInt8* RwRasterLock(RwRaster* raster, RwUInt8 level, RwInt32 lockMode) { EAXJMP(0x5AD9D0); } +WRAPPER RpMaterial* RpMaterialCreate() { EAXJMP(0x5ADC30); } +WRAPPER RwBool RpMaterialDestroy(RpMaterial* material) { EAXJMP(0x5ADCB0); } +WRAPPER RpMaterial* RpMaterialSetTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5ADD10); } +WRAPPER RwInt32 RpMaterialRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ADD40); } +WRAPPER RwInt32 RpMaterialRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5ADD70); } +WRAPPER RpMaterial* RpMaterialStreamRead(RwStream* stream) { EAXJMP(0x5ADDA0); } +WRAPPER RpWorldSector* _rpSectorDefaultRenderCallBack(RpWorldSector* sector) { EAXJMP(0x5AE0B0); } +WRAPPER RwBool _rpWorldForAllGlobalLights(RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE100); } +WRAPPER RpWorldSector* _rpWorldSectorForAllLocalLights(RpWorldSector* sector, RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE150); } +WRAPPER RpWorld* RpWorldUnlock(RpWorld* world) { EAXJMP(0x5AE190); } +WRAPPER RpWorld* RpWorldSectorGetWorld(RpWorldSector const* sector) { EAXJMP(0x5AE2B0); } +WRAPPER RwBool RpWorldDestroy(RpWorld* world) { EAXJMP(0x5AE340); } +WRAPPER RpWorld* RpWorldCreate(RwBBox* boundingBox) { EAXJMP(0x5AE6A0); } +WRAPPER RwInt32 RpWorldRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AEA40); } +WRAPPER RwInt32 RpWorldRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AEA70); } +WRAPPER RwBool RpWorldPluginAttach() { EAXJMP(0x5AEAA0); } +WRAPPER RpWorld* RpWorldAddCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFB80); } +WRAPPER RpWorld* RpWorldRemoveCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFBB0); } +WRAPPER RpWorld* RpAtomicGetWorld(RpAtomic const* atomic) { EAXJMP(0x5AFC10); } +WRAPPER RpWorld* RpWorldAddClump(RpWorld* world, RpClump* clump) { EAXJMP(0x5AFC20); } +WRAPPER RpWorld* RpWorldAddLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDA0); } +WRAPPER RpWorld* RpWorldRemoveLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDF0); } +WRAPPER RwImage* RtBMPImageRead(RwChar const* imageName) { EAXJMP(0x5AFE70); } +WRAPPER RwBool RpSkinPluginAttach() { EAXJMP(0x5B07D0); } +WRAPPER RpAtomic* RpSkinAtomicSetHAnimHierarchy(RpAtomic* atomic, RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1050); } +WRAPPER RpHAnimHierarchy* RpSkinAtomicGetHAnimHierarchy(RpAtomic const* atomic) { EAXJMP(0x5B1070); } +WRAPPER RpSkin* RpSkinGeometryGetSkin(RpGeometry* geometry) { EAXJMP(0x5B1080); } +WRAPPER RpGeometry* RpSkinGeometrySetSkin(RpGeometry* geometry, RpSkin* skin) { EAXJMP(0x5B1090); } +WRAPPER RwMatrix const* RpSkinGetSkinToBoneMatrices(RpSkin* skin) { EAXJMP(0x5B10D0); } +WRAPPER RpHAnimHierarchy* RpHAnimHierarchyCreate(RwInt32 numNodes, RwUInt32* nodeFlags, RwInt32* nodeIDs, RpHAnimHierarchyFlag flags, RwInt32 maxKeyFrameSize) { EAXJMP(0x5B10E0); } +WRAPPER RpHAnimHierarchy* RpHAnimFrameGetHierarchy(RwFrame* frame) { EAXJMP(0x5B11F0); } +WRAPPER RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy* hierarchy, RpHAnimAnimation* anim) { EAXJMP(0x5B1200); } +WRAPPER RwBool RpHAnimHierarchySubAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B12B0); } +WRAPPER RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B1480); } +WRAPPER RwBool RpHAnimHierarchyUpdateMatrices(RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1780); } +WRAPPER RpHAnimAnimation* RpHAnimAnimationStreamRead(RwStream* stream) { EAXJMP(0x5B1C10); } +WRAPPER RwBool RpHAnimPluginAttach() { EAXJMP(0x5B1D50); } +WRAPPER RwBool RpMatFXPluginAttach() { EAXJMP(0x5B2640); } +WRAPPER RpAtomic* RpMatFXAtomicEnableEffects(RpAtomic* atomic) { EAXJMP(0x5B3750); } +WRAPPER RpMaterial* RpMatFXMaterialSetEffects(RpMaterial* material, RpMatFXMaterialFlags flags) { EAXJMP(0x5B3780); } +WRAPPER RpMaterial* RpMatFXMaterialSetupEnvMap(RpMaterial* material, RwTexture* texture, RwFrame* frame, RwBool useFrameBufferAlpha, RwReal coef) { EAXJMP(0x5B38D0); } +WRAPPER RpMaterial* RpMatFXMaterialSetBumpMapTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5B3A40); } +WRAPPER RwBool RwD3D8SetRenderState(RwUInt32 state, RwUInt32 value) { EAXJMP(0x5B3CF0); } +WRAPPER void RwD3D8GetRenderState(RwUInt32 state, void* value) { EAXJMP(0x5B3D40); } +WRAPPER RwBool RwD3D8SetTextureStageState(RwUInt32 stage, RwUInt32 type, RwUInt32 value) { EAXJMP(0x5B3D60); } +WRAPPER RwBool RwD3D8SetTexture(RwTexture* texture, RwUInt32 stage) { EAXJMP(0x5B53A0); } +WRAPPER void* RwIm3DTransform(RwIm3DVertex* pVerts, RwUInt32 numVerts, RwMatrix* ltm, RwUInt32 flags) { EAXJMP(0x5B6720); } +WRAPPER RwBool RwIm3DEnd() { EAXJMP(0x5B67F0); } +WRAPPER RwBool RwIm3DRenderIndexedPrimitive(RwPrimitiveType primType, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5B6820); } +WRAPPER RwBool RwIm3DRenderLine(RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5B6980); } +WRAPPER RxPipeline* RwIm3DSetTransformPipeline(RxPipeline* pipeline) { EAXJMP(0x5B6A50); } +WRAPPER RxPipeline* RwIm3DSetRenderPipeline(RxPipeline* pipeline, RwPrimitiveType primType) { EAXJMP(0x5B6AC0); } +WRAPPER void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate) { EAXJMP(0x5B95D0); } +WRAPPER RwBool RwD3D8CameraAttachWindow(void* camera, void* hwnd) { EAXJMP(0x5B9640); } +WRAPPER RwBool RwD3D8DeviceSupportsDXTTexture() { EAXJMP(0x5BAEB0); } +WRAPPER RwBool RwD3D8SetVertexShader(RwUInt32 handle) { EAXJMP(0x5BAF90); } +WRAPPER RwBool RwD3D8SetPixelShader(RwUInt32 handle) { EAXJMP(0x5BAFD0); } +WRAPPER RwBool RwD3D8SetStreamSource(RwUInt32 streamNumber, void* streamData, RwUInt32 stride) { EAXJMP(0x5BB010); } +WRAPPER RwBool RwD3D8SetIndices(void* indexData, RwUInt32 baseVertexIndex) { EAXJMP(0x5BB060); } +WRAPPER RwBool RwD3D8DrawIndexedPrimitive(RwUInt32 primitiveType, RwUInt32 minIndex, RwUInt32 numVertices, RwUInt32 startIndex, RwUInt32 numIndices) { EAXJMP(0x5BB0B0); } +WRAPPER RwBool RwD3D8DrawPrimitive(RwUInt32 primitiveType, RwUInt32 startVertex, RwUInt32 numVertices) { EAXJMP(0x5BB140); } +WRAPPER RwBool RwD3D8SetTransform(RwUInt32 state, void const* matrix) { EAXJMP(0x5BB1D0); } +WRAPPER void RwD3D8GetTransform(RwUInt32 state, void* matrix) { EAXJMP(0x5BB310); } +WRAPPER RwBool RwD3D8SetTransformWorld(RwMatrix const* matrix) { EAXJMP(0x5BB340); } +WRAPPER RwBool RwD3D8SetSurfaceProperties(RwRGBA const* color, RwSurfaceProperties const* surfaceProps, RwBool modulate) { EAXJMP(0x5BB490); } +WRAPPER RwBool RwD3D8SetLight(RwInt32 index, void const* light) { EAXJMP(0x5BB7A0); } +WRAPPER RwBool RwD3D8EnableLight(RwInt32 index, RwBool enable) { EAXJMP(0x5BB890); } +WRAPPER RwBool RwD3D8DynamicVertexBufferCreate(RwUInt32 fvf, RwUInt32 size, void** vertexBuffer) { EAXJMP(0x5BB9F0); } +WRAPPER void RwD3D8DynamicVertexBufferDestroy(void* vertexBuffer) { EAXJMP(0x5BBAE0); } +WRAPPER RwBool RwD3D8IndexBufferCreate(RwUInt32 numIndices, void** indexBuffer) { EAXJMP(0x5BBB10); } +WRAPPER RwBool RwD3D8CreatePixelShader(RwUInt32 const* function, RwUInt32* handle) { EAXJMP(0x5BBB40); } +WRAPPER void RwD3D8DeletePixelShader(RwUInt32 handle) { EAXJMP(0x5BBB90); } +WRAPPER RwBool RwD3D8SetPixelShaderConstant(RwUInt32 registerAddress, void const* antData, RwUInt32 antCount) { EAXJMP(0x5BBC00); } +WRAPPER void const* RwD3D8GetCaps() { EAXJMP(0x5BBC30); } +WRAPPER RwBool RwD3D8CameraIsSphereFullyInsideFrustum(void const* camera, void const* sphere) { EAXJMP(0x5BBC40); } +WRAPPER RwBool RwD3D8CameraIsBBoxFullyInsideFrustum(void const* camera, void const* boundingBox) { EAXJMP(0x5BBCA0); } +WRAPPER RwBool RwD3D8DynamicVertexBufferLock(RwUInt32 vertexSize, RwUInt32 numVertex, void** vertexBufferOut, void** vertexDataOut, RwUInt32* baseIndexOut) { EAXJMP(0x5BBD30); } +WRAPPER RwBool RwD3D8DynamicVertexBufferUnlock(void* vertexBuffer) { EAXJMP(0x5BBEB0); } +WRAPPER RwBool _rwIntelSSEsupported() { EAXJMP(0x5BBED0); } +WRAPPER RwImage* RwImageSetFromRaster(RwImage* image, RwRaster* raster) { EAXJMP(0x5BBF10); } +WRAPPER RwRaster* RwRasterSetFromImage(RwRaster* raster, RwImage* image) { EAXJMP(0x5BBF50); } +WRAPPER RwImage* RwImageFindRasterFormat(RwImage* ipImage, RwInt32 nRasterType, RwInt32* npWidth, RwInt32* npHeight, RwInt32* npDepth, RwInt32* npFormat) { EAXJMP(0x5BBF80); } +WRAPPER RwInt32 RwFrameRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5BBFF0); } +WRAPPER rwFrameList* _rwFrameListDeinitialize(rwFrameList* frameList) { EAXJMP(0x5BC020); } +WRAPPER rwFrameList* _rwFrameListStreamRead(RwStream* stream, rwFrameList* fl) { EAXJMP(0x5BC050); } +WRAPPER RpLight* RpLightSetRadius(RpLight* light, RwReal radius) { EAXJMP(0x5BC300); } +WRAPPER RpLight* RpLightSetColor(RpLight* light, RwRGBAReal const* color) { EAXJMP(0x5BC320); } +WRAPPER RwReal RpLightGetConeAngle(RpLight const* light) { EAXJMP(0x5BC370); } +WRAPPER RwInt32 RpLightRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5BC5B0); } +WRAPPER RpLight* RpLightStreamRead(RwStream* stream) { EAXJMP(0x5BC5E0); } +WRAPPER RwBool RpLightDestroy(RpLight* light) { EAXJMP(0x5BC780); } +WRAPPER RpLight* RpLightCreate(RwInt32 type) { EAXJMP(0x5BC7C0); } +WRAPPER void _rwD3D8TexDictionaryEnableRasterFormatConversion(RwBool enable) { EAXJMP(0x5BE280); } +WRAPPER RwFileFunctions* RwOsGetFileInterface() { EAXJMP(0x5BF110); } +WRAPPER RwBool RwFreeListDestroy(RwFreeList* freelist) { EAXJMP(0x5C1720); } +WRAPPER RwFreeList* RwFreeListCreate(RwInt32 entrySize, RwInt32 entriesPerBlock, RwInt32 alignment) { EAXJMP(0x5C1790); } +WRAPPER RwInt32 RwFreeListPurge(RwFreeList* freelist) { EAXJMP(0x5C19F0); } +WRAPPER RwInt32 RwFreeListPurgeAllFreeLists() { EAXJMP(0x5C1B90); } +WRAPPER RwFreeList* RwFreeListForAllUsed(RwFreeList* freelist, RwFreeListCallBack fpCallBack, void* pData) { EAXJMP(0x5C1D40); } +WRAPPER RwBool _rxPipelineClose() { EAXJMP(0x5C2780); } +WRAPPER RwBool _rxPipelineOpen() { EAXJMP(0x5C27E0); } +WRAPPER RxHeap* RxHeapGetGlobalHeap() { EAXJMP(0x5C2AD0); } +WRAPPER RxPacket* RxPacketCreate(RxPipelineNode* node) { EAXJMP(0x5C2AE0); } +WRAPPER RxCluster* RxClusterSetExternalData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B10); } +WRAPPER RxCluster* RxClusterSetData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B70); } +WRAPPER RxCluster* RxClusterInitializeData(RxCluster* cluster, RwUInt32 numElements, RwUInt16 stride) { EAXJMP(0x5C2BD0); } +WRAPPER RxCluster* RxClusterResizeData(RxCluster* CurrentCluster, RwUInt32 NumElements) { EAXJMP(0x5C2C40); } +WRAPPER RxCluster* RxClusterLockWrite(RxPacket* packet, RwUInt32 clusterIndex, RxPipelineNode* node) { EAXJMP(0x5C2C90); } +WRAPPER RxPipeline* RxPipelineExecute(RxPipeline* pipeline, void* data, RwBool heapReset) { EAXJMP(0x5C2D60); } +WRAPPER RxPipeline* RxPipelineCreate() { EAXJMP(0x5C2E00); } +WRAPPER void _rxPipelineDestroy(RxPipeline* Pipeline) { EAXJMP(0x5C2E70); } +WRAPPER RwBool RwResourcesFreeResEntry(RwResEntry* entry) { EAXJMP(0x5C3080); } +WRAPPER void _rwResourcesPurge() { EAXJMP(0x5C30F0); } +WRAPPER RwResEntry* RwResourcesAllocateResEntry(void* owner, RwResEntry** ownerRef, RwInt32 size, RwResEntryDestroyNotify destroyNotify) { EAXJMP(0x5C3170); } +WRAPPER RwBool RwResourcesEmptyArena() { EAXJMP(0x5C3360); } +WRAPPER RwBool _rwPluginRegistryOpen() { EAXJMP(0x5C3450); } +WRAPPER RwBool _rwPluginRegistryClose() { EAXJMP(0x5C3480); } +WRAPPER RwInt32 _rwPluginRegistryGetPluginOffset(RwPluginRegistry const* reg, RwUInt32 pluginID) { EAXJMP(0x5C3590); } +WRAPPER RwInt32 _rwPluginRegistryAddPlugin(RwPluginRegistry* reg, RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5C35C0); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C37F0); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryDeInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C3850); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryCopyObject(RwPluginRegistry const* reg, void* dstObject, void const* srcObject) { EAXJMP(0x5C3880); } +WRAPPER RwError* RwErrorSet(RwError* code) { EAXJMP(0x5C3910); } +WRAPPER RwInt32 _rwerror(RwInt32 code, ...) { EAXJMP(0x5C3970); } +WRAPPER RwInt32 _rwPluginRegistryAddPluginStream(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5C3980); } +WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmlwysCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5C39C0); } +WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmRightsCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5C39F0); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryReadDataChunks(RwPluginRegistry const* reg, RwStream* stream, void* object) { EAXJMP(0x5C3A20); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryInvokeRights(RwPluginRegistry const* reg, RwUInt32 id, void* obj, RwUInt32 extraData) { EAXJMP(0x5C3B50); } +WRAPPER RwInt32 _rwPluginRegistryGetSize(RwPluginRegistry const* reg, void const* object) { EAXJMP(0x5C3BA0); } +WRAPPER RwPluginRegistry const* _rwPluginRegistryWriteDataChunks(RwPluginRegistry const* reg, RwStream* stream, void const* object) { EAXJMP(0x5C3BE0); } +WRAPPER RwPluginRegistry const* _rwPluginRegistrySkipDataChunks(RwPluginRegistry const* reg, RwStream* stream) { EAXJMP(0x5C3CB0); } +WRAPPER RwCamera* RwCameraStreamRead(RwStream* stream) { EAXJMP(0x5C3D30); } +WRAPPER RwBBox* RwBBoxCalculate(RwBBox* boundBox, RwV3d const* verts, RwInt32 numVerts) { EAXJMP(0x5C5570); } +WRAPPER RwImage* RwImageResample(RwImage* dstImage, RwImage const* srcImage) { EAXJMP(0x5C72B0); } +WRAPPER RwImage* RwImageCreateResample(RwImage const* srcImage, RwInt32 width, RwInt32 height) { EAXJMP(0x5C7B30); } +WRAPPER RxRenderStateVector* RxRenderStateVectorSetDefaultRenderStateVector(RxRenderStateVector* rsvp) { EAXJMP(0x5D9240); } +WRAPPER RxRenderStateVector* RxRenderStateVectorCreate(RwBool current) { EAXJMP(0x5D9340); } +WRAPPER void RxRenderStateVectorDestroy(RxRenderStateVector* rsvp) { EAXJMP(0x5D9410); } +WRAPPER RxRenderStateVector* RxRenderStateVectorLoadDriverState(RxRenderStateVector* rsvp) { EAXJMP(0x5D9460); } +WRAPPER void _rxEmbeddedPacketBetweenPipelines(RxPipeline* fromPipeline, RxPipeline* toPipeline) { EAXJMP(0x5D95D0); } +WRAPPER RxPipelineNode* _rxEmbeddedPacketBetweenNodes(RxPipeline* pipeline, RxPipelineNode* nodeFrom, RwUInt32 whichOutput) { EAXJMP(0x5D9740); } +WRAPPER void _rxPacketDestroy(RxPacket* Packet) { EAXJMP(0x5D9810); } +WRAPPER RpMaterialList* _rpMaterialListDeinitialize(RpMaterialList* matList) { EAXJMP(0x5C8B10); } +WRAPPER RpMaterialList* _rpMaterialListInitialize(RpMaterialList* matList) { EAXJMP(0x5C8B70); } +WRAPPER RpMaterial* _rpMaterialListGetMaterial(RpMaterialList const* matList, RwInt32 matIndex) { EAXJMP(0x5C8B80); } +WRAPPER RwInt32 _rpMaterialListAppendMaterial(RpMaterialList* matList, RpMaterial* material) { EAXJMP(0x5C8B90); } +WRAPPER RwInt32 _rpMaterialListFindMaterialIndex(RpMaterialList const* matList, RpMaterial const* material) { EAXJMP(0x5C8C50); } +WRAPPER RpMaterialList* _rpMaterialListStreamRead(RwStream* stream, RpMaterialList* matList) { EAXJMP(0x5C8C80); } +WRAPPER RpMeshHeader* _rpMeshHeaderCreate(RwUInt32 size) { EAXJMP(0x5C8FE0); } +WRAPPER void* _rpMeshClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C8FF0); } +WRAPPER void* _rpMeshOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C9020); } +WRAPPER RpBuildMesh* _rpBuildMeshCreate(RwUInt32 bufferSize) { EAXJMP(0x5C9140); } +WRAPPER RwBool _rpBuildMeshDestroy(RpBuildMesh* mesh) { EAXJMP(0x5C9220); } +WRAPPER RwBool _rpMeshDestroy(RpMeshHeader* mesh) { EAXJMP(0x5C9260); } +WRAPPER RpBuildMesh* _rpBuildMeshAddTriangle(RpBuildMesh* mesh, RpMaterial* material, RwInt32 vert1, RwInt32 vert2, RwInt32 vert3) { EAXJMP(0x5C92A0); } +WRAPPER RpMeshHeader* _rpMeshHeaderForAllMeshes(RpMeshHeader* meshHeader, RpMeshCallBack fpCallBack, void* pData) { EAXJMP(0x5C9380); } +WRAPPER RwStream* _rpMeshWrite(RpMeshHeader const* meshHeader, void const* object, RwStream* stream, RpMaterialList const* matList) { EAXJMP(0x5C93C0); } +WRAPPER RpMeshHeader* _rpMeshRead(RwStream* stream, void const* object, RpMaterialList const* matList) { EAXJMP(0x5C9510); } +WRAPPER RwInt32 _rpMeshSize(RpMeshHeader const* meshHeader, void const* object) { EAXJMP(0x5C96E0); } +WRAPPER RpMeshHeader* RpBuildMeshGenerateDefaultTriStrip(RpBuildMesh* buildmesh, void* data) { EAXJMP(0x5C9730); } +WRAPPER RpMeshHeader* _rpTriListMeshGenerate(RpBuildMesh* buildMesh, void* data) { EAXJMP(0x5CAE10); } +WRAPPER RpMeshHeader* _rpMeshOptimise(RpBuildMesh* buildmesh, RwUInt32 flags) { EAXJMP(0x5CB230); } +WRAPPER RwInt32 RpWorldSectorRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5CB2B0); } +WRAPPER RwInt32 RpWorldSectorRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5CB2E0); } +WRAPPER RxPipeline* RpWorldSetDefaultSectorPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB630); } +WRAPPER RxPipeline* RpAtomicSetDefaultPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB670); } +WRAPPER void RpHAnimStdKeyFrameToMatrix(RwMatrix* matrix, void* voidIFrame) { EAXJMP(0x5CDEE0); } +WRAPPER void RpHAnimStdKeyFrameInterpolate(void* voidOut, void* voidIn1, void* voidIn2, RwReal time) { EAXJMP(0x5CE000); } +WRAPPER void RpHAnimStdKeyFrameBlend(void* voidOut, void* voidIn1, void* voidIn2, RwReal alpha) { EAXJMP(0x5CE420); } +WRAPPER RpHAnimAnimation* RpHAnimStdKeyFrameStreamRead(RwStream* stream, RpHAnimAnimation* animation) { EAXJMP(0x5CE820); } +WRAPPER RwBool RpHAnimStdKeyFrameStreamWrite(RpHAnimAnimation* animation, RwStream* stream) { EAXJMP(0x5CE8C0); } +WRAPPER RwInt32 RpHAnimStdKeyFrameStreamGetSize(RpHAnimAnimation* animation) { EAXJMP(0x5CE930); } +WRAPPER void RpHAnimStdKeyFrameMulRecip(void* voidFrame, void* voidStart) { EAXJMP(0x5CE950); } +WRAPPER void RpHAnimStdKeyFrameAdd(void* voidOut, void* voidIn1, void* voidIn2) { EAXJMP(0x5CEAB0); } +WRAPPER void RxHeapFree(RxHeap* heap, void* block) { EAXJMP(0x5D1070); } +WRAPPER void* RxHeapAlloc(RxHeap* heap, RwUInt32 size) { EAXJMP(0x5D1260); } +WRAPPER void* RxHeapRealloc(RxHeap* heap, void* block, RwUInt32 newSize, RwBool allowCopy) { EAXJMP(0x5D14D0); } +WRAPPER RwBool _rxHeapReset(RxHeap* heap) { EAXJMP(0x5D1680); } +WRAPPER void RxHeapDestroy(RxHeap* heap) { EAXJMP(0x5D16F0); } +WRAPPER RxHeap* RxHeapCreate(RwUInt32 size) { EAXJMP(0x5D1750); } +WRAPPER RxNodeOutput RxPipelineNodeFindOutputByName(RxPipelineNode* node, RwChar const* outputname) { EAXJMP(0x5D1EC0); } +WRAPPER RxNodeInput RxPipelineNodeFindInput(RxPipelineNode* node) { EAXJMP(0x5D1F20); } +WRAPPER RxPipeline* RxPipelineNodeRequestCluster(RxPipeline* pipeline, RxPipelineNode* node, RxClusterDefinition* clusterDef) { EAXJMP(0x5D1F30); } +WRAPPER RxPipeline* RxLockedPipeUnlock(RxLockedPipe* pipeline) { EAXJMP(0x5D1FA0); } +WRAPPER RxLockedPipe* RxPipelineLock(RxPipeline* pipeline) { EAXJMP(0x5D29F0); } +WRAPPER RxPipelineNode* RxPipelineFindNodeByName(RxPipeline* pipeline, RwChar const* name, RxPipelineNode* start, RwInt32* nodeIndex) { EAXJMP(0x5D2B10); } +WRAPPER RxLockedPipe* RxLockedPipeAddFragment(RxLockedPipe *pipeline, RwUInt32 *firstIndex, RxNodeDefinition *nodeDef0, ...) { EAXJMP(0x5D2BA0); } +WRAPPER RxPipeline* RxLockedPipeAddPath(RxLockedPipe* pipeline, RxNodeOutput out, RxNodeInput in) { EAXJMP(0x5D2EE0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmRenderSetup() { EAXJMP(0x5D31C0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleTriangleIndices() { EAXJMP(0x5D35C0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetCullTriangle() { EAXJMP(0x5D3C60); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipTriangle() { EAXJMP(0x5D4F80); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitTriangle() { EAXJMP(0x5D51C0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmInstance() { EAXJMP(0x5D5400); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetTransform() { EAXJMP(0x5D6000); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmStash() { EAXJMP(0x5D61C0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleLineIndices() { EAXJMP(0x5D6470); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipLine() { EAXJMP(0x5D7230); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitLine() { EAXJMP(0x5D74C0); } +WRAPPER RwBool _rwD3D8LightsOpen() { EAXJMP(0x5D9C90); } +WRAPPER void _rwD3D8LightsClose() { EAXJMP(0x5D9EF0); } +WRAPPER RwBool _rwD3D8LightsGlobalEnable(RpLightFlag flags) { EAXJMP(0x5D9F80); } +WRAPPER RwBool _rwD3D8LightLocalEnable(RpLight* light) { EAXJMP(0x5DA210); } +WRAPPER void _rwD3D8LightsEnable(RwBool enable, RwUInt32 type) { EAXJMP(0x5DA450); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8WorldSectorAllInOne() { EAXJMP(0x5DAAC0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8AtomicAllInOne() { EAXJMP(0x5DC500); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorInstance() { EAXJMP(0x5DCC50); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorEnumerateLights() { EAXJMP(0x5DCD80); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicInstance() { EAXJMP(0x5DD800); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicEnumerateLights() { EAXJMP(0x5DD9B0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetMaterialScatter() { EAXJMP(0x5DDAA0); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetLight() { EAXJMP(0x5DF040); } +WRAPPER RxNodeDefinition* RxNodeDefinitionGetPostLight() { EAXJMP(0x5DF560); } +WRAPPER void RxD3D8AllInOneSetRenderCallBack(RxPipelineNode* node, RxD3D8AllInOneRenderCallBack callback) { EAXJMP(0x5DFC60); } \ No newline at end of file diff --git a/src/core/templates.h b/src/core/templates.h new file mode 100644 index 00000000..ef2db33a --- /dev/null +++ b/src/core/templates.h @@ -0,0 +1,205 @@ +#pragma once + +template +class CStore +{ +public: + int allocPtr; + T store[n]; + + T *alloc(void){ + if(this->allocPtr >= n){ + printf("Size of this thing:%d needs increasing\n", n); + assert(0); + } + return &this->store[this->allocPtr++]; + } + void clear(void){ + this->allocPtr = 0; + } +}; + +template +class CPool +{ + U *m_entries; + union Flags { + struct { + uint8 id : 7; + uint8 free : 1; + }; + uint8 u; + } *m_flags; + int m_size; + int m_allocPtr; + +public: + CPool(int size){ + m_entries = (U*)malloc(sizeof(U)*size); + m_flags = (Flags*)malloc(sizeof(Flags)*size); + m_size = size; + m_allocPtr = 0; + for(int i = 0; i < size; i++){ + m_flags[i].id = 0; + m_flags[i].free = 1; + } + } + int GetSize(void) { return m_size; } + T *New(void){ + bool wrapped = false; + do + if(++m_allocPtr == m_size){ + if(wrapped) + return nil; + wrapped = true; + m_allocPtr = 0; + } + while(!m_flags[m_allocPtr].free); + m_flags[m_allocPtr].free = 0; + m_flags[m_allocPtr].id++; + return (T*)&m_entries[m_allocPtr]; + } + T *New(int handle){ + T *entry = (T*)&m_entries[handle>>8]; + SetNotFreeAt(handle); + return entry; + } + void SetNotFreeAt(int handle){ + int idx = handle>>8; + m_flags[idx].free = 0; + m_flags[idx].id = handle & 0x7F; + for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++) + if(m_flags[m_allocPtr].free) + return; + } + void Delete(T *entry){ + int i = GetJustIndex(entry); + m_flags[i].free = 1; + if(i < m_allocPtr) + m_allocPtr = i; + } + T *GetSlot(int i){ + return m_flags[i].free ? nil : (T*)&m_entries[i]; + } + T *GetAt(int handle){ + return m_flags[handle>>8].u == (handle & 0xFF) ? + (T*)&m_entries[handle >> 8] : nil; + } + int GetIndex(T *entry){ + int i = GetJustIndex(entry); + return m_flags[i].u + (i<<8); + } + int GetJustIndex(T *entry){ + // TODO: the cast is unsafe + return (int)((U*)entry - m_entries); + } + int GetNoOfUsedSpaces(void){ + int i; + int n = 0; + for(i = 0; i < m_size; i++) + if(!m_flags[i].free) + n++; + return n; + } + void ClearStorage(uint8 *&flags, U *&entries){ + free(flags); + free(entries); + flags = nil; + entries = nil; + } + void CopyBack(uint8 *&flags, U *&entries){ + memcpy(m_flags, flags, sizeof(uint8)*m_size); + memcpy(m_entries, entries, sizeof(U)*m_size); + debug("Size copied:%d (%d)\n", sizeof(U)*m_size, sizeof(Flags)*m_size); + m_allocPtr = 0; + ClearStorage(flags, entries); + debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ + } + void Store(uint8 *&flags, U *&entries){ + flags = (uint8*)malloc(sizeof(uint8)*m_size); + entries = (U*)malloc(sizeof(U)*m_size); + memcpy(flags, m_flags, sizeof(uint8)*m_size); + memcpy(entries, m_entries, sizeof(U)*m_size); + debug("Stored:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ + } +}; + +template +class CLink +{ +public: + T item; + CLink *prev; + CLink *next; + + void Insert(CLink *link){ + link->next = this->next; + this->next->prev = link; + link->prev = this; + this->next = link; + } + void Remove(void){ + this->prev->next = this->next; + this->next->prev = this->prev; + } +}; + +template +class CLinkList +{ +public: + CLink head, tail; + CLink freeHead, freeTail; + CLink *links; + + void Init(int n){ + links = new CLink[n]; + head.next = &tail; + tail.prev = &head; + freeHead.next = &freeTail; + freeTail.prev = &freeHead; + while(n--) + freeHead.Insert(&links[n]); + } + void Shutdown(void){ + delete[] links; + links = nil; + } + void Clear(void){ + while(head.next != &tail) + Remove(head.next); + } + CLink *Insert(T const &item){ + CLink *node = freeHead.next; + if(node == &freeTail) + return nil; + node->item = item; + node->Remove(); // remove from free list + head.Insert(node); + return node; + } + CLink *InsertSorted(T const &item){ + CLink *sort; + for(sort = head.next; sort != &tail; sort = sort->next) + if(sort->item.sort >= item.sort) + break; + CLink *node = freeHead.next; + if(node == &freeTail) + return nil; + node->item = item; + node->Remove(); // remove from free list + sort->prev->Insert(node); + return node; + } + void Remove(CLink *link){ + link->Remove(); // remove from list + freeHead.Insert(link); // insert into free list + } + int Count(void){ + int n = 0; + CLink *lnk; + for(lnk = head.next; lnk != &tail; lnk = lnk->next) + n++; + return n; + } +}; diff --git a/src/debugmenu_public.h b/src/debugmenu_public.h deleted file mode 100644 index 778e7afe..00000000 --- a/src/debugmenu_public.h +++ /dev/null @@ -1,154 +0,0 @@ - -extern "C" { - -typedef void (*TriggerFunc)(void); - -struct DebugMenuEntry; - -typedef DebugMenuEntry *(*DebugMenuAddInt8_TYPE)(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddInt16_TYPE)(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddInt32_TYPE)(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddInt64_TYPE)(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddUInt8_TYPE)(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddUInt16_TYPE)(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddUInt32_TYPE)(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddUInt64_TYPE)(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings); -typedef DebugMenuEntry *(*DebugMenuAddFloat32_TYPE)(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound); -typedef DebugMenuEntry *(*DebugMenuAddFloat64_TYPE)(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound); -typedef DebugMenuEntry *(*DebugMenuAddCmd_TYPE)(const char *path, const char *name, TriggerFunc triggerFunc); -typedef void (*DebugMenuEntrySetWrap_TYPE)(DebugMenuEntry *e, bool wrap); -typedef void (*DebugMenuEntrySetStrings_TYPE)(DebugMenuEntry *e, const char **strings); -typedef void (*DebugMenuEntrySetAddress_TYPE)(DebugMenuEntry *e, void *addr); - -struct DebugMenuAPI -{ - bool isLoaded; - HMODULE module; - DebugMenuAddInt8_TYPE addint8; - DebugMenuAddInt16_TYPE addint16; - DebugMenuAddInt32_TYPE addint32; - DebugMenuAddInt64_TYPE addint64; - DebugMenuAddUInt8_TYPE adduint8; - DebugMenuAddUInt16_TYPE adduint16; - DebugMenuAddUInt32_TYPE adduint32; - DebugMenuAddUInt64_TYPE adduint64; - DebugMenuAddFloat32_TYPE addfloat32; - DebugMenuAddFloat64_TYPE addfloat64; - DebugMenuAddCmd_TYPE addcmd; - DebugMenuEntrySetWrap_TYPE setwrap; - DebugMenuEntrySetStrings_TYPE setstrings; - DebugMenuEntrySetAddress_TYPE setaddress; -}; -extern DebugMenuAPI gDebugMenuAPI; - -inline DebugMenuEntry *DebugMenuAddInt8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddInt16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddInt32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddInt64(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddUInt8(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddUInt16(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddUInt32(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddUInt64(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddFloat32(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) -{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } -inline DebugMenuEntry *DebugMenuAddFloat64(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) -{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } -inline DebugMenuEntry *DebugMenuAddCmd(const char *path, const char *name, TriggerFunc triggerFunc) -{ return gDebugMenuAPI.addcmd(path, name, triggerFunc); } -inline void DebugMenuEntrySetWrap(DebugMenuEntry *e, bool wrap) -{ gDebugMenuAPI.setwrap(e, wrap); } -inline void DebugMenuEntrySetStrings(DebugMenuEntry *e, const char **strings) -{ gDebugMenuAPI.setstrings(e, strings); } -inline void DebugMenuEntrySetAddress(DebugMenuEntry *e, void *addr) -{ gDebugMenuAPI.setaddress(e, addr); } - -inline bool DebugMenuLoad(void) -{ - if(gDebugMenuAPI.isLoaded) - return true; - HMODULE mod = LoadLibraryA("debugmenu"); - if(mod == nil){ - char modulePath[MAX_PATH]; - HMODULE dllModule; - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&gDebugMenuAPI, &dllModule); - GetModuleFileNameA(dllModule, modulePath, MAX_PATH); - char *p = strchr(modulePath, '\\'); - if(p) p[1] = '\0'; - strcat(modulePath, "debugmenu"); - mod = LoadLibraryA(modulePath); - } - if(mod == nil) - return false; - gDebugMenuAPI.addint8 = (DebugMenuAddInt8_TYPE)GetProcAddress(mod, "DebugMenuAddInt8"); - gDebugMenuAPI.addint16 = (DebugMenuAddInt16_TYPE)GetProcAddress(mod, "DebugMenuAddInt16"); - gDebugMenuAPI.addint32 = (DebugMenuAddInt32_TYPE)GetProcAddress(mod, "DebugMenuAddInt32"); - gDebugMenuAPI.addint64 = (DebugMenuAddInt64_TYPE)GetProcAddress(mod, "DebugMenuAddInt64"); - gDebugMenuAPI.adduint8 = (DebugMenuAddUInt8_TYPE)GetProcAddress(mod, "DebugMenuAddUInt8"); - gDebugMenuAPI.adduint16 = (DebugMenuAddUInt16_TYPE)GetProcAddress(mod, "DebugMenuAddUInt16"); - gDebugMenuAPI.adduint32 = (DebugMenuAddUInt32_TYPE)GetProcAddress(mod, "DebugMenuAddUInt32"); - gDebugMenuAPI.adduint64 = (DebugMenuAddUInt64_TYPE)GetProcAddress(mod, "DebugMenuAddUInt64"); - gDebugMenuAPI.addfloat32 = (DebugMenuAddFloat32_TYPE)GetProcAddress(mod, "DebugMenuAddFloat32"); - gDebugMenuAPI.addfloat64 = (DebugMenuAddFloat64_TYPE)GetProcAddress(mod, "DebugMenuAddFloat64"); - gDebugMenuAPI.addcmd = (DebugMenuAddCmd_TYPE)GetProcAddress(mod, "DebugMenuAddCmd"); - gDebugMenuAPI.setwrap = (DebugMenuEntrySetWrap_TYPE)GetProcAddress(mod, "DebugMenuEntrySetWrap"); - gDebugMenuAPI.setstrings = (DebugMenuEntrySetStrings_TYPE)GetProcAddress(mod, "DebugMenuEntrySetStrings"); - gDebugMenuAPI.setaddress = (DebugMenuEntrySetAddress_TYPE)GetProcAddress(mod, "DebugMenuEntrySetAddress"); - gDebugMenuAPI.isLoaded = true; - gDebugMenuAPI.module = mod; - return true; -} - -} - -// Also overload them for simplicity - -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc, int8_t step, int8_t lowerBound, int8_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc, int16_t step, int16_t lowerBound, int16_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc, int32_t step, int32_t lowerBound, int32_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, int64_t *ptr, TriggerFunc triggerFunc, int64_t step, int64_t lowerBound, int64_t upperBound, const char **strings) -{ return gDebugMenuAPI.addint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint8_t *ptr, TriggerFunc triggerFunc, uint8_t step, uint8_t lowerBound, uint8_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint8(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint16_t *ptr, TriggerFunc triggerFunc, uint16_t step, uint16_t lowerBound, uint16_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint16(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint32_t *ptr, TriggerFunc triggerFunc, uint32_t step, uint32_t lowerBound, uint32_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint32(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, uint64_t *ptr, TriggerFunc triggerFunc, uint64_t step, uint64_t lowerBound, uint64_t upperBound, const char **strings) -{ return gDebugMenuAPI.adduint64(path, name, ptr, triggerFunc, step, lowerBound, upperBound, strings); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, float *ptr, TriggerFunc triggerFunc, float step, float lowerBound, float upperBound) -{ return gDebugMenuAPI.addfloat32(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } -inline DebugMenuEntry *DebugMenuAddVar(const char *path, const char *name, double *ptr, TriggerFunc triggerFunc, double step, double lowerBound, double upperBound) -{ return gDebugMenuAPI.addfloat64(path, name, ptr, triggerFunc, step, lowerBound, upperBound); } - -inline DebugMenuEntry *DebugMenuAddVarBool32(const char *path, const char *name, int32_t *ptr, TriggerFunc triggerFunc) -{ - static const char *boolstr[] = { "Off", "On" }; - DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); - DebugMenuEntrySetWrap(e, true); - return e; -} -inline DebugMenuEntry *DebugMenuAddVarBool16(const char *path, const char *name, int16_t *ptr, TriggerFunc triggerFunc) -{ - static const char *boolstr[] = { "Off", "On" }; - DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); - DebugMenuEntrySetWrap(e, true); - return e; -} -inline DebugMenuEntry *DebugMenuAddVarBool8(const char *path, const char *name, int8_t *ptr, TriggerFunc triggerFunc) -{ - static const char *boolstr[] = { "Off", "On" }; - DebugMenuEntry *e = DebugMenuAddVar(path, name, ptr, triggerFunc, 1, 0, 1, boolstr); - DebugMenuEntrySetWrap(e, true); - return e; -} diff --git a/src/entities/Automobile.cpp b/src/entities/Automobile.cpp deleted file mode 100644 index 54eed17a..00000000 --- a/src/entities/Automobile.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Automobile.h" - -CAutomobile::CAutomobile(int mi, uint8 owner) -{ - ctor(mi, owner); -} - -WRAPPER CAutomobile* CAutomobile::ctor(int, uint8) { EAXJMP(0x52C6B0); } - -WRAPPER void CAutomobile::SetDoorDamage(int32, uint32, bool) { EAXJMP(0x530200); } -WRAPPER void CAutomobile::SetPanelDamage(int32, uint32, bool) { EAXJMP(0x5301A0); } -WRAPPER void CAutomobile::SetBumperDamage(int32, uint32, bool) { EAXJMP(0x530120); } - -STARTPATCHES -InjectHook(0x52D170, &CAutomobile::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/Automobile.h b/src/entities/Automobile.h deleted file mode 100644 index b1463936..00000000 --- a/src/entities/Automobile.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "DamageManager.h" -#include "Vehicle.h" - -struct CDoor -{ - float m_fAngleWhenOpened; - float m_fAngleWhenClosed; - char field_8; - char field_9; - char field_10; - char field_11; - float m_fAngle; - float m_fPreviousAngle; - float m_fAngularVelocity; - CVector m_vecVelocity; -}; - -class CAutomobile : public CVehicle -{ -public: - // 0x288 - CDamageManager Damage; - CDoor Doors[6]; - RwFrame *m_aCarNodes[NUM_CAR_NODES]; - CColPoint m_aWheelColPoints[4]; - float m_aWheelDist[4]; - float m_aWheelDistPrev[4]; - float m_aWheelSkidThing[4]; - int field_49C; - bool m_aWheelSkidmarkMuddy[4]; - bool m_aWheelSkidmarkBloody[4]; - float m_aWheelRotation[4]; - float m_aWheelPosition[4]; - float m_aWheelSpeed[4]; - uint8 stuff3[12]; - uint32 m_nBusDoorTimerEnd; - uint32 m_nBusDoorTimerStart; - float m_aSuspensionRange[4]; - float m_aSuspensionLineLength[4]; - float m_fHeightAboveRoad; - float m_fImprovedHandling; - uint8 stuff6[32]; - CPhysical *m_aGroundPhysical[4]; // physicals touching wheels - CVector m_aGroundOffset[4]; // from ground object to colpoint - CEntity *m_pBlowUpEntity; - float m_weaponThingA; // TODO - float m_weaponThingB; // TODO - float m_fCarGunLR; - float m_fCarGunUD; - float m_fWindScreenRotation; - uint8 stuff4[4]; - uint8 m_nWheelsOnGround_2; - uint8 m_nWheelsOnGround; - uint8 m_nWheelsOnGroundPrev; - uint8 stuff5[5]; - int32 m_aWheelState[4]; - - CAutomobile(int, uint8); - CAutomobile* ctor(int, uint8); - void SetDoorDamage(int32, uint32, bool); /* TODO: eDoors */ - void SetPanelDamage(int32, uint32, bool); /* TODO: ePanels */ - void SetBumperDamage(int32, uint32, bool); /* TODO: ePanels */ - void dtor() { this->CAutomobile::~CAutomobile(); } -}; -static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); -static_assert(offsetof(CAutomobile, m_aWheelDist) == 0x46C, "CAutomobile: error"); diff --git a/src/entities/Boat.cpp b/src/entities/Boat.cpp deleted file mode 100644 index 076a910e..00000000 --- a/src/entities/Boat.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Boat.h" - -CBoat::CBoat(int mi, uint8 owner) -{ - ctor(mi, owner); -} - -WRAPPER CBoat* CBoat::ctor(int, uint8) { EAXJMP(0x53E3E0); } - -STARTPATCHES -InjectHook(0x53E790, &CBoat::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/Boat.h b/src/entities/Boat.h deleted file mode 100644 index 6d6482a4..00000000 --- a/src/entities/Boat.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Vehicle.h" - -class CBoat : public CVehicle -{ -public: - // 0x288 - uint8 stuff1[57]; - bool m_bIsAnchored; - uint8 stuff[450]; - - CBoat(int, uint8); - CBoat* ctor(int, uint8); - void dtor() { this->CBoat::~CBoat(); }; -}; -static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); diff --git a/src/entities/CivilianPed.cpp b/src/entities/CivilianPed.cpp deleted file mode 100644 index a4881e71..00000000 --- a/src/entities/CivilianPed.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "CivilianPed.h" - -WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } - -CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) -{ - CPed::SetModelIndex(mi); - for (int i = 0; i < 10; i++) - { - m_nearPeds[i] = nil; - } -} - -STARTPATCHES - InjectHook(0x4BFF30, &CCivilianPed::ctor, PATCH_JUMP); - InjectHook(0x4BFFC0, &CCivilianPed::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/CivilianPed.h b/src/entities/CivilianPed.h deleted file mode 100644 index 8d004ad7..00000000 --- a/src/entities/CivilianPed.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "Ped.h" - -class CCivilianPed : public CPed -{ -public: - CCivilianPed(int, int); - virtual ~CCivilianPed(void) { } - - virtual void ProcessControl(void); - - CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; - void dtor(void) { this->CCivilianPed::~CCivilianPed(); } -}; -static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/entities/CopPed.cpp b/src/entities/CopPed.cpp deleted file mode 100644 index 041185ee..00000000 --- a/src/entities/CopPed.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "CopPed.h" - -CCopPed::~CCopPed() -{ - ClearPursuit(); -} - -WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); } - -STARTPATCHES - InjectHook(0x4C13E0, &CCopPed::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/CopPed.h b/src/entities/CopPed.h deleted file mode 100644 index b938dfc2..00000000 --- a/src/entities/CopPed.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once -#include "Ped.h" - -enum eCrimeType -{ - CRIME_NONE, - CRIME_POSSESSION_GUN, - CRIME_HIT_PED, - CRIME_HIT_COP, - CRIME_SHOOT_PED, - CRIME_SHOOT_COP, - CRIME_STEAL_CAR, - CRIME_RUN_REDLIGHT, - CRIME_RECKLESS_DRIVING, - CRIME_SPEEDING, - CRIME_RUNOVER_PED, - CRIME_RUNOVER_COP, - CRIME_SHOOT_HELI, - CRIME_PED_BURNED, - CRIME_COP_BURNED, - CRIME_VEHICLE_BURNED, - CRIME_DESTROYED_CESSNA, -}; - -enum eCopType -{ - COP_STREET = 0, - COP_FBI = 1, - COP_SWAT = 2, - COP_ARMY = 3, -}; - -class CCrime -{ -public: - eCrimeType m_eCrimeType; - CEntity *m_pVictim; - int32 m_nCrimeTime; - CVector m_vecCrimePos; - int8 m_bReported; - int8 m_bMultiplier; - int8 pad_20[2]; -}; - -class CCopPed : public CPed -{ -public: - int16 m_wRoadblockNode; - int8 field_1342; - int8 field_1343; - float m_fDistanceToTarget; - int8 m_bIsInPursuit; - int8 m_bIsDisabledCop; - int8 field_1350; - int8 field_1351; - int8 m_bZoneDisabledButClose; - int8 m_bZoneDisabled; - int8 field_1354; - int8 field_1355; - int32 field_1356; - eCopType m_nCopType; - int8 field_1364; - int8 field_1365; - int8 field_1366; - int8 field_1367; - - ~CCopPed(); - void dtor(void) { this->CCopPed::~CCopPed(); } - - void ClearPursuit(void); -}; - -static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); diff --git a/src/entities/CutsceneHead.cpp b/src/entities/CutsceneHead.cpp deleted file mode 100644 index a9c47777..00000000 --- a/src/entities/CutsceneHead.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "common.h" -#include -#include "patcher.h" -#include "main.h" -#include "RwHelper.h" -#include "RpAnimBlend.h" -#include "AnimBlendClumpData.h" -#include "Directory.h" -#include "CutsceneMgr.h" -#include "Streaming.h" -#include "CutsceneHead.h" - - -CCutsceneHead::CCutsceneHead(CObject *obj) -{ - RpAtomic *atm; - - assert(RwObjectGetType(obj->m_rwObject) == rpCLUMP); - m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame; - atm = (RpAtomic*)GetFirstObject(m_pHeadNode); - if(atm){ - assert(RwObjectGetType(atm) == rpATOMIC); - RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER); - } -} - -void -CCutsceneHead::CreateRwObject(void) -{ - RpAtomic *atm; - - CEntity::CreateRwObject(); - assert(RwObjectGetType(m_rwObject) == rpCLUMP); - atm = GetFirstAtomic((RpClump*)m_rwObject); - RpSkinAtomicSetHAnimHierarchy(atm, RpHAnimFrameGetHierarchy(GetFirstChild(RpClumpGetFrame((RpClump*)m_rwObject)))); -} - -void -CCutsceneHead::DeleteRwObject(void) -{ - CEntity::DeleteRwObject(); -} - -void -CCutsceneHead::ProcessControl(void) -{ - RpAtomic *atm; - RpHAnimHierarchy *hier; - - CPhysical::ProcessControl(); - - m_matrix.SetRotateY(PI/2); - m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; - UpdateRwFrame(); - - assert(RwObjectGetType(m_rwObject) == rpCLUMP); - atm = GetFirstAtomic((RpClump*)m_rwObject); - hier = RpSkinAtomicGetHAnimHierarchy(atm); - RpHAnimHierarchyAddAnimTime(hier, CTimer::GetTimeStepNonClipped()/50.0f); -} - -void -CCutsceneHead::Render(void) -{ - RpAtomic *atm; - - m_matrix.SetRotateY(PI/2); - m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; - UpdateRwFrame(); - - assert(RwObjectGetType(m_rwObject) == rpCLUMP); - atm = GetFirstAtomic((RpClump*)m_rwObject); - RpHAnimHierarchyUpdateMatrices(RpSkinAtomicGetHAnimHierarchy(atm)); - - CObject::Render(); -} - -void -CCutsceneHead::PlayAnimation(const char *animName) -{ - RpAtomic *atm; - RpHAnimHierarchy *hier; - RpHAnimAnimation *anim; - uint32 offset, size; - RwStream *stream; - - assert(RwObjectGetType(m_rwObject) == rpCLUMP); - atm = GetFirstAtomic((RpClump*)m_rwObject); - hier = RpSkinAtomicGetHAnimHierarchy(atm); - - sprintf(gString, "%s.anm", animName); - - if(CCutsceneMgr::ms_pCutsceneDir->FindItem(gString, offset, size)){ - stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG"); - assert(stream); - - CStreaming::MakeSpaceFor(size*2048); - CStreaming::ImGonnaUseStreamingMemory(); - - RwStreamSkip(stream, offset*2048); - if(RwStreamFindChunk(stream, rwID_HANIMANIMATION, nil, nil)){ - anim = RpHAnimAnimationStreamRead(stream); - RpHAnimHierarchySetCurrentAnim(hier, anim); - } - - CStreaming::IHaveUsedStreamingMemory(); - - RwStreamClose(stream, nil); - } -} - -STARTPATCHES - InjectHook(0x4BA650, &CCutsceneHead::CreateRwObject_, PATCH_JUMP); - InjectHook(0x4BA690, &CCutsceneHead::DeleteRwObject_, PATCH_JUMP); - InjectHook(0x4BA760, &CCutsceneHead::ProcessControl_, PATCH_JUMP); - InjectHook(0x4BA800, &CCutsceneHead::Render_, PATCH_JUMP); - InjectHook(0x4BA6A0, &CCutsceneHead::PlayAnimation, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/CutsceneHead.h b/src/entities/CutsceneHead.h deleted file mode 100644 index de4f011f..00000000 --- a/src/entities/CutsceneHead.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "CutsceneObject.h" - -class CCutsceneHead : public CCutsceneObject -{ -public: - RwFrame *m_pHeadNode; - - CCutsceneHead(CObject *obj); - - void CreateRwObject(void); - void DeleteRwObject(void); - void ProcessControl(void); - void Render(void); - - void PlayAnimation(const char *animName); - - void CreateRwObject_(void) { CCutsceneHead::CreateRwObject(); } - void DeleteRwObject_(void) { CCutsceneHead::DeleteRwObject(); } - void ProcessControl_(void) { CCutsceneHead::ProcessControl(); } - void Render_(void) { CCutsceneHead::Render(); } -}; -static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error"); diff --git a/src/entities/CutsceneObject.cpp b/src/entities/CutsceneObject.cpp deleted file mode 100644 index ede5be5b..00000000 --- a/src/entities/CutsceneObject.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Lights.h" -#include "PointLights.h" -#include "RpAnimBlend.h" -#include "AnimBlendClumpData.h" -#include "Renderer.h" -#include "ModelIndices.h" -#include "Shadows.h" -#include "Timecycle.h" -#include "CutsceneObject.h" - -CCutsceneObject::CCutsceneObject(void) -{ - m_status = STATUS_SIMPLE; - bUsesCollision = false; - bStreamingDontDelete = true; - ObjectCreatedBy = CUTSCENE_OBJECT; - m_fMass = 1.0f; - m_fTurnMass = 1.0f; -} - -void -CCutsceneObject::SetModelIndex(uint32 id) -{ - CEntity::SetModelIndex(id); - assert(RwObjectGetType(m_rwObject) == rpCLUMP); - RpAnimBlendClumpInit((RpClump*)m_rwObject); - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = &m_vecMoveSpeed; - (*RPANIMBLENDCLUMPDATA(m_rwObject))->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION_3D; -} - -void -CCutsceneObject::ProcessControl(void) -{ - CPhysical::ProcessControl(); - - if(CTimer::GetTimeStep() < 1/100.0f) - m_vecMoveSpeed *= 100.0f; - else - m_vecMoveSpeed *= 1.0f/CTimer::GetTimeStep(); - - ApplyMoveSpeed(); -} - -void -CCutsceneObject::PreRender(void) -{ - if(IsPedModel(GetModelIndex())) - CShadows::StoreShadowForPedObject(this, - CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); -} - -void -CCutsceneObject::Render(void) -{ - CObject::Render(); -} - -bool -CCutsceneObject::SetupLighting(void) -{ - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); - - if(bRenderScorched){ - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - }else{ - CVector coors = GetPosition(); - float lighting = CPointLights::GenerateLightsAffectingObject(&coors); - if(!bHasBlip && lighting != 1.0f){ - SetAmbientAndDirectionalColours(lighting); - return true; - } - } - - return false; -} - -void -CCutsceneObject::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} - -STARTPATCHES - InjectHook(0x4BA960, &CCutsceneObject::dtor, PATCH_JUMP); - InjectHook(0x4BA980, &CCutsceneObject::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4BA9C0, &CCutsceneObject::ProcessControl_, PATCH_JUMP); - InjectHook(0x4BAA40, &CCutsceneObject::PreRender_, PATCH_JUMP); - InjectHook(0x4BAAA0, &CCutsceneObject::Render_, PATCH_JUMP); - InjectHook(0x4A7E70, &CCutsceneObject::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7F00, &CCutsceneObject::RemoveLighting_, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/CutsceneObject.h b/src/entities/CutsceneObject.h deleted file mode 100644 index 9360651e..00000000 --- a/src/entities/CutsceneObject.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "Object.h" - -class CCutsceneObject : public CObject -{ -public: - CCutsceneObject(void); - - virtual void SetModelIndex(uint32 id); - virtual void ProcessControl(void); - virtual void PreRender(void); - virtual void Render(void); - virtual bool SetupLighting(void); - virtual void RemoveLighting(bool reset); - - void dtor(void) { this->CCutsceneObject::~CCutsceneObject(); } - void SetModelIndex_(uint32 id) { CCutsceneObject::SetModelIndex(id); } - void ProcessControl_(void) { CCutsceneObject::ProcessControl(); } - void PreRender_(void) { CCutsceneObject::PreRender(); } - void Render_(void) { CCutsceneObject::Render(); } - bool SetupLighting_(void) { return CCutsceneObject::SetupLighting(); } - void RemoveLighting_(bool reset) { CCutsceneObject::RemoveLighting(reset); } -}; -static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error"); diff --git a/src/entities/DummyObject.cpp b/src/entities/DummyObject.cpp deleted file mode 100644 index 1e4b2ae0..00000000 --- a/src/entities/DummyObject.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "DummyObject.h" -#include "Pools.h" - -CDummyObject::CDummyObject(CObject *obj) -{ - SetModelIndexNoCreate(obj->GetModelIndex()); - if(obj->m_rwObject) - AttachToRwObject(obj->m_rwObject); - obj->DetachFromRwObject(); - m_level = obj->m_level; -} - -STARTPATCHES - InjectHook(0x4BAB70, &CDummyObject::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/DummyObject.h b/src/entities/DummyObject.h deleted file mode 100644 index 10554bdd..00000000 --- a/src/entities/DummyObject.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "Dummy.h" - -class CObject; - -class CDummyObject : public CDummy -{ -public: - CDummyObject(void) {} - CDummyObject(CObject *obj); - void dtor(void) { this->CDummyObject::~CDummyObject(); } -}; -static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error"); diff --git a/src/entities/DummyPed.h b/src/entities/DummyPed.h deleted file mode 100644 index af633dc4..00000000 --- a/src/entities/DummyPed.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "Dummy.h" - -// actually unused -class CDummyPed : CDummy -{ - int32 pedType; - int32 unknown; -}; -static_assert(sizeof(CDummyPed) == 0x70, "CDummyPed: error"); diff --git a/src/entities/EmergencyPed.cpp b/src/entities/EmergencyPed.cpp deleted file mode 100644 index 7b847896..00000000 --- a/src/entities/EmergencyPed.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "EmergencyPed.h" - -STARTPATCHES -InjectHook(0x4C2EF0, &CEmergencyPed::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/EmergencyPed.h b/src/entities/EmergencyPed.h deleted file mode 100644 index fa07f3ee..00000000 --- a/src/entities/EmergencyPed.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Ped.h" - -class CEmergencyPed : public CPed -{ -public: - // 0x53C - uint8 stuff[24]; - - void dtor(void) { this->CEmergencyPed::~CEmergencyPed(); } -}; -static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/entities/Heli.cpp b/src/entities/Heli.cpp deleted file mode 100644 index 01ee5375..00000000 --- a/src/entities/Heli.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Heli.h" - -CHeli::CHeli(int mi, uint8 owner) -{ - ctor(mi, owner); -} - -WRAPPER CHeli* CHeli::ctor(int, uint8) { EAXJMP(0x547220); } -WRAPPER void CHeli::SpecialHeliPreRender(void) { EAXJMP(0x54AE10); } - -STARTPATCHES -InjectHook(0x5474A0, &CHeli::dtor, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/Heli.h b/src/entities/Heli.h deleted file mode 100644 index da7bb171..00000000 --- a/src/entities/Heli.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Vehicle.h" - -class CHeli : public CVehicle -{ -public: - // 0x288 - uint8 stuff[180]; - - CHeli(int, uint8); - CHeli* ctor(int, uint8); - void dtor(void) { this->CHeli::~CHeli(); } - - static void SpecialHeliPreRender(void); -}; -static_assert(sizeof(CHeli) == 0x33C, "CHeli: error"); diff --git a/src/entities/Object.cpp b/src/entities/Object.cpp deleted file mode 100644 index 6712d77b..00000000 --- a/src/entities/Object.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Lights.h" -#include "Pools.h" -#include "Radar.h" -#include "Object.h" - -WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); } - -int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2; - -void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); } -void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); } - -CObject::CObject(void) -{ - m_type = ENTITY_TYPE_OBJECT; - m_fUprootLimit = 0.0f; - m_nCollisionDamageEffect = 0; - m_nSpecialCollisionResponseCases = COLLRESPONSE_NONE; - m_bCameraToAvoidThisObject = false; - ObjectCreatedBy = 0; - m_nEndOfLifeTime = 0; -// m_nRefModelIndex = -1; // duplicate -// bUseVehicleColours = false; // duplicate - m_colour2 = 0; - m_colour1 = m_colour2; - field_172 = 0; - bIsPickup = false; - m_obj_flag2 = false; - m_obj_flag4 = false; - m_obj_flag8 = false; - m_obj_flag10 = false; - bHasBeenDamaged = false; - m_nRefModelIndex = -1; - bUseVehicleColours = false; - m_pCurSurface = nil; - m_pCollidingEntity = nil; -} - -CObject::~CObject(void) -{ - CRadar::ClearBlipForEntity(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(this)); - - if(m_nRefModelIndex != -1) - CModelInfo::GetModelInfo(m_nRefModelIndex)->RemoveRef(); - - if(ObjectCreatedBy == TEMP_OBJECT && nNoTempObjects != 0) - nNoTempObjects--; -} - -void -CObject::Render(void) -{ - if(m_flagD80) - return; - - if(m_nRefModelIndex != -1 && ObjectCreatedBy == TEMP_OBJECT && bUseVehicleColours){ - CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_nRefModelIndex); - assert(mi->m_type == MITYPE_VEHICLE); - mi->SetVehicleColour(m_colour1, m_colour2); - } - - CEntity::Render(); -} - -bool -CObject::SetupLighting(void) -{ - DeActivateDirectional(); - SetAmbientColours(); - - if(bRenderScorched){ - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - return true; - } - return false; -} - -void -CObject::RemoveLighting(bool reset) -{ - if(reset) - WorldReplaceScorchedLightsWithNormal(Scene.world); -} - -WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); } - -STARTPATCHES - InjectHook(0x4BAE00, &CObject::dtor, PATCH_JUMP); - InjectHook(0x4BB1E0, &CObject::Render_, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/Object.h b/src/entities/Object.h deleted file mode 100644 index de4c8e05..00000000 --- a/src/entities/Object.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include "Physical.h" - -enum { - GAME_OBJECT = 1, - MISSION_OBJECT = 2, - TEMP_OBJECT = 3, - CUTSCENE_OBJECT = 4, -}; - -enum { - COLLRESPONSE_NONE, - COLLRESPONSE_CHANGE_MODEL, - COLLRESPONSE_SPLIT_MODEL, - COLLRESPONSE_SMASH_COMPLETELY, - COLLRESPONSE_CHANGE_THEN_SMASH, - COLLRESPONSE_UNKNOWN5, - - COLLRESPONSE_SMASH_CARDBOARD_COMPLETELY = 50, - COLLRESPONSE_SMASH_WOODENBOX_COMPLETELY = 60, - COLLRESPONSE_SMASH_TRAFFICCONE_COMPLETELY = 70, - COLLRESPONSE_SMASH_BARPOST_COMPLETELY = 80, - -}; - -class CVehicle; - -class CObject : public CPhysical -{ -public: - CMatrix m_objectMatrix; - float m_fUprootLimit; - int8 ObjectCreatedBy; - int8 bIsPickup : 1; - int8 m_obj_flag2 : 1; - int8 m_obj_flag4 : 1; - int8 m_obj_flag8 : 1; - int8 m_obj_flag10 : 1; - int8 bHasBeenDamaged : 1; - int8 bUseVehicleColours : 1; - int8 m_obj_flag80 : 1; - int8 field_172; - int8 field_173; - float m_fCollisionDamageMultiplier; - uint8 m_nCollisionDamageEffect; - uint8 m_nSpecialCollisionResponseCases; - bool m_bCameraToAvoidThisObject; - int8 field_17B; - int8 field_17C; - int8 field_17D; - int8 field_17E; - int8 field_17F; - int32 m_nEndOfLifeTime; - int16 m_nRefModelIndex; - int8 field_186; - int8 field_187; - CEntity *m_pCurSurface; - CEntity *m_pCollidingEntity; - int8 m_colour1, m_colour2; - - static int16 &nNoTempObjects; - - static void *operator new(size_t); - static void operator delete(void*, size_t); - - CObject(void); - ~CObject(void); - - void Render(void); - bool SetupLighting(void); - void RemoveLighting(bool reset); - - void ObjectDamage(float amount); - - static void DeleteAllTempObjectInArea(CVector, float); - - void dtor(void) { this->CObject::~CObject(); } - void Render_(void) { CObject::Render(); } -}; -static_assert(sizeof(CObject) == 0x198, "CObject: error"); diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp deleted file mode 100644 index 055ea3fb..00000000 --- a/src/entities/Ped.cpp +++ /dev/null @@ -1,2949 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "Pools.h" -#include "Particle.h" -#include "Stats.h" -#include "World.h" -#include "DMAudio.h" -#include "RpAnimBlend.h" -#include "Ped.h" -#include "PlayerPed.h" -#include "General.h" -#include "VisibilityPlugins.h" -#include "AudioManager.h" -#include "HandlingMgr.h" -#include "Replay.h" -#include "PedPlacement.h" -#include "Shadows.h" -#include "Weather.h" -#include "CullZones.h" -#include "Population.h" -#include "Renderer.h" -#include "Lights.h" -#include "PointLights.h" -#include "Pad.h" - -WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } -WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); } -WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4D37D0); } -WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } -WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); } -WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); } -WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } -WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } -WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } -WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); } -WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } -WRAPPER void CPed::Render(void) { EAXJMP(0x4D03F0); } -WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); } -WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } -WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); } -WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } -WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } - -bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; -bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; -bool &CPed::bPedCheat3 = *(bool*)0x95CD59; - -uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98; - -CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030; -CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C; -CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048; - -void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); } -void *CPed::operator new(size_t sz, int handle) { return CPools::GetPedPool()->New(handle); } -void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); } -void CPed::operator delete(void *p, int handle) { CPools::GetPedPool()->Delete((CPed*)p); } - -CPed::~CPed(void) -{ - CWorld::Remove(this); - CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); - if (bInVehicle && m_pMyVehicle){ - uint8 door_flag = GetVehEnterExitFlag(m_vehEnterType); - if (m_pMyVehicle->pDriver == this) - m_pMyVehicle->pDriver = nil; - else { - for (int i = 0; i < m_pMyVehicle->m_nNumMaxPassengers; i++) { - if (m_pMyVehicle->pPassengers[i] == this) - m_pMyVehicle->pPassengers[i] = nil; - } - } - if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) - m_pMyVehicle->m_nGettingOutFlags &= ~door_flag; - bInVehicle = false; - m_pMyVehicle = nil; - }else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK){ - QuitEnteringCar(); - } - if (m_pFire) - m_pFire->Extinguish(); - CPopulation::UpdatePedCount(m_nPedType, true); - DMAudio.DestroyEntity(m_audioEntityId); -} - -void -CPed::FlagToDestroyWhenNextProcessed(void) -{ - bRemoveFromWorld = true; - if (!bInVehicle || !m_pMyVehicle) - return; - if (m_pMyVehicle->pDriver == this){ - m_pMyVehicle->pDriver = nil; - if (IsPlayer() && m_pMyVehicle->m_status != STATUS_WRECKED) - m_pMyVehicle->m_status = STATUS_ABANDONED; - }else{ - m_pMyVehicle->RemovePassenger(this); - } - bInVehicle = false; - m_pMyVehicle = nil; - if (CharCreatedBy == MISSION_CHAR) - m_nPedState = PED_DEAD; - else - m_nPedState = PED_NONE; - m_pVehicleAnim = nil; -} - -static char ObjectiveText[34][28] = { - "No Obj", - "Wait on Foot", - "Flee on Foot Till Safe", - "Guard Spot", - "Guard Area", - "Wait in Car", - "Wait in Car then Getout", - "Kill Char on Foot", - "Kill Char Any Means", - "Flee Char on Foot Till Safe", - "Flee Char on Foot Always", - "GoTo Char on Foot", - "Follow Char in Formation", - "Leave Car", - "Enter Car as Passenger", - "Enter Car as Driver", - "Follow Car in Car", - "Fire at Obj from Vehicle", - "Destroy Obj", - "Destroy Car", - "GoTo Area Any Means", - "GoTo Area on Foot", - "Run to Area", - "GoTo Area in Car", - "Follow Car on Foot Woffset", - "Guard Attack", - "Set Leader", - "Follow Route", - "Solicit", - "Take Taxi", - "Catch Train", - "Buy IceCream", - "Steal Any Car", - "Mug Char", -}; - -static char StateText[56][18] = { - "None", // 1 - "Idle", - "Look Entity", - "Look Heading", - "Wander Range", - "Wander Path", - "Seek Pos", - "Seek Entity", - "Flee Pos", - "Flee Entity", - "Pursue", - "Follow Path", - "Sniper Mode", - "Rocket Mode", - "Dummy", - "Pause", - "Attack", - "Fight", - "Face Phone", - "Make Call", - "Chat", - "Mug", - "AimGun", - "AI Control", - "Seek Car", - "Seek InBoat", - "Follow Route", - "C.P.R.", - "Solicit", - "Buy IceCream", - "Investigate", - "Step away", - "STATES_NO_AI", - "On Fire", - "Jump", - "Fall", - "GetUp", - "Stagger", - "Dive away", - "STATES_NO_ST", - "Enter Train", - "Exit Train", - "Arrest Plyr", - "Driving", - "Passenger", - "Taxi Passngr", - "Open Door", - "Die", - "Dead", - "CarJack", - "Drag fm Car", - "Enter Car", - "Steal Car", - "Exit Car", - "Hands Up", - "Arrested", -}; - -static char PersonalityTypeText[32][18] = { - "Player", - "Cop", - "Medic", - "Fireman", - "Gang 1", - "Gang 2", - "Gang 3", - "Gang 4", - "Gang 5", - "Gang 6", - "Gang 7", - "Street Guy", - "Suit Guy", - "Sensible Guy", - "Geek Guy", - "Old Guy", - "Tough Guy", - "Street Girl", - "Suit Girl", - "Sensible Girl", - "Geek Girl", - "Old Girl", - "Tough Girl", - "Tramp", - "Tourist", - "Prostitute", - "Criminal", - "Busker", - "Taxi Driver", - "Psycho", - "Steward", - "Sports Fan", -}; - -static char WaitStateText[21][16] = { - "No Wait", - "Traffic Lights", - "Pause CrossRoad", - "Look CrossRoad", - "Look Ped", - "Look Shop", - "Look Accident", - "FaceOff Gang", - "Double Back", - "Hit Wall", - "Turn 180deg", - "Surprised", - "Ped Stuck", - "Look About", - "Play Duck", - "Play Cower", - "Play Taxi", - "Play HandsUp", - "Play HandsCower", - "Play Chat", - "Finish Flee", -}; - -CPed::CPed(uint32 pedType) : m_pedIK(this) -{ - m_type = ENTITY_TYPE_PED; - bPedPhysics = true; - bUseCollisionRecords = true; - - m_vecAnimMoveDelta.x = 0.0; - m_vecAnimMoveDelta.y = 0.0; - m_fHealth = 100.0f; - m_fArmour = 0.0f; - m_nPedType = pedType; - field_520 = 0; - m_talkTimer = 0; - m_talkTypeLast = 167; - m_talkType = 167; - m_objective = OBJECTIVE_NONE; - m_prevObjective = OBJECTIVE_NONE; - CharCreatedBy = RANDOM_CHAR; - m_leader = nil; - m_pedInObjective = nil; - m_carInObjective = nil; - bInVehicle = 0; - m_pMyVehicle = nil; - m_pVehicleAnim = nil; - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; - m_vecOffsetSeek.z = 0.0; - m_pedFormation = 0; - m_lastThreatTimer = 0; - m_nPedStateTimer = 0; - m_actionX = 0; - m_actionY = 0; - m_phoneTalkTimer = 0; - m_stateUnused = 0; - m_leaveCarTimer = 0; - m_getUpTimer = 0; - m_attackTimer = 0; - m_timerUnused = 0; - m_lookTimer = 0; - m_standardTimer = 0; - m_lastHitTime = 0; - m_hitRecoverTimer = 0; - field_4E8 = 0; - m_moved = CVector2D(0.0f, 0.0f); - m_fRotationCur = 0.0f; - m_headingRate = 15.0f; - m_fRotationDest = 0.0f; - m_vehEnterType = VEHICLE_ENTER_FRONT_LEFT; - m_walkAroundType = 0; - m_pCurrentPhysSurface = nil; - m_vecOffsetFromPhysSurface = CVector(0.0f, 0.0f, 0.0f); - m_pSeekTarget = nil; - m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); - m_wepSkills = 0; - field_318 = 1.0f; - field_31C = 0; - m_phoneId = -1; - m_lastAccident = 0; - m_fleeFrom = nil; - m_fleeFromPosX = 0; - m_fleeFromPosY = 0; - m_fleeTimer = 0; - m_vecSeekPosEx = CVector(0.0f, 0.0f, 0.0f); - m_seekExAngle = 0.0f; - m_nWaitState = WAITSTATE_FALSE; - m_nWaitTimer = 0; - m_pCollidingEntity = nil; - m_nPedState = PED_IDLE; - m_nLastPedState = PED_NONE; - m_nMoveState = PEDMOVE_STILL; - m_nStoredActionState = 0; - m_pFire = nil; - m_pPointGunAt = nil; - m_pLookTarget = nil; - m_fLookDirection = 0.0f; - m_pCurSurface = nil; - m_targetUnused = nil; - m_nPathNodes = 0; - m_nCurPathNode = 0; - m_nPathState = 0; - m_pNextPathNode = nil; - m_pLastPathNode = nil; - m_routeLastPoint = -1; - m_routePoints = 0; - m_routePos = 0; - m_routeType = 0; - m_bodyPartBleeding = -1; - - m_fMass = 70.0f; - m_fTurnMass = 100.0f; - m_fAirResistance = 0.4f / m_fMass; - m_fElasticity = 0.05f; - - bIsStanding = false; - m_ped_flagA2 = false; - m_ped_flagA4 = false; - bIsPointingGunAt = false; - bIsLooking = false; - m_ped_flagA20 = false; - bIsRestoringLook = false; - bIsAimingGun = false; - - bIsRestoringGun = false; - bCanPointGunAtTarget = false; - bIsTalking = false; - bIsInTheAir = false; - bIsLanding = false; - m_ped_flagB20 = false; - m_ped_flagB40 = false; - m_ped_flagB80 = false; - - m_ped_flagC1 = false; - bRespondsToThreats = true; - m_ped_flagC4 = true; - m_ped_flagC8 = false; - m_ped_flagC10 = false; - m_ped_flagC20 = false; - m_ped_flagC40 = false; - m_ped_flagC80 = false; - - m_ped_flagD1 = false; - m_ped_flagD2 = false; - m_ped_flagD4 = false; - m_ped_flagD8 = false; - m_ped_flagD10 = false; - m_ped_flagD20 = false; - m_ped_flagD40 = false; - m_ped_flagD80 = false; - - m_ped_flagE1 = false; - m_ped_flagE2 = false; - bNotAllowedToDuck = false; - bCrouchWhenShooting = false; - bIsDucking = false; - m_ped_flagE20 = false; - bDoBloodyFootprints = false; - m_ped_flagE80 = false; - - m_ped_flagF1 = false; - m_ped_flagF2 = false; - m_ped_flagF4 = false; - m_ped_flagF8 = false; - m_ped_flagF10 = false; - m_ped_flagF20 = false; - m_ped_flagF40 = false; - m_ped_flagF80 = false; - - m_ped_flagG1 = false; - m_ped_flagG2 = true; - m_ped_flagG4 = false; - m_ped_flagG8 = false; - m_ped_flagG10 = false; - m_ped_flagG20 = false; - m_ped_flagG40 = false; - m_ped_flagG80 = false; - - m_ped_flagH1 = false; - m_ped_flagH2 = false; - m_ped_flagH4 = false; - m_ped_flagH8 = false; - m_ped_flagH10 = false; - m_ped_flagH20 = false; - m_ped_flagH40 = false; - m_ped_flagH80 = false; - - m_ped_flagI1 = false; - m_ped_flagI2 = false; - m_ped_flagI4 = false; - bRecordedForReplay = false; - m_ped_flagI10 = false; -#ifdef KANGAROO_CHEAT - m_ped_flagI80 = false; -#endif - - if ((CGeneral::GetRandomNumber() & 3) == 0) - m_ped_flagD1 = true; - - m_audioEntityId = DMAudio.CreateEntity(0, this); - DMAudio.SetEntityStatus(m_audioEntityId, 1); - m_fearFlags = CPedType::GetThreats(m_nPedType); - m_threatEntity = nil; - m_eventOrThread = CVector2D(0.0f, 0.0f); - m_pEventEntity = nil; - m_fAngleToEvent = 0.0f; - m_numNearPeds = 0; - - for (int i = 0; i < 10; i++) - { - m_nearPeds[i] = nil; - if (i < 8) { - m_pPathNodesStates[i] = nil; - } - } - m_maxWeaponTypeAllowed = 0; - m_currentWeapon = 0; - m_storedWeapon = NO_STORED_WEAPON; - - for(int i = 0; i < NUM_PED_WEAPONTYPES; i++) - { - CWeapon &weapon = GetWeapon(i); - weapon.m_eWeaponType = WEAPONTYPE_UNARMED; - weapon.m_eWeaponState = WEAPONSTATE_READY; - weapon.m_nAmmoInClip = 0; - weapon.m_nAmmoTotal = 0; - weapon.m_nTimer = 0; - } - - m_lastHitState = 0; - GiveWeapon(WEAPONTYPE_UNARMED, 0); - m_wepAccuracy = 60; - m_lastWepDam = -1; - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - m_wepModelID = -1; - CPopulation::UpdatePedCount(m_nPedType, false); -} - -uint32 -CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) -{ - CWeapon &weapon = GetWeapon(weaponType); - - if (HasWeapon(weaponType)) { - if (weapon.m_nAmmoTotal + ammo > 99999) - weapon.m_nAmmoTotal = 99999; - else - weapon.m_nAmmoTotal += ammo; - - weapon.Reload(); - } else { - weapon.Initialise(weaponType, ammo); - // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. - m_maxWeaponTypeAllowed++; - } - if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) - weapon.m_eWeaponState = WEAPONSTATE_READY; - - return weaponType; -} - -static RwObject* -RemoveAllModelCB(RwObject *object, void *data) -{ - RpAtomic *atomic = (RpAtomic*)object; - if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { - RpClumpRemoveAtomic(atomic->clump, atomic); - RpAtomicDestroy(atomic); - } - return object; -} - -static PedOnGroundState -CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround) -{ - PedOnGroundState stateToReturn; - float angleToFace; - CPed *currentPed = nil; - PedState currentPedState; - CPed *pedOnTheFloor = nil; - CPed *deadPed = nil; - CPed *pedBelow = nil; - bool foundDead = false; - bool foundOnTheFloor = false; - bool foundBelow = false; - float angleDiff; - float distance; - - if (!CGame::nastyGame) - return NO_PED; - - for (int currentPedId = 0; currentPedId < player->m_numNearPeds; currentPedId++) { - - currentPed = player->m_nearPeds[currentPedId]; - - CVector posDifference = currentPed->GetPosition() - player->GetPosition(); - distance = posDifference.Magnitude(); - - if (distance < 2.0f) { - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - currentPed->GetPosition().x, currentPed->GetPosition().y, - player->GetPosition().x, player->GetPosition().y); - - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - player->m_fRotationCur = CGeneral::LimitRadianAngle(player->m_fRotationCur); - - angleDiff = fabs(angleToFace - player->m_fRotationCur); - - if (angleDiff > PI) - angleDiff = 2 * PI - angleDiff; - - currentPedState = currentPed->m_nPedState; - - if (currentPedState == PED_FALL || currentPedState == PED_GETUP || currentPedState == PED_DIE || currentPedState == PED_DEAD) { - if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { - if (currentPedState == PED_DEAD) { - foundDead = 1; - if (!deadPed) - deadPed = currentPed; - } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { - foundOnTheFloor = 1; - if (!pedOnTheFloor) - pedOnTheFloor = currentPed; - } - } - } else if ((distance >= 0.8f || angleDiff >= DEGTORAD(75.0f)) - && (distance >= 1.3f || angleDiff >= DEGTORAD(55.0f)) - && (distance >= 1.7f || angleDiff >= DEGTORAD(35.0f)) - && (distance >= 2.0f || angleDiff >= DEGTORAD(30.0f))) { - - if (angleDiff < DEGTORAD(75.0f)) { - foundBelow = 1; - if (!pedBelow) - pedBelow = currentPed; - } - } else { - foundBelow = 1; - pedBelow = currentPed; - break; - } - } - } - - if (foundOnTheFloor) { - currentPed = pedOnTheFloor; - stateToReturn = PED_ON_THE_FLOOR; - } else if (foundDead) { - currentPed = deadPed; - stateToReturn = PED_DEAD_ON_THE_FLOOR; - } else if (foundBelow) { - currentPed = pedBelow; - stateToReturn = PED_BELOW_PLAYER; - } else { - currentPed = nil; - stateToReturn = NO_PED; - } - - if (pedOnGround) - * pedOnGround = currentPed; - - return stateToReturn; -} - -bool -CPed::IsPlayer(void) -{ - return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType== PEDTYPE_PLAYER2 || - m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; -} - -bool -CPed::UseGroundColModel(void) -{ - return m_nPedState == PED_FALL || - m_nPedState == PED_DIVE_AWAY || - m_nPedState == PED_DIE || - m_nPedState == PED_DEAD; -} - -bool -CPed::CanSetPedState(void) -{ - return m_nPedState != PED_DIE && m_nPedState != PED_ARRESTED && - m_nPedState != PED_ENTER_CAR && m_nPedState != PED_DEAD && m_nPedState != PED_CARJACK && m_nPedState != PED_STEAL_CAR; -} - -bool -CPed::IsPedInControl(void) -{ - return m_nPedState <= PED_STATES_NO_AI - && !bIsInTheAir && !bIsLanding - && m_fHealth > 0.0f; -} - -bool -CPed::CanStrafeOrMouseControl(void) -{ - return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || - m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; -} - -void -CPed::AddWeaponModel(int id) -{ - RpAtomic *atm; - - if (id != -1) { - atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - RwFrameDestroy(RpAtomicGetFrame(atm)); - RpAtomicSetFrame(atm, GetNodeFrame(PED_HANDR)); - RpClumpAddAtomic((RpClump*)m_rwObject, atm); - m_wepModelID = id; - } -} - -void -CPed::AimGun(void) -{ - RwV3d pos; - CVector vector; - - if (m_pSeekTarget) { - if (m_pSeekTarget->IsPed()) { - ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_TORSO); - vector.x = pos.x; - vector.y = pos.y; - vector.z = pos.z; - } else { - vector = *(m_pSeekTarget->GetPosition()); - } - Say(SOUND_PED_ATTACK); - - bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(&vector); - if (m_pLookTarget != m_pSeekTarget) { - SetLookFlag(m_pSeekTarget, 1); - } - - } else { - if (IsPlayer()) { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); - } else { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); - } - } -} - -void -CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) -{ - CVector pos2 = CVector( - pos.x, - pos.y, - pos.z + 0.1f - ); - - if (!CPed::IsPlayer() || evenOnPlayer) { - ++CStats::HeadShots; - - // BUG: This condition will always return true. - if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { - CPed::SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - } - - m_ped_flagC20 = true; - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; - - CParticle::AddParticle(PARTICLE_TEST, pos2, - CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); - - if (CEntity::GetIsOnScreen()) { - for(int i=0; i < 32; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos2, CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_DEBRIS2, - pos2, - CVector(0.0f, 0.0f, 0.01f), - nil, 0.0f, 0, 0, 0, 0); - } - } - } -} - -void -CPed::RemoveBodyPart(PedNode nodeId, int8 unk) -{ - RwFrame *frame; - RwV3d pos; - - frame = GetNodeFrame(nodeId); - if (frame) { - if (CGame::nastyGame) { - if (nodeId != PED_HEAD) - CPed::SpawnFlyingComponent(nodeId, unk); - - RecurseFrameChildrenVisibilityCB(frame, nil); - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - - for (frame = RwFrameGetParent(frame); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints(&pos, &pos, 1, RwFrameGetMatrix(frame)); - - if (CEntity::GetIsOnScreen()) { - CParticle::AddParticle(PARTICLE_TEST, pos, - CVector(0.0f, 0.0f, 0.0f), - nil, 0.2f, 0, 0, 0, 0); - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos, - CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - } - m_ped_flagC20 = true; - m_bodyPartBleeding = nodeId; - } - } else { - printf("Trying to remove ped component"); - } -} - -RwObject* -CPed::SetPedAtomicVisibilityCB(RwObject *object, void *data) -{ - if (data == nil) - RpAtomicSetFlags(object, 0); - return object; -} - -RwFrame* -CPed::RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data) -{ - RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); - RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); - return frame; -} - -void -CPed::SetLookFlag(CEntity *target, bool unknown) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = target; - m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - m_fLookDirection = 999999.0f; - m_lookTimer = 0; - m_ped_flagA20 = unknown; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::FLAG_2; - } - } -} - -void -CPed::SetLookFlag(float direction, bool unknown) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = nil; - m_fLookDirection = direction; - m_lookTimer = 0; - m_ped_flagA20 = unknown; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::FLAG_2; - } - } -} - -void -CPed::SetLookTimer(int time) -{ - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + time; - } -} - -bool -CPed::OurPedCanSeeThisOne(CEntity *target) -{ - CColPoint colpoint; - CEntity *ent; - - CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(this->GetPosition()); - - // Check if target is behind ped - if (DotProduct2D(dist, CVector2D(this->GetForward())) < 0.0f) - return false; - - // Check if target is too far away - if (dist.Magnitude() >= 40.0f) - return false; - - // Check line of sight from head - CVector headPos = this->GetPosition(); - headPos.z += 1.0f; - return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); -} - -void -CPed::Avoid(void) -{ - CPed *nearestPed; - - if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) - return; - - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { - - if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { - nearestPed = m_nearPeds[0]; - - if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { - - // Check if this ped wants to avoid the nearest one - if (CPedType::GetAvoid(this->m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { - - // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. - // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. - - // Game converts from radians to degress and back again here, doesn't make much sense - CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); - forward.Normalise(); // this is kinda pointless - - // Move forward 1.25 meters - CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; - - // Get distance to ped we want to avoid - CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; - - if (distToPed.Magnitude() <= 1.0f && CPed::OurPedCanSeeThisOne((CEntity*)nearestPed)) { - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() - + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) - % 1000 / 5; - - m_fRotationDest += DEGTORAD(45.0f); - if (!bIsLooking) { - CPed::SetLookFlag(nearestPed, 0); - CPed::SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); - } - } - } - } - } - } -} - -void -CPed::ClearAimFlag(void) -{ - if (bIsAimingGun) { - bIsAimingGun = false; - bIsRestoringGun = true; - m_pedIK.m_flags &= ~CPedIK:: FLAG_4; - } - - if (CPed::IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0; -} - -void -CPed::ClearLookFlag(void) { - if (bIsLooking) { - bIsLooking = false; - bIsRestoringLook = true; - m_ped_flagI1 = false; - - m_pedIK.m_flags &= ~CPedIK::FLAG_2; - if (CPed::IsPlayer()) - m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; - else - m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; - - if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { - CPed::RestorePreviousState(); - CPed::ClearLookFlag(); - } - } -} - -bool -CPed::IsPedHeadAbovePos(float zOffset) -{ - RwMatrix mat; - - CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat); - return zOffset + GetPosition().z < RwMatrixGetPos(&mat)->z; -} - -void -CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) -{ - CWeaponInfo *currentWeapon; - CAnimBlendAssociation *newAnim; - CPed *ped = (CPed*)arg; - - if (attackAssoc) { - switch (attackAssoc->animId) { - case ANIM_WEAPON_START_THROW: - if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1380) && ped->IsPlayer()) { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROWU); - } else { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROW); - } - - newAnim->SetFinishCallback(FinishedAttackCB, ped); - return; - - case ANIM_FIGHT_PPUNCH: - attackAssoc->blendDelta = -8.0f; - attackAssoc->flags |= ASSOC_DELETEFADEDOUT; - ped->ClearAttack(); - return; - - case ANIM_WEAPON_THROW: - case ANIM_WEAPON_THROWU: - if (ped->GetWeapon()->m_nAmmoTotal > 0) { - currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); - ped->AddWeaponModel(currentWeapon->m_nModelId); - } - break; - default: - break; - } - } - - if (!ped->m_ped_flagA4) - ped->ClearAttack(); -} - -void -CPed::Attack(void) -{ - CAnimBlendAssociation *weaponAnimAssoc; - int32 weaponAnim; - float animStart; - RwFrame *frame; - eWeaponType ourWeaponType; - float weaponAnimTime; - eWeaponFire ourWeaponFire; - float animLoopEnd; - CWeaponInfo *ourWeapon; - bool lastReloadWasInFuture; - AnimationId reloadAnim; - CAnimBlendAssociation *reloadAnimAssoc; - float delayBetweenAnimAndFire; - CVector firePos; - - ourWeaponType = GetWeapon()->m_eWeaponType; - ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); - ourWeaponFire = ourWeapon->m_eWeaponFire; - weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_AnimToPlay); - lastReloadWasInFuture = m_ped_flagA4; - reloadAnimAssoc = nil; - reloadAnim = NUM_ANIMS; - delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; - weaponAnim = ourWeapon->m_AnimToPlay; - - if (weaponAnim == ANIM_WEAPON_HGUN_BODY) - reloadAnim = ANIM_HGUN_RELOAD; - else if (weaponAnim == ANIM_WEAPON_AK_BODY) - reloadAnim = ANIM_AK_RELOAD; - - if (reloadAnim != NUM_ANIMS) - reloadAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, reloadAnim); - - if (bIsDucking) - return; - - if (reloadAnimAssoc) { - if (!CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) - ClearAttack(); - - return; - } - - // BUG: We currently don't know any situation this cond. could be true. - if (CTimer::GetTimeInMilliseconds() < m_lastHitTime) - lastReloadWasInFuture = true; - - if (!weaponAnimAssoc) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_Anim2ToPlay); - delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; - - // Long throw granade, molotov - if (!weaponAnimAssoc && ourWeapon->m_bThrow) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU); - delayBetweenAnimAndFire = 0.2f; - } - } - if (weaponAnimAssoc) { - animStart = ourWeapon->m_fAnimLoopStart; - weaponAnimTime = weaponAnimAssoc->currentTime; - if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { - if (ourWeapon->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::FLAG_4; - else - m_pedIK.m_flags &= ~CPedIK::FLAG_4; - } - - if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { - if (weaponAnimAssoc->speed < 1.0f) - weaponAnimAssoc->speed = 1.0f; - - } else { - firePos = ourWeapon->m_vecFireOffset; - if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { - if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; - - firePos = GetMatrix() * firePos; - } else if (ourWeaponType != WEAPONTYPE_UNARMED) { - if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR) - frame = GetNodeFrame(PED_FOOTR); - else - frame = GetNodeFrame(PED_HANDR); - - for (; frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); - } else { - firePos = GetMatrix() * firePos; - } - - GetWeapon()->Fire(this, &firePos); - - if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { - RemoveWeaponModel(ourWeapon->m_nModelId); - } - if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { - SelectGunIfArmed(); - } - - if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { - // If reloading just began, start the animation - if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f); - ClearLookFlag(); - ClearAimFlag(); - m_ped_flagA4 = false; - bIsPointingGunAt = false; - m_lastHitTime = CTimer::GetTimeInMilliseconds(); - return; - } - } else { - if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); - } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); - } - - weaponAnimAssoc->speed = 0.5f; - - // BUG: We currently don't know any situation this cond. could be true. - if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) { - weaponAnimAssoc->callbackType = 0; - } - } - - lastReloadWasInFuture = false; - } - - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { - weaponAnimTime = weaponAnimAssoc->currentTime; - firePos = ourWeapon->m_vecFireOffset; - - if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); - - CVector gunshellPos( - firePos.x - 0.6f * GetForward().x, - firePos.y - 0.6f * GetForward().y, - firePos.z - 0.15f * GetUp().z - ); - - CVector2D gunshellRot( - GetRight().x, - GetRight().y - ); - - gunshellRot.Normalise(); - GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); - } - } - animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - animLoopEnd = 3.4f/6.0f; - - weaponAnimTime = weaponAnimAssoc->currentTime; - - // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { - - if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd - && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) - && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - - weaponAnim = weaponAnimAssoc->animId; - if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { - if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { - weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); - } else { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } - } else { - if (weaponAnim == ourWeapon->m_Anim2ToPlay) - weaponAnimAssoc->SetCurrentTime(0.1f); - else - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } - } else { - ClearAimFlag(); - - // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) - if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { - switch (ourWeaponType) { - case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_M16: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); - break; - default: - break; - } - } - - // Fun fact: removing this part leds to reloading flamethrower - if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { - weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - weaponAnimAssoc->blendDelta = -4.0f; - } - } - } - if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) - lastReloadWasInFuture = false; - - m_ped_flagA4 = lastReloadWasInFuture; - return; - } - - if (lastReloadWasInFuture) { - if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) { - if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { - weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } else { - weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } - - weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this); - weaponAnimAssoc->flags |= ASSOC_RUNNING; - - if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) - weaponAnimAssoc->SetCurrentTime(0.0f); - - if (CPed::IsPlayer()) { - ((CPlayerPed*)this)->field_1376 = 0.0f; - ((CPlayerPed*)this)->field_1380 = false; - } - } - } - else - CPed::FinishedAttackCB(nil, this); -} - -void -CPed::RemoveWeaponModel(int modelId) -{ - // modelId is not used!! This function just removes the current weapon. - RwFrameForAllObjects(GetNodeFrame(PED_HANDR),RemoveAllModelCB,nil); - m_wepModelID = -1; -} - -void -CPed::SetCurrentWeapon(uint32 weaponType) -{ - CWeaponInfo *weaponInfo; - if (HasWeapon(weaponType)) { - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(weaponInfo->m_nModelId); - - m_currentWeapon = weaponType; - - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(weaponInfo->m_nModelId); - } -} - -// Only used while deciding which gun ped should switch to, if no ammo left. -bool -CPed::SelectGunIfArmed(void) -{ - for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { - if (GetWeapon(i).m_nAmmoTotal > 0) { - eWeaponType weaponType = GetWeapon(i).m_eWeaponType; - if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { - SetCurrentWeapon(i); - return true; - } - } - } - SetCurrentWeapon(WEAPONTYPE_UNARMED); - return false; -} - -void -CPed::Duck(void) -{ - if (CTimer::GetTimeInMilliseconds() > m_duckTimer) - ClearDuck(); -} - -void -CPed::ClearDuck(void) -{ - CAnimBlendAssociation *animAssoc; - - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_LOW); - - if (animAssoc) { - - if (bCrouchWhenShooting) { - - if (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN) { - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); - } - } - } - } else - bIsDucking = false; -} - -void -CPed::ClearPointGunAt(void) -{ - CAnimBlendAssociation *animAssoc; - CWeaponInfo *weaponInfo; - - ClearLookFlag(); - ClearAimFlag(); - bIsPointingGunAt = false; - if (m_nPedState == PED_AIM_GUN) { - RestorePreviousState(); - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_AnimToPlay); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_Anim2ToPlay); - } - if (animAssoc) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->blendDelta = -4.0; - } - } -} - -void -CPed::BeingDraggedFromCar(void) -{ - CAnimBlendAssociation *animAssoc; - AnimationId enterAnim; - bool dontRunAnim = false; - PedLineUpPhase lineUpType; - - if (!m_pVehicleAnim) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f); - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_LSIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITP); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITPLO); - } - } - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { - if (m_ped_flagF10) { - enterAnim = ANIM_CAR_QJACKED; - } else if (m_pMyVehicle->bLowVehicle) { - enterAnim = ANIM_CAR_LJACKED_LHS; - } else { - enterAnim = ANIM_CAR_JACKED_LHS; - } - } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { - if (m_pMyVehicle->bLowVehicle) - enterAnim = ANIM_CAR_LJACKED_RHS; - else - enterAnim = ANIM_CAR_JACKED_RHS; - } else - dontRunAnim = true; - - - if (!dontRunAnim) - m_pVehicleAnim = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, enterAnim); - - m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this); - lineUpType = LINE_UP_TO_CAR_START; - } else if (m_pVehicleAnim->currentTime <= 1.4f) { - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - lineUpType = LINE_UP_TO_CAR_START; - } else { - lineUpType = LINE_UP_TO_CAR_2; - } - - LineUpPedWithCar(lineUpType); -} - -void -CPed::RestartNonPartialAnims(void) -{ - CAnimBlendAssociation *assoc; - - for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->flags |= ASSOC_RUNNING; - } -} - -void -CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) -{ - CAnimBlendAssociation *quickJackedAssoc; - CVehicle *vehicle; - CPed *ped = (CPed*)arg; - eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType; - - quickJackedAssoc = RpAnimBlendClumpGetAssociation((RpClump*) ped->m_rwObject, ANIM_CAR_QJACKED); - if (ped->m_nPedState != PED_ARRESTED) { - ped->m_nLastPedState = PED_NONE; - if (dragAssoc) - dragAssoc->blendDelta = -1000.0; - } - ped->RestartNonPartialAnims(); - ped->m_pVehicleAnim = nil; - ped->m_pSeekTarget = nil; - vehicle = ped->m_pMyVehicle; - - vehicle->m_nGettingOutFlags &= ~GetVehEnterExitFlag(ped->m_vehEnterType); - - if (vehicle->pDriver == ped) { - vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_COP_CAR) - vehicle->m_nDoorLock = CARLOCK_UNLOCKED; - - if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) - vehicle->ChangeLawEnforcerState(false); - } else { - for (int i = 0; i < vehicle->m_nNumMaxPassengers; i++) { - if (vehicle->pPassengers[i] == ped) { - vehicle->pPassengers[i] = nil; - vehicle->m_nNumPassengers--; - } - } - } - - ped->bInVehicle = false; - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); - - if (quickJackedAssoc) { - dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); - } else { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - if (ped->CanSetPedState()) - CAnimManager::BlendAnimation((RpClump*) ped->m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - } - - // Only uzi can be used on cars, so previous weapon was stored - if (ped->IsPlayer() && weaponType == WEAPONTYPE_UZI) { - if (ped->m_storedWeapon != NO_STORED_WEAPON) { - ped->SetCurrentWeapon(ped->m_storedWeapon); - ped->m_storedWeapon = NO_STORED_WEAPON; - } - } else { - ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); - } - ped->m_nStoredActionState = 0; - ped->m_ped_flagI4 = false; -} - -void -CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult) -{ - CVehicleModelInfo *vehModel; - CVector vehDoorPos; - CVector vehDoorOffset; - float seatOffset; - - vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex); - if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { - seatOffset = 0.0f; - vehDoorOffset = offsetToOpenVanDoor; - } else { - seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult; - if (veh->bLowVehicle) { - vehDoorOffset = offsetToOpenLowCarDoor; - } else { - vehDoorOffset = offsetToOpenRegularCarDoor; - } - } - - switch (enterType) { - case VEHICLE_ENTER_FRONT_RIGHT: - if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; - else - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; - - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case VEHICLE_ENTER_REAR_RIGHT: - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case VEHICLE_ENTER_FRONT_LEFT: - if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; - else - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; - - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - case VEHICLE_ENTER_REAR_LEFT: - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - default: - if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; - else - vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; - - vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); - } - *output = vehDoorPos - vehDoorOffset; -} - -// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. -void -CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType) -{ - CVector localPos; - CVector vehDoorPos; - - GetLocalPositionToOpenCarDoor(&localPos, veh, enterType, 1.0f); - vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); - -/* - // Not used. - CVector localVehDoorOffset; - - if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { - localVehDoorOffset = offsetToOpenVanDoor; - } else { - if (veh->bIsLow) { - localVehDoorOffset = offsetToOpenLowCarDoor; - } else { - localVehDoorOffset = offsetToOpenRegularCarDoor; - } - } - - vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); -*/ - *output = vehDoorPos; -} - -void -CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset) -{ - CVector doorPos; - CMatrix vehMat(veh->GetMatrix()); - - GetLocalPositionToOpenCarDoor(output, veh, enterType, offset); - doorPos = Multiply3x3(vehMat, *output); - - *output = *veh->GetPosition() + doorPos; -} - -void -CPed::LineUpPedWithCar(PedLineUpPhase phase) -{ - bool vehIsUpsideDown = false; - int vehAnim; - float seatPosMult = 0.0f; - float currentZ; - float adjustedTimeStep; - - if (CReplay::IsPlayingBack()) - return; - - if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) { - if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_LSIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITP)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITPLO)) { - SetPedPositionInCar(); - return; - } - m_ped_flagC8 = 1; - } - if (phase == LINE_UP_TO_CAR_START) { - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } - CVehicle *veh = m_pMyVehicle; - - // Not quite right, IsUpsideDown func. checks for <= -0.9f. - // Since that function is also used in this file, doesn't this variable indicate upsidedownness?! - if (veh->GetUp().z <= -0.8f) - vehIsUpsideDown = true; - - if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { - if (vehIsUpsideDown) { - m_fRotationDest = -PI + veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = 0.5 * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { - if (vehIsUpsideDown) { - m_fRotationDest = veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = -0.5 * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } - - if (!bInVehicle) - seatPosMult = 1.0f; - - if (m_pVehicleAnim) { - vehAnim = m_pVehicleAnim->animId; - - switch (vehAnim) { - case ANIM_CAR_JACKED_RHS: - case ANIM_CAR_LJACKED_RHS: - case ANIM_CAR_JACKED_LHS: - case ANIM_CAR_LJACKED_LHS: - case ANIM_CAR_QJACKED: - case ANIM_CAR_GETOUT_LHS: - case ANIM_CAR_GETOUT_LOW_LHS: - case ANIM_CAR_GETOUT_RHS: - case ANIM_CAR_GETOUT_LOW_RHS: - case ANIM_CAR_CRAWLOUT_RHS: - case ANIM_CAR_CRAWLOUT_RHS2: - case ANIM_VAN_GETIN_L: - case ANIM_VAN_GETOUT_L: - case ANIM_VAN_GETIN: - case ANIM_VAN_GETOUT: - seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; - break; - case ANIM_CAR_QJACK: - case ANIM_CAR_GETIN_LHS: - case ANIM_CAR_GETIN_LOW_LHS: - case ANIM_CAR_GETIN_RHS: - case ANIM_CAR_GETIN_LOW_RHS: - case ANIM_DRIVE_BOAT: - seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; - break; - case ANIM_CAR_CLOSEDOOR_LHS: - case ANIM_CAR_CLOSEDOOR_LOW_LHS: - case ANIM_CAR_CLOSEDOOR_RHS: - case ANIM_CAR_CLOSEDOOR_LOW_RHS: - case ANIM_CAR_SHUFFLE_RHS: - case ANIM_CAR_LSHUFFLE_RHS: - seatPosMult = 0.0f; - break; - case ANIM_CAR_CLOSE_LHS: - case ANIM_CAR_CLOSE_RHS: - case ANIM_COACH_OPEN_L: - case ANIM_COACH_OPEN_R: - case ANIM_COACH_IN_L: - case ANIM_COACH_IN_R: - case ANIM_COACH_OUT_L: - seatPosMult = 1.0f; - break; - default: - break; - } - } - - CVector neededPos; - - if (phase == LINE_UP_TO_CAR_2) { - neededPos = *GetPosition(); - } else { - GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult); - } - - CVector autoZPos = neededPos; - - if (veh->bIsInWater) { - if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) - autoZPos.z += 1.0f; - } else { - CPedPlacement::FindZCoorForPed(&autoZPos); - } - - if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { - neededPos.z = GetPosition().z; - - // Getting out - if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { - float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep(); - - // If we're not in ground at next step, apply animation - if (neededPos.z + pedZSpeedOnExit >= autoZPos.z) { - m_vecMoveSpeed.z = pedZSpeedOnExit; - ApplyMoveSpeed(); - // Removing below line breaks the animation - neededPos.z = GetPosition().z; - } else { - neededPos.z = autoZPos.z; - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } - } - } - - if (autoZPos.z > neededPos.z) { - currentZ = GetPosition().z; - if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { - neededPos.z = autoZPos.z; - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { - adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); - - // Smoothly change ped position - neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); - } - } else { - // We may need to raise up the ped - if (phase == LINE_UP_TO_CAR_START) { - currentZ = GetPosition().z; - - if (neededPos.z > currentZ) { - - if (m_pVehicleAnim && - (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS - || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { - adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); - - // Smoothly change ped position - neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; - } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) { - neededPos.z = max(currentZ, autoZPos.z); - } - } - } - } - - bool stillGettingInOut = false; - if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) - stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10; - - if (!stillGettingInOut) { - m_fRotationCur = m_fRotationDest; - } else { - float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); - float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; - - m_vecOffsetSeek.z = 0.0; - if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0; - m_vecOffsetSeek.y = 0.0; - } else { - neededPos -= timeUntilStateChange * m_vecOffsetSeek; - } - - if (limitedAngle > PI + m_fRotationCur) { - limitedAngle -= 2 * PI; - } else if (limitedAngle < m_fRotationCur - PI) { - limitedAngle += 2 * PI; - } - m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange); - } - - if (seatPosMult > 0.2f || vehIsUpsideDown) { - GetPosition() = neededPos; - - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - - // It will be all 0 after rotate. - GetPosition() = neededPos; - } else { - CVector output; - CMatrix vehDoorMat(veh->GetMatrix()); - - GetLocalPositionToOpenCarDoor(&output, veh, m_vehEnterType, 0.0f); - *vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output); - GetMatrix() = vehDoorMat; - } - -} - -static void -particleProduceFootDust(CPed *ped, CVector *pos, float size, int times) -{ - switch (ped->m_nLastCollType) - { - case 1: // somewhere hard - case 3: // soft dirt - case 5: // pavement - case 18:// sand - for (int i = 0; i < times; ++i) { - CVector adjustedPos = *pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); - } - break; - default: - break; - } -} - -static void -particleProduceFootSplash(CPed *ped, CVector *pos, float size, int times) -{ - for (int i = 0; i < times; i++) { - CVector adjustedPos = *pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - - CVector direction = ped->GetForward() * -0.05f; - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumberInRange(0, 1), 200); - } -} - -void -CPed::PlayFootSteps(void) -{ - if (bDoBloodyFootprints) { - if (m_bloodyFootprintCount > 0 && m_bloodyFootprintCount < 300) { - m_bloodyFootprintCount--; - - if (m_bloodyFootprintCount == 0) - bDoBloodyFootprints = false; - } - } - - if (!bIsStanding) - return; - - CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); - CAnimBlendAssociation *walkRunAssoc = nil; - float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; - - for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (assoc->flags & ASSOC_FLAG80) { - walkRunAssoc = assoc; - walkRunAssocBlend += assoc->blendAmount; - } else if ((assoc->flags & ASSOC_FLAG200) == 0) { - idleAssocBlend += assoc->blendAmount; - } - } - - if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { - float stepStart = 1 / 15.0f; - float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; - float currentTime = walkRunAssoc->currentTime; - int stepPart = 0; - - if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) - stepPart = 1; - else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) - stepPart = 2; - - if (stepPart != 0) { - DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); - CVector footPos(0.0f, 0.0f, 0.0f); - - for (RwFrame *frame = GetNodeFrame(stepPart == 1 ? PED_FOOTL : PED_FOOTR); frame; frame = RwFrameGetParent(frame)) - RwV3dTransformPoints(footPos, footPos, 1, RwFrameGetMatrix(frame)); - - CVector forward = GetForward(); - - footPos.z -= 0.1f; - footPos += 0.2f * forward; - - if (bDoBloodyFootprints) { - CVector2D top(forward * 0.26f); - CVector2D right(GetRight() * 0.14f); - - CShadows::AddPermanentShadow(1, gpBloodPoolTex, &footPos, - top.x, top.y, - right.x, right.y, - 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); - - if (m_bloodyFootprintCount <= 20) { - m_bloodyFootprintCount = 0; - bDoBloodyFootprints = false; - } else { - m_bloodyFootprintCount -= 20; - } - } - if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { - if(IsPlayer()) - particleProduceFootDust(this, &footPos, 0.0f, 4); - } else if(stepPart == 2) { - particleProduceFootSplash(this, &footPos, 0.15f, 4); - } - } - } - - if (m_nLastCollType == 19) { // Water - float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); - if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { - float particleSize = pedSpeed * 2.0f; - - if (particleSize < 0.25f) - particleSize = 0.25f; - - if (particleSize > 0.75f) - particleSize = 0.75f; - - CVector particlePos = GetPosition() + GetForward() * 0.3f; - particlePos.z -= 1.2f; - - CVector particleDir = m_vecMoveSpeed * 0.75f; - - particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); - CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); - - particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); - CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); - } - } -} - -bool -CPed::IsPointerValid(void) -{ - int8 pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; - if (pedIndex < 0 || pedIndex >= NUMPEDS) - return false; - - if (m_entryInfoList.first || FindPlayerPed() == this) - return true; - - return false; -} - -// Some kind of binary sort -void -CPed::SortPeds(CPed **list, int min, int max) -{ - if (min >= max) - return; - - CVector leftDiff, rightDiff; - CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); - float middleDist = middleDiff.Magnitude(); - - int left = max; - int right; - for(right = min; right <= left; ){ - // Those 1.0s are to make sure loop always run for first time. - for (float rightDist = middleDist-1.0f; middleDist > rightDist; right++) { - rightDiff = GetPosition() - list[right]->GetPosition(); - rightDist = rightDiff.Magnitude(); - } - right--; - - for (float leftDist = middleDist+1.0f; middleDist < leftDist; left--) { - leftDiff = GetPosition() - list[left]->GetPosition(); - leftDist = leftDiff.Magnitude(); - } - left++; - - if (right <= left) { - CPed *ped = list[right]; - list[right] = list[left]; - list[left] = ped; - right++; - left--; - } - } - SortPeds(list, min, left); - SortPeds(list, right, max); -} - -void -CPed::BuildPedLists(void) -{ - static CPed *unsortedNearPeds[10]; - uint16 nextNearPedSlot = 0; - - if ((CTimer::GetFrameCounter() + m_randomSeed) & 15) { - - for(int i = 0; i < 10; ) { - if (m_nearPeds[i]) { - if (m_nearPeds[i]->IsPointerValid()) { - float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); - if (distSqr < 900.0f) { - i++; - continue; - } - } - - // If we arrive here, the ped we're checking isn't "near", so we should remove it. - for (int j = i; j < 9; j++) { - m_nearPeds[j] = m_nearPeds[j + 1]; - m_nearPeds[j + 1] = nil; - } - // Above loop won't work when it's 9, so we need to empty slot 9. - m_nearPeds[9] = nil; - m_numNearPeds--; - } else - i++; - } - } else { - CVector centre = CEntity::GetBoundCentre(); - CRect rect( - (centre.x - 20.0f) * 0.025f + 50.0f, - (centre.y - 20.0f) * 0.025f + 50.0f, - (centre.x + 20.0f) * 0.025f + 50.0f, - (centre.y + 20.0f) * 0.025f + 50.0f); - - for(int y = rect.top; y <= rect.bottom; y++) { - for(int x = rect.left; x <= rect.right; x++) { - for (CPtrNode *pedPtrNode = CWorld::GetSector(x,y)->m_lists[ENTITYLIST_PEDS].first; pedPtrNode; pedPtrNode = pedPtrNode->next) { - CPed *ped = (CPed*)pedPtrNode->item; - if (ped != this && !ped->bInVehicle) { - float dist = (ped->GetPosition() - GetPosition()).Magnitude2D(); - if (distanceMultToCountPedNear * 30.0f > dist) - { - unsortedNearPeds[nextNearPedSlot] = ped; - nextNearPedSlot++; - } - } - } - } - } - unsortedNearPeds[nextNearPedSlot] = nil; - SortPeds(unsortedNearPeds, 0, nextNearPedSlot - 1); - for (m_numNearPeds = 0; m_numNearPeds < 10; m_numNearPeds++) { - CPed *ped = unsortedNearPeds[m_numNearPeds]; - if (!ped) - break; - - m_nearPeds[m_numNearPeds] = ped; - } - for (int pedToClear = m_numNearPeds; pedToClear < 10; pedToClear++) - m_nearPeds[pedToClear] = nil; - } -} - -void -CPed::SetPedStats(ePedStats pedStat) -{ - m_pedStats = CPedStats::ms_apPedStats[pedStat]; -} - -void -CPed::SetModelIndex(uint32 mi) -{ - CEntity::SetModelIndex(mi); - RpAnimBlendClumpInit((RpClump*) m_rwObject); - RpAnimBlendClumpFillFrameArray((RpClump*) m_rwObject, m_pFrames); - CPedModelInfo *modelInfo = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); - SetPedStats((ePedStats) modelInfo->m_pedStatType); - m_headingRate = m_pedStats->m_headingChangeRate; - m_animGroup = (AssocGroupId) modelInfo->m_animGroup; - CAnimManager::AddAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE); - - // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; -} - -void -CPed::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} - -bool -CPed::SetupLighting(void) -{ - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); - if (bRenderScorched) { - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - } else { - // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. - float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); - if (!bHasBlip && lightMult != 1.0f) { - SetAmbientAndDirectionalColours(lightMult); - return true; - } - } - return false; -} - -void -CPed::Teleport(CVector pos) -{ - CWorld::Remove(this); - GetPosition() = pos; - bIsStanding = false; - m_nPedStateTimer = 0; - m_actionX = 0.0f; - m_actionY = 0.0f; - m_pDamageEntity = nil; - CWorld::Add(this); -} - -void -CPed::CalculateNewOrientation(void) -{ - if (CReplay::IsPlayingBack() || !IsPedInControl()) - return; - - CVector pos = *GetPosition(); - - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - - // Because SetRotate makes pos. all 0 - GetPosition() = pos; -} - -float -CPed::WorkOutHeadingForMovingFirstPerson(float offset) -{ - if (!IsPlayer()) - return 0.0f; - - CPad *pad0 = CPad::GetPad(0); - float leftRight = pad0->GetPedWalkLeftRight(); - float upDown = pad0->GetPedWalkUpDown(); - float &angle = ((CPlayerPed*)this)->m_fWalkAngle; - - if (upDown != 0.0f) { - angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); - } else { - if (leftRight < 0.0f) - angle = 0.5 * PI; - else if (leftRight > 0.0f) - angle = -0.5 * PI; - } - - return CGeneral::LimitRadianAngle(offset + angle); -} - -void -CPed::CalculateNewVelocity(void) -{ - if (IsPedInControl()) { - float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep(); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest); - - if (m_fRotationCur - PI > limitedRotDest) { - limitedRotDest += 2 * PI; - } else if(PI + m_fRotationCur < limitedRotDest) { - limitedRotDest -= 2 * PI; - } - - if (IsPlayer() && m_nPedState == PED_ATTACK) - headAmount /= 4.0f; - - float neededTurn = limitedRotDest - m_fRotationCur; - if (neededTurn <= headAmount) { - if (neededTurn > (-headAmount)) - m_fRotationCur += neededTurn; - else - m_fRotationCur -= headAmount; - } else { - m_fRotationCur += headAmount; - } - } - - CVector2D forward(sin(m_fRotationCur), cos(m_fRotationCur)); - - m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * cos(m_fRotationCur)) + -sin(m_fRotationCur) * m_vecAnimMoveDelta.y; - m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * sin(m_fRotationCur)); - - if (CTimer::GetTimeStep() >= 0.01f) { - m_moved = m_moved * (1 / CTimer::GetTimeStep()); - } else { - m_moved = m_moved * (1 / 100.0f); - } - - if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) - || FindPlayerPed() != this || !CanStrafeOrMouseControl()) - return; - - float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); - float pedSpeed = m_moved.Magnitude(); - float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); - - if (localWalkAngle < -0.5 * PI) { - localWalkAngle += PI; - } else if (localWalkAngle > 0.5 * PI) { - localWalkAngle -= PI; - } - - // Interestingly this part is responsible for diagonal walking. - if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { - TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; - m_moved = CVector2D(-sin(walkAngle), cos(walkAngle)) * pedSpeed; - } - - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE); - CAnimBlendAssociation* fightAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_FIGHT_IDLE); - - if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { - LimbOrientation newUpperLegs; - newUpperLegs.phi = localWalkAngle; - - if (newUpperLegs.phi < -DEGTORAD(100.0f)) { - newUpperLegs.phi += PI; - } else if (newUpperLegs.phi > DEGTORAD(100.0f)) { - newUpperLegs.phi -= PI; - } - - if (newUpperLegs.phi > -DEGTORAD(50.0f) && newUpperLegs.phi < DEGTORAD(50.0f)) { - newUpperLegs.theta = 0.0f; - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); - } - } -} - -bool -CPed::CanBeDeleted(void) -{ - if (this->bInVehicle) - return false; - - switch (CharCreatedBy) { - case RANDOM_CHAR: - return true; - case MISSION_CHAR: - return false; - default: - return true; - } -} - -bool -CPed::CanPedDriveOff(void) -{ - if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) - return false; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *ped = m_nearPeds[i]; - if (ped->m_nPedType == m_nPedType && ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && ped->m_carInObjective == m_carInObjective) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; - return false; - } - } - return true; -} - -// I couldn't find where it is used. -bool -CPed::CanPedJumpThis(int32 unused) -{ - CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); - CVector pos = GetPosition(); - // wat? - CVector forwardPos( - forward.x + pos.x, - forward.y + pos.y, - pos.z); - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} - -bool -CPed::CanPedReturnToState(void) -{ - return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && - m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; -} - -bool -CPed::CanSeeEntity(CEntity *entity, float threshold) -{ - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - entity->GetPosition().x, - entity->GetPosition().x, - GetPosition().x, - GetPosition().y); - - if (neededAngle < 0.0f) - neededAngle += 2 * PI; - else if (neededAngle > 2 * PI) - neededAngle -= 2 * PI; - - float ourAngle = m_fRotationCur; - if (ourAngle < 0.0f) - ourAngle += 2 * PI; - else if (ourAngle > 2 * PI) - ourAngle -= 2 * PI; - - float neededTurn = fabs(neededAngle - ourAngle); - - return neededTurn < threshold || 2 * PI - threshold < neededTurn; -} - -bool -CPed::IsTemporaryObjective(eObjective objective) -{ - return objective == OBJECTIVE_LEAVE_VEHICLE || objective == OBJECTIVE_SET_LEADER || - objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; -} - -void -CPed::SetMoveState(eMoveState state) -{ - m_nMoveState = state; -} - -void -CPed::SetObjectiveTimer(int time) -{ - if (time == 0) { - m_objectiveTimer = 0; - } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; - } -} - -void -CPed::ForceStoredObjective(eObjective objective) -{ - if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - m_prevObjective = m_objective; - return; - } - - switch (m_objective) - { - case OBJECTIVE_FLEE_TILL_SAFE: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - return; - default: - m_prevObjective = m_objective; - } -} - -void -CPed::SetStoredObjective(void) -{ - if (m_objective == m_prevObjective) - return; - - switch (m_objective) - { - case OBJECTIVE_FLEE_TILL_SAFE: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_PED_IN_FORMATION: - case OBJECTIVE_LEAVE_VEHICLE: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - return; - default: - m_prevObjective = m_objective; - } -} - -void -CPed::RestorePreviousObjective(void) -{ - if (m_objective == OBJECTIVE_NONE) - return; - - if (m_objective != OBJECTIVE_LEAVE_VEHICLE && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) - m_pedInObjective = nil; - - if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT) { - m_objective = OBJECTIVE_NONE; - if (m_pMyVehicle) - SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); - - } else { - m_objective = m_prevObjective; - m_prevObjective = OBJECTIVE_NONE; - } - m_ped_flagD40 = false; -} - -void -CPed::SetLeader(CEntity *leader) -{ - m_leader = (CPed*)leader; - - if(m_leader) - m_leader->RegisterReference((CEntity **)&m_leader); -} - -void -CPed::SetObjective(eObjective newObj, void *entity) -{ - if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) - return; - - if (m_prevObjective == newObj) { - // Why? - if (m_prevObjective != OBJECTIVE_NONE) - return; - } - - if (entity == this) - return; - - SetObjectiveTimer(0); - if (m_objective == newObj) { - switch (newObj) { - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_PED_IN_FORMATION: - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_FIGHT_CHAR: - if (m_pedInObjective == entity) - return; - - break; - case OBJECTIVE_LEAVE_VEHICLE: - case OBJECTIVE_FLEE_CAR: - return; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_DESTROY_CAR: - case OBJECTIVE_SOLICIT: - case OBJECTIVE_BUY_ICE_CREAM: - if (m_carInObjective == entity) - return; - - break; - case OBJECTIVE_SET_LEADER: - if (m_leader == entity) - return; - - break; - default: - break; - } - } else { - if (newObj == OBJECTIVE_LEAVE_VEHICLE && !bInVehicle) - return; - } - - m_ped_flagD40 = false; - if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { - if (m_objective != newObj) { - if (IsTemporaryObjective(newObj)) - ForceStoredObjective(newObj); - else - SetStoredObjective(); - } - m_objective = newObj; - } else { - m_prevObjective = newObj; - } - - switch (newObj) { - case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT: - - // In this special case, entity parameter isn't CEntity, but int. - SetObjectiveTimer((int)entity); - return; - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_MUG_CHAR: - m_pLastPathNode = nil; - m_ped_flagD20 = false; - m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - m_pLookTarget = (CEntity*)entity; - m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - return; - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FIGHT_CHAR: - m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - return; - case OBJECTIVE_FOLLOW_PED_IN_FORMATION: - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - m_pedFormation = 1; - return; - case OBJECTIVE_LEAVE_VEHICLE: - case OBJECTIVE_FLEE_CAR: - m_carInObjective = (CVehicle*)entity; - m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); - if (!m_carInObjective->bIsBus || m_leaveCarTimer) - return; - break; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_RUN); - - if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { - RestorePreviousObjective(); - return; - } - // fall through - case OBJECTIVE_DESTROY_CAR: - case OBJECTIVE_SOLICIT: - case OBJECTIVE_BUY_ICE_CREAM: - m_carInObjective = (CVehicle*)entity; - m_carInObjective->RegisterReference((CEntity**)&m_carInObjective); - m_pSeekTarget = m_carInObjective; - m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); - m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); - if (newObj == OBJECTIVE_SOLICIT) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; - } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && - (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) { - SetObjectiveTimer(14000); - } else { - m_objectiveTimer = 0; - } - return; - case OBJECTIVE_SET_LEADER: - SetLeader((CEntity*)entity); - RestorePreviousObjective(); - return; - default: - return; - } - for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) { - if (m_carInObjective->pPassengers[i] == this) { - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; - return; - } - } -} - -void -CPed::SetIdle(void) -{ - if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { - m_nPedState = PED_IDLE; - SetMoveState(PEDMOVE_STILL); - } - if (m_nWaitState == WAITSTATE_FALSE) { - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); - } -} - -void -CPed::SetObjective(eObjective newObj) -{ - if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) - return; - - if (newObj == OBJECTIVE_NONE) { - if ((m_objective == OBJECTIVE_LEAVE_VEHICLE || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) - && IsPedInControl()) { - - m_ped_flagG8 = true; - return; - } - // Unused code from assembly... - /* - else if(m_objective == OBJECTIVE_FLEE_CAR) { - - } else { - - } - */ - m_objective = newObj; - m_prevObjective = OBJECTIVE_NONE; - } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { - SetObjectiveTimer(0); - - if (m_objective == newObj) - return; - - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - m_ped_flagD40 = false; - - switch (newObj) { - case OBJECTIVE_NONE: - m_prevObjective = OBJECTIVE_NONE; - break; - case OBJECTIVE_HAIL_TAXI: - m_nWaitTimer = 0; - SetIdle(); - SetMoveState(PEDMOVE_STILL); - break; - default: - break; - } - } -} - -// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode -// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... -void -CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) -{ - if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) - return; - - if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) - return; - - SetObjectiveTimer(0); - - if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) - return; - - m_ped_flagD40 = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - - if (newObj == OBJECTIVE_FOLLOW_ROUTE) { - SetFollowRoute(routePoint, routeType); - } -} - -void -CPed::ClearChat(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - bIsTalking = false; - ClearLookFlag(); - RestorePreviousState(); -} - -bool -CPed::IsGangMember(void) -{ - return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; -} - -void -CPed::InformMyGangOfAttack(CEntity *attacker) -{ - CPed *attackerPed; - - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) - return; - - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; - - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } - - if (attackerPed->m_nPedType == PEDTYPE_COP) - return; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed && nearPed != this) { - CPed *leader = nearPed->m_leader; - if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) - { - nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); - nearPed->SetObjectiveTimer(30000); - } - } - } -} - -void -CPed::QuitEnteringCar(void) -{ - CAnimBlendAssociation *animAssoc = m_pVehicleAnim; - CVehicle *veh = m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - RestartNonPartialAnims(); - - if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE)) - CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f); - - if (veh) { - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK) - veh->m_veh_flagC10 = false; - - if (veh->m_nNumGettingIn != 0) - veh->m_nNumGettingIn--; - - veh->m_nGettingInFlags = GetVehEnterExitFlag(m_vehEnterType); - } - - bUsesCollision = true; - - if (IsPlayer() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { - if (IsPlayer() && m_storedWeapon != NO_STORED_WEAPON) { - SetCurrentWeapon(m_storedWeapon); - m_storedWeapon = NO_STORED_WEAPON; - } - } else { - CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(curWeapon->m_nModelId); - } - if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) { - animAssoc = m_pVehicleAnim; - if (animAssoc) { - animAssoc->blendDelta = -4.0; - animAssoc->flags |= ASSOC_FADEOUTWHENDONE; - animAssoc = m_pVehicleAnim; - animAssoc->flags &= ~ASSOC_RUNNING; - } - } else - SetIdle(); - - m_pVehicleAnim = nil; - - if (veh) { - if (veh->m_autoPilot.m_nCruiseSpeed == 0) - veh->m_autoPilot.m_nCruiseSpeed = 17; - } -} - -void -CPed::ReactToAttack(CEntity *attacker) -{ - if (IsPlayer() && attacker->IsPed()) { - InformMyGangOfAttack(attacker); - SetLookFlag(attacker, 1); - SetLookTimer(700); - return; - } - - if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) { - CPed *ourLeader = m_leader; - if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader) - && attacker->IsPed()) { - - CPed *attackerPed = (CPed*)attacker; - if (bNotAllowedToDuck) { - if (!attackerPed->GetWeapon()->IsTypeMelee()) { - field_4E8 = CTimer::GetTimeInMilliseconds(); - return; - } - } else if (bCrouchWhenShooting || m_ped_flagE1) { - SetDuck(CGeneral::GetRandomNumberInRange(1000,3000)); - return; - } - - if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) { - if (m_pedStats != attackerPed->m_pedStats) { - if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { - RegisterThreatWithGangPeds(attackerPed); - } - if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker); - SetMoveState(PEDMOVE_RUN); - } else { - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker); - SetObjectiveTimer(20000); - } - } - } else { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed); - SetMoveState(PEDMOVE_RUN); - if (attackerPed->GetWeapon()->IsTypeMelee()) - Say(SOUND_PED_FLEE_RUN); - } - } - } -} - -bool -CPed::TurnBody(void) -{ - float lookDir; - bool doneSmoothly = true; - - if (m_pLookTarget) { - CVector &lookPos = m_pLookTarget->GetPosition(); - - lookDir = CGeneral::GetRadianAngleBetweenPoints( - lookPos.x, - lookPos.y, - GetPosition().x, - GetPosition().y); - } else - lookDir = m_fLookDirection; - - float limitedLookDir = CGeneral::LimitRadianAngle(lookDir); - float currentRot = m_fRotationCur; - - if (currentRot - PI > limitedLookDir) - limitedLookDir += 2 * PI; - else if (PI + currentRot < limitedLookDir) - limitedLookDir -= 2 * PI; - - float neededTurn = currentRot - limitedLookDir; - m_fRotationDest = limitedLookDir; - - if (fabs(neededTurn) > 0.05f) { - doneSmoothly = false; - currentRot -= neededTurn * 0.2f; - } - - m_fRotationCur = currentRot; - m_fLookDirection = limitedLookDir; - return doneSmoothly; -} - -void -CPed::Chat(void) -{ - if (bIsLooking && TurnBody()) - ClearLookFlag(); - - if (!m_pLookTarget || !m_pLookTarget->IsPed()) { - ClearChat(); - return; - } - - CPed *partner = (CPed*) m_pLookTarget; - - if (partner->m_nPedState != PED_CHAT) { - ClearChat(); - if (partner->m_pedInObjective) { - if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || - partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) - ReactToAttack(partner->m_pedInObjective); - } - return; - } - if (bIsTalking) { - if (CGeneral::GetRandomNumber() < 512) { - CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); - if (chatAssoc) { - chatAssoc->blendDelta = -4.0f; - chatAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } - bIsTalking = false; - } else - Say(SOUND_PED_CHAT); - - } else if (!RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject, ASSOC_FLAG100)) { - - if (CGeneral::GetRandomNumber() < 20) { - CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); - } - if (!bIsTalking) { - CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); - float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); - chatAssoc->SetCurrentTime(chatTime); - - bIsTalking = true; - Say(SOUND_PED_CHAT); - } - } - if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { - ClearChat(); - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - } -} - -WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); } -WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } -WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); } -WRAPPER void CPed::FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D3950); } -WRAPPER void CPed::FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6520); } -WRAPPER void CPed::FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7490); } -WRAPPER void CPed::FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A80); } -WRAPPER void CPed::PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEC80); } -WRAPPER void CPed::PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE500); } -WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEAF0); } -WRAPPER void CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF1B0); } -WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF220); } -WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } -WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); } -WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); } -WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } -WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } -WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); } -WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); } -WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); } -WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } -WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } -WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } - -STARTPATCHES - InjectHook(0x4C41C0, &CPed::ctor, PATCH_JUMP); - InjectHook(0x4C50D0, &CPed::dtor, PATCH_JUMP); - InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); - InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); - InjectHook(0x4EB470, &CPed::ApplyHeadShot, PATCH_JUMP); - InjectHook(0x4EAEE0, &CPed::RemoveBodyPart, PATCH_JUMP); - InjectHook(0x4C6460, (void (CPed::*)(CEntity*, bool)) &CPed::SetLookFlag, PATCH_JUMP); - InjectHook(0x4C63E0, (void (CPed::*)(float, bool)) &CPed::SetLookFlag, PATCH_JUMP); - InjectHook(0x4D12E0, &CPed::SetLookTimer, PATCH_JUMP); - InjectHook(0x4C5700, &CPed::OurPedCanSeeThisOne, PATCH_JUMP); - InjectHook(0x4D2BB0, &CPed::Avoid, PATCH_JUMP); - InjectHook(0x4C6A50, &CPed::ClearAimFlag, PATCH_JUMP); - InjectHook(0x4C64F0, &CPed::ClearLookFlag, PATCH_JUMP); - InjectHook(0x4EB670, &CPed::IsPedHeadAbovePos, PATCH_JUMP); - InjectHook(0x4E68A0, &CPed::FinishedAttackCB, PATCH_JUMP); - InjectHook(0x4E5BD0, &CheckForPedsOnGroundToAttack, PATCH_JUMP); - InjectHook(0x4E6BA0, &CPed::Attack, PATCH_JUMP); - InjectHook(0x4CF980, &CPed::RemoveWeaponModel, PATCH_JUMP); - InjectHook(0x4CFA60, &CPed::SetCurrentWeapon, PATCH_JUMP); - InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP); - InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP); - InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP); - InjectHook(0x4E07D0, &CPed::BeingDraggedFromCar, PATCH_JUMP); - InjectHook(0x4CF000, &CPed::PedSetDraggedOutCarCB, PATCH_JUMP); - InjectHook(0x4C5D80, &CPed::RestartNonPartialAnims, PATCH_JUMP); - InjectHook(0x4E4730, &CPed::GetLocalPositionToOpenCarDoor, PATCH_JUMP); - InjectHook(0x4E4660, (void (*)(CVector*, CVehicle*, uint32, float)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); - InjectHook(0x4E1A30, (void (*)(CVector*, CVehicle*, uint32)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); - InjectHook(0x4DF940, &CPed::LineUpPedWithCar, PATCH_JUMP); - InjectHook(0x4CC6C0, &CPed::PlayFootSteps, PATCH_JUMP); - InjectHook(0x4C5350, &CPed::BuildPedLists, PATCH_JUMP); - InjectHook(0x4CF9B0, &CPed::GiveWeapon, PATCH_JUMP); - InjectHook(0x4C52A0, &CPed::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4D6570, &CPed::FlagToDestroyWhenNextProcessed_, PATCH_JUMP); - InjectHook(0x4A7D30, &CPed::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7DC0, &CPed::RemoveLighting_, PATCH_JUMP); - InjectHook(0x4D3E70, &CPed::Teleport_, PATCH_JUMP); - InjectHook(0x4C7EA0, &CPed::CalculateNewOrientation, PATCH_JUMP); - InjectHook(0x4C78F0, &CPed::WorkOutHeadingForMovingFirstPerson, PATCH_JUMP); - InjectHook(0x4C73F0, &CPed::CalculateNewVelocity, PATCH_JUMP); - InjectHook(0x4D72F0, &CPed::CanPedJumpThis, PATCH_JUMP); - InjectHook(0x4DD820, &CPed::CanSeeEntity, PATCH_JUMP); - InjectHook(0x4D9460, &CPed::RestorePreviousObjective, PATCH_JUMP); - InjectHook(0x4D82C0, (void (CPed::*)(eObjective)) &CPed::SetObjective, PATCH_JUMP); - InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP); - InjectHook(0x4D89A0, (void (CPed::*)(eObjective, int16, int16)) &CPed::SetObjective, PATCH_JUMP); - InjectHook(0x4DDEC0, &CPed::ReactToAttack, PATCH_JUMP); - InjectHook(0x4D0600, &CPed::SetIdle, PATCH_JUMP); - InjectHook(0x4E0E00, &CPed::QuitEnteringCar, PATCH_JUMP); - InjectHook(0x4E4AD0, &CPed::InformMyGangOfAttack, PATCH_JUMP); - InjectHook(0x4D3C80, &CPed::ClearChat, PATCH_JUMP); - InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP); - InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/Ped.h b/src/entities/Ped.h deleted file mode 100644 index 95731e15..00000000 --- a/src/entities/Ped.h +++ /dev/null @@ -1,577 +0,0 @@ -#pragma once - -#include "Physical.h" -#include "Weapon.h" -#include "PedStats.h" -#include "PedType.h" -#include "PedIK.h" -#include "AnimManager.h" -#include "AnimBlendClumpData.h" -#include "AnimBlendAssociation.h" -#include "WeaponInfo.h" -#include "Fire.h" - -struct CPathNode; - -enum eWaitState : uint32 { - WAITSTATE_FALSE, - WAITSTATE_TRAFFIC_LIGHTS, - WAITSTATE_CROSS_ROAD, - WAITSTATE_CROSS_ROAD_LOOK, - WAITSTATE_LOOK_PED, - WAITSTATE_LOOK_SHOP, - WAITSTATE_LOOK_ACCIDENT, - WAITSTATE_FACEOFF_GANG, - WAITSTATE_DOUBLEBACK, - WAITSTATE_HITWALL, - WAITSTATE_TURN180, - WAITSTATE_SURPRISE, - WAITSTATE_STUCK, - WAITSTATE_LOOK_ABOUT, - WAITSTATE_PLAYANIM_DUCK, - WAITSTATE_PLAYANIM_COWER, - WAITSTATE_PLAYANIM_TAXI, - WAITSTATE_PLAYANIM_HANDSUP, - WAITSTATE_PLAYANIM_HANDSCOWER, - WAITSTATE_PLAYANIM_CHAT, - WAITSTATE_FINISH_FLEE -}; - -enum eObjective : uint32 { - OBJECTIVE_NONE, - OBJECTIVE_IDLE, - OBJECTIVE_FLEE_TILL_SAFE, - OBJECTIVE_GUARD_SPOT, - OBJECTIVE_GUARD_AREA, - OBJECTIVE_WAIT_IN_CAR, - OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT, - OBJECTIVE_KILL_CHAR_ON_FOOT, - OBJECTIVE_KILL_CHAR_ANY_MEANS, - OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, - OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, - OBJECTIVE_GOTO_CHAR_ON_FOOT, - OBJECTIVE_FOLLOW_PED_IN_FORMATION, - OBJECTIVE_LEAVE_VEHICLE, - OBJECTIVE_ENTER_CAR_AS_PASSENGER, - OBJECTIVE_ENTER_CAR_AS_DRIVER, - OBJECTIVE_FOLLOW_CAR_IN_CAR, - OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE, - OBJECTIVE_DESTROY_OBJ, - OBJECTIVE_DESTROY_CAR, - OBJECTIVE_GOTO_AREA_ANY_MEANS, - OBJECTIVE_GOTO_AREA_ON_FOOT, - OBJECTIVE_RUN_TO_AREA, - OBJECTIVE_23, - OBJECTIVE_24, - OBJECTIVE_FIGHT_CHAR, - OBJECTIVE_SET_LEADER, - OBJECTIVE_FOLLOW_ROUTE, - OBJECTIVE_SOLICIT, - OBJECTIVE_HAIL_TAXI, - OBJECTIVE_CATCH_TRAIN, - OBJECTIVE_BUY_ICE_CREAM, - OBJECTIVE_STEAL_ANY_CAR, - OBJECTIVE_MUG_CHAR, - OBJECTIVE_FLEE_CAR, - OBJECTIVE_35 -}; - -enum eVehEnter : uint16 { - VEHICLE_ENTER_FRONT_RIGHT = 11, - VEHICLE_ENTER_REAR_RIGHT = 12, - VEHICLE_ENTER_FRONT_LEFT = 15, - VEHICLE_ENTER_REAR_LEFT = 16, -}; - -enum { - RANDOM_CHAR = 1, - MISSION_CHAR, -}; - -enum PedLineUpPhase { - LINE_UP_TO_CAR_START, - LINE_UP_TO_CAR_END, - LINE_UP_TO_CAR_2 -}; - -enum PedOnGroundState { - NO_PED, - PED_BELOW_PLAYER, - PED_ON_THE_FLOOR, - PED_DEAD_ON_THE_FLOOR -}; - -enum PedState -{ - PED_NONE, - PED_IDLE, - PED_LOOK_ENTITY, - PED_LOOK_HEADING, - PED_WANDER_RANGE, - PED_WANDER_PATH, - PED_SEEK_POS, - PED_SEEK_ENTITY, - PED_FLEE_POS, - PED_FLEE_ENTITY, - PED_PURSUE, - PED_FOLLOW_PATH, - PED_SNIPER_MODE, - PED_ROCKET_ODE, - PED_DUMMY, - PED_PAUSE, - PED_ATTACK, - PED_FIGHT, - PED_FACE_PHONE, - PED_MAKE_CALL, - PED_CHAT, - PED_MUG, - PED_AIM_GUN, - PED_AI_CONTROL, - PED_SEEK_CAR, - PED_SEEK_IN_BOAT, - PED_FOLLOW_ROUTE, - PED_CPR, - PED_SOLICIT, - PED_BUY_ICECREAM, - PED_INVESTIGATE, - PED_STEP_AWAY, - PED_ON_FIRE, - - PED_UNKNOWN, // HANG_OUT in Fire_Head's idb - - PED_STATES_NO_AI, - PED_JUMP, - PED_FALL, - PED_GETUP, - PED_STAGGER, - PED_DIVE_AWAY, - - PED_STATES_NO_ST, - PED_ENTER_TRAIN, - PED_EXIT_TRAIN, - PED_ARREST_PLAYER, - PED_DRIVING, - PED_PASSENGER, - PED_TAXI_PASSENGER, - PED_OPEN_DOOR, - PED_DIE, - PED_DEAD, - PED_CARJACK, - PED_DRAG_FROM_CAR, - PED_ENTER_CAR, - PED_STEAL_CAR, - PED_EXIT_CAR, - PED_HANDS_UP, - PED_ARRESTED, -}; - -enum eMoveState { - PEDMOVE_NONE, - PEDMOVE_STILL, - PEDMOVE_WALK, - PEDMOVE_RUN, - PEDMOVE_SPRINT, -}; - -class CVehicle; - -class CPed : public CPhysical -{ -public: - // 0x128 - CStoredCollPoly m_collPoly; - float m_fCollisionSpeed; - - // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R* - uint8 bIsStanding : 1; - uint8 m_ped_flagA2 : 1; - uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime) - uint8 bIsPointingGunAt : 1; - uint8 bIsLooking : 1; - uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA - uint8 bIsRestoringLook : 1; - uint8 bIsAimingGun : 1; - - uint8 bIsRestoringGun : 1; - uint8 bCanPointGunAtTarget : 1; - uint8 bIsTalking : 1; - uint8 bIsInTheAir : 1; - uint8 bIsLanding : 1; - uint8 m_ped_flagB20 : 1; - uint8 m_ped_flagB40 : 1; - uint8 m_ped_flagB80 : 1; - - uint8 m_ped_flagC1 : 1; - uint8 bRespondsToThreats : 1; - uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar? - uint8 m_ped_flagC8 : 1; - uint8 m_ped_flagC10 : 1; - uint8 m_ped_flagC20 : 1; // just left some body part? - uint8 m_ped_flagC40 : 1; - uint8 m_ped_flagC80 : 1; - - uint8 m_ped_flagD1 : 1; - uint8 m_ped_flagD2 : 1; - uint8 m_ped_flagD4 : 1; - uint8 m_ped_flagD8 : 1; - uint8 m_ped_flagD10 : 1; - uint8 m_ped_flagD20 : 1; - uint8 m_ped_flagD40 : 1; // reset when objective changes - uint8 m_ped_flagD80 : 1; - - uint8 m_ped_flagE1 : 1; - uint8 m_ped_flagE2 : 1; - uint8 bNotAllowedToDuck : 1; - uint8 bCrouchWhenShooting : 1; - uint8 bIsDucking : 1; // set if you don't want ped to attack - uint8 m_ped_flagE20 : 1; - uint8 bDoBloodyFootprints : 1; - uint8 m_ped_flagE80 : 1; - - uint8 m_ped_flagF1 : 1; - uint8 m_ped_flagF2 : 1; - uint8 m_ped_flagF4 : 1; - uint8 m_ped_flagF8 : 1; - uint8 m_ped_flagF10 : 1; - uint8 m_ped_flagF20 : 1; - uint8 m_ped_flagF40 : 1; - uint8 m_ped_flagF80 : 1; - - uint8 m_ped_flagG1 : 1; - uint8 m_ped_flagG2 : 1; - uint8 m_ped_flagG4 : 1; - uint8 m_ped_flagG8 : 1; - uint8 m_ped_flagG10 : 1; - uint8 m_ped_flagG20 : 1; - uint8 m_ped_flagG40 : 1; - uint8 m_ped_flagG80 : 1; - - uint8 m_ped_flagH1 : 1; - uint8 m_ped_flagH2 : 1; - uint8 m_ped_flagH4 : 1; - uint8 m_ped_flagH8 : 1; - uint8 m_ped_flagH10 : 1; - uint8 m_ped_flagH20 : 1; - uint8 m_ped_flagH40 : 1; - uint8 m_ped_flagH80 : 1; - - uint8 m_ped_flagI1 : 1; - uint8 m_ped_flagI2 : 1; - uint8 m_ped_flagI4 : 1; - uint8 bRecordedForReplay : 1; - uint8 m_ped_flagI10 : 1; - uint8 m_ped_flagI20 : 1; - uint8 m_ped_flagI40 : 1; - uint8 m_ped_flagI80 : 1; - - uint8 stuff10[3]; - uint8 CharCreatedBy; - uint8 field_161; - uint8 pad_162[2]; - eObjective m_objective; - eObjective m_prevObjective; - CPed *m_pedInObjective; - CVehicle *m_carInObjective; - uint32 field_174; - uint32 field_178; - uint32 field_17C; - CPed *m_leader; - uint32 m_pedFormation; - uint32 m_fearFlags; - CEntity *m_threatEntity; - CVector2D m_eventOrThread; - uint32 m_eventType; - CEntity* m_pEventEntity; - float m_fAngleToEvent; - AnimBlendFrameData *m_pFrames[PED_NODE_MAX]; - AssocGroupId m_animGroup; - CAnimBlendAssociation *m_pVehicleAnim; - CVector2D m_vecAnimMoveDelta; - CVector m_vecOffsetSeek; - CPedIK m_pedIK; - float m_actionX; - float m_actionY; - uint32 m_nPedStateTimer; - PedState m_nPedState; - PedState m_nLastPedState; - eMoveState m_nMoveState; - int32 m_nStoredActionState; - int32 m_nPrevActionState; - eWaitState m_nWaitState; - uint32 m_nWaitTimer; - void *m_pPathNodesStates[8]; - CVector2D m_stPathNodeStates[10]; - uint16 m_nPathNodes; - uint8 m_nCurPathNode; - int8 m_nPathState; -private: - int8 _pad2B5[3]; -public: - CPathNode *m_pNextPathNode; - CPathNode *m_pLastPathNode; - float m_fHealth; - float m_fArmour; - int16 m_routeLastPoint; - uint16 m_routePoints; - int16 m_routePos; - int16 m_routeType; - int16 m_routeCurDir; - uint16 field_2D2; - CVector2D m_moved; - float m_fRotationCur; - float m_fRotationDest; - float m_headingRate; - eVehEnter m_vehEnterType; - uint16 m_walkAroundType; - CEntity *m_pCurrentPhysSurface; - CVector m_vecOffsetFromPhysSurface; - CEntity *m_pCurSurface; - CVector m_vecSeekVehicle; - CEntity *m_pSeekTarget; - CVehicle *m_pMyVehicle; - bool bInVehicle; - uint8 pad_315[3]; - uint32 field_318; - uint8 field_31C; - uint8 field_31D; - int16 m_phoneId; - uint32 m_lookingForPhone; - uint32 m_phoneTalkTimer; - void *m_lastAccident; - int32 m_nPedType; - CPedStats *m_pedStats; - float m_fleeFromPosX; - float m_fleeFromPosY; - CEntity *m_fleeFrom; - uint32 m_fleeTimer; - uint32 field_344; - uint32 m_lastThreatTimer; - CEntity *m_pCollidingEntity; - uint8 m_stateUnused; - uint8 pad_351[3]; - uint32 m_timerUnused; - CEntity *m_targetUnused; - CWeapon m_weapons[NUM_PED_WEAPONTYPES]; - eWeaponType m_storedWeapon; - uint8 m_currentWeapon; // eWeaponType - uint8 m_maxWeaponTypeAllowed; // eWeaponType - uint8 m_wepSkills; - uint8 m_wepAccuracy; - CEntity *m_pPointGunAt; - CVector m_vecHitLastPos; - uint32 m_lastHitState; - uint8 m_fightFlags1; - uint8 m_fightFlags2; - uint8 pad_4B2[2]; - CFire* m_pFire; - CEntity *m_pLookTarget; - float m_fLookDirection; - int32 m_wepModelID; - uint32 m_leaveCarTimer; - uint32 m_getUpTimer; - uint32 m_lookTimer; - uint32 m_standardTimer; - uint32 m_attackTimer; - uint32 m_lastHitTime; - uint32 m_hitRecoverTimer; - uint32 m_objectiveTimer; - uint32 m_duckTimer; - uint32 field_4E8; - int32 m_bloodyFootprintCount; - uint8 stuff9[2]; - int8 m_bodyPartBleeding; // PedNode - uint8 m_field_4F3; - CPed *m_nearPeds[10]; - uint16 m_numNearPeds; - int8 m_lastWepDam; - uint8 pad_51F; - uint8 field_520; - uint8 pad_521[3]; - uint32 m_talkTimer; - uint16 m_talkTypeLast; - uint16 m_talkType; - CVector m_vecSeekPosEx; - float m_seekExAngle; - - static void *operator new(size_t); - static void *operator new(size_t, int); - static void operator delete(void*, size_t); - static void operator delete(void*, int); - - CPed(uint32 pedType); - virtual ~CPed(void); - - virtual void SetModelIndex(uint32 mi); - virtual void ProcessControl(void); - virtual void Teleport(CVector); - virtual void PreRender(void); - virtual void Render(void); - virtual bool SetupLighting(void); - virtual void RemoveLighting(bool); - virtual void FlagToDestroyWhenNextProcessed(void); - virtual int32 ProcessEntityCollision(CEntity*, CColPoint*); - virtual void SetMoveAnim(void); - - CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); } - void dtor(void) { this->CPed::~CPed(); } - - void AddWeaponModel(int id); - void AimGun(void); - void KillPedWithCar(CVehicle *veh, float impulse); - void Say(uint16 audio); - void SetLookFlag(CEntity *target, bool unknown); - void SetLookFlag(float direction, bool unknown); - void SetLookTimer(int time); - void SetDie(AnimationId anim, float arg1, float arg2); - void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer); - void RemoveBodyPart(PedNode nodeId, int8 unknown); - void SpawnFlyingComponent(int, int8 unknown); - bool OurPedCanSeeThisOne(CEntity *target); - void Avoid(void); - void Attack(void); - void ClearAimFlag(void); - void ClearLookFlag(void); - void RestorePreviousState(void); - void ClearAttack(void); - bool IsPedHeadAbovePos(float zOffset); - void RemoveWeaponModel(int modelId); - void SetCurrentWeapon(uint32 weaponType); - void Duck(void); - void ClearDuck(void); - void ClearPointGunAt(void); - void BeingDraggedFromCar(void); - void RestartNonPartialAnims(void); - void LineUpPedWithCar(PedLineUpPhase phase); - void SetPedPositionInCar(void); - void PlayFootSteps(void); - void QuitEnteringCar(void); - void BuildPedLists(void); - uint32 GiveWeapon(eWeaponType weaponType, uint32 ammo); - void CalculateNewOrientation(void); - float WorkOutHeadingForMovingFirstPerson(float); - void CalculateNewVelocity(void); - bool CanPedJumpThis(int32); - bool CanSeeEntity(CEntity*, float); - void RestorePreviousObjective(void); - void SetIdle(void); - void SetObjective(eObjective, void*); - void SetObjective(eObjective); - void SetObjective(eObjective, int16, int16); - void ClearChat(void); - void InformMyGangOfAttack(CEntity*); - void SetFollowRoute(int16, int16); - void ReactToAttack(CEntity*); - void SetDuck(uint32); - void RegisterThreatWithGangPeds(CEntity*); - bool TurnBody(void); - void Chat(void); - - // Static methods - static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); - static void GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult); - static void GetPositionToOpenCarDoor(CVector* output, CVehicle* veh, uint32 enterType); - - // Callbacks - static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data); - static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data); - static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg); - static void PedStaggerCB(CAnimBlendAssociation *assoc, void *arg); - static void PedEvadeCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg); - static void SetInCarCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetDraggedOutCarCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishedAttackCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg); - static void PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg); - static void FinishJumpCB(CAnimBlendAssociation *assoc, void *arg); - static void PedLandCB(CAnimBlendAssociation *assoc, void *arg); - static void RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); - static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); - - // functions that I see unnecessary to hook - bool IsPlayer(void); - bool UseGroundColModel(void); - bool CanSetPedState(void); - bool IsPedInControl(void); - bool CanPedDriveOff(void); - bool CanBeDeleted(void); - bool CanStrafeOrMouseControl(void); - bool CanPedReturnToState(void); - void SetMoveState(eMoveState); - bool IsTemporaryObjective(eObjective objective); - void SetObjectiveTimer(int); - bool SelectGunIfArmed(void); - bool IsPointerValid(void); - void SortPeds(CPed**, int, int); - void ForceStoredObjective(eObjective); - void SetStoredObjective(void); - void SetLeader(CEntity* leader); - void SetPedStats(ePedStats); - bool IsGangMember(void); - - bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } - CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } - CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } - RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; } - static uint8 GetVehEnterExitFlag(eVehEnter vehEnter) { - switch (vehEnter) { - case VEHICLE_ENTER_FRONT_RIGHT: - return 4; - case VEHICLE_ENTER_REAR_RIGHT: - return 8; - case VEHICLE_ENTER_FRONT_LEFT: - return 1; - case VEHICLE_ENTER_REAR_LEFT: - return 2; - default: - return 0; - } - } - PedState GetPedState(void) { return m_nPedState; } - void SetPedState(PedState state) { m_nPedState = state; } - - // to make patching virtual functions possible - void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); } - void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); } - bool SetupLighting_(void) { return CPed::SetupLighting(); } - void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); } - void Teleport_(CVector pos) { CPed::Teleport(pos); } - - // set by 0482:set_threat_reaction_range_multiplier opcode - static uint16 &distanceMultToCountPedNear; - - static CVector &offsetToOpenRegularCarDoor; - static CVector &offsetToOpenLowCarDoor; - static CVector &offsetToOpenVanDoor; - static bool &bNastyLimbsCheat; - static bool &bPedCheat2; - static bool &bPedCheat3; -}; - -void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); - -static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error"); -static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error"); -static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error"); -static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error"); -static_assert(offsetof(CPed, m_pCollidingEntity) == 0x34C, "CPed: error"); -static_assert(offsetof(CPed, m_weapons) == 0x35C, "CPed: error"); -static_assert(offsetof(CPed, m_currentWeapon) == 0x498, "CPed: error"); -static_assert(offsetof(CPed, m_lookTimer) == 0x4CC, "CPed: error"); -static_assert(offsetof(CPed, m_bodyPartBleeding) == 0x4F2, "CPed: error"); -static_assert(offsetof(CPed, m_pedInObjective) == 0x16C, "CPed: error"); -static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error"); -static_assert(sizeof(CPed) == 0x53C, "CPed: error"); diff --git a/src/entities/PedIK.cpp b/src/entities/PedIK.cpp deleted file mode 100644 index b9baf49c..00000000 --- a/src/entities/PedIK.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PedIK.h" -#include "Ped.h" - -WRAPPER bool CPedIK::PointGunInDirection(float phi, float theta) { EAXJMP(0x4ED9B0); } -WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); } -WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); } -WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); } - -CPedIK::CPedIK(CPed *ped) -{ - m_ped = ped; - m_flags = 0; - m_headOrient.phi = 0.0f; - m_headOrient.theta = 0.0f; - m_torsoOrient.phi = 0.0f; - m_torsoOrient.theta = 0.0f; - m_upperArmOrient.phi = 0.0f; - m_upperArmOrient.theta = 0.0f; - m_lowerArmOrient.phi = 0.0f; - m_lowerArmOrient.theta = 0.0f; -} - -void -CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool changeRoll) -{ - RwFrame *f = animBlend->frame; - RwMatrix *mat = CPedIK::GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate()); - - RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z }; - RwV3d rightVector; - RwV3d pos = RwFrameGetMatrix(f)->pos; - - // rotation == 0 -> looking in y direction - // left? vector - float c = cos(m_ped->m_fRotationCur); - float s = sin(m_ped->m_fRotationCur); - rightVector.x = -(c*mat->right.x + s*mat->right.y); - rightVector.y = -(c*mat->up.x + s*mat->up.y); - rightVector.z = -(c*mat->at.x + s*mat->at.y); - - if(changeRoll){ - // Used when aiming only involves over the legs.(canAimWithArm) - // Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs. - // Not noticeable in normal conditions... - - RwV3d forwardVector; - CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up); - inversedForward.Normalise(); - float dotProduct = DotProduct(mat->at, inversedForward); - if(dotProduct > 1.0f) dotProduct = 1.0f; - if(dotProduct < -1.0f) dotProduct = -1.0f; - float alpha = acos(dotProduct); - - if(mat->at.z < 0.0f) - alpha = -alpha; - - forwardVector.x = s * mat->right.x - c * mat->right.y; - forwardVector.y = s * mat->up.x - c * mat->up.y; - forwardVector.z = s * mat->at.x - c * mat->at.y; - - float curYaw, curPitch; - CPedIK::ExtractYawAndPitchWorld(mat, &curYaw, &curPitch); - RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); - RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT); - RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT); - }else{ - // pitch - RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); - // yaw - RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT); - } - RwFrameGetMatrix(f)->pos = pos; - RwMatrixDestroy(mat); -} - -void -CPedIK::GetComponentPosition(RwV3d *pos, PedNode node) -{ - RwFrame *f; - RwMatrix *mat; - - f = m_ped->GetNodeFrame(node); - mat = RwFrameGetMatrix(f); - *pos = mat->pos; - - for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) - RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(f)); -} - -RwMatrix* -CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) -{ - RwFrame *i; - - *destination = *RwFrameGetMatrix(source); - - for (i = RwFrameGetParent(source); i; i = RwFrameGetParent(i)) - RwMatrixTransform(destination, RwFrameGetMatrix(i), rwCOMBINEPOSTCONCAT); - - return destination; -} - -STARTPATCHES - InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP); - InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP); - InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/PedIK.h b/src/entities/PedIK.h deleted file mode 100644 index e17d52eb..00000000 --- a/src/entities/PedIK.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "common.h" -#include "PedModelInfo.h" -#include "AnimBlendClumpData.h" - -struct LimbOrientation -{ - float phi; - float theta; -}; - -class CPed; - -class CPedIK -{ -public: - // TODO - enum { - FLAG_1 = 1, - FLAG_2 = 2, // related to looking somewhere - FLAG_4 = 4, // aims with arm - }; - - CPed *m_ped; - LimbOrientation m_headOrient; - LimbOrientation m_torsoOrient; - LimbOrientation m_upperArmOrient; - LimbOrientation m_lowerArmOrient; - int32 m_flags; - - CPedIK(CPed *ped); - bool PointGunInDirection(float phi, float theta); - bool PointGunAtPosition(CVector *position); - void GetComponentPosition(RwV3d *pos, PedNode node); - static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination); - void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); - void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); - void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); -}; -static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 600e5dca..d6a82658 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -1897,10 +1897,10 @@ CPhysical::ProcessCollision(void) CVehicle *veh = (CVehicle*)this; if(veh->m_vehType == VEHICLE_TYPE_CAR){ CAutomobile *car = (CAutomobile*)this; - car->m_aWheelDist[0] = 1.0f; - car->m_aWheelDist[1] = 1.0f; - car->m_aWheelDist[2] = 1.0f; - car->m_aWheelDist[3] = 1.0f; + car->m_aSuspensionSpringRatio[0] = 1.0f; + car->m_aSuspensionSpringRatio[1] = 1.0f; + car->m_aSuspensionSpringRatio[2] = 1.0f; + car->m_aSuspensionSpringRatio[3] = 1.0f; }else if(veh->m_vehType == VEHICLE_TYPE_BIKE){ assert(0 && "TODO - but unused"); } diff --git a/src/entities/Plane.cpp b/src/entities/Plane.cpp deleted file mode 100644 index 6e30bced..00000000 --- a/src/entities/Plane.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Plane.h" - -CPlane::CPlane(int mi, uint8 owner) -{ - ctor(mi, owner); -} - -WRAPPER CPlane* CPlane::ctor(int, uint8) { EAXJMP(0x54B170); } - -CPlane::~CPlane() -{ - DeleteRwObject(); -} - -STARTPATCHES -InjectHook(0x54B270, &CPlane::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/Plane.h b/src/entities/Plane.h deleted file mode 100644 index e26008f6..00000000 --- a/src/entities/Plane.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "common.h" -#include "Vehicle.h" - -class CPlane : public CVehicle -{ -public: - // 0x288 - uint8 stuff[20]; - - CPlane(int, uint8); - ~CPlane(void); - CPlane* ctor(int, uint8); - void dtor(void) { this->CPlane::~CPlane(); } - void FlagToDestroyWhenNextProcessed() { bRemoveFromWorld = true; } -}; -static_assert(sizeof(CPlane) == 0x29C, "CPlane: error"); diff --git a/src/entities/PlayerInfo.cpp b/src/entities/PlayerInfo.cpp deleted file mode 100644 index 59efe2ae..00000000 --- a/src/entities/PlayerInfo.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PlayerInfo.h" - -WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); } \ No newline at end of file diff --git a/src/entities/PlayerInfo.h b/src/entities/PlayerInfo.h deleted file mode 100644 index e2b42fe7..00000000 --- a/src/entities/PlayerInfo.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "Collision.h" - -enum eWastedBustedState -{ - WBSTATE_PLAYING, - WBSTATE_WASTED, - WBSTATE_BUSTED, - WBSTATE_FAILED_CRITICAL_MISSION, -}; - -class CVehicle; -class CPlayerPed; -class CCivilianPed; - -class CPlayerInfo -{ -public: - CPlayerPed *m_pPed; - CVehicle *m_pRemoteVehicle; - CColModel m_ColModel; - CVehicle *m_pVehicleEx; - char m_aPlayerName[70]; - int32 m_nMoney; - int32 m_nVisibleMoney; - int32 m_nCollectedPackages; - int32 m_nTotalPackages; - int32 field_188; - int32 m_nSwitchTaxiTime; - bool m_bSwitchTaxi; - int8 field_197; - int8 field_198; - int8 field_199; - int32 m_nNextSexFrequencyUpdateTime; - int32 m_nNextSexMoneyUpdateTime; - int32 m_nSexFrequency; - CCivilianPed *m_pHooker; - int8 m_WBState; // eWastedBustedState - int8 field_217; - int8 field_218; - int8 field_219; - int32 m_nWBTime; - bool m_bInRemoteMode; - int8 field_225; - int8 field_226; - int8 field_227; - int32 m_nTimeLostRemoteCar; - int32 m_nTimeLastHealthLoss; - int32 m_nTimeLastArmourLoss; - int32 field_240; - int32 m_nUpsideDownCounter; - int32 field_248; - int16 m_nTrafficMultiplier; - int8 field_254; - int8 field_255; - float m_fRoadDensity; - int32 m_nPreviousTimeRewardedForExplosion; - int32 m_nExplosionsSinceLastReward; - int32 field_268; - int32 field_272; - bool m_bInfiniteSprint; - bool m_bFastReload; - bool m_bGetOutOfJailFree; - bool m_bGetOutOfHospitalFree; - uint8 m_aSkinName[32]; - RwTexture *m_pSkinTexture; - - void MakePlayerSafe(bool); -}; - -static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/entities/PlayerPed.cpp b/src/entities/PlayerPed.cpp deleted file mode 100644 index 2d67d5b2..00000000 --- a/src/entities/PlayerPed.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PlayerPed.h" - -CPlayerPed::~CPlayerPed() -{ - delete m_pWanted; -} - -WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } - -STARTPATCHES - InjectHook(0x4EFB30, &CPlayerPed::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/PlayerPed.h b/src/entities/PlayerPed.h deleted file mode 100644 index 15ad74a6..00000000 --- a/src/entities/PlayerPed.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "Ped.h" -#include "Wanted.h" - -class CPlayerPed : public CPed -{ -public: - CWanted *m_pWanted; - CCopPed *m_pArrestingCop; - float m_fMoveSpeed; - float m_fCurrentStamina; - float m_fMaxStamina; - float m_fStaminaProgress; - bool m_bWeaponSlot; - bool m_bSpeedTimerFlag; - bool m_bShouldEvade; - int8 field_1367; - int32 m_nSpeedTimer; - int32 m_nShotDelay; - float field_1376; - int8 field_1380; // set if can't attack, why? - int8 field_1381; - int8 field_1382; - int8 field_1383; - CEntity *m_pEvadingFrom; - int32 m_nTargettableObjects[4]; - bool m_bAdrenalineActive; - bool m_bHasLockOnTarget; - int8 field_1406; - int8 field_1407; - bool m_bAdrenalineTime; - bool m_bCanBeDamaged; - int8 field_1413; - int8 field_1414; - int8 field_1415; - CVector field_1416[6]; - int32 field_1488[6]; - float m_fWalkAngle; - float m_fFPSMoveHeading; - - ~CPlayerPed(); - - void dtor(void) { this->CPlayerPed::~CPlayerPed(); } - void ReApplyMoveAnims(void); -}; - -static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error"); diff --git a/src/entities/PlayerSkin.cpp b/src/entities/PlayerSkin.cpp deleted file mode 100644 index 1c9ca2c6..00000000 --- a/src/entities/PlayerSkin.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "PlayerSkin.h" - -WRAPPER void CPlayerSkin::BeginFrontEndSkinEdit() { EAXJMP(0x59BC70); } diff --git a/src/entities/PlayerSkin.h b/src/entities/PlayerSkin.h deleted file mode 100644 index 61e09cdf..00000000 --- a/src/entities/PlayerSkin.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -class CPlayerSkin -{ -public: - static void BeginFrontEndSkinEdit(); -}; \ No newline at end of file diff --git a/src/entities/Projectile.cpp b/src/entities/Projectile.cpp deleted file mode 100644 index e21323de..00000000 --- a/src/entities/Projectile.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Projectile.h" - -STARTPATCHES - InjectHook(0x4BFED0, &CProjectile::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/Projectile.h b/src/entities/Projectile.h deleted file mode 100644 index a8e826b6..00000000 --- a/src/entities/Projectile.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#pragma once - -#include "Object.h" - -class CProjectile : public CObject -{ -public: - void dtor(void) { this->CProjectile::~CProjectile(); } -}; diff --git a/src/entities/Train.cpp b/src/entities/Train.cpp deleted file mode 100644 index 62fd53ec..00000000 --- a/src/entities/Train.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "Train.h" - -CTrain::CTrain(int mi, uint8 owner) -{ - ctor(mi, owner); -} - -WRAPPER CTrain* CTrain::ctor(int, uint8) { EAXJMP(0x54E2A0); } - -STARTPATCHES -InjectHook(0x54E450, &CTrain::dtor, PATCH_JUMP); -ENDPATCHES \ No newline at end of file diff --git a/src/entities/Train.h b/src/entities/Train.h deleted file mode 100644 index 84b6faf5..00000000 --- a/src/entities/Train.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "common.h" -#include "patcher.h" -#include "Vehicle.h" - -enum -{ - TRAIN_DOOR_STATE2 = 2 -}; - -class CTrain : public CVehicle -{ -public: - // 0x288 - uint8 stuff1[20]; - uint8 m_trackId; - uint8 stuff2[7]; - int16 m_doorState; - uint8 stuff3[62]; - - CTrain(int, uint8); - CTrain* ctor(int, uint8); - void dtor(void) { this->CTrain::~CTrain(); } -}; -static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error"); diff --git a/src/entities/Vehicle.cpp b/src/entities/Vehicle.cpp deleted file mode 100644 index dccd9195..00000000 --- a/src/entities/Vehicle.cpp +++ /dev/null @@ -1,489 +0,0 @@ -#include "common.h" -#include "main.h" -#include "patcher.h" -#include "Timer.h" -#include "Vehicle.h" -#include "Pools.h" -#include "HandlingMgr.h" -#include "CarCtrl.h" -#include "Population.h" -#include "ModelIndices.h" -#include "World.h" -#include "Lights.h" -#include "PointLights.h" -#include "Renderer.h" -#include "DMAudio.h" -#include "Radar.h" - -bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78; -bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75; -bool &CVehicle::bCheat3 = *(bool *)0x95CD66; -bool &CVehicle::bCheat4 = *(bool *)0x95CD65; -bool &CVehicle::bCheat5 = *(bool *)0x95CD64; -bool &CVehicle::m_bDisableMouseSteering = *(bool *)0x60252C; - -void *CVehicle::operator new(size_t sz) { return CPools::GetVehiclePool()->New(); } -void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehiclePool()->New(handle); } -void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } -void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } - -CVehicle::~CVehicle() -{ - m_nAlarmState = 0; - if (m_audioEntityId >= 0){ - DMAudio.DestroyEntity(m_audioEntityId); - m_audioEntityId = -5; - } - CRadar::ClearBlipForEntity(BLIP_CAR, CPools::GetVehiclePool()->GetIndex(this)); - if (pDriver) - pDriver->FlagToDestroyWhenNextProcessed(); - for (int i = 0; i < m_nNumMaxPassengers; i++){ - if (pPassengers[i]) - pPassengers[i]->FlagToDestroyWhenNextProcessed(); - } - if (m_pCarFire) - m_pCarFire->Extinguish(); - CCarCtrl::UpdateCarCount(this, true); - if (bIsAmbulanceOnDuty){ - CCarCtrl::NumAmbulancesOnDuty--; - bIsAmbulanceOnDuty = false; - } - if (bIsFireTruckOnDuty){ - CCarCtrl::NumFiretrucksOnDuty--; - bIsFireTruckOnDuty = false; - } -} - -void -CVehicle::SetModelIndex(uint32 id) -{ - CEntity::SetModelIndex(id); - m_aExtras[0] = CVehicleModelInfo::ms_compsUsed[0]; - m_aExtras[1] = CVehicleModelInfo::ms_compsUsed[1]; - m_nNumMaxPassengers = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(id); -} - -bool -CVehicle::SetupLighting(void) -{ - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); - - if(bRenderScorched){ - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - }else{ - CVector coors = GetPosition(); - float lighting = CPointLights::GenerateLightsAffectingObject(&coors); - if(!bHasBlip && lighting != 1.0f){ - SetAmbientAndDirectionalColours(lighting); - return true; - } - } - - return false; -} - -void -CVehicle::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} - -float -CVehicle::GetHeightAboveRoad(void) -{ - return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z; -} - - -bool -CVehicle::IsLawEnforcementVehicle(void) -{ - switch(GetModelIndex()){ - case MI_FBICAR: - case MI_POLICE: - case MI_ENFORCER: - case MI_PREDATOR: - case MI_RHINO: - case MI_BARRACKS: - return true; - default: - return false; - } -} - -bool -CVehicle::UsesSiren(uint32 id) -{ - switch(id){ - case MI_FIRETRUCK: - case MI_AMBULAN: - case MI_FBICAR: - case MI_MRWHOOP: - case MI_POLICE: - case MI_ENFORCER: - case MI_PREDATOR: - return true; - default: - return false; - } -} - -bool -CVehicle::IsVehicleNormal(void) -{ - if(pDriver && m_nNumPassengers == 0 && m_status != STATUS_WRECKED){ - switch(GetModelIndex()) - case MI_FIRETRUCK: - case MI_AMBULAN: - case MI_TAXI: - case MI_POLICE: - case MI_ENFORCER: - case MI_BUS: - case MI_RHINO: - case MI_BARRACKS: - case MI_DODO: - case MI_COACH: - case MI_CABBIE: - case MI_RCBANDIT: - case MI_BORGNINE: - return false; - } - return false; -} - -bool -CVehicle::CarHasRoof(void) -{ - if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0) - return true; - if(m_aExtras[0] && m_aExtras[1]) - return false; - return true; -} - -bool -CVehicle::IsUpsideDown(void) -{ - if(GetUp().z > -0.9f) - return false; - return true; -} - -bool -CVehicle::IsOnItsSide(void) -{ - if(GetRight().z < 0.8f && GetRight().z > -0.8f) - return false; - return true; -} - -bool -CVehicle::CanBeDeleted(void) -{ - int i; - - if(m_nNumGettingIn || m_nGettingOutFlags) - return false; - - if(pDriver){ - // This looks like it was inlined - if(pDriver->CharCreatedBy == MISSION_CHAR) - return false; - if(pDriver->GetPedState() != PED_DRIVING && - pDriver->GetPedState() != PED_DEAD) - return false; - } - - for(i = 0; i < 8; i++){ - // Same check as above - if(pPassengers[i]){ - if(pPassengers[i]->CharCreatedBy == MISSION_CHAR) - return false; - if(pPassengers[i]->GetPedState() != PED_DRIVING && - pPassengers[i]->GetPedState() != PED_DEAD) - return false; - } - // and then again... probably because something was inlined - if(pPassengers[i]){ - if(pPassengers[i]->GetPedState() != PED_DRIVING && - pPassengers[i]->GetPedState() != PED_DEAD) - return false; - } - } - - switch(VehicleCreatedBy){ - case RANDOM_VEHICLE: return true; - case MISSION_VEHICLE: return false; - case PARKED_VEHICLE: return true; - case PERMANENT_VEHICLE: return false; - } - return true; -} - -bool -CVehicle::CanPedOpenLocks(CPed *ped) -{ - if(m_nDoorLock == CARLOCK_LOCKED || - m_nDoorLock == CARLOCK_COP_CAR || - m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) - return false; - if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY) - return false; - return true; -} - -bool -CVehicle::CanPedEnterCar(void) -{ - CVector up = GetUp(); - // can't enter when car is on side - if(up.z > 0.1f || up.z < -0.1f){ - // also when car is moving too fast - if(m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f)) - return false; - if(m_vecTurnSpeed.MagnitudeSqr() > sq(0.2f)) - return false; - return true; - } - return false; -} - -bool -CVehicle::CanPedExitCar(void) -{ - CVector up = GetUp(); - if(up.z > 0.1f || up.z < -0.1f){ - // can't exit when car is moving too fast - if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f) - return false; - // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) > 0.01f || - fabs(m_vecTurnSpeed.y) > 0.01f || - fabs(m_vecTurnSpeed.z) > 0.01f) - return false; - return true; - }else{ - // What is this? just > replaced by >= ?? - - // can't exit when car is moving too fast - if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f) - return false; - // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) >= 0.01f || - fabs(m_vecTurnSpeed.y) >= 0.01f || - fabs(m_vecTurnSpeed.z) >= 0.01f) - return false; - return true; - } -} - -void -CVehicle::ChangeLawEnforcerState(uint8 enable) -{ - if (enable) { - if (!bIsLawEnforcer) { - bIsLawEnforcer = true; - CCarCtrl::NumLawEnforcerCars++; - } - } else { - if (bIsLawEnforcer) { - bIsLawEnforcer = false; - CCarCtrl::NumLawEnforcerCars--; - } - } -} - -CPed* -CVehicle::SetUpDriver(void) -{ - if(pDriver) - return pDriver; - if(VehicleCreatedBy != RANDOM_VEHICLE) - return nil; - - pDriver = CPopulation::AddPedInCar(this); - pDriver->m_pMyVehicle = this; - pDriver->m_pMyVehicle->RegisterReference((CEntity**)&pDriver->m_pMyVehicle); - pDriver->bInVehicle = true; - pDriver->SetPedState(PED_DRIVING); - if(bIsBus) - pDriver->m_ped_flagC4 = false; - return pDriver; -} - -CPed* -CVehicle::SetupPassenger(int n) -{ - if(pPassengers[n]) - return pPassengers[n]; - - pPassengers[n] = CPopulation::AddPedInCar(this); - pPassengers[n]->m_pMyVehicle = this; - pPassengers[n]->m_pMyVehicle->RegisterReference((CEntity**)&pPassengers[n]->m_pMyVehicle); - pPassengers[n]->bInVehicle = true; - pPassengers[n]->SetPedState(PED_DRIVING); - if(bIsBus) - pPassengers[n]->m_ped_flagC4 = false; - return pPassengers[n]; -} - -void -CVehicle::SetDriver(CPed *driver) -{ - pDriver = driver; - pDriver->RegisterReference((CEntity**)&pDriver); - - if(bFreebies && driver == FindPlayerPed()){ - if(GetModelIndex() == MI_AMBULAN) - FindPlayerPed()->m_fHealth = min(FindPlayerPed()->m_fHealth + 20.0f, 100.0f); - else if(GetModelIndex() == MI_TAXI) - CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25; - else if(GetModelIndex() == MI_POLICE) - driver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5); - else if(GetModelIndex() == MI_ENFORCER) - driver->m_fArmour = max(driver->m_fArmour, 100.0f); - else if(GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE) - CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25; - bFreebies = false; - } - - ApplyTurnForce(0.0f, 0.0f, -0.2f*driver->m_fMass, - driver->GetPosition().x - GetPosition().x, - driver->GetPosition().y - GetPosition().y, - 0.0f); -} - -bool -CVehicle::AddPassenger(CPed *passenger) -{ - int i; - - ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass, - passenger->GetPosition().x - GetPosition().x, - passenger->GetPosition().y - GetPosition().y, - 0.0f); - - for(i = 0; i < m_nNumMaxPassengers; i++) - if(pPassengers[i] == nil){ - pPassengers[i] = passenger; - m_nNumPassengers++; - return true; - } - return false; -} - -bool -CVehicle::AddPassenger(CPed *passenger, uint8 n) -{ - if(bIsBus) - return AddPassenger(passenger); - - ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass, - passenger->GetPosition().x - GetPosition().x, - passenger->GetPosition().y - GetPosition().y, - 0.0f); - - if(n < m_nNumMaxPassengers && pPassengers[n] == nil){ - pPassengers[n] = passenger; - m_nNumPassengers++; - return true; - } - return false; -} - -void -CVehicle::RemoveDriver(void) -{ - m_status = STATUS_ABANDONED; - pDriver = nil; -} - -void -CVehicle::RemovePassenger(CPed *p) -{ - if (IsTrain()){ - for (int i = 0; i < 8; i++){ - if (pPassengers[i] == p) { - pPassengers[i] = nil; - m_nNumPassengers--; - return; - } - } - return; - } - for (int i = 0; i < m_nNumMaxPassengers; i++){ - if (pPassengers[i] == p){ - pPassengers[i] = nil; - m_nNumPassengers--; - return; - } - } -} - -void -CVehicle::ProcessCarAlarm(void) -{ - uint32 step; - - if(m_nAlarmState == 0 || m_nAlarmState == -1) - return; - - step = CTimer::GetTimeStepInMilliseconds(); - if((uint16)m_nAlarmState < step) - m_nAlarmState = 0; - else - m_nAlarmState -= step; -} - -bool -CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) -{ - float x, y, z; - // sphere relative to vehicle - CVector sph = CVector(sx, sy, sz) - GetPosition(); - CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); - - x = DotProduct(sph, GetRight()); - if(colmodel->boundingBox.min.x - radius > x || - colmodel->boundingBox.max.x + radius < x) - return false; - y = DotProduct(sph, GetForward()); - if(colmodel->boundingBox.min.y - radius > y || - colmodel->boundingBox.max.y + radius < y) - return false; - z = DotProduct(sph, GetUp()); - if(colmodel->boundingBox.min.z - radius > z || - colmodel->boundingBox.max.z + radius < z) - return false; - - return true; -} - -STARTPATCHES - InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP); - InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP); - - InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP); - InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP); - InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP); - InjectHook(0x5527E0, &CVehicle::IsVehicleNormal, PATCH_JUMP); - InjectHook(0x552B70, &CVehicle::CarHasRoof, PATCH_JUMP); - InjectHook(0x552230, &CVehicle::IsUpsideDown, PATCH_JUMP); - InjectHook(0x552260, &CVehicle::IsOnItsSide, PATCH_JUMP); - InjectHook(0x5511B0, &CVehicle::CanBeDeleted, PATCH_JUMP); - InjectHook(0x5522A0, &CVehicle::CanPedOpenLocks, PATCH_JUMP); - InjectHook(0x5522F0, &CVehicle::CanPedEnterCar, PATCH_JUMP); - InjectHook(0x5523C0, &CVehicle::CanPedExitCar, PATCH_JUMP); - InjectHook(0x5520C0, &CVehicle::SetUpDriver, PATCH_JUMP); - InjectHook(0x552160, &CVehicle::SetupPassenger, PATCH_JUMP); - InjectHook(0x551F20, &CVehicle::SetDriver, PATCH_JUMP); - InjectHook(0x551D90, (bool (CVehicle::*)(CPed*))&CVehicle::AddPassenger, PATCH_JUMP); - InjectHook(0x551E10, (bool (CVehicle::*)(CPed*,uint8))&CVehicle::AddPassenger, PATCH_JUMP); - InjectHook(0x5520A0, &CVehicle::RemoveDriver, PATCH_JUMP); - InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP); - InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP); - InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP); -ENDPATCHES diff --git a/src/entities/Vehicle.h b/src/entities/Vehicle.h deleted file mode 100644 index 39a56fe0..00000000 --- a/src/entities/Vehicle.h +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once - -#include "Physical.h" -#include "AutoPilot.h" - -class CPed; -class CFire; -struct tHandlingData; - -enum { - RANDOM_VEHICLE = 1, - MISSION_VEHICLE = 2, - PARKED_VEHICLE = 3, - PERMANENT_VEHICLE = 4, -}; - -enum eCarLock { - CARLOCK_NOT_USED, - CARLOCK_UNLOCKED, - CARLOCK_LOCKED, - CARLOCK_LOCKOUT_PLAYER_ONLY, - CARLOCK_LOCKED_PLAYER_INSIDE, - CARLOCK_COP_CAR, - CARLOCK_FORCE_SHUT_DOORS, - CARLOCK_SKIP_SHUT_DOORS -}; - - -enum eCarNodes -{ - CAR_WHEEL_RF = 1, - CAR_WHEEL_RM, - CAR_WHEEL_RB, - CAR_WHEEL_LF, - CAR_WHEEL_LM, - CAR_WHEEL_LB, - CAR_BUMP_FRONT, - CAR_BUMP_REAR, - CAR_WING_RF, - CAR_WING_RR, - CAR_DOOR_RF, - CAR_DOOR_RR, - CAR_WING_LF, - CAR_WING_LR, - CAR_DOOR_LF, - CAR_DOOR_LR, - CAR_BONNET, - CAR_BOOT, - CAR_WINDSCREEN, - NUM_CAR_NODES, -}; - -enum -{ - CAR_POS_HEADLIGHTS, - CAR_POS_TAILLIGHTS, - CAR_POS_FRONTSEAT, - CAR_POS_BACKSEAT, - CAR_POS_EXHAUST = 9, -}; - -enum eDoors -{ - DOOR_BONNET = 0, - DOOR_BOOT, - DOOR_FRONT_LEFT, - DOOR_FRONT_RIGHT, - DOOR_REAR_LEFT, - DOOR_REAR_RIGHT -}; - -class CVehicle : public CPhysical -{ -public: - // 0x128 - tHandlingData *m_handling; - CAutoPilot m_autoPilot; - uint8 m_currentColour1; - uint8 m_currentColour2; - uint8 m_aExtras[2]; - int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22 - int16 m_nMissionValue; - CPed *pDriver; - CPed *pPassengers[8]; - uint8 m_nNumPassengers; - int8 m_nNumGettingIn; - int8 m_nGettingInFlags; - int8 m_nGettingOutFlags; - uint8 m_nNumMaxPassengers; - char field_1CD[19]; - CEntity *m_pCurSurface; - CFire *m_pCarFire; - float m_fSteerAngle; - float m_fGasPedal; - float m_fBreakPedal; - uint8 VehicleCreatedBy; - - // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* - uint8 bIsLawEnforcer: 1; // Is this guy chasing the player at the moment - uint8 bIsAmbulanceOnDuty: 1; // Ambulance trying to get to an accident - uint8 bIsFireTruckOnDuty: 1; // Firetruck trying to get to a fire - uint8 bIsLocked: 1; // Is this guy locked by the script (cannot be removed) - uint8 bEngineOn: 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars) - uint8 bIsHandbrakeOn: 1; // How's the handbrake doing ? - uint8 bLightsOn: 1; // Are the lights switched on ? - uint8 bFreebies: 1; // Any freebies left in this vehicle ? - - uint8 bIsVan: 1; // Is this vehicle a van (doors at back of vehicle) - uint8 bIsBus: 1; // Is this vehicle a bus - uint8 bIsBig: 1; // Is this vehicle a bus - uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims - uint8 m_veh_flagB10 : 1; - uint8 m_veh_flagB20 : 1; - uint8 m_veh_flagB40 : 1; - uint8 m_veh_flagB80 : 1; - - uint8 m_veh_flagC1 : 1; - uint8 m_veh_flagC2 : 1; - uint8 m_veh_flagC4 : 1; - uint8 m_veh_flagC8 : 1; - uint8 m_veh_flagC10 : 1; - uint8 m_veh_flagC20 : 1; - uint8 m_veh_flagC40 : 1; - uint8 m_veh_flagC80 : 1; - - uint8 m_veh_flagD1 : 1; - uint8 m_veh_flagD2 : 1; - uint8 m_veh_flagD4 : 1; - uint8 m_veh_flagD8 : 1; - uint8 bRecordedForReplay : 1; - uint8 m_veh_flagD20 : 1; - uint8 m_veh_flagD40 : 1; - uint8 m_veh_flagD80 : 1; - - int8 field_1F9; - uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) - int8 field_1FB; - int8 field_1FC[4]; - float m_fHealth; // 1000.0f = full health. 0 -> explode - uint8 m_nCurrentGear; - int8 field_205[3]; - int field_208; - uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) - uint32 m_nTimeOfDeath; - int16 field_214; - int16 m_nBombTimer; // goes down with each frame - CPed *m_pWhoDetonatedMe; - float field_21C; - float field_220; - eCarLock m_nDoorLock; - int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage - int8 m_nRadioStation; - int8 field_22A; - int8 field_22B; - uint8 m_nCarHornTimer; - int8 field_22D; - uint8 m_nSirenOrAlarm; - int8 field_22F; - // TODO: this is an array - CStoredCollPoly m_frontCollPoly; // poly which is under front part of car - CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car - float m_fSteerRatio; - eVehicleType m_vehType; - - static void *operator new(size_t); - static void *operator new(size_t sz, int slot); - static void operator delete(void*, size_t); - static void operator delete(void*, int); - - ~CVehicle(void); - // from CEntity - void SetModelIndex(uint32 i); - bool SetupLighting(void); - void RemoveLighting(bool); - void FlagToDestroyWhenNextProcessed(void) {} - - virtual void ProcessControlInputs(uint8) {} - virtual void GetComponentWorldPosition(int32 component, CVector &pos) {} - virtual bool IsComponentPresent(int32 component) { return false; } - virtual void SetComponentRotation(int32 component, CVector rotation) {} - virtual void OpenDoor(int32, eDoors door, float) {} - virtual void ProcessOpenDoor(uint32, uint32, float) {} - virtual bool IsDoorReady(eDoors door) { return false; } - virtual bool IsDoorFullyOpen(eDoors door) { return false; } - virtual bool IsDoorClosed(eDoors door) { return false; } - virtual bool IsDoorMissing(eDoors door) { return false; } - virtual void RemoveRefsToVehicle(CEntity *ent) {} - virtual void BlowUpCar(CEntity *ent) {} - virtual bool SetUpWheelColModel(CColModel *colModel) { return false; } - virtual void BurstTyre(uint8 tyre) {} - virtual bool IsRoomForPedToLeaveCar(uint32, CVector *) { return false;} - virtual float GetHeightAboveRoad(void); - virtual void PlayCarHorn(void) {} - - bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } - bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } - bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; } - bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; } - bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; } - bool IsLawEnforcementVehicle(void); - void ChangeLawEnforcerState(uint8 enable); - bool UsesSiren(uint32 id); - bool IsVehicleNormal(void); - bool CarHasRoof(void); - bool IsUpsideDown(void); - bool IsOnItsSide(void); - bool CanBeDeleted(void); - bool CanPedOpenLocks(CPed *ped); - bool CanPedEnterCar(void); - bool CanPedExitCar(void); - // do these two actually return something? - CPed *SetUpDriver(void); - CPed *SetupPassenger(int n); - void SetDriver(CPed *driver); - bool AddPassenger(CPed *passenger); - bool AddPassenger(CPed *passenger, uint8 n); - void RemovePassenger(CPed *passenger); - void RemoveDriver(void); - void ProcessCarAlarm(void); - bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius); - - static bool &bWheelsOnlyCheat; - static bool &bAllDodosCheat; - static bool &bCheat3; - static bool &bCheat4; - static bool &bCheat5; - static bool &m_bDisableMouseSteering; - - - void dtor(void) { CVehicle::~CVehicle(); } - void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); } - bool SetupLighting_(void) { return CVehicle::SetupLighting(); } - void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); } - float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); } -}; - -static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error"); -static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error"); diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 2835f396..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,891 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "main.h" -#include "General.h" -#include "RwHelper.h" -#include "Clouds.h" -#include "Draw.h" -#include "Sprite2d.h" -#include "Renderer.h" -#include "Coronas.h" -#include "WaterLevel.h" -#include "Weather.h" -#include "Glass.h" -#include "WaterCannon.h" -#include "SpecialFX.h" -#include "Shadows.h" -#include "Skidmarks.h" -#include "Antennas.h" -#include "Rubbish.h" -#include "Particle.h" -#include "Pickups.h" -#include "WeaponEffects.h" -#include "PointLights.h" -#include "Fluff.h" -#include "Replay.h" -#include "Camera.h" -#include "World.h" -#include "Ped.h" -#include "Font.h" -#include "Pad.h" -#include "Hud.h" -#include "User.h" -#include "Messages.h" -#include "Darkel.h" -#include "Garages.h" -#include "MusicManager.h" -#include "VisibilityPlugins.h" -#include "NodeName.h" -#include "DMAudio.h" -#include "CutsceneMgr.h" -#include "Lights.h" -#include "Credits.h" -#include "CullZones.h" -#include "Timecycle.h" -#include "TxdStore.h" -#include "FileMgr.h" -#include "Text.h" -#include "RpAnimBlend.h" -#include "Frontend.h" - -#define DEFAULT_VIEWWINDOW (tan(DEGTORAD(CDraw::GetFOV() * 0.5f))) - - -GlobalScene &Scene = *(GlobalScene*)0x726768; - -uint8 work_buff[55000]; -char gString[256]; -wchar *gUString = (wchar*)0x74B018; - -bool &b_FoundRecentSavedGameWantToLoad = *(bool*)0x95CDA8; - - -bool DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha); -void DoRWStuffEndOfFrame(void); - -void RenderScene(void); -void RenderDebugShit(void); -void RenderEffects(void); -void Render2dStuff(void); -void RenderMenus(void); -void DoFade(void); -void Render2dStuffAfterFade(void); - -CSprite2d *LoadSplash(const char *name); -void DestroySplashScreen(void); - - -extern void (*DebugMenuProcess)(void); -extern void (*DebugMenuRender)(void); -void DebugMenuInit(void); -void DebugMenuPopulate(void); - -void PrintGameVersion(); - -RwRGBA gColourTop; - -void -InitialiseGame(void) -{ - LoadingScreen(nil, nil, "loadsc0"); - CGame::Initialise("DATA\\GTA3.DAT"); -} - -void -Idle(void *arg) -{ -#ifdef ASPECT_RATIO_SCALE - CDraw::SetAspectRatio(CDraw::FindAspectRatio()); -#endif - - CTimer::Update(); - CSprite2d::InitPerFrame(); - CFont::InitPerFrame(); - CPointLights::InitPerFrame(); - CGame::Process(); - DMAudio.Service(); - - if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){ - FrontEndMenuManager.m_bStartGameLoading = true; - FrontEndMenuManager.m_bLoadingSavedGame = false; - return; - } - - if(FrontEndMenuManager.m_bStartGameLoading || b_FoundRecentSavedGameWantToLoad) - return; - - SetLightsWithTimeOfDayColour(Scene.world); - - if(arg == nil) - return; - - if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.field_452 == 1) && - TheCamera.GetScreenFadeStatus() != FADE_2){ -#ifdef GTA_PC - // This is from SA, but it's nice for windowed mode - RwV2d pos; - pos.x = SCREEN_WIDTH/2.0f; - pos.y = SCREEN_HEIGHT/2.0f; - RsMouseSetPos(&pos); -#endif - CRenderer::ConstructRenderList(); - CRenderer::PreRender(); - - if(CWeather::LightningFlash && !CCullZones::CamNoRain()){ - if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255)) - return; - }else{ - if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(), - CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), - 255)) - return; - } - - DefinedState(); - - // BUG. This has to be done BEFORE RwCameraBeginUpdate - RwCameraSetFarClipPlane(Scene.camera, CTimeCycle::GetFarClip()); - RwCameraSetFogDistance(Scene.camera, CTimeCycle::GetFogStart()); - - RenderScene(); - RenderDebugShit(); - RenderEffects(); - - if((TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) && - TheCamera.m_ScreenReductionPercentage > 0.0) - TheCamera.SetMotionBlurAlpha(150); - TheCamera.RenderMotionBlur(); - - Render2dStuff(); - }else{ - float viewWindow = DEFAULT_VIEWWINDOW; - CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO); - CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); - if(!RsCameraBeginUpdate(Scene.camera)) - return; - } - - RenderMenus(); -#ifndef FINAL - PrintGameVersion(); -#endif - DoFade(); - Render2dStuffAfterFade(); - CCredits::Render(); - DoRWStuffEndOfFrame(); - -// if(g_SlowMode) -// ProcessSlowMode(); -} - -void -FrontendIdle(void) -{ -#ifdef ASPECT_RATIO_SCALE - CDraw::SetAspectRatio(CDraw::FindAspectRatio()); -#endif - - CTimer::Update(); - CSprite2d::SetRecipNearClip(); - CSprite2d::InitPerFrame(); - CFont::InitPerFrame(); - CPad::UpdatePads(); - FrontEndMenuManager.Process(); - - if(RsGlobal.quit) - return; - - float viewWindow = DEFAULT_VIEWWINDOW; - CameraSize(Scene.camera, nil, viewWindow, DEFAULT_ASPECT_RATIO); - CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); - if(!RsCameraBeginUpdate(Scene.camera)) - return; - - DefinedState(); - RenderMenus(); -#ifndef FINAL - PrintGameVersion(); -#endif - DoFade(); - Render2dStuffAfterFade(); - CFont::DrawFonts(); - DoRWStuffEndOfFrame(); -} - -bool -DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha) -{ - CRGBA TopColor(TopRed, TopGreen, TopBlue, Alpha); - CRGBA BottomColor(BottomRed, BottomGreen, BottomBlue, Alpha); - - CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO); - CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); - - if(!RsCameraBeginUpdate(Scene.camera)) - return false; - - CSprite2d::InitPerFrame(); - - if(Alpha != 0) - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), BottomColor, BottomColor, TopColor, TopColor); - - return true; -} - -bool -DoRWStuffStartOfFrame_Horizon(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha) -{ - CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, SCREEN_ASPECT_RATIO); - CVisibilityPlugins::SetRenderWareCamera(Scene.camera); - RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); - - if(!RsCameraBeginUpdate(Scene.camera)) - return false; - - TheCamera.m_viewMatrix.Update(); - CClouds::RenderBackground(TopRed, TopGreen, TopBlue, BottomRed, BottomGreen, BottomBlue, Alpha); - - return true; -} - -void -DoRWStuffEndOfFrame(void) -{ - // CDebug::DebugDisplayTextBuffer(); - // FlushObrsPrintfs(); - RwCameraEndUpdate(Scene.camera); - RsCameraShowRaster(Scene.camera); -} - - -// This is certainly a very useful function -void -DoRWRenderHorizon(void) -{ - CClouds::RenderHorizon(); -} - -void -RenderScene(void) -{ - CClouds::Render(); - DoRWRenderHorizon(); - CRenderer::RenderRoads(); - CCoronas::RenderReflections(); - RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE); - CRenderer::RenderEverythingBarRoads(); - CRenderer::RenderBoats(); - DefinedState(); - CWaterLevel::RenderWater(); - CRenderer::RenderFadingInEntities(); - CRenderer::RenderVehiclesButNotBoats(); - CWeather::RenderRainStreaks(); -} - -void -RenderDebugShit(void) -{ - // CTheScripts::RenderTheScriptDebugLines() -} - -void -RenderEffects(void) -{ - CGlass::Render(); - CWaterCannons::Render(); - CSpecialFX::Render(); - CShadows::RenderStaticShadows(); - CShadows::RenderStoredShadows(); - CSkidmarks::Render(); - CAntennas::Render(); - CRubbish::Render(); - CCoronas::Render(); - CParticle::Render(); - CPacManPickups::Render(); - CWeaponEffects::Render(); - CPointLights::RenderFogEffect(); - CMovingThings::Render(); - CRenderer::RenderFirstPersonVehicle(); -} - -void -Render2dStuff(void) -{ - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE); - - CReplay::Display(); - CPickups::RenderPickUpText(); - - if(TheCamera.m_WideScreenOn) - TheCamera.DrawBordersForWideScreen(); - - CPed *player = FindPlayerPed(); - int weaponType = 0; - if(player) - weaponType = player->GetWeapon()->m_eWeaponType; - - bool firstPersonWeapon = false; - int cammode = TheCamera.Cams[TheCamera.ActiveCam].Mode; - if(cammode == CCam::MODE_SNIPER || - cammode == CCam::MODE_SNIPER_RUN_AROUND || - cammode == CCam::MODE_ROCKET || - cammode == CCam::MODE_ROCKET_RUN_AROUND) - firstPersonWeapon = true; - - // Draw black border for sniper and rocket launcher - if((weaponType == WEAPONTYPE_SNIPERRIFLE || weaponType == WEAPONTYPE_ROCKETLAUNCHER) && firstPersonWeapon){ - CRGBA black(0, 0, 0, 255); - - // top and bottom strips - if (weaponType == WEAPONTYPE_ROCKETLAUNCHER) { - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(180)), black); - CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(170), SCREEN_WIDTH, SCREEN_HEIGHT), black); - } - else { - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(210)), black); - CSprite2d::DrawRect(CRect(0.0f, SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(210), SCREEN_WIDTH, SCREEN_HEIGHT), black); - } - CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREEN_WIDTH / 2 - SCREEN_SCALE_X(210), SCREEN_HEIGHT), black); - CSprite2d::DrawRect(CRect(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(210), 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), black); - } - - MusicManager.DisplayRadioStationName(); -// TheConsole.Display(); -/* - if(CSceneEdit::m_bEditOn) - CSceneEdit::Draw(); - else -*/ - CHud::Draw(); - CUserDisplay::OnscnTimer.ProcessForDisplay(); - CMessages::Display(); - CDarkel::DrawMessages(); - CGarages::PrintMessages(); - CPad::PrintErrorMessage(); - CFont::DrawFonts(); - - DebugMenuRender(); -} - -void -RenderMenus(void) -{ - if(FrontEndMenuManager.m_bMenuActive) - FrontEndMenuManager.DrawFrontEnd(); -} - -bool &JustLoadedDontFadeInYet = *(bool*)0x95CDB4; -bool &StillToFadeOut = *(bool*)0x95CD99; -uint32 &TimeStartedCountingForFade = *(uint32*)0x9430EC; -uint32 &TimeToStayFadedBeforeFadeOut = *(uint32*)0x611564; - -void -DoFade(void) -{ - if(CTimer::GetIsPaused()) - return; - - if(JustLoadedDontFadeInYet){ - JustLoadedDontFadeInYet = false; - TimeStartedCountingForFade = CTimer::GetTimeInMilliseconds(); - } - - if(StillToFadeOut){ - if(CTimer::GetTimeInMilliseconds() - TimeStartedCountingForFade > TimeToStayFadedBeforeFadeOut){ - StillToFadeOut = false; - TheCamera.Fade(3.0f, FADE_IN); - TheCamera.ProcessFade(); - TheCamera.ProcessMusicFade(); - }else{ - TheCamera.SetFadeColour(0, 0, 0); - TheCamera.Fade(0.0f, FADE_OUT); - TheCamera.ProcessFade(); - } - } - - if(CDraw::FadeValue != 0 || CMenuManager::m_PrefsBrightness < 256){ - CSprite2d *splash = LoadSplash(nil); - - CRGBA fadeColor; - CRect rect; - int fadeValue = CDraw::FadeValue; - float brightness = min(CMenuManager::m_PrefsBrightness, 256); - if(brightness <= 50) - brightness = 50; - if(FrontEndMenuManager.m_bMenuActive) - brightness = 256; - - if(TheCamera.m_FadeTargetIsSplashScreen) - fadeValue = 0; - - float fade = fadeValue + 256 - brightness; - if(fade == 0){ - fadeColor.r = 0; - fadeColor.g = 0; - fadeColor.b = 0; - fadeColor.a = 0; - }else{ - fadeColor.r = fadeValue * CDraw::FadeRed / fade; - fadeColor.g = fadeValue * CDraw::FadeGreen / fade; - fadeColor.b = fadeValue * CDraw::FadeBlue / fade; - int alpha = 255 - brightness*(256 - fadeValue)/256; - if(alpha < 0) - alpha = 0; - fadeColor.a = alpha; - } - - if(TheCamera.m_WideScreenOn){ - // what's this? - float y = SCREEN_HEIGHT/2 * TheCamera.m_ScreenReductionPercentage/100.0f; - rect.left = 0.0f; - rect.right = SCREEN_WIDTH; - rect.top = y - 8.0f; - rect.bottom = SCREEN_HEIGHT - y - 8.0f; - }else{ - rect.left = 0.0f; - rect.right = SCREEN_WIDTH; - rect.top = 0.0f; - rect.bottom = SCREEN_HEIGHT; - } - CSprite2d::DrawRect(rect, fadeColor); - - if(CDraw::FadeValue != 0 && TheCamera.m_FadeTargetIsSplashScreen){ - fadeColor.r = 255; - fadeColor.g = 255; - fadeColor.b = 255; - fadeColor.a = CDraw::FadeValue; - splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), fadeColor, fadeColor, fadeColor, fadeColor); - } - } -} - -void -Render2dStuffAfterFade(void) -{ - CHud::DrawAfterFade(); - CFont::DrawFonts(); -} - -CSprite2d splash; -int splashTxdId = -1; - -CSprite2d* -LoadSplash(const char *name) -{ - RwTexDictionary *txd; - char filename[140]; - RwTexture *tex = nil; - - if(name == nil) - return &splash; - if(splashTxdId == -1) - splashTxdId = CTxdStore::AddTxdSlot("splash"); - - txd = CTxdStore::GetSlot(splashTxdId)->texDict; - if(txd) - tex = RwTexDictionaryFindNamedTexture(txd, name); - // if texture is found, splash was already set up below - - if(tex == nil){ - CFileMgr::SetDir("TXD\\"); - sprintf(filename, "%s.txd", name); - if(splash.m_pTexture) - splash.Delete(); - if(txd) - CTxdStore::RemoveTxd(splashTxdId); - CTxdStore::LoadTxd(splashTxdId, filename); - CTxdStore::AddRef(splashTxdId); - CTxdStore::PushCurrentTxd(); - CTxdStore::SetCurrentTxd(splashTxdId); - splash.SetTexture(name); - CTxdStore::PopCurrentTxd(); - CFileMgr::SetDir(""); - } - - return &splash; -} - -void -DestroySplashScreen(void) -{ - splash.Delete(); - if(splashTxdId != -1) - CTxdStore::RemoveTxdSlot(splashTxdId); - splashTxdId = -1; -} - -float NumberOfChunksLoaded; -#define TOTALNUMCHUNKS 73.0f - -// TODO: compare with PS2 -void -LoadingScreen(const char *str1, const char *str2, const char *splashscreen) -{ - CSprite2d *splash; - -#ifndef RANDOMSPLASH - if(CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) - splashscreen = "mainsc2"; - else - splashscreen = "mainsc1"; -#endif - - splash = LoadSplash(splashscreen); - - if(RsGlobal.quit) - return; - - if(DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)){ - CSprite2d::SetRecipNearClip(); - CSprite2d::InitPerFrame(); - CFont::InitPerFrame(); - DefinedState(); - RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); - splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - - if(str1){ - NumberOfChunksLoaded += 1; - - float hpos = SCREEN_SCALE_X(40); - float length = SCREEN_WIDTH - SCREEN_SCALE_X(100); - float vpos = SCREEN_HEIGHT - SCREEN_SCALE_Y(13); - float height = SCREEN_SCALE_Y(7); - CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(40, 53, 68, 255)); - - length *= NumberOfChunksLoaded/TOTALNUMCHUNKS; - CSprite2d::DrawRect(CRect(hpos, vpos, hpos + length, vpos + height), CRGBA(81, 106, 137, 255)); - - // this is done by the game but is unused - CFont::SetScale(SCREEN_SCALE_X(2), SCREEN_SCALE_Y(2)); - CFont::SetPropOn(); - CFont::SetRightJustifyOn(); - CFont::SetFontStyle(FONT_HEADING); - -#ifdef CHATTYSPLASH - // my attempt - static wchar tmpstr[80]; - float scale = SCREEN_SCALE_Y(0.8f); - vpos -= 50*scale; - CFont::SetScale(scale, scale); - CFont::SetPropOn(); - CFont::SetRightJustifyOff(); - CFont::SetFontStyle(FONT_BANK); - CFont::SetColor(CRGBA(255, 255, 255, 255)); - AsciiToUnicode(str1, tmpstr); - CFont::PrintString(hpos, vpos, tmpstr); - vpos += 25*scale; - AsciiToUnicode(str2, tmpstr); - CFont::PrintString(hpos, vpos, tmpstr); -#endif - } - - CFont::DrawFonts(); - DoRWStuffEndOfFrame(); - } -} - -void -ResetLoadingScreenBar(void) -{ - NumberOfChunksLoaded = 0.0f; -} - -void -LoadingIslandScreen(const char *levelName) -{ - CSprite2d *splash; - wchar *name; - char str[100]; - wchar wstr[80]; - CRGBA col; - - splash = LoadSplash(nil); - name = TheText.Get(levelName); - if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)) - return; - - CSprite2d::SetRecipNearClip(); - CSprite2d::InitPerFrame(); - CFont::InitPerFrame(); - DefinedState(); - col = CRGBA(255, 255, 255, 255); - splash->Draw(CRect(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT), col, col, col, col); - CFont::SetBackgroundOff(); - CFont::SetScale(1.5f, 1.5f); - CFont::SetPropOn(); - CFont::SetRightJustifyOn(); - CFont::SetRightJustifyWrap(150.0f); - CFont::SetFontStyle(FONT_HEADING); - sprintf(str, "WELCOME TO"); - AsciiToUnicode(str, wstr); - CFont::SetDropColor(CRGBA(0, 0, 0, 255)); - CFont::SetDropShadowPosition(3); - CFont::SetColor(CRGBA(243, 237, 71, 255)); - CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); - CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); - TextCopy(wstr, name); - TheText.UpperCase(wstr); - CFont::SetColor(CRGBA(243, 237, 71, 255)); - CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); - CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); - CFont::DrawFonts(); - DoRWStuffEndOfFrame(); -} - -char* -GetLevelSplashScreen(int level) -{ - static char *splashScreens[4] = { - nil, - "splash1", - "splash2", - "splash3", - }; - - return splashScreens[level]; -} - -char* -GetRandomSplashScreen(void) -{ - int index; - static int index2 = 0; - static char splashName[128]; - static int splashIndex[24] = { - 25, 22, 4, 13, - 1, 21, 14, 16, - 10, 12, 5, 9, - 11, 18, 3, 2, - 19, 23, 7, 17, - 15, 6, 8, 20 - }; - - index = splashIndex[4*index2 + CGeneral::GetRandomNumberInRange(0, 3)]; - index2++; - if(index2 == 6) - index2 = 0; - sprintf(splashName, "loadsc%d", index); - return splashName; -} - -#include "rwcore.h" -#include "rpworld.h" -#include "rpmatfx.h" -#include "rpskin.h" -#include "rphanim.h" -#include "rtbmp.h" - -_TODO("temp, move this includes out of here") - -static RwBool -PluginAttach(void) -{ - if( !RpWorldPluginAttach() ) - { - printf("Couldn't attach world plugin\n"); - - return FALSE; - } - - if( !RpSkinPluginAttach() ) - { - printf("Couldn't attach RpSkin plugin\n"); - - return FALSE; - } - - if( !RpHAnimPluginAttach() ) - { - printf("Couldn't attach RpHAnim plugin\n"); - - return FALSE; - } - - if( !NodeNamePluginAttach() ) - { - printf("Couldn't attach node name plugin\n"); - - return FALSE; - } - - if( !CVisibilityPlugins::PluginAttach() ) - { - printf("Couldn't attach visibility plugins\n"); - - return FALSE; - } - - if( !RpAnimBlendPluginAttach() ) - { - printf("Couldn't attach RpAnimBlend plugin\n"); - - return FALSE; - } - - if( !RpMatFXPluginAttach() ) - { - printf("Couldn't attach RpMatFX plugin\n"); - - return FALSE; - } - - return TRUE; -} - -static RwBool -Initialise3D(void *param) -{ - if (RsRwInitialise(param)) - { - // - DebugMenuInit(); - DebugMenuPopulate(); - // - - return CGame::InitialiseRenderWare(); - } - - return (FALSE); -} - - -static void -Terminate3D(void) -{ - CGame::ShutdownRenderWare(); - - RsRwTerminate(); - - return; -} - -RsEventStatus -AppEventHandler(RsEvent event, void *param) -{ - switch( event ) - { - case rsINITIALISE: - { - CGame::InitialiseOnceBeforeRW(); - return RsInitialise() ? rsEVENTPROCESSED : rsEVENTERROR; - } - - case rsCAMERASIZE: - { - - CameraSize(Scene.camera, (RwRect *)param, - DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO); - - return rsEVENTPROCESSED; - } - - case rsRWINITIALISE: - { - return Initialise3D(param) ? rsEVENTPROCESSED : rsEVENTERROR; - } - - case rsRWTERMINATE: - { - Terminate3D(); - - return rsEVENTPROCESSED; - } - - case rsTERMINATE: - { - CGame::FinalShutdown(); - - return rsEVENTPROCESSED; - } - - case rsPLUGINATTACH: - { - return PluginAttach() ? rsEVENTPROCESSED : rsEVENTERROR; - } - - case rsINPUTDEVICEATTACH: - { - AttachInputDevices(); - - return rsEVENTPROCESSED; - } - - case rsIDLE: - { - Idle(param); - - return rsEVENTPROCESSED; - } - - case rsFRONTENDIDLE: - { - FrontendIdle(); - - return rsEVENTPROCESSED; - } - - case rsACTIVATE: - { - param ? DMAudio.ReacquireDigitalHandle() : DMAudio.ReleaseDigitalHandle(); - - return rsEVENTPROCESSED; - } - - default: - { - return rsEVENTNOTPROCESSED; - } - } -} - -void PrintGameVersion() -{ - CFont::SetPropOn(); - CFont::SetBackgroundOff(); - CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.5f)); - CFont::SetCentreOff(); - CFont::SetRightJustifyOff(); - CFont::SetBackGroundOnlyTextOff(); - CFont::SetFontStyle(FONT_BANK); - CFont::SetWrapx(SCREEN_WIDTH); - CFont::SetDropShadowPosition(0); - CFont::SetDropColor(CRGBA(0, 0, 0, 255)); - CFont::SetColor(CRGBA(235, 170, 50, 255)); - - strcpy(gString, "RE3"); - AsciiToUnicode(gString, gUString); - CFont::PrintString(SCREEN_SCALE_X(10.5f), SCREEN_SCALE_Y(8.0f), gUString); -} - -STARTPATCHES - InjectHook(0x48E480, Idle, PATCH_JUMP); - InjectHook(0x48E700, FrontendIdle, PATCH_JUMP); - - InjectHook(0x48CF10, DoRWStuffStartOfFrame, PATCH_JUMP); - InjectHook(0x48D040, DoRWStuffStartOfFrame_Horizon, PATCH_JUMP); - InjectHook(0x48E030, RenderScene, PATCH_JUMP); - InjectHook(0x48E080, RenderDebugShit, PATCH_JUMP); - InjectHook(0x48E090, RenderEffects, PATCH_JUMP); - InjectHook(0x48E0E0, Render2dStuff, PATCH_JUMP); - InjectHook(0x48E450, RenderMenus, PATCH_JUMP); - InjectHook(0x48D120, DoFade, PATCH_JUMP); - InjectHook(0x48E470, Render2dStuffAfterFade, PATCH_JUMP); - - InjectHook(0x48D550, LoadSplash, PATCH_JUMP); - InjectHook(0x48D670, DestroySplashScreen, PATCH_JUMP); - InjectHook(0x48D770, LoadingScreen, PATCH_JUMP); - InjectHook(0x48D760, ResetLoadingScreenBar, PATCH_JUMP); - - InjectHook(0x48D470, PluginAttach, PATCH_JUMP); - InjectHook(0x48D520, Initialise3D, PATCH_JUMP); - InjectHook(0x48D540, Terminate3D, PATCH_JUMP); - InjectHook(0x48E800, AppEventHandler, PATCH_JUMP); -ENDPATCHES diff --git a/src/main.h b/src/main.h deleted file mode 100644 index bdb0e008..00000000 --- a/src/main.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -struct GlobalScene -{ - RpWorld *world; - RwCamera *camera; -}; -extern GlobalScene &Scene; - -extern uint8 work_buff[55000]; -extern char gString[256]; -extern wchar *gUString; -extern bool &b_FoundRecentSavedGameWantToLoad; - -class CSprite2d; - -void InitialiseGame(void); -void LoadingScreen(const char *str1, const char *str2, const char *splashscreen); -void LoadingIslandScreen(const char *levelName); -CSprite2d *LoadSplash(const char *name); -char *GetLevelSplashScreen(int level); -char *GetRandomSplashScreen(void); diff --git a/src/modelinfo/MloInstance.cpp b/src/modelinfo/MloInstance.cpp new file mode 100644 index 00000000..dbd83727 --- /dev/null +++ b/src/modelinfo/MloInstance.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "patcher.h" +#include "MloInstance.h" + +STARTPATCHES +InjectHook(0x50BE90, &CMloInstance::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/modelinfo/MloInstance.h b/src/modelinfo/MloInstance.h new file mode 100644 index 00000000..00afc379 --- /dev/null +++ b/src/modelinfo/MloInstance.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Placeable.h" + +class CMloInstance : CPlaceable +{ +public: + void dtor() { this->CMloInstance::~CMloInstance(); } +}; \ No newline at end of file diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp new file mode 100644 index 00000000..a9c47777 --- /dev/null +++ b/src/objects/CutsceneHead.cpp @@ -0,0 +1,118 @@ +#include "common.h" +#include +#include "patcher.h" +#include "main.h" +#include "RwHelper.h" +#include "RpAnimBlend.h" +#include "AnimBlendClumpData.h" +#include "Directory.h" +#include "CutsceneMgr.h" +#include "Streaming.h" +#include "CutsceneHead.h" + + +CCutsceneHead::CCutsceneHead(CObject *obj) +{ + RpAtomic *atm; + + assert(RwObjectGetType(obj->m_rwObject) == rpCLUMP); + m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame; + atm = (RpAtomic*)GetFirstObject(m_pHeadNode); + if(atm){ + assert(RwObjectGetType(atm) == rpATOMIC); + RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER); + } +} + +void +CCutsceneHead::CreateRwObject(void) +{ + RpAtomic *atm; + + CEntity::CreateRwObject(); + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + atm = GetFirstAtomic((RpClump*)m_rwObject); + RpSkinAtomicSetHAnimHierarchy(atm, RpHAnimFrameGetHierarchy(GetFirstChild(RpClumpGetFrame((RpClump*)m_rwObject)))); +} + +void +CCutsceneHead::DeleteRwObject(void) +{ + CEntity::DeleteRwObject(); +} + +void +CCutsceneHead::ProcessControl(void) +{ + RpAtomic *atm; + RpHAnimHierarchy *hier; + + CPhysical::ProcessControl(); + + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; + UpdateRwFrame(); + + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + atm = GetFirstAtomic((RpClump*)m_rwObject); + hier = RpSkinAtomicGetHAnimHierarchy(atm); + RpHAnimHierarchyAddAnimTime(hier, CTimer::GetTimeStepNonClipped()/50.0f); +} + +void +CCutsceneHead::Render(void) +{ + RpAtomic *atm; + + m_matrix.SetRotateY(PI/2); + m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix; + UpdateRwFrame(); + + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + atm = GetFirstAtomic((RpClump*)m_rwObject); + RpHAnimHierarchyUpdateMatrices(RpSkinAtomicGetHAnimHierarchy(atm)); + + CObject::Render(); +} + +void +CCutsceneHead::PlayAnimation(const char *animName) +{ + RpAtomic *atm; + RpHAnimHierarchy *hier; + RpHAnimAnimation *anim; + uint32 offset, size; + RwStream *stream; + + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + atm = GetFirstAtomic((RpClump*)m_rwObject); + hier = RpSkinAtomicGetHAnimHierarchy(atm); + + sprintf(gString, "%s.anm", animName); + + if(CCutsceneMgr::ms_pCutsceneDir->FindItem(gString, offset, size)){ + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG"); + assert(stream); + + CStreaming::MakeSpaceFor(size*2048); + CStreaming::ImGonnaUseStreamingMemory(); + + RwStreamSkip(stream, offset*2048); + if(RwStreamFindChunk(stream, rwID_HANIMANIMATION, nil, nil)){ + anim = RpHAnimAnimationStreamRead(stream); + RpHAnimHierarchySetCurrentAnim(hier, anim); + } + + CStreaming::IHaveUsedStreamingMemory(); + + RwStreamClose(stream, nil); + } +} + +STARTPATCHES + InjectHook(0x4BA650, &CCutsceneHead::CreateRwObject_, PATCH_JUMP); + InjectHook(0x4BA690, &CCutsceneHead::DeleteRwObject_, PATCH_JUMP); + InjectHook(0x4BA760, &CCutsceneHead::ProcessControl_, PATCH_JUMP); + InjectHook(0x4BA800, &CCutsceneHead::Render_, PATCH_JUMP); + InjectHook(0x4BA6A0, &CCutsceneHead::PlayAnimation, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/CutsceneHead.h b/src/objects/CutsceneHead.h new file mode 100644 index 00000000..de4f011f --- /dev/null +++ b/src/objects/CutsceneHead.h @@ -0,0 +1,24 @@ +#pragma once + +#include "CutsceneObject.h" + +class CCutsceneHead : public CCutsceneObject +{ +public: + RwFrame *m_pHeadNode; + + CCutsceneHead(CObject *obj); + + void CreateRwObject(void); + void DeleteRwObject(void); + void ProcessControl(void); + void Render(void); + + void PlayAnimation(const char *animName); + + void CreateRwObject_(void) { CCutsceneHead::CreateRwObject(); } + void DeleteRwObject_(void) { CCutsceneHead::DeleteRwObject(); } + void ProcessControl_(void) { CCutsceneHead::ProcessControl(); } + void Render_(void) { CCutsceneHead::Render(); } +}; +static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error"); diff --git a/src/objects/CutsceneObject.cpp b/src/objects/CutsceneObject.cpp new file mode 100644 index 00000000..ede5be5b --- /dev/null +++ b/src/objects/CutsceneObject.cpp @@ -0,0 +1,100 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Lights.h" +#include "PointLights.h" +#include "RpAnimBlend.h" +#include "AnimBlendClumpData.h" +#include "Renderer.h" +#include "ModelIndices.h" +#include "Shadows.h" +#include "Timecycle.h" +#include "CutsceneObject.h" + +CCutsceneObject::CCutsceneObject(void) +{ + m_status = STATUS_SIMPLE; + bUsesCollision = false; + bStreamingDontDelete = true; + ObjectCreatedBy = CUTSCENE_OBJECT; + m_fMass = 1.0f; + m_fTurnMass = 1.0f; +} + +void +CCutsceneObject::SetModelIndex(uint32 id) +{ + CEntity::SetModelIndex(id); + assert(RwObjectGetType(m_rwObject) == rpCLUMP); + RpAnimBlendClumpInit((RpClump*)m_rwObject); + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = &m_vecMoveSpeed; + (*RPANIMBLENDCLUMPDATA(m_rwObject))->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION_3D; +} + +void +CCutsceneObject::ProcessControl(void) +{ + CPhysical::ProcessControl(); + + if(CTimer::GetTimeStep() < 1/100.0f) + m_vecMoveSpeed *= 100.0f; + else + m_vecMoveSpeed *= 1.0f/CTimer::GetTimeStep(); + + ApplyMoveSpeed(); +} + +void +CCutsceneObject::PreRender(void) +{ + if(IsPedModel(GetModelIndex())) + CShadows::StoreShadowForPedObject(this, + CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); +} + +void +CCutsceneObject::Render(void) +{ + CObject::Render(); +} + +bool +CCutsceneObject::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + + if(bRenderScorched){ + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + }else{ + CVector coors = GetPosition(); + float lighting = CPointLights::GenerateLightsAffectingObject(&coors); + if(!bHasBlip && lighting != 1.0f){ + SetAmbientAndDirectionalColours(lighting); + return true; + } + } + + return false; +} + +void +CCutsceneObject::RemoveLighting(bool reset) +{ + CRenderer::RemoveVehiclePedLights(this, reset); +} + +STARTPATCHES + InjectHook(0x4BA960, &CCutsceneObject::dtor, PATCH_JUMP); + InjectHook(0x4BA980, &CCutsceneObject::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4BA9C0, &CCutsceneObject::ProcessControl_, PATCH_JUMP); + InjectHook(0x4BAA40, &CCutsceneObject::PreRender_, PATCH_JUMP); + InjectHook(0x4BAAA0, &CCutsceneObject::Render_, PATCH_JUMP); + InjectHook(0x4A7E70, &CCutsceneObject::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7F00, &CCutsceneObject::RemoveLighting_, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/CutsceneObject.h b/src/objects/CutsceneObject.h new file mode 100644 index 00000000..9360651e --- /dev/null +++ b/src/objects/CutsceneObject.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Object.h" + +class CCutsceneObject : public CObject +{ +public: + CCutsceneObject(void); + + virtual void SetModelIndex(uint32 id); + virtual void ProcessControl(void); + virtual void PreRender(void); + virtual void Render(void); + virtual bool SetupLighting(void); + virtual void RemoveLighting(bool reset); + + void dtor(void) { this->CCutsceneObject::~CCutsceneObject(); } + void SetModelIndex_(uint32 id) { CCutsceneObject::SetModelIndex(id); } + void ProcessControl_(void) { CCutsceneObject::ProcessControl(); } + void PreRender_(void) { CCutsceneObject::PreRender(); } + void Render_(void) { CCutsceneObject::Render(); } + bool SetupLighting_(void) { return CCutsceneObject::SetupLighting(); } + void RemoveLighting_(bool reset) { CCutsceneObject::RemoveLighting(reset); } +}; +static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error"); diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp new file mode 100644 index 00000000..1e4b2ae0 --- /dev/null +++ b/src/objects/DummyObject.cpp @@ -0,0 +1,17 @@ +#include "common.h" +#include "patcher.h" +#include "DummyObject.h" +#include "Pools.h" + +CDummyObject::CDummyObject(CObject *obj) +{ + SetModelIndexNoCreate(obj->GetModelIndex()); + if(obj->m_rwObject) + AttachToRwObject(obj->m_rwObject); + obj->DetachFromRwObject(); + m_level = obj->m_level; +} + +STARTPATCHES + InjectHook(0x4BAB70, &CDummyObject::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/objects/DummyObject.h b/src/objects/DummyObject.h new file mode 100644 index 00000000..10554bdd --- /dev/null +++ b/src/objects/DummyObject.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Dummy.h" + +class CObject; + +class CDummyObject : public CDummy +{ +public: + CDummyObject(void) {} + CDummyObject(CObject *obj); + void dtor(void) { this->CDummyObject::~CDummyObject(); } +}; +static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error"); diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp new file mode 100644 index 00000000..6712d77b --- /dev/null +++ b/src/objects/Object.cpp @@ -0,0 +1,93 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Lights.h" +#include "Pools.h" +#include "Radar.h" +#include "Object.h" + +WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); } + +int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2; + +void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); } +void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); } + +CObject::CObject(void) +{ + m_type = ENTITY_TYPE_OBJECT; + m_fUprootLimit = 0.0f; + m_nCollisionDamageEffect = 0; + m_nSpecialCollisionResponseCases = COLLRESPONSE_NONE; + m_bCameraToAvoidThisObject = false; + ObjectCreatedBy = 0; + m_nEndOfLifeTime = 0; +// m_nRefModelIndex = -1; // duplicate +// bUseVehicleColours = false; // duplicate + m_colour2 = 0; + m_colour1 = m_colour2; + field_172 = 0; + bIsPickup = false; + m_obj_flag2 = false; + m_obj_flag4 = false; + m_obj_flag8 = false; + m_obj_flag10 = false; + bHasBeenDamaged = false; + m_nRefModelIndex = -1; + bUseVehicleColours = false; + m_pCurSurface = nil; + m_pCollidingEntity = nil; +} + +CObject::~CObject(void) +{ + CRadar::ClearBlipForEntity(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(this)); + + if(m_nRefModelIndex != -1) + CModelInfo::GetModelInfo(m_nRefModelIndex)->RemoveRef(); + + if(ObjectCreatedBy == TEMP_OBJECT && nNoTempObjects != 0) + nNoTempObjects--; +} + +void +CObject::Render(void) +{ + if(m_flagD80) + return; + + if(m_nRefModelIndex != -1 && ObjectCreatedBy == TEMP_OBJECT && bUseVehicleColours){ + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_nRefModelIndex); + assert(mi->m_type == MITYPE_VEHICLE); + mi->SetVehicleColour(m_colour1, m_colour2); + } + + CEntity::Render(); +} + +bool +CObject::SetupLighting(void) +{ + DeActivateDirectional(); + SetAmbientColours(); + + if(bRenderScorched){ + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + return true; + } + return false; +} + +void +CObject::RemoveLighting(bool reset) +{ + if(reset) + WorldReplaceScorchedLightsWithNormal(Scene.world); +} + +WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); } + +STARTPATCHES + InjectHook(0x4BAE00, &CObject::dtor, PATCH_JUMP); + InjectHook(0x4BB1E0, &CObject::Render_, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/Object.h b/src/objects/Object.h new file mode 100644 index 00000000..de4c8e05 --- /dev/null +++ b/src/objects/Object.h @@ -0,0 +1,81 @@ +#pragma once + +#include "Physical.h" + +enum { + GAME_OBJECT = 1, + MISSION_OBJECT = 2, + TEMP_OBJECT = 3, + CUTSCENE_OBJECT = 4, +}; + +enum { + COLLRESPONSE_NONE, + COLLRESPONSE_CHANGE_MODEL, + COLLRESPONSE_SPLIT_MODEL, + COLLRESPONSE_SMASH_COMPLETELY, + COLLRESPONSE_CHANGE_THEN_SMASH, + COLLRESPONSE_UNKNOWN5, + + COLLRESPONSE_SMASH_CARDBOARD_COMPLETELY = 50, + COLLRESPONSE_SMASH_WOODENBOX_COMPLETELY = 60, + COLLRESPONSE_SMASH_TRAFFICCONE_COMPLETELY = 70, + COLLRESPONSE_SMASH_BARPOST_COMPLETELY = 80, + +}; + +class CVehicle; + +class CObject : public CPhysical +{ +public: + CMatrix m_objectMatrix; + float m_fUprootLimit; + int8 ObjectCreatedBy; + int8 bIsPickup : 1; + int8 m_obj_flag2 : 1; + int8 m_obj_flag4 : 1; + int8 m_obj_flag8 : 1; + int8 m_obj_flag10 : 1; + int8 bHasBeenDamaged : 1; + int8 bUseVehicleColours : 1; + int8 m_obj_flag80 : 1; + int8 field_172; + int8 field_173; + float m_fCollisionDamageMultiplier; + uint8 m_nCollisionDamageEffect; + uint8 m_nSpecialCollisionResponseCases; + bool m_bCameraToAvoidThisObject; + int8 field_17B; + int8 field_17C; + int8 field_17D; + int8 field_17E; + int8 field_17F; + int32 m_nEndOfLifeTime; + int16 m_nRefModelIndex; + int8 field_186; + int8 field_187; + CEntity *m_pCurSurface; + CEntity *m_pCollidingEntity; + int8 m_colour1, m_colour2; + + static int16 &nNoTempObjects; + + static void *operator new(size_t); + static void operator delete(void*, size_t); + + CObject(void); + ~CObject(void); + + void Render(void); + bool SetupLighting(void); + void RemoveLighting(bool reset); + + void ObjectDamage(float amount); + + static void DeleteAllTempObjectInArea(CVector, float); + + void dtor(void) { this->CObject::~CObject(); } + void Render_(void) { CObject::Render(); } +}; +static_assert(sizeof(CObject) == 0x198, "CObject: error"); diff --git a/src/objects/ObjectData.cpp b/src/objects/ObjectData.cpp new file mode 100644 index 00000000..ef5bcc5e --- /dev/null +++ b/src/objects/ObjectData.cpp @@ -0,0 +1,103 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "ModelInfo.h" +#include "Object.h" +#include "FileMgr.h" +#include "ObjectData.h" + +CObjectInfo CObjectData::ms_aObjectInfo[NUMOBJECTINFO]; + +// Another ugly file reader +void +CObjectData::Initialise(const char *filename) +{ + char *p, *lp; + char line[1024], name[256]; + int id; + float percentSubmerged; + int damageEffect, responseCase, camAvoid; + CBaseModelInfo *mi; + + CFileMgr::SetDir(""); + CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r"); + + id = 0; + p = (char*)work_buff; + while(*p != '*'){ + // skip over white space and comments + while(*p == ' ' || *p == '\n' || *p == '\r' || *p == ';') + if(*p == ';') + while(*p != '\n' && *p != '*') + p++; + else + p++; + + if(*p == '*') + break; + + // read one line + lp = line; + while(*p != '\n' && *p != '*'){ + *lp++ = *p == ',' ? ' ' : *p; + p++; + } + if(*p == '\n') + p++; + *lp = '\0'; // FIX: game wrote '\n' here + + assert(id < NUMOBJECTINFO); + sscanf(line, "%s %f %f %f %f %f %f %f %d %d %d", name, + &ms_aObjectInfo[id].m_fMass, + &ms_aObjectInfo[id].m_fTurnMass, + &ms_aObjectInfo[id].m_fAirResistance, + &ms_aObjectInfo[id].m_fElasticity, + &percentSubmerged, + &ms_aObjectInfo[id].m_fUprootLimit, + &ms_aObjectInfo[id].m_fCollisionDamageMultiplier, + &damageEffect, &responseCase, &camAvoid); + + ms_aObjectInfo[id].m_fBuoyancy = 100.0f/percentSubmerged * 0.008*ms_aObjectInfo[id].m_fMass; + ms_aObjectInfo[id].m_nCollisionDamageEffect = damageEffect; + ms_aObjectInfo[id].m_nSpecialCollisionResponseCases = responseCase; + ms_aObjectInfo[id].m_bCameraToAvoidThisObject = camAvoid; + + mi = CModelInfo::GetModelInfo(name, nil); + if(mi) + mi->SetObjectID(id++); + else + debug("CObjectData: Cannot find object %s\n", name); + } +} + +void +CObjectData::SetObjectData(int32 modelId, CObject &object) +{ + CObjectInfo *objinfo; + + if(CModelInfo::GetModelInfo(modelId)->GetObjectID() == -1) + return; + + objinfo = &ms_aObjectInfo[CModelInfo::GetModelInfo(modelId)->GetObjectID()]; + + object.m_fMass = objinfo->m_fMass; + object.m_fTurnMass = objinfo->m_fTurnMass; + object.m_fAirResistance = objinfo->m_fAirResistance; + object.m_fElasticity = objinfo->m_fElasticity; + object.m_fBuoyancy = objinfo->m_fBuoyancy; + object.m_fUprootLimit = objinfo->m_fUprootLimit; + object.m_fCollisionDamageMultiplier = objinfo->m_fCollisionDamageMultiplier; + object.m_nCollisionDamageEffect = objinfo->m_nCollisionDamageEffect; + object.m_nSpecialCollisionResponseCases = objinfo->m_nSpecialCollisionResponseCases; + object.m_bCameraToAvoidThisObject = objinfo->m_bCameraToAvoidThisObject; + if(object.m_fMass >= 99998.0){ + object.bInfiniteMass = true; + object.bAffectedByGravity = false; + object.m_flagB2 = true; + } +} + +STARTPATCHES + InjectHook(0x4BC0E0, CObjectData::Initialise, PATCH_JUMP); + InjectHook(0x4BC270, CObjectData::SetObjectData, PATCH_JUMP); +ENDPATCHES diff --git a/src/objects/ObjectData.h b/src/objects/ObjectData.h new file mode 100644 index 00000000..e3a5c1bd --- /dev/null +++ b/src/objects/ObjectData.h @@ -0,0 +1,27 @@ +#pragma once + +class CObject; + +class CObjectInfo +{ +public: + float m_fMass; + float m_fTurnMass; + float m_fAirResistance; + float m_fElasticity; + float m_fBuoyancy; + float m_fUprootLimit; + float m_fCollisionDamageMultiplier; + uint8 m_nCollisionDamageEffect; + uint8 m_nSpecialCollisionResponseCases; + bool m_bCameraToAvoidThisObject; +}; +static_assert(sizeof(CObjectInfo) == 0x20, "CObjectInfo: error"); + +class CObjectData +{ + static CObjectInfo ms_aObjectInfo[NUMOBJECTINFO]; +public: + static void Initialise(const char *filename); + static void SetObjectData(int32 modelId, CObject &object); +}; diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp new file mode 100644 index 00000000..cf6e84bf --- /dev/null +++ b/src/objects/ParticleObject.cpp @@ -0,0 +1,23 @@ +#include "common.h" +#include "patcher.h" +#include "ParticleObject.h" + +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, float size, bool remove) { EAXJMP(0x4BC520); } +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove) { EAXJMP(0x4BC570); } + +// Converted from static void __cdecl CParticleObject::Initialise() 0x42C760 +void CParticleObject::Initialise() +{ + ((void (__cdecl *)())0x4BC440)(); +} + +// Converted from static void __cdecl CParticleObject::UpdateAll() 0x4BCA30 +void CParticleObject::UpdateAll() +{ + ((void (__cdecl *)())0x4BCA30)(); +} + +STARTPATCHES + InjectHook(0x4BC420, &CParticleObject::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/objects/ParticleObject.h b/src/objects/ParticleObject.h new file mode 100644 index 00000000..def7b7de --- /dev/null +++ b/src/objects/ParticleObject.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Placeable.h" + +enum eParticleObjectType +{ + POBJECT_PAVEMENT_STEAM, + POBJECT_PAVEMENT_STEAM_SLOWMOTION, + POBJECT_WALL_STEAM, + POBJECT_WALL_STEAM_SLOWMOTION, + POBJECT_DARK_SMOKE, + POBJECT_FIRE_HYDRANT, + POBJECT_CAR_WATER_SPLASH, + POBJECT_PED_WATER_SPLASH, + POBJECT_SPLASHES_AROUND, + POBJECT_SMALL_FIRE, + POBJECT_BIG_FIRE, + POBJECT_DRY_ICE, + POBJECT_DRY_ICE_SLOWMOTION, + POBJECT_FIRE_TRAIL, + POBJECT_SMOKE_TRAIL, + POBJECT_FIREBALL_AND_SMOKE, + POBJECT_ROCKET_TRAIL, + POBJECT_EXPLOSION_ONCE, + POBJECT_CATALINAS_GUNFLASH, + POBJECT_CATALINAS_SHOTGUNFLASH, +}; + +class CParticleObject : CPlaceable +{ +public: + static void AddObject(uint16 type, const CVector &pos, bool remove); + static void AddObject(uint16 type, const CVector &pos, float size, bool remove); + static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove); + static void Initialise(); + static void UpdateAll(); + + void dtor() { this->CParticleObject::~CParticleObject(); } +}; diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp new file mode 100644 index 00000000..e21323de --- /dev/null +++ b/src/objects/Projectile.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "patcher.h" +#include "Projectile.h" + +STARTPATCHES + InjectHook(0x4BFED0, &CProjectile::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/objects/Projectile.h b/src/objects/Projectile.h new file mode 100644 index 00000000..a8e826b6 --- /dev/null +++ b/src/objects/Projectile.h @@ -0,0 +1,11 @@ +#pragma once + +#pragma once + +#include "Object.h" + +class CProjectile : public CObject +{ +public: + void dtor(void) { this->CProjectile::~CProjectile(); } +}; diff --git a/src/patcher.cpp b/src/patcher.cpp deleted file mode 100644 index 5fdbdf8b..00000000 --- a/src/patcher.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "common.h" -#include "patcher.h" - -StaticPatcher *StaticPatcher::ms_head; - -StaticPatcher::StaticPatcher(Patcher func) - : m_func(func) -{ - m_next = ms_head; - ms_head = this; -} - -void -StaticPatcher::Apply() -{ - StaticPatcher *current = ms_head; - while(current){ - current->Run(); - current = current->m_next; - } - ms_head = nil; -} diff --git a/src/patcher.h b/src/patcher.h deleted file mode 100644 index 87a6bea4..00000000 --- a/src/patcher.h +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once - -#define WRAPPER __declspec(naked) -#define DEPRECATED __declspec(deprecated) -#define EAXJMP(a) { _asm mov eax, a _asm jmp eax } -#define VARJMP(a) { _asm jmp a } -#define WRAPARG(a) UNREFERENCED_PARAMETER(a) - -#define NOVMT __declspec(novtable) -#define SETVMT(a) *((DWORD_PTR*)this) = (DWORD_PTR)a - -#include -#include - -#include "common.h" - -enum -{ - PATCH_CALL, - PATCH_JUMP, - PATCH_NOTHING, -}; - -enum -{ - III_10 = 1, - III_11, - III_STEAM, - VC_10, - VC_11, - VC_STEAM -}; - -extern int gtaversion; - -class StaticPatcher -{ -private: - using Patcher = void(*)(); - - Patcher m_func; - StaticPatcher *m_next; - static StaticPatcher *ms_head; - - void Run() { m_func(); } -public: - StaticPatcher(Patcher func); - static void Apply(); -}; - -template -inline T AddressByVersion(uint32_t addressIII10, uint32_t addressIII11, uint32_t addressIIISteam, uint32_t addressvc10, uint32_t addressvc11, uint32_t addressvcSteam) -{ - if(gtaversion == -1){ - if(*(uint32_t*)0x5C1E75 == 0xB85548EC) gtaversion = III_10; - else if(*(uint32_t*)0x5C2135 == 0xB85548EC) gtaversion = III_11; - else if(*(uint32_t*)0x5C6FD5 == 0xB85548EC) gtaversion = III_STEAM; - else if(*(uint32_t*)0x667BF5 == 0xB85548EC) gtaversion = VC_10; - else if(*(uint32_t*)0x667C45 == 0xB85548EC) gtaversion = VC_11; - else if(*(uint32_t*)0x666BA5 == 0xB85548EC) gtaversion = VC_STEAM; - else gtaversion = 0; - } - switch(gtaversion){ - case III_10: - return (T)addressIII10; - case III_11: - return (T)addressIII11; - case III_STEAM: - return (T)addressIIISteam; - case VC_10: - return (T)addressvc10; - case VC_11: - return (T)addressvc11; - case VC_STEAM: - return (T)addressvcSteam; - default: - return (T)0; - } -} - -inline bool -is10(void) -{ - return gtaversion == III_10 || gtaversion == VC_10; -} - -inline bool -isIII(void) -{ - return gtaversion >= III_10 && gtaversion <= III_STEAM; -} - -inline bool -isVC(void) -{ - return gtaversion >= VC_10 && gtaversion <= VC_STEAM; -} - -#define PTRFROMCALL(addr) (uint32_t)(*(uint32_t*)((uint32_t)addr+1) + (uint32_t)addr + 5) -#define INTERCEPT(saved, func, a) \ -{ \ - saved = PTRFROMCALL(a); \ - InjectHook(a, func); \ -} - -template inline void -Patch(AT address, T value) -{ - DWORD dwProtect[2]; - VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(T*)address = value; - VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); -} - -template inline void -Nop(AT address, unsigned int nCount) -{ - DWORD dwProtect[2]; - VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - memset((void*)address, 0x90, nCount); - VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); -} - -template inline void -ClearCC(AT address, unsigned int nCount) -{ - DWORD dwProtect[2]; - VirtualProtect((void*)address, nCount, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - memset((void*)address, 0xCC, nCount); - VirtualProtect((void*)address, nCount, dwProtect[0], &dwProtect[1]); -} - -extern std::vector usedAddresses; - -template inline void -InjectHook(AT address, HT hook, unsigned int nType=PATCH_NOTHING) -{ - if(std::any_of(usedAddresses.begin(), usedAddresses.end(), - [address](AT value) { return (int32)value == address; })) { - debug("Used address %#06x twice when injecting hook\n", address); - } - - usedAddresses.push_back((int32)address); - - DWORD dwProtect[2]; - switch ( nType ) - { - case PATCH_JUMP: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE9; - break; - case PATCH_CALL: - VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - *(BYTE*)address = 0xE8; - break; - default: - VirtualProtect((void*)((DWORD)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); - break; - } - DWORD dwHook; - _asm - { - mov eax, hook - mov dwHook, eax - } - - *(ptrdiff_t*)((DWORD)address + 1) = (DWORD)dwHook - (DWORD)address - 5; - if ( nType == PATCH_NOTHING ) - VirtualProtect((void*)((DWORD)address + 1), 4, dwProtect[0], &dwProtect[1]); - else - VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); -} - -inline void ExtractCall(void *dst, uint32_t a) -{ - *(uint32_t*)dst = (uint32_t)(*(uint32_t*)(a+1) + a + 5); -} -template -inline void InterceptCall(void *dst, T func, uint32_t a) -{ - ExtractCall(dst, a); - InjectHook(a, func); -} -template -inline void InterceptVmethod(void *dst, T func, uint32_t a) -{ - *(uint32_t*)dst = *(uint32_t*)a; - Patch(a, func); -} - -#define STARTPATCHES static StaticPatcher Patcher([](){ -#define ENDPATCHES }); diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp new file mode 100644 index 00000000..a4881e71 --- /dev/null +++ b/src/peds/CivilianPed.cpp @@ -0,0 +1,19 @@ +#include "common.h" +#include "patcher.h" +#include "CivilianPed.h" + +WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } + +CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) +{ + CPed::SetModelIndex(mi); + for (int i = 0; i < 10; i++) + { + m_nearPeds[i] = nil; + } +} + +STARTPATCHES + InjectHook(0x4BFF30, &CCivilianPed::ctor, PATCH_JUMP); + InjectHook(0x4BFFC0, &CCivilianPed::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h new file mode 100644 index 00000000..8d004ad7 --- /dev/null +++ b/src/peds/CivilianPed.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Ped.h" + +class CCivilianPed : public CPed +{ +public: + CCivilianPed(int, int); + virtual ~CCivilianPed(void) { } + + virtual void ProcessControl(void); + + CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); }; + void dtor(void) { this->CCivilianPed::~CCivilianPed(); } +}; +static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp new file mode 100644 index 00000000..041185ee --- /dev/null +++ b/src/peds/CopPed.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "patcher.h" +#include "CopPed.h" + +CCopPed::~CCopPed() +{ + ClearPursuit(); +} + +WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); } + +STARTPATCHES + InjectHook(0x4C13E0, &CCopPed::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h new file mode 100644 index 00000000..b938dfc2 --- /dev/null +++ b/src/peds/CopPed.h @@ -0,0 +1,73 @@ +#pragma once +#include "Ped.h" + +enum eCrimeType +{ + CRIME_NONE, + CRIME_POSSESSION_GUN, + CRIME_HIT_PED, + CRIME_HIT_COP, + CRIME_SHOOT_PED, + CRIME_SHOOT_COP, + CRIME_STEAL_CAR, + CRIME_RUN_REDLIGHT, + CRIME_RECKLESS_DRIVING, + CRIME_SPEEDING, + CRIME_RUNOVER_PED, + CRIME_RUNOVER_COP, + CRIME_SHOOT_HELI, + CRIME_PED_BURNED, + CRIME_COP_BURNED, + CRIME_VEHICLE_BURNED, + CRIME_DESTROYED_CESSNA, +}; + +enum eCopType +{ + COP_STREET = 0, + COP_FBI = 1, + COP_SWAT = 2, + COP_ARMY = 3, +}; + +class CCrime +{ +public: + eCrimeType m_eCrimeType; + CEntity *m_pVictim; + int32 m_nCrimeTime; + CVector m_vecCrimePos; + int8 m_bReported; + int8 m_bMultiplier; + int8 pad_20[2]; +}; + +class CCopPed : public CPed +{ +public: + int16 m_wRoadblockNode; + int8 field_1342; + int8 field_1343; + float m_fDistanceToTarget; + int8 m_bIsInPursuit; + int8 m_bIsDisabledCop; + int8 field_1350; + int8 field_1351; + int8 m_bZoneDisabledButClose; + int8 m_bZoneDisabled; + int8 field_1354; + int8 field_1355; + int32 field_1356; + eCopType m_nCopType; + int8 field_1364; + int8 field_1365; + int8 field_1366; + int8 field_1367; + + ~CCopPed(); + void dtor(void) { this->CCopPed::~CCopPed(); } + + void ClearPursuit(void); +}; + +static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error"); diff --git a/src/peds/DummyPed.h b/src/peds/DummyPed.h new file mode 100644 index 00000000..af633dc4 --- /dev/null +++ b/src/peds/DummyPed.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Dummy.h" + +// actually unused +class CDummyPed : CDummy +{ + int32 pedType; + int32 unknown; +}; +static_assert(sizeof(CDummyPed) == 0x70, "CDummyPed: error"); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp new file mode 100644 index 00000000..7b847896 --- /dev/null +++ b/src/peds/EmergencyPed.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "patcher.h" +#include "EmergencyPed.h" + +STARTPATCHES +InjectHook(0x4C2EF0, &CEmergencyPed::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h new file mode 100644 index 00000000..fa07f3ee --- /dev/null +++ b/src/peds/EmergencyPed.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Ped.h" + +class CEmergencyPed : public CPed +{ +public: + // 0x53C + uint8 stuff[24]; + + void dtor(void) { this->CEmergencyPed::~CEmergencyPed(); } +}; +static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp new file mode 100644 index 00000000..80ef53ee --- /dev/null +++ b/src/peds/Ped.cpp @@ -0,0 +1,2949 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Pools.h" +#include "Particle.h" +#include "Stats.h" +#include "World.h" +#include "DMAudio.h" +#include "RpAnimBlend.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "General.h" +#include "VisibilityPlugins.h" +#include "AudioManager.h" +#include "HandlingMgr.h" +#include "Replay.h" +#include "PedPlacement.h" +#include "Shadows.h" +#include "Weather.h" +#include "ZoneCull.h" +#include "Population.h" +#include "Renderer.h" +#include "Lights.h" +#include "PointLights.h" +#include "Pad.h" + +WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } +WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); } +WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4D37D0); } +WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } +WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); } +WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); } +WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } +WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } +WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } +WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); } +WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } +WRAPPER void CPed::Render(void) { EAXJMP(0x4D03F0); } +WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); } +WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } +WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); } +WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } +WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } + +bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; +bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; +bool &CPed::bPedCheat3 = *(bool*)0x95CD59; + +uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98; + +CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030; +CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C; +CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048; + +void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); } +void *CPed::operator new(size_t sz, int handle) { return CPools::GetPedPool()->New(handle); } +void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); } +void CPed::operator delete(void *p, int handle) { CPools::GetPedPool()->Delete((CPed*)p); } + +CPed::~CPed(void) +{ + CWorld::Remove(this); + CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); + if (bInVehicle && m_pMyVehicle){ + uint8 door_flag = GetVehEnterExitFlag(m_vehEnterType); + if (m_pMyVehicle->pDriver == this) + m_pMyVehicle->pDriver = nil; + else { + for (int i = 0; i < m_pMyVehicle->m_nNumMaxPassengers; i++) { + if (m_pMyVehicle->pPassengers[i] == this) + m_pMyVehicle->pPassengers[i] = nil; + } + } + if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) + m_pMyVehicle->m_nGettingOutFlags &= ~door_flag; + bInVehicle = false; + m_pMyVehicle = nil; + }else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK){ + QuitEnteringCar(); + } + if (m_pFire) + m_pFire->Extinguish(); + CPopulation::UpdatePedCount(m_nPedType, true); + DMAudio.DestroyEntity(m_audioEntityId); +} + +void +CPed::FlagToDestroyWhenNextProcessed(void) +{ + bRemoveFromWorld = true; + if (!bInVehicle || !m_pMyVehicle) + return; + if (m_pMyVehicle->pDriver == this){ + m_pMyVehicle->pDriver = nil; + if (IsPlayer() && m_pMyVehicle->m_status != STATUS_WRECKED) + m_pMyVehicle->m_status = STATUS_ABANDONED; + }else{ + m_pMyVehicle->RemovePassenger(this); + } + bInVehicle = false; + m_pMyVehicle = nil; + if (CharCreatedBy == MISSION_CHAR) + m_nPedState = PED_DEAD; + else + m_nPedState = PED_NONE; + m_pVehicleAnim = nil; +} + +static char ObjectiveText[34][28] = { + "No Obj", + "Wait on Foot", + "Flee on Foot Till Safe", + "Guard Spot", + "Guard Area", + "Wait in Car", + "Wait in Car then Getout", + "Kill Char on Foot", + "Kill Char Any Means", + "Flee Char on Foot Till Safe", + "Flee Char on Foot Always", + "GoTo Char on Foot", + "Follow Char in Formation", + "Leave Car", + "Enter Car as Passenger", + "Enter Car as Driver", + "Follow Car in Car", + "Fire at Obj from Vehicle", + "Destroy Obj", + "Destroy Car", + "GoTo Area Any Means", + "GoTo Area on Foot", + "Run to Area", + "GoTo Area in Car", + "Follow Car on Foot Woffset", + "Guard Attack", + "Set Leader", + "Follow Route", + "Solicit", + "Take Taxi", + "Catch Train", + "Buy IceCream", + "Steal Any Car", + "Mug Char", +}; + +static char StateText[56][18] = { + "None", // 1 + "Idle", + "Look Entity", + "Look Heading", + "Wander Range", + "Wander Path", + "Seek Pos", + "Seek Entity", + "Flee Pos", + "Flee Entity", + "Pursue", + "Follow Path", + "Sniper Mode", + "Rocket Mode", + "Dummy", + "Pause", + "Attack", + "Fight", + "Face Phone", + "Make Call", + "Chat", + "Mug", + "AimGun", + "AI Control", + "Seek Car", + "Seek InBoat", + "Follow Route", + "C.P.R.", + "Solicit", + "Buy IceCream", + "Investigate", + "Step away", + "STATES_NO_AI", + "On Fire", + "Jump", + "Fall", + "GetUp", + "Stagger", + "Dive away", + "STATES_NO_ST", + "Enter Train", + "Exit Train", + "Arrest Plyr", + "Driving", + "Passenger", + "Taxi Passngr", + "Open Door", + "Die", + "Dead", + "CarJack", + "Drag fm Car", + "Enter Car", + "Steal Car", + "Exit Car", + "Hands Up", + "Arrested", +}; + +static char PersonalityTypeText[32][18] = { + "Player", + "Cop", + "Medic", + "Fireman", + "Gang 1", + "Gang 2", + "Gang 3", + "Gang 4", + "Gang 5", + "Gang 6", + "Gang 7", + "Street Guy", + "Suit Guy", + "Sensible Guy", + "Geek Guy", + "Old Guy", + "Tough Guy", + "Street Girl", + "Suit Girl", + "Sensible Girl", + "Geek Girl", + "Old Girl", + "Tough Girl", + "Tramp", + "Tourist", + "Prostitute", + "Criminal", + "Busker", + "Taxi Driver", + "Psycho", + "Steward", + "Sports Fan", +}; + +static char WaitStateText[21][16] = { + "No Wait", + "Traffic Lights", + "Pause CrossRoad", + "Look CrossRoad", + "Look Ped", + "Look Shop", + "Look Accident", + "FaceOff Gang", + "Double Back", + "Hit Wall", + "Turn 180deg", + "Surprised", + "Ped Stuck", + "Look About", + "Play Duck", + "Play Cower", + "Play Taxi", + "Play HandsUp", + "Play HandsCower", + "Play Chat", + "Finish Flee", +}; + +CPed::CPed(uint32 pedType) : m_pedIK(this) +{ + m_type = ENTITY_TYPE_PED; + bPedPhysics = true; + bUseCollisionRecords = true; + + m_vecAnimMoveDelta.x = 0.0; + m_vecAnimMoveDelta.y = 0.0; + m_fHealth = 100.0f; + m_fArmour = 0.0f; + m_nPedType = pedType; + field_520 = 0; + m_talkTimer = 0; + m_talkTypeLast = 167; + m_talkType = 167; + m_objective = OBJECTIVE_NONE; + m_prevObjective = OBJECTIVE_NONE; + CharCreatedBy = RANDOM_CHAR; + m_leader = nil; + m_pedInObjective = nil; + m_carInObjective = nil; + bInVehicle = 0; + m_pMyVehicle = nil; + m_pVehicleAnim = nil; + m_vecOffsetSeek.x = 0.0; + m_vecOffsetSeek.y = 0.0; + m_vecOffsetSeek.z = 0.0; + m_pedFormation = 0; + m_lastThreatTimer = 0; + m_nPedStateTimer = 0; + m_actionX = 0; + m_actionY = 0; + m_phoneTalkTimer = 0; + m_stateUnused = 0; + m_leaveCarTimer = 0; + m_getUpTimer = 0; + m_attackTimer = 0; + m_timerUnused = 0; + m_lookTimer = 0; + m_standardTimer = 0; + m_lastHitTime = 0; + m_hitRecoverTimer = 0; + field_4E8 = 0; + m_moved = CVector2D(0.0f, 0.0f); + m_fRotationCur = 0.0f; + m_headingRate = 15.0f; + m_fRotationDest = 0.0f; + m_vehEnterType = VEHICLE_ENTER_FRONT_LEFT; + m_walkAroundType = 0; + m_pCurrentPhysSurface = nil; + m_vecOffsetFromPhysSurface = CVector(0.0f, 0.0f, 0.0f); + m_pSeekTarget = nil; + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_wepSkills = 0; + field_318 = 1.0f; + field_31C = 0; + m_phoneId = -1; + m_lastAccident = 0; + m_fleeFrom = nil; + m_fleeFromPosX = 0; + m_fleeFromPosY = 0; + m_fleeTimer = 0; + m_vecSeekPosEx = CVector(0.0f, 0.0f, 0.0f); + m_seekExAngle = 0.0f; + m_nWaitState = WAITSTATE_FALSE; + m_nWaitTimer = 0; + m_pCollidingEntity = nil; + m_nPedState = PED_IDLE; + m_nLastPedState = PED_NONE; + m_nMoveState = PEDMOVE_STILL; + m_nStoredActionState = 0; + m_pFire = nil; + m_pPointGunAt = nil; + m_pLookTarget = nil; + m_fLookDirection = 0.0f; + m_pCurSurface = nil; + m_targetUnused = nil; + m_nPathNodes = 0; + m_nCurPathNode = 0; + m_nPathState = 0; + m_pNextPathNode = nil; + m_pLastPathNode = nil; + m_routeLastPoint = -1; + m_routePoints = 0; + m_routePos = 0; + m_routeType = 0; + m_bodyPartBleeding = -1; + + m_fMass = 70.0f; + m_fTurnMass = 100.0f; + m_fAirResistance = 0.4f / m_fMass; + m_fElasticity = 0.05f; + + bIsStanding = false; + m_ped_flagA2 = false; + m_ped_flagA4 = false; + bIsPointingGunAt = false; + bIsLooking = false; + m_ped_flagA20 = false; + bIsRestoringLook = false; + bIsAimingGun = false; + + bIsRestoringGun = false; + bCanPointGunAtTarget = false; + bIsTalking = false; + bIsInTheAir = false; + bIsLanding = false; + m_ped_flagB20 = false; + m_ped_flagB40 = false; + m_ped_flagB80 = false; + + m_ped_flagC1 = false; + bRespondsToThreats = true; + m_ped_flagC4 = true; + m_ped_flagC8 = false; + m_ped_flagC10 = false; + m_ped_flagC20 = false; + m_ped_flagC40 = false; + m_ped_flagC80 = false; + + m_ped_flagD1 = false; + m_ped_flagD2 = false; + m_ped_flagD4 = false; + m_ped_flagD8 = false; + m_ped_flagD10 = false; + m_ped_flagD20 = false; + m_ped_flagD40 = false; + m_ped_flagD80 = false; + + m_ped_flagE1 = false; + m_ped_flagE2 = false; + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + bIsDucking = false; + m_ped_flagE20 = false; + bDoBloodyFootprints = false; + m_ped_flagE80 = false; + + m_ped_flagF1 = false; + m_ped_flagF2 = false; + m_ped_flagF4 = false; + m_ped_flagF8 = false; + m_ped_flagF10 = false; + m_ped_flagF20 = false; + m_ped_flagF40 = false; + m_ped_flagF80 = false; + + m_ped_flagG1 = false; + m_ped_flagG2 = true; + m_ped_flagG4 = false; + m_ped_flagG8 = false; + m_ped_flagG10 = false; + m_ped_flagG20 = false; + m_ped_flagG40 = false; + m_ped_flagG80 = false; + + m_ped_flagH1 = false; + m_ped_flagH2 = false; + m_ped_flagH4 = false; + m_ped_flagH8 = false; + m_ped_flagH10 = false; + m_ped_flagH20 = false; + m_ped_flagH40 = false; + m_ped_flagH80 = false; + + m_ped_flagI1 = false; + m_ped_flagI2 = false; + m_ped_flagI4 = false; + bRecordedForReplay = false; + m_ped_flagI10 = false; +#ifdef KANGAROO_CHEAT + m_ped_flagI80 = false; +#endif + + if ((CGeneral::GetRandomNumber() & 3) == 0) + m_ped_flagD1 = true; + + m_audioEntityId = DMAudio.CreateEntity(0, this); + DMAudio.SetEntityStatus(m_audioEntityId, 1); + m_fearFlags = CPedType::GetThreats(m_nPedType); + m_threatEntity = nil; + m_eventOrThread = CVector2D(0.0f, 0.0f); + m_pEventEntity = nil; + m_fAngleToEvent = 0.0f; + m_numNearPeds = 0; + + for (int i = 0; i < 10; i++) + { + m_nearPeds[i] = nil; + if (i < 8) { + m_pPathNodesStates[i] = nil; + } + } + m_maxWeaponTypeAllowed = 0; + m_currentWeapon = 0; + m_storedWeapon = NO_STORED_WEAPON; + + for(int i = 0; i < NUM_PED_WEAPONTYPES; i++) + { + CWeapon &weapon = GetWeapon(i); + weapon.m_eWeaponType = WEAPONTYPE_UNARMED; + weapon.m_eWeaponState = WEAPONSTATE_READY; + weapon.m_nAmmoInClip = 0; + weapon.m_nAmmoTotal = 0; + weapon.m_nTimer = 0; + } + + m_lastHitState = 0; + GiveWeapon(WEAPONTYPE_UNARMED, 0); + m_wepAccuracy = 60; + m_lastWepDam = -1; + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + m_wepModelID = -1; + CPopulation::UpdatePedCount(m_nPedType, false); +} + +uint32 +CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) +{ + CWeapon &weapon = GetWeapon(weaponType); + + if (HasWeapon(weaponType)) { + if (weapon.m_nAmmoTotal + ammo > 99999) + weapon.m_nAmmoTotal = 99999; + else + weapon.m_nAmmoTotal += ammo; + + weapon.Reload(); + } else { + weapon.Initialise(weaponType, ammo); + // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. + m_maxWeaponTypeAllowed++; + } + if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) + weapon.m_eWeaponState = WEAPONSTATE_READY; + + return weaponType; +} + +static RwObject* +RemoveAllModelCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { + RpClumpRemoveAtomic(atomic->clump, atomic); + RpAtomicDestroy(atomic); + } + return object; +} + +static PedOnGroundState +CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround) +{ + PedOnGroundState stateToReturn; + float angleToFace; + CPed *currentPed = nil; + PedState currentPedState; + CPed *pedOnTheFloor = nil; + CPed *deadPed = nil; + CPed *pedBelow = nil; + bool foundDead = false; + bool foundOnTheFloor = false; + bool foundBelow = false; + float angleDiff; + float distance; + + if (!CGame::nastyGame) + return NO_PED; + + for (int currentPedId = 0; currentPedId < player->m_numNearPeds; currentPedId++) { + + currentPed = player->m_nearPeds[currentPedId]; + + CVector posDifference = currentPed->GetPosition() - player->GetPosition(); + distance = posDifference.Magnitude(); + + if (distance < 2.0f) { + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + currentPed->GetPosition().x, currentPed->GetPosition().y, + player->GetPosition().x, player->GetPosition().y); + + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + player->m_fRotationCur = CGeneral::LimitRadianAngle(player->m_fRotationCur); + + angleDiff = fabs(angleToFace - player->m_fRotationCur); + + if (angleDiff > PI) + angleDiff = 2 * PI - angleDiff; + + currentPedState = currentPed->m_nPedState; + + if (currentPedState == PED_FALL || currentPedState == PED_GETUP || currentPedState == PED_DIE || currentPedState == PED_DEAD) { + if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { + if (currentPedState == PED_DEAD) { + foundDead = 1; + if (!deadPed) + deadPed = currentPed; + } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { + foundOnTheFloor = 1; + if (!pedOnTheFloor) + pedOnTheFloor = currentPed; + } + } + } else if ((distance >= 0.8f || angleDiff >= DEGTORAD(75.0f)) + && (distance >= 1.3f || angleDiff >= DEGTORAD(55.0f)) + && (distance >= 1.7f || angleDiff >= DEGTORAD(35.0f)) + && (distance >= 2.0f || angleDiff >= DEGTORAD(30.0f))) { + + if (angleDiff < DEGTORAD(75.0f)) { + foundBelow = 1; + if (!pedBelow) + pedBelow = currentPed; + } + } else { + foundBelow = 1; + pedBelow = currentPed; + break; + } + } + } + + if (foundOnTheFloor) { + currentPed = pedOnTheFloor; + stateToReturn = PED_ON_THE_FLOOR; + } else if (foundDead) { + currentPed = deadPed; + stateToReturn = PED_DEAD_ON_THE_FLOOR; + } else if (foundBelow) { + currentPed = pedBelow; + stateToReturn = PED_BELOW_PLAYER; + } else { + currentPed = nil; + stateToReturn = NO_PED; + } + + if (pedOnGround) + * pedOnGround = currentPed; + + return stateToReturn; +} + +bool +CPed::IsPlayer(void) +{ + return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType== PEDTYPE_PLAYER2 || + m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; +} + +bool +CPed::UseGroundColModel(void) +{ + return m_nPedState == PED_FALL || + m_nPedState == PED_DIVE_AWAY || + m_nPedState == PED_DIE || + m_nPedState == PED_DEAD; +} + +bool +CPed::CanSetPedState(void) +{ + return m_nPedState != PED_DIE && m_nPedState != PED_ARRESTED && + m_nPedState != PED_ENTER_CAR && m_nPedState != PED_DEAD && m_nPedState != PED_CARJACK && m_nPedState != PED_STEAL_CAR; +} + +bool +CPed::IsPedInControl(void) +{ + return m_nPedState <= PED_STATES_NO_AI + && !bIsInTheAir && !bIsLanding + && m_fHealth > 0.0f; +} + +bool +CPed::CanStrafeOrMouseControl(void) +{ + return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || + m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; +} + +void +CPed::AddWeaponModel(int id) +{ + RpAtomic *atm; + + if (id != -1) { + atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atm)); + RpAtomicSetFrame(atm, GetNodeFrame(PED_HANDR)); + RpClumpAddAtomic((RpClump*)m_rwObject, atm); + m_wepModelID = id; + } +} + +void +CPed::AimGun(void) +{ + RwV3d pos; + CVector vector; + + if (m_pSeekTarget) { + if (m_pSeekTarget->IsPed()) { + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_TORSO); + vector.x = pos.x; + vector.y = pos.y; + vector.z = pos.z; + } else { + vector = *(m_pSeekTarget->GetPosition()); + } + Say(SOUND_PED_ATTACK); + + bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(&vector); + if (m_pLookTarget != m_pSeekTarget) { + SetLookFlag(m_pSeekTarget, 1); + } + + } else { + if (IsPlayer()) { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); + } else { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); + } + } +} + +void +CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) +{ + CVector pos2 = CVector( + pos.x, + pos.y, + pos.z + 0.1f + ); + + if (!CPed::IsPlayer() || evenOnPlayer) { + ++CStats::HeadShots; + + // BUG: This condition will always return true. + if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { + CPed::SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + + m_ped_flagC20 = true; + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; + + CParticle::AddParticle(PARTICLE_TEST, pos2, + CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); + + if (CEntity::GetIsOnScreen()) { + for(int i=0; i < 32; i++) { + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, + pos2, CVector(0.0f, 0.0f, 0.03f), + nil, 0.0f, 0, 0, 0, 0); + } + + for (int i = 0; i < 16; i++) { + CParticle::AddParticle(PARTICLE_DEBRIS2, + pos2, + CVector(0.0f, 0.0f, 0.01f), + nil, 0.0f, 0, 0, 0, 0); + } + } + } +} + +void +CPed::RemoveBodyPart(PedNode nodeId, int8 unk) +{ + RwFrame *frame; + RwV3d pos; + + frame = GetNodeFrame(nodeId); + if (frame) { + if (CGame::nastyGame) { + if (nodeId != PED_HEAD) + CPed::SpawnFlyingComponent(nodeId, unk); + + RecurseFrameChildrenVisibilityCB(frame, nil); + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + + for (frame = RwFrameGetParent(frame); frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints(&pos, &pos, 1, RwFrameGetMatrix(frame)); + + if (CEntity::GetIsOnScreen()) { + CParticle::AddParticle(PARTICLE_TEST, pos, + CVector(0.0f, 0.0f, 0.0f), + nil, 0.2f, 0, 0, 0, 0); + + for (int i = 0; i < 16; i++) { + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, + pos, + CVector(0.0f, 0.0f, 0.03f), + nil, 0.0f, 0, 0, 0, 0); + } + } + m_ped_flagC20 = true; + m_bodyPartBleeding = nodeId; + } + } else { + printf("Trying to remove ped component"); + } +} + +RwObject* +CPed::SetPedAtomicVisibilityCB(RwObject *object, void *data) +{ + if (data == nil) + RpAtomicSetFlags(object, 0); + return object; +} + +RwFrame* +CPed::RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data) +{ + RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); + RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); + return frame; +} + +void +CPed::SetLookFlag(CEntity *target, bool unknown) +{ + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = target; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + m_fLookDirection = 999999.0f; + m_lookTimer = 0; + m_ped_flagA20 = unknown; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::FLAG_2; + } + } +} + +void +CPed::SetLookFlag(float direction, bool unknown) +{ + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = nil; + m_fLookDirection = direction; + m_lookTimer = 0; + m_ped_flagA20 = unknown; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::FLAG_2; + } + } +} + +void +CPed::SetLookTimer(int time) +{ + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +bool +CPed::OurPedCanSeeThisOne(CEntity *target) +{ + CColPoint colpoint; + CEntity *ent; + + CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(this->GetPosition()); + + // Check if target is behind ped + if (DotProduct2D(dist, CVector2D(this->GetForward())) < 0.0f) + return false; + + // Check if target is too far away + if (dist.Magnitude() >= 40.0f) + return false; + + // Check line of sight from head + CVector headPos = this->GetPosition(); + headPos.z += 1.0f; + return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); +} + +void +CPed::Avoid(void) +{ + CPed *nearestPed; + + if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) + return; + + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + + if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { + nearestPed = m_nearPeds[0]; + + if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { + + // Check if this ped wants to avoid the nearest one + if (CPedType::GetAvoid(this->m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { + + // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. + // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. + + // Game converts from radians to degress and back again here, doesn't make much sense + CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); + forward.Normalise(); // this is kinda pointless + + // Move forward 1.25 meters + CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; + + // Get distance to ped we want to avoid + CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; + + if (distToPed.Magnitude() <= 1.0f && CPed::OurPedCanSeeThisOne((CEntity*)nearestPed)) { + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) + % 1000 / 5; + + m_fRotationDest += DEGTORAD(45.0f); + if (!bIsLooking) { + CPed::SetLookFlag(nearestPed, 0); + CPed::SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); + } + } + } + } + } + } +} + +void +CPed::ClearAimFlag(void) +{ + if (bIsAimingGun) { + bIsAimingGun = false; + bIsRestoringGun = true; + m_pedIK.m_flags &= ~CPedIK:: FLAG_4; + } + + if (CPed::IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0; +} + +void +CPed::ClearLookFlag(void) { + if (bIsLooking) { + bIsLooking = false; + bIsRestoringLook = true; + m_ped_flagI1 = false; + + m_pedIK.m_flags &= ~CPedIK::FLAG_2; + if (CPed::IsPlayer()) + m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; + else + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + + if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { + CPed::RestorePreviousState(); + CPed::ClearLookFlag(); + } + } +} + +bool +CPed::IsPedHeadAbovePos(float zOffset) +{ + RwMatrix mat; + + CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat); + return zOffset + GetPosition().z < RwMatrixGetPos(&mat)->z; +} + +void +CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) +{ + CWeaponInfo *currentWeapon; + CAnimBlendAssociation *newAnim; + CPed *ped = (CPed*)arg; + + if (attackAssoc) { + switch (attackAssoc->animId) { + case ANIM_WEAPON_START_THROW: + if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1380) && ped->IsPlayer()) { + attackAssoc->blendDelta = -1000.0f; + newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROWU); + } else { + attackAssoc->blendDelta = -1000.0f; + newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROW); + } + + newAnim->SetFinishCallback(FinishedAttackCB, ped); + return; + + case ANIM_FIGHT_PPUNCH: + attackAssoc->blendDelta = -8.0f; + attackAssoc->flags |= ASSOC_DELETEFADEDOUT; + ped->ClearAttack(); + return; + + case ANIM_WEAPON_THROW: + case ANIM_WEAPON_THROWU: + if (ped->GetWeapon()->m_nAmmoTotal > 0) { + currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); + ped->AddWeaponModel(currentWeapon->m_nModelId); + } + break; + default: + break; + } + } + + if (!ped->m_ped_flagA4) + ped->ClearAttack(); +} + +void +CPed::Attack(void) +{ + CAnimBlendAssociation *weaponAnimAssoc; + int32 weaponAnim; + float animStart; + RwFrame *frame; + eWeaponType ourWeaponType; + float weaponAnimTime; + eWeaponFire ourWeaponFire; + float animLoopEnd; + CWeaponInfo *ourWeapon; + bool lastReloadWasInFuture; + AnimationId reloadAnim; + CAnimBlendAssociation *reloadAnimAssoc; + float delayBetweenAnimAndFire; + CVector firePos; + + ourWeaponType = GetWeapon()->m_eWeaponType; + ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); + ourWeaponFire = ourWeapon->m_eWeaponFire; + weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_AnimToPlay); + lastReloadWasInFuture = m_ped_flagA4; + reloadAnimAssoc = nil; + reloadAnim = NUM_ANIMS; + delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; + weaponAnim = ourWeapon->m_AnimToPlay; + + if (weaponAnim == ANIM_WEAPON_HGUN_BODY) + reloadAnim = ANIM_HGUN_RELOAD; + else if (weaponAnim == ANIM_WEAPON_AK_BODY) + reloadAnim = ANIM_AK_RELOAD; + + if (reloadAnim != NUM_ANIMS) + reloadAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, reloadAnim); + + if (bIsDucking) + return; + + if (reloadAnimAssoc) { + if (!CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) + ClearAttack(); + + return; + } + + // BUG: We currently don't know any situation this cond. could be true. + if (CTimer::GetTimeInMilliseconds() < m_lastHitTime) + lastReloadWasInFuture = true; + + if (!weaponAnimAssoc) { + weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_Anim2ToPlay); + delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; + + // Long throw granade, molotov + if (!weaponAnimAssoc && ourWeapon->m_bThrow) { + weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU); + delayBetweenAnimAndFire = 0.2f; + } + } + if (weaponAnimAssoc) { + animStart = ourWeapon->m_fAnimLoopStart; + weaponAnimTime = weaponAnimAssoc->currentTime; + if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { + if (ourWeapon->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::FLAG_4; + else + m_pedIK.m_flags &= ~CPedIK::FLAG_4; + } + + if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { + if (weaponAnimAssoc->speed < 1.0f) + weaponAnimAssoc->speed = 1.0f; + + } else { + firePos = ourWeapon->m_vecFireOffset; + if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { + if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; + + firePos = GetMatrix() * firePos; + } else if (ourWeaponType != WEAPONTYPE_UNARMED) { + if (weaponAnimAssoc->animId == ANIM_KICK_FLOOR) + frame = GetNodeFrame(PED_FOOTR); + else + frame = GetNodeFrame(PED_HANDR); + + for (; frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + } else { + firePos = GetMatrix() * firePos; + } + + GetWeapon()->Fire(this, &firePos); + + if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { + RemoveWeaponModel(ourWeapon->m_nModelId); + } + if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { + SelectGunIfArmed(); + } + + if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { + // If reloading just began, start the animation + if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f); + ClearLookFlag(); + ClearAimFlag(); + m_ped_flagA4 = false; + bIsPointingGunAt = false; + m_lastHitTime = CTimer::GetTimeInMilliseconds(); + return; + } + } else { + if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); + } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); + } + + weaponAnimAssoc->speed = 0.5f; + + // BUG: We currently don't know any situation this cond. could be true. + if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) { + weaponAnimAssoc->callbackType = 0; + } + } + + lastReloadWasInFuture = false; + } + + if (ourWeaponType == WEAPONTYPE_SHOTGUN) { + weaponAnimTime = weaponAnimAssoc->currentTime; + firePos = ourWeapon->m_vecFireOffset; + + if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { + for (frame = GetNodeFrame(PED_HANDR); frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints((RwV3d*)firePos, (RwV3d*)firePos, 1, RwFrameGetMatrix(frame)); + + CVector gunshellPos( + firePos.x - 0.6f * GetForward().x, + firePos.y - 0.6f * GetForward().y, + firePos.z - 0.15f * GetUp().z + ); + + CVector2D gunshellRot( + GetRight().x, + GetRight().y + ); + + gunshellRot.Normalise(); + GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); + } + } + animLoopEnd = ourWeapon->m_fAnimLoopEnd; + if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + animLoopEnd = 3.4f/6.0f; + + weaponAnimTime = weaponAnimAssoc->currentTime; + + // Anim loop end, either start the loop again or finish the attack + if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { + + if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd + && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) + && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { + + weaponAnim = weaponAnimAssoc->animId; + if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { + if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { + weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); + } else { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + } + } else { + if (weaponAnim == ourWeapon->m_Anim2ToPlay) + weaponAnimAssoc->SetCurrentTime(0.1f); + else + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } + } else { + ClearAimFlag(); + + // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) + if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { + switch (ourWeaponType) { + case WEAPONTYPE_UZI: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_AK47: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_M16: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); + break; + default: + break; + } + } + + // Fun fact: removing this part leds to reloading flamethrower + if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { + weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; + weaponAnimAssoc->flags &= ~ASSOC_RUNNING; + weaponAnimAssoc->blendDelta = -4.0f; + } + } + } + if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) + lastReloadWasInFuture = false; + + m_ped_flagA4 = lastReloadWasInFuture; + return; + } + + if (lastReloadWasInFuture) { + if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) { + if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) { + weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + } else { + weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } + + weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this); + weaponAnimAssoc->flags |= ASSOC_RUNNING; + + if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) + weaponAnimAssoc->SetCurrentTime(0.0f); + + if (CPed::IsPlayer()) { + ((CPlayerPed*)this)->field_1376 = 0.0f; + ((CPlayerPed*)this)->field_1380 = false; + } + } + } + else + CPed::FinishedAttackCB(nil, this); +} + +void +CPed::RemoveWeaponModel(int modelId) +{ + // modelId is not used!! This function just removes the current weapon. + RwFrameForAllObjects(GetNodeFrame(PED_HANDR),RemoveAllModelCB,nil); + m_wepModelID = -1; +} + +void +CPed::SetCurrentWeapon(uint32 weaponType) +{ + CWeaponInfo *weaponInfo; + if (HasWeapon(weaponType)) { + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weaponInfo->m_nModelId); + + m_currentWeapon = weaponType; + + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(weaponInfo->m_nModelId); + } +} + +// Only used while deciding which gun ped should switch to, if no ammo left. +bool +CPed::SelectGunIfArmed(void) +{ + for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { + if (GetWeapon(i).m_nAmmoTotal > 0) { + eWeaponType weaponType = GetWeapon(i).m_eWeaponType; + if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { + SetCurrentWeapon(i); + return true; + } + } + } + SetCurrentWeapon(WEAPONTYPE_UNARMED); + return false; +} + +void +CPed::Duck(void) +{ + if (CTimer::GetTimeInMilliseconds() > m_duckTimer) + ClearDuck(); +} + +void +CPed::ClearDuck(void) +{ + CAnimBlendAssociation *animAssoc; + + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_LOW); + + if (animAssoc) { + + if (bCrouchWhenShooting) { + + if (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); + } + } + } + } else + bIsDucking = false; +} + +void +CPed::ClearPointGunAt(void) +{ + CAnimBlendAssociation *animAssoc; + CWeaponInfo *weaponInfo; + + ClearLookFlag(); + ClearAimFlag(); + bIsPointingGunAt = false; + if (m_nPedState == PED_AIM_GUN) { + RestorePreviousState(); + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_AnimToPlay); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_Anim2ToPlay); + } + if (animAssoc) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->blendDelta = -4.0; + } + } +} + +void +CPed::BeingDraggedFromCar(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId enterAnim; + bool dontRunAnim = false; + PedLineUpPhase lineUpType; + + if (!m_pVehicleAnim) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f); + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_LSIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITP); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITPLO); + } + } + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + if (m_ped_flagF10) { + enterAnim = ANIM_CAR_QJACKED; + } else if (m_pMyVehicle->bLowVehicle) { + enterAnim = ANIM_CAR_LJACKED_LHS; + } else { + enterAnim = ANIM_CAR_JACKED_LHS; + } + } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { + if (m_pMyVehicle->bLowVehicle) + enterAnim = ANIM_CAR_LJACKED_RHS; + else + enterAnim = ANIM_CAR_JACKED_RHS; + } else + dontRunAnim = true; + + + if (!dontRunAnim) + m_pVehicleAnim = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, enterAnim); + + m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this); + lineUpType = LINE_UP_TO_CAR_START; + } else if (m_pVehicleAnim->currentTime <= 1.4f) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + lineUpType = LINE_UP_TO_CAR_START; + } else { + lineUpType = LINE_UP_TO_CAR_2; + } + + LineUpPedWithCar(lineUpType); +} + +void +CPed::RestartNonPartialAnims(void) +{ + CAnimBlendAssociation *assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->flags |= ASSOC_RUNNING; + } +} + +void +CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) +{ + CAnimBlendAssociation *quickJackedAssoc; + CVehicle *vehicle; + CPed *ped = (CPed*)arg; + eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType; + + quickJackedAssoc = RpAnimBlendClumpGetAssociation((RpClump*) ped->m_rwObject, ANIM_CAR_QJACKED); + if (ped->m_nPedState != PED_ARRESTED) { + ped->m_nLastPedState = PED_NONE; + if (dragAssoc) + dragAssoc->blendDelta = -1000.0; + } + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + ped->m_pSeekTarget = nil; + vehicle = ped->m_pMyVehicle; + + vehicle->m_nGettingOutFlags &= ~GetVehEnterExitFlag(ped->m_vehEnterType); + + if (vehicle->pDriver == ped) { + vehicle->RemoveDriver(); + if (vehicle->m_nDoorLock == CARLOCK_COP_CAR) + vehicle->m_nDoorLock = CARLOCK_UNLOCKED; + + if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) + vehicle->ChangeLawEnforcerState(false); + } else { + for (int i = 0; i < vehicle->m_nNumMaxPassengers; i++) { + if (vehicle->pPassengers[i] == ped) { + vehicle->pPassengers[i] = nil; + vehicle->m_nNumPassengers--; + } + } + } + + ped->bInVehicle = false; + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + + if (quickJackedAssoc) { + dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); + } else { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + if (ped->CanSetPedState()) + CAnimManager::BlendAnimation((RpClump*) ped->m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + } + + // Only uzi can be used on cars, so previous weapon was stored + if (ped->IsPlayer() && weaponType == WEAPONTYPE_UZI) { + if (ped->m_storedWeapon != NO_STORED_WEAPON) { + ped->SetCurrentWeapon(ped->m_storedWeapon); + ped->m_storedWeapon = NO_STORED_WEAPON; + } + } else { + ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); + } + ped->m_nStoredActionState = 0; + ped->m_ped_flagI4 = false; +} + +void +CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult) +{ + CVehicleModelInfo *vehModel; + CVector vehDoorPos; + CVector vehDoorOffset; + float seatOffset; + + vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex); + if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { + seatOffset = 0.0f; + vehDoorOffset = offsetToOpenVanDoor; + } else { + seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult; + if (veh->bLowVehicle) { + vehDoorOffset = offsetToOpenLowCarDoor; + } else { + vehDoorOffset = offsetToOpenRegularCarDoor; + } + } + + switch (enterType) { + case VEHICLE_ENTER_FRONT_RIGHT: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case VEHICLE_ENTER_REAR_RIGHT: + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case VEHICLE_ENTER_FRONT_LEFT: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + case VEHICLE_ENTER_REAR_LEFT: + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + default: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); + } + *output = vehDoorPos - vehDoorOffset; +} + +// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. +void +CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType) +{ + CVector localPos; + CVector vehDoorPos; + + GetLocalPositionToOpenCarDoor(&localPos, veh, enterType, 1.0f); + vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); + +/* + // Not used. + CVector localVehDoorOffset; + + if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { + localVehDoorOffset = offsetToOpenVanDoor; + } else { + if (veh->bIsLow) { + localVehDoorOffset = offsetToOpenLowCarDoor; + } else { + localVehDoorOffset = offsetToOpenRegularCarDoor; + } + } + + vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); +*/ + *output = vehDoorPos; +} + +void +CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset) +{ + CVector doorPos; + CMatrix vehMat(veh->GetMatrix()); + + GetLocalPositionToOpenCarDoor(output, veh, enterType, offset); + doorPos = Multiply3x3(vehMat, *output); + + *output = *veh->GetPosition() + doorPos; +} + +void +CPed::LineUpPedWithCar(PedLineUpPhase phase) +{ + bool vehIsUpsideDown = false; + int vehAnim; + float seatPosMult = 0.0f; + float currentZ; + float adjustedTimeStep; + + if (CReplay::IsPlayingBack()) + return; + + if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) { + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_LSIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITP)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITPLO)) { + SetPedPositionInCar(); + return; + } + m_ped_flagC8 = 1; + } + if (phase == LINE_UP_TO_CAR_START) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + CVehicle *veh = m_pMyVehicle; + + // Not quite right, IsUpsideDown func. checks for <= -0.9f. + // Since that function is also used in this file, doesn't this variable indicate upsidedownness?! + if (veh->GetUp().z <= -0.8f) + vehIsUpsideDown = true; + + if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { + if (vehIsUpsideDown) { + m_fRotationDest = -PI + veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5 * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + if (vehIsUpsideDown) { + m_fRotationDest = veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = -0.5 * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } + + if (!bInVehicle) + seatPosMult = 1.0f; + + if (m_pVehicleAnim) { + vehAnim = m_pVehicleAnim->animId; + + switch (vehAnim) { + case ANIM_CAR_JACKED_RHS: + case ANIM_CAR_LJACKED_RHS: + case ANIM_CAR_JACKED_LHS: + case ANIM_CAR_LJACKED_LHS: + case ANIM_CAR_QJACKED: + case ANIM_CAR_GETOUT_LHS: + case ANIM_CAR_GETOUT_LOW_LHS: + case ANIM_CAR_GETOUT_RHS: + case ANIM_CAR_GETOUT_LOW_RHS: + case ANIM_CAR_CRAWLOUT_RHS: + case ANIM_CAR_CRAWLOUT_RHS2: + case ANIM_VAN_GETIN_L: + case ANIM_VAN_GETOUT_L: + case ANIM_VAN_GETIN: + case ANIM_VAN_GETOUT: + seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_QJACK: + case ANIM_CAR_GETIN_LHS: + case ANIM_CAR_GETIN_LOW_LHS: + case ANIM_CAR_GETIN_RHS: + case ANIM_CAR_GETIN_LOW_RHS: + case ANIM_DRIVE_BOAT: + seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_CLOSEDOOR_LHS: + case ANIM_CAR_CLOSEDOOR_LOW_LHS: + case ANIM_CAR_CLOSEDOOR_RHS: + case ANIM_CAR_CLOSEDOOR_LOW_RHS: + case ANIM_CAR_SHUFFLE_RHS: + case ANIM_CAR_LSHUFFLE_RHS: + seatPosMult = 0.0f; + break; + case ANIM_CAR_CLOSE_LHS: + case ANIM_CAR_CLOSE_RHS: + case ANIM_COACH_OPEN_L: + case ANIM_COACH_OPEN_R: + case ANIM_COACH_IN_L: + case ANIM_COACH_IN_R: + case ANIM_COACH_OUT_L: + seatPosMult = 1.0f; + break; + default: + break; + } + } + + CVector neededPos; + + if (phase == LINE_UP_TO_CAR_2) { + neededPos = *GetPosition(); + } else { + GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult); + } + + CVector autoZPos = neededPos; + + if (veh->bIsInWater) { + if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) + autoZPos.z += 1.0f; + } else { + CPedPlacement::FindZCoorForPed(&autoZPos); + } + + if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { + neededPos.z = GetPosition().z; + + // Getting out + if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { + float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep(); + + // If we're not in ground at next step, apply animation + if (neededPos.z + pedZSpeedOnExit >= autoZPos.z) { + m_vecMoveSpeed.z = pedZSpeedOnExit; + ApplyMoveSpeed(); + // Removing below line breaks the animation + neededPos.z = GetPosition().z; + } else { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + } + } + + if (autoZPos.z > neededPos.z) { + currentZ = GetPosition().z; + if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { + adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); + } + } else { + // We may need to raise up the ped + if (phase == LINE_UP_TO_CAR_START) { + currentZ = GetPosition().z; + + if (neededPos.z > currentZ) { + + if (m_pVehicleAnim && + (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS + || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { + adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; + } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) { + neededPos.z = max(currentZ, autoZPos.z); + } + } + } + } + + bool stillGettingInOut = false; + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) + stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10; + + if (!stillGettingInOut) { + m_fRotationCur = m_fRotationDest; + } else { + float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); + float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; + + m_vecOffsetSeek.z = 0.0; + if (timeUntilStateChange <= 0.0f) { + m_vecOffsetSeek.x = 0.0; + m_vecOffsetSeek.y = 0.0; + } else { + neededPos -= timeUntilStateChange * m_vecOffsetSeek; + } + + if (limitedAngle > PI + m_fRotationCur) { + limitedAngle -= 2 * PI; + } else if (limitedAngle < m_fRotationCur - PI) { + limitedAngle += 2 * PI; + } + m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange); + } + + if (seatPosMult > 0.2f || vehIsUpsideDown) { + GetPosition() = neededPos; + + GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); + + // It will be all 0 after rotate. + GetPosition() = neededPos; + } else { + CVector output; + CMatrix vehDoorMat(veh->GetMatrix()); + + GetLocalPositionToOpenCarDoor(&output, veh, m_vehEnterType, 0.0f); + *vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output); + GetMatrix() = vehDoorMat; + } + +} + +static void +particleProduceFootDust(CPed *ped, CVector *pos, float size, int times) +{ + switch (ped->m_nLastCollType) + { + case 1: // somewhere hard + case 3: // soft dirt + case 5: // pavement + case 18:// sand + for (int i = 0; i < times; ++i) { + CVector adjustedPos = *pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); + } + break; + default: + break; + } +} + +static void +particleProduceFootSplash(CPed *ped, CVector *pos, float size, int times) +{ + for (int i = 0; i < times; i++) { + CVector adjustedPos = *pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + + CVector direction = ped->GetForward() * -0.05f; + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumberInRange(0, 1), 200); + } +} + +void +CPed::PlayFootSteps(void) +{ + if (bDoBloodyFootprints) { + if (m_bloodyFootprintCount > 0 && m_bloodyFootprintCount < 300) { + m_bloodyFootprintCount--; + + if (m_bloodyFootprintCount == 0) + bDoBloodyFootprints = false; + } + } + + if (!bIsStanding) + return; + + CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); + CAnimBlendAssociation *walkRunAssoc = nil; + float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; + + for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (assoc->flags & ASSOC_FLAG80) { + walkRunAssoc = assoc; + walkRunAssocBlend += assoc->blendAmount; + } else if ((assoc->flags & ASSOC_FLAG200) == 0) { + idleAssocBlend += assoc->blendAmount; + } + } + + if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { + float stepStart = 1 / 15.0f; + float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; + float currentTime = walkRunAssoc->currentTime; + int stepPart = 0; + + if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) + stepPart = 1; + else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) + stepPart = 2; + + if (stepPart != 0) { + DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); + CVector footPos(0.0f, 0.0f, 0.0f); + + for (RwFrame *frame = GetNodeFrame(stepPart == 1 ? PED_FOOTL : PED_FOOTR); frame; frame = RwFrameGetParent(frame)) + RwV3dTransformPoints(footPos, footPos, 1, RwFrameGetMatrix(frame)); + + CVector forward = GetForward(); + + footPos.z -= 0.1f; + footPos += 0.2f * forward; + + if (bDoBloodyFootprints) { + CVector2D top(forward * 0.26f); + CVector2D right(GetRight() * 0.14f); + + CShadows::AddPermanentShadow(1, gpBloodPoolTex, &footPos, + top.x, top.y, + right.x, right.y, + 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); + + if (m_bloodyFootprintCount <= 20) { + m_bloodyFootprintCount = 0; + bDoBloodyFootprints = false; + } else { + m_bloodyFootprintCount -= 20; + } + } + if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { + if(IsPlayer()) + particleProduceFootDust(this, &footPos, 0.0f, 4); + } else if(stepPart == 2) { + particleProduceFootSplash(this, &footPos, 0.15f, 4); + } + } + } + + if (m_nLastCollType == 19) { // Water + float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); + if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { + float particleSize = pedSpeed * 2.0f; + + if (particleSize < 0.25f) + particleSize = 0.25f; + + if (particleSize > 0.75f) + particleSize = 0.75f; + + CVector particlePos = GetPosition() + GetForward() * 0.3f; + particlePos.z -= 1.2f; + + CVector particleDir = m_vecMoveSpeed * 0.75f; + + particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); + CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); + + particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); + CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); + } + } +} + +bool +CPed::IsPointerValid(void) +{ + int8 pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; + if (pedIndex < 0 || pedIndex >= NUMPEDS) + return false; + + if (m_entryInfoList.first || FindPlayerPed() == this) + return true; + + return false; +} + +// Some kind of binary sort +void +CPed::SortPeds(CPed **list, int min, int max) +{ + if (min >= max) + return; + + CVector leftDiff, rightDiff; + CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); + float middleDist = middleDiff.Magnitude(); + + int left = max; + int right; + for(right = min; right <= left; ){ + // Those 1.0s are to make sure loop always run for first time. + for (float rightDist = middleDist-1.0f; middleDist > rightDist; right++) { + rightDiff = GetPosition() - list[right]->GetPosition(); + rightDist = rightDiff.Magnitude(); + } + right--; + + for (float leftDist = middleDist+1.0f; middleDist < leftDist; left--) { + leftDiff = GetPosition() - list[left]->GetPosition(); + leftDist = leftDiff.Magnitude(); + } + left++; + + if (right <= left) { + CPed *ped = list[right]; + list[right] = list[left]; + list[left] = ped; + right++; + left--; + } + } + SortPeds(list, min, left); + SortPeds(list, right, max); +} + +void +CPed::BuildPedLists(void) +{ + static CPed *unsortedNearPeds[10]; + uint16 nextNearPedSlot = 0; + + if ((CTimer::GetFrameCounter() + m_randomSeed) & 15) { + + for(int i = 0; i < 10; ) { + if (m_nearPeds[i]) { + if (m_nearPeds[i]->IsPointerValid()) { + float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); + if (distSqr < 900.0f) { + i++; + continue; + } + } + + // If we arrive here, the ped we're checking isn't "near", so we should remove it. + for (int j = i; j < 9; j++) { + m_nearPeds[j] = m_nearPeds[j + 1]; + m_nearPeds[j + 1] = nil; + } + // Above loop won't work when it's 9, so we need to empty slot 9. + m_nearPeds[9] = nil; + m_numNearPeds--; + } else + i++; + } + } else { + CVector centre = CEntity::GetBoundCentre(); + CRect rect( + (centre.x - 20.0f) * 0.025f + 50.0f, + (centre.y - 20.0f) * 0.025f + 50.0f, + (centre.x + 20.0f) * 0.025f + 50.0f, + (centre.y + 20.0f) * 0.025f + 50.0f); + + for(int y = rect.top; y <= rect.bottom; y++) { + for(int x = rect.left; x <= rect.right; x++) { + for (CPtrNode *pedPtrNode = CWorld::GetSector(x,y)->m_lists[ENTITYLIST_PEDS].first; pedPtrNode; pedPtrNode = pedPtrNode->next) { + CPed *ped = (CPed*)pedPtrNode->item; + if (ped != this && !ped->bInVehicle) { + float dist = (ped->GetPosition() - GetPosition()).Magnitude2D(); + if (distanceMultToCountPedNear * 30.0f > dist) + { + unsortedNearPeds[nextNearPedSlot] = ped; + nextNearPedSlot++; + } + } + } + } + } + unsortedNearPeds[nextNearPedSlot] = nil; + SortPeds(unsortedNearPeds, 0, nextNearPedSlot - 1); + for (m_numNearPeds = 0; m_numNearPeds < 10; m_numNearPeds++) { + CPed *ped = unsortedNearPeds[m_numNearPeds]; + if (!ped) + break; + + m_nearPeds[m_numNearPeds] = ped; + } + for (int pedToClear = m_numNearPeds; pedToClear < 10; pedToClear++) + m_nearPeds[pedToClear] = nil; + } +} + +void +CPed::SetPedStats(ePedStats pedStat) +{ + m_pedStats = CPedStats::ms_apPedStats[pedStat]; +} + +void +CPed::SetModelIndex(uint32 mi) +{ + CEntity::SetModelIndex(mi); + RpAnimBlendClumpInit((RpClump*) m_rwObject); + RpAnimBlendClumpFillFrameArray((RpClump*) m_rwObject, m_pFrames); + CPedModelInfo *modelInfo = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); + SetPedStats((ePedStats) modelInfo->m_pedStatType); + m_headingRate = m_pedStats->m_headingChangeRate; + m_animGroup = (AssocGroupId) modelInfo->m_animGroup; + CAnimManager::AddAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE); + + // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; +} + +void +CPed::RemoveLighting(bool reset) +{ + CRenderer::RemoveVehiclePedLights(this, reset); +} + +bool +CPed::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + if (bRenderScorched) { + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + } else { + // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. + float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); + if (!bHasBlip && lightMult != 1.0f) { + SetAmbientAndDirectionalColours(lightMult); + return true; + } + } + return false; +} + +void +CPed::Teleport(CVector pos) +{ + CWorld::Remove(this); + GetPosition() = pos; + bIsStanding = false; + m_nPedStateTimer = 0; + m_actionX = 0.0f; + m_actionY = 0.0f; + m_pDamageEntity = nil; + CWorld::Add(this); +} + +void +CPed::CalculateNewOrientation(void) +{ + if (CReplay::IsPlayingBack() || !IsPedInControl()) + return; + + CVector pos = *GetPosition(); + + GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); + + // Because SetRotate makes pos. all 0 + GetPosition() = pos; +} + +float +CPed::WorkOutHeadingForMovingFirstPerson(float offset) +{ + if (!IsPlayer()) + return 0.0f; + + CPad *pad0 = CPad::GetPad(0); + float leftRight = pad0->GetPedWalkLeftRight(); + float upDown = pad0->GetPedWalkUpDown(); + float &angle = ((CPlayerPed*)this)->m_fWalkAngle; + + if (upDown != 0.0f) { + angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); + } else { + if (leftRight < 0.0f) + angle = 0.5 * PI; + else if (leftRight > 0.0f) + angle = -0.5 * PI; + } + + return CGeneral::LimitRadianAngle(offset + angle); +} + +void +CPed::CalculateNewVelocity(void) +{ + if (IsPedInControl()) { + float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep(); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest); + + if (m_fRotationCur - PI > limitedRotDest) { + limitedRotDest += 2 * PI; + } else if(PI + m_fRotationCur < limitedRotDest) { + limitedRotDest -= 2 * PI; + } + + if (IsPlayer() && m_nPedState == PED_ATTACK) + headAmount /= 4.0f; + + float neededTurn = limitedRotDest - m_fRotationCur; + if (neededTurn <= headAmount) { + if (neededTurn > (-headAmount)) + m_fRotationCur += neededTurn; + else + m_fRotationCur -= headAmount; + } else { + m_fRotationCur += headAmount; + } + } + + CVector2D forward(sin(m_fRotationCur), cos(m_fRotationCur)); + + m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * cos(m_fRotationCur)) + -sin(m_fRotationCur) * m_vecAnimMoveDelta.y; + m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * sin(m_fRotationCur)); + + if (CTimer::GetTimeStep() >= 0.01f) { + m_moved = m_moved * (1 / CTimer::GetTimeStep()); + } else { + m_moved = m_moved * (1 / 100.0f); + } + + if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) + || FindPlayerPed() != this || !CanStrafeOrMouseControl()) + return; + + float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); + float pedSpeed = m_moved.Magnitude(); + float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); + + if (localWalkAngle < -0.5 * PI) { + localWalkAngle += PI; + } else if (localWalkAngle > 0.5 * PI) { + localWalkAngle -= PI; + } + + // Interestingly this part is responsible for diagonal walking. + if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { + TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; + m_moved = CVector2D(-sin(walkAngle), cos(walkAngle)) * pedSpeed; + } + + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE); + CAnimBlendAssociation* fightAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_FIGHT_IDLE); + + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { + LimbOrientation newUpperLegs; + newUpperLegs.phi = localWalkAngle; + + if (newUpperLegs.phi < -DEGTORAD(100.0f)) { + newUpperLegs.phi += PI; + } else if (newUpperLegs.phi > DEGTORAD(100.0f)) { + newUpperLegs.phi -= PI; + } + + if (newUpperLegs.phi > -DEGTORAD(50.0f) && newUpperLegs.phi < DEGTORAD(50.0f)) { + newUpperLegs.theta = 0.0f; + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); + } + } +} + +bool +CPed::CanBeDeleted(void) +{ + if (this->bInVehicle) + return false; + + switch (CharCreatedBy) { + case RANDOM_CHAR: + return true; + case MISSION_CHAR: + return false; + default: + return true; + } +} + +bool +CPed::CanPedDriveOff(void) +{ + if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + return false; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *ped = m_nearPeds[i]; + if (ped->m_nPedType == m_nPedType && ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && ped->m_carInObjective == m_carInObjective) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; + return false; + } + } + return true; +} + +// I couldn't find where it is used. +bool +CPed::CanPedJumpThis(int32 unused) +{ + CVector2D forward(-sin(m_fRotationCur), cos(m_fRotationCur)); + CVector pos = GetPosition(); + // wat? + CVector forwardPos( + forward.x + pos.x, + forward.y + pos.y, + pos.z); + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} + +bool +CPed::CanPedReturnToState(void) +{ + return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && + m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; +} + +bool +CPed::CanSeeEntity(CEntity *entity, float threshold) +{ + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + entity->GetPosition().x, + entity->GetPosition().x, + GetPosition().x, + GetPosition().y); + + if (neededAngle < 0.0f) + neededAngle += 2 * PI; + else if (neededAngle > 2 * PI) + neededAngle -= 2 * PI; + + float ourAngle = m_fRotationCur; + if (ourAngle < 0.0f) + ourAngle += 2 * PI; + else if (ourAngle > 2 * PI) + ourAngle -= 2 * PI; + + float neededTurn = fabs(neededAngle - ourAngle); + + return neededTurn < threshold || 2 * PI - threshold < neededTurn; +} + +bool +CPed::IsTemporaryObjective(eObjective objective) +{ + return objective == OBJECTIVE_LEAVE_VEHICLE || objective == OBJECTIVE_SET_LEADER || + objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; +} + +void +CPed::SetMoveState(eMoveState state) +{ + m_nMoveState = state; +} + +void +CPed::SetObjectiveTimer(int time) +{ + if (time == 0) { + m_objectiveTimer = 0; + } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::ForceStoredObjective(eObjective objective) +{ + if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + m_prevObjective = m_objective; + return; + } + + switch (m_objective) + { + case OBJECTIVE_FLEE_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::SetStoredObjective(void) +{ + if (m_objective == m_prevObjective) + return; + + switch (m_objective) + { + case OBJECTIVE_FLEE_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::RestorePreviousObjective(void) +{ + if (m_objective == OBJECTIVE_NONE) + return; + + if (m_objective != OBJECTIVE_LEAVE_VEHICLE && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) + m_pedInObjective = nil; + + if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT) { + m_objective = OBJECTIVE_NONE; + if (m_pMyVehicle) + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + + } else { + m_objective = m_prevObjective; + m_prevObjective = OBJECTIVE_NONE; + } + m_ped_flagD40 = false; +} + +void +CPed::SetLeader(CEntity *leader) +{ + m_leader = (CPed*)leader; + + if(m_leader) + m_leader->RegisterReference((CEntity **)&m_leader); +} + +void +CPed::SetObjective(eObjective newObj, void *entity) +{ + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return; + + if (m_prevObjective == newObj) { + // Why? + if (m_prevObjective != OBJECTIVE_NONE) + return; + } + + if (entity == this) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + switch (newObj) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_FIGHT_CHAR: + if (m_pedInObjective == entity) + return; + + break; + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_FLEE_CAR: + return; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT: + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective == entity) + return; + + break; + case OBJECTIVE_SET_LEADER: + if (m_leader == entity) + return; + + break; + default: + break; + } + } else { + if (newObj == OBJECTIVE_LEAVE_VEHICLE && !bInVehicle) + return; + } + + m_ped_flagD40 = false; + if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { + if (m_objective != newObj) { + if (IsTemporaryObjective(newObj)) + ForceStoredObjective(newObj); + else + SetStoredObjective(); + } + m_objective = newObj; + } else { + m_prevObjective = newObj; + } + + switch (newObj) { + case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT: + + // In this special case, entity parameter isn't CEntity, but int. + SetObjectiveTimer((int)entity); + return; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_MUG_CHAR: + m_pLastPathNode = nil; + m_ped_flagD20 = false; + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pLookTarget = (CEntity*)entity; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + return; + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FIGHT_CHAR: + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + return; + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pedFormation = 1; + return; + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_FLEE_CAR: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); + if (!m_carInObjective->bIsBus || m_leaveCarTimer) + return; + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_RUN); + + if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { + RestorePreviousObjective(); + return; + } + // fall through + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT: + case OBJECTIVE_BUY_ICE_CREAM: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity**)&m_carInObjective); + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + if (newObj == OBJECTIVE_SOLICIT) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && + (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) { + SetObjectiveTimer(14000); + } else { + m_objectiveTimer = 0; + } + return; + case OBJECTIVE_SET_LEADER: + SetLeader((CEntity*)entity); + RestorePreviousObjective(); + return; + default: + return; + } + for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + return; + } + } +} + +void +CPed::SetIdle(void) +{ + if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { + m_nPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + } + if (m_nWaitState == WAITSTATE_FALSE) { + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); + } +} + +void +CPed::SetObjective(eObjective newObj) +{ + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return; + + if (newObj == OBJECTIVE_NONE) { + if ((m_objective == OBJECTIVE_LEAVE_VEHICLE || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + && IsPedInControl()) { + + m_ped_flagG8 = true; + return; + } + // Unused code from assembly... + /* + else if(m_objective == OBJECTIVE_FLEE_CAR) { + + } else { + + } + */ + m_objective = newObj; + m_prevObjective = OBJECTIVE_NONE; + } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { + SetObjectiveTimer(0); + + if (m_objective == newObj) + return; + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + m_ped_flagD40 = false; + + switch (newObj) { + case OBJECTIVE_NONE: + m_prevObjective = OBJECTIVE_NONE; + break; + case OBJECTIVE_HAIL_TAXI: + m_nWaitTimer = 0; + SetIdle(); + SetMoveState(PEDMOVE_STILL); + break; + default: + break; + } + } +} + +// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode +// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... +void +CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) +{ + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return; + + if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) + return; + + SetObjectiveTimer(0); + + if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) + return; + + m_ped_flagD40 = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_FOLLOW_ROUTE) { + SetFollowRoute(routePoint, routeType); + } +} + +void +CPed::ClearChat(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + bIsTalking = false; + ClearLookFlag(); + RestorePreviousState(); +} + +bool +CPed::IsGangMember(void) +{ + return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; +} + +void +CPed::InformMyGangOfAttack(CEntity *attacker) +{ + CPed *attackerPed; + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) + return; + + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed->m_nPedType == PEDTYPE_COP) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed && nearPed != this) { + CPed *leader = nearPed->m_leader; + if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) + { + nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); + nearPed->SetObjectiveTimer(30000); + } + } + } +} + +void +CPed::QuitEnteringCar(void) +{ + CAnimBlendAssociation *animAssoc = m_pVehicleAnim; + CVehicle *veh = m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + RestartNonPartialAnims(); + + if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE)) + CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f); + + if (veh) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK) + veh->m_veh_flagC10 = false; + + if (veh->m_nNumGettingIn != 0) + veh->m_nNumGettingIn--; + + veh->m_nGettingInFlags = GetVehEnterExitFlag(m_vehEnterType); + } + + bUsesCollision = true; + + if (IsPlayer() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { + if (IsPlayer() && m_storedWeapon != NO_STORED_WEAPON) { + SetCurrentWeapon(m_storedWeapon); + m_storedWeapon = NO_STORED_WEAPON; + } + } else { + CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(curWeapon->m_nModelId); + } + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) { + animAssoc = m_pVehicleAnim; + if (animAssoc) { + animAssoc->blendDelta = -4.0; + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; + animAssoc = m_pVehicleAnim; + animAssoc->flags &= ~ASSOC_RUNNING; + } + } else + SetIdle(); + + m_pVehicleAnim = nil; + + if (veh) { + if (veh->m_autoPilot.m_nCruiseSpeed == 0) + veh->m_autoPilot.m_nCruiseSpeed = 17; + } +} + +void +CPed::ReactToAttack(CEntity *attacker) +{ + if (IsPlayer() && attacker->IsPed()) { + InformMyGangOfAttack(attacker); + SetLookFlag(attacker, 1); + SetLookTimer(700); + return; + } + + if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) { + CPed *ourLeader = m_leader; + if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader) + && attacker->IsPed()) { + + CPed *attackerPed = (CPed*)attacker; + if (bNotAllowedToDuck) { + if (!attackerPed->GetWeapon()->IsTypeMelee()) { + field_4E8 = CTimer::GetTimeInMilliseconds(); + return; + } + } else if (bCrouchWhenShooting || m_ped_flagE1) { + SetDuck(CGeneral::GetRandomNumberInRange(1000,3000)); + return; + } + + if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) { + if (m_pedStats != attackerPed->m_pedStats) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(attackerPed); + } + if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker); + SetMoveState(PEDMOVE_RUN); + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker); + SetObjectiveTimer(20000); + } + } + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed); + SetMoveState(PEDMOVE_RUN); + if (attackerPed->GetWeapon()->IsTypeMelee()) + Say(SOUND_PED_FLEE_RUN); + } + } + } +} + +bool +CPed::TurnBody(void) +{ + float lookDir; + bool doneSmoothly = true; + + if (m_pLookTarget) { + CVector &lookPos = m_pLookTarget->GetPosition(); + + lookDir = CGeneral::GetRadianAngleBetweenPoints( + lookPos.x, + lookPos.y, + GetPosition().x, + GetPosition().y); + } else + lookDir = m_fLookDirection; + + float limitedLookDir = CGeneral::LimitRadianAngle(lookDir); + float currentRot = m_fRotationCur; + + if (currentRot - PI > limitedLookDir) + limitedLookDir += 2 * PI; + else if (PI + currentRot < limitedLookDir) + limitedLookDir -= 2 * PI; + + float neededTurn = currentRot - limitedLookDir; + m_fRotationDest = limitedLookDir; + + if (fabs(neededTurn) > 0.05f) { + doneSmoothly = false; + currentRot -= neededTurn * 0.2f; + } + + m_fRotationCur = currentRot; + m_fLookDirection = limitedLookDir; + return doneSmoothly; +} + +void +CPed::Chat(void) +{ + if (bIsLooking && TurnBody()) + ClearLookFlag(); + + if (!m_pLookTarget || !m_pLookTarget->IsPed()) { + ClearChat(); + return; + } + + CPed *partner = (CPed*) m_pLookTarget; + + if (partner->m_nPedState != PED_CHAT) { + ClearChat(); + if (partner->m_pedInObjective) { + if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || + partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) + ReactToAttack(partner->m_pedInObjective); + } + return; + } + if (bIsTalking) { + if (CGeneral::GetRandomNumber() < 512) { + CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); + if (chatAssoc) { + chatAssoc->blendDelta = -4.0f; + chatAssoc->flags |= ASSOC_FADEOUTWHENDONE; + } + bIsTalking = false; + } else + Say(SOUND_PED_CHAT); + + } else if (!RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject, ASSOC_FLAG100)) { + + if (CGeneral::GetRandomNumber() < 20) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + } + if (!bIsTalking) { + CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); + float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); + chatAssoc->SetCurrentTime(chatTime); + + bIsTalking = true; + Say(SOUND_PED_CHAT); + } + } + if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + ClearChat(); + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + } +} + +WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); } +WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } +WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); } +WRAPPER void CPed::FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D3950); } +WRAPPER void CPed::FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6520); } +WRAPPER void CPed::FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7490); } +WRAPPER void CPed::FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A80); } +WRAPPER void CPed::PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEC80); } +WRAPPER void CPed::PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE500); } +WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEAF0); } +WRAPPER void CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF1B0); } +WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF220); } +WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } +WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); } +WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); } +WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } +WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } +WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); } +WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); } +WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); } +WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } +WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } +WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } + +STARTPATCHES + InjectHook(0x4C41C0, &CPed::ctor, PATCH_JUMP); + InjectHook(0x4C50D0, &CPed::dtor, PATCH_JUMP); + InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); + InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); + InjectHook(0x4EB470, &CPed::ApplyHeadShot, PATCH_JUMP); + InjectHook(0x4EAEE0, &CPed::RemoveBodyPart, PATCH_JUMP); + InjectHook(0x4C6460, (void (CPed::*)(CEntity*, bool)) &CPed::SetLookFlag, PATCH_JUMP); + InjectHook(0x4C63E0, (void (CPed::*)(float, bool)) &CPed::SetLookFlag, PATCH_JUMP); + InjectHook(0x4D12E0, &CPed::SetLookTimer, PATCH_JUMP); + InjectHook(0x4C5700, &CPed::OurPedCanSeeThisOne, PATCH_JUMP); + InjectHook(0x4D2BB0, &CPed::Avoid, PATCH_JUMP); + InjectHook(0x4C6A50, &CPed::ClearAimFlag, PATCH_JUMP); + InjectHook(0x4C64F0, &CPed::ClearLookFlag, PATCH_JUMP); + InjectHook(0x4EB670, &CPed::IsPedHeadAbovePos, PATCH_JUMP); + InjectHook(0x4E68A0, &CPed::FinishedAttackCB, PATCH_JUMP); + InjectHook(0x4E5BD0, &CheckForPedsOnGroundToAttack, PATCH_JUMP); + InjectHook(0x4E6BA0, &CPed::Attack, PATCH_JUMP); + InjectHook(0x4CF980, &CPed::RemoveWeaponModel, PATCH_JUMP); + InjectHook(0x4CFA60, &CPed::SetCurrentWeapon, PATCH_JUMP); + InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP); + InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP); + InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP); + InjectHook(0x4E07D0, &CPed::BeingDraggedFromCar, PATCH_JUMP); + InjectHook(0x4CF000, &CPed::PedSetDraggedOutCarCB, PATCH_JUMP); + InjectHook(0x4C5D80, &CPed::RestartNonPartialAnims, PATCH_JUMP); + InjectHook(0x4E4730, &CPed::GetLocalPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4E4660, (void (*)(CVector*, CVehicle*, uint32, float)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4E1A30, (void (*)(CVector*, CVehicle*, uint32)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4DF940, &CPed::LineUpPedWithCar, PATCH_JUMP); + InjectHook(0x4CC6C0, &CPed::PlayFootSteps, PATCH_JUMP); + InjectHook(0x4C5350, &CPed::BuildPedLists, PATCH_JUMP); + InjectHook(0x4CF9B0, &CPed::GiveWeapon, PATCH_JUMP); + InjectHook(0x4C52A0, &CPed::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4D6570, &CPed::FlagToDestroyWhenNextProcessed_, PATCH_JUMP); + InjectHook(0x4A7D30, &CPed::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7DC0, &CPed::RemoveLighting_, PATCH_JUMP); + InjectHook(0x4D3E70, &CPed::Teleport_, PATCH_JUMP); + InjectHook(0x4C7EA0, &CPed::CalculateNewOrientation, PATCH_JUMP); + InjectHook(0x4C78F0, &CPed::WorkOutHeadingForMovingFirstPerson, PATCH_JUMP); + InjectHook(0x4C73F0, &CPed::CalculateNewVelocity, PATCH_JUMP); + InjectHook(0x4D72F0, &CPed::CanPedJumpThis, PATCH_JUMP); + InjectHook(0x4DD820, &CPed::CanSeeEntity, PATCH_JUMP); + InjectHook(0x4D9460, &CPed::RestorePreviousObjective, PATCH_JUMP); + InjectHook(0x4D82C0, (void (CPed::*)(eObjective)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4D89A0, (void (CPed::*)(eObjective, int16, int16)) &CPed::SetObjective, PATCH_JUMP); + InjectHook(0x4DDEC0, &CPed::ReactToAttack, PATCH_JUMP); + InjectHook(0x4D0600, &CPed::SetIdle, PATCH_JUMP); + InjectHook(0x4E0E00, &CPed::QuitEnteringCar, PATCH_JUMP); + InjectHook(0x4E4AD0, &CPed::InformMyGangOfAttack, PATCH_JUMP); + InjectHook(0x4D3C80, &CPed::ClearChat, PATCH_JUMP); + InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP); + InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/Ped.h b/src/peds/Ped.h new file mode 100644 index 00000000..95731e15 --- /dev/null +++ b/src/peds/Ped.h @@ -0,0 +1,577 @@ +#pragma once + +#include "Physical.h" +#include "Weapon.h" +#include "PedStats.h" +#include "PedType.h" +#include "PedIK.h" +#include "AnimManager.h" +#include "AnimBlendClumpData.h" +#include "AnimBlendAssociation.h" +#include "WeaponInfo.h" +#include "Fire.h" + +struct CPathNode; + +enum eWaitState : uint32 { + WAITSTATE_FALSE, + WAITSTATE_TRAFFIC_LIGHTS, + WAITSTATE_CROSS_ROAD, + WAITSTATE_CROSS_ROAD_LOOK, + WAITSTATE_LOOK_PED, + WAITSTATE_LOOK_SHOP, + WAITSTATE_LOOK_ACCIDENT, + WAITSTATE_FACEOFF_GANG, + WAITSTATE_DOUBLEBACK, + WAITSTATE_HITWALL, + WAITSTATE_TURN180, + WAITSTATE_SURPRISE, + WAITSTATE_STUCK, + WAITSTATE_LOOK_ABOUT, + WAITSTATE_PLAYANIM_DUCK, + WAITSTATE_PLAYANIM_COWER, + WAITSTATE_PLAYANIM_TAXI, + WAITSTATE_PLAYANIM_HANDSUP, + WAITSTATE_PLAYANIM_HANDSCOWER, + WAITSTATE_PLAYANIM_CHAT, + WAITSTATE_FINISH_FLEE +}; + +enum eObjective : uint32 { + OBJECTIVE_NONE, + OBJECTIVE_IDLE, + OBJECTIVE_FLEE_TILL_SAFE, + OBJECTIVE_GUARD_SPOT, + OBJECTIVE_GUARD_AREA, + OBJECTIVE_WAIT_IN_CAR, + OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT, + OBJECTIVE_KILL_CHAR_ON_FOOT, + OBJECTIVE_KILL_CHAR_ANY_MEANS, + OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, + OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, + OBJECTIVE_GOTO_CHAR_ON_FOOT, + OBJECTIVE_FOLLOW_PED_IN_FORMATION, + OBJECTIVE_LEAVE_VEHICLE, + OBJECTIVE_ENTER_CAR_AS_PASSENGER, + OBJECTIVE_ENTER_CAR_AS_DRIVER, + OBJECTIVE_FOLLOW_CAR_IN_CAR, + OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE, + OBJECTIVE_DESTROY_OBJ, + OBJECTIVE_DESTROY_CAR, + OBJECTIVE_GOTO_AREA_ANY_MEANS, + OBJECTIVE_GOTO_AREA_ON_FOOT, + OBJECTIVE_RUN_TO_AREA, + OBJECTIVE_23, + OBJECTIVE_24, + OBJECTIVE_FIGHT_CHAR, + OBJECTIVE_SET_LEADER, + OBJECTIVE_FOLLOW_ROUTE, + OBJECTIVE_SOLICIT, + OBJECTIVE_HAIL_TAXI, + OBJECTIVE_CATCH_TRAIN, + OBJECTIVE_BUY_ICE_CREAM, + OBJECTIVE_STEAL_ANY_CAR, + OBJECTIVE_MUG_CHAR, + OBJECTIVE_FLEE_CAR, + OBJECTIVE_35 +}; + +enum eVehEnter : uint16 { + VEHICLE_ENTER_FRONT_RIGHT = 11, + VEHICLE_ENTER_REAR_RIGHT = 12, + VEHICLE_ENTER_FRONT_LEFT = 15, + VEHICLE_ENTER_REAR_LEFT = 16, +}; + +enum { + RANDOM_CHAR = 1, + MISSION_CHAR, +}; + +enum PedLineUpPhase { + LINE_UP_TO_CAR_START, + LINE_UP_TO_CAR_END, + LINE_UP_TO_CAR_2 +}; + +enum PedOnGroundState { + NO_PED, + PED_BELOW_PLAYER, + PED_ON_THE_FLOOR, + PED_DEAD_ON_THE_FLOOR +}; + +enum PedState +{ + PED_NONE, + PED_IDLE, + PED_LOOK_ENTITY, + PED_LOOK_HEADING, + PED_WANDER_RANGE, + PED_WANDER_PATH, + PED_SEEK_POS, + PED_SEEK_ENTITY, + PED_FLEE_POS, + PED_FLEE_ENTITY, + PED_PURSUE, + PED_FOLLOW_PATH, + PED_SNIPER_MODE, + PED_ROCKET_ODE, + PED_DUMMY, + PED_PAUSE, + PED_ATTACK, + PED_FIGHT, + PED_FACE_PHONE, + PED_MAKE_CALL, + PED_CHAT, + PED_MUG, + PED_AIM_GUN, + PED_AI_CONTROL, + PED_SEEK_CAR, + PED_SEEK_IN_BOAT, + PED_FOLLOW_ROUTE, + PED_CPR, + PED_SOLICIT, + PED_BUY_ICECREAM, + PED_INVESTIGATE, + PED_STEP_AWAY, + PED_ON_FIRE, + + PED_UNKNOWN, // HANG_OUT in Fire_Head's idb + + PED_STATES_NO_AI, + PED_JUMP, + PED_FALL, + PED_GETUP, + PED_STAGGER, + PED_DIVE_AWAY, + + PED_STATES_NO_ST, + PED_ENTER_TRAIN, + PED_EXIT_TRAIN, + PED_ARREST_PLAYER, + PED_DRIVING, + PED_PASSENGER, + PED_TAXI_PASSENGER, + PED_OPEN_DOOR, + PED_DIE, + PED_DEAD, + PED_CARJACK, + PED_DRAG_FROM_CAR, + PED_ENTER_CAR, + PED_STEAL_CAR, + PED_EXIT_CAR, + PED_HANDS_UP, + PED_ARRESTED, +}; + +enum eMoveState { + PEDMOVE_NONE, + PEDMOVE_STILL, + PEDMOVE_WALK, + PEDMOVE_RUN, + PEDMOVE_SPRINT, +}; + +class CVehicle; + +class CPed : public CPhysical +{ +public: + // 0x128 + CStoredCollPoly m_collPoly; + float m_fCollisionSpeed; + + // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R* + uint8 bIsStanding : 1; + uint8 m_ped_flagA2 : 1; + uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime) + uint8 bIsPointingGunAt : 1; + uint8 bIsLooking : 1; + uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA + uint8 bIsRestoringLook : 1; + uint8 bIsAimingGun : 1; + + uint8 bIsRestoringGun : 1; + uint8 bCanPointGunAtTarget : 1; + uint8 bIsTalking : 1; + uint8 bIsInTheAir : 1; + uint8 bIsLanding : 1; + uint8 m_ped_flagB20 : 1; + uint8 m_ped_flagB40 : 1; + uint8 m_ped_flagB80 : 1; + + uint8 m_ped_flagC1 : 1; + uint8 bRespondsToThreats : 1; + uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar? + uint8 m_ped_flagC8 : 1; + uint8 m_ped_flagC10 : 1; + uint8 m_ped_flagC20 : 1; // just left some body part? + uint8 m_ped_flagC40 : 1; + uint8 m_ped_flagC80 : 1; + + uint8 m_ped_flagD1 : 1; + uint8 m_ped_flagD2 : 1; + uint8 m_ped_flagD4 : 1; + uint8 m_ped_flagD8 : 1; + uint8 m_ped_flagD10 : 1; + uint8 m_ped_flagD20 : 1; + uint8 m_ped_flagD40 : 1; // reset when objective changes + uint8 m_ped_flagD80 : 1; + + uint8 m_ped_flagE1 : 1; + uint8 m_ped_flagE2 : 1; + uint8 bNotAllowedToDuck : 1; + uint8 bCrouchWhenShooting : 1; + uint8 bIsDucking : 1; // set if you don't want ped to attack + uint8 m_ped_flagE20 : 1; + uint8 bDoBloodyFootprints : 1; + uint8 m_ped_flagE80 : 1; + + uint8 m_ped_flagF1 : 1; + uint8 m_ped_flagF2 : 1; + uint8 m_ped_flagF4 : 1; + uint8 m_ped_flagF8 : 1; + uint8 m_ped_flagF10 : 1; + uint8 m_ped_flagF20 : 1; + uint8 m_ped_flagF40 : 1; + uint8 m_ped_flagF80 : 1; + + uint8 m_ped_flagG1 : 1; + uint8 m_ped_flagG2 : 1; + uint8 m_ped_flagG4 : 1; + uint8 m_ped_flagG8 : 1; + uint8 m_ped_flagG10 : 1; + uint8 m_ped_flagG20 : 1; + uint8 m_ped_flagG40 : 1; + uint8 m_ped_flagG80 : 1; + + uint8 m_ped_flagH1 : 1; + uint8 m_ped_flagH2 : 1; + uint8 m_ped_flagH4 : 1; + uint8 m_ped_flagH8 : 1; + uint8 m_ped_flagH10 : 1; + uint8 m_ped_flagH20 : 1; + uint8 m_ped_flagH40 : 1; + uint8 m_ped_flagH80 : 1; + + uint8 m_ped_flagI1 : 1; + uint8 m_ped_flagI2 : 1; + uint8 m_ped_flagI4 : 1; + uint8 bRecordedForReplay : 1; + uint8 m_ped_flagI10 : 1; + uint8 m_ped_flagI20 : 1; + uint8 m_ped_flagI40 : 1; + uint8 m_ped_flagI80 : 1; + + uint8 stuff10[3]; + uint8 CharCreatedBy; + uint8 field_161; + uint8 pad_162[2]; + eObjective m_objective; + eObjective m_prevObjective; + CPed *m_pedInObjective; + CVehicle *m_carInObjective; + uint32 field_174; + uint32 field_178; + uint32 field_17C; + CPed *m_leader; + uint32 m_pedFormation; + uint32 m_fearFlags; + CEntity *m_threatEntity; + CVector2D m_eventOrThread; + uint32 m_eventType; + CEntity* m_pEventEntity; + float m_fAngleToEvent; + AnimBlendFrameData *m_pFrames[PED_NODE_MAX]; + AssocGroupId m_animGroup; + CAnimBlendAssociation *m_pVehicleAnim; + CVector2D m_vecAnimMoveDelta; + CVector m_vecOffsetSeek; + CPedIK m_pedIK; + float m_actionX; + float m_actionY; + uint32 m_nPedStateTimer; + PedState m_nPedState; + PedState m_nLastPedState; + eMoveState m_nMoveState; + int32 m_nStoredActionState; + int32 m_nPrevActionState; + eWaitState m_nWaitState; + uint32 m_nWaitTimer; + void *m_pPathNodesStates[8]; + CVector2D m_stPathNodeStates[10]; + uint16 m_nPathNodes; + uint8 m_nCurPathNode; + int8 m_nPathState; +private: + int8 _pad2B5[3]; +public: + CPathNode *m_pNextPathNode; + CPathNode *m_pLastPathNode; + float m_fHealth; + float m_fArmour; + int16 m_routeLastPoint; + uint16 m_routePoints; + int16 m_routePos; + int16 m_routeType; + int16 m_routeCurDir; + uint16 field_2D2; + CVector2D m_moved; + float m_fRotationCur; + float m_fRotationDest; + float m_headingRate; + eVehEnter m_vehEnterType; + uint16 m_walkAroundType; + CEntity *m_pCurrentPhysSurface; + CVector m_vecOffsetFromPhysSurface; + CEntity *m_pCurSurface; + CVector m_vecSeekVehicle; + CEntity *m_pSeekTarget; + CVehicle *m_pMyVehicle; + bool bInVehicle; + uint8 pad_315[3]; + uint32 field_318; + uint8 field_31C; + uint8 field_31D; + int16 m_phoneId; + uint32 m_lookingForPhone; + uint32 m_phoneTalkTimer; + void *m_lastAccident; + int32 m_nPedType; + CPedStats *m_pedStats; + float m_fleeFromPosX; + float m_fleeFromPosY; + CEntity *m_fleeFrom; + uint32 m_fleeTimer; + uint32 field_344; + uint32 m_lastThreatTimer; + CEntity *m_pCollidingEntity; + uint8 m_stateUnused; + uint8 pad_351[3]; + uint32 m_timerUnused; + CEntity *m_targetUnused; + CWeapon m_weapons[NUM_PED_WEAPONTYPES]; + eWeaponType m_storedWeapon; + uint8 m_currentWeapon; // eWeaponType + uint8 m_maxWeaponTypeAllowed; // eWeaponType + uint8 m_wepSkills; + uint8 m_wepAccuracy; + CEntity *m_pPointGunAt; + CVector m_vecHitLastPos; + uint32 m_lastHitState; + uint8 m_fightFlags1; + uint8 m_fightFlags2; + uint8 pad_4B2[2]; + CFire* m_pFire; + CEntity *m_pLookTarget; + float m_fLookDirection; + int32 m_wepModelID; + uint32 m_leaveCarTimer; + uint32 m_getUpTimer; + uint32 m_lookTimer; + uint32 m_standardTimer; + uint32 m_attackTimer; + uint32 m_lastHitTime; + uint32 m_hitRecoverTimer; + uint32 m_objectiveTimer; + uint32 m_duckTimer; + uint32 field_4E8; + int32 m_bloodyFootprintCount; + uint8 stuff9[2]; + int8 m_bodyPartBleeding; // PedNode + uint8 m_field_4F3; + CPed *m_nearPeds[10]; + uint16 m_numNearPeds; + int8 m_lastWepDam; + uint8 pad_51F; + uint8 field_520; + uint8 pad_521[3]; + uint32 m_talkTimer; + uint16 m_talkTypeLast; + uint16 m_talkType; + CVector m_vecSeekPosEx; + float m_seekExAngle; + + static void *operator new(size_t); + static void *operator new(size_t, int); + static void operator delete(void*, size_t); + static void operator delete(void*, int); + + CPed(uint32 pedType); + virtual ~CPed(void); + + virtual void SetModelIndex(uint32 mi); + virtual void ProcessControl(void); + virtual void Teleport(CVector); + virtual void PreRender(void); + virtual void Render(void); + virtual bool SetupLighting(void); + virtual void RemoveLighting(bool); + virtual void FlagToDestroyWhenNextProcessed(void); + virtual int32 ProcessEntityCollision(CEntity*, CColPoint*); + virtual void SetMoveAnim(void); + + CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); } + void dtor(void) { this->CPed::~CPed(); } + + void AddWeaponModel(int id); + void AimGun(void); + void KillPedWithCar(CVehicle *veh, float impulse); + void Say(uint16 audio); + void SetLookFlag(CEntity *target, bool unknown); + void SetLookFlag(float direction, bool unknown); + void SetLookTimer(int time); + void SetDie(AnimationId anim, float arg1, float arg2); + void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer); + void RemoveBodyPart(PedNode nodeId, int8 unknown); + void SpawnFlyingComponent(int, int8 unknown); + bool OurPedCanSeeThisOne(CEntity *target); + void Avoid(void); + void Attack(void); + void ClearAimFlag(void); + void ClearLookFlag(void); + void RestorePreviousState(void); + void ClearAttack(void); + bool IsPedHeadAbovePos(float zOffset); + void RemoveWeaponModel(int modelId); + void SetCurrentWeapon(uint32 weaponType); + void Duck(void); + void ClearDuck(void); + void ClearPointGunAt(void); + void BeingDraggedFromCar(void); + void RestartNonPartialAnims(void); + void LineUpPedWithCar(PedLineUpPhase phase); + void SetPedPositionInCar(void); + void PlayFootSteps(void); + void QuitEnteringCar(void); + void BuildPedLists(void); + uint32 GiveWeapon(eWeaponType weaponType, uint32 ammo); + void CalculateNewOrientation(void); + float WorkOutHeadingForMovingFirstPerson(float); + void CalculateNewVelocity(void); + bool CanPedJumpThis(int32); + bool CanSeeEntity(CEntity*, float); + void RestorePreviousObjective(void); + void SetIdle(void); + void SetObjective(eObjective, void*); + void SetObjective(eObjective); + void SetObjective(eObjective, int16, int16); + void ClearChat(void); + void InformMyGangOfAttack(CEntity*); + void SetFollowRoute(int16, int16); + void ReactToAttack(CEntity*); + void SetDuck(uint32); + void RegisterThreatWithGangPeds(CEntity*); + bool TurnBody(void); + void Chat(void); + + // Static methods + static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); + static void GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult); + static void GetPositionToOpenCarDoor(CVector* output, CVehicle* veh, uint32 enterType); + + // Callbacks + static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data); + static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data); + static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg); + static void PedStaggerCB(CAnimBlendAssociation *assoc, void *arg); + static void PedEvadeCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg); + static void SetInCarCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetDraggedOutCarCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishedAttackCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg); + static void PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg); + static void FinishJumpCB(CAnimBlendAssociation *assoc, void *arg); + static void PedLandCB(CAnimBlendAssociation *assoc, void *arg); + static void RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); + static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); + + // functions that I see unnecessary to hook + bool IsPlayer(void); + bool UseGroundColModel(void); + bool CanSetPedState(void); + bool IsPedInControl(void); + bool CanPedDriveOff(void); + bool CanBeDeleted(void); + bool CanStrafeOrMouseControl(void); + bool CanPedReturnToState(void); + void SetMoveState(eMoveState); + bool IsTemporaryObjective(eObjective objective); + void SetObjectiveTimer(int); + bool SelectGunIfArmed(void); + bool IsPointerValid(void); + void SortPeds(CPed**, int, int); + void ForceStoredObjective(eObjective); + void SetStoredObjective(void); + void SetLeader(CEntity* leader); + void SetPedStats(ePedStats); + bool IsGangMember(void); + + bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } + CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } + CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } + RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; } + static uint8 GetVehEnterExitFlag(eVehEnter vehEnter) { + switch (vehEnter) { + case VEHICLE_ENTER_FRONT_RIGHT: + return 4; + case VEHICLE_ENTER_REAR_RIGHT: + return 8; + case VEHICLE_ENTER_FRONT_LEFT: + return 1; + case VEHICLE_ENTER_REAR_LEFT: + return 2; + default: + return 0; + } + } + PedState GetPedState(void) { return m_nPedState; } + void SetPedState(PedState state) { m_nPedState = state; } + + // to make patching virtual functions possible + void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); } + void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); } + bool SetupLighting_(void) { return CPed::SetupLighting(); } + void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); } + void Teleport_(CVector pos) { CPed::Teleport(pos); } + + // set by 0482:set_threat_reaction_range_multiplier opcode + static uint16 &distanceMultToCountPedNear; + + static CVector &offsetToOpenRegularCarDoor; + static CVector &offsetToOpenLowCarDoor; + static CVector &offsetToOpenVanDoor; + static bool &bNastyLimbsCheat; + static bool &bPedCheat2; + static bool &bPedCheat3; +}; + +void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); + +static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error"); +static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error"); +static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error"); +static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error"); +static_assert(offsetof(CPed, m_pCollidingEntity) == 0x34C, "CPed: error"); +static_assert(offsetof(CPed, m_weapons) == 0x35C, "CPed: error"); +static_assert(offsetof(CPed, m_currentWeapon) == 0x498, "CPed: error"); +static_assert(offsetof(CPed, m_lookTimer) == 0x4CC, "CPed: error"); +static_assert(offsetof(CPed, m_bodyPartBleeding) == 0x4F2, "CPed: error"); +static_assert(offsetof(CPed, m_pedInObjective) == 0x16C, "CPed: error"); +static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error"); +static_assert(sizeof(CPed) == 0x53C, "CPed: error"); diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp new file mode 100644 index 00000000..b9baf49c --- /dev/null +++ b/src/peds/PedIK.cpp @@ -0,0 +1,109 @@ +#include "common.h" +#include "patcher.h" +#include "PedIK.h" +#include "Ped.h" + +WRAPPER bool CPedIK::PointGunInDirection(float phi, float theta) { EAXJMP(0x4ED9B0); } +WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); } +WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); } +WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); } + +CPedIK::CPedIK(CPed *ped) +{ + m_ped = ped; + m_flags = 0; + m_headOrient.phi = 0.0f; + m_headOrient.theta = 0.0f; + m_torsoOrient.phi = 0.0f; + m_torsoOrient.theta = 0.0f; + m_upperArmOrient.phi = 0.0f; + m_upperArmOrient.theta = 0.0f; + m_lowerArmOrient.phi = 0.0f; + m_lowerArmOrient.theta = 0.0f; +} + +void +CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool changeRoll) +{ + RwFrame *f = animBlend->frame; + RwMatrix *mat = CPedIK::GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate()); + + RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z }; + RwV3d rightVector; + RwV3d pos = RwFrameGetMatrix(f)->pos; + + // rotation == 0 -> looking in y direction + // left? vector + float c = cos(m_ped->m_fRotationCur); + float s = sin(m_ped->m_fRotationCur); + rightVector.x = -(c*mat->right.x + s*mat->right.y); + rightVector.y = -(c*mat->up.x + s*mat->up.y); + rightVector.z = -(c*mat->at.x + s*mat->at.y); + + if(changeRoll){ + // Used when aiming only involves over the legs.(canAimWithArm) + // Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs. + // Not noticeable in normal conditions... + + RwV3d forwardVector; + CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up); + inversedForward.Normalise(); + float dotProduct = DotProduct(mat->at, inversedForward); + if(dotProduct > 1.0f) dotProduct = 1.0f; + if(dotProduct < -1.0f) dotProduct = -1.0f; + float alpha = acos(dotProduct); + + if(mat->at.z < 0.0f) + alpha = -alpha; + + forwardVector.x = s * mat->right.x - c * mat->right.y; + forwardVector.y = s * mat->up.x - c * mat->up.y; + forwardVector.z = s * mat->at.x - c * mat->at.y; + + float curYaw, curPitch; + CPedIK::ExtractYawAndPitchWorld(mat, &curYaw, &curPitch); + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT); + }else{ + // pitch + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + // yaw + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT); + } + RwFrameGetMatrix(f)->pos = pos; + RwMatrixDestroy(mat); +} + +void +CPedIK::GetComponentPosition(RwV3d *pos, PedNode node) +{ + RwFrame *f; + RwMatrix *mat; + + f = m_ped->GetNodeFrame(node); + mat = RwFrameGetMatrix(f); + *pos = mat->pos; + + for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) + RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(f)); +} + +RwMatrix* +CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) +{ + RwFrame *i; + + *destination = *RwFrameGetMatrix(source); + + for (i = RwFrameGetParent(source); i; i = RwFrameGetParent(i)) + RwMatrixTransform(destination, RwFrameGetMatrix(i), rwCOMBINEPOSTCONCAT); + + return destination; +} + +STARTPATCHES + InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP); + InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP); + InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h new file mode 100644 index 00000000..e17d52eb --- /dev/null +++ b/src/peds/PedIK.h @@ -0,0 +1,40 @@ +#pragma once +#include "common.h" +#include "PedModelInfo.h" +#include "AnimBlendClumpData.h" + +struct LimbOrientation +{ + float phi; + float theta; +}; + +class CPed; + +class CPedIK +{ +public: + // TODO + enum { + FLAG_1 = 1, + FLAG_2 = 2, // related to looking somewhere + FLAG_4 = 4, // aims with arm + }; + + CPed *m_ped; + LimbOrientation m_headOrient; + LimbOrientation m_torsoOrient; + LimbOrientation m_upperArmOrient; + LimbOrientation m_lowerArmOrient; + int32 m_flags; + + CPedIK(CPed *ped); + bool PointGunInDirection(float phi, float theta); + bool PointGunAtPosition(CVector *position); + void GetComponentPosition(RwV3d *pos, PedNode node); + static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination); + void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); + void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); + void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); +}; +static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp new file mode 100644 index 00000000..e9a3f7d9 --- /dev/null +++ b/src/peds/PedPlacement.cpp @@ -0,0 +1,40 @@ +#include "common.h" +#include "patcher.h" +#include "PedPlacement.h" +#include "World.h" + +void +CPedPlacement::FindZCoorForPed(CVector* pos) +{ + float zForPed; + float startZ = pos->z - 100.0f; + float foundColZ = -100.0f; + float foundColZ2 = -100.0f; + CColPoint foundCol; + CEntity* foundEnt; + + CVector vec( + pos->x, + pos->y, + pos->z + 1.0f + ); + + if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil)) + foundColZ = foundCol.point.z; + + // Adjust coords and do a second test + vec.x += 0.1f; + vec.y += 0.1f; + + if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil)) + foundColZ2 = foundCol.point.z; + + zForPed = max(foundColZ, foundColZ2); + + if (zForPed > -99.0f) + pos->z = 1.04f + zForPed; +} + +STARTPATCHES + InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h new file mode 100644 index 00000000..4bd48b62 --- /dev/null +++ b/src/peds/PedPlacement.h @@ -0,0 +1,8 @@ +#pragma once + +class CVector; + +class CPedPlacement { +public: + static void FindZCoorForPed(CVector* pos); +}; \ No newline at end of file diff --git a/src/peds/PedStats.cpp b/src/peds/PedStats.cpp new file mode 100644 index 00000000..f6508580 --- /dev/null +++ b/src/peds/PedStats.cpp @@ -0,0 +1,125 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "PedStats.h" + +CPedStats *(&CPedStats::ms_apPedStats)[NUM_PEDSTATS] = *(CPedStats *(*)[NUM_PEDSTATS]) *(uintptr*)0x9404D4; + +void +CPedStats::Initialise(void) +{ + int i; + + debug("Initialising CPedStats...\n"); + for(i = 0; i < NUM_PEDSTATS; i++){ + ms_apPedStats[i] = new CPedStats; + ms_apPedStats[i]->m_type = PEDSTAT_PLAYER; + ms_apPedStats[i]->m_name[8] = 'R'; // WHAT? + ms_apPedStats[i]->m_fleeDistance = 20.0f; + ms_apPedStats[i]->m_headingChangeRate = 15.0f; + ms_apPedStats[i]->m_fear = 50; + ms_apPedStats[i]->m_temper = 50; + ms_apPedStats[i]->m_lawfulness = 50; + ms_apPedStats[i]->m_sexiness = 50; + ms_apPedStats[i]->m_attackStrength = 1.0f; + ms_apPedStats[i]->m_defendWeakness = 1.0f; + ms_apPedStats[i]->m_flags = 0; + } + debug("Loading pedstats data...\n"); + CPedStats::LoadPedStats(); + debug("CPedStats ready\n"); +} + +void +CPedStats::Shutdown(void) +{ + int i; + debug("Shutting down CPedStats...\n"); + for(i = 0; i < NUM_PEDSTATS; i++) + delete ms_apPedStats[i]; + debug("CPedStats shut down\n"); +} + +void +CPedStats::LoadPedStats(void) +{ + char *buf; + char line[256]; + char name[32]; + int bp, buflen; + int lp, linelen; + int type; + float fleeDist, headingChangeRate, attackStrength, defendWeakness; + int fear, temper, lawfullness, sexiness, flags; + + + type = 0; + buf = new char[16 * 1024]; + + CFileMgr::SetDir("DATA"); + buflen = CFileMgr::LoadFile("PEDSTATS.DAT", (uint8*)buf, 16 * 1024, "r"); + CFileMgr::SetDir(""); + + for(bp = 0; bp < buflen; ){ + // read file line by line + for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ + if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') + line[linelen++] = ' '; + else + line[linelen++] = buf[bp]; + line[linelen] = '\0'; + } + bp++; + + // skip white space + for(lp = 0; line[lp] <= ' '; lp++); + + if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines + line[lp] == '#') + continue; + + sscanf(&line[lp], "%s %f %f %d %d %d %d %f %f %d", + name, + &fleeDist, + &headingChangeRate, + &fear, + &temper, + &lawfullness, + &sexiness, + &attackStrength, + &defendWeakness, + &flags); + ms_apPedStats[type]->m_type = (ePedStats)type; + strncpy(ms_apPedStats[type]->m_name, name, 24); // FIX: game uses strcpy + ms_apPedStats[type]->m_fleeDistance = fleeDist; + ms_apPedStats[type]->m_headingChangeRate = headingChangeRate; + ms_apPedStats[type]->m_fear = fear; + ms_apPedStats[type]->m_temper = temper; + ms_apPedStats[type]->m_lawfulness = lawfullness; + ms_apPedStats[type]->m_sexiness = sexiness; + ms_apPedStats[type]->m_attackStrength = attackStrength; + ms_apPedStats[type]->m_defendWeakness = defendWeakness; + ms_apPedStats[type]->m_flags = flags; + type++; + } + + delete[] buf; +} + +int32 +CPedStats::GetPedStatType(char *name) +{ + int type; + + for(type = 0; type < NUM_PEDSTATS; type++) + if(strcmp(ms_apPedStats[type]->m_name, name) == 0) + return type; + return NUM_PEDSTATS; +} + +STARTPATCHES + InjectHook(0x4EF460, &CPedStats::Initialise, PATCH_JUMP); + InjectHook(0x4EF540, &CPedStats::Shutdown, PATCH_JUMP); + InjectHook(0x4EF580, &CPedStats::LoadPedStats, PATCH_JUMP); + InjectHook(0x4EF780, &CPedStats::GetPedStatType, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/PedStats.h b/src/peds/PedStats.h new file mode 100644 index 00000000..ce92d4da --- /dev/null +++ b/src/peds/PedStats.h @@ -0,0 +1,79 @@ +#pragma once + +enum ePedStats +{ + PEDSTAT_PLAYER, + PEDSTAT_COP, + PEDSTAT_MEDIC, + PEDSTAT_FIREMAN, + PEDSTAT_GANG1, + PEDSTAT_GANG2, + PEDSTAT_GANG3, + PEDSTAT_GANG4, + PEDSTAT_GANG5, + PEDSTAT_GANG6, + PEDSTAT_GANG7, + PEDSTAT_STREET_GUY, + PEDSTAT_SUIT_GUY, + PEDSTAT_SENSIBLE_GUY, + PEDSTAT_GEEK_GUY, + PEDSTAT_OLD_GUY, + PEDSTAT_TOUGH_GUY, + PEDSTAT_STREET_GIRL, + PEDSTAT_SUIT_GIRL, + PEDSTAT_SENSIBLE_GIRL, + PEDSTAT_GEEK_GIRL, + PEDSTAT_OLD_GIRL, + PEDSTAT_TOUGH_GIRL, + PEDSTAT_TRAMP_MALE, + PEDSTAT_TRAMP_FEMALE, + PEDSTAT_TOURIST, + PEDSTAT_PROSTITUTE, + PEDSTAT_CRIMINAL, + PEDSTAT_BUSKER, + PEDSTAT_TAXIDRIVER, + PEDSTAT_PSYCHO, + PEDSTAT_STEWARD, + PEDSTAT_SPORTSFAN, + PEDSTAT_SHOPPER, + PEDSTAT_OLDSHOPPER, + + NUM_PEDSTATS +}; + +// flags +enum +{ + STAT_PUNCH_ONLY = 1, + STAT_CAN_KNEE_HEAD = 2, + STAT_CAN_KICK = 4, + STAT_CAN_ROUNDHOUSE = 8, + STAT_NO_DIVE = 0x10, + STAT_ONE_HIT_KNOCKDOWN = 0x20, + STAT_SHOPPING_BAGS = 0x40, + STAT_GUN_PANIC = 0x80 +}; + +class CPedStats +{ +public: + ePedStats m_type; + char m_name[24]; + float m_fleeDistance; + float m_headingChangeRate; + int8 m_fear; + int8 m_temper; + int8 m_lawfulness; + int8 m_sexiness; + float m_attackStrength; + float m_defendWeakness; + int16 m_flags; + + static CPedStats* (&ms_apPedStats)[NUM_PEDSTATS]; + + static void Initialise(void); + static void Shutdown(void); + static void LoadPedStats(void); + static int32 GetPedStatType(char *name); +}; +static_assert(sizeof(CPedStats) == 0x34, "CPedStats: error"); diff --git a/src/peds/PedType.cpp b/src/peds/PedType.cpp new file mode 100644 index 00000000..66eb49a1 --- /dev/null +++ b/src/peds/PedType.cpp @@ -0,0 +1,243 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "PedType.h" + +CPedType *(&CPedType::ms_apPedType)[NUM_PEDTYPES] = *(CPedType *(*)[NUM_PEDTYPES]) *(uintptr*)0x941594; + +void +CPedType::Initialise(void) +{ + int i; + + debug("Initialising CPedType...\n"); + for(i = 0; i < NUM_PEDTYPES; i++){ + ms_apPedType[i] = new CPedType; + ms_apPedType[i]->m_flag = PED_FLAG_PLAYER1; + ms_apPedType[i]->unknown1 = 0.0f; + ms_apPedType[i]->unknown2 = 0.0f; + // unknown3 not initialized + ms_apPedType[i]->unknown4 = 0.0f; + ms_apPedType[i]->unknown5 = 0.0f; + ms_apPedType[i]->m_threats = 0; + ms_apPedType[i]->m_avoid = 0; + } + debug("Loading ped data...\n"); + LoadPedData(); + debug("CPedType ready\n"); +} + +void +CPedType::Shutdown(void) +{ + int i; + debug("Shutting down CPedType...\n"); + for(i = 0; i < NUM_PEDTYPES; i++) + delete ms_apPedType[i]; + debug("CPedType shut down\n"); +} + +void +CPedType::LoadPedData(void) +{ + char *buf; + char line[256]; + char word[32]; + int bp, buflen; + int lp, linelen; + int type; + uint32 flags; + float f1, f2, f3, f4, f5; + + type = NUM_PEDTYPES; + buf = new char[16 * 1024]; + + CFileMgr::SetDir("DATA"); + buflen = CFileMgr::LoadFile("PED.DAT", (uint8*)buf, 16 * 1024, "r"); + CFileMgr::SetDir(""); + + for(bp = 0; bp < buflen; ){ + // read file line by line + for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ + if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') + line[linelen++] = ' '; + else + line[linelen++] = buf[bp]; + line[linelen] = '\0'; + } + bp++; + + // skip white space + for(lp = 0; line[lp] <= ' '; lp++); + + if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines + line[lp] == '#') + continue; + + // FIX: game just uses line here + sscanf(&line[lp], "%s", word); + + if(strncmp(word, "Threat", 7) == 0){ + flags = 0; + lp += 7; + while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){ + flags |= FindPedFlag(word); + // skip word + while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0') + lp++; + // skip white space + while(line[lp] == ' ') + lp++; + } + ms_apPedType[type]->m_threats = flags; + }else if(strncmp(word, "Avoid", 6) == 0){ + flags = 0; + lp += 6; + while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){ + flags |= FindPedFlag(word); + // skip word + while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0') + lp++; + // skip white space + while(line[lp] == ' ') + lp++; + } + ms_apPedType[type]->m_avoid = flags; + }else{ + sscanf(line, "%s %f %f %f %f %f", word, &f1, &f2, &f3, &f4, &f5); + type = FindPedType(word); + ms_apPedType[type]->m_flag = FindPedFlag(word); + // unknown values + ms_apPedType[type]->unknown1 = f1 / 50.0f; + ms_apPedType[type]->unknown2 = f2 / 50.0f; + ms_apPedType[type]->unknown3 = f3 / 50.0f; + ms_apPedType[type]->unknown4 = f4; + ms_apPedType[type]->unknown5 = f5; + + } + } + + delete[] buf; +} + +int32 +CPedType::FindPedType(char *type) +{ + if(strcmp(type, "PLAYER1") == 0) return PEDTYPE_PLAYER1; + if(strcmp(type, "PLAYER2") == 0) return PEDTYPE_PLAYER2; + if(strcmp(type, "PLAYER3") == 0) return PEDTYPE_PLAYER3; + if(strcmp(type, "PLAYER4") == 0) return PEDTYPE_PLAYER4; + if(strcmp(type, "CIVMALE") == 0) return PEDTYPE_CIVMALE; + if(strcmp(type, "CIVFEMALE") == 0) return PEDTYPE_CIVFEMALE; + if(strcmp(type, "COP") == 0) return PEDTYPE_COP; + if(strcmp(type, "GANG1") == 0) return PEDTYPE_GANG1; + if(strcmp(type, "GANG2") == 0) return PEDTYPE_GANG2; + if(strcmp(type, "GANG3") == 0) return PEDTYPE_GANG3; + if(strcmp(type, "GANG4") == 0) return PEDTYPE_GANG4; + if(strcmp(type, "GANG5") == 0) return PEDTYPE_GANG5; + if(strcmp(type, "GANG6") == 0) return PEDTYPE_GANG6; + if(strcmp(type, "GANG7") == 0) return PEDTYPE_GANG7; + if(strcmp(type, "GANG8") == 0) return PEDTYPE_GANG8; + if(strcmp(type, "GANG9") == 0) return PEDTYPE_GANG9; + if(strcmp(type, "EMERGENCY") == 0) return PEDTYPE_EMERGENCY; + if(strcmp(type, "FIREMAN") == 0) return PEDTYPE_FIREMAN; + if(strcmp(type, "CRIMINAL") == 0) return PEDTYPE_CRIMINAL; + if(strcmp(type, "SPECIAL") == 0) return PEDTYPE_SPECIAL; + if(strcmp(type, "PROSTITUTE") == 0) return PEDTYPE_PROSTITUTE; + Error("Unknown ped type, Pedtype.cpp"); + return NUM_PEDTYPES; +} + +uint32 +CPedType::FindPedFlag(char *type) +{ + if(strcmp(type, "PLAYER1") == 0) return PED_FLAG_PLAYER1; + if(strcmp(type, "PLAYER2") == 0) return PED_FLAG_PLAYER2; + if(strcmp(type, "PLAYER3") == 0) return PED_FLAG_PLAYER3; + if(strcmp(type, "PLAYER4") == 0) return PED_FLAG_PLAYER4; + if(strcmp(type, "CIVMALE") == 0) return PED_FLAG_CIVMALE; + if(strcmp(type, "CIVFEMALE") == 0) return PED_FLAG_CIVFEMALE; + if(strcmp(type, "COP") == 0) return PED_FLAG_COP; + if(strcmp(type, "GANG1") == 0) return PED_FLAG_GANG1; + if(strcmp(type, "GANG2") == 0) return PED_FLAG_GANG2; + if(strcmp(type, "GANG3") == 0) return PED_FLAG_GANG3; + if(strcmp(type, "GANG4") == 0) return PED_FLAG_GANG4; + if(strcmp(type, "GANG5") == 0) return PED_FLAG_GANG5; + if(strcmp(type, "GANG6") == 0) return PED_FLAG_GANG6; + if(strcmp(type, "GANG7") == 0) return PED_FLAG_GANG7; + if(strcmp(type, "GANG8") == 0) return PED_FLAG_GANG8; + if(strcmp(type, "GANG9") == 0) return PED_FLAG_GANG9; + if(strcmp(type, "EMERGENCY") == 0) return PED_FLAG_EMERGENCY; + if(strcmp(type, "FIREMAN") == 0) return PED_FLAG_FIREMAN; + if(strcmp(type, "CRIMINAL") == 0) return PED_FLAG_CRIMINAL; + if(strcmp(type, "SPECIAL") == 0) return PED_FLAG_SPECIAL; + if(strcmp(type, "GUN") == 0) return PED_FLAG_GUN; + if(strcmp(type, "COP_CAR") == 0) return PED_FLAG_COP_CAR; + if(strcmp(type, "FAST_CAR") == 0) return PED_FLAG_FAST_CAR; + if(strcmp(type, "EXPLOSION") == 0) return PED_FLAG_EXPLOSION; + if(strcmp(type, "PROSTITUTE") == 0) return PED_FLAG_PROSTITUTE; + if(strcmp(type, "DEADPEDS") == 0) return PED_FLAG_DEADPEDS; + return 0; +} + +void +CPedType::Save(uint8 *buffer, uint32 *length) +{ + int i; + + *length = 8 + NUM_PEDTYPES*32; + + buffer[0] = 'P'; + buffer[1] = 'T'; + buffer[2] = 'P'; + buffer[3] = '\0'; + *(uint32*)(buffer+4) = *length - 8; + buffer += 8; + + for(i = 0; i < NUM_PEDTYPES; i++){ + *(uint32*)(buffer) = ms_apPedType[i]->m_flag; + *(float*)(buffer+4) = ms_apPedType[i]->unknown1; + *(float*)(buffer+8) = ms_apPedType[i]->unknown2; + *(float*)(buffer+12) = ms_apPedType[i]->unknown3; + *(float*)(buffer+16) = ms_apPedType[i]->unknown4; + *(float*)(buffer+20) = ms_apPedType[i]->unknown5; + *(uint32*)(buffer+24) = ms_apPedType[i]->m_threats; + *(uint32*)(buffer+28) = ms_apPedType[i]->m_avoid; + buffer += 32; + } +} + +void +CPedType::Load(uint8 *buffer, uint32 length) +{ + int i; + + assert(length == 8 + NUM_PEDTYPES*32); + assert(buffer[0] == 'P'); + assert(buffer[1] == 'T'); + assert(buffer[2] == 'P'); + assert(buffer[3] == '\0'); + assert(*(uint32*)(buffer+4) == length - 8); + buffer += 8; + + for(i = 0; i < NUM_PEDTYPES; i++){ + ms_apPedType[i]->m_flag = *(uint32*)(buffer); + ms_apPedType[i]->unknown1 = *(float*)(buffer+4); + ms_apPedType[i]->unknown2 = *(float*)(buffer+8); + ms_apPedType[i]->unknown3 = *(float*)(buffer+12); + ms_apPedType[i]->unknown4 = *(float*)(buffer+16); + ms_apPedType[i]->unknown5 = *(float*)(buffer+20); + ms_apPedType[i]->m_threats = *(uint32*)(buffer+24); + ms_apPedType[i]->m_avoid = *(uint32*)(buffer+28); + buffer += 32; + } +} + +STARTPATCHES + InjectHook(0x4EE7E0, &CPedType::Initialise, PATCH_JUMP); + InjectHook(0x4EE890, &CPedType::Shutdown, PATCH_JUMP); + InjectHook(0x4EEC10, &CPedType::FindPedType, PATCH_JUMP); + InjectHook(0x4EEF40, &CPedType::FindPedFlag, PATCH_JUMP); + InjectHook(0x4EF320, &CPedType::Save, PATCH_JUMP); + InjectHook(0x4EF3D0, &CPedType::Load, PATCH_JUMP); +ENDPATCHES diff --git a/src/peds/PedType.h b/src/peds/PedType.h new file mode 100644 index 00000000..455d8d8d --- /dev/null +++ b/src/peds/PedType.h @@ -0,0 +1,90 @@ +#pragma once + +// Index into the PedType array +enum +{ + PEDTYPE_PLAYER1, + PEDTYPE_PLAYER2, + PEDTYPE_PLAYER3, + PEDTYPE_PLAYER4, + PEDTYPE_CIVMALE, + PEDTYPE_CIVFEMALE, + PEDTYPE_COP, + PEDTYPE_GANG1, + PEDTYPE_GANG2, + PEDTYPE_GANG3, + PEDTYPE_GANG4, + PEDTYPE_GANG5, + PEDTYPE_GANG6, + PEDTYPE_GANG7, + PEDTYPE_GANG8, + PEDTYPE_GANG9, + PEDTYPE_EMERGENCY, + PEDTYPE_FIREMAN, + PEDTYPE_CRIMINAL, + PEDTYPE_UNUSED1, + PEDTYPE_PROSTITUTE, + PEDTYPE_SPECIAL, + PEDTYPE_UNUSED2, + + NUM_PEDTYPES +}; + +enum +{ + PED_FLAG_PLAYER1 = 1 << 0, + PED_FLAG_PLAYER2 = 1 << 1, + PED_FLAG_PLAYER3 = 1 << 2, + PED_FLAG_PLAYER4 = 1 << 3, + PED_FLAG_CIVMALE = 1 << 4, + PED_FLAG_CIVFEMALE = 1 << 5, + PED_FLAG_COP = 1 << 6, + PED_FLAG_GANG1 = 1 << 7, + PED_FLAG_GANG2 = 1 << 8, + PED_FLAG_GANG3 = 1 << 9, + PED_FLAG_GANG4 = 1 << 10, + PED_FLAG_GANG5 = 1 << 11, + PED_FLAG_GANG6 = 1 << 12, + PED_FLAG_GANG7 = 1 << 13, + PED_FLAG_GANG8 = 1 << 14, + PED_FLAG_GANG9 = 1 << 15, + PED_FLAG_EMERGENCY = 1 << 16, + PED_FLAG_PROSTITUTE = 1 << 17, + PED_FLAG_CRIMINAL = 1 << 18, + PED_FLAG_SPECIAL = 1 << 19, + PED_FLAG_GUN = 1 << 20, + PED_FLAG_COP_CAR = 1 << 21, + PED_FLAG_FAST_CAR = 1 << 22, + PED_FLAG_EXPLOSION = 1 << 23, + PED_FLAG_FIREMAN = 1 << 24, + PED_FLAG_DEADPEDS = 1 << 25, +}; + +class CPedType +{ + uint32 m_flag; + float unknown1; + float unknown2; + float unknown3; + float unknown4; + float unknown5; + uint32 m_threats; + uint32 m_avoid; + + static CPedType *(&ms_apPedType)[NUM_PEDTYPES]; +public: + + static void Initialise(void); + static void Shutdown(void); + static void LoadPedData(void); + static int32 FindPedType(char *type); + static uint32 FindPedFlag(char *type); + static void Save(uint8 *buffer, uint32 *length); + static void Load(uint8 *buffer, uint32 length); + + static uint32 GetFlag(int type) { return ms_apPedType[type]->m_flag; } + static uint32 GetAvoid(int type) { return ms_apPedType[type]->m_avoid; } + static uint32 GetThreats(int type) { return ms_apPedType[type]->m_threats; } +}; + +static_assert(sizeof(CPedType) == 0x20, "CPedType: error"); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp new file mode 100644 index 00000000..2d67d5b2 --- /dev/null +++ b/src/peds/PlayerPed.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "patcher.h" +#include "PlayerPed.h" + +CPlayerPed::~CPlayerPed() +{ + delete m_pWanted; +} + +WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); } + +STARTPATCHES + InjectHook(0x4EFB30, &CPlayerPed::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h new file mode 100644 index 00000000..15ad74a6 --- /dev/null +++ b/src/peds/PlayerPed.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Ped.h" +#include "Wanted.h" + +class CPlayerPed : public CPed +{ +public: + CWanted *m_pWanted; + CCopPed *m_pArrestingCop; + float m_fMoveSpeed; + float m_fCurrentStamina; + float m_fMaxStamina; + float m_fStaminaProgress; + bool m_bWeaponSlot; + bool m_bSpeedTimerFlag; + bool m_bShouldEvade; + int8 field_1367; + int32 m_nSpeedTimer; + int32 m_nShotDelay; + float field_1376; + int8 field_1380; // set if can't attack, why? + int8 field_1381; + int8 field_1382; + int8 field_1383; + CEntity *m_pEvadingFrom; + int32 m_nTargettableObjects[4]; + bool m_bAdrenalineActive; + bool m_bHasLockOnTarget; + int8 field_1406; + int8 field_1407; + bool m_bAdrenalineTime; + bool m_bCanBeDamaged; + int8 field_1413; + int8 field_1414; + int8 field_1415; + CVector field_1416[6]; + int32 field_1488[6]; + float m_fWalkAngle; + float m_fFPSMoveHeading; + + ~CPlayerPed(); + + void dtor(void) { this->CPlayerPed::~CPlayerPed(); } + void ReApplyMoveAnims(void); +}; + +static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error"); diff --git a/src/re3.cpp b/src/re3.cpp deleted file mode 100644 index 9dc39d46..00000000 --- a/src/re3.cpp +++ /dev/null @@ -1,381 +0,0 @@ -#include -#include -#include -#include "common.h" -#include "patcher.h" -#include "Renderer.h" -#include "Credits.h" -#include "Camera.h" -#include "Weather.h" -#include "Clock.h" -#include "World.h" -#include "Vehicle.h" -#include "Streaming.h" -#include "PathFind.h" -#include "Boat.h" -#include "Automobile.h" -#include "debugmenu_public.h" - -#include - -std::vector usedAddresses; - -void **rwengine = *(void***)0x5A10E1; - -DebugMenuAPI gDebugMenuAPI; - -WRAPPER void *gtanew(uint32 sz) { EAXJMP(0x5A0690); } -WRAPPER void gtadelete(void *p) { EAXJMP(0x5A07E0); } - -// overload our own new/delete with GTA's functions -void *operator new(size_t sz) { return gtanew(sz); } -void operator delete(void *ptr) noexcept { gtadelete(ptr); } - -#ifdef USE_PS2_RAND -unsigned __int64 myrand_seed = 1; -#else -unsigned long int myrand_seed = 1; -#endif - -int -myrand(void) -{ -#ifdef USE_PS2_RAND - // Use our own implementation of rand, stolen from PS2 - myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1; - return ((myrand_seed >> 32) & 0x7FFFFFFF); -#else - // or original codewarrior rand - myrand_seed = myrand_seed * 1103515245 + 12345; - return((myrand_seed >> 16) & 0x7FFF); -#endif -} - -void -mysrand(unsigned int seed) -{ - myrand_seed = seed; -} - -int (*open_script_orig)(const char *path, const char *mode); -int -open_script(const char *path, const char *mode) -{ - static int scriptToLoad = 1; - - if(GetAsyncKeyState('G') & 0x8000) - scriptToLoad = 0; - if(GetAsyncKeyState('R') & 0x8000) - scriptToLoad = 1; - if(GetAsyncKeyState('D') & 0x8000) - scriptToLoad = 2; - - switch(scriptToLoad){ - case 0: return open_script_orig(path, mode); - case 1: return open_script_orig("main_freeroam.scm", mode); - case 2: return open_script_orig("main_d.scm", mode); - } - return open_script_orig(path, mode); -} - -int gDbgSurf; - -void (*DebugMenuProcess)(void); -void (*DebugMenuRender)(void); -static void stub(void) { } - -void -DebugMenuInit(void) -{ - if(DebugMenuLoad()){ - DebugMenuProcess = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuProcess"); - DebugMenuRender = (void(*)(void))GetProcAddress(gDebugMenuAPI.module, "DebugMenuRender"); - } - if(DebugMenuProcess == nil || DebugMenuRender == nil){ - DebugMenuProcess = stub; - DebugMenuRender = stub; - } - -} - -void WeaponCheat(); -void HealthCheat(); -void TankCheat(); -void BlowUpCarsCheat(); -void ChangePlayerCheat(); -void MayhemCheat(); -void EverybodyAttacksPlayerCheat(); -void WeaponsForAllCheat(); -void FastTimeCheat(); -void SlowTimeCheat(); -void MoneyCheat(); -void ArmourCheat(); -void WantedLevelUpCheat(); -void WantedLevelDownCheat(); -void SunnyWeatherCheat(); -void CloudyWeatherCheat(); -void RainyWeatherCheat(); -void FoggyWeatherCheat(); -void FastWeatherCheat(); -void OnlyRenderWheelsCheat(); -void ChittyChittyBangBangCheat(); -void StrongGripCheat(); -void NastyLimbsCheat(); - -// needs too much stuff for now -#if 0 -void -spawnCar(int id) -{ - CVector playerpos; - CStreaming::RequestModel(id, 0); - CStreaming::LoadAllRequestedModels(false); - if(CStreaming::HasModelLoaded(id)){ - FindPlayerCoors(playerpos); - int node = ThePaths.FindNodeClosestToCoors(playerpos, 0, 100.0f, false, false); - if(node < 0) - return; - - CVehicle *v; - if(CModelInfo::IsBoatModel(id)){ -// CBoat* boat = (CBoat*)CVehicle__new(0x484); -// boat = boat->ctor(id, 1); -// v = (CVehicle*)(boat); - }else{ -// CAutomobile *au = (CAutomobile*)CVehicle__new(0x5A8); -// au = au->ctor(id, 1); -// v = (CVehicle*)au; - } -/* - // unlock doors - FIELD(int, v, 0x224) = 1; - // set player owned - FIELD(uint8, v, 0x1F7) |= 4; - - DebugMenuEntrySetAddress(carCol1, &FIELD(uchar, v, 0x19C)); - DebugMenuEntrySetAddress(carCol2, &FIELD(uchar, v, 0x19D)); - //if(id == MODELID_ESPERANTO) - // FIELD(uchar, v, 0x19C) = 54; - - v->matrix.matrix.pos.x = ThePaths.nodes[node].x; - v->matrix.matrix.pos.y = ThePaths.nodes[node].y; - v->matrix.matrix.pos.z = ThePaths.nodes[node].z + 4.0f; - float x = v->matrix.matrix.pos.x; - float y = v->matrix.matrix.pos.y; - float z = v->matrix.matrix.pos.z; - v->matrix.SetRotate(0.0f, 0.0f, 3.49f); - v->matrix.matrix.pos.x += x; - v->matrix.matrix.pos.y += y; - v->matrix.matrix.pos.z += z; - v->bfTypeStatus = v->bfTypeStatus & 7 | 0x20; - FIELD(int, v, 0x224) = 1; -*/ - CWorld::Add(v); - } -} -#endif - -void -DebugMenuPopulate(void) -{ - if(DebugMenuLoad()){ - static const char *weathers[] = { - "Sunny", "Cloudy", "Rainy", "Foggy" - }; - DebugMenuEntry *e; - e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil); - DebugMenuEntrySetWrap(e, true); - e = DebugMenuAddVar("Time & Weather", "Current Minute", &CClock::GetMinutesRef(), - [](){ CWeather::InterpolationValue = CClock::GetMinutes()/60.0f; }, 1, 0, 59, nil); - DebugMenuEntrySetWrap(e, true); - e = DebugMenuAddVar("Time & Weather", "Old Weather", (int16*)&CWeather::OldWeatherType, nil, 1, 0, 3, weathers); - DebugMenuEntrySetWrap(e, true); - e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers); - DebugMenuEntrySetWrap(e, true); - DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f); - DebugMenuAddVar("Time & Weather", "Time scale", (float*)0x8F2C20, nil, 0.1f, 0.0f, 10.0f); - - DebugMenuAddCmd("Cheats", "Weapons", WeaponCheat); - DebugMenuAddCmd("Cheats", "Money", MoneyCheat); - DebugMenuAddCmd("Cheats", "Health", HealthCheat); - DebugMenuAddCmd("Cheats", "Wanted level up", WantedLevelUpCheat); - DebugMenuAddCmd("Cheats", "Wanted level down", WantedLevelDownCheat); - DebugMenuAddCmd("Cheats", "Tank", TankCheat); - DebugMenuAddCmd("Cheats", "Blow up cars", BlowUpCarsCheat); - DebugMenuAddCmd("Cheats", "Change player", ChangePlayerCheat); - DebugMenuAddCmd("Cheats", "Mayhem", MayhemCheat); - DebugMenuAddCmd("Cheats", "Everybody attacks player", EverybodyAttacksPlayerCheat); - DebugMenuAddCmd("Cheats", "Weapons for all", WeaponsForAllCheat); - DebugMenuAddCmd("Cheats", "Fast time", FastTimeCheat); - DebugMenuAddCmd("Cheats", "Slow time", SlowTimeCheat); - DebugMenuAddCmd("Cheats", "Armour", ArmourCheat); - DebugMenuAddCmd("Cheats", "Sunny weather", SunnyWeatherCheat); - DebugMenuAddCmd("Cheats", "Cloudy weather", CloudyWeatherCheat); - DebugMenuAddCmd("Cheats", "Rainy weather", RainyWeatherCheat); - DebugMenuAddCmd("Cheats", "Foggy weather", FoggyWeatherCheat); - DebugMenuAddCmd("Cheats", "Fast weather", FastWeatherCheat); - DebugMenuAddCmd("Cheats", "Only render wheels", OnlyRenderWheelsCheat); - DebugMenuAddCmd("Cheats", "Chitty chitty bang bang", ChittyChittyBangBangCheat); - DebugMenuAddCmd("Cheats", "Strong grip", StrongGripCheat); - DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat); - - DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil); - DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil); - DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil); - DebugMenuAddVarBool8("Debug", "Don't render Buildings", (int8*)&gbDontRenderBuildings, nil); - DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil); - DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil); - DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil); - DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil); - - DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); - DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); - } -} - -/* -int (*RsEventHandler_orig)(int a, int b); -int -delayedPatches10(int a, int b) -{ - DebugMenuInit(); - DebugMenuPopulate(); - - return RsEventHandler_orig(a, b); -} -*/ - -void __declspec(naked) HeadlightsFix() -{ - static const float fMinusOne = -1.0f; - _asm - { - fld [esp+708h-690h] - fcomp fMinusOne - fnstsw ax - and ah, 5 - cmp ah, 1 - jnz HeadlightsFix_DontLimit - fld fMinusOne - fstp [esp+708h-690h] - -HeadlightsFix_DontLimit: - fld [esp+708h-690h] - fabs - fld st - push 0x5382F2 - retn - } -} - -const int re3_buffsize = 1024; -static char re3_buff[re3_buffsize]; - -void re3_assert(const char *expr, const char *filename, unsigned int lineno, const char *func) -{ - int nCode; - - strcpy_s(re3_buff, re3_buffsize, "Assertion failed!" ); - strcat_s(re3_buff, re3_buffsize, "\n" ); - - strcat_s(re3_buff, re3_buffsize, "File: "); - strcat_s(re3_buff, re3_buffsize, filename ); - strcat_s(re3_buff, re3_buffsize, "\n" ); - - strcat_s(re3_buff, re3_buffsize, "Line: " ); - _itoa_s( lineno, re3_buff + strlen(re3_buff), re3_buffsize - strlen(re3_buff), 10 ); - strcat_s(re3_buff, re3_buffsize, "\n"); - - strcat_s(re3_buff, re3_buffsize, "Function: "); - strcat_s(re3_buff, re3_buffsize, func ); - strcat_s(re3_buff, re3_buffsize, "\n" ); - - strcat_s(re3_buff, re3_buffsize, "Expression: "); - strcat_s(re3_buff, re3_buffsize, expr); - strcat_s(re3_buff, re3_buffsize, "\n"); - - strcat_s(re3_buff, re3_buffsize, "\n" ); - strcat_s(re3_buff, re3_buffsize, "(Press Retry to debug the application)"); - - - nCode = ::MessageBoxA(nil, re3_buff, "RE3 Assertion Failed!", - MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL); - - if (nCode == IDABORT) - { - raise(SIGABRT); - _exit(3); - } - - if (nCode == IDRETRY) - { - __debugbreak(); - return; - } - - if (nCode == IDIGNORE) - return; - - abort(); -} - -void re3_debug(char *format, ...) -{ - va_list va; - va_start(va, format); - vsprintf_s(re3_buff, re3_buffsize, format, va); - va_end(va); - - printf("%s", re3_buff); -} - -void re3_trace(const char *filename, unsigned int lineno, const char *func, char *format, ...) -{ - char buff[re3_buffsize *2]; - va_list va; - va_start(va, format); - vsprintf_s(re3_buff, re3_buffsize, format, va); - va_end(va); - - sprintf_s(buff, re3_buffsize * 2, "[%s.%s:%d]: %s", filename, func, lineno, re3_buff); - - OutputDebugStringA(buff); -} - -void -patch() -{ - StaticPatcher::Apply(); - -// Patch(0x46BC61+6, 1.0f); // car distance - InjectHook(0x59E460, printf, PATCH_JUMP); - InjectHook(0x475E00, printf, PATCH_JUMP); // _Error - - - // stolen from silentpatch (sorry) - Patch(0x5382BF, 0x0EEB); - InjectHook(0x5382EC, HeadlightsFix, PATCH_JUMP); - - InterceptCall(&open_script_orig, open_script, 0x438869); - -// InterceptCall(&RsEventHandler_orig, delayedPatches10, 0x58275E); -} - -BOOL WINAPI -DllMain(HINSTANCE hInst, DWORD reason, LPVOID) -{ - if(reason == DLL_PROCESS_ATTACH){ - - AllocConsole(); - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - - if (*(DWORD*)0x5C1E75 == 0xB85548EC) // 1.0 - patch(); - else - return FALSE; - } - - return TRUE; -} diff --git a/src/render/Lights.cpp b/src/render/Lights.cpp index 1e27ec48..cd83a898 100644 --- a/src/render/Lights.cpp +++ b/src/render/Lights.cpp @@ -6,7 +6,7 @@ #include "Timecycle.h" #include "Coronas.h" #include "Weather.h" -#include "CullZones.h" +#include "ZoneCull.h" #include "Frontend.h" RpLight *&pAmbient = *(RpLight**)0x885B6C; diff --git a/src/render/Timecycle.cpp b/src/render/Timecycle.cpp new file mode 100644 index 00000000..af154716 --- /dev/null +++ b/src/render/Timecycle.cpp @@ -0,0 +1,322 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "Clock.h" +#include "Weather.h" +#include "Camera.h" +#include "Shadows.h" +#include "ZoneCull.h" +#include "CutsceneMgr.h" +#include "FileMgr.h" +#include "Timecycle.h" + +int (*CTimeCycle::m_nAmbientRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86AF78; +int (*CTimeCycle::m_nAmbientGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x665308; +int (*CTimeCycle::m_nAmbientBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72CF88; +int (*CTimeCycle::m_nDirectionalRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FAB78; +int (*CTimeCycle::m_nDirectionalGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F4528; +int (*CTimeCycle::m_nDirectionalBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83CE58; +int (*CTimeCycle::m_nSkyTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FB90; +int (*CTimeCycle::m_nSkyTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x8460A8; +int (*CTimeCycle::m_nSkyTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87B158; +int (*CTimeCycle::m_nSkyBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6FA960; +int (*CTimeCycle::m_nSkyBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70D6A8; +int (*CTimeCycle::m_nSkyBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x83D288; +int (*CTimeCycle::m_nSunCoreRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x878360; +int (*CTimeCycle::m_nSunCoreGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE088; +int (*CTimeCycle::m_nSunCoreBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x773A68; +int (*CTimeCycle::m_nSunCoronaRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x664B60; +int (*CTimeCycle::m_nSunCoronaGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6F01E0; +int (*CTimeCycle::m_nSunCoronaBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E6340; +float (*CTimeCycle::m_fSunSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733510; +float (*CTimeCycle::m_fSpriteSize)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87F820; +float (*CTimeCycle::m_fSpriteBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x6E96F0; +short (*CTimeCycle::m_nShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x83CFD8; +short (*CTimeCycle::m_nLightShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x72B0F8; +short (*CTimeCycle::m_nTreeShadowStrength)[NUMWEATHERS] = (short(*)[NUMWEATHERS])0x733450; +float (*CTimeCycle::m_fFogStart)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8806C8; +float (*CTimeCycle::m_fFarClip)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8804E0; +float (*CTimeCycle::m_fLightsOnGroundBrightness)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x83D108; +int (*CTimeCycle::m_nLowCloudsRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x726770; +int (*CTimeCycle::m_nLowCloudsGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87BF08; +int (*CTimeCycle::m_nLowCloudsBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x87FA10; +int (*CTimeCycle::m_nFluffyCloudsTopRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x70F2B0; +int (*CTimeCycle::m_nFluffyCloudsTopGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x72D288; +int (*CTimeCycle::m_nFluffyCloudsTopBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x86B108; +int (*CTimeCycle::m_nFluffyCloudsBottomRed)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6E8DA8; +int (*CTimeCycle::m_nFluffyCloudsBottomGreen)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x715AA8; +int (*CTimeCycle::m_nFluffyCloudsBottomBlue)[NUMWEATHERS] = (int(*)[NUMWEATHERS])0x6EE2D0; +float (*CTimeCycle::m_fBlurRed)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x87C7E0; +float (*CTimeCycle::m_fBlurGreen)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x774C10; +float (*CTimeCycle::m_fBlurBlue)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x8784E0; +float (*CTimeCycle::m_fBlurAlpha)[NUMWEATHERS] = (float(*)[NUMWEATHERS])0x733690; + +float &CTimeCycle::m_fCurrentAmbientRed = *(float*)0x8F29B4; +float &CTimeCycle::m_fCurrentAmbientGreen = *(float*)0x94144C; +float &CTimeCycle::m_fCurrentAmbientBlue = *(float*)0x942FC0; +float &CTimeCycle::m_fCurrentDirectionalRed = *(float*)0x8F29D8; +float &CTimeCycle::m_fCurrentDirectionalGreen = *(float*)0x940594; +float &CTimeCycle::m_fCurrentDirectionalBlue = *(float*)0x942FAC; +int &CTimeCycle::m_nCurrentSkyTopRed = *(int*)0x9403C0; +int &CTimeCycle::m_nCurrentSkyTopGreen = *(int*)0x943074; +int &CTimeCycle::m_nCurrentSkyTopBlue = *(int*)0x8F29B8; +int &CTimeCycle::m_nCurrentSkyBottomRed = *(int*)0x9414D0; +int &CTimeCycle::m_nCurrentSkyBottomGreen = *(int*)0x8F2BD0; +int &CTimeCycle::m_nCurrentSkyBottomBlue = *(int*)0x8F625C; +int &CTimeCycle::m_nCurrentSunCoreRed = *(int*)0x8F2534; +int &CTimeCycle::m_nCurrentSunCoreGreen = *(int*)0x8F6264; +int &CTimeCycle::m_nCurrentSunCoreBlue = *(int*)0x94149C; +int &CTimeCycle::m_nCurrentSunCoronaRed = *(int*)0x8F2C1C; +int &CTimeCycle::m_nCurrentSunCoronaGreen = *(int*)0x885B54; +int &CTimeCycle::m_nCurrentSunCoronaBlue = *(int*)0x880F60; +float &CTimeCycle::m_fCurrentSunSize = *(float*)0x940588; +float &CTimeCycle::m_fCurrentSpriteSize = *(float*)0x8F1AA8; +float &CTimeCycle::m_fCurrentSpriteBrightness = *(float*)0x8F5FDC; +int &CTimeCycle::m_nCurrentShadowStrength = *(int*)0x95CC76; +int &CTimeCycle::m_nCurrentLightShadowStrength = *(int*)0x95CC66; +int &CTimeCycle::m_nCurrentTreeShadowStrength = *(int*)0x95CC86; +float &CTimeCycle::m_fCurrentFogStart = *(float*)0x8F1AE0; +float &CTimeCycle::m_fCurrentFarClip = *(float*)0x8F5FD8; +float &CTimeCycle::m_fCurrentLightsOnGroundBrightness = *(float*)0x8F1B60; +int &CTimeCycle::m_nCurrentLowCloudsRed = *(int*)0x95CB54; +int &CTimeCycle::m_nCurrentLowCloudsGreen = *(int*)0x95CB48; +int &CTimeCycle::m_nCurrentLowCloudsBlue = *(int*)0x95CC1C; +int &CTimeCycle::m_nCurrentFluffyCloudsTopRed = *(int*)0x8F2550; +int &CTimeCycle::m_nCurrentFluffyCloudsTopGreen = *(int*)0x8F59CC; +int &CTimeCycle::m_nCurrentFluffyCloudsTopBlue = *(int*)0x941434; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomRed = *(int*)0x8F1A38; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomGreen = *(int*)0x8E28B8; +int &CTimeCycle::m_nCurrentFluffyCloudsBottomBlue = *(int*)0x8F3960; +float &CTimeCycle::m_fCurrentBlurRed = *(float*)0x8F6000; +float &CTimeCycle::m_fCurrentBlurGreen = *(float*)0x9405A0; +float &CTimeCycle::m_fCurrentBlurBlue = *(float*)0x8F250C; +float &CTimeCycle::m_fCurrentBlurAlpha = *(float*)0x940728; +int &CTimeCycle::m_nCurrentFogColourRed = *(int*)0x940714; +int &CTimeCycle::m_nCurrentFogColourGreen = *(int*)0x8E2A60; +int &CTimeCycle::m_nCurrentFogColourBlue = *(int*)0x8F57EC; + +int &CTimeCycle::m_FogReduction = *(int*)0x880FB8; + +int &CTimeCycle::m_CurrentStoredValue = *(int*)0x94057C; +CVector *CTimeCycle::m_VectorToSun = (CVector*)0x665548; // [16] +float *CTimeCycle::m_fShadowFrontX = (float*)0x72CE90; +float *CTimeCycle::m_fShadowFrontY = (float*)0x72CE50; +float *CTimeCycle::m_fShadowSideX = (float*)0x87C708; +float *CTimeCycle::m_fShadowSideY = (float*)0x87C6C8; +float *CTimeCycle::m_fShadowDisplacementX = (float*)0x6F0748; +float *CTimeCycle::m_fShadowDisplacementY = (float*)0x6F0788; + + +void +CTimeCycle::Initialise(void) +{ + int w, h; + int li, bi; + char line[1040]; + + int ambR, ambG, ambB; + int dirR, dirG, dirB; + int skyTopR, skyTopG, skyTopB; + int skyBotR, skyBotG, skyBotB; + int sunCoreR, sunCoreG, sunCoreB; + int sunCoronaR, sunCoronaG, sunCoronaB; + float sunSz, sprSz, sprBght; + int shad, lightShad, treeShad; + float farClp, fogSt, lightGnd; + int cloudR, cloudG, cloudB; + int fluffyTopR, fluffyTopG, fluffyTopB; + int fluffyBotR, fluffyBotG, fluffyBotB; + float blurR, blurG, blurB, blurA; + + debug("Intialising CTimeCycle...\n"); + + CFileMgr::SetDir("DATA"); + CFileMgr::LoadFile("TIMECYC.DAT", work_buff, sizeof(work_buff), "rb"); + CFileMgr::SetDir(""); + + line[0] = '\0'; + bi = 0; + for(w = 0; w < NUMWEATHERS; w++) + for(h = 0; h < NUMHOURS; h++){ + li = 0; + while(work_buff[bi] == '/'){ + while(work_buff[bi] != '\n') + bi++; + bi++; + } + while(work_buff[bi] != '\n') + line[li++] = work_buff[bi++]; + line[li] = '\0'; + bi++; + + sscanf(line, "%d %d %d %d %d %d %d %d %d %d %d %d " + "%d %d %d %d %d %d %f %f %f %d %d %d %f %f %f " + "%d %d %d %d %d %d %d %d %d %f %f %f %f", + &ambR, &ambG, &ambB, + &dirR, &dirG, &dirB, + &skyTopR, &skyTopG, &skyTopB, + &skyBotR, &skyBotG, &skyBotB, + &sunCoreR, &sunCoreG, &sunCoreB, + &sunCoronaR, &sunCoronaG, &sunCoronaB, + &sunSz, &sprSz, &sprBght, + &shad, &lightShad, &treeShad, + &farClp, &fogSt, &lightGnd, + &cloudR, &cloudG, &cloudB, + &fluffyTopR, &fluffyTopG, &fluffyTopB, + &fluffyBotR, &fluffyBotG, &fluffyBotB, + &blurR, &blurG, &blurB, &blurA); + + m_nAmbientRed[h][w] = ambR; + m_nAmbientGreen[h][w] = ambG; + m_nAmbientBlue[h][w] = ambB; + m_nDirectionalRed[h][w] = dirR; + m_nDirectionalGreen[h][w] = dirG; + m_nDirectionalBlue[h][w] = dirB; + m_nSkyTopRed[h][w] = skyTopR; + m_nSkyTopGreen[h][w] = skyTopG; + m_nSkyTopBlue[h][w] = skyTopB; + m_nSkyBottomRed[h][w] = skyBotR; + m_nSkyBottomGreen[h][w] = skyBotG; + m_nSkyBottomBlue[h][w] = skyBotB; + m_nSunCoreRed[h][w] = sunCoreR; + m_nSunCoreGreen[h][w] = sunCoreG; + m_nSunCoreBlue[h][w] = sunCoreB; + m_nSunCoronaRed[h][w] = sunCoronaR; + m_nSunCoronaGreen[h][w] = sunCoronaG; + m_nSunCoronaBlue[h][w] = sunCoronaB; + m_fSunSize[h][w] = sunSz; + m_fSpriteSize[h][w] = sprSz; + m_fSpriteBrightness[h][w] = sprBght; + m_nShadowStrength[h][w] = shad; + m_nLightShadowStrength[h][w] = lightShad; + m_nTreeShadowStrength[h][w] = treeShad; + m_fFarClip[h][w] = farClp; + m_fFogStart[h][w] = fogSt; + m_fLightsOnGroundBrightness[h][w] = lightGnd; + m_nLowCloudsRed[h][w] = cloudR; + m_nLowCloudsGreen[h][w] = cloudG; + m_nLowCloudsBlue[h][w] = cloudB; + m_nFluffyCloudsTopRed[h][w] = fluffyTopR; + m_nFluffyCloudsTopGreen[h][w] = fluffyTopG; + m_nFluffyCloudsTopBlue[h][w] = fluffyTopB; + m_nFluffyCloudsBottomRed[h][w] = fluffyBotR; + m_nFluffyCloudsBottomGreen[h][w] = fluffyBotG; + m_nFluffyCloudsBottomBlue[h][w] = fluffyBotB; + m_fBlurRed[h][w] = blurR; + m_fBlurGreen[h][w] = blurG; + m_fBlurBlue[h][w] = blurB; + m_fBlurAlpha[h][w] = blurA; + } + + m_FogReduction = 0; + + debug("CTimeCycle ready\n"); +} + +void +CTimeCycle::Update(void) +{ + int h1 = CClock::GetHours(); + int h2 = (h1+1)%24; + int w1 = CWeather::OldWeatherType; + int w2 = CWeather::NewWeatherType; + float timeInterp = CClock::GetMinutes()/60.0f; + // coefficients for a bilinear interpolation + float c0 = (1.0f-timeInterp) * (1.0f-CWeather::InterpolationValue); + float c1 = timeInterp * (1.0f-CWeather::InterpolationValue); + float c2 = (1.0f-timeInterp) * CWeather::InterpolationValue; + float c3 = timeInterp * CWeather::InterpolationValue; + +#define INTERP(v) v[h1][w1]*c0 + v[h2][w1]*c1 + v[h1][w2]*c2 + v[h2][w2]*c3; + + m_nCurrentSkyTopRed = INTERP(m_nSkyTopRed); + m_nCurrentSkyTopGreen = INTERP(m_nSkyTopGreen); + m_nCurrentSkyTopBlue = INTERP(m_nSkyTopBlue); + + m_nCurrentSkyBottomRed = INTERP(m_nSkyBottomRed); + m_nCurrentSkyBottomGreen = INTERP(m_nSkyBottomGreen); + m_nCurrentSkyBottomBlue = INTERP(m_nSkyBottomBlue); + + m_fCurrentAmbientRed = INTERP(m_nAmbientRed); + m_fCurrentAmbientGreen = INTERP(m_nAmbientGreen); + m_fCurrentAmbientBlue = INTERP(m_nAmbientBlue); + m_fCurrentAmbientRed /= 255.0f; + m_fCurrentAmbientGreen /= 255.0f; + m_fCurrentAmbientBlue /= 255.0f; + + m_fCurrentDirectionalRed = INTERP(m_nDirectionalRed); + m_fCurrentDirectionalGreen = INTERP(m_nDirectionalGreen); + m_fCurrentDirectionalBlue = INTERP(m_nDirectionalBlue); + m_fCurrentDirectionalRed /= 255.0f; + m_fCurrentDirectionalGreen /= 255.0f; + m_fCurrentDirectionalBlue /= 255.0f; + + m_nCurrentSunCoreRed = INTERP(m_nSunCoreRed); + m_nCurrentSunCoreGreen = INTERP(m_nSunCoreGreen); + m_nCurrentSunCoreBlue = INTERP(m_nSunCoreBlue); + + m_nCurrentSunCoronaRed = INTERP(m_nSunCoronaRed); + m_nCurrentSunCoronaGreen = INTERP(m_nSunCoronaGreen); + m_nCurrentSunCoronaBlue = INTERP(m_nSunCoronaBlue); + + m_fCurrentSunSize = INTERP(m_fSunSize); + m_fCurrentSpriteSize = INTERP(m_fSpriteSize); + m_fCurrentSpriteBrightness = INTERP(m_fSpriteBrightness); + m_nCurrentShadowStrength = INTERP(m_nShadowStrength); + m_nCurrentLightShadowStrength = INTERP(m_nLightShadowStrength); + m_nCurrentTreeShadowStrength = INTERP(m_nTreeShadowStrength); + m_fCurrentFarClip = INTERP(m_fFarClip); + m_fCurrentFogStart = INTERP(m_fFogStart); + m_fCurrentLightsOnGroundBrightness = INTERP(m_fLightsOnGroundBrightness); + + m_nCurrentLowCloudsRed = INTERP(m_nLowCloudsRed); + m_nCurrentLowCloudsGreen = INTERP(m_nLowCloudsGreen); + m_nCurrentLowCloudsBlue = INTERP(m_nLowCloudsBlue); + + m_nCurrentFluffyCloudsTopRed = INTERP(m_nFluffyCloudsTopRed); + m_nCurrentFluffyCloudsTopGreen = INTERP(m_nFluffyCloudsTopGreen); + m_nCurrentFluffyCloudsTopBlue = INTERP(m_nFluffyCloudsTopBlue); + + m_nCurrentFluffyCloudsBottomRed = INTERP(m_nFluffyCloudsBottomRed); + m_nCurrentFluffyCloudsBottomGreen = INTERP(m_nFluffyCloudsBottomGreen); + m_nCurrentFluffyCloudsBottomBlue = INTERP(m_nFluffyCloudsBottomBlue); + + m_fCurrentBlurRed = INTERP(m_fBlurRed); + m_fCurrentBlurGreen = INTERP(m_fBlurGreen); + m_fCurrentBlurBlue = INTERP(m_fBlurBlue); + m_fCurrentBlurAlpha = INTERP(m_fBlurAlpha); + + if(TheCamera.m_BlurType == MBLUR_NONE || TheCamera.m_BlurType == MBLUR_NORMAL) + TheCamera.SetMotionBlur(m_fCurrentBlurRed, m_fCurrentBlurGreen, m_fCurrentBlurBlue, m_fCurrentBlurAlpha, MBLUR_NORMAL); + + if(m_FogReduction != 0) + m_fCurrentFarClip = max(m_fCurrentFarClip, m_FogReduction/64.0f * 650.0f); + m_nCurrentFogColourRed = (m_nCurrentSkyTopRed + 2*m_nCurrentSkyBottomRed) / 3; + m_nCurrentFogColourGreen = (m_nCurrentSkyTopGreen + 2*m_nCurrentSkyBottomGreen) / 3; + m_nCurrentFogColourBlue = (m_nCurrentSkyTopBlue + 2*m_nCurrentSkyBottomBlue) / 3; + + m_CurrentStoredValue = (m_CurrentStoredValue+1)&0xF; + + float sunAngle = 2*PI*(CClock::GetMinutes() + CClock::GetHours()*60)/(24*60); + CVector &sunPos = GetSunPosition(); + sunPos.x = sinf(sunAngle); + sunPos.y = 1.0f; + sunPos.z = 0.2f - cosf(sunAngle); + sunPos.Normalise(); + + CShadows::CalcPedShadowValues(sunPos, + &m_fShadowFrontX[m_CurrentStoredValue], &m_fShadowFrontY[m_CurrentStoredValue], + &m_fShadowSideX[m_CurrentStoredValue], &m_fShadowSideY[m_CurrentStoredValue], + &m_fShadowDisplacementX[m_CurrentStoredValue], &m_fShadowDisplacementY[m_CurrentStoredValue]); + + if(TheCamera.GetForward().z < -0.9f || + !CWeather::bScriptsForceRain && (CCullZones::PlayerNoRain() || CCullZones::CamNoRain() || CCutsceneMgr::IsRunning())) + m_FogReduction = min(m_FogReduction+1, 64); + else + m_FogReduction = max(m_FogReduction-1, 0); +} + +STARTPATCHES + InjectHook(0x4ABAE0, CTimeCycle::Initialise, PATCH_JUMP); + InjectHook(0x4ABF40, CTimeCycle::Update, PATCH_JUMP); +ENDPATCHES diff --git a/src/render/Timecycle.h b/src/render/Timecycle.h new file mode 100644 index 00000000..71ddedb7 --- /dev/null +++ b/src/render/Timecycle.h @@ -0,0 +1,141 @@ +#pragma once + +class CTimeCycle +{ + static int (*m_nAmbientRed)[NUMWEATHERS]; + static int (*m_nAmbientGreen)[NUMWEATHERS]; + static int (*m_nAmbientBlue)[NUMWEATHERS]; + static int (*m_nDirectionalRed)[NUMWEATHERS]; + static int (*m_nDirectionalGreen)[NUMWEATHERS]; + static int (*m_nDirectionalBlue)[NUMWEATHERS]; + static int (*m_nSkyTopRed)[NUMWEATHERS]; + static int (*m_nSkyTopGreen)[NUMWEATHERS]; + static int (*m_nSkyTopBlue)[NUMWEATHERS]; + static int (*m_nSkyBottomRed)[NUMWEATHERS]; + static int (*m_nSkyBottomGreen)[NUMWEATHERS]; + static int (*m_nSkyBottomBlue)[NUMWEATHERS]; + static int (*m_nSunCoreRed)[NUMWEATHERS]; + static int (*m_nSunCoreGreen)[NUMWEATHERS]; + static int (*m_nSunCoreBlue)[NUMWEATHERS]; + static int (*m_nSunCoronaRed)[NUMWEATHERS]; + static int (*m_nSunCoronaGreen)[NUMWEATHERS]; + static int (*m_nSunCoronaBlue)[NUMWEATHERS]; + static float (*m_fSunSize)[NUMWEATHERS]; + static float (*m_fSpriteSize)[NUMWEATHERS]; + static float (*m_fSpriteBrightness)[NUMWEATHERS]; + static short (*m_nShadowStrength)[NUMWEATHERS]; + static short (*m_nLightShadowStrength)[NUMWEATHERS]; + static short (*m_nTreeShadowStrength)[NUMWEATHERS]; + static float (*m_fFogStart)[NUMWEATHERS]; + static float (*m_fFarClip)[NUMWEATHERS]; + static float (*m_fLightsOnGroundBrightness)[NUMWEATHERS]; + static int (*m_nLowCloudsRed)[NUMWEATHERS]; + static int (*m_nLowCloudsGreen)[NUMWEATHERS]; + static int (*m_nLowCloudsBlue)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopRed)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopGreen)[NUMWEATHERS]; + static int (*m_nFluffyCloudsTopBlue)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomRed)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomGreen)[NUMWEATHERS]; + static int (*m_nFluffyCloudsBottomBlue)[NUMWEATHERS]; + static float (*m_fBlurRed)[NUMWEATHERS]; + static float (*m_fBlurGreen)[NUMWEATHERS]; + static float (*m_fBlurBlue)[NUMWEATHERS]; + static float (*m_fBlurAlpha)[NUMWEATHERS]; + + static float &m_fCurrentAmbientRed; + static float &m_fCurrentAmbientGreen; + static float &m_fCurrentAmbientBlue; + static float &m_fCurrentDirectionalRed; + static float &m_fCurrentDirectionalGreen; + static float &m_fCurrentDirectionalBlue; + static int &m_nCurrentSkyTopRed; + static int &m_nCurrentSkyTopGreen; + static int &m_nCurrentSkyTopBlue; + static int &m_nCurrentSkyBottomRed; + static int &m_nCurrentSkyBottomGreen; + static int &m_nCurrentSkyBottomBlue; + static int &m_nCurrentSunCoreRed; + static int &m_nCurrentSunCoreGreen; + static int &m_nCurrentSunCoreBlue; + static int &m_nCurrentSunCoronaRed; + static int &m_nCurrentSunCoronaGreen; + static int &m_nCurrentSunCoronaBlue; + static float &m_fCurrentSunSize; + static float &m_fCurrentSpriteSize; + static float &m_fCurrentSpriteBrightness; + static int &m_nCurrentShadowStrength; + static int &m_nCurrentLightShadowStrength; + static int &m_nCurrentTreeShadowStrength; + static float &m_fCurrentFogStart; + static float &m_fCurrentFarClip; + static float &m_fCurrentLightsOnGroundBrightness; + static int &m_nCurrentLowCloudsRed; + static int &m_nCurrentLowCloudsGreen; + static int &m_nCurrentLowCloudsBlue; + static int &m_nCurrentFluffyCloudsTopRed; + static int &m_nCurrentFluffyCloudsTopGreen; + static int &m_nCurrentFluffyCloudsTopBlue; + static int &m_nCurrentFluffyCloudsBottomRed; + static int &m_nCurrentFluffyCloudsBottomGreen; + static int &m_nCurrentFluffyCloudsBottomBlue; + static float &m_fCurrentBlurRed; + static float &m_fCurrentBlurGreen; + static float &m_fCurrentBlurBlue; + static float &m_fCurrentBlurAlpha; + static int &m_nCurrentFogColourRed; + static int &m_nCurrentFogColourGreen; + static int &m_nCurrentFogColourBlue; + + static int &m_FogReduction; + +public: + static int &m_CurrentStoredValue; + static CVector *m_VectorToSun; // [16] + static float *m_fShadowFrontX; // [16] + static float *m_fShadowFrontY; // [16] + static float *m_fShadowSideX; // [16] + static float *m_fShadowSideY; // [16] + static float *m_fShadowDisplacementX; // [16] + static float *m_fShadowDisplacementY; // [16] + + static float GetAmbientRed(void) { return m_fCurrentAmbientRed; } + static float GetAmbientGreen(void) { return m_fCurrentAmbientGreen; } + static float GetAmbientBlue(void) { return m_fCurrentAmbientBlue; } + static float GetDirectionalRed(void) { return m_fCurrentDirectionalRed; } + static float GetDirectionalGreen(void) { return m_fCurrentDirectionalGreen; } + static float GetDirectionalBlue(void) { return m_fCurrentDirectionalBlue; } + static int GetSkyTopRed(void) { return m_nCurrentSkyTopRed; } + static int GetSkyTopGreen(void) { return m_nCurrentSkyTopGreen; } + static int GetSkyTopBlue(void) { return m_nCurrentSkyTopBlue; } + static int GetSkyBottomRed(void) { return m_nCurrentSkyBottomRed; } + static int GetSkyBottomGreen(void) { return m_nCurrentSkyBottomGreen; } + static int GetSkyBottomBlue(void) { return m_nCurrentSkyBottomBlue; } + static int GetSunCoreRed(void) { return m_nCurrentSunCoreRed; } + static int GetSunCoreGreen(void) { return m_nCurrentSunCoreGreen; } + static int GetSunCoreBlue(void) { return m_nCurrentSunCoreBlue; } + static int GetSunCoronaRed(void) { return m_nCurrentSunCoronaRed; } + static int GetSunCoronaGreen(void) { return m_nCurrentSunCoronaGreen; } + static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; } + static float GetSunSize(void) { return m_fCurrentSunSize; } + static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; } + static float GetFarClip(void) { return m_fCurrentFarClip; } + static float GetFogStart(void) { return m_fCurrentFogStart; } + + static int GetLowCloudsRed(void) { return m_nCurrentLowCloudsRed; } + static int GetLowCloudsGreen(void) { return m_nCurrentLowCloudsGreen; } + static int GetLowCloudsBlue(void) { return m_nCurrentLowCloudsBlue; } + static int GetFluffyCloudsTopRed(void) { return m_nCurrentFluffyCloudsTopRed; } + static int GetFluffyCloudsTopGreen(void) { return m_nCurrentFluffyCloudsTopGreen; } + static int GetFluffyCloudsTopBlue(void) { return m_nCurrentFluffyCloudsTopBlue; } + static int GetFluffyCloudsBottomRed(void) { return m_nCurrentFluffyCloudsBottomRed; } + static int GetFluffyCloudsBottomGreen(void) { return m_nCurrentFluffyCloudsBottomGreen; } + static int GetFluffyCloudsBottomBlue(void) { return m_nCurrentFluffyCloudsBottomBlue; } + static int GetFogRed(void) { return m_nCurrentFogColourRed; } + static int GetFogGreen(void) { return m_nCurrentFogColourGreen; } + static int GetFogBlue(void) { return m_nCurrentFogColourBlue; } + + static void Initialise(void); + static void Update(void); + static CVector &GetSunPosition(void) { return m_VectorToSun[m_CurrentStoredValue]; } +}; diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp new file mode 100644 index 00000000..460deeac --- /dev/null +++ b/src/render/Weather.cpp @@ -0,0 +1,35 @@ +#include "common.h" +#include "patcher.h" +#include "Weather.h" + +int32 &CWeather::SoundHandle = *(int32*)0x5FFBC4; + +int32 &CWeather::WeatherTypeInList = *(int32*)0x8F626C; +int16 &CWeather::OldWeatherType = *(int16*)0x95CCEC; +int16 &CWeather::NewWeatherType = *(int16*)0x95CC70; +int16 &CWeather::ForcedWeatherType = *(int16*)0x95CC80; + +bool &CWeather::LightningFlash = *(bool*)0x95CDA3; +bool &CWeather::LightningBurst = *(bool*)0x95CDAC; +uint32 &CWeather::LightningStart = *(uint32*)0x8F5F84; +uint32 &CWeather::LightningFlashLastChange = *(uint32*)0x8E2C0C; +uint32 &CWeather::WhenToPlayLightningSound = *(uint32*)0x8F57E4; +uint32 &CWeather::LightningDuration = *(uint32*)0x940578; + +float &CWeather::Foggyness = *(float*)0x885AF4; +float &CWeather::CloudCoverage = *(float*)0x8E2818; +float &CWeather::Wind = *(float*)0x8E2BF8; +float &CWeather::Rain = *(float*)0x8E2BFC; +float &CWeather::InterpolationValue = *(float*)0x8F2520; +float &CWeather::WetRoads = *(float*)0x8F5FF8; +float &CWeather::Rainbow = *(float*)0x940598; + +bool &CWeather::bScriptsForceRain = *(bool*)0x95CD7D; +bool &CWeather::Stored_StateStored = *(bool*)0x95CDC1; + +WRAPPER void CWeather::RenderRainStreaks(void) { EAXJMP(0x524550); } + +void CWeather::ReleaseWeather() +{ + ForcedWeatherType = -1; +} diff --git a/src/render/Weather.h b/src/render/Weather.h new file mode 100644 index 00000000..a9c15fd9 --- /dev/null +++ b/src/render/Weather.h @@ -0,0 +1,39 @@ +enum { + WEATHER_SUNNY, + WEATHER_CLOUDY, + WEATHER_RAINY, + WEATHER_FOGGY +}; + +class CWeather +{ +public: + static int32 &SoundHandle; + + static int32 &WeatherTypeInList; + static int16 &OldWeatherType; + static int16 &NewWeatherType; + static int16 &ForcedWeatherType; + + static bool &LightningFlash; + static bool &LightningBurst; + static uint32 &LightningStart; + static uint32 &LightningFlashLastChange; + static uint32 &WhenToPlayLightningSound; + static uint32 &LightningDuration; + + static float &Foggyness; + static float &CloudCoverage; + static float &Wind; + static float &Rain; + static float &InterpolationValue; + static float &WetRoads; + static float &Rainbow; + + static bool &bScriptsForceRain; + static bool &Stored_StateStored; + + static void RenderRainStreaks(void); + + static void ReleaseWeather(); +}; diff --git a/src/rw.cpp b/src/rw.cpp deleted file mode 100644 index 52bcf5bb..00000000 --- a/src/rw.cpp +++ /dev/null @@ -1,415 +0,0 @@ -#include "common.h" -#include "patcher.h" -#include "rwcore.h" -#include "rpworld.h" -#include "rpmatfx.h" -#include "rpskin.h" -#include "rphanim.h" -#include "rtbmp.h" - -typedef RwV3d *(*rwVectorsMultFn) (RwV3d * pointsOut, - const RwV3d * pointsIn, - RwInt32 numPoints, - const RwMatrix * matrix); - - -WRAPPER void _rwObjectHasFrameSetFrame(void* object, RwFrame* frame) { EAXJMP(0x5BC950); } -WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { EAXJMP(0x59E690); } -WRAPPER void _rpAtomicResyncInterpolatedSphere(RpAtomic* atomic) { EAXJMP(0x59E6C0); } -WRAPPER RwSphere const* RpAtomicGetWorldBoundingSphere(RpAtomic* atomic) { EAXJMP(0x59E800); } -WRAPPER RwInt32 RpClumpGetNumAtomics(RpClump* clump) { EAXJMP(0x59ED50); } -WRAPPER RpClump* RpClumpRender(RpClump* clump) { EAXJMP(0x59ED80); } -WRAPPER RpClump* RpClumpForAllAtomics(RpClump* clump, RpAtomicCallBack callback, void* pData) { EAXJMP(0x59EDD0); } -WRAPPER RpClump* RpClumpForAllCameras(RpClump* clump, RwCameraCallBack callback, void* pData) { EAXJMP(0x59EE10); } -WRAPPER RpClump* RpClumpForAllLights(RpClump* clump, RpLightCallBack callback, void* pData) { EAXJMP(0x59EE60); } -WRAPPER RpAtomic* RpAtomicCreate() { EAXJMP(0x59EEB0); } -WRAPPER RpAtomic* RpAtomicSetGeometry(RpAtomic* atomic, RpGeometry* geometry, RwUInt32 flags) { EAXJMP(0x59EFA0); } -WRAPPER RwBool RpAtomicDestroy(RpAtomic* atomic) { EAXJMP(0x59F020); } -WRAPPER RpAtomic* RpAtomicClone(RpAtomic* atomic) { EAXJMP(0x59F0A0); } -WRAPPER RpClump* RpClumpClone(RpClump* clump) { EAXJMP(0x59F1B0); } -WRAPPER RpClump* RpClumpCreate() { EAXJMP(0x59F490); } -WRAPPER RwBool RpClumpDestroy(RpClump* clump) { EAXJMP(0x59F500); } -WRAPPER RpClump* RpClumpAddAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F680); } -WRAPPER RpClump* RpClumpRemoveAtomic(RpClump* clump, RpAtomic* atomic) { EAXJMP(0x59F6B0); } -WRAPPER RpClump* RpClumpRemoveLight(RpClump* clump, RpLight* light) { EAXJMP(0x59F6E0); } -WRAPPER RpClump* RpClumpStreamRead(RwStream* stream) { EAXJMP(0x59FC50); } -WRAPPER RwInt32 RpAtomicRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0510); } -WRAPPER RwInt32 RpClumpRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A0540); } -WRAPPER RwInt32 RpAtomicRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5A0570); } -WRAPPER RwInt32 RpAtomicSetStreamAlwaysCallBack(RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5A05A0); } -WRAPPER RwInt32 RpAtomicSetStreamRightsCallBack(RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5A05C0); } -WRAPPER RwInt32 RpAtomicGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A05E0); } -WRAPPER RpAtomic* RpAtomicSetFrame(RpAtomic* atomic, RwFrame* frame) { EAXJMP(0x5A0600); } -WRAPPER RwInt32 RwEngineRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor initCB, RwPluginObjectDestructor termCB) { EAXJMP(0x5A0DC0); } -WRAPPER RwInt32 RwEngineGetPluginOffset(RwUInt32 pluginID) { EAXJMP(0x5A0DF0); } -WRAPPER RwInt32 RwEngineGetNumSubSystems() { EAXJMP(0x5A0E10); } -WRAPPER RwSubSystemInfo* RwEngineGetSubSystemInfo(RwSubSystemInfo* subSystemInfo, RwInt32 subSystemIndex) { EAXJMP(0x5A0E40); } -WRAPPER RwInt32 RwEngineGetCurrentSubSystem() { EAXJMP(0x5A0E70); } -WRAPPER RwBool RwEngineSetSubSystem(RwInt32 subSystemIndex) { EAXJMP(0x5A0EA0); } -WRAPPER RwInt32 RwEngineGetNumVideoModes() { EAXJMP(0x5A0ED0); } -WRAPPER RwVideoMode* RwEngineGetVideoModeInfo(RwVideoMode* modeinfo, RwInt32 modeIndex) { EAXJMP(0x5A0F00); } -WRAPPER RwInt32 RwEngineGetCurrentVideoMode() { EAXJMP(0x5A0F30); } -WRAPPER RwBool RwEngineSetVideoMode(RwInt32 modeIndex) { EAXJMP(0x5A0F60); } -WRAPPER RwBool RwEngineStop() { EAXJMP(0x5A0F90); } -WRAPPER RwBool RwEngineStart() { EAXJMP(0x5A0FE0); } -WRAPPER RwBool RwEngineClose() { EAXJMP(0x5A1070); } -WRAPPER RwBool RwEngineOpen(RwEngineOpenParams* initParams) { EAXJMP(0x5A10E0); } -WRAPPER RwBool RwEngineTerm() { EAXJMP(0x5A1290); } -WRAPPER RwBool RwEngineInit(RwMemoryFunctions* memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) { EAXJMP(0x5A12D0); } -WRAPPER void* _rwFrameOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A15E0); } -WRAPPER void* _rwFrameClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A1650); } -WRAPPER RwFrame* _rwFrameCloneAndLinkClones(RwFrame* root) { EAXJMP(0x5A1690); } -WRAPPER RwFrame* _rwFramePurgeClone(RwFrame* root) { EAXJMP(0x5A1880); } -WRAPPER RwBool RwFrameDirty(RwFrame const* frame) { EAXJMP(0x5A1930); } -WRAPPER void _rwFrameInit(RwFrame* frame) { EAXJMP(0x5A1950); } -WRAPPER RwFrame* RwFrameCreate() { EAXJMP(0x5A1A00); } -WRAPPER RwBool RwFrameDestroy(RwFrame* frame) { EAXJMP(0x5A1A30); } -WRAPPER RwBool RwFrameDestroyHierarchy(RwFrame* frame) { EAXJMP(0x5A1BF0); } -WRAPPER RwFrame* RwFrameUpdateObjects(RwFrame* frame) { EAXJMP(0x5A1C60); } -WRAPPER RwMatrix* RwFrameGetLTM(RwFrame* frame) { EAXJMP(0x5A1CE0); } -WRAPPER RwFrame* RwFrameAddChild(RwFrame* parent, RwFrame* child) { EAXJMP(0x5A1D00); } -WRAPPER RwFrame* RwFrameRemoveChild(RwFrame* child) { EAXJMP(0x5A1ED0); } -WRAPPER RwFrame* RwFrameForAllChildren(RwFrame* frame, RwFrameCallBack callBack, void* data) { EAXJMP(0x5A1FC0); } -WRAPPER RwFrame* RwFrameTranslate(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A2000); } -WRAPPER RwFrame* RwFrameScale(RwFrame* frame, RwV3d const* v, RwOpCombineType combine) { EAXJMP(0x5A20A0); } -WRAPPER RwFrame* RwFrameTransform(RwFrame* frame, RwMatrix const* m, RwOpCombineType combine) { EAXJMP(0x5A2140); } -WRAPPER RwFrame* RwFrameRotate(RwFrame* frame, RwV3d const* axis, RwReal angle, RwOpCombineType combine) { EAXJMP(0x5A21E0); } -WRAPPER RwFrame* RwFrameSetIdentity(RwFrame* frame) { EAXJMP(0x5A2280); } -WRAPPER RwFrame* RwFrameForAllObjects(RwFrame* frame, RwObjectCallBack callBack, void* data) { EAXJMP(0x5A2340); } -WRAPPER RwInt32 RwFrameRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A2380); } -WRAPPER RwBool _rwMatrixSetMultFn(rwMatrixMultFn multMat) { EAXJMP(0x5A23B0); } -WRAPPER RwReal _rwMatrixDeterminant(RwMatrix const* matrix) { EAXJMP(0x5A2520); } -WRAPPER RwReal _rwMatrixOrthogonalError(RwMatrix const* matrix) { EAXJMP(0x5A2570); } -WRAPPER RwReal _rwMatrixNormalError(RwMatrix const* matrix) { EAXJMP(0x5A25D0); } -WRAPPER RwReal _rwMatrixIdentityError(RwMatrix const* matrix) { EAXJMP(0x5A2660); } -WRAPPER void* _rwMatrixClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2730); } -WRAPPER void* _rwMatrixOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A2770); } -WRAPPER RwMatrix* RwMatrixOptimize(RwMatrix* matrix, RwMatrixTolerance const* tolerance) { EAXJMP(0x5A2820); } -WRAPPER RwMatrix* RwMatrixUpdate(RwMatrix* matrix) { EAXJMP(0x5A28E0); } -WRAPPER RwMatrix* RwMatrixMultiply(RwMatrix* matrixOut, RwMatrix const* MatrixIn1, RwMatrix const* matrixIn2) { EAXJMP(0x5A28F0); } -WRAPPER RwMatrix* RwMatrixRotateOneMinusCosineSine(RwMatrix* matrix, RwV3d const* unitAxis, RwReal oneMinusCosine, RwReal sine, RwOpCombineType combineOp) { EAXJMP(0x5A2960); } -WRAPPER RwMatrix* RwMatrixRotate(RwMatrix* matrix, RwV3d const* axis, RwReal angle, RwOpCombineType combineOp) { EAXJMP(0x5A2BF0); } -WRAPPER RwMatrix* RwMatrixInvert(RwMatrix* matrixOut, RwMatrix const* matrixIn) { EAXJMP(0x5A2C90); } -WRAPPER RwMatrix* RwMatrixScale(RwMatrix* matrix, RwV3d const* scale, RwOpCombineType combineOp) { EAXJMP(0x5A2EE0); } -WRAPPER RwMatrix* RwMatrixTranslate(RwMatrix* matrix, RwV3d const* translation, RwOpCombineType combineOp) { EAXJMP(0x5A3070); } -WRAPPER RwMatrix* RwMatrixTransform(RwMatrix* matrix, RwMatrix const* transform, RwOpCombineType combineOp) { EAXJMP(0x5A31C0); } -WRAPPER RwBool RwMatrixDestroy(RwMatrix* mpMat) { EAXJMP(0x5A3300); } -WRAPPER RwMatrix* RwMatrixCreate() { EAXJMP(0x5A3330); } -WRAPPER RwBool _rwVectorSetMultFn(rwVectorMultFn multPoint, rwVectorsMultFn multPoints, rwVectorMultFn multVector, rwVectorsMultFn multVectors) { EAXJMP(0x5A3450); } -WRAPPER RwReal _rwV3dNormalize(RwV3d* out, RwV3d const* in) { EAXJMP(0x5A3600); } -WRAPPER RwReal RwV3dLength(RwV3d const* in) { EAXJMP(0x5A36A0); } -WRAPPER RwReal _rwSqrt(RwReal const num) { EAXJMP(0x5A3710); } -WRAPPER RwReal _rwInvSqrt(RwReal const num) { EAXJMP(0x5A3770); } -WRAPPER RwV3d* RwV3dTransformPoints(RwV3d* pointsOut, RwV3d const* pointsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37D0); } -WRAPPER RwV3d* RwV3dTransformVectors(RwV3d* vectorsOut, RwV3d const* vectorsIn, RwInt32 numPoints, RwMatrix const* matrix) { EAXJMP(0x5A37E0); } -WRAPPER void* _rwVectorClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A37F0); } -WRAPPER void* _rwVectorOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5A3860); } -WRAPPER RwUInt32 RwStreamRead(RwStream* stream, void* buffer, RwUInt32 length) { EAXJMP(0x5A3AD0); } -WRAPPER RwStream* RwStreamWrite(RwStream* stream, void const* buffer, RwUInt32 length) { EAXJMP(0x5A3C30); } -WRAPPER RwStream* RwStreamSkip(RwStream* stream, RwUInt32 offset) { EAXJMP(0x5A3DF0); } -WRAPPER RwBool RwStreamClose(RwStream* stream, void* pData) { EAXJMP(0x5A3F10); } -WRAPPER RwStream* RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, void const* pData) { EAXJMP(0x5A3FE0); } -WRAPPER RwReal RwIm2DGetNearScreenZ() { EAXJMP(0x5A43A0); } -WRAPPER RwReal RwIm2DGetFarScreenZ() { EAXJMP(0x5A43B0); } -WRAPPER RwBool RwRenderStateSet(RwRenderState state, void* value) { EAXJMP(0x5A43C0); } -WRAPPER RwBool RwRenderStateGet(RwRenderState state, void* value) { EAXJMP(0x5A4410); } -WRAPPER RwBool RwIm2DRenderLine(RwIm2DVertex* vertices, RwInt32 numVertices, RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5A4420); } -WRAPPER RwBool RwIm2DRenderPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices) { EAXJMP(0x5A4430); } -WRAPPER RwBool RwIm2DRenderIndexedPrimitive(RwPrimitiveType primType, RwIm2DVertex* vertices, RwInt32 numVertices, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5A4440); } -WRAPPER RwCamera* RwCameraEndUpdate(RwCamera* camera) { EAXJMP(0x5A5020); } -WRAPPER RwCamera* RwCameraBeginUpdate(RwCamera* camera) { EAXJMP(0x5A5030); } -WRAPPER RwCamera* RwCameraSetViewOffset(RwCamera* camera, RwV2d const* offset) { EAXJMP(0x5A5040); } -WRAPPER RwCamera* RwCameraSetNearClipPlane(RwCamera* camera, RwReal nearClip) { EAXJMP(0x5A5070); } -WRAPPER RwCamera* RwCameraSetFarClipPlane(RwCamera* camera, RwReal farClip) { EAXJMP(0x5A5140); } -WRAPPER RwFrustumTestResult RwCameraFrustumTestSphere(RwCamera const* camera, RwSphere const* sphere) { EAXJMP(0x5A5170); } -WRAPPER RwCamera* RwCameraClear(RwCamera* camera, RwRGBA* colour, RwInt32 clearMode) { EAXJMP(0x5A51E0); } -WRAPPER RwCamera* RwCameraShowRaster(RwCamera* camera, void* pDev, RwUInt32 flags) { EAXJMP(0x5A5210); } -WRAPPER RwCamera* RwCameraSetProjection(RwCamera* camera, RwCameraProjection projection) { EAXJMP(0x5A5240); } -WRAPPER RwCamera* RwCameraSetViewWindow(RwCamera* camera, RwV2d const* viewWindow) { EAXJMP(0x5A52B0); } -WRAPPER RwInt32 RwCameraRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5A52F0); } -WRAPPER RwBool RwCameraDestroy(RwCamera* camera) { EAXJMP(0x5A5320); } -WRAPPER RwCamera* RwCameraCreate() { EAXJMP(0x5A5360); } -WRAPPER RwBool RwTextureSetMipmapping(RwBool enable) { EAXJMP(0x5A7100); } -WRAPPER RwBool RwTextureGetMipmapping() { EAXJMP(0x5A7120); } -WRAPPER RwBool RwTextureSetAutoMipmapping(RwBool enable) { EAXJMP(0x5A7130); } -WRAPPER RwBool RwTextureGetAutoMipmapping() { EAXJMP(0x5A7150); } -WRAPPER RwTexDictionary* RwTexDictionaryCreate() { EAXJMP(0x5A7160); } -WRAPPER RwBool RwTexDictionaryDestroy(RwTexDictionary* dict) { EAXJMP(0x5A7200); } -WRAPPER RwTexDictionary const* RwTexDictionaryForAllTextures(RwTexDictionary const* dict, RwTextureCallBack fpCallBack, void* pData) { EAXJMP(0x5A7290); } -WRAPPER RwTexture* RwTextureCreate(RwRaster* raster) { EAXJMP(0x5A72D0); } -WRAPPER RwBool RwTextureDestroy(RwTexture* texture) { EAXJMP(0x5A7330); } -WRAPPER RwTexture* RwTextureSetName(RwTexture* texture, RwChar const* name) { EAXJMP(0x5A73B0); } -WRAPPER RwTexture* RwTextureSetMaskName(RwTexture* texture, RwChar const* maskName) { EAXJMP(0x5A7420); } -WRAPPER RwTexture* RwTexDictionaryAddTexture(RwTexDictionary* dict, RwTexture* texture) { EAXJMP(0x5A7490); } -WRAPPER RwTexture* RwTexDictionaryFindNamedTexture(RwTexDictionary* dict, RwChar const* name) { EAXJMP(0x5A74D0); } -WRAPPER RwTexDictionary* RwTexDictionarySetCurrent(RwTexDictionary* dict) { EAXJMP(0x5A7550); } -WRAPPER RwTexDictionary* RwTexDictionaryGetCurrent() { EAXJMP(0x5A7570); } -WRAPPER RwTexture* RwTextureRead(RwChar const* name, RwChar const* maskName) { EAXJMP(0x5A7580); } -WRAPPER RwBool RwTextureRasterGenerateMipmaps(RwRaster* raster, RwImage* image) { EAXJMP(0x5A7780); } -WRAPPER RwImage* RwImageCreate(RwInt32 width, RwInt32 height, RwInt32 depth) { EAXJMP(0x5A9120); } -WRAPPER RwBool RwImageDestroy(RwImage* image) { EAXJMP(0x5A9180); } -WRAPPER RwImage* RwImageAllocatePixels(RwImage* image) { EAXJMP(0x5A91E0); } -WRAPPER RwImage* RwImageFreePixels(RwImage* image) { EAXJMP(0x5A92A0); } -WRAPPER RwImage* RwImageMakeMask(RwImage* image) { EAXJMP(0x5A92D0); } -WRAPPER RwImage* RwImageApplyMask(RwImage* image, RwImage const* mask) { EAXJMP(0x5A93A0); } -WRAPPER RwChar const* RwImageSetPath(RwChar const* path) { EAXJMP(0x5A9750); } -WRAPPER RwImage* RwImageRead(RwChar const* imageName) { EAXJMP(0x5A9810); } -WRAPPER RwChar const* RwImageFindFileType(RwChar const* imageName) { EAXJMP(0x5A9B40); } -WRAPPER RwImage* RwImageReadMaskedImage(RwChar const* imageName, RwChar const* maskname) { EAXJMP(0x5A9C10); } -WRAPPER RwImage* RwImageCopy(RwImage* destImage, RwImage const* sourceImage) { EAXJMP(0x5A9F50); } -WRAPPER RwImage* RwImageGammaCorrect(RwImage* image) { EAXJMP(0x5AA130); } -WRAPPER RwBool RwImageSetGamma(RwReal gammaValue) { EAXJMP(0x5AA2C0); } -WRAPPER RwStream* _rwStreamWriteVersionedChunkHeader(RwStream* stream, RwInt32 type, RwInt32 size, RwUInt32 version, RwUInt32 buildNum) { EAXJMP(0x5AA4E0); } -WRAPPER RwBool RwStreamFindChunk(RwStream* stream, RwUInt32 type, RwUInt32* lengthOut, RwUInt32* versionOut) { EAXJMP(0x5AA540); } -WRAPPER void* RwMemLittleEndian32(void* mem, RwUInt32 size) { EAXJMP(0x5AA640); } -WRAPPER void* RwMemNative32(void* mem, RwUInt32 size) { EAXJMP(0x5AA650); } -WRAPPER void* RwMemFloat32ToReal(void* mem, RwUInt32 size) { EAXJMP(0x5AA660); } -WRAPPER RwStream* RwStreamWriteReal(RwStream* stream, RwReal const* reals, RwUInt32 numBytes) { EAXJMP(0x5AA680); } -WRAPPER RwStream* RwStreamWriteInt32(RwStream* stream, RwInt32 const* ints, RwUInt32 numBytes) { EAXJMP(0x5AA720); } -WRAPPER RwStream* RwStreamReadReal(RwStream* stream, RwReal* reals, RwUInt32 numBytes) { EAXJMP(0x5AA740); } -WRAPPER RwStream* RwStreamReadInt32(RwStream* stream, RwInt32* ints, RwUInt32 numBytes) { EAXJMP(0x5AA7B0); } -WRAPPER RwUInt32 RwTextureStreamGetSize(RwTexture const* texture) { EAXJMP(0x5AA800); } -WRAPPER RwTexture const* RwTextureStreamWrite(RwTexture const* texture, RwStream* stream) { EAXJMP(0x5AA870); } -WRAPPER RwTexture* RwTextureStreamRead(RwStream* stream) { EAXJMP(0x5AAA40); } -WRAPPER RwTexDictionary const* RwTexDictionaryStreamWrite(RwTexDictionary const* texDict, RwStream* stream) { EAXJMP(0x5AB020); } -WRAPPER RpMorphTarget const* RpMorphTargetCalcBoundingSphere(RpMorphTarget const* morphTarget, RwSphere* boundingSphere) { EAXJMP(0x5AC890); } -WRAPPER RwInt32 RpGeometryAddMorphTargets(RpGeometry* geometry, RwInt32 mtcount) { EAXJMP(0x5AC9A0); } -WRAPPER RpGeometry const* RpGeometryTriangleSetVertexIndices(RpGeometry const* geometry, RpTriangle* triangle, RwUInt16 vert1, RwUInt16 vert2, RwUInt16 vert3) { EAXJMP(0x5ACB60); } -WRAPPER RpGeometry* RpGeometryTriangleSetMaterial(RpGeometry* geometry, RpTriangle* triangle, RpMaterial* material) { EAXJMP(0x5ACB90); } -WRAPPER RpGeometry* RpGeometryForAllMaterials(RpGeometry* geometry, RpMaterialCallBack fpCallBack, void* pData) { EAXJMP(0x5ACBF0); } -WRAPPER RpGeometry* RpGeometryLock(RpGeometry* geometry, RwInt32 lockMode) { EAXJMP(0x5ACC30); } -WRAPPER RpGeometry* RpGeometryUnlock(RpGeometry* geometry) { EAXJMP(0x5ACC60); } -WRAPPER RpGeometry* RpGeometryCreate(RwInt32 numVert, RwInt32 numTriangles, RwUInt32 format) { EAXJMP(0x5ACD10); } -WRAPPER RpGeometry* _rpGeometryAddRef(RpGeometry* geometry) { EAXJMP(0x5ACF40); } -WRAPPER RwBool RpGeometryDestroy(RpGeometry* geometry) { EAXJMP(0x5ACF50); } -WRAPPER RwInt32 RpGeometryRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ACFF0); } -WRAPPER RwInt32 RpGeometryRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AD020); } -WRAPPER RpGeometry* RpGeometryStreamRead(RwStream* stream) { EAXJMP(0x5AD050); } -WRAPPER RwRaster* RwRasterGetCurrentContext() { EAXJMP(0x5AD6D0); } -WRAPPER RwRaster* RwRasterUnlock(RwRaster* raster) { EAXJMP(0x5AD6F0); } -WRAPPER RwRaster* RwRasterRenderFast(RwRaster* raster, RwInt32 x, RwInt32 y) { EAXJMP(0x5AD710); } -WRAPPER RwRaster* RwRasterUnlockPalette(RwRaster* raster) { EAXJMP(0x5AD750); } -WRAPPER RwBool RwRasterDestroy(RwRaster* raster) { EAXJMP(0x5AD780); } -WRAPPER RwRaster* RwRasterPushContext(RwRaster* raster) { EAXJMP(0x5AD7C0); } -WRAPPER RwInt32 RwRasterRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AD810); } -WRAPPER RwUInt8* RwRasterLockPalette(RwRaster* raster, RwInt32 lockMode) { EAXJMP(0x5AD840); } -WRAPPER RwRaster* RwRasterPopContext() { EAXJMP(0x5AD870); } -WRAPPER RwInt32 RwRasterGetNumLevels(RwRaster* raster) { EAXJMP(0x5AD8C0); } -WRAPPER RwRaster* RwRasterShowRaster(RwRaster* raster, void* dev, RwUInt32 flags) { EAXJMP(0x5AD900); } -WRAPPER RwRaster* RwRasterCreate(RwInt32 width, RwInt32 height, RwInt32 depth, RwInt32 flags) { EAXJMP(0x5AD930); } -WRAPPER RwUInt8* RwRasterLock(RwRaster* raster, RwUInt8 level, RwInt32 lockMode) { EAXJMP(0x5AD9D0); } -WRAPPER RpMaterial* RpMaterialCreate() { EAXJMP(0x5ADC30); } -WRAPPER RwBool RpMaterialDestroy(RpMaterial* material) { EAXJMP(0x5ADCB0); } -WRAPPER RpMaterial* RpMaterialSetTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5ADD10); } -WRAPPER RwInt32 RpMaterialRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5ADD40); } -WRAPPER RwInt32 RpMaterialRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5ADD70); } -WRAPPER RpMaterial* RpMaterialStreamRead(RwStream* stream) { EAXJMP(0x5ADDA0); } -WRAPPER RpWorldSector* _rpSectorDefaultRenderCallBack(RpWorldSector* sector) { EAXJMP(0x5AE0B0); } -WRAPPER RwBool _rpWorldForAllGlobalLights(RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE100); } -WRAPPER RpWorldSector* _rpWorldSectorForAllLocalLights(RpWorldSector* sector, RpLightCallBack callBack, void* pData) { EAXJMP(0x5AE150); } -WRAPPER RpWorld* RpWorldUnlock(RpWorld* world) { EAXJMP(0x5AE190); } -WRAPPER RpWorld* RpWorldSectorGetWorld(RpWorldSector const* sector) { EAXJMP(0x5AE2B0); } -WRAPPER RwBool RpWorldDestroy(RpWorld* world) { EAXJMP(0x5AE340); } -WRAPPER RpWorld* RpWorldCreate(RwBBox* boundingBox) { EAXJMP(0x5AE6A0); } -WRAPPER RwInt32 RpWorldRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5AEA40); } -WRAPPER RwInt32 RpWorldRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5AEA70); } -WRAPPER RwBool RpWorldPluginAttach() { EAXJMP(0x5AEAA0); } -WRAPPER RpWorld* RpWorldAddCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFB80); } -WRAPPER RpWorld* RpWorldRemoveCamera(RpWorld* world, RwCamera* camera) { EAXJMP(0x5AFBB0); } -WRAPPER RpWorld* RpAtomicGetWorld(RpAtomic const* atomic) { EAXJMP(0x5AFC10); } -WRAPPER RpWorld* RpWorldAddClump(RpWorld* world, RpClump* clump) { EAXJMP(0x5AFC20); } -WRAPPER RpWorld* RpWorldAddLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDA0); } -WRAPPER RpWorld* RpWorldRemoveLight(RpWorld* world, RpLight* light) { EAXJMP(0x5AFDF0); } -WRAPPER RwImage* RtBMPImageRead(RwChar const* imageName) { EAXJMP(0x5AFE70); } -WRAPPER RwBool RpSkinPluginAttach() { EAXJMP(0x5B07D0); } -WRAPPER RpAtomic* RpSkinAtomicSetHAnimHierarchy(RpAtomic* atomic, RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1050); } -WRAPPER RpHAnimHierarchy* RpSkinAtomicGetHAnimHierarchy(RpAtomic const* atomic) { EAXJMP(0x5B1070); } -WRAPPER RpSkin* RpSkinGeometryGetSkin(RpGeometry* geometry) { EAXJMP(0x5B1080); } -WRAPPER RpGeometry* RpSkinGeometrySetSkin(RpGeometry* geometry, RpSkin* skin) { EAXJMP(0x5B1090); } -WRAPPER RwMatrix const* RpSkinGetSkinToBoneMatrices(RpSkin* skin) { EAXJMP(0x5B10D0); } -WRAPPER RpHAnimHierarchy* RpHAnimHierarchyCreate(RwInt32 numNodes, RwUInt32* nodeFlags, RwInt32* nodeIDs, RpHAnimHierarchyFlag flags, RwInt32 maxKeyFrameSize) { EAXJMP(0x5B10E0); } -WRAPPER RpHAnimHierarchy* RpHAnimFrameGetHierarchy(RwFrame* frame) { EAXJMP(0x5B11F0); } -WRAPPER RwBool RpHAnimHierarchySetCurrentAnim(RpHAnimHierarchy* hierarchy, RpHAnimAnimation* anim) { EAXJMP(0x5B1200); } -WRAPPER RwBool RpHAnimHierarchySubAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B12B0); } -WRAPPER RwBool RpHAnimHierarchyAddAnimTime(RpHAnimHierarchy* hierarchy, RwReal time) { EAXJMP(0x5B1480); } -WRAPPER RwBool RpHAnimHierarchyUpdateMatrices(RpHAnimHierarchy* hierarchy) { EAXJMP(0x5B1780); } -WRAPPER RpHAnimAnimation* RpHAnimAnimationStreamRead(RwStream* stream) { EAXJMP(0x5B1C10); } -WRAPPER RwBool RpHAnimPluginAttach() { EAXJMP(0x5B1D50); } -WRAPPER RwBool RpMatFXPluginAttach() { EAXJMP(0x5B2640); } -WRAPPER RpAtomic* RpMatFXAtomicEnableEffects(RpAtomic* atomic) { EAXJMP(0x5B3750); } -WRAPPER RpMaterial* RpMatFXMaterialSetEffects(RpMaterial* material, RpMatFXMaterialFlags flags) { EAXJMP(0x5B3780); } -WRAPPER RpMaterial* RpMatFXMaterialSetupEnvMap(RpMaterial* material, RwTexture* texture, RwFrame* frame, RwBool useFrameBufferAlpha, RwReal coef) { EAXJMP(0x5B38D0); } -WRAPPER RpMaterial* RpMatFXMaterialSetBumpMapTexture(RpMaterial* material, RwTexture* texture) { EAXJMP(0x5B3A40); } -WRAPPER RwBool RwD3D8SetRenderState(RwUInt32 state, RwUInt32 value) { EAXJMP(0x5B3CF0); } -WRAPPER void RwD3D8GetRenderState(RwUInt32 state, void* value) { EAXJMP(0x5B3D40); } -WRAPPER RwBool RwD3D8SetTextureStageState(RwUInt32 stage, RwUInt32 type, RwUInt32 value) { EAXJMP(0x5B3D60); } -WRAPPER RwBool RwD3D8SetTexture(RwTexture* texture, RwUInt32 stage) { EAXJMP(0x5B53A0); } -WRAPPER void* RwIm3DTransform(RwIm3DVertex* pVerts, RwUInt32 numVerts, RwMatrix* ltm, RwUInt32 flags) { EAXJMP(0x5B6720); } -WRAPPER RwBool RwIm3DEnd() { EAXJMP(0x5B67F0); } -WRAPPER RwBool RwIm3DRenderIndexedPrimitive(RwPrimitiveType primType, RwImVertexIndex* indices, RwInt32 numIndices) { EAXJMP(0x5B6820); } -WRAPPER RwBool RwIm3DRenderLine(RwInt32 vert1, RwInt32 vert2) { EAXJMP(0x5B6980); } -WRAPPER RxPipeline* RwIm3DSetTransformPipeline(RxPipeline* pipeline) { EAXJMP(0x5B6A50); } -WRAPPER RxPipeline* RwIm3DSetRenderPipeline(RxPipeline* pipeline, RwPrimitiveType primType) { EAXJMP(0x5B6AC0); } -WRAPPER void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate) { EAXJMP(0x5B95D0); } -WRAPPER RwBool RwD3D8CameraAttachWindow(void* camera, void* hwnd) { EAXJMP(0x5B9640); } -WRAPPER RwBool RwD3D8DeviceSupportsDXTTexture() { EAXJMP(0x5BAEB0); } -WRAPPER RwBool RwD3D8SetVertexShader(RwUInt32 handle) { EAXJMP(0x5BAF90); } -WRAPPER RwBool RwD3D8SetPixelShader(RwUInt32 handle) { EAXJMP(0x5BAFD0); } -WRAPPER RwBool RwD3D8SetStreamSource(RwUInt32 streamNumber, void* streamData, RwUInt32 stride) { EAXJMP(0x5BB010); } -WRAPPER RwBool RwD3D8SetIndices(void* indexData, RwUInt32 baseVertexIndex) { EAXJMP(0x5BB060); } -WRAPPER RwBool RwD3D8DrawIndexedPrimitive(RwUInt32 primitiveType, RwUInt32 minIndex, RwUInt32 numVertices, RwUInt32 startIndex, RwUInt32 numIndices) { EAXJMP(0x5BB0B0); } -WRAPPER RwBool RwD3D8DrawPrimitive(RwUInt32 primitiveType, RwUInt32 startVertex, RwUInt32 numVertices) { EAXJMP(0x5BB140); } -WRAPPER RwBool RwD3D8SetTransform(RwUInt32 state, void const* matrix) { EAXJMP(0x5BB1D0); } -WRAPPER void RwD3D8GetTransform(RwUInt32 state, void* matrix) { EAXJMP(0x5BB310); } -WRAPPER RwBool RwD3D8SetTransformWorld(RwMatrix const* matrix) { EAXJMP(0x5BB340); } -WRAPPER RwBool RwD3D8SetSurfaceProperties(RwRGBA const* color, RwSurfaceProperties const* surfaceProps, RwBool modulate) { EAXJMP(0x5BB490); } -WRAPPER RwBool RwD3D8SetLight(RwInt32 index, void const* light) { EAXJMP(0x5BB7A0); } -WRAPPER RwBool RwD3D8EnableLight(RwInt32 index, RwBool enable) { EAXJMP(0x5BB890); } -WRAPPER RwBool RwD3D8DynamicVertexBufferCreate(RwUInt32 fvf, RwUInt32 size, void** vertexBuffer) { EAXJMP(0x5BB9F0); } -WRAPPER void RwD3D8DynamicVertexBufferDestroy(void* vertexBuffer) { EAXJMP(0x5BBAE0); } -WRAPPER RwBool RwD3D8IndexBufferCreate(RwUInt32 numIndices, void** indexBuffer) { EAXJMP(0x5BBB10); } -WRAPPER RwBool RwD3D8CreatePixelShader(RwUInt32 const* function, RwUInt32* handle) { EAXJMP(0x5BBB40); } -WRAPPER void RwD3D8DeletePixelShader(RwUInt32 handle) { EAXJMP(0x5BBB90); } -WRAPPER RwBool RwD3D8SetPixelShaderConstant(RwUInt32 registerAddress, void const* antData, RwUInt32 antCount) { EAXJMP(0x5BBC00); } -WRAPPER void const* RwD3D8GetCaps() { EAXJMP(0x5BBC30); } -WRAPPER RwBool RwD3D8CameraIsSphereFullyInsideFrustum(void const* camera, void const* sphere) { EAXJMP(0x5BBC40); } -WRAPPER RwBool RwD3D8CameraIsBBoxFullyInsideFrustum(void const* camera, void const* boundingBox) { EAXJMP(0x5BBCA0); } -WRAPPER RwBool RwD3D8DynamicVertexBufferLock(RwUInt32 vertexSize, RwUInt32 numVertex, void** vertexBufferOut, void** vertexDataOut, RwUInt32* baseIndexOut) { EAXJMP(0x5BBD30); } -WRAPPER RwBool RwD3D8DynamicVertexBufferUnlock(void* vertexBuffer) { EAXJMP(0x5BBEB0); } -WRAPPER RwBool _rwIntelSSEsupported() { EAXJMP(0x5BBED0); } -WRAPPER RwImage* RwImageSetFromRaster(RwImage* image, RwRaster* raster) { EAXJMP(0x5BBF10); } -WRAPPER RwRaster* RwRasterSetFromImage(RwRaster* raster, RwImage* image) { EAXJMP(0x5BBF50); } -WRAPPER RwImage* RwImageFindRasterFormat(RwImage* ipImage, RwInt32 nRasterType, RwInt32* npWidth, RwInt32* npHeight, RwInt32* npDepth, RwInt32* npFormat) { EAXJMP(0x5BBF80); } -WRAPPER RwInt32 RwFrameRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5BBFF0); } -WRAPPER rwFrameList* _rwFrameListDeinitialize(rwFrameList* frameList) { EAXJMP(0x5BC020); } -WRAPPER rwFrameList* _rwFrameListStreamRead(RwStream* stream, rwFrameList* fl) { EAXJMP(0x5BC050); } -WRAPPER RpLight* RpLightSetRadius(RpLight* light, RwReal radius) { EAXJMP(0x5BC300); } -WRAPPER RpLight* RpLightSetColor(RpLight* light, RwRGBAReal const* color) { EAXJMP(0x5BC320); } -WRAPPER RwReal RpLightGetConeAngle(RpLight const* light) { EAXJMP(0x5BC370); } -WRAPPER RwInt32 RpLightRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5BC5B0); } -WRAPPER RpLight* RpLightStreamRead(RwStream* stream) { EAXJMP(0x5BC5E0); } -WRAPPER RwBool RpLightDestroy(RpLight* light) { EAXJMP(0x5BC780); } -WRAPPER RpLight* RpLightCreate(RwInt32 type) { EAXJMP(0x5BC7C0); } -WRAPPER void _rwD3D8TexDictionaryEnableRasterFormatConversion(RwBool enable) { EAXJMP(0x5BE280); } -WRAPPER RwFileFunctions* RwOsGetFileInterface() { EAXJMP(0x5BF110); } -WRAPPER RwBool RwFreeListDestroy(RwFreeList* freelist) { EAXJMP(0x5C1720); } -WRAPPER RwFreeList* RwFreeListCreate(RwInt32 entrySize, RwInt32 entriesPerBlock, RwInt32 alignment) { EAXJMP(0x5C1790); } -WRAPPER RwInt32 RwFreeListPurge(RwFreeList* freelist) { EAXJMP(0x5C19F0); } -WRAPPER RwInt32 RwFreeListPurgeAllFreeLists() { EAXJMP(0x5C1B90); } -WRAPPER RwFreeList* RwFreeListForAllUsed(RwFreeList* freelist, RwFreeListCallBack fpCallBack, void* pData) { EAXJMP(0x5C1D40); } -WRAPPER RwBool _rxPipelineClose() { EAXJMP(0x5C2780); } -WRAPPER RwBool _rxPipelineOpen() { EAXJMP(0x5C27E0); } -WRAPPER RxHeap* RxHeapGetGlobalHeap() { EAXJMP(0x5C2AD0); } -WRAPPER RxPacket* RxPacketCreate(RxPipelineNode* node) { EAXJMP(0x5C2AE0); } -WRAPPER RxCluster* RxClusterSetExternalData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B10); } -WRAPPER RxCluster* RxClusterSetData(RxCluster* cluster, void* data, RwInt32 stride, RwInt32 numElements) { EAXJMP(0x5C2B70); } -WRAPPER RxCluster* RxClusterInitializeData(RxCluster* cluster, RwUInt32 numElements, RwUInt16 stride) { EAXJMP(0x5C2BD0); } -WRAPPER RxCluster* RxClusterResizeData(RxCluster* CurrentCluster, RwUInt32 NumElements) { EAXJMP(0x5C2C40); } -WRAPPER RxCluster* RxClusterLockWrite(RxPacket* packet, RwUInt32 clusterIndex, RxPipelineNode* node) { EAXJMP(0x5C2C90); } -WRAPPER RxPipeline* RxPipelineExecute(RxPipeline* pipeline, void* data, RwBool heapReset) { EAXJMP(0x5C2D60); } -WRAPPER RxPipeline* RxPipelineCreate() { EAXJMP(0x5C2E00); } -WRAPPER void _rxPipelineDestroy(RxPipeline* Pipeline) { EAXJMP(0x5C2E70); } -WRAPPER RwBool RwResourcesFreeResEntry(RwResEntry* entry) { EAXJMP(0x5C3080); } -WRAPPER void _rwResourcesPurge() { EAXJMP(0x5C30F0); } -WRAPPER RwResEntry* RwResourcesAllocateResEntry(void* owner, RwResEntry** ownerRef, RwInt32 size, RwResEntryDestroyNotify destroyNotify) { EAXJMP(0x5C3170); } -WRAPPER RwBool RwResourcesEmptyArena() { EAXJMP(0x5C3360); } -WRAPPER RwBool _rwPluginRegistryOpen() { EAXJMP(0x5C3450); } -WRAPPER RwBool _rwPluginRegistryClose() { EAXJMP(0x5C3480); } -WRAPPER RwInt32 _rwPluginRegistryGetPluginOffset(RwPluginRegistry const* reg, RwUInt32 pluginID) { EAXJMP(0x5C3590); } -WRAPPER RwInt32 _rwPluginRegistryAddPlugin(RwPluginRegistry* reg, RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5C35C0); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C37F0); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryDeInitObject(RwPluginRegistry const* reg, void* object) { EAXJMP(0x5C3850); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryCopyObject(RwPluginRegistry const* reg, void* dstObject, void const* srcObject) { EAXJMP(0x5C3880); } -WRAPPER RwError* RwErrorSet(RwError* code) { EAXJMP(0x5C3910); } -WRAPPER RwInt32 _rwerror(RwInt32 code, ...) { EAXJMP(0x5C3970); } -WRAPPER RwInt32 _rwPluginRegistryAddPluginStream(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5C3980); } -WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmlwysCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkAlwaysCallBack alwaysCB) { EAXJMP(0x5C39C0); } -WRAPPER RwInt32 _rwPluginRegistryAddPlgnStrmRightsCB(RwPluginRegistry* reg, RwUInt32 pluginID, RwPluginDataChunkRightsCallBack rightsCB) { EAXJMP(0x5C39F0); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryReadDataChunks(RwPluginRegistry const* reg, RwStream* stream, void* object) { EAXJMP(0x5C3A20); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryInvokeRights(RwPluginRegistry const* reg, RwUInt32 id, void* obj, RwUInt32 extraData) { EAXJMP(0x5C3B50); } -WRAPPER RwInt32 _rwPluginRegistryGetSize(RwPluginRegistry const* reg, void const* object) { EAXJMP(0x5C3BA0); } -WRAPPER RwPluginRegistry const* _rwPluginRegistryWriteDataChunks(RwPluginRegistry const* reg, RwStream* stream, void const* object) { EAXJMP(0x5C3BE0); } -WRAPPER RwPluginRegistry const* _rwPluginRegistrySkipDataChunks(RwPluginRegistry const* reg, RwStream* stream) { EAXJMP(0x5C3CB0); } -WRAPPER RwCamera* RwCameraStreamRead(RwStream* stream) { EAXJMP(0x5C3D30); } -WRAPPER RwBBox* RwBBoxCalculate(RwBBox* boundBox, RwV3d const* verts, RwInt32 numVerts) { EAXJMP(0x5C5570); } -WRAPPER RwImage* RwImageResample(RwImage* dstImage, RwImage const* srcImage) { EAXJMP(0x5C72B0); } -WRAPPER RwImage* RwImageCreateResample(RwImage const* srcImage, RwInt32 width, RwInt32 height) { EAXJMP(0x5C7B30); } -WRAPPER RxRenderStateVector* RxRenderStateVectorSetDefaultRenderStateVector(RxRenderStateVector* rsvp) { EAXJMP(0x5D9240); } -WRAPPER RxRenderStateVector* RxRenderStateVectorCreate(RwBool current) { EAXJMP(0x5D9340); } -WRAPPER void RxRenderStateVectorDestroy(RxRenderStateVector* rsvp) { EAXJMP(0x5D9410); } -WRAPPER RxRenderStateVector* RxRenderStateVectorLoadDriverState(RxRenderStateVector* rsvp) { EAXJMP(0x5D9460); } -WRAPPER void _rxEmbeddedPacketBetweenPipelines(RxPipeline* fromPipeline, RxPipeline* toPipeline) { EAXJMP(0x5D95D0); } -WRAPPER RxPipelineNode* _rxEmbeddedPacketBetweenNodes(RxPipeline* pipeline, RxPipelineNode* nodeFrom, RwUInt32 whichOutput) { EAXJMP(0x5D9740); } -WRAPPER void _rxPacketDestroy(RxPacket* Packet) { EAXJMP(0x5D9810); } -WRAPPER RpMaterialList* _rpMaterialListDeinitialize(RpMaterialList* matList) { EAXJMP(0x5C8B10); } -WRAPPER RpMaterialList* _rpMaterialListInitialize(RpMaterialList* matList) { EAXJMP(0x5C8B70); } -WRAPPER RpMaterial* _rpMaterialListGetMaterial(RpMaterialList const* matList, RwInt32 matIndex) { EAXJMP(0x5C8B80); } -WRAPPER RwInt32 _rpMaterialListAppendMaterial(RpMaterialList* matList, RpMaterial* material) { EAXJMP(0x5C8B90); } -WRAPPER RwInt32 _rpMaterialListFindMaterialIndex(RpMaterialList const* matList, RpMaterial const* material) { EAXJMP(0x5C8C50); } -WRAPPER RpMaterialList* _rpMaterialListStreamRead(RwStream* stream, RpMaterialList* matList) { EAXJMP(0x5C8C80); } -WRAPPER RpMeshHeader* _rpMeshHeaderCreate(RwUInt32 size) { EAXJMP(0x5C8FE0); } -WRAPPER void* _rpMeshClose(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C8FF0); } -WRAPPER void* _rpMeshOpen(void* instance, RwInt32 offset, RwInt32 size) { EAXJMP(0x5C9020); } -WRAPPER RpBuildMesh* _rpBuildMeshCreate(RwUInt32 bufferSize) { EAXJMP(0x5C9140); } -WRAPPER RwBool _rpBuildMeshDestroy(RpBuildMesh* mesh) { EAXJMP(0x5C9220); } -WRAPPER RwBool _rpMeshDestroy(RpMeshHeader* mesh) { EAXJMP(0x5C9260); } -WRAPPER RpBuildMesh* _rpBuildMeshAddTriangle(RpBuildMesh* mesh, RpMaterial* material, RwInt32 vert1, RwInt32 vert2, RwInt32 vert3) { EAXJMP(0x5C92A0); } -WRAPPER RpMeshHeader* _rpMeshHeaderForAllMeshes(RpMeshHeader* meshHeader, RpMeshCallBack fpCallBack, void* pData) { EAXJMP(0x5C9380); } -WRAPPER RwStream* _rpMeshWrite(RpMeshHeader const* meshHeader, void const* object, RwStream* stream, RpMaterialList const* matList) { EAXJMP(0x5C93C0); } -WRAPPER RpMeshHeader* _rpMeshRead(RwStream* stream, void const* object, RpMaterialList const* matList) { EAXJMP(0x5C9510); } -WRAPPER RwInt32 _rpMeshSize(RpMeshHeader const* meshHeader, void const* object) { EAXJMP(0x5C96E0); } -WRAPPER RpMeshHeader* RpBuildMeshGenerateDefaultTriStrip(RpBuildMesh* buildmesh, void* data) { EAXJMP(0x5C9730); } -WRAPPER RpMeshHeader* _rpTriListMeshGenerate(RpBuildMesh* buildMesh, void* data) { EAXJMP(0x5CAE10); } -WRAPPER RpMeshHeader* _rpMeshOptimise(RpBuildMesh* buildmesh, RwUInt32 flags) { EAXJMP(0x5CB230); } -WRAPPER RwInt32 RpWorldSectorRegisterPlugin(RwInt32 size, RwUInt32 pluginID, RwPluginObjectConstructor ructCB, RwPluginObjectDestructor destructCB, RwPluginObjectCopy copyCB) { EAXJMP(0x5CB2B0); } -WRAPPER RwInt32 RpWorldSectorRegisterPluginStream(RwUInt32 pluginID, RwPluginDataChunkReadCallBack readCB, RwPluginDataChunkWriteCallBack writeCB, RwPluginDataChunkGetSizeCallBack getSizeCB) { EAXJMP(0x5CB2E0); } -WRAPPER RxPipeline* RpWorldSetDefaultSectorPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB630); } -WRAPPER RxPipeline* RpAtomicSetDefaultPipeline(RxPipeline* pipeline) { EAXJMP(0x5CB670); } -WRAPPER void RpHAnimStdKeyFrameToMatrix(RwMatrix* matrix, void* voidIFrame) { EAXJMP(0x5CDEE0); } -WRAPPER void RpHAnimStdKeyFrameInterpolate(void* voidOut, void* voidIn1, void* voidIn2, RwReal time) { EAXJMP(0x5CE000); } -WRAPPER void RpHAnimStdKeyFrameBlend(void* voidOut, void* voidIn1, void* voidIn2, RwReal alpha) { EAXJMP(0x5CE420); } -WRAPPER RpHAnimAnimation* RpHAnimStdKeyFrameStreamRead(RwStream* stream, RpHAnimAnimation* animation) { EAXJMP(0x5CE820); } -WRAPPER RwBool RpHAnimStdKeyFrameStreamWrite(RpHAnimAnimation* animation, RwStream* stream) { EAXJMP(0x5CE8C0); } -WRAPPER RwInt32 RpHAnimStdKeyFrameStreamGetSize(RpHAnimAnimation* animation) { EAXJMP(0x5CE930); } -WRAPPER void RpHAnimStdKeyFrameMulRecip(void* voidFrame, void* voidStart) { EAXJMP(0x5CE950); } -WRAPPER void RpHAnimStdKeyFrameAdd(void* voidOut, void* voidIn1, void* voidIn2) { EAXJMP(0x5CEAB0); } -WRAPPER void RxHeapFree(RxHeap* heap, void* block) { EAXJMP(0x5D1070); } -WRAPPER void* RxHeapAlloc(RxHeap* heap, RwUInt32 size) { EAXJMP(0x5D1260); } -WRAPPER void* RxHeapRealloc(RxHeap* heap, void* block, RwUInt32 newSize, RwBool allowCopy) { EAXJMP(0x5D14D0); } -WRAPPER RwBool _rxHeapReset(RxHeap* heap) { EAXJMP(0x5D1680); } -WRAPPER void RxHeapDestroy(RxHeap* heap) { EAXJMP(0x5D16F0); } -WRAPPER RxHeap* RxHeapCreate(RwUInt32 size) { EAXJMP(0x5D1750); } -WRAPPER RxNodeOutput RxPipelineNodeFindOutputByName(RxPipelineNode* node, RwChar const* outputname) { EAXJMP(0x5D1EC0); } -WRAPPER RxNodeInput RxPipelineNodeFindInput(RxPipelineNode* node) { EAXJMP(0x5D1F20); } -WRAPPER RxPipeline* RxPipelineNodeRequestCluster(RxPipeline* pipeline, RxPipelineNode* node, RxClusterDefinition* clusterDef) { EAXJMP(0x5D1F30); } -WRAPPER RxPipeline* RxLockedPipeUnlock(RxLockedPipe* pipeline) { EAXJMP(0x5D1FA0); } -WRAPPER RxLockedPipe* RxPipelineLock(RxPipeline* pipeline) { EAXJMP(0x5D29F0); } -WRAPPER RxPipelineNode* RxPipelineFindNodeByName(RxPipeline* pipeline, RwChar const* name, RxPipelineNode* start, RwInt32* nodeIndex) { EAXJMP(0x5D2B10); } -WRAPPER RxLockedPipe* RxLockedPipeAddFragment(RxLockedPipe *pipeline, RwUInt32 *firstIndex, RxNodeDefinition *nodeDef0, ...) { EAXJMP(0x5D2BA0); } -WRAPPER RxPipeline* RxLockedPipeAddPath(RxLockedPipe* pipeline, RxNodeOutput out, RxNodeInput in) { EAXJMP(0x5D2EE0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmRenderSetup() { EAXJMP(0x5D31C0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleTriangleIndices() { EAXJMP(0x5D35C0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetCullTriangle() { EAXJMP(0x5D3C60); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipTriangle() { EAXJMP(0x5D4F80); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitTriangle() { EAXJMP(0x5D51C0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmInstance() { EAXJMP(0x5D5400); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetTransform() { EAXJMP(0x5D6000); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmStash() { EAXJMP(0x5D61C0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetImmMangleLineIndices() { EAXJMP(0x5D6470); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetClipLine() { EAXJMP(0x5D7230); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetSubmitLine() { EAXJMP(0x5D74C0); } -WRAPPER RwBool _rwD3D8LightsOpen() { EAXJMP(0x5D9C90); } -WRAPPER void _rwD3D8LightsClose() { EAXJMP(0x5D9EF0); } -WRAPPER RwBool _rwD3D8LightsGlobalEnable(RpLightFlag flags) { EAXJMP(0x5D9F80); } -WRAPPER RwBool _rwD3D8LightLocalEnable(RpLight* light) { EAXJMP(0x5DA210); } -WRAPPER void _rwD3D8LightsEnable(RwBool enable, RwUInt32 type) { EAXJMP(0x5DA450); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8WorldSectorAllInOne() { EAXJMP(0x5DAAC0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetD3D8AtomicAllInOne() { EAXJMP(0x5DC500); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorInstance() { EAXJMP(0x5DCC50); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetWorldSectorEnumerateLights() { EAXJMP(0x5DCD80); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicInstance() { EAXJMP(0x5DD800); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetAtomicEnumerateLights() { EAXJMP(0x5DD9B0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetMaterialScatter() { EAXJMP(0x5DDAA0); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetLight() { EAXJMP(0x5DF040); } -WRAPPER RxNodeDefinition* RxNodeDefinitionGetPostLight() { EAXJMP(0x5DF560); } -WRAPPER void RxD3D8AllInOneSetRenderCallBack(RxPipelineNode* node, RxD3D8AllInOneRenderCallBack callback) { EAXJMP(0x5DFC60); } \ No newline at end of file diff --git a/src/templates.h b/src/templates.h deleted file mode 100644 index ef2db33a..00000000 --- a/src/templates.h +++ /dev/null @@ -1,205 +0,0 @@ -#pragma once - -template -class CStore -{ -public: - int allocPtr; - T store[n]; - - T *alloc(void){ - if(this->allocPtr >= n){ - printf("Size of this thing:%d needs increasing\n", n); - assert(0); - } - return &this->store[this->allocPtr++]; - } - void clear(void){ - this->allocPtr = 0; - } -}; - -template -class CPool -{ - U *m_entries; - union Flags { - struct { - uint8 id : 7; - uint8 free : 1; - }; - uint8 u; - } *m_flags; - int m_size; - int m_allocPtr; - -public: - CPool(int size){ - m_entries = (U*)malloc(sizeof(U)*size); - m_flags = (Flags*)malloc(sizeof(Flags)*size); - m_size = size; - m_allocPtr = 0; - for(int i = 0; i < size; i++){ - m_flags[i].id = 0; - m_flags[i].free = 1; - } - } - int GetSize(void) { return m_size; } - T *New(void){ - bool wrapped = false; - do - if(++m_allocPtr == m_size){ - if(wrapped) - return nil; - wrapped = true; - m_allocPtr = 0; - } - while(!m_flags[m_allocPtr].free); - m_flags[m_allocPtr].free = 0; - m_flags[m_allocPtr].id++; - return (T*)&m_entries[m_allocPtr]; - } - T *New(int handle){ - T *entry = (T*)&m_entries[handle>>8]; - SetNotFreeAt(handle); - return entry; - } - void SetNotFreeAt(int handle){ - int idx = handle>>8; - m_flags[idx].free = 0; - m_flags[idx].id = handle & 0x7F; - for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++) - if(m_flags[m_allocPtr].free) - return; - } - void Delete(T *entry){ - int i = GetJustIndex(entry); - m_flags[i].free = 1; - if(i < m_allocPtr) - m_allocPtr = i; - } - T *GetSlot(int i){ - return m_flags[i].free ? nil : (T*)&m_entries[i]; - } - T *GetAt(int handle){ - return m_flags[handle>>8].u == (handle & 0xFF) ? - (T*)&m_entries[handle >> 8] : nil; - } - int GetIndex(T *entry){ - int i = GetJustIndex(entry); - return m_flags[i].u + (i<<8); - } - int GetJustIndex(T *entry){ - // TODO: the cast is unsafe - return (int)((U*)entry - m_entries); - } - int GetNoOfUsedSpaces(void){ - int i; - int n = 0; - for(i = 0; i < m_size; i++) - if(!m_flags[i].free) - n++; - return n; - } - void ClearStorage(uint8 *&flags, U *&entries){ - free(flags); - free(entries); - flags = nil; - entries = nil; - } - void CopyBack(uint8 *&flags, U *&entries){ - memcpy(m_flags, flags, sizeof(uint8)*m_size); - memcpy(m_entries, entries, sizeof(U)*m_size); - debug("Size copied:%d (%d)\n", sizeof(U)*m_size, sizeof(Flags)*m_size); - m_allocPtr = 0; - ClearStorage(flags, entries); - debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ - } - void Store(uint8 *&flags, U *&entries){ - flags = (uint8*)malloc(sizeof(uint8)*m_size); - entries = (U*)malloc(sizeof(U)*m_size); - memcpy(flags, m_flags, sizeof(uint8)*m_size); - memcpy(entries, m_entries, sizeof(U)*m_size); - debug("Stored:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ - } -}; - -template -class CLink -{ -public: - T item; - CLink *prev; - CLink *next; - - void Insert(CLink *link){ - link->next = this->next; - this->next->prev = link; - link->prev = this; - this->next = link; - } - void Remove(void){ - this->prev->next = this->next; - this->next->prev = this->prev; - } -}; - -template -class CLinkList -{ -public: - CLink head, tail; - CLink freeHead, freeTail; - CLink *links; - - void Init(int n){ - links = new CLink[n]; - head.next = &tail; - tail.prev = &head; - freeHead.next = &freeTail; - freeTail.prev = &freeHead; - while(n--) - freeHead.Insert(&links[n]); - } - void Shutdown(void){ - delete[] links; - links = nil; - } - void Clear(void){ - while(head.next != &tail) - Remove(head.next); - } - CLink *Insert(T const &item){ - CLink *node = freeHead.next; - if(node == &freeTail) - return nil; - node->item = item; - node->Remove(); // remove from free list - head.Insert(node); - return node; - } - CLink *InsertSorted(T const &item){ - CLink *sort; - for(sort = head.next; sort != &tail; sort = sort->next) - if(sort->item.sort >= item.sort) - break; - CLink *node = freeHead.next; - if(node == &freeTail) - return nil; - node->item = item; - node->Remove(); // remove from free list - sort->prev->Insert(node); - return node; - } - void Remove(CLink *link){ - link->Remove(); // remove from list - freeHead.Insert(link); // insert into free list - } - int Count(void){ - int n = 0; - CLink *lnk; - for(lnk = head.next; lnk != &tail; lnk = lnk->next) - n++; - return n; - } -}; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp new file mode 100644 index 00000000..54eed17a --- /dev/null +++ b/src/vehicles/Automobile.cpp @@ -0,0 +1,18 @@ +#include "common.h" +#include "patcher.h" +#include "Automobile.h" + +CAutomobile::CAutomobile(int mi, uint8 owner) +{ + ctor(mi, owner); +} + +WRAPPER CAutomobile* CAutomobile::ctor(int, uint8) { EAXJMP(0x52C6B0); } + +WRAPPER void CAutomobile::SetDoorDamage(int32, uint32, bool) { EAXJMP(0x530200); } +WRAPPER void CAutomobile::SetPanelDamage(int32, uint32, bool) { EAXJMP(0x5301A0); } +WRAPPER void CAutomobile::SetBumperDamage(int32, uint32, bool) { EAXJMP(0x530120); } + +STARTPATCHES +InjectHook(0x52D170, &CAutomobile::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h new file mode 100644 index 00000000..630635c7 --- /dev/null +++ b/src/vehicles/Automobile.h @@ -0,0 +1,67 @@ +#pragma once + +#include "DamageManager.h" +#include "Vehicle.h" + +struct CDoor +{ + float m_fAngleWhenOpened; + float m_fAngleWhenClosed; + char field_8; + char field_9; + char field_10; + char field_11; + float m_fAngle; + float m_fPreviousAngle; + float m_fAngularVelocity; + CVector m_vecVelocity; +}; + +class CAutomobile : public CVehicle +{ +public: + // 0x288 + CDamageManager Damage; + CDoor Doors[6]; + RwFrame *m_aCarNodes[NUM_CAR_NODES]; + CColPoint m_aWheelColPoints[4]; + float m_aSuspensionSpringRatio[4]; + float m_aSuspensionSpringRatioPrev[4]; + float m_aWheelSkidThing[4]; + int field_49C; + bool m_aWheelSkidmarkMuddy[4]; + bool m_aWheelSkidmarkBloody[4]; + float m_aWheelRotation[4]; + float m_aWheelPosition[4]; + float m_aWheelSpeed[4]; + uint8 stuff3[12]; + uint32 m_nBusDoorTimerEnd; + uint32 m_nBusDoorTimerStart; + float m_aSuspensionSpringLength[4]; + float m_aSuspensionLineLength[4]; + float m_fHeightAboveRoad; + float m_fImprovedHandling; + uint8 stuff6[32]; + CPhysical *m_aGroundPhysical[4]; // physicals touching wheels + CVector m_aGroundOffset[4]; // from ground object to colpoint + CEntity *m_pBlowUpEntity; + float m_weaponThingA; // TODO + float m_weaponThingB; // TODO + float m_fCarGunLR; + float m_fCarGunUD; + float m_fWindScreenRotation; + uint8 stuff4[4]; + uint8 m_nWheelsOnGround_2; + uint8 m_nWheelsOnGround; + uint8 m_nWheelsOnGroundPrev; + uint8 stuff5[5]; + int32 m_aWheelState[4]; + + CAutomobile(int, uint8); + CAutomobile* ctor(int, uint8); + void SetDoorDamage(int32, uint32, bool); /* TODO: eDoors */ + void SetPanelDamage(int32, uint32, bool); /* TODO: ePanels */ + void SetBumperDamage(int32, uint32, bool); /* TODO: ePanels */ + void dtor() { this->CAutomobile::~CAutomobile(); } +}; +static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error"); diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp new file mode 100644 index 00000000..076a910e --- /dev/null +++ b/src/vehicles/Boat.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "patcher.h" +#include "Boat.h" + +CBoat::CBoat(int mi, uint8 owner) +{ + ctor(mi, owner); +} + +WRAPPER CBoat* CBoat::ctor(int, uint8) { EAXJMP(0x53E3E0); } + +STARTPATCHES +InjectHook(0x53E790, &CBoat::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h new file mode 100644 index 00000000..6d6482a4 --- /dev/null +++ b/src/vehicles/Boat.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Vehicle.h" + +class CBoat : public CVehicle +{ +public: + // 0x288 + uint8 stuff1[57]; + bool m_bIsAnchored; + uint8 stuff[450]; + + CBoat(int, uint8); + CBoat* ctor(int, uint8); + void dtor() { this->CBoat::~CBoat(); }; +}; +static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp new file mode 100644 index 00000000..1a7f25ed --- /dev/null +++ b/src/vehicles/DamageManager.cpp @@ -0,0 +1,243 @@ +#include "common.h" +#include "patcher.h" +#include "General.h" +#include "DamageManager.h" + + +float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f }; + +void +CDamageManager::ResetDamageStatus(void) +{ + memset(this, 0, sizeof(*this)); +} + +void +CDamageManager::FuckCarCompletely(void) +{ + int i; + + m_wheelStatus[0] = 2; + // wheels 1-3 not reset? + + m_doorStatus[0] = 3; + m_doorStatus[1] = 3; + m_doorStatus[2] = 3; + m_doorStatus[3] = 3; + m_doorStatus[4] = 3; + m_doorStatus[5] = 3; + + for(i = 0; i < 3; i++){ +#ifdef FIX_BUGS + ProgressPanelDamage(VEHBUMPER_FRONT); + ProgressPanelDamage(VEHBUMPER_REAR); +#else + // this can't be right + ProgressPanelDamage(COMPONENT_BUMPER_FRONT); + ProgressPanelDamage(COMPONENT_BUMPER_REAR); +#endif + } + // Why set to no damage? + m_lightStatus = 0; + m_panelStatus = 0; + SetEngineStatus(250); +} + +bool +CDamageManager::ApplyDamage(tComponent component, float damage, float unused) +{ + tComponentGroup group; + uint8 subComp; + + GetComponentGroup(component, &group, &subComp); + damage *= G_aComponentDamage[group]; + if(damage > 150.0f){ + switch(group){ + case COMPGROUP_WHEEL: + ProgressWheelDamage(subComp); + break; + case COMPGROUP_DOOR: + case COMPGROUP_BOOT: + ProgressDoorDamage(subComp); + break; + case COMPGROUP_BONNET: + if(damage > 220.0f) + ProgressEngineDamage(); + ProgressDoorDamage(subComp); + break; + case COMPGROUP_PANEL: + // so windscreen is a light? + SetLightStatus((eLights)subComp, 1); + // fall through + case COMPGROUP_BUMPER: + if(damage > 220.0f && + (component == COMPONENT_PANEL_FRONT_LEFT || + component == COMPONENT_PANEL_FRONT_RIGHT || + component == COMPONENT_PANEL_WINDSCREEN)) + ProgressEngineDamage(); + ProgressPanelDamage(subComp); + break; + } + return true; + } + return false; +} + +bool +CDamageManager::GetComponentGroup(tComponent component, tComponentGroup *componentGroup, uint8 *subComp) +{ + *subComp = -2; // ?? + + // This is done very strangely in the game, maybe an optimized switch? + if(component >= COMPONENT_PANEL_FRONT_LEFT){ + if(component >= COMPONENT_BUMPER_FRONT) + *componentGroup = COMPGROUP_BUMPER; + else + *componentGroup = COMPGROUP_PANEL; + *subComp = component - COMPONENT_PANEL_FRONT_LEFT; + return true; + }else if(component >= COMPONENT_DOOR_BONNET){ + if(component == COMPONENT_DOOR_BONNET) + *componentGroup = COMPGROUP_BONNET; + else if(component == COMPONENT_DOOR_BOOT) + *componentGroup = COMPGROUP_BOOT; + else + *componentGroup = COMPGROUP_DOOR; + *subComp = component - COMPONENT_DOOR_BONNET; + return true; + }else if(component >= COMPONENT_WHEEL_FRONT_LEFT){ + *componentGroup = COMPGROUP_WHEEL; + *subComp = component - COMPONENT_WHEEL_FRONT_LEFT; + return true; + }else if(component >= COMPONENT_DEFAULT){ + *componentGroup = COMPGROUP_DEFAULT; + *subComp = component - COMPONENT_DEFAULT; + return true; + }else + return false; +} + +void +CDamageManager::SetDoorStatus(int32 door, uint32 status) +{ + m_doorStatus[door] = status; +} + +int32 +CDamageManager::GetDoorStatus(int32 door) +{ + return m_doorStatus[door]; +} + +bool +CDamageManager::ProgressDoorDamage(uint8 door) +{ + int status = GetDoorStatus(door); + if(status == 3) + return false; + SetDoorStatus(door, status+1); + return true; +} + +void +CDamageManager::SetPanelStatus(int32 panel, uint32 status) +{ + m_panelStatus = dpb(status, panel*4, 4, m_panelStatus); +} + +int32 +CDamageManager::GetPanelStatus(int32 panel) +{ + return ldb(panel*4, 4, m_panelStatus); +} + +bool +CDamageManager::ProgressPanelDamage(uint8 panel) +{ + int status = GetPanelStatus(panel); + if(status == 3) + return false; + SetPanelStatus(panel, status+1); + return true; +} + +void +CDamageManager::SetLightStatus(eLights light, uint32 status) +{ + m_lightStatus = dpb(status, light*2, 2, m_lightStatus); +} + +int32 +CDamageManager::GetLightStatus(eLights light) +{ + return ldb(light*2, 2, m_lightStatus); +} + +void +CDamageManager::SetWheelStatus(int32 wheel, uint32 status) +{ + m_wheelStatus[wheel] = status; +} + +int32 +CDamageManager::GetWheelStatus(int32 wheel) +{ + return m_wheelStatus[wheel]; +} + +bool +CDamageManager::ProgressWheelDamage(uint8 wheel) +{ + int status = GetWheelStatus(wheel); + if(status == 3) + return false; + SetWheelStatus(wheel, status+1); + return true; +} + +void +CDamageManager::SetEngineStatus(uint32 status) +{ + if(status > 250) + m_engineStatus = 250; + else + m_engineStatus = status; +} + +int32 +CDamageManager::GetEngineStatus(void) +{ + return m_engineStatus; +} + +bool +CDamageManager::ProgressEngineDamage(void) +{ + int status = GetEngineStatus(); + int newstatus = status + 32 + (CGeneral::GetRandomNumber() & 0x1F); + if(status < 225 && newstatus > 224) + newstatus = 224; + SetEngineStatus(newstatus); + return true; +} + +STARTPATCHES + InjectHook(0x545850, &CDamageManager::ResetDamageStatus, PATCH_JUMP); + InjectHook(0x545B70, &CDamageManager::FuckCarCompletely, PATCH_JUMP); + InjectHook(0x545790, &CDamageManager::GetComponentGroup, PATCH_JUMP); + InjectHook(0x545A80, &CDamageManager::ApplyDamage, PATCH_JUMP); + InjectHook(0x545920, &CDamageManager::SetDoorStatus, PATCH_JUMP); + InjectHook(0x545930, &CDamageManager::GetDoorStatus, PATCH_JUMP); + InjectHook(0x545970, &CDamageManager::ProgressDoorDamage, PATCH_JUMP); + InjectHook(0x5458B0, &CDamageManager::SetPanelStatus, PATCH_JUMP); + InjectHook(0x5458E0, (int32 (CDamageManager::*)(int32))&CDamageManager::GetPanelStatus, PATCH_JUMP); + InjectHook(0x545A00, &CDamageManager::ProgressPanelDamage, PATCH_JUMP); + InjectHook(0x545860, &CDamageManager::SetLightStatus, PATCH_JUMP); + InjectHook(0x545890, &CDamageManager::GetLightStatus, PATCH_JUMP); + InjectHook(0x545900, &CDamageManager::SetWheelStatus, PATCH_JUMP); + InjectHook(0x545910, &CDamageManager::GetWheelStatus, PATCH_JUMP); + InjectHook(0x545A40, &CDamageManager::ProgressWheelDamage, PATCH_JUMP); + InjectHook(0x545940, &CDamageManager::SetEngineStatus, PATCH_JUMP); + InjectHook(0x545960, &CDamageManager::GetEngineStatus, PATCH_JUMP); + InjectHook(0x5459B0, &CDamageManager::ProgressEngineDamage, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h new file mode 100644 index 00000000..1fdbc6b1 --- /dev/null +++ b/src/vehicles/DamageManager.h @@ -0,0 +1,92 @@ +#pragma once + +#include "common.h" + +// TODO: move some of this into Vehicle.h + +enum tComponent +{ + COMPONENT_DEFAULT, + COMPONENT_WHEEL_FRONT_LEFT, + COMPONENT_WHEEL_FRONT_RIGHT, + COMPONENT_WHEEL_REAR_LEFT, + COMPONENT_WHEEL_REAR_RIGHT, + COMPONENT_DOOR_BONNET, + COMPONENT_DOOR_BOOT, + COMPONENT_DOOR_FRONT_LEFT, + COMPONENT_DOOR_FRONT_RIGHT, + COMPONENT_DOOR_REAR_LEFT, + COMPONENT_DOOR_REAR_RIGHT, + COMPONENT_PANEL_FRONT_LEFT, + COMPONENT_PANEL_FRONT_RIGHT, + COMPONENT_PANEL_REAR_LEFT, + COMPONENT_PANEL_REAR_RIGHT, + COMPONENT_PANEL_WINDSCREEN, + COMPONENT_BUMPER_FRONT, + COMPONENT_BUMPER_REAR, +}; + +enum tComponentGroup +{ + COMPGROUP_BUMPER, + COMPGROUP_WHEEL, + COMPGROUP_DOOR, + COMPGROUP_BONNET, + COMPGROUP_BOOT, + COMPGROUP_PANEL, + COMPGROUP_DEFAULT, +}; + +enum eLights +{ + VEHLIGHT_FRONT_LEFT, + VEHLIGHT_FRONT_RIGHT, + VEHLIGHT_REAR_LEFT, + VEHLIGHT_REAR_RIGHT, +}; + +enum { + VEHPANEL_FRONT_LEFT, + VEHPANEL_FRONT_RIGHT, + VEHPANEL_REAR_LEFT, + VEHPANEL_REAR_RIGHT, + VEHPANEL_WINDSCREEN, + VEHBUMPER_FRONT, + VEHBUMPER_REAR, +}; + +class CDamageManager +{ +public: + + float field_0; + uint8 m_engineStatus; + uint8 m_wheelStatus[4]; + uint8 m_doorStatus[6]; + uint32 m_lightStatus; + uint32 m_panelStatus; + uint32 field_24; + + void ResetDamageStatus(void); + void FuckCarCompletely(void); + bool ApplyDamage(tComponent component, float damage, float unused); + bool GetComponentGroup(tComponent component, tComponentGroup *componentGroup, uint8 *foo); + + void SetDoorStatus(int32 door, uint32 status); + int32 GetDoorStatus(int32 door); + bool ProgressDoorDamage(uint8 door); + void SetPanelStatus(int32 panel, uint32 status); + int32 GetPanelStatus(int32 panel); + bool ProgressPanelDamage(uint8 panel); + // needed for CReplay + static int32 GetPanelStatus(uint32 panelstatus, int32 panel) { return ldb(panel*4, 4, panelstatus); } + void SetLightStatus(eLights light, uint32 status); + int32 GetLightStatus(eLights light); + void SetWheelStatus(int32 wheel, uint32 status); + int32 GetWheelStatus(int32 wheel); + bool ProgressWheelDamage(uint8 wheel); + void SetEngineStatus(uint32 status); + int32 GetEngineStatus(void); + bool ProgressEngineDamage(void); +}; +VALIDATE_SIZE(CDamageManager, 0x1C); diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp new file mode 100644 index 00000000..47d0564c --- /dev/null +++ b/src/vehicles/HandlingMgr.cpp @@ -0,0 +1,247 @@ +#include "common.h" +#include "patcher.h" +#include "main.h" +#include "FileMgr.h" +#include "HandlingMgr.h" + +cHandlingDataMgr &mod_HandlingManager = *(cHandlingDataMgr*)0x728060; + +char *HandlingFilename = "HANDLING.CFG"; + +char VehicleNames[NUMHANDLINGS][14] = { + "LANDSTAL", + "IDAHO", + "STINGER", + "LINERUN", + "PEREN", + "SENTINEL", + "PATRIOT", + "FIRETRUK", + "TRASH", + "STRETCH", + "MANANA", + "INFERNUS", + "BLISTA", + "PONY", + "MULE", + "CHEETAH", + "AMBULAN", + "FBICAR", + "MOONBEAM", + "ESPERANT", + "TAXI", + "KURUMA", + "BOBCAT", + "MRWHOOP", + "BFINJECT", + "POLICE", + "ENFORCER", + "SECURICA", + "BANSHEE", + "PREDATOR", + "BUS", + "RHINO", + "BARRACKS", + "TRAIN", + "HELI", + "DODO", + "COACH", + "CABBIE", + "STALLION", + "RUMPO", + "RCBANDIT", + "BELLYUP", + "MRWONGS", + "MAFIA", + "YARDIE", + "YAKUZA", + "DIABLOS", + "COLUMB", + "HOODS", + "AIRTRAIN", + "DEADDODO", + "SPEEDER", + "REEFER", + "PANLANT", + "FLATBED", + "YANKEE", + "BORGNINE" +}; + +cHandlingDataMgr::cHandlingDataMgr(void) +{ + memset(this, 0, sizeof(this)); +} + +void +cHandlingDataMgr::Initialise(void) +{ + LoadHandlingData(); + field_0 = 0.1f; + field_4 = 0.9f; + field_8 = 1.0f; + field_C = 0.8f; + field_10 = 0.98f; +} + +void +cHandlingDataMgr::LoadHandlingData(void) +{ + char *start, *end; + char line[201]; // weird value + char delim[4]; // not sure + char *word; + int field, handlingId; + int keepGoing; + tHandlingData *handling; + + CFileMgr::SetDir("DATA"); + CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r"); + CFileMgr::SetDir(""); + + start = (char*)work_buff; + end = start+1; + handling = nil; + keepGoing = 1; + + while(keepGoing){ + // find end of line + while(*end != '\n') end++; + + // get line + strncpy(line, start, end - start); + line[end - start] = '\0'; + start = end+1; + end = start+1; + + // yeah, this is kinda crappy + if(strncmp(line, ";the end", 9) == 0) + keepGoing = 0; + else if(line[0] != ';'){ + field = 0; + strcpy(delim, " \t"); + // FIX: game seems to use a do-while loop here + for(word = strtok(line, delim); word; word = strtok(nil, delim)){ + switch(field){ + case 0: + handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS); + assert(handlingId >= 0 && handlingId < NUMHANDLINGS); + handling = &HandlingData[handlingId]; + handling->nIdentifier = handlingId; + break; + case 1: handling->fMass = strtod(word, nil); break; + case 2: handling->Dimension.x = strtod(word, nil); break; + case 3: handling->Dimension.y = strtod(word, nil); break; + case 4: handling->Dimension.z = strtod(word, nil); break; + case 5: handling->CentreOfMass.x = strtod(word, nil); break; + case 6: handling->CentreOfMass.y = strtod(word, nil); break; + case 7: handling->CentreOfMass.z = strtod(word, nil); break; + case 8: handling->nPercentSubmerged = atoi(word); break; + case 9: handling->fTractionMultiplier = strtod(word, nil); break; + case 10: handling->fTractionLoss = strtod(word, nil); break; + case 11: handling->fTractionBias = strtod(word, nil); break; + case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break; + case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break; + case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break; + case 15: handling->TransmissionData.nDriveType = word[0]; break; + case 16: handling->TransmissionData.nEngineType = word[0]; break; + case 17: handling->fBrakeDeceleration = strtod(word, nil); break; + case 18: handling->fBrakeBias = strtod(word, nil); break; + case 19: handling->bABS = !!atoi(word); break; + case 20: handling->fSteeringLock = strtod(word, nil); break; + case 21: handling->fSuspensionForceLevel = strtod(word, nil); break; + case 22: handling->fSuspensionDampingLevel = strtod(word, nil); break; + case 23: handling->fSeatOffsetDistance = strtod(word, nil); break; + case 24: handling->fCollisionDamageMultiplier = strtod(word, nil); break; + case 25: handling->nMonetaryValue = atoi(word); break; + case 26: handling->fSuspensionUpperLimit = strtod(word, nil); break; + case 27: handling->fSuspensionLowerLimit = strtod(word, nil); break; + case 28: handling->fSuspensionBias = strtod(word, nil); break; + case 29: + sscanf(word, "%x", &handling->Flags); + handling->TransmissionData.Flags = handling->Flags; + break; + case 30: handling->FrontLights = atoi(word); break; + case 31: handling->RearLights = atoi(word); break; + } + field++; + } + ConvertDataToGameUnits(handling); + } + } +} + +int +cHandlingDataMgr::FindExactWord(const char *word, const char *words, int wordLen, int numWords) +{ + int i; + + for(i = 0; i < numWords; i++){ + // BUG: the game does something really stupid here, it's fixed here + if(strncmp(word, words, wordLen) == 0) + return i; + words += wordLen; + } + return numWords; +} + + +void +cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling) +{ + // TODO: figure out what exactly is being converted here + float velocity, a, b, specificVolume; + + handling->TransmissionData.fEngineAcceleration /= 2500.0f; + handling->TransmissionData.fMaxVelocity /= 180.0f; + handling->fBrakeDeceleration /= 2500.0f; + handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f; + if(handling->fTurnMass < 10.0f) + handling->fTurnMass *= 5.0f; + handling->fInvMass = 1.0f/handling->fMass; + handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * 0.008*handling->fMass; + + // What the hell is going on here? + specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ? + a = 0.0f; + b = 100.0f; + velocity = handling->TransmissionData.fMaxVelocity; + while(a < b && velocity > 0.0f){ + velocity -= 0.01; + a = handling->TransmissionData.fEngineAcceleration/6.0f; + b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f); + } + + if(handling->nIdentifier == HANDLING_RCBANDIT){ + handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity; + }else{ + handling->TransmissionData.fUnkMaxVelocity = velocity; + handling->TransmissionData.fMaxVelocity = velocity * 1.2f; + } + handling->TransmissionData.fMaxReverseVelocity = -0.2f; + + if(handling->TransmissionData.nDriveType == '4') + handling->TransmissionData.fEngineAcceleration /= 4.0f; + else + handling->TransmissionData.fEngineAcceleration /= 2.0f; + + handling->TransmissionData.InitGearRatios(); +} + +int32 +cHandlingDataMgr::GetHandlingId(const char *name) +{ + int i; + for(i = 0; i < NUMHANDLINGS; i++) + if(strncmp(VehicleNames[i], name, 14) == 0) + break; + return i; +} + +STARTPATCHES + InjectHook(0x546D80, &cHandlingDataMgr::Initialise, PATCH_JUMP); + InjectHook(0x546DB0, &cHandlingDataMgr::LoadHandlingData, PATCH_JUMP); + InjectHook(0x546BB0, &cHandlingDataMgr::ConvertDataToGameUnits, PATCH_JUMP); + InjectHook(0x546AA0, &cHandlingDataMgr::FindExactWord, PATCH_JUMP); + InjectHook(0x546B70, &cHandlingDataMgr::GetHandlingId, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h new file mode 100644 index 00000000..958e2351 --- /dev/null +++ b/src/vehicles/HandlingMgr.h @@ -0,0 +1,139 @@ +#pragma once + +#include "Transmission.h" + +enum eHandlingId +{ + HANDLING_LANDSTAL, + HANDLING_IDAHO, + HANDLING_STINGER, + HANDLING_LINERUN, + HANDLING_PEREN, + HANDLING_SENTINEL, + HANDLING_PATRIOT, + HANDLING_FIRETRUK, + HANDLING_TRASH, + HANDLING_STRETCH, + HANDLING_MANANA, + HANDLING_INFERNUS, + HANDLING_BLISTA, + HANDLING_PONY, + HANDLING_MULE, + HANDLING_CHEETAH, + HANDLING_AMBULAN, + HANDLING_FBICAR, + HANDLING_MOONBEAM, + HANDLING_ESPERANT, + HANDLING_TAXI, + HANDLING_KURUMA, + HANDLING_BOBCAT, + HANDLING_MRWHOOP, + HANDLING_BFINJECT, + HANDLING_POLICE, + HANDLING_ENFORCER, + HANDLING_SECURICA, + HANDLING_BANSHEE, + HANDLING_PREDATOR, + HANDLING_BUS, + HANDLING_RHINO, + HANDLING_BARRACKS, + HANDLING_TRAIN, + HANDLING_HELI, + HANDLING_DODO, + HANDLING_COACH, + HANDLING_CABBIE, + HANDLING_STALLION, + HANDLING_RUMPO, + HANDLING_RCBANDIT, + HANDLING_BELLYUP, + HANDLING_MRWONGS, + HANDLING_MAFIA, + HANDLING_YARDIE, + HANDLING_YAKUZA, + HANDLING_DIABLOS, + HANDLING_COLUMB, + HANDLING_HOODS, + HANDLING_AIRTRAIN, + HANDLING_DEADDODO, + HANDLING_SPEEDER, + HANDLING_REEFER, + HANDLING_PANLANT, + HANDLING_FLATBED, + HANDLING_YANKEE, + HANDLING_BORGNINE +}; + +enum +{ + HANDLING_1G_BOOST = 1, + HANDLING_2G_BOOST = 2, + HANDLING_REV_BONNET = 4, + HANDLING_HANGING_BOOT = 8, + HANDLING_NO_DOORS = 0x10, + HANDLING_IS_VAN = 0x20, + HANDLING_IS_BUS = 0x40, + HANDLING_IS_LOW = 0x80, + HANDLING_DBL_EXHAUST = 0x100, + HANDLING_TAILGATE_BOOT = 0x200, + HANDLING_NOSWING_BOOT = 0x400, + HANDLING_NONPLAYER_STABILISER = 0x800, + HANDLING_NEUTRALHANDLING = 0x1000, + HANDLING_HAS_NO_ROOF = 0x2000, + HANDLING_IS_BIG = 0x4000, + HANDLING_HALOGEN_LIGHTS = 0x8000, +}; + +struct tHandlingData +{ + int32 nIdentifier; + float fMass; + float fInvMass; + float fTurnMass; + CVector Dimension; + CVector CentreOfMass; + int8 nPercentSubmerged; + float fBuoyancy; + float fTractionMultiplier; + cTransmission TransmissionData; + float fBrakeDeceleration; + float fBrakeBias; + int8 bABS; + float fSteeringLock; + float fTractionLoss; + float fTractionBias; + uint32 field_AC; + float fSuspensionForceLevel; + float fSuspensionDampingLevel; + float fSuspensionUpperLimit; + float fSuspensionLowerLimit; + float fSuspensionBias; + float fCollisionDamageMultiplier; + uint32 Flags; + float fSeatOffsetDistance; + int32 nMonetaryValue; + int8 FrontLights; + int8 RearLights; +}; +VALIDATE_SIZE(tHandlingData, 0xD8); + +class cHandlingDataMgr +{ + float field_0; // unused it seems + float field_4; // wheel related + float field_8; // + float field_C; // unused it seems + float field_10; // + tHandlingData HandlingData[NUMHANDLINGS]; + uint32 field_302C; // unused it seems, padding? + +public: + cHandlingDataMgr(void); + void Initialise(void); + void LoadHandlingData(void); + int FindExactWord(const char *word, const char *words, int wordLen, int numWords); + void ConvertDataToGameUnits(tHandlingData *handling); + int32 GetHandlingId(const char *name); + tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; } +}; +VALIDATE_SIZE(cHandlingDataMgr, 0x3030); +extern cHandlingDataMgr &mod_HandlingManager; diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp new file mode 100644 index 00000000..01ee5375 --- /dev/null +++ b/src/vehicles/Heli.cpp @@ -0,0 +1,15 @@ +#include "common.h" +#include "patcher.h" +#include "Heli.h" + +CHeli::CHeli(int mi, uint8 owner) +{ + ctor(mi, owner); +} + +WRAPPER CHeli* CHeli::ctor(int, uint8) { EAXJMP(0x547220); } +WRAPPER void CHeli::SpecialHeliPreRender(void) { EAXJMP(0x54AE10); } + +STARTPATCHES +InjectHook(0x5474A0, &CHeli::dtor, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Heli.h b/src/vehicles/Heli.h new file mode 100644 index 00000000..da7bb171 --- /dev/null +++ b/src/vehicles/Heli.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Vehicle.h" + +class CHeli : public CVehicle +{ +public: + // 0x288 + uint8 stuff[180]; + + CHeli(int, uint8); + CHeli* ctor(int, uint8); + void dtor(void) { this->CHeli::~CHeli(); } + + static void SpecialHeliPreRender(void); +}; +static_assert(sizeof(CHeli) == 0x33C, "CHeli: error"); diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp new file mode 100644 index 00000000..6e30bced --- /dev/null +++ b/src/vehicles/Plane.cpp @@ -0,0 +1,19 @@ +#include "common.h" +#include "patcher.h" +#include "Plane.h" + +CPlane::CPlane(int mi, uint8 owner) +{ + ctor(mi, owner); +} + +WRAPPER CPlane* CPlane::ctor(int, uint8) { EAXJMP(0x54B170); } + +CPlane::~CPlane() +{ + DeleteRwObject(); +} + +STARTPATCHES +InjectHook(0x54B270, &CPlane::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h new file mode 100644 index 00000000..e26008f6 --- /dev/null +++ b/src/vehicles/Plane.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common.h" +#include "Vehicle.h" + +class CPlane : public CVehicle +{ +public: + // 0x288 + uint8 stuff[20]; + + CPlane(int, uint8); + ~CPlane(void); + CPlane* ctor(int, uint8); + void dtor(void) { this->CPlane::~CPlane(); } + void FlagToDestroyWhenNextProcessed() { bRemoveFromWorld = true; } +}; +static_assert(sizeof(CPlane) == 0x29C, "CPlane: error"); diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp new file mode 100644 index 00000000..62fd53ec --- /dev/null +++ b/src/vehicles/Train.cpp @@ -0,0 +1,14 @@ +#include "common.h" +#include "patcher.h" +#include "Train.h" + +CTrain::CTrain(int mi, uint8 owner) +{ + ctor(mi, owner); +} + +WRAPPER CTrain* CTrain::ctor(int, uint8) { EAXJMP(0x54E2A0); } + +STARTPATCHES +InjectHook(0x54E450, &CTrain::dtor, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/vehicles/Train.h b/src/vehicles/Train.h new file mode 100644 index 00000000..84b6faf5 --- /dev/null +++ b/src/vehicles/Train.h @@ -0,0 +1,26 @@ +#pragma once + +#include "common.h" +#include "patcher.h" +#include "Vehicle.h" + +enum +{ + TRAIN_DOOR_STATE2 = 2 +}; + +class CTrain : public CVehicle +{ +public: + // 0x288 + uint8 stuff1[20]; + uint8 m_trackId; + uint8 stuff2[7]; + int16 m_doorState; + uint8 stuff3[62]; + + CTrain(int, uint8); + CTrain* ctor(int, uint8); + void dtor(void) { this->CTrain::~CTrain(); } +}; +static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error"); diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp new file mode 100644 index 00000000..2be25cbb --- /dev/null +++ b/src/vehicles/Transmission.cpp @@ -0,0 +1,37 @@ +#include "common.h" +#include "patcher.h" +#include "Transmission.h" + +void +cTransmission::InitGearRatios(void) +{ + static tGear *pGearRatio0 = nil; + static tGear *pGearRatio1 = nil; + int i; + float velocityDiff; + + memset(Gears, 0, sizeof(Gears)); + + for(i = 1; i <= nNumberOfGears; i++){ + pGearRatio0 = &Gears[i-1]; + pGearRatio1 = &Gears[i]; + + pGearRatio1->fMaxVelocity = (float)i / nNumberOfGears * fMaxVelocity; + + velocityDiff = pGearRatio1->fMaxVelocity - pGearRatio0->fMaxVelocity; + + if(i >= nNumberOfGears){ + pGearRatio1->fShiftUpVelocity = fMaxVelocity; + }else{ + Gears[i+1].fShiftDownVelocity = velocityDiff*0.42f + pGearRatio0->fMaxVelocity; + pGearRatio1->fShiftUpVelocity = velocityDiff*0.6667f + pGearRatio0->fMaxVelocity; + } + } + + // Reverse gear + Gears[0].fMaxVelocity = fMaxReverseVelocity; + Gears[0].fShiftUpVelocity = -0.01f; + Gears[0].fShiftDownVelocity = fMaxReverseVelocity; + + Gears[1].fShiftDownVelocity = -0.01f; +} diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h new file mode 100644 index 00000000..686e0aca --- /dev/null +++ b/src/vehicles/Transmission.h @@ -0,0 +1,26 @@ +#pragma once + +struct tGear +{ + float fMaxVelocity; + float fShiftUpVelocity; + float fShiftDownVelocity; +}; + +class cTransmission +{ +public: + // Gear 0 is reverse, 1-5 are forward + tGear Gears[6]; + char nDriveType; + char nEngineType; + int8 nNumberOfGears; + uint8 Flags; + float fEngineAcceleration; + float fMaxVelocity; + float fUnkMaxVelocity; + float fMaxReverseVelocity; + float field_5C; + + void InitGearRatios(void); +}; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp new file mode 100644 index 00000000..dccd9195 --- /dev/null +++ b/src/vehicles/Vehicle.cpp @@ -0,0 +1,489 @@ +#include "common.h" +#include "main.h" +#include "patcher.h" +#include "Timer.h" +#include "Vehicle.h" +#include "Pools.h" +#include "HandlingMgr.h" +#include "CarCtrl.h" +#include "Population.h" +#include "ModelIndices.h" +#include "World.h" +#include "Lights.h" +#include "PointLights.h" +#include "Renderer.h" +#include "DMAudio.h" +#include "Radar.h" + +bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78; +bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75; +bool &CVehicle::bCheat3 = *(bool *)0x95CD66; +bool &CVehicle::bCheat4 = *(bool *)0x95CD65; +bool &CVehicle::bCheat5 = *(bool *)0x95CD64; +bool &CVehicle::m_bDisableMouseSteering = *(bool *)0x60252C; + +void *CVehicle::operator new(size_t sz) { return CPools::GetVehiclePool()->New(); } +void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehiclePool()->New(handle); } +void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } +void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } + +CVehicle::~CVehicle() +{ + m_nAlarmState = 0; + if (m_audioEntityId >= 0){ + DMAudio.DestroyEntity(m_audioEntityId); + m_audioEntityId = -5; + } + CRadar::ClearBlipForEntity(BLIP_CAR, CPools::GetVehiclePool()->GetIndex(this)); + if (pDriver) + pDriver->FlagToDestroyWhenNextProcessed(); + for (int i = 0; i < m_nNumMaxPassengers; i++){ + if (pPassengers[i]) + pPassengers[i]->FlagToDestroyWhenNextProcessed(); + } + if (m_pCarFire) + m_pCarFire->Extinguish(); + CCarCtrl::UpdateCarCount(this, true); + if (bIsAmbulanceOnDuty){ + CCarCtrl::NumAmbulancesOnDuty--; + bIsAmbulanceOnDuty = false; + } + if (bIsFireTruckOnDuty){ + CCarCtrl::NumFiretrucksOnDuty--; + bIsFireTruckOnDuty = false; + } +} + +void +CVehicle::SetModelIndex(uint32 id) +{ + CEntity::SetModelIndex(id); + m_aExtras[0] = CVehicleModelInfo::ms_compsUsed[0]; + m_aExtras[1] = CVehicleModelInfo::ms_compsUsed[1]; + m_nNumMaxPassengers = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(id); +} + +bool +CVehicle::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + + if(bRenderScorched){ + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + }else{ + CVector coors = GetPosition(); + float lighting = CPointLights::GenerateLightsAffectingObject(&coors); + if(!bHasBlip && lighting != 1.0f){ + SetAmbientAndDirectionalColours(lighting); + return true; + } + } + + return false; +} + +void +CVehicle::RemoveLighting(bool reset) +{ + CRenderer::RemoveVehiclePedLights(this, reset); +} + +float +CVehicle::GetHeightAboveRoad(void) +{ + return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z; +} + + +bool +CVehicle::IsLawEnforcementVehicle(void) +{ + switch(GetModelIndex()){ + case MI_FBICAR: + case MI_POLICE: + case MI_ENFORCER: + case MI_PREDATOR: + case MI_RHINO: + case MI_BARRACKS: + return true; + default: + return false; + } +} + +bool +CVehicle::UsesSiren(uint32 id) +{ + switch(id){ + case MI_FIRETRUCK: + case MI_AMBULAN: + case MI_FBICAR: + case MI_MRWHOOP: + case MI_POLICE: + case MI_ENFORCER: + case MI_PREDATOR: + return true; + default: + return false; + } +} + +bool +CVehicle::IsVehicleNormal(void) +{ + if(pDriver && m_nNumPassengers == 0 && m_status != STATUS_WRECKED){ + switch(GetModelIndex()) + case MI_FIRETRUCK: + case MI_AMBULAN: + case MI_TAXI: + case MI_POLICE: + case MI_ENFORCER: + case MI_BUS: + case MI_RHINO: + case MI_BARRACKS: + case MI_DODO: + case MI_COACH: + case MI_CABBIE: + case MI_RCBANDIT: + case MI_BORGNINE: + return false; + } + return false; +} + +bool +CVehicle::CarHasRoof(void) +{ + if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0) + return true; + if(m_aExtras[0] && m_aExtras[1]) + return false; + return true; +} + +bool +CVehicle::IsUpsideDown(void) +{ + if(GetUp().z > -0.9f) + return false; + return true; +} + +bool +CVehicle::IsOnItsSide(void) +{ + if(GetRight().z < 0.8f && GetRight().z > -0.8f) + return false; + return true; +} + +bool +CVehicle::CanBeDeleted(void) +{ + int i; + + if(m_nNumGettingIn || m_nGettingOutFlags) + return false; + + if(pDriver){ + // This looks like it was inlined + if(pDriver->CharCreatedBy == MISSION_CHAR) + return false; + if(pDriver->GetPedState() != PED_DRIVING && + pDriver->GetPedState() != PED_DEAD) + return false; + } + + for(i = 0; i < 8; i++){ + // Same check as above + if(pPassengers[i]){ + if(pPassengers[i]->CharCreatedBy == MISSION_CHAR) + return false; + if(pPassengers[i]->GetPedState() != PED_DRIVING && + pPassengers[i]->GetPedState() != PED_DEAD) + return false; + } + // and then again... probably because something was inlined + if(pPassengers[i]){ + if(pPassengers[i]->GetPedState() != PED_DRIVING && + pPassengers[i]->GetPedState() != PED_DEAD) + return false; + } + } + + switch(VehicleCreatedBy){ + case RANDOM_VEHICLE: return true; + case MISSION_VEHICLE: return false; + case PARKED_VEHICLE: return true; + case PERMANENT_VEHICLE: return false; + } + return true; +} + +bool +CVehicle::CanPedOpenLocks(CPed *ped) +{ + if(m_nDoorLock == CARLOCK_LOCKED || + m_nDoorLock == CARLOCK_COP_CAR || + m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE) + return false; + if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY) + return false; + return true; +} + +bool +CVehicle::CanPedEnterCar(void) +{ + CVector up = GetUp(); + // can't enter when car is on side + if(up.z > 0.1f || up.z < -0.1f){ + // also when car is moving too fast + if(m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f)) + return false; + if(m_vecTurnSpeed.MagnitudeSqr() > sq(0.2f)) + return false; + return true; + } + return false; +} + +bool +CVehicle::CanPedExitCar(void) +{ + CVector up = GetUp(); + if(up.z > 0.1f || up.z < -0.1f){ + // can't exit when car is moving too fast + if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f) + return false; + // if car is slow enough, check turn speed + if(fabs(m_vecTurnSpeed.x) > 0.01f || + fabs(m_vecTurnSpeed.y) > 0.01f || + fabs(m_vecTurnSpeed.z) > 0.01f) + return false; + return true; + }else{ + // What is this? just > replaced by >= ?? + + // can't exit when car is moving too fast + if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f) + return false; + // if car is slow enough, check turn speed + if(fabs(m_vecTurnSpeed.x) >= 0.01f || + fabs(m_vecTurnSpeed.y) >= 0.01f || + fabs(m_vecTurnSpeed.z) >= 0.01f) + return false; + return true; + } +} + +void +CVehicle::ChangeLawEnforcerState(uint8 enable) +{ + if (enable) { + if (!bIsLawEnforcer) { + bIsLawEnforcer = true; + CCarCtrl::NumLawEnforcerCars++; + } + } else { + if (bIsLawEnforcer) { + bIsLawEnforcer = false; + CCarCtrl::NumLawEnforcerCars--; + } + } +} + +CPed* +CVehicle::SetUpDriver(void) +{ + if(pDriver) + return pDriver; + if(VehicleCreatedBy != RANDOM_VEHICLE) + return nil; + + pDriver = CPopulation::AddPedInCar(this); + pDriver->m_pMyVehicle = this; + pDriver->m_pMyVehicle->RegisterReference((CEntity**)&pDriver->m_pMyVehicle); + pDriver->bInVehicle = true; + pDriver->SetPedState(PED_DRIVING); + if(bIsBus) + pDriver->m_ped_flagC4 = false; + return pDriver; +} + +CPed* +CVehicle::SetupPassenger(int n) +{ + if(pPassengers[n]) + return pPassengers[n]; + + pPassengers[n] = CPopulation::AddPedInCar(this); + pPassengers[n]->m_pMyVehicle = this; + pPassengers[n]->m_pMyVehicle->RegisterReference((CEntity**)&pPassengers[n]->m_pMyVehicle); + pPassengers[n]->bInVehicle = true; + pPassengers[n]->SetPedState(PED_DRIVING); + if(bIsBus) + pPassengers[n]->m_ped_flagC4 = false; + return pPassengers[n]; +} + +void +CVehicle::SetDriver(CPed *driver) +{ + pDriver = driver; + pDriver->RegisterReference((CEntity**)&pDriver); + + if(bFreebies && driver == FindPlayerPed()){ + if(GetModelIndex() == MI_AMBULAN) + FindPlayerPed()->m_fHealth = min(FindPlayerPed()->m_fHealth + 20.0f, 100.0f); + else if(GetModelIndex() == MI_TAXI) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25; + else if(GetModelIndex() == MI_POLICE) + driver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5); + else if(GetModelIndex() == MI_ENFORCER) + driver->m_fArmour = max(driver->m_fArmour, 100.0f); + else if(GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25; + bFreebies = false; + } + + ApplyTurnForce(0.0f, 0.0f, -0.2f*driver->m_fMass, + driver->GetPosition().x - GetPosition().x, + driver->GetPosition().y - GetPosition().y, + 0.0f); +} + +bool +CVehicle::AddPassenger(CPed *passenger) +{ + int i; + + ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass, + passenger->GetPosition().x - GetPosition().x, + passenger->GetPosition().y - GetPosition().y, + 0.0f); + + for(i = 0; i < m_nNumMaxPassengers; i++) + if(pPassengers[i] == nil){ + pPassengers[i] = passenger; + m_nNumPassengers++; + return true; + } + return false; +} + +bool +CVehicle::AddPassenger(CPed *passenger, uint8 n) +{ + if(bIsBus) + return AddPassenger(passenger); + + ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass, + passenger->GetPosition().x - GetPosition().x, + passenger->GetPosition().y - GetPosition().y, + 0.0f); + + if(n < m_nNumMaxPassengers && pPassengers[n] == nil){ + pPassengers[n] = passenger; + m_nNumPassengers++; + return true; + } + return false; +} + +void +CVehicle::RemoveDriver(void) +{ + m_status = STATUS_ABANDONED; + pDriver = nil; +} + +void +CVehicle::RemovePassenger(CPed *p) +{ + if (IsTrain()){ + for (int i = 0; i < 8; i++){ + if (pPassengers[i] == p) { + pPassengers[i] = nil; + m_nNumPassengers--; + return; + } + } + return; + } + for (int i = 0; i < m_nNumMaxPassengers; i++){ + if (pPassengers[i] == p){ + pPassengers[i] = nil; + m_nNumPassengers--; + return; + } + } +} + +void +CVehicle::ProcessCarAlarm(void) +{ + uint32 step; + + if(m_nAlarmState == 0 || m_nAlarmState == -1) + return; + + step = CTimer::GetTimeStepInMilliseconds(); + if((uint16)m_nAlarmState < step) + m_nAlarmState = 0; + else + m_nAlarmState -= step; +} + +bool +CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) +{ + float x, y, z; + // sphere relative to vehicle + CVector sph = CVector(sx, sy, sz) - GetPosition(); + CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + + x = DotProduct(sph, GetRight()); + if(colmodel->boundingBox.min.x - radius > x || + colmodel->boundingBox.max.x + radius < x) + return false; + y = DotProduct(sph, GetForward()); + if(colmodel->boundingBox.min.y - radius > y || + colmodel->boundingBox.max.y + radius < y) + return false; + z = DotProduct(sph, GetUp()); + if(colmodel->boundingBox.min.z - radius > z || + colmodel->boundingBox.max.z + radius < z) + return false; + + return true; +} + +STARTPATCHES + InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP); + InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP); + + InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP); + InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP); + InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP); + InjectHook(0x5527E0, &CVehicle::IsVehicleNormal, PATCH_JUMP); + InjectHook(0x552B70, &CVehicle::CarHasRoof, PATCH_JUMP); + InjectHook(0x552230, &CVehicle::IsUpsideDown, PATCH_JUMP); + InjectHook(0x552260, &CVehicle::IsOnItsSide, PATCH_JUMP); + InjectHook(0x5511B0, &CVehicle::CanBeDeleted, PATCH_JUMP); + InjectHook(0x5522A0, &CVehicle::CanPedOpenLocks, PATCH_JUMP); + InjectHook(0x5522F0, &CVehicle::CanPedEnterCar, PATCH_JUMP); + InjectHook(0x5523C0, &CVehicle::CanPedExitCar, PATCH_JUMP); + InjectHook(0x5520C0, &CVehicle::SetUpDriver, PATCH_JUMP); + InjectHook(0x552160, &CVehicle::SetupPassenger, PATCH_JUMP); + InjectHook(0x551F20, &CVehicle::SetDriver, PATCH_JUMP); + InjectHook(0x551D90, (bool (CVehicle::*)(CPed*))&CVehicle::AddPassenger, PATCH_JUMP); + InjectHook(0x551E10, (bool (CVehicle::*)(CPed*,uint8))&CVehicle::AddPassenger, PATCH_JUMP); + InjectHook(0x5520A0, &CVehicle::RemoveDriver, PATCH_JUMP); + InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP); + InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP); + InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP); +ENDPATCHES diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h new file mode 100644 index 00000000..39a56fe0 --- /dev/null +++ b/src/vehicles/Vehicle.h @@ -0,0 +1,240 @@ +#pragma once + +#include "Physical.h" +#include "AutoPilot.h" + +class CPed; +class CFire; +struct tHandlingData; + +enum { + RANDOM_VEHICLE = 1, + MISSION_VEHICLE = 2, + PARKED_VEHICLE = 3, + PERMANENT_VEHICLE = 4, +}; + +enum eCarLock { + CARLOCK_NOT_USED, + CARLOCK_UNLOCKED, + CARLOCK_LOCKED, + CARLOCK_LOCKOUT_PLAYER_ONLY, + CARLOCK_LOCKED_PLAYER_INSIDE, + CARLOCK_COP_CAR, + CARLOCK_FORCE_SHUT_DOORS, + CARLOCK_SKIP_SHUT_DOORS +}; + + +enum eCarNodes +{ + CAR_WHEEL_RF = 1, + CAR_WHEEL_RM, + CAR_WHEEL_RB, + CAR_WHEEL_LF, + CAR_WHEEL_LM, + CAR_WHEEL_LB, + CAR_BUMP_FRONT, + CAR_BUMP_REAR, + CAR_WING_RF, + CAR_WING_RR, + CAR_DOOR_RF, + CAR_DOOR_RR, + CAR_WING_LF, + CAR_WING_LR, + CAR_DOOR_LF, + CAR_DOOR_LR, + CAR_BONNET, + CAR_BOOT, + CAR_WINDSCREEN, + NUM_CAR_NODES, +}; + +enum +{ + CAR_POS_HEADLIGHTS, + CAR_POS_TAILLIGHTS, + CAR_POS_FRONTSEAT, + CAR_POS_BACKSEAT, + CAR_POS_EXHAUST = 9, +}; + +enum eDoors +{ + DOOR_BONNET = 0, + DOOR_BOOT, + DOOR_FRONT_LEFT, + DOOR_FRONT_RIGHT, + DOOR_REAR_LEFT, + DOOR_REAR_RIGHT +}; + +class CVehicle : public CPhysical +{ +public: + // 0x128 + tHandlingData *m_handling; + CAutoPilot m_autoPilot; + uint8 m_currentColour1; + uint8 m_currentColour2; + uint8 m_aExtras[2]; + int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22 + int16 m_nMissionValue; + CPed *pDriver; + CPed *pPassengers[8]; + uint8 m_nNumPassengers; + int8 m_nNumGettingIn; + int8 m_nGettingInFlags; + int8 m_nGettingOutFlags; + uint8 m_nNumMaxPassengers; + char field_1CD[19]; + CEntity *m_pCurSurface; + CFire *m_pCarFire; + float m_fSteerAngle; + float m_fGasPedal; + float m_fBreakPedal; + uint8 VehicleCreatedBy; + + // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R* + uint8 bIsLawEnforcer: 1; // Is this guy chasing the player at the moment + uint8 bIsAmbulanceOnDuty: 1; // Ambulance trying to get to an accident + uint8 bIsFireTruckOnDuty: 1; // Firetruck trying to get to a fire + uint8 bIsLocked: 1; // Is this guy locked by the script (cannot be removed) + uint8 bEngineOn: 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars) + uint8 bIsHandbrakeOn: 1; // How's the handbrake doing ? + uint8 bLightsOn: 1; // Are the lights switched on ? + uint8 bFreebies: 1; // Any freebies left in this vehicle ? + + uint8 bIsVan: 1; // Is this vehicle a van (doors at back of vehicle) + uint8 bIsBus: 1; // Is this vehicle a bus + uint8 bIsBig: 1; // Is this vehicle a bus + uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims + uint8 m_veh_flagB10 : 1; + uint8 m_veh_flagB20 : 1; + uint8 m_veh_flagB40 : 1; + uint8 m_veh_flagB80 : 1; + + uint8 m_veh_flagC1 : 1; + uint8 m_veh_flagC2 : 1; + uint8 m_veh_flagC4 : 1; + uint8 m_veh_flagC8 : 1; + uint8 m_veh_flagC10 : 1; + uint8 m_veh_flagC20 : 1; + uint8 m_veh_flagC40 : 1; + uint8 m_veh_flagC80 : 1; + + uint8 m_veh_flagD1 : 1; + uint8 m_veh_flagD2 : 1; + uint8 m_veh_flagD4 : 1; + uint8 m_veh_flagD8 : 1; + uint8 bRecordedForReplay : 1; + uint8 m_veh_flagD20 : 1; + uint8 m_veh_flagD40 : 1; + uint8 m_veh_flagD80 : 1; + + int8 field_1F9; + uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) + int8 field_1FB; + int8 field_1FC[4]; + float m_fHealth; // 1000.0f = full health. 0 -> explode + uint8 m_nCurrentGear; + int8 field_205[3]; + int field_208; + uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) + uint32 m_nTimeOfDeath; + int16 field_214; + int16 m_nBombTimer; // goes down with each frame + CPed *m_pWhoDetonatedMe; + float field_21C; + float field_220; + eCarLock m_nDoorLock; + int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage + int8 m_nRadioStation; + int8 field_22A; + int8 field_22B; + uint8 m_nCarHornTimer; + int8 field_22D; + uint8 m_nSirenOrAlarm; + int8 field_22F; + // TODO: this is an array + CStoredCollPoly m_frontCollPoly; // poly which is under front part of car + CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car + float m_fSteerRatio; + eVehicleType m_vehType; + + static void *operator new(size_t); + static void *operator new(size_t sz, int slot); + static void operator delete(void*, size_t); + static void operator delete(void*, int); + + ~CVehicle(void); + // from CEntity + void SetModelIndex(uint32 i); + bool SetupLighting(void); + void RemoveLighting(bool); + void FlagToDestroyWhenNextProcessed(void) {} + + virtual void ProcessControlInputs(uint8) {} + virtual void GetComponentWorldPosition(int32 component, CVector &pos) {} + virtual bool IsComponentPresent(int32 component) { return false; } + virtual void SetComponentRotation(int32 component, CVector rotation) {} + virtual void OpenDoor(int32, eDoors door, float) {} + virtual void ProcessOpenDoor(uint32, uint32, float) {} + virtual bool IsDoorReady(eDoors door) { return false; } + virtual bool IsDoorFullyOpen(eDoors door) { return false; } + virtual bool IsDoorClosed(eDoors door) { return false; } + virtual bool IsDoorMissing(eDoors door) { return false; } + virtual void RemoveRefsToVehicle(CEntity *ent) {} + virtual void BlowUpCar(CEntity *ent) {} + virtual bool SetUpWheelColModel(CColModel *colModel) { return false; } + virtual void BurstTyre(uint8 tyre) {} + virtual bool IsRoomForPedToLeaveCar(uint32, CVector *) { return false;} + virtual float GetHeightAboveRoad(void); + virtual void PlayCarHorn(void) {} + + bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; } + bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; } + bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; } + bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; } + bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; } + bool IsLawEnforcementVehicle(void); + void ChangeLawEnforcerState(uint8 enable); + bool UsesSiren(uint32 id); + bool IsVehicleNormal(void); + bool CarHasRoof(void); + bool IsUpsideDown(void); + bool IsOnItsSide(void); + bool CanBeDeleted(void); + bool CanPedOpenLocks(CPed *ped); + bool CanPedEnterCar(void); + bool CanPedExitCar(void); + // do these two actually return something? + CPed *SetUpDriver(void); + CPed *SetupPassenger(int n); + void SetDriver(CPed *driver); + bool AddPassenger(CPed *passenger); + bool AddPassenger(CPed *passenger, uint8 n); + void RemovePassenger(CPed *passenger); + void RemoveDriver(void); + void ProcessCarAlarm(void); + bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius); + + static bool &bWheelsOnlyCheat; + static bool &bAllDodosCheat; + static bool &bCheat3; + static bool &bCheat4; + static bool &bCheat5; + static bool &m_bDisableMouseSteering; + + + void dtor(void) { CVehicle::~CVehicle(); } + void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); } + bool SetupLighting_(void) { return CVehicle::SetupLighting(); } + void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); } + float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); } +}; + +static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error"); +static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error"); +static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error"); +static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error"); -- cgit v1.2.3