summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFire-Head <Fire-Head@users.noreply.github.com>2019-08-02 22:23:05 +0200
committerFire-Head <Fire-Head@users.noreply.github.com>2019-08-02 22:23:05 +0200
commit73e2a4b035e19ace0ad5c55c58a15ee1d8265fee (patch)
treeeafd98b48c650c84139804ca89259ae61e00e3ea
parentfix (diff)
parentrestore original shadows fading (diff)
downloadre3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar.gz
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar.bz2
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar.lz
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar.xz
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.tar.zst
re3-73e2a4b035e19ace0ad5c55c58a15ee1d8265fee.zip
-rw-r--r--src/audio/AudioManager.cpp2
-rw-r--r--src/audio/DMAudio.h30
-rw-r--r--src/control/CarCtrl.cpp4
-rw-r--r--src/control/CarCtrl.h4
-rw-r--r--src/control/CarGen.cpp308
-rw-r--r--src/control/CarGen.h56
-rw-r--r--src/control/Garages.cpp5
-rw-r--r--src/control/Garages.h1
-rw-r--r--src/control/Phones.cpp10
-rw-r--r--src/control/Pickups.cpp1
-rw-r--r--src/control/Pickups.h1
-rw-r--r--src/control/Remote.cpp1
-rw-r--r--src/control/Remote.h1
-rw-r--r--src/control/Replay.cpp8
-rw-r--r--src/control/Script.cpp945
-rw-r--r--src/control/Script.h47
-rw-r--r--src/control/ScriptCommands.h2
-rw-r--r--src/core/Camera.cpp11
-rw-r--r--src/core/Camera.h2
-rw-r--r--src/core/Collision.cpp6
-rw-r--r--src/core/ControllerConfig.h2
-rw-r--r--src/core/Explosion.h12
-rw-r--r--src/core/Fire.cpp1
-rw-r--r--src/core/Fire.h3
-rw-r--r--src/core/PlayerInfo.cpp9
-rw-r--r--src/core/PlayerInfo.h11
-rw-r--r--src/core/User.cpp2
-rw-r--r--src/core/User.h2
-rw-r--r--src/core/Wanted.cpp13
-rw-r--r--src/core/World.cpp1
-rw-r--r--src/core/World.h1
-rw-r--r--src/core/config.h6
-rw-r--r--src/core/re3.cpp18
-rw-r--r--src/entities/Entity.cpp2
-rw-r--r--src/entities/Entity.h2
-rw-r--r--src/math/Matrix.h148
-rw-r--r--src/math/Vector.h6
-rw-r--r--src/math/Vector2D.h3
-rw-r--r--src/math/math.cpp139
-rw-r--r--src/modelinfo/VehicleModelInfo.cpp2
-rw-r--r--src/modelinfo/VehicleModelInfo.h3
-rw-r--r--src/objects/Object.cpp10
-rw-r--r--src/objects/Object.h2
-rw-r--r--src/objects/ParticleObject.cpp7
-rw-r--r--src/objects/ParticleObject.h7
-rw-r--r--src/peds/CivilianPed.cpp2
-rw-r--r--src/peds/Ped.cpp1511
-rw-r--r--src/peds/Ped.h141
-rw-r--r--src/peds/PedIK.cpp4
-rw-r--r--src/peds/PedIK.h2
-rw-r--r--src/render/Coronas.cpp2
-rw-r--r--src/render/Coronas.h2
-rw-r--r--src/render/Renderer.cpp4
-rw-r--r--src/render/Shadows.h1
-rw-r--r--src/render/Skidmarks.cpp1
-rw-r--r--src/render/Skidmarks.h1
-rw-r--r--src/render/SpecialFX.cpp1
-rw-r--r--src/render/SpecialFX.h9
-rw-r--r--src/render/WaterCannon.cpp1
-rw-r--r--src/render/WaterCannon.h1
-rw-r--r--src/skel/win/win.cpp71
-rw-r--r--src/vehicles/Automobile.cpp1704
-rw-r--r--src/vehicles/Automobile.h10
-rw-r--r--src/vehicles/Boat.cpp2
-rw-r--r--src/vehicles/DamageManager.h9
-rw-r--r--src/vehicles/Floater.cpp14
-rw-r--r--src/vehicles/Floater.h4
-rw-r--r--src/vehicles/Vehicle.cpp25
-rw-r--r--src/vehicles/Vehicle.h21
-rw-r--r--src/weapons/Weapon.cpp38
-rw-r--r--src/weapons/Weapon.h2
71 files changed, 4953 insertions, 487 deletions
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index ea54c9e6..ebf6a153 100644
--- a/src/audio/AudioManager.cpp
+++ b/src/audio/AudioManager.cpp
@@ -4037,7 +4037,7 @@ cAudioManager::ProcessEntity(int32 id)
case AUDIOTYPE_BRIDGE:
if(!m_bUserPause) {
m_sQueueSample.m_bReverbFlag = 1;
- cAudioManager::ProcessBridgeOneShots();
+ cAudioManager::ProcessBridge();
}
break;
case AUDIOTYPE_FRONTEND:
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index da20dc31..907755b9 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -20,9 +20,9 @@ enum eSound : int16
SOUND_F = 15,
SOUND_CAR_ENGINE_START = 16,
SOUND_CAR_LIGHT_BREAK = 17,
- SOUND_CAR_HYDRALIC_1 = 18,
- SOUND_CAR_HYDRALIC_2 = 19,
- SOUND_CAR_HYDRALIC_3 = 20,
+ SOUND_CAR_HYDRAULIC_1 = 18,
+ SOUND_CAR_HYDRAULIC_2 = 19,
+ SOUND_CAR_HYDRAULIC_3 = 20,
SOUND_CAR_JERK = 21,
SOUND_CAR_SPLASH = 22,
SOUND_17 = 23,
@@ -35,18 +35,18 @@ enum eSound : int16
SOUND_STEP_END = 30,
SOUND_FALL_LAND = 31,
SOUND_FALL_COLLAPSE = 32,
- SOUND_21 = 33,
- SOUND_22 = 34,
- SOUND_23 = 35,
- SOUND_24 = 36,
- SOUND_25 = 37,
- SOUND_26 = 38,
- SOUND_WEAPON_PUNCH_ATTACK = 39,
- SOUND_28 = 40,
- SOUND_29 = 41,
- SOUND_2A = 42,
- SOUND_2B = 43,
- SOUND_2C = 44,
+ SOUND_FIGHT_PUNCH_33 = 33,
+ SOUND_FIGHT_KICK_34 = 34,
+ SOUND_FIGHT_HEADBUTT_35 = 35,
+ SOUND_FIGHT_PUNCH_36 = 36,
+ SOUND_FIGHT_PUNCH_37 = 37,
+ SOUND_FIGHT_CLOSE_PUNCH_38 = 38,
+ SOUND_FIGHT_PUNCH_39 = 39,
+ SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 = 40,
+ SOUND_FIGHT_PUNCH_41 = 41,
+ SOUND_FIGHT_PUNCH_FROM_BEHIND_42 = 42,
+ SOUND_FIGHT_KNEE_OR_KICK_43 = 43,
+ SOUND_FIGHT_KICK_44 = 44,
SOUND_2D = 45,
SOUND_WEAPON_BAT_ATTACK = 46,
SOUND_WEAPON_SHOT_FIRED = 47,
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 5e436c84..12b444a2 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -7,6 +7,9 @@ int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0;
int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0;
bool &CCarCtrl::bCarsGeneratedAroundCamera = *(bool*)0x95CD8A;
float& CCarCtrl::CarDensityMultiplier = *(float*)0x5EC8B4;
+int32 &CCarCtrl::NumMissionCars = *(int32*)0x8F1B54;
+int32 &CCarCtrl::NumRandomCars = *(int32*)0x943118;
+int32 &CCarCtrl::NumParkedCars = *(int32*)0x8F29E0;
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); }
@@ -17,6 +20,7 @@ WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); }
WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); }
+WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
bool
CCarCtrl::MapCouldMoveInThisArea(float x, float y)
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index 677dcf36..2ad52d49 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -15,10 +15,14 @@ public:
static void UpdateCarOnRails(CVehicle*);
static bool MapCouldMoveInThisArea(float x, float y);
static void ScanForPedDanger(CVehicle *veh);
+ static void RemoveFromInterestingVehicleList(CVehicle*);
static int32 &NumLawEnforcerCars;
static int32 &NumAmbulancesOnDuty;
static int32 &NumFiretrucksOnDuty;
+ static int32 &NumRandomCars;
+ static int32 &NumMissionCars;
+ static int32 &NumParkedCars;
static bool &bCarsGeneratedAroundCamera;
static float &CarDensityMultiplier;
};
diff --git a/src/control/CarGen.cpp b/src/control/CarGen.cpp
new file mode 100644
index 00000000..65a23c8c
--- /dev/null
+++ b/src/control/CarGen.cpp
@@ -0,0 +1,308 @@
+#include "common.h"
+#include "patcher.h"
+#include "CarGen.h"
+
+#include "Automobile.h"
+#include "Boat.h"
+#include "Camera.h"
+#include "CarCtrl.h"
+#include "CutsceneMgr.h"
+#include "General.h"
+#include "Pools.h"
+#include "Streaming.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "World.h"
+
+uint8 &CTheCarGenerators::ProcessCounter = *(uint8*)0x95CDAF;
+uint32 &CTheCarGenerators::NumOfCarGenerators = *(uint32*)0x8E2C1C;
+CCarGenerator (&CTheCarGenerators::CarGeneratorArray)[NUM_CARGENS] = *(CCarGenerator(*)[NUM_CARGENS])*(uintptr*)0x87CB18;
+uint8 &CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = *(uint8*)0x95CDC6;
+uint32 &CTheCarGenerators::CurrentActiveCount = *(uint32*)0x8F2C5C;
+
+void CCarGenerator::SwitchOff()
+{
+ m_nUsesRemaining = 0;
+ --CTheCarGenerators::CurrentActiveCount;
+}
+
+void CCarGenerator::SwitchOn()
+{
+ m_nUsesRemaining = -1;
+ m_nTimer = CalcNextGen();
+ ++CTheCarGenerators::CurrentActiveCount;
+}
+
+uint32 CCarGenerator::CalcNextGen()
+{
+ return CTimer::GetTimeInMilliseconds() + 4;
+}
+
+void CCarGenerator::DoInternalProcessing()
+{
+ if (CheckForBlockage()) {
+ m_nTimer += 4;
+ if (m_nUsesRemaining == 0)
+ --CTheCarGenerators::CurrentActiveCount;
+ return;
+ }
+ if (CCarCtrl::NumParkedCars >= 10)
+ return;
+ CStreaming::RequestModel(m_nModelIndex, STREAMFLAGS_DEPENDENCY);
+ if (!CStreaming::HasModelLoaded(m_nModelIndex))
+ return;
+ if (CModelInfo::IsBoatModel(m_nModelIndex)){
+ CBoat* pBoat = new CBoat(m_nModelIndex, PARKED_VEHICLE);
+ pBoat->bIsStatic = false;
+ pBoat->bEngineOn = false;
+ CVector pos = m_vecPos;
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += pBoat->GetDistanceFromCentreOfMassToBaseOfModel();
+ pBoat->GetPosition() = pos;
+ pBoat->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
+ pBoat->m_status = STATUS_ABANDONED;
+ pBoat->m_nDoorLock = CARLOCK_UNLOCKED;
+ CWorld::Add(pBoat);
+ if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
+ pBoat->m_nAlarmState = -1;
+ if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
+ pBoat->m_nDoorLock = CARLOCK_LOCKED;
+ if (m_nColor1 != -1 && m_nColor2){
+ pBoat->m_currentColour1 = m_nColor1;
+ pBoat->m_currentColour2 = m_nColor2;
+ }
+ m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pBoat);
+ }else{
+ bool groundFound = false;
+ CVector pos = m_vecPos;
+ if (pos.z > -100.0f){
+ pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &groundFound);
+ }else{
+ CColPoint cp;
+ CEntity* pEntity;
+ groundFound = CWorld::ProcessVerticalLine(CVector(pos.x, pos.y, 1000.0f), -1000.0f,
+ cp, pEntity, true, false, false, false, false, false, nil);
+ if (groundFound)
+ pos.z = cp.point.z;
+ }
+ if (!groundFound) {
+ debug("CCarGenerator::DoInternalProcessing - can't find ground z for new car x = %f y = %f \n", m_vecPos.x, m_vecPos.y);
+ }else{
+ CAutomobile* pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE);
+ pCar->bIsStatic = false;
+ pCar->bEngineOn = false;
+ pos.z += pCar->GetDistanceFromCentreOfMassToBaseOfModel();
+ pCar->GetPosition() = pos;
+ pCar->SetOrientation(0.0f, 0.0f, DEGTORAD(m_fAngle));
+ pCar->m_status = STATUS_ABANDONED;
+ pCar->bLightsOn = false;
+ pCar->m_nDoorLock = CARLOCK_UNLOCKED;
+ CWorld::Add(pCar);
+ if (CGeneral::GetRandomNumberInRange(0, 100) < m_nAlarm)
+ pCar->m_nAlarmState = -1;
+ if (CGeneral::GetRandomNumberInRange(0, 100) < m_nDoorlock)
+ pCar->m_nDoorLock = CARLOCK_LOCKED;
+ if (m_nColor1 != -1 && m_nColor2) {
+ pCar->m_currentColour1 = m_nColor1;
+ pCar->m_currentColour2 = m_nColor2;
+ }
+ m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pCar);
+ }
+ }
+ if (m_nUsesRemaining < -1) /* I don't think this is a correct comparasion */
+ --m_nUsesRemaining;
+ m_nTimer = CalcNextGen();
+ if (m_nUsesRemaining == 0)
+ --CTheCarGenerators::CurrentActiveCount;
+}
+
+void CCarGenerator::Process()
+{
+ if (m_nVehicleHandle == -1 &&
+ (CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter || CTimer::GetTimeInMilliseconds() >= m_nTimer) &&
+ m_nUsesRemaining != 0 && CheckIfWithinRangeOfAnyPlayer())
+ DoInternalProcessing();
+ if (m_nVehicleHandle == -1)
+ return;
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(m_nVehicleHandle);
+ if (!pVehicle){
+ m_nVehicleHandle = -1;
+ return;
+ }
+ if (pVehicle->m_status != STATUS_PLAYER)
+ return;
+ m_nTimer += 60000;
+ m_nVehicleHandle = -1;
+ m_bIsBlocking = true;
+ pVehicle->bExtendedRange = false;
+}
+
+void CCarGenerator::Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
+{
+ CMatrix m1, m2, m3; /* Unused but present on stack, so I'll leave them. */
+ m_vecPos = CVector(x, y, z);
+ m_fAngle = angle;
+ m_nModelIndex = mi;
+ m_nColor1 = color1;
+ m_nColor2 = color2;
+ m_bForceSpawn = force;
+ m_nAlarm = alarm;
+ m_nDoorlock = lock;
+ m_nMinDelay = min_delay;
+ m_nMaxDelay = max_delay;
+ m_nVehicleHandle = -1;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 1;
+ m_nUsesRemaining = 0;
+ m_bIsBlocking = false;
+ m_vecInf = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.min;
+ m_vecSup = CModelInfo::GetModelInfo(m_nModelIndex)->GetColModel()->boundingBox.max;
+ m_fSize = max(m_vecInf.Magnitude(), m_vecSup.Magnitude());
+}
+
+bool CCarGenerator::CheckForBlockage()
+{
+ int16 entities;
+ CWorld::FindObjectsKindaColliding(CVector(m_vecPos), m_fSize, 1, &entities, 2, nil, false, true, true, false, false);
+ return entities > 0;
+}
+
+bool CCarGenerator::CheckIfWithinRangeOfAnyPlayer()
+{
+ CVector2D direction = FindPlayerCentreOfWorld(CWorld::PlayerInFocus) - m_vecPos;
+ float distance = direction.Magnitude();
+ float farclip = 120.0f * TheCamera.GenerationDistMultiplier;
+ float nearclip = farclip - 20.0f;
+ if (distance >= farclip){
+ if (m_bIsBlocking)
+ m_bIsBlocking = false;
+ return false;
+ }
+ if (CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter)
+ return true;
+ if (m_bIsBlocking)
+ return false;
+ if (distance < nearclip)
+ return false;
+ return DotProduct2D(direction, FindPlayerSpeed()) <= 0;
+}
+
+void CCarGenerator::Save(uint8* buffer)
+{
+ *(uint32*)(buffer) = m_nModelIndex;
+ *(CVector*)(buffer + 4) = m_vecPos;
+ *(float*)(buffer + 16) = m_fAngle;
+ *(int16*)(buffer + 20) = m_nColor1;
+ *(int16*)(buffer + 22) = m_nColor2;
+ *(bool*)(buffer + 24) = m_bForceSpawn;
+ *(uint8*)(buffer + 25) = m_nAlarm;
+ *(uint8*)(buffer + 26) = m_nDoorlock;
+ *(uint8*)(buffer + 27) = 0;
+ *(uint16*)(buffer + 28) = m_nMinDelay;
+ *(uint16*)(buffer + 30) = m_nMaxDelay;
+ *(uint32*)(buffer + 32) = m_nTimer;
+ *(int32*)(buffer + 36) = m_nVehicleHandle;
+ *(uint16*)(buffer + 40) = m_nUsesRemaining;
+ *(bool*)(buffer + 42) = m_bIsBlocking;
+ *(uint8*)(buffer + 43) = 0;
+ *(CVector*)(buffer + 44) = m_vecInf;
+ *(CVector*)(buffer + 56) = m_vecSup;
+ *(float*)(buffer + 68) = m_fSize;
+}
+
+void CCarGenerator::Load(uint8* buffer)
+{
+ m_nModelIndex = *(uint32*)(buffer);
+ m_vecPos = *(CVector*)(buffer + 4);
+ m_fAngle = *(float*)(buffer + 16);
+ m_nColor1 = *(int16*)(buffer + 20);
+ m_nColor2 = *(int16*)(buffer + 22);
+ m_bForceSpawn = *(bool*)(buffer + 24);
+ m_nAlarm = *(uint8*)(buffer + 25);
+ m_nDoorlock = *(uint8*)(buffer + 26);
+ m_nMinDelay = *(uint16*)(buffer + 28);
+ m_nMaxDelay = *(uint16*)(buffer + 30);
+ m_nTimer = *(uint32*)(buffer + 32);
+ m_nVehicleHandle = *(int32*)(buffer + 36);
+ m_nUsesRemaining = *(uint16*)(buffer + 40);
+ m_bIsBlocking = *(bool*)(buffer + 42);
+ m_vecInf = *(CVector*)(buffer + 44);
+ m_vecSup = *(CVector*)(buffer + 56);
+ m_fSize = *(float*)(buffer + 68);
+}
+
+void CTheCarGenerators::Process()
+{
+ if (FindPlayerTrain() || CCutsceneMgr::IsRunning())
+ return;
+ if (++CTheCarGenerators::ProcessCounter == 4)
+ CTheCarGenerators::ProcessCounter = 0;
+ for (uint32 i = ProcessCounter; i < NumOfCarGenerators; i += 4)
+ CTheCarGenerators::CarGeneratorArray[i].Process();
+ if (GenerateEvenIfPlayerIsCloseCounter)
+ GenerateEvenIfPlayerIsCloseCounter--;
+}
+
+int32 CTheCarGenerators::CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay)
+{
+ CarGeneratorArray[NumOfCarGenerators].Setup(x, y, z, angle, mi, color1, color2, force, alarm, lock, min_delay, max_delay);
+ return NumOfCarGenerators++;
+}
+
+void CTheCarGenerators::Init()
+{
+ GenerateEvenIfPlayerIsCloseCounter = 0;
+ NumOfCarGenerators = 0;
+ ProcessCounter = 0;
+ CurrentActiveCount = 0;
+}
+
+void CTheCarGenerators::SaveAllCarGenerators(uint8 *buffer, uint32 *size)
+{
+ *size = 28 + 72 * NUM_CARGENS;
+ buffer[0] = 'C';
+ buffer[1] = 'G';
+ buffer[2] = 'N';
+ buffer[3] = '\0';
+ *(uint32*)(buffer + 4) = *size - 8;
+ *(uint32*)(buffer + 8) = 12; /* what is this? */
+ *(uint32*)(buffer + 12) = NumOfCarGenerators;
+ *(uint32*)(buffer + 16) = CurrentActiveCount;
+ *(uint8*)(buffer + 20) = ProcessCounter;
+ *(uint8*)(buffer + 21) = GenerateEvenIfPlayerIsCloseCounter;
+ *(uint16*)(buffer + 22) = 0;
+ *(uint32*)(buffer + 24) = 72 * NUM_CARGENS;
+ buffer += 28;
+ for (int i = 0; i < NUM_CARGENS; i++){
+ CarGeneratorArray[i].Save(buffer);
+ buffer += 72;
+ }
+}
+
+void CTheCarGenerators::LoadAllCarGenerators(uint8* buffer, uint32 size)
+{
+ Init();
+ assert(size == 28 + NUM_CARGENS * 72);
+ assert(buffer[0] == 'C');
+ assert(buffer[1] == 'G');
+ assert(buffer[2] == 'N');
+ assert(buffer[3] == '\0');
+ assert(*(uint32*)(buffer + 4) == size - 8);
+ NumOfCarGenerators = *(uint32*)(buffer + 12);
+ CurrentActiveCount = *(uint32*)(buffer + 16);
+ ProcessCounter = *(uint8*)(buffer + 20);
+ GenerateEvenIfPlayerIsCloseCounter = *(uint8*)(buffer + 21);
+ assert(*(uint32*)(buffer + 24) == 72 * NUM_CARGENS);
+ buffer += 28;
+ for (int i = 0; i < NUM_CARGENS; i++) {
+ CarGeneratorArray[i].Load(buffer);
+ buffer += 72;
+ }
+}
+
+STARTPATCHES
+InjectHook(0x543020, CTheCarGenerators::Init, PATCH_JUMP);
+InjectHook(0x542F40, CTheCarGenerators::Process, PATCH_JUMP);
+InjectHook(0x543050, CTheCarGenerators::SaveAllCarGenerators, PATCH_JUMP);
+InjectHook(0x5431E0, CTheCarGenerators::LoadAllCarGenerators, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/CarGen.h b/src/control/CarGen.h
new file mode 100644
index 00000000..c1ca304c
--- /dev/null
+++ b/src/control/CarGen.h
@@ -0,0 +1,56 @@
+#pragma once
+#include "common.h"
+#include "config.h"
+
+enum {
+ CARGEN_MAXACTUALLIMIT = 100
+};
+
+class CCarGenerator
+{
+ int32 m_nModelIndex;
+ CVector m_vecPos;
+ float m_fAngle;
+ int16 m_nColor1;
+ int16 m_nColor2;
+ uint8 m_bForceSpawn;
+ uint8 m_nAlarm;
+ uint8 m_nDoorlock;
+ int16 m_nMinDelay;
+ int16 m_nMaxDelay;
+ uint32 m_nTimer;
+ int32 m_nVehicleHandle;
+ uint16 m_nUsesRemaining;
+ bool m_bIsBlocking;
+ CVector m_vecInf;
+ CVector m_vecSup;
+ float m_fSize;
+public:
+ void SwitchOff();
+ void SwitchOn();
+ uint32 CalcNextGen();
+ void DoInternalProcessing();
+ void Process();
+ void Setup(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
+ bool CheckForBlockage();
+ bool CheckIfWithinRangeOfAnyPlayer();
+ void Save(uint8*);
+ void Load(uint8*);
+ void SetUsesRemaining(uint16 uses) { m_nUsesRemaining = uses; }
+};
+
+class CTheCarGenerators
+{
+public:
+ static uint8 &ProcessCounter;
+ static uint32 &NumOfCarGenerators;
+ static CCarGenerator (&CarGeneratorArray)[NUM_CARGENS];
+ static uint8 &GenerateEvenIfPlayerIsCloseCounter;
+ static uint32 &CurrentActiveCount;
+
+ static void Process();
+ static int32 CreateCarGenerator(float x, float y, float z, float angle, int32 mi, int16 color1, int16 color2, uint8 force, uint8 alarm, uint8 lock, uint16 min_delay, uint16 max_delay);
+ static void Init();
+ static void SaveAllCarGenerators(uint8 *, uint32 *);
+ static void LoadAllCarGenerators(uint8 *, uint32);
+};
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index acc2b459..0629ac0c 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -63,6 +63,11 @@ CGarages::IsModelIndexADoor(uint32 id)
id == MI_CRUSHERLID;
}
+bool CGarages::HasCarBeenCrushed(int32 handle)
+{
+ return CrushedCarId == handle;
+}
+
WRAPPER void CGarages::TriggerMessage(char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); }
#if 0
diff --git a/src/control/Garages.h b/src/control/Garages.h
index 69f9d256..45a9345d 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -24,4 +24,5 @@ public:
static bool IsModelIndexADoor(uint32 id);
static void TriggerMessage(char *text, int16, uint16 time, int16);
static void PrintMessages(void);
+ static bool HasCarBeenCrushed(int32);
};
diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp
index 376e2757..e2a9ee13 100644
--- a/src/control/Phones.cpp
+++ b/src/control/Phones.cpp
@@ -76,6 +76,7 @@ CPhoneInfo::Load(CPhoneInfo *source, uint8 buffer)
m_aPhones[phoneId].m_vecPos = phone->m_vecPos;
memcpy(m_aPhones[phoneId].m_apMessages, phone->m_apMessages, sizeof(wchar*) * 6);
+ m_aPhones[phoneId].m_lastTimeRepeatedMsgShown = phone->m_lastTimeRepeatedMsgShown;
m_aPhones[phoneId].m_pEntity = phone->m_pEntity;
m_aPhones[phoneId].m_nState = phone->m_nState;
m_aPhones[phoneId].field_30 = phone->field_30;
@@ -183,13 +184,14 @@ CPhoneInfo::Save(CPhoneInfo *destination, uint32 *size)
phone->m_vecPos = m_aPhones[phoneId].m_vecPos;
memcpy(phone->m_apMessages, m_aPhones[phoneId].m_apMessages, sizeof(wchar*) * 6);
+ phone->m_lastTimeRepeatedMsgShown = m_aPhones[phoneId].m_lastTimeRepeatedMsgShown;
phone->m_pEntity = m_aPhones[phoneId].m_pEntity;
phone->m_nState = m_aPhones[phoneId].m_nState;
phone->field_30 = m_aPhones[phoneId].field_30;
// Convert entity pointer to building pool index while saving
if (phone->m_pEntity) {
- phone->m_pEntity = (CEntity*) CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1;
+ phone->m_pEntity = (CEntity*) (CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1);
}
}
}
@@ -210,7 +212,7 @@ PhonePutDownCB(CAnimBlendAssociation *assoc, void *arg)
CPed *ped = (CPed*)arg;
if (assoc->blendAmount > 0.5f)
- ped->m_ped_flagC10 = true;
+ ped->bUpdateAnimHeading = true;
if (ped->m_nPedState == PED_MAKE_CALL)
ped->m_nPedState = PED_IDLE;
@@ -244,10 +246,10 @@ PhonePickUpCB(CAnimBlendAssociation *assoc, void *arg)
CPed *ped = CPhoneInfo::pedWhoPickingUpPhone;
ped->m_nMoveState = PEDMOVE_STILL;
- CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f);
+ CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f);
if (assoc->blendAmount > 0.5f && ped)
- CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f);
+ CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f);
CPhoneInfo::pedWhoPickingUpPhone = nil;
}
diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp
index 56254d56..c93798fe 100644
--- a/src/control/Pickups.cpp
+++ b/src/control/Pickups.cpp
@@ -9,5 +9,6 @@ WRAPPER void CPickups::DoCollectableEffects(CEntity *ent) { EAXJMP(0x431C30); }
WRAPPER void CPickups::DoMoneyEffects(CEntity *ent) { EAXJMP(0x431F40); }
WRAPPER void CPickups::DoMineEffects(CEntity *ent) { EAXJMP(0x4321C0); }
WRAPPER void CPickups::DoPickUpEffects(CEntity *ent) { EAXJMP(0x431520); }
+WRAPPER void CPickups::RemoveAllFloatingPickups() { EAXJMP(0x430800); }
WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); }
diff --git a/src/control/Pickups.h b/src/control/Pickups.h
index 9cf485d0..b740e72e 100644
--- a/src/control/Pickups.h
+++ b/src/control/Pickups.h
@@ -41,6 +41,7 @@ public:
static void DoMoneyEffects(CEntity *ent);
static void DoMineEffects(CEntity *ent);
static void DoPickUpEffects(CEntity *ent);
+ static void RemoveAllFloatingPickups();
static CPickup (&aPickUps)[NUMPICKUPS];
};
diff --git a/src/control/Remote.cpp b/src/control/Remote.cpp
index 8d8d08f2..32ee4eda 100644
--- a/src/control/Remote.cpp
+++ b/src/control/Remote.cpp
@@ -2,4 +2,5 @@
#include "patcher.h"
#include "Remote.h"
+WRAPPER void CRemote::GivePlayerRemoteControlledCar(float, float, float, float, uint16) { EAXJMP(0x435C30); }
WRAPPER void CRemote::TakeRemoteControlledCarFromPlayer(void) { EAXJMP(0x435DA0); }
diff --git a/src/control/Remote.h b/src/control/Remote.h
index f8ef96bf..5e474586 100644
--- a/src/control/Remote.h
+++ b/src/control/Remote.h
@@ -3,5 +3,6 @@
class CRemote
{
public:
+ static void GivePlayerRemoteControlledCar(float, float, float, float, uint16);
static void TakeRemoteControlledCarFromPlayer(void);
};
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index d9453ad6..1e77da3a 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -240,15 +240,15 @@ void CReplay::Update(void)
if (CDraw::FadeValue || !bReplayEnabled)
return;
if (Mode == MODE_PLAYBACK){
- if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0])
+ if (CPad::GetPad(0)->GetFJustDown(0))
FinishPlayback();
}
else if (Mode == MODE_RECORD){
- if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0])
+ if (CPad::GetPad(0)->GetFJustDown(0))
TriggerPlayback(REPLAYCAMMODE_ASSTORED, 0.0f, 0.0f, 0.0f, false);
- if (CPad::NewKeyState.F[1] && !CPad::OldKeyState.F[1])
+ if (CPad::GetPad(0)->GetFJustDown(1))
SaveReplayToHD();
- if (CPad::NewKeyState.F[2] && !CPad::OldKeyState.F[2])
+ if (CPad::GetPad(0)->GetFJustDown(2))
PlayReplayFromHD();
}
}
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index bd43d301..b61a466b 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -7,22 +7,26 @@
#include "Boat.h"
#include "Camera.h"
#include "CarCtrl.h"
+#include "CarGen.h"
#include "CivilianPed.h"
#include "Clock.h"
#include "CopPed.h"
#include "DMAudio.h"
#include "EmergencyPed.h"
#include "FileMgr.h"
+#include "Garages.h"
#include "General.h"
#include "HandlingMgr.h"
#include "Hud.h"
#include "Messages.h"
#include "ModelIndices.h"
#include "Pad.h"
+#include "Pickups.h"
#include "PlayerInfo.h"
#include "PlayerPed.h"
#include "Pools.h"
#include "Population.h"
+#include "Remote.h"
#include "Replay.h"
#include "Streaming.h"
#include "Text.h"
@@ -170,6 +174,9 @@ void CMissionCleanup::Process()
default:
break;
}
+ m_sEntities[i].id = 0;
+ m_sEntities[i].type = CLEANUP_UNUSED;
+ m_nCount--;
}
}
@@ -426,8 +433,8 @@ void CRunningScript::Init()
m_anLocalVariables[i] = 0;
m_nAndOrState = 0;
m_bNotFlag = false;
- m_bWBCheckEnabled = true;
- m_bWBChecked = false;
+ m_bDeatharrestEnabled = true;
+ m_bDeatharrestExecuted = false;
m_bMissionFlag = false;
}
@@ -1113,6 +1120,13 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command)
UpdateCompareFlag(*ptr1 == *ptr2);
return 0;
}
+ /* Following commands are not implemented, and go to default case
+ case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_NUMBER:
+ case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_NUMBER:
+ case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_VAR:
+ case COMMAND_IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR:
+ case COMMAND_IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR:
+ */
case COMMAND_IS_FLOAT_VAR_EQUAL_TO_NUMBER:
{
int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL);
@@ -1148,6 +1162,13 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command)
UpdateCompareFlag(*(float*)ptr1 == *(float*)ptr2);
return 0;
}
+ /* Following commands are not implemented, and go to default case
+ case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER:
+ case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER:
+ case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR:
+ case COMMAND_IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR:
+ case COMMAND_IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR:
+ */
case COMMAND_GOTO_IF_TRUE:
CollectParameters(&m_nIp, 1);
if (m_bCondResult)
@@ -1311,7 +1332,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command)
UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2));
if (!ScriptParams[7])
return 0;
- CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2);
if (CTheScripts::DbgFlag)
CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
return 0;
@@ -1730,6 +1751,9 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
ped->SetWanderPath(path);
return 0;
}
+ /* Not implemented.
+ case COMMAND_CHAR_WANDER_RANGE:
+ */
case COMMAND_CHAR_FOLLOW_PATH:
{
CollectParameters(&m_nIp, 4);
@@ -1747,7 +1771,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
CollectParameters(&m_nIp, 1);
CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
assert(ped);
- ped->m_bScriptObjectiveCompleted = false;
+ ped->bScriptObjectiveCompleted = false;
ped->SetObjective(OBJECTIVE_IDLE);
return 0;
}
@@ -1826,7 +1850,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
{
CollectParameters(&m_nIp, 1);
CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
- UpdateCompareFlag(ped && ped->m_status != PED_DEAD && ped->m_status != PED_DIE);
+ UpdateCompareFlag(ped && ped->GetPedState() != PED_DEAD && ped->GetPedState() != PED_DIE);
return 0;
}
case COMMAND_IS_CHAR_IN_AREA_2D:
@@ -1848,6 +1872,8 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, x2, y2));
else
UpdateCompareFlag(ped->IsWithinArea(x1, y1, x2, y2));
+ if (!ScriptParams[5])
+ return 0;
CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
if (CTheScripts::DbgFlag)
CTheScripts::DrawDebugSquare(x1, y1, x2, y2);
@@ -1874,7 +1900,9 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2));
else
UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2));
- CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (!ScriptParams[7])
+ return 0;
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2);
if (CTheScripts::DbgFlag)
CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
return 0;
@@ -2043,7 +2071,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
}
case COMMAND_IS_CAR_STILL_ALIVE:
{
- CollectParameters(&m_nIp, 4);
+ CollectParameters(&m_nIp, 1);
CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
UpdateCompareFlag(car && car->m_status != STATUS_WRECKED && (car->IsBoat() || !car->bIsInWater));
return 0;
@@ -2085,6 +2113,8 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
x2 = *(float*)&ScriptParams[3];
y2 = *(float*)&ScriptParams[4];
UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, x2, y2));
+ if (!ScriptParams[5])
+ return 0;
CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
if (CTheScripts::DbgFlag)
CTheScripts::DrawDebugSquare(x1, y1, x2, y2);
@@ -2103,7 +2133,9 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
y2 = *(float*)&ScriptParams[5];
z2 = *(float*)&ScriptParams[6];
UpdateCompareFlag(vehicle->IsWithinArea(x1, y1, z1, x2, y2, z2));
- CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (!ScriptParams[7])
+ return 0;
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2);
if (CTheScripts::DbgFlag)
CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
return 0;
@@ -2187,6 +2219,583 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
case COMMAND_RETURN_FALSE:
UpdateCompareFlag(false);
return 0;
+ /* Special command only used by compiler.
+ case COMMAND_VAR_INT:
+ */
+ default:
+ assert(0);
+ break;
+ }
+ return -1;
+}
+
+int8 CRunningScript::ProcessCommandsFrom200To299(int32 command)
+{
+ switch (command) {
+ /* Special commands.
+ case COMMAND_VAR_FLOAT:
+ case COMMAND_LVAR_INT:
+ case COMMAND_LVAR_FLOAT:
+ case COMMAND_LBRACKET:
+ case COMMAND_RBRACKET:
+ case COMMAND_REPEAT:
+ case COMMAND_ENDREPEAT:
+ case COMMAND_IF:
+ case COMMAND_IFNOT:
+ case COMMAND_ELSE:
+ case COMMAND_ENDIF:
+ case COMMAND_WHILE:
+ case COMMAND_WHILENOT:
+ case COMMAND_ENDWHILE:
+ */
+ case COMMAND_ANDOR:
+ CollectParameters(&m_nIp, 1);
+ m_nAndOrState = ScriptParams[0];
+ if (m_nAndOrState == ANDOR_NONE){
+ m_bCondResult = false; // pointless
+ }else if (m_nAndOrState >= ANDS_1 && m_nAndOrState <= ANDS_8){
+ m_bCondResult = true;
+ m_nAndOrState++;
+ }else if (m_nAndOrState >= ORS_1 && m_nAndOrState <= ORS_8){
+ m_bCondResult = false;
+ m_nAndOrState++;
+ }else{
+ assert(0 && "COMMAND_ANDOR: invalid ANDOR state");
+ }
+ return 0;
+ case COMMAND_LAUNCH_MISSION:
+ {
+ CollectParameters(&m_nIp, 1);
+ CRunningScript* pNew = CTheScripts::StartNewScript(ScriptParams[0]);
+ pNew->m_bIsMissionScript = true;
+ return 0;
+ }
+ case COMMAND_MISSION_HAS_FINISHED:
+ {
+ if (!m_bIsMissionScript)
+ return 0;
+ if (strcmp(m_abScriptName, "love3") == 0) /* A Drop in the Ocean */
+ CPickups::RemoveAllFloatingPickups();
+ CTheScripts::MissionCleanup.Process();
+ return 0;
+ }
+ case COMMAND_STORE_CAR_CHAR_IS_IN:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(ped);
+ CVehicle* pCurrent = nil;
+ if (ped->bInVehicle) {
+ pCurrent = ped->m_pMyVehicle;
+ }
+ assert(pCurrent); // GetIndex(0) doesn't look good
+ int handle = CPools::GetVehiclePool()->GetIndex(pCurrent);
+ if (handle != CTheScripts::StoreVehicleIndex && m_bIsMissionScript){
+ CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex);
+ if (pOld){
+ CCarCtrl::RemoveFromInterestingVehicleList(pOld);
+ if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom){
+ pOld->VehicleCreatedBy = RANDOM_VEHICLE;
+ pOld->bIsLocked = false;
+ CCarCtrl::NumRandomCars++;
+ CCarCtrl::NumMissionCars--;
+ CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ }
+ }
+ CTheScripts::StoreVehicleIndex = handle;
+ switch (pCurrent->VehicleCreatedBy){
+ case RANDOM_VEHICLE:
+ pCurrent->VehicleCreatedBy = MISSION_VEHICLE;
+ CCarCtrl::NumMissionCars++;
+ CCarCtrl::NumRandomCars--;
+ CTheScripts::StoreVehicleWasRandom = true;
+ CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ break;
+ case PARKED_VEHICLE:
+ pCurrent->VehicleCreatedBy = MISSION_VEHICLE;
+ CCarCtrl::NumMissionCars++;
+ CCarCtrl::NumParkedCars--;
+ CTheScripts::StoreVehicleWasRandom = true;
+ CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ break;
+ case MISSION_VEHICLE:
+ case PERMANENT_VEHICLE:
+ CTheScripts::StoreVehicleWasRandom = false;
+ break;
+ default:
+ break;
+ }
+ }
+ ScriptParams[0] = CTheScripts::StoreVehicleIndex;
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ }
+ case COMMAND_STORE_CAR_PLAYER_IS_IN:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* ped = CWorld::Players[ScriptParams[0]].m_pPed;
+ assert(ped);
+ if (!ped->bInVehicle)
+ return 0; // No value written to output variable
+ CVehicle* pCurrent = ped->m_pMyVehicle;
+ assert(pCurrent); // Here pCurrent shouldn't be NULL anyway
+ int handle = CPools::GetVehiclePool()->GetIndex(pCurrent);
+ if (handle != CTheScripts::StoreVehicleIndex && m_bIsMissionScript) {
+ CVehicle* pOld = CPools::GetVehiclePool()->GetAt(CTheScripts::StoreVehicleIndex);
+ if (pOld) {
+ CCarCtrl::RemoveFromInterestingVehicleList(pOld);
+ if (pOld->VehicleCreatedBy == MISSION_VEHICLE && CTheScripts::StoreVehicleWasRandom) {
+ pOld->VehicleCreatedBy = RANDOM_VEHICLE;
+ pOld->bIsLocked = false;
+ CCarCtrl::NumRandomCars++;
+ CCarCtrl::NumMissionCars--;
+ CTheScripts::MissionCleanup.RemoveEntityFromList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ }
+ }
+ CTheScripts::StoreVehicleIndex = handle;
+ switch (pCurrent->VehicleCreatedBy) {
+ case RANDOM_VEHICLE:
+ pCurrent->VehicleCreatedBy = MISSION_VEHICLE;
+ CCarCtrl::NumMissionCars++;
+ CCarCtrl::NumRandomCars--;
+ CTheScripts::StoreVehicleWasRandom = true;
+ CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ break;
+ case PARKED_VEHICLE:
+ pCurrent->VehicleCreatedBy = MISSION_VEHICLE;
+ CCarCtrl::NumMissionCars++;
+ CCarCtrl::NumParkedCars--;
+ CTheScripts::StoreVehicleWasRandom = true;
+ CTheScripts::MissionCleanup.AddEntityToList(CTheScripts::StoreVehicleIndex, CLEANUP_CAR);
+ break;
+ case MISSION_VEHICLE:
+ case PERMANENT_VEHICLE:
+ CTheScripts::StoreVehicleWasRandom = false;
+ break;
+ default:
+ break;
+ }
+ }
+ ScriptParams[0] = CTheScripts::StoreVehicleIndex;
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ }
+ case COMMAND_IS_CHAR_IN_CAR:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ CVehicle* pCheckedVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]);
+ CVehicle* pActualVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil;
+ UpdateCompareFlag(pActualVehicle && pActualVehicle == pCheckedVehicle);
+ return 0;
+ }
+ case COMMAND_IS_PLAYER_IN_CAR:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* pCheckedVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]);
+ CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed;
+ UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle == pCheckedVehicle);
+ return 0;
+ }
+ case COMMAND_IS_CHAR_IN_MODEL:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ CVehicle* pActualVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil;
+ UpdateCompareFlag(pActualVehicle && pActualVehicle->GetModelIndex() == ScriptParams[1]);
+ return 0;
+ }
+ case COMMAND_IS_PLAYER_IN_MODEL:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed;
+ UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->GetModelIndex() == ScriptParams[1]);
+ return 0;
+ }
+ case COMMAND_IS_CHAR_IN_ANY_CAR:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ UpdateCompareFlag(pPed->bInVehicle);
+ return 0;
+ }
+ case COMMAND_IS_PLAYER_IN_ANY_CAR:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed;
+ UpdateCompareFlag(pPed->bInVehicle);
+ return 0;
+ }
+ case COMMAND_IS_BUTTON_PRESSED:
+ {
+ CollectParameters(&m_nIp, 2);
+ bool value = GetPadState(ScriptParams[0], ScriptParams[1]) != 0;
+ if (CGame::playingIntro && ScriptParams[0] == 0 && ScriptParams[1] == 12){ /* pad1, start */
+ if (CPad::GetPad(0)->GetLeftMouseJustDown() ||
+ CPad::GetPad(0)->GetPadEnterJustDown() ||
+ CPad::GetPad(0)->GetCharJustDown(' '))
+ value = true;
+ }
+ UpdateCompareFlag(value);
+ return 0;
+ }
+ case COMMAND_GET_PAD_STATE:
+ {
+ CollectParameters(&m_nIp, 1);
+ ScriptParams[0] = GetPadState(ScriptParams[0], ScriptParams[1]);
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ }
+ case COMMAND_LOCATE_PLAYER_ANY_MEANS_2D:
+ case COMMAND_LOCATE_PLAYER_ON_FOOT_2D:
+ case COMMAND_LOCATE_PLAYER_IN_CAR_2D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D:
+ LocatePlayerCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_2D:
+ case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_2D:
+ case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_2D:
+ LocatePlayerCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_CHAR_ANY_MEANS_2D:
+ case COMMAND_LOCATE_CHAR_ON_FOOT_2D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_2D:
+ case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D:
+ case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D:
+ case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D:
+ LocateCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_2D:
+ case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_2D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_2D:
+ LocateCharCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_PLAYER_ANY_MEANS_3D:
+ case COMMAND_LOCATE_PLAYER_ON_FOOT_3D:
+ case COMMAND_LOCATE_PLAYER_IN_CAR_3D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D:
+ case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D:
+ LocatePlayerCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D:
+ case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D:
+ case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D:
+ LocatePlayerCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_CHAR_ANY_MEANS_3D:
+ case COMMAND_LOCATE_CHAR_ON_FOOT_3D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_3D:
+ case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D:
+ case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D:
+ case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D:
+ LocateCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D:
+ case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D:
+ LocateCharCharCommand(command, &m_nIp);
+ return 0;
+ case COMMAND_CREATE_OBJECT:
+ {
+ CollectParameters(&m_nIp, 4);
+ int mi = ScriptParams[0] >= 0 ? ScriptParams[0] : CTheScripts::UsedObjectArray[-ScriptParams[0]].index;
+ CObject* pObj = new CObject(mi, 0);
+ pObj->ObjectCreatedBy = MISSION_OBJECT;
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ pos.z += pObj->GetDistanceFromCentreOfMassToBaseOfModel();
+ pObj->GetPosition() = pos;
+ pObj->SetOrientation(0.0f, 0.0f, 0.0f);
+ pObj->GetMatrix().UpdateRW();
+ pObj->UpdateRwFrame();
+ CTheScripts::ClearSpaceForMissionEntity(pos, pObj);
+ CWorld::Add(pObj);
+ ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj);
+ StoreParameters(&m_nIp, 1);
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT);
+ return 0;
+ }
+ case COMMAND_DELETE_OBJECT:
+ {
+ CollectParameters(&m_nIp, 1);
+ CObject* pObj = CPools::GetObjectPool()->GetAt(ScriptParams[0]);
+ if (pObj){
+ CWorld::Remove(pObj);
+ CWorld::RemoveReferencesToDeletedObject(pObj);
+ delete pObj;
+ }
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT);
+ return 0;
+ }
+ case COMMAND_ADD_SCORE:
+ CollectParameters(&m_nIp, 2);
+ CWorld::Players[ScriptParams[0]].m_nMoney += ScriptParams[1];
+ return 0;
+ case COMMAND_IS_SCORE_GREATER:
+ CollectParameters(&m_nIp, 2);
+ UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_nMoney > ScriptParams[1]);
+ return 0;
+ case COMMAND_STORE_SCORE:
+ CollectParameters(&m_nIp, 1);
+ ScriptParams[0] = CWorld::Players[ScriptParams[0]].m_nMoney;
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ case COMMAND_GIVE_REMOTE_CONTROLLED_CAR_TO_PLAYER:
+ {
+ CollectParameters(&m_nIp, 5);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ CRemote::GivePlayerRemoteControlledCar(pos.x, pos.y, pos.z, DEGTORAD(*(float*)&ScriptParams[4]), MI_RCBANDIT);
+ return 0;
+ }
+ case COMMAND_ALTER_WANTED_LEVEL:
+ CollectParameters(&m_nIp, 2);
+ CWorld::Players[ScriptParams[0]].m_pPed->SetWantedLevel(ScriptParams[1]);
+ return 0;
+ case COMMAND_ALTER_WANTED_LEVEL_NO_DROP:
+ CollectParameters(&m_nIp, 2);
+ CWorld::Players[ScriptParams[0]].m_pPed->SetWantedLevelNoDrop(ScriptParams[1]);
+ return 0;
+ case COMMAND_IS_WANTED_LEVEL_GREATER:
+ CollectParameters(&m_nIp, 2);
+ UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_pPed->m_pWanted->m_nWantedLevel > ScriptParams[1]);
+ return 0;
+ case COMMAND_CLEAR_WANTED_LEVEL:
+ CollectParameters(&m_nIp, 1);
+ CWorld::Players[ScriptParams[0]].m_pPed->SetWantedLevel(0);
+ return 0;
+ case COMMAND_SET_DEATHARREST_STATE:
+ CollectParameters(&m_nIp, 1);
+ m_bDeatharrestEnabled = (ScriptParams[0] == 1);
+ return 0;
+ case COMMAND_HAS_DEATHARREST_BEEN_EXECUTED:
+ UpdateCompareFlag(m_bDeatharrestExecuted);
+ return 0;
+ case COMMAND_ADD_AMMO_TO_PLAYER:
+ {
+ CollectParameters(&m_nIp, 3);
+ CWorld::Players[ScriptParams[0]].m_pPed->GrantAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]);
+ return 0;
+ }
+ case COMMAND_ADD_AMMO_TO_CHAR:
+ {
+ CollectParameters(&m_nIp, 3);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ pPed->GrantAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]);
+ return 0;
+ }
+ /* Not implemented
+ case COMMAND_ADD_AMMO_TO_CAR:
+ case COMMAND_IS_PLAYER_STILL_ALIVE:
+ */
+ case COMMAND_IS_PLAYER_DEAD:
+ CollectParameters(&m_nIp, 1);
+ UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_WASTED);
+ return 0;
+ case COMMAND_IS_CHAR_DEAD:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ UpdateCompareFlag(!pPed || pPed->GetPedState() == PED_DIE || pPed->GetPedState() == PED_DEAD);
+ return 0;
+ }
+ case COMMAND_IS_CAR_DEAD:
+ {
+ CollectParameters(&m_nIp, 1);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ UpdateCompareFlag(!pVehicle || pVehicle->m_status == STATUS_WRECKED || !pVehicle->IsBoat() && pVehicle->bIsInWater);
+ return 0;
+ }
+ case COMMAND_SET_CHAR_THREAT_SEARCH:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ pPed->m_fearFlags |= ScriptParams[1];
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_SET_CHAR_THREAT_REACTION:
+ */
+ case COMMAND_SET_CHAR_OBJ_NO_OBJ:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ pPed->bScriptObjectiveCompleted = false;
+ pPed->ClearObjective();
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_ORDER_DRIVER_OUT_OF_CAR:
+ case COMMAND_ORDER_CHAR_TO_DRIVE_CAR:
+ case COMMAND_ADD_PATROL_POINT:
+ case COMMAND_IS_PLAYER_IN_GANGZONE:
+ */
+ case COMMAND_IS_PLAYER_IN_ZONE:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]];
+ char label[12];
+ CTheScripts::ReadTextLabelFromScript(&m_nIp, label);
+ int zoneToCheck = CTheZones::FindZoneByLabelAndReturnIndex(label);
+ if (zoneToCheck != -1)
+ m_nIp += 8; /* why only if zone != 1? */
+ CVector pos = pPlayer->GetPos();
+ CZone* pZone = CTheZones::GetZone(zoneToCheck);
+ UpdateCompareFlag(CTheZones::PointLiesWithinZone(pos, pZone));
+ return 0;
+ }
+ case COMMAND_IS_PLAYER_PRESSING_HORN:
+ CollectParameters(&m_nIp, 1);
+ UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_pPed->GetPedState() == PED_DRIVING &&
+ CPad::GetPad(ScriptParams[0])->GetHorn());
+ /* Is it correct that same parameter is used both as index of Players */
+ /* and as ID of pad? Pratically this parameter is always 0 anyway of course. */
+ return 0;
+ case COMMAND_HAS_CHAR_SPOTTED_PLAYER:
+ {
+ CollectParameters(&m_nIp, 2);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ UpdateCompareFlag(pPed->OurPedCanSeeThisOne(CWorld::Players[ScriptParams[1]].m_pPed));
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_ORDER_CHAR_TO_BACKDOOR:
+ case COMMAND_ADD_CHAR_TO_GANG:
+ */
+ case COMMAND_IS_CHAR_OBJECTIVE_PASSED:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ UpdateCompareFlag(pPed->bScriptObjectiveCompleted);
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_SET_CHAR_DRIVE_AGGRESSION:
+ case COMMAND_SET_CHAR_MAX_DRIVESPEED:
+ */
+ case COMMAND_CREATE_CHAR_INSIDE_CAR:
+ {
+ CollectParameters(&m_nIp, 3);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(pVehicle);
+ switch (ScriptParams[2]) {
+ case MI_COP:
+ if (ScriptParams[1] == PEDTYPE_COP)
+ ScriptParams[2] = COP_STREET;
+ break;
+ case MI_SWAT:
+ if (ScriptParams[1] == PEDTYPE_COP)
+ ScriptParams[2] = COP_SWAT;
+ break;
+ case MI_FBI:
+ if (ScriptParams[1] == PEDTYPE_COP)
+ ScriptParams[2] = COP_FBI;
+ break;
+ case MI_ARMY:
+ if (ScriptParams[1] == PEDTYPE_COP)
+ ScriptParams[2] = COP_ARMY;
+ break;
+ case MI_MEDIC:
+ if (ScriptParams[1] == PEDTYPE_EMERGENCY)
+ ScriptParams[2] = PEDTYPE_EMERGENCY;
+ break;
+ case MI_FIREMAN:
+ if (ScriptParams[1] == PEDTYPE_FIREMAN)
+ ScriptParams[2] = PEDTYPE_FIREMAN;
+ break;
+ default:
+ break;
+ }
+ CPed* pPed;
+ if (ScriptParams[1] == PEDTYPE_COP)
+ pPed = new CCopPed((eCopType)ScriptParams[2]);
+ else if (ScriptParams[1] == PEDTYPE_EMERGENCY || ScriptParams[1] == PEDTYPE_FIREMAN)
+ pPed = new CEmergencyPed(ScriptParams[2]);
+ else
+ pPed = new CCivilianPed(ScriptParams[1], ScriptParams[2]);
+ pPed->CharCreatedBy = MISSION_CHAR;
+ pPed->bRespondsToThreats = false;
+ pPed->m_ped_flagG2 = false;
+ pPed->GetPosition() = pVehicle->GetPosition();
+ pPed->SetOrientation(0.0f, 0.0f, 0.0f);
+ pPed->SetPedState(PED_DRIVING);
+ CPopulation::ms_nTotalMissionPeds++;
+ assert(!pVehicle->pDriver);
+ pVehicle->pDriver = pPed;
+ pVehicle->pDriver->RegisterReference((CEntity**)&pVehicle->pDriver);
+ pPed->m_pMyVehicle = pVehicle;
+ pPed->m_pMyVehicle->RegisterReference((CEntity**)&pPed->m_pMyVehicle);
+ pPed->bInVehicle = true;
+ pVehicle->m_status = STATUS_PHYSICS;
+ if (!pVehicle->IsBoat())
+ pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
+ pVehicle->bEngineOn = true;
+ pPed->bUsesCollision = false;
+ AnimationId anim = pVehicle->bLowVehicle ? ANIM_CAR_LSIT : ANIM_CAR_SIT;
+ pPed->m_pVehicleAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, anim, 100.0f);
+ pPed->StopNonPartialAnims();
+ pPed->m_level = CTheZones::GetLevelFromPosition(pPed->GetPosition());
+ CWorld::Add(pPed);
+ ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed);
+ StoreParameters(&m_nIp, 1);
+ if (m_bIsMissionScript)
+ CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR);
+ return 0;
+ }
+ case COMMAND_WARP_PLAYER_FROM_CAR_TO_COORD:
+ {
+ CollectParameters(&m_nIp, 4);
+ CVector pos = *(CVector*)&ScriptParams[1];
+ CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]];
+ if (pos.z <= -100.0f)
+ pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y);
+ if (pPlayer->m_pPed->bInVehicle){
+ assert(pPlayer->m_pPed->m_pMyVehicle);
+ if (pPlayer->m_pPed->m_pMyVehicle->bIsBus)
+ pPlayer->m_pPed->bRenderPedInCar = true;
+ if (pPlayer->m_pPed->m_pMyVehicle->pDriver == pPlayer->m_pPed){
+ pPlayer->m_pPed->m_pMyVehicle->RemoveDriver();
+ pPlayer->m_pPed->m_pMyVehicle->m_status = STATUS_ABANDONED;
+ pPlayer->m_pPed->m_pMyVehicle->bEngineOn = false;
+ pPlayer->m_pPed->m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0;
+ }else{
+ pPlayer->m_pPed->m_pMyVehicle->RemovePassenger(pPlayer->m_pPed);
+ }
+ }
+ pPlayer->m_pPed->bInVehicle = false;
+ pPlayer->m_pPed->m_pMyVehicle = nil;
+ pPlayer->m_pPed->SetPedState(PED_IDLE);
+ pPlayer->m_pPed->bUsesCollision = true;
+ pPlayer->m_pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ pPlayer->m_pPed->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pPlayer->m_pPed->GetWeapon()->m_eWeaponType)->m_nModelId);
+ pPlayer->m_pPed->RemoveInCarAnims();
+ if (pPlayer->m_pPed->m_pVehicleAnim)
+ pPlayer->m_pPed->m_pVehicleAnim->blendDelta = -1000.0f;
+ pPlayer->m_pPed->m_pVehicleAnim = nil;
+ pPlayer->m_pPed->SetMoveState(PEDMOVE_NONE);
+ CAnimManager::BlendAnimation(pPlayer->m_pPed->GetClump(), pPlayer->m_pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ pPlayer->m_pPed->RestartNonPartialAnims();
+ AudioManager.PlayerJustLeftCar();
+ pos.z += pPlayer->m_pPed->GetDistanceFromCentreOfMassToBaseOfModel();
+ pPlayer->m_pPed->Teleport(pos);
+ CTheScripts::ClearSpaceForMissionEntity(pos, pPlayer->m_pPed);
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_MAKE_CHAR_DO_NOTHING:
+ */
default:
assert(0);
break;
@@ -2194,8 +2803,310 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
return -1;
}
-WRAPPER int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) { EAXJMP(0x43D530); }
+#if 1
WRAPPER int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) { EAXJMP(0x43ED30); }
+#else
+int8 CRunningScript::ProcessCommandsFrom300To399(int32 command)
+{
+ switch (command) {
+ /* Not implemented.
+ case COMMAND_SET_CHAR_INVINCIBLE:
+ case COMMAND_SET_PLAYER_INVINCIBLE:
+ case COMMAND_SET_CHAR_GRAPHIC_TYPE:
+ case COMMAND_SET_PLAYER_GRAPHIC_TYPE:
+ */
+ case COMMAND_HAS_PLAYER_BEEN_ARRESTED:
+ CollectParameters(&m_nIp, 1);
+ UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_BUSTED);
+ return 0;
+ /* Not implemented.
+ case COMMAND_STOP_CHAR_DRIVING:
+ case COMMAND_KILL_CHAR:
+ case COMMAND_SET_FAVOURITE_CAR_MODEL_FOR_CHAR:
+ case COMMAND_SET_CHAR_OCCUPATION:
+ */
+ case COMMAND_CHANGE_CAR_LOCK:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(pVehicle);
+ pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1];
+ return 0;
+ }
+ case COMMAND_SHAKE_CAM_WITH_POINT:
+ CollectParameters(&m_nIp, 4);
+ TheCamera.CamShake(ScriptParams[0] / 1000.0f,
+ *(float*)&ScriptParams[1],
+ *(float*)&ScriptParams[2],
+ *(float*)&ScriptParams[3]);
+ return 0;
+ case COMMAND_IS_CAR_MODEL:
+ {
+ CollectParameters(&m_nIp, 2);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(pVehicle);
+ UpdateCompareFlag(pVehicle->GetModelIndex() == ScriptParams[1]);
+ }
+ /* Not implemented.
+ case COMMAND_IS_CAR_REMAP:
+ case COMMAND_HAS_CAR_JUST_SUNK:
+ case COMMAND_SET_CAR_NO_COLLIDE:
+ */
+ case COMMAND_IS_CAR_DEAD_IN_AREA_2D:
+ {
+ CollectParameters(&m_nIp, 6);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(pVehicle);
+ float x1, y1, x2, y2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ x2 = *(float*)&ScriptParams[3];
+ y2 = *(float*)&ScriptParams[4];
+ UpdateCompareFlag(pVehicle->m_status == STATUS_WRECKED &&
+ pVehicle->IsWithinArea(x1, y1, x2, y2));
+ if (!ScriptParams[5])
+ return 0;
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugSquare(x1, y1, x2, y2);
+ return 0;
+ }
+ case COMMAND_IS_CAR_DEAD_IN_AREA_3D:
+ {
+ CollectParameters(&m_nIp, 8);
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
+ assert(pVehicle);
+ float x1, y1, z1, x2, y2, z2;
+ x1 = *(float*)&ScriptParams[1];
+ y1 = *(float*)&ScriptParams[2];
+ z1 = *(float*)&ScriptParams[3];
+ x2 = *(float*)&ScriptParams[4];
+ y2 = *(float*)&ScriptParams[5];
+ z2 = *(float*)&ScriptParams[6];
+ UpdateCompareFlag(pVehicle->m_status == STATUS_WRECKED &&
+ pVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2));
+ if (!ScriptParams[7])
+ return 0;
+ CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2);
+ if (CTheScripts::DbgFlag)
+ CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2);
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_IS_TRAILER_ATTACHED:
+ case COMMAND_IS_CAR_ON_TRAILER:
+ case COMMAND_HAS_CAR_GOT_WEAPON:
+ case COMMAND_PARK:
+ case COMMAND_HAS_PARK_FINISHED:
+ case COMMAND_KILL_ALL_PASSENGERS:
+ case COMMAND_SET_CAR_BULLETPROOF:
+ case COMMAND_SET_CAR_FLAMEPROOF:
+ case COMMAND_SET_CAR_ROCKETPROOF:
+ case COMMAND_IS_CARBOMB_ACTIVE:
+ case COMMAND_GIVE_CAR_ALARM:
+ case COMMAND_PUT_CAR_ON_TRAILER:
+ */
+ case COMMAND_IS_CAR_CRUSHED:
+ CollectParameters(&m_nIp, 1);
+ UpdateCompareFlag(CGarages::HasCarBeenCrushed(ScriptParams[0]));
+ return 0;
+ /* Not implemented.
+ case COMMAND_CREATE_GANG_CAR:
+ */
+ case COMMAND_CREATE_CAR_GENERATOR:
+ CollectParameters(&m_nIp, 12);
+ ScriptParams[0] = CTheCarGenerators::CreateCarGenerator(
+ *(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[3],
+ ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7],
+ ScriptParams[8], ScriptParams[9], ScriptParams[10], ScriptParams[11]);
+ StoreParameters(&m_nIp, 1);
+ return 0;
+ case COMMAND_SWITCH_CAR_GENERATOR:
+ {
+ CollectParameters(&m_nIp, 2);
+ CCarGenerator* pCarGen = &CTheCarGenerators::CarGeneratorArray[ScriptParams[0]];
+ if (ScriptParams[1] == 0){
+ pCarGen->SwitchOff();
+ }else if (ScriptParams[1] <= 100){
+ pCarGen->SwitchOn();
+ }else{
+ pCarGen->SwitchOn();
+ pCarGen->SetUsesRemaining(ScriptParams[1]);
+ }
+ return 0;
+ }
+ case COMMAND_ADD_PAGER_MESSAGE:
+ {
+ wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp);
+ CollectParameters(&m_nIp, 3);
+ CUserDisplay::Pager.AddMessage(text, ScriptParams[0], ScriptParams[1], ScriptParams[2]);
+ return 0;
+ }
+ case COMMAND_DISPLAY_ONSCREEN_TIMER:
+ {
+ assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR);
+ m_nIp++;
+ CUserDisplay::OnscnTimer.AddClock(CTheScripts::Read2BytesFromScript(&m_nIp), nil);
+ return 0;
+ }
+ case COMMAND_CLEAR_ONSCREEN_TIMER:
+ {
+ assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR);
+ m_nIp++;
+ CUserDisplay::OnscnTimer.ClearClock(CTheScripts::Read2BytesFromScript(&m_nIp));
+ return 0;
+ }
+ case COMMAND_DISPLAY_ONSCREEN_COUNTER:
+ {
+ assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR);
+ m_nIp++;
+ int32 counter = CTheScripts::Read2BytesFromScript(&m_nIp);
+ CollectParameters(&m_nIp, 1);
+ CUserDisplay::OnscnTimer.AddCounter(counter, ScriptParams[0], nil);
+ return 0;
+ }
+ case COMMAND_CLEAR_ONSCREEN_COUNTER:
+ {
+ assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR);
+ m_nIp++;
+ CUserDisplay::OnscnTimer.ClearCounter(CTheScripts::Read2BytesFromScript(&m_nIp));
+ return 0;
+ }
+ case COMMAND_SET_ZONE_CAR_INFO:
+ {
+ char label[12];
+ CTheScripts::ReadTextLabelFromScript(&m_nIp, label);
+ m_nIp += 8;
+ CollectParameters(&m_nIp, 16);
+ int zone = CTheZones::FindZoneByLabelAndReturnIndex(label);
+ if (zone < 0) {
+ debug("Couldn't find zone - %s\n", label);
+ return 0;
+ }
+ CTheZones::SetZoneCarInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3],
+ ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0,
+ ScriptParams[9], ScriptParams[10], ScriptParams[11], ScriptParams[12],
+ ScriptParams[13], ScriptParams[14], ScriptParams[15]);
+ return 0;
+ }
+ /* Not implemented.
+ case COMMAND_IS_CHAR_IN_GANG_ZONE:
+ */
+ case COMMAND_IS_CHAR_IN_ZONE:
+ {
+ CollectParameters(&m_nIp, 1);
+ CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]);
+ assert(pPed);
+ char label[12];
+ CTheScripts::ReadTextLabelFromScript(&m_nIp, label);
+ int zone = CTheZones::FindZoneByLabelAndReturnIndex(label);
+ if (zone != -1)
+ m_nIp += 8;
+ CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition();
+ UpdateCompareFlag(CTheZones::PointLiesWithinZone(pos, CTheZones::GetZone(zone)));
+ return 0;
+ }
+ case COMMAND_SET_CAR_DENSITY:
+ {
+ char label[12];
+ CTheScripts::ReadTextLabelFromScript(&m_nIp, label);
+ m_nIp += 8;
+
+ }
+ case COMMAND_SET_PED_DENSITY:
+ case COMMAND_POINT_CAMERA_AT_PLAYER:
+ case COMMAND_POINT_CAMERA_AT_CAR:
+ case COMMAND_POINT_CAMERA_AT_CHAR:
+ case COMMAND_RESTORE_CAMERA:
+ case COMMAND_SHAKE_PAD:
+ case COMMAND_SET_ZONE_PED_INFO:
+ case COMMAND_SET_TIME_SCALE:
+ case COMMAND_IS_CAR_IN_AIR:
+ case COMMAND_SET_FIXED_CAMERA_POSITION:
+ case COMMAND_POINT_CAMERA_AT_POINT:
+ case COMMAND_ADD_BLIP_FOR_CAR_OLD:
+ case COMMAND_ADD_BLIP_FOR_CHAR_OLD:
+ case COMMAND_ADD_BLIP_FOR_OBJECT_OLD:
+ case COMMAND_REMOVE_BLIP:
+ case COMMAND_CHANGE_BLIP_COLOUR:
+ case COMMAND_DIM_BLIP:
+ case COMMAND_ADD_BLIP_FOR_COORD_OLD:
+ case COMMAND_CHANGE_BLIP_SCALE:
+ case COMMAND_SET_FADING_COLOUR:
+ case COMMAND_DO_FADE:
+ case COMMAND_GET_FADING_STATUS:
+ case COMMAND_ADD_HOSPITAL_RESTART:
+ case COMMAND_ADD_POLICE_RESTART:
+ case COMMAND_OVERRIDE_NEXT_RESTART:
+ case COMMAND_DRAW_SHADOW:
+ case COMMAND_GET_PLAYER_HEADING:
+ case COMMAND_SET_PLAYER_HEADING:
+ case COMMAND_GET_CHAR_HEADING:
+ case COMMAND_SET_CHAR_HEADING:
+ case COMMAND_GET_CAR_HEADING:
+ case COMMAND_SET_CAR_HEADING:
+ case COMMAND_GET_OBJECT_HEADING:
+ case COMMAND_SET_OBJECT_HEADING:
+ case COMMAND_IS_PLAYER_TOUCHING_OBJECT:
+ case COMMAND_IS_CHAR_TOUCHING_OBJECT:
+ case COMMAND_SET_PLAYER_AMMO:
+ case COMMAND_SET_CHAR_AMMO:
+ case COMMAND_SET_CAR_AMMO:
+ case COMMAND_LOAD_CAMERA_SPLINE:
+ case COMMAND_MOVE_CAMERA_ALONG_SPLINE:
+ case COMMAND_GET_CAMERA_POSITION_ALONG_SPLINE:
+ case COMMAND_DECLARE_MISSION_FLAG:
+ case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT:
+ case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT:
+ case COMMAND_IS_PLAYER_HEALTH_GREATER:
+ case COMMAND_IS_CHAR_HEALTH_GREATER:
+ case COMMAND_IS_CAR_HEALTH_GREATER:
+ case COMMAND_ADD_BLIP_FOR_CAR:
+ case COMMAND_ADD_BLIP_FOR_CHAR:
+ case COMMAND_ADD_BLIP_FOR_OBJECT:
+ case COMMAND_ADD_BLIP_FOR_CONTACT_POINT:
+ case COMMAND_ADD_BLIP_FOR_COORD:
+ case COMMAND_CHANGE_BLIP_DISPLAY:
+ case COMMAND_ADD_ONE_OFF_SOUND:
+ case COMMAND_ADD_CONTINUOUS_SOUND:
+ case COMMAND_REMOVE_SOUND:
+ case COMMAND_IS_CAR_STUCK_ON_ROOF:
+ default:
+ assert(0);
+ }
+ return -1;
+}
+#endif
+
+int16 CRunningScript::GetPadState(uint16 pad, uint16 button)
+{
+ CPad* pPad = CPad::GetPad(pad);
+ switch (button){
+ case 0: return pPad->NewState.LeftStickX;
+ case 1: return pPad->NewState.LeftStickY;
+ case 2: return pPad->NewState.RightStickX;
+ case 3: return pPad->NewState.RightStickY;
+ case 4: return pPad->NewState.LeftShoulder1;
+ case 5: return pPad->NewState.LeftShoulder2;
+ case 6: return pPad->NewState.RightShoulder1;
+ case 7: return pPad->NewState.RightShoulder2;
+ case 8: return pPad->NewState.DPadUp;
+ case 9: return pPad->NewState.DPadDown;
+ case 10: return pPad->NewState.DPadLeft;
+ case 11: return pPad->NewState.DPadRight;
+ case 12: return pPad->NewState.Start;
+ case 13: return pPad->NewState.Select;
+ case 14: return pPad->NewState.Square;
+ case 15: return pPad->NewState.Triangle;
+ case 16: return pPad->NewState.Cross;
+ case 17: return pPad->NewState.Circle;
+ case 18: return pPad->NewState.LeftShock;
+ case 19: return pPad->NewState.RightShock;
+ default: break;
+ }
+ return 0;
+}
+
WRAPPER int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) { EAXJMP(0x440CB0); }
WRAPPER int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) { EAXJMP(0x4429C0); }
WRAPPER int8 CRunningScript::ProcessCommandsFrom600To699(int32 command) { EAXJMP(0x444B20); }
@@ -2205,6 +3116,20 @@ WRAPPER int8 CRunningScript::ProcessCommandsFrom900To999(int32 command) { EAXJMP
WRAPPER int8 CRunningScript::ProcessCommandsFrom1000To1099(int32 command) { EAXJMP(0x588490); }
WRAPPER int8 CRunningScript::ProcessCommandsFrom1100To1199(int32 command) { EAXJMP(0x589D00); }
+WRAPPER void CRunningScript::LocatePlayerCommand(int32, uint32*) { EAXJMP(0x44FE10); }
+WRAPPER void CRunningScript::LocatePlayerCharCommand(int32, uint32*) { EAXJMP(0x4501E0); }
+WRAPPER void CRunningScript::LocatePlayerCarCommand(int32, uint32*) { EAXJMP(0x450540); }
+WRAPPER void CRunningScript::LocateCharCommand(int32, uint32*) { EAXJMP(0x450870); }
+WRAPPER void CRunningScript::LocateCharCharCommand(int32, uint32*) { EAXJMP(0x450BF0); }
+WRAPPER void CRunningScript::LocateCharCarCommand(int32, uint32*) { EAXJMP(0x450F30); }
+WRAPPER void CRunningScript::LocateCharObjectCommand(int32, uint32*) { EAXJMP(0x451260); }
+WRAPPER void CRunningScript::LocateCarCommand(int32, uint32*) { EAXJMP(0x451590); }
+WRAPPER void CRunningScript::LocateSniperBulletCommand(int32, uint32*) { EAXJMP(0x4518A0); }
+WRAPPER void CRunningScript::LocatePlayerInAreaCheckCommand(int32, uint32*) { EAXJMP(0x451A60); }
+WRAPPER void CRunningScript::LocatePlayerInAngledAreaCheckCommand(int32, uint32*) { EAXJMP(0x451E50); }
+WRAPPER void CRunningScript::LocateCharInAreaCheckCommand(int32, uint32*) { EAXJMP(0x4523B0); }
+WRAPPER void CRunningScript::LocateCharInAngledAreaCheckCommand(int32, uint32*) { EAXJMP(0x452750); }
+
WRAPPER void CTheScripts::DrawScriptSpheres() { EAXJMP(0x44FAC0); }
WRAPPER void CRunningScript::DoDeatharrestCheck() { EAXJMP(0x452A30); }
WRAPPER void CTheScripts::DrawDebugSquare(float, float, float, float) { EAXJMP(0x452D00); }
@@ -2244,4 +3169,4 @@ InjectHook(0x439000, &CTheScripts::StartNewScript, PATCH_JUMP);
InjectHook(0x439040, &CTheScripts::Process, PATCH_JUMP);
InjectHook(0x439400, &CTheScripts::StartTestScript, PATCH_JUMP);
InjectHook(0x439410, &CTheScripts::IsPlayerOnAMission, PATCH_JUMP);
-ENDPATCHES \ No newline at end of file
+ENDPATCHES
diff --git a/src/control/Script.h b/src/control/Script.h
index 9e9d9ab6..47c70914 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -1,5 +1,6 @@
#pragma once
#include "common.h"
+#include "Text.h"
#include "Sprite2d.h"
class CEntity;
@@ -78,8 +79,8 @@ class CRunningScript
uint32 m_nWakeTime;
uint16 m_nAndOrState;
bool m_bNotFlag;
- bool m_bWBCheckEnabled;
- bool m_bWBChecked;
+ bool m_bDeatharrestEnabled;
+ bool m_bDeatharrestExecuted;
bool m_bMissionFlag;
public:
@@ -113,6 +114,40 @@ public:
int8 ProcessCommandsFrom1000To1099(int32);
int8 ProcessCommandsFrom1100To1199(int32);
void UpdateCompareFlag(bool);
+ int16 GetPadState(uint16, uint16);
+ void LocatePlayerCommand(int32, uint32*);
+ void LocatePlayerCharCommand(int32, uint32*);
+ void LocatePlayerCarCommand(int32, uint32*);
+ void LocateCharCommand(int32, uint32*);
+ void LocateCharCharCommand(int32, uint32*);
+ void LocateCharCarCommand(int32, uint32*);
+ void LocateCharObjectCommand(int32, uint32*);
+ void LocateCarCommand(int32, uint32*);
+ void LocateSniperBulletCommand(int32, uint32*);
+ void LocatePlayerInAreaCheckCommand(int32, uint32*);
+ void LocatePlayerInAngledAreaCheckCommand(int32, uint32*);
+ void LocateCharInAreaCheckCommand(int32, uint32*);
+ void LocateCharInAngledAreaCheckCommand(int32, uint32*);
+private:
+ enum {
+ ANDOR_NONE = 0,
+ ANDS_1 = 1,
+ ANDS_2,
+ ANDS_3,
+ ANDS_4,
+ ANDS_5,
+ ANDS_6,
+ ANDS_7,
+ ANDS_8,
+ ORS_1 = 21,
+ ORS_2,
+ ORS_3,
+ ORS_4,
+ ORS_5,
+ ORS_6,
+ ORS_7,
+ ORS_8
+ };
};
enum {
@@ -338,4 +373,12 @@ public:
static float ReadFloatFromScript(uint32* pIp){
return Read2BytesFromScript(pIp) / 16.0f;
}
+ static void ReadTextLabelFromScript(uint32* pIp, char* buf){
+ strncpy(buf, (const char*)&ScriptSpace[*pIp], 8);
+ }
+ static wchar* GetTextByKeyFromScript(uint32* pIp) {
+ wchar* text = TheText.Get((const char*)&ScriptSpace[*pIp]);
+ *pIp += 8;
+ return text;
+ }
};
diff --git a/src/control/ScriptCommands.h b/src/control/ScriptCommands.h
index 55ac4439..fcc0a23f 100644
--- a/src/control/ScriptCommands.h
+++ b/src/control/ScriptCommands.h
@@ -208,7 +208,7 @@ enum {
COMMAND_RBRACKET,
COMMAND_REPEAT,
COMMAND_ENDREPEAT,
- COMMAND_IF_,
+ COMMAND_IF,
COMMAND_IFNOT,
COMMAND_ELSE,
COMMAND_ENDIF,
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index a66d6ac9..b5ba76db 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -1304,6 +1304,17 @@ CCam::GetWeaponFirstPersonOn()
return false;
}
+float
+CCamera::Find3rdPersonQuickAimPitch(void)
+{
+ float clampedFrontZ = clamp(Cams[ActiveCam].Front.z, -1.0f, 1.0f);
+
+ // float rot = atan2(clampedFrontZ, sqrt(1.0f - sq(clampedFrontZ)));
+ float rot = Asin(clampedFrontZ);
+
+ return -(DEGTORAD(((0.5f - m_f3rdPersonCHairMultY) * 1.8f * 0.5f * Cams[ActiveCam].FOV)) + rot);
+}
+
STARTPATCHES
InjectHook(0x42C760, (bool (CCamera::*)(const CVector &center, float radius, const CMatrix *mat))&CCamera::IsSphereVisible, PATCH_JUMP);
InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP);
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 1a2aae79..3ce0d9a6 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -469,6 +469,8 @@ int m_iModeObbeCamIsInForCar;
void Restore(void);
void SetWidescreenOff(void);
+ float Find3rdPersonQuickAimPitch(void);
+
void dtor(void) { this->CCamera::~CCamera(); }
};
static_assert(offsetof(CCamera, m_WideScreenOn) == 0x70, "CCamera: error");
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 7982e77d..cc360f79 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -2023,11 +2023,11 @@ CColModel::operator=(const CColModel &other)
numVerts = 0;
for(i = 0; i < other.numTriangles; i++){
if(other.triangles[i].a > numVerts)
- other.triangles[i].a = numVerts;
+ numVerts = other.triangles[i].a;
if(other.triangles[i].b > numVerts)
- other.triangles[i].b = numVerts;
+ numVerts = other.triangles[i].b;
if(other.triangles[i].c > numVerts)
- other.triangles[i].c = numVerts;
+ numVerts = other.triangles[i].c;
}
numVerts++;
if(vertices)
diff --git a/src/core/ControllerConfig.h b/src/core/ControllerConfig.h
index 8a434245..b064a381 100644
--- a/src/core/ControllerConfig.h
+++ b/src/core/ControllerConfig.h
@@ -22,7 +22,7 @@ public:
int32 m_ContSetOrder;
};
- bool field_0;
+ bool firstCapture;
char _pad0[3];
DIJOYSTATE2 m_OldState;
DIJOYSTATE2 m_NewState;
diff --git a/src/core/Explosion.h b/src/core/Explosion.h
index 69508490..93d60ab3 100644
--- a/src/core/Explosion.h
+++ b/src/core/Explosion.h
@@ -4,8 +4,16 @@ class CEntity;
enum eExplosionType
{
- EXPLOSION_3 = 3,
- EXPLOSION_4
+ EXPLOSION_GRENADE,
+ EXPLOSION_MOLOTOV,
+ EXPLOSION_ROCKET,
+ EXPLOSION_CAR,
+ EXPLOSION_CAR_QUICK,
+ EXPLOSION_HELI,
+ EXPLOSION_MINE,
+ EXPLOSION_BARREL,
+ EXPLOSION_TANK_GRENADE,
+ EXPLOSION_HELI_BOMB
};
class CExplosion
diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp
index bc59de2f..a2894d43 100644
--- a/src/core/Fire.cpp
+++ b/src/core/Fire.cpp
@@ -7,3 +7,4 @@ CFireManager &gFireManager = *(CFireManager*)0x8F31D0;
WRAPPER void CFire::Extinguish(void) { EAXJMP(0x479D40); }
WRAPPER void CFireManager::StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32) { EAXJMP(0x479590); }
+WRAPPER CFire *CFireManager::FindFurthestFire_NeverMindFireMen(CVector coors, float, float) { EAXJMP(0x479430); }
diff --git a/src/core/Fire.h b/src/core/Fire.h
index 9c9e1dec..040e9a25 100644
--- a/src/core/Fire.h
+++ b/src/core/Fire.h
@@ -4,6 +4,7 @@ class CEntity;
class CFire
{
+public:
bool m_bIsOngoing;
bool m_bExists;
bool m_bPropogationFlag;
@@ -18,7 +19,6 @@ class CFire
int field_28;
float field_2C;
-public:
void Extinguish(void);
};
@@ -26,5 +26,6 @@ class CFireManager
{
public:
void StartFire(CEntity *entityOnFire, CEntity *culprit, float, uint32);
+ CFire *FindFurthestFire_NeverMindFireMen(CVector coors, float, float);
};
extern CFireManager &gFireManager;
diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp
index 81c7a199..d9a4c0b0 100644
--- a/src/core/PlayerInfo.cpp
+++ b/src/core/PlayerInfo.cpp
@@ -1,7 +1,9 @@
#include "common.h"
#include "patcher.h"
+#include "PlayerPed.h"
#include "PlayerInfo.h"
#include "Frontend.h"
+#include "Vehicle.h"
WRAPPER void CPlayerInfo::MakePlayerSafe(bool) { EAXJMP(0x4A1400); }
WRAPPER void CPlayerInfo::LoadPlayerSkin() { EAXJMP(0x4A1700); }
@@ -12,3 +14,10 @@ void CPlayerInfo::SetPlayerSkin(char *skin)
strncpy(m_aSkinName, skin, 32);
LoadPlayerSkin();
}
+
+CVector& CPlayerInfo::GetPos()
+{
+ if (m_pPed->bInVehicle && m_pPed->m_pMyVehicle)
+ return m_pPed->m_pMyVehicle->GetPosition();
+ return m_pPed->GetPosition();
+}
diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h
index d8128424..decfb24c 100644
--- a/src/core/PlayerInfo.h
+++ b/src/core/PlayerInfo.h
@@ -20,7 +20,7 @@ public:
CPlayerPed *m_pPed;
CVehicle *m_pRemoteVehicle;
CColModel m_ColModel;
- CVehicle *m_pVehicleEx;
+ CVehicle *m_pVehicleEx; // vehicle using the col model above
char m_aPlayerName[70];
int32 m_nMoney;
int32 m_nVisibleMoney;
@@ -45,10 +45,10 @@ public:
int8 field_225;
int8 field_226;
int8 field_227;
- int32 m_nTimeLostRemoteCar;
- int32 m_nTimeLastHealthLoss;
- int32 m_nTimeLastArmourLoss;
- int32 field_240;
+ uint32 m_nTimeLostRemoteCar;
+ uint32 m_nTimeLastHealthLoss;
+ uint32 m_nTimeLastArmourLoss;
+ uint32 m_nTimeTankShotGun;
int32 m_nUpsideDownCounter;
int32 field_248;
int16 m_nTrafficMultiplier;
@@ -70,6 +70,7 @@ public:
void LoadPlayerSkin();
void AwardMoneyForExplosion(CVehicle *vehicle);
void SetPlayerSkin(char* skin);
+ CVector& GetPos();
};
static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error");
diff --git a/src/core/User.cpp b/src/core/User.cpp
index c9cb97cc..f40a06db 100644
--- a/src/core/User.cpp
+++ b/src/core/User.cpp
@@ -13,6 +13,8 @@ COnscreenTimer& CUserDisplay::OnscnTimer = *(COnscreenTimer*)0x862238;
CPager& CUserDisplay::Pager = *(CPager*)0x8F2744;
CCurrentVehicle& CUserDisplay::CurrentVehicle = *(CCurrentVehicle*)0x8F5FE8;
+WRAPPER void CPager::AddMessage(wchar*, uint16, uint16, uint16) { EAXJMP(0x52B940); }
+
void COnscreenTimer::Init() {
m_bDisabled = false;
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
diff --git a/src/core/User.h b/src/core/User.h
index 8b744c7e..cac2a318 100644
--- a/src/core/User.h
+++ b/src/core/User.h
@@ -52,6 +52,8 @@ class CCurrentVehicle
class CPager
{
+public:
+ void AddMessage(wchar*, uint16, uint16, uint16);
};
class CUserDisplay
diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp
index 7b865311..26b115e3 100644
--- a/src/core/Wanted.cpp
+++ b/src/core/Wanted.cpp
@@ -40,19 +40,19 @@ CWanted::Initialise()
bool
CWanted::AreSwatRequired()
{
- return m_nWantedLevel >= 4;
+ return m_nWantedLevel == 4 || m_bSwatRequired;
}
bool
CWanted::AreFbiRequired()
{
- return m_nWantedLevel >= 5;
+ return m_nWantedLevel == 5 || m_bFbiRequired;
}
bool
CWanted::AreArmyRequired()
{
- return m_nWantedLevel >= 6;
+ return m_nWantedLevel == 6 || m_bArmyRequired;
}
int32
@@ -77,6 +77,8 @@ void
CWanted::SetWantedLevel(int32 level)
{
ClearQdCrimes();
+ if (level > MaximumWantedLevel)
+ level = MaximumWantedLevel;
switch (level) {
case 0:
m_nChaos = 0;
@@ -100,8 +102,6 @@ CWanted::SetWantedLevel(int32 level)
m_nChaos = 3220;
break;
default:
- if (level > MaximumWantedLevel)
- m_nChaos = MaximumWantedLevel;
break;
}
UpdateWantedLevel();
@@ -275,6 +275,9 @@ CWanted::UpdateWantedLevel()
{
int32 CurrWantedLevel = m_nWantedLevel;
+ if (m_nChaos > nMaximumWantedLevel)
+ m_nChaos = nMaximumWantedLevel;
+
if (m_nChaos >= 0 && m_nChaos < 40) {
m_nWantedLevel = 0;
m_MaximumLawEnforcerVehicles = 0;
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 829a64d4..0440a951 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -29,6 +29,7 @@ bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C;
bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); }
+WRAPPER void CWorld::FindObjectsKindaColliding(const CVector &, float, bool, int16*, int16, CEntity **, bool, bool, bool, bool, bool){ EAXJMP(0x4B2A30); }
void
CWorld::Add(CEntity *ent)
diff --git a/src/core/World.h b/src/core/World.h
index fd9d6fc3..e4f46589 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -103,6 +103,7 @@ public:
static float FindGroundZFor3DCoord(float x, float y, float z, bool *found);
static float FindRoofZFor3DCoord(float x, float y, float z, bool *found);
static void RemoveReferencesToDeletedObject(CEntity*);
+ static void FindObjectsKindaColliding(const CVector &, float, bool, int16*, int16, CEntity **, bool, bool, bool, bool, bool);
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); }
diff --git a/src/core/config.h b/src/core/config.h
index 38682e22..07c86c0d 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -64,6 +64,8 @@ enum Config {
NUMRADARBLIPS = 32,
NUMPICKUPS = 336,
NUMEVENTS = 64,
+
+ NUM_CARGENS = 160
};
// We'll use this once we're ready to become independent of the game
@@ -117,7 +119,7 @@ enum Config {
# define CHATTYSPLASH // print what the game is loading
#endif
-//#define FIX_BUGS // fix bugs in the game, TODO: use this more
+#define FIX_BUGS // fix bugs in the game, TODO: use this more
#define KANGAROO_CHEAT
#define ASPECT_RATIO_SCALE
-#define USE_DEBUG_SCRIPT_LOADER \ No newline at end of file
+#define USE_DEBUG_SCRIPT_LOADER
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index a0032bc6..35b3cfa4 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -150,6 +150,18 @@ FixCar(void)
((CAutomobile*)veh)->Fix();
}
+static int engineStatus;
+static void
+SetEngineStatus(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ if(!veh->IsCar())
+ return;
+ ((CAutomobile*)veh)->Damage.SetEngineStatus(engineStatus);
+}
+
static void
ToggleComedy(void)
{
@@ -295,9 +307,13 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); });
DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); });
DebugMenuAddCmd("Spawn", "Spawn Yakuza", [](){ SpawnCar(MI_YAKUZA); });
+ DebugMenuAddCmd("Spawn", "Spawn Yardie", [](){ SpawnCar(MI_YARDIE); });
DebugMenuAddCmd("Spawn", "Spawn Dodo", [](){ SpawnCar(MI_DODO); });
+ DebugMenuAddCmd("Spawn", "Spawn Rhino", [](){ SpawnCar(MI_RHINO); });
+ DebugMenuAddCmd("Spawn", "Spawn Firetruck", [](){ SpawnCar(MI_FIRETRUCK); });
-
+ DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
+ DebugMenuAddCmd("Debug", "Set Engine Status", SetEngineStatus);
DebugMenuAddCmd("Debug", "Fix Car", FixCar);
DebugMenuAddCmd("Debug", "Toggle Comedy Controls", ToggleComedy);
DebugMenuAddCmd("Debug", "Place Car on Road", PlaceOnRoad);
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index b795931f..04a93420 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -65,7 +65,7 @@ CEntity::CEntity(void)
m_flagD8 = false;
bIsSubway = false;
bDrawLast = false;
- m_flagD40 = false;
+ bNoBrightHeadLights = false;
m_flagD80 = false;
bDistanceFade = false;
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index cdc9a173..11d3e8cd 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -76,7 +76,7 @@ public:
uint32 m_flagD8 : 1; // used by cBuoyancy::ProcessBuoyancy
uint32 bIsSubway : 1; // set when subway, but maybe different meaning?
uint32 bDrawLast : 1;
- uint32 m_flagD40 : 1;
+ uint32 bNoBrightHeadLights : 1;
uint32 m_flagD80 : 1; // CObject visibility?
// flagsE
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index 05a6eb03..bfe85afa 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -125,6 +125,24 @@ public:
m_matrix.pos.y = 0.0f;
m_matrix.pos.z = 0.0f;
}
+ void Scale(float scale)
+ {
+ // GTA treats this as 4x4 floats
+ m_matrix.right.x *= scale;
+ m_matrix.right.y *= scale;
+ m_matrix.right.z *= scale;
+ m_matrix.up.x *= scale;
+ m_matrix.up.y *= scale;
+ m_matrix.up.z *= scale;
+ m_matrix.at.x *= scale;
+ m_matrix.at.y *= scale;
+ m_matrix.at.z *= scale;
+ m_matrix.pos.x *= scale;
+ m_matrix.pos.y *= scale;
+ m_matrix.pos.z *= scale;
+ m_matrix.flags = 0;
+ }
+
void SetRotateXOnly(float angle){
float c = Cos(angle);
@@ -192,40 +210,10 @@ public:
m_matrix.pos.y = 0.0f;
m_matrix.pos.z = 0.0f;
}
- void SetRotate(float xAngle, float yAngle, float zAngle) {
- float cX = Cos(xAngle);
- float sX = Sin(xAngle);
- float cY = Cos(yAngle);
- float sY = Sin(yAngle);
- float cZ = Cos(zAngle);
- float sZ = Sin(zAngle);
-
- m_matrix.right.x = cZ * cY - (sZ * sX) * sY;
- m_matrix.right.y = (cZ * sX) * sY + sZ * cY;
- m_matrix.right.z = -cX * sY;
+ void SetRotate(float xAngle, float yAngle, float zAngle);
+ void Rotate(float x, float y, float z);
- m_matrix.up.x = -sZ * cX;
- m_matrix.up.y = cZ * cX;
- m_matrix.up.z = sX;
-
- m_matrix.at.x = (sZ * sX) * cY + cZ * sY;
- m_matrix.at.y = sZ * sY - (cZ * sX) * cY;
- m_matrix.at.z = cX * cY;
-
- m_matrix.pos.x = 0.0f;
- m_matrix.pos.y = 0.0f;
- m_matrix.pos.z = 0.0f;
- }
- void Reorthogonalise(void){
- CVector &r = GetRight();
- CVector &f = GetForward();
- CVector &u = GetUp();
- u = CrossProduct(r, f);
- u.Normalise();
- r = CrossProduct(f, u);
- r.Normalise();
- f = CrossProduct(u, r);
- }
+ void Reorthogonalise(void);
void CopyOnlyMatrix(CMatrix *other){
m_matrix = other->m_matrix;
}
@@ -245,35 +233,13 @@ public:
}
};
-inline CMatrix&
-Invert(const CMatrix &src, CMatrix &dst)
-{
- // GTA handles this as a raw 4x4 orthonormal matrix
- // and trashes the RW flags, let's not do that
- // actual copy of librw code:
- RwMatrix *d = &dst.m_matrix;
- const RwMatrix *s = &src.m_matrix;
- d->right.x = s->right.x;
- d->right.y = s->up.x;
- d->right.z = s->at.x;
- d->up.x = s->right.y;
- d->up.y = s->up.y;
- d->up.z = s->at.y;
- d->at.x = s->right.z;
- d->at.y = s->up.z;
- d->at.z = s->at.z;
- d->pos.x = -(s->pos.x*s->right.x +
- s->pos.y*s->right.y +
- s->pos.z*s->right.z);
- d->pos.y = -(s->pos.x*s->up.x +
- s->pos.y*s->up.y +
- s->pos.z*s->up.z);
- d->pos.z = -(s->pos.x*s->at.x +
- s->pos.y*s->at.y +
- s->pos.z*s->at.z);
- d->flags = rwMATRIXTYPEORTHONORMAL;
- return dst;
-}
+
+CMatrix &Invert(const CMatrix &src, CMatrix &dst);
+CVector operator*(const CMatrix &mat, const CVector &vec);
+CMatrix operator*(const CMatrix &m1, const CMatrix &m2);
+CVector MultiplyInverse(const CMatrix &mat, const CVector &vec);
+CVector Multiply3x3(const CMatrix &mat, const CVector &vec);
+CVector Multiply3x3(const CVector &vec, const CMatrix &mat);
inline CMatrix
Invert(const CMatrix &matrix)
@@ -282,64 +248,6 @@ Invert(const CMatrix &matrix)
return Invert(matrix, inv);
}
-inline CVector
-operator*(const CMatrix &mat, const CVector &vec)
-{
- return CVector(
- mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x,
- mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y,
- mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z);
-}
-
-inline CMatrix
-operator*(const CMatrix &m1, const CMatrix &m2)
-{
- CMatrix out;
- RwMatrix *dst = &out.m_matrix;
- const RwMatrix *src1 = &m1.m_matrix;
- const RwMatrix *src2 = &m2.m_matrix;
- dst->right.x = src1->right.x*src2->right.x + src1->up.x*src2->right.y + src1->at.x*src2->right.z;
- dst->right.y = src1->right.y*src2->right.x + src1->up.y*src2->right.y + src1->at.y*src2->right.z;
- dst->right.z = src1->right.z*src2->right.x + src1->up.z*src2->right.y + src1->at.z*src2->right.z;
- dst->up.x = src1->right.x*src2->up.x + src1->up.x*src2->up.y + src1->at.x*src2->up.z;
- dst->up.y = src1->right.y*src2->up.x + src1->up.y*src2->up.y + src1->at.y*src2->up.z;
- dst->up.z = src1->right.z*src2->up.x + src1->up.z*src2->up.y + src1->at.z*src2->up.z;
- dst->at.x = src1->right.x*src2->at.x + src1->up.x*src2->at.y + src1->at.x*src2->at.z;
- dst->at.y = src1->right.y*src2->at.x + src1->up.y*src2->at.y + src1->at.y*src2->at.z;
- dst->at.z = src1->right.z*src2->at.x + src1->up.z*src2->at.y + src1->at.z*src2->at.z;
- dst->pos.x = src1->right.x*src2->pos.x + src1->up.x*src2->pos.y + src1->at.x*src2->pos.z + src1->pos.x;
- dst->pos.y = src1->right.y*src2->pos.x + src1->up.y*src2->pos.y + src1->at.y*src2->pos.z + src1->pos.y;
- dst->pos.z = src1->right.z*src2->pos.x + src1->up.z*src2->pos.y + src1->at.z*src2->pos.z + src1->pos.z;
- return out;
-}
-
-inline CVector
-MultiplyInverse(const CMatrix &mat, const CVector &vec)
-{
- CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z);
- return CVector(
- mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z,
- mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z,
- mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z);
-}
-
-inline CVector
-Multiply3x3(const CMatrix &mat, const CVector &vec)
-{
- return CVector(
- mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z,
- mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z,
- mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z);
-}
-
-inline CVector
-Multiply3x3(const CVector &vec, const CMatrix &mat)
-{
- return CVector(
- mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z,
- mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z,
- mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z);
-}
class CCompressedMatrixNotAligned
{
diff --git a/src/math/Vector.h b/src/math/Vector.h
index f794a57f..42087339 100644
--- a/src/math/Vector.h
+++ b/src/math/Vector.h
@@ -31,7 +31,7 @@ public:
void Normalise(void) {
float sq = MagnitudeSqr();
if(sq > 0.0f){
- float invsqrt = 1.0f/Sqrt(sq); // CMaths::RecipSqrt
+ float invsqrt = RecipSqrt(sq);
x *= invsqrt;
y *= invsqrt;
z *= invsqrt;
@@ -71,6 +71,10 @@ public:
return CVector(-x, -y, -z);
}
+ const bool operator==(CVector const &right) {
+ return x == right.x && y == right.y && z == right.z;
+ }
+
bool IsZero(void) { return x == 0.0f && y == 0.0f && z == 0.0f; }
};
diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h
index e6b04c14..c8835ec0 100644
--- a/src/math/Vector2D.h
+++ b/src/math/Vector2D.h
@@ -7,13 +7,14 @@ public:
CVector2D(void) {}
CVector2D(float x, float y) : x(x), y(y) {}
CVector2D(const CVector &v) : x(v.x), y(v.y) {}
+ float Heading(void) const { return Atan2(-x, y); }
float Magnitude(void) const { return Sqrt(x*x + y*y); }
float MagnitudeSqr(void) const { return x*x + y*y; }
void Normalise(void){
float sq = MagnitudeSqr();
if(sq > 0.0f){
- float invsqrt = 1.0f/Sqrt(sq);
+ float invsqrt = RecipSqrt(sq);
x *= invsqrt;
y *= invsqrt;
}else
diff --git a/src/math/math.cpp b/src/math/math.cpp
index c1199fcc..e8b7d933 100644
--- a/src/math/math.cpp
+++ b/src/math/math.cpp
@@ -5,6 +5,145 @@
// TODO: move more stuff into here
void
+CMatrix::SetRotate(float xAngle, float yAngle, float zAngle)
+{
+ float cX = Cos(xAngle);
+ float sX = Sin(xAngle);
+ float cY = Cos(yAngle);
+ float sY = Sin(yAngle);
+ float cZ = Cos(zAngle);
+ float sZ = Sin(zAngle);
+
+ m_matrix.right.x = cZ * cY - (sZ * sX) * sY;
+ m_matrix.right.y = (cZ * sX) * sY + sZ * cY;
+ m_matrix.right.z = -cX * sY;
+
+ m_matrix.up.x = -sZ * cX;
+ m_matrix.up.y = cZ * cX;
+ m_matrix.up.z = sX;
+
+ m_matrix.at.x = (sZ * sX) * cY + cZ * sY;
+ m_matrix.at.y = sZ * sY - (cZ * sX) * cY;
+ m_matrix.at.z = cX * cY;
+
+ m_matrix.pos.x = 0.0f;
+ m_matrix.pos.y = 0.0f;
+ m_matrix.pos.z = 0.0f;
+}
+
+void
+CMatrix::Rotate(float x, float y, float z)
+{
+ // TODO? do this directly without creating another matrix
+ CMatrix rot;
+ rot.SetRotate(x, y, z);
+ *this = rot * *this;
+}
+
+void
+CMatrix::Reorthogonalise(void)
+{
+ CVector &r = GetRight();
+ CVector &f = GetForward();
+ CVector &u = GetUp();
+ u = CrossProduct(r, f);
+ u.Normalise();
+ r = CrossProduct(f, u);
+ r.Normalise();
+ f = CrossProduct(u, r);
+}
+
+CMatrix&
+Invert(const CMatrix &src, CMatrix &dst)
+{
+ // GTA handles this as a raw 4x4 orthonormal matrix
+ // and trashes the RW flags, let's not do that
+ // actual copy of librw code:
+ RwMatrix *d = &dst.m_matrix;
+ const RwMatrix *s = &src.m_matrix;
+ d->right.x = s->right.x;
+ d->right.y = s->up.x;
+ d->right.z = s->at.x;
+ d->up.x = s->right.y;
+ d->up.y = s->up.y;
+ d->up.z = s->at.y;
+ d->at.x = s->right.z;
+ d->at.y = s->up.z;
+ d->at.z = s->at.z;
+ d->pos.x = -(s->pos.x*s->right.x +
+ s->pos.y*s->right.y +
+ s->pos.z*s->right.z);
+ d->pos.y = -(s->pos.x*s->up.x +
+ s->pos.y*s->up.y +
+ s->pos.z*s->up.z);
+ d->pos.z = -(s->pos.x*s->at.x +
+ s->pos.y*s->at.y +
+ s->pos.z*s->at.z);
+ d->flags = rwMATRIXTYPEORTHONORMAL;
+ return dst;
+}
+
+CVector
+operator*(const CMatrix &mat, const CVector &vec)
+{
+ return CVector(
+ mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x,
+ mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y,
+ mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z);
+}
+
+CMatrix
+operator*(const CMatrix &m1, const CMatrix &m2)
+{
+ CMatrix out;
+ RwMatrix *dst = &out.m_matrix;
+ const RwMatrix *src1 = &m1.m_matrix;
+ const RwMatrix *src2 = &m2.m_matrix;
+ dst->right.x = src1->right.x*src2->right.x + src1->up.x*src2->right.y + src1->at.x*src2->right.z;
+ dst->right.y = src1->right.y*src2->right.x + src1->up.y*src2->right.y + src1->at.y*src2->right.z;
+ dst->right.z = src1->right.z*src2->right.x + src1->up.z*src2->right.y + src1->at.z*src2->right.z;
+ dst->up.x = src1->right.x*src2->up.x + src1->up.x*src2->up.y + src1->at.x*src2->up.z;
+ dst->up.y = src1->right.y*src2->up.x + src1->up.y*src2->up.y + src1->at.y*src2->up.z;
+ dst->up.z = src1->right.z*src2->up.x + src1->up.z*src2->up.y + src1->at.z*src2->up.z;
+ dst->at.x = src1->right.x*src2->at.x + src1->up.x*src2->at.y + src1->at.x*src2->at.z;
+ dst->at.y = src1->right.y*src2->at.x + src1->up.y*src2->at.y + src1->at.y*src2->at.z;
+ dst->at.z = src1->right.z*src2->at.x + src1->up.z*src2->at.y + src1->at.z*src2->at.z;
+ dst->pos.x = src1->right.x*src2->pos.x + src1->up.x*src2->pos.y + src1->at.x*src2->pos.z + src1->pos.x;
+ dst->pos.y = src1->right.y*src2->pos.x + src1->up.y*src2->pos.y + src1->at.y*src2->pos.z + src1->pos.y;
+ dst->pos.z = src1->right.z*src2->pos.x + src1->up.z*src2->pos.y + src1->at.z*src2->pos.z + src1->pos.z;
+ return out;
+}
+
+CVector
+MultiplyInverse(const CMatrix &mat, const CVector &vec)
+{
+ CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z);
+ return CVector(
+ mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z,
+ mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z,
+ mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z);
+}
+
+CVector
+Multiply3x3(const CMatrix &mat, const CVector &vec)
+{
+ return CVector(
+ mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z,
+ mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z,
+ mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z);
+}
+
+CVector
+Multiply3x3(const CVector &vec, const CMatrix &mat)
+{
+ return CVector(
+ mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z,
+ mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z,
+ mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z);
+}
+
+
+void
CQuaternion::Slerp(const CQuaternion &q1, const CQuaternion &q2, float theta, float invSin, float t)
{
if(theta == 0.0f)
diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp
index 9b2924e9..33e7195b 100644
--- a/src/modelinfo/VehicleModelInfo.cpp
+++ b/src/modelinfo/VehicleModelInfo.cpp
@@ -79,7 +79,7 @@ RwObjectNameIdAssocation boatIds[] = {
{ "boat_moving_hi", 1, VEHICLE_FLAG_COLLAPSE },
{ "boat_rudder_hi", 3, VEHICLE_FLAG_COLLAPSE },
{ "windscreen", 2, VEHICLE_FLAG_WINDSCREEN | VEHICLE_FLAG_COLLAPSE },
- { "ped_frontseat", 0, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
+ { "ped_frontseat", BOAT_POS_FRONTSEAT, VEHICLE_FLAG_POS | CLUMP_FLAG_NO_HIERID },
{ nil, 0, 0 }
};
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
index 37f47489..b5399d44 100644
--- a/src/modelinfo/VehicleModelInfo.h
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -47,9 +47,6 @@ enum {
};
enum {
- VEHICLE_DUMMY_BOAT_RUDDER = 0,
- VEHICLE_DUMMY_FRONT_SEATS = 2,
- VEHICLE_DUMMY_REAR_SEATS = 3,
NUM_VEHICLE_POSITIONS = 10
};
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
index f3ba8087..bba4d7d9 100644
--- a/src/objects/Object.cpp
+++ b/src/objects/Object.cpp
@@ -8,6 +8,7 @@
WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); }
+WRAPPER void CObject::Init(void) { EAXJMP(0x4BAEC0); }
int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2;
int16 &CObject::nBodyCastHealth = *(int16*)0x5F7D4C; // 1000
@@ -41,6 +42,15 @@ CObject::CObject(void)
m_pCollidingEntity = nil;
}
+CObject::CObject(int32 mi, bool createRW)
+{
+ if (createRW)
+ SetModelIndex(mi);
+ else
+ SetModelIndexNoCreate(mi);
+ Init();
+}
+
CObject::~CObject(void)
{
CRadar::ClearBlipForEntity(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(this));
diff --git a/src/objects/Object.h b/src/objects/Object.h
index 0ce1a3aa..21348b52 100644
--- a/src/objects/Object.h
+++ b/src/objects/Object.h
@@ -66,6 +66,7 @@ public:
static void operator delete(void*, size_t);
CObject(void);
+ CObject(int32, bool);
~CObject(void);
void Render(void);
@@ -74,6 +75,7 @@ public:
void ObjectDamage(float amount);
void RefModelInfo(int32 modelId);
+ void Init(void);
static void DeleteAllTempObjectInArea(CVector, float);
};
diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp
index 25f223e1..f5cd4c94 100644
--- a/src/objects/ParticleObject.cpp
+++ b/src/objects/ParticleObject.cpp
@@ -2,9 +2,10 @@
#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); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, uint8 remove) { EAXJMP(0x4BC4D0); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, float size, uint8 remove) { EAXJMP(0x4BC520); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, uint8 remove) { EAXJMP(0x4BC570); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, uint32, const RwRGBA &col, uint8 remove) { EAXJMP(0x4BC5B0); }
// Converted from static void __cdecl CParticleObject::Initialise() 0x42C760
void CParticleObject::Initialise()
diff --git a/src/objects/ParticleObject.h b/src/objects/ParticleObject.h
index 6ec090e7..192d3703 100644
--- a/src/objects/ParticleObject.h
+++ b/src/objects/ParticleObject.h
@@ -29,9 +29,10 @@ enum eParticleObjectType
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 AddObject(uint16 type, const CVector &pos, uint8 remove);
+ static void AddObject(uint16 type, const CVector &pos, float size, uint8 remove);
+ static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, uint8 remove);
+ static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, uint32, const RwRGBA &col, uint8 remove);
static void Initialise();
static void UpdateAll();
};
diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp
index 3b1f9e1c..f28a1134 100644
--- a/src/peds/CivilianPed.cpp
+++ b/src/peds/CivilianPed.cpp
@@ -28,7 +28,7 @@ CCivilianPed::ProcessNearestFreePhone(int unused)
if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE)
return false;
- field_31C = 1;
+ bRunningToPhone = true;
SetMoveState(PEDMOVE_RUN);
SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f);
m_phoneId = phoneId;
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 0c4e33d6..f8b44301 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -5,7 +5,6 @@
#include "Particle.h"
#include "Stats.h"
#include "World.h"
-#include "DMAudio.h"
#include "RpAnimBlend.h"
#include "Ped.h"
#include "PlayerPed.h"
@@ -29,9 +28,10 @@
#include "Darkel.h"
#include "PathFind.h"
#include "ModelIndices.h"
+#include "FileMgr.h"
+#include "TempColModels.h"
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
-WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); }
WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
@@ -47,12 +47,22 @@ WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); }
WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); }
WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); }
WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); }
+WRAPPER void CPed::RemoveInCarAnims(void) { EAXJMP(0x4E4E20); }
+WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); }
+WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); }
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
+
CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14;
+// TODO: PedAudioData should be hardcoded into exe, and it isn't reversed yet.
+CPedAudioData (&CPed::PedAudioData)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4;
+
+uint16 &CPed::unknownFightThing = *(uint16*)0x95CC58;
+FightMove (&CPed::ms_fightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
+
uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98;
CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030;
@@ -279,17 +289,17 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_fHealth = 100.0f;
m_fArmour = 0.0f;
m_nPedType = pedType;
- field_520 = 0;
- m_talkTimer = 0;
- m_talkTypeLast = 167;
- m_talkType = 167;
+ m_lastSoundStart = 0;
+ m_soundStart = 0;
+ m_lastQueuedSound = SOUND_TOTAL_PED_SOUNDS;
+ m_queuedSound = SOUND_TOTAL_PED_SOUNDS;
m_objective = OBJECTIVE_NONE;
m_prevObjective = OBJECTIVE_NONE;
CharCreatedBy = RANDOM_CHAR;
m_leader = nil;
m_pedInObjective = nil;
m_carInObjective = nil;
- bInVehicle = 0;
+ bInVehicle = false;
m_pMyVehicle = nil;
m_pVehicleAnim = nil;
m_vecOffsetSeek.x = 0.0f;
@@ -323,7 +333,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
m_wepSkills = 0;
field_318 = 1.0f;
- field_31C = 0;
+ bRunningToPhone = false;
m_phoneId = -1;
m_lastAccident = 0;
m_fleeFrom = nil;
@@ -338,7 +348,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_nPedState = PED_IDLE;
m_nLastPedState = PED_NONE;
m_nMoveState = PEDMOVE_STILL;
- m_nStoredActionState = 0;
+ m_nStoredMoveState = PEDMOVE_NONE;
m_pFire = nil;
m_pPointGunAt = nil;
m_pLookTarget = nil;
@@ -383,7 +393,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bRespondsToThreats = true;
bRenderPedInCar = true;
bChangedSeat = false;
- m_ped_flagC10 = false;
+ bUpdateAnimHeading = false;
bBodyPartJustCameOff = false;
m_ped_flagC40 = false;
m_ped_flagC80 = false;
@@ -393,16 +403,16 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_ped_flagD4 = false;
m_ped_flagD8 = false;
bIsPedDieAnimPlaying = false;
- m_ped_flagD20 = false;
+ bIsFleeing = false;
m_ped_flagD40 = false;
- m_bScriptObjectiveCompleted = false;
+ bScriptObjectiveCompleted = false;
- m_ped_flagE1 = false;
+ bKindaStayInSamePlace = false;
m_ped_flagE2 = false;
bNotAllowedToDuck = false;
bCrouchWhenShooting = false;
bIsDucking = false;
- m_ped_flagE20 = false;
+ bGetUpAnimStarted = false;
bDoBloodyFootprints = false;
m_ped_flagE80 = false;
@@ -427,17 +437,17 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_ped_flagH1 = false;
m_ped_flagH2 = false;
m_ped_flagH4 = false;
- m_ped_flagH8 = false;
+ bClearObjective = 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;
+ bNoCriticalHits = false;
m_ped_flagI4 = false;
bHasAlreadyBeenRecorded = false;
- m_ped_flagI10 = false;
+ bIsFell = false;
#ifdef KANGAROO_CHEAT
m_ped_flagI80 = false;
#endif
@@ -449,7 +459,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
DMAudio.SetEntityStatus(m_audioEntityId, 1);
m_fearFlags = CPedType::GetThreats(m_nPedType);
m_threatEntity = nil;
- m_eventOrThread = CVector2D(0.0f, 0.0f);
+ m_eventOrThreat = CVector2D(0.0f, 0.0f);
m_pEventEntity = nil;
m_fAngleToEvent = 0.0f;
m_numNearPeds = 0;
@@ -461,8 +471,8 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_pPathNodesStates[i] = nil;
}
}
- m_maxWeaponTypeAllowed = 0;
- m_currentWeapon = 0;
+ m_maxWeaponTypeAllowed = WEAPONTYPE_UNARMED;
+ m_currentWeapon = WEAPONTYPE_UNARMED;
m_storedWeapon = WEAPONTYPE_UNIDENTIFIED;
for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++)
@@ -475,7 +485,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
weapon.m_nTimer = 0;
}
- m_lastHitState = 0;
+ m_lastFightMove = FIGHTMOVE_NULL;
GiveWeapon(WEAPONTYPE_UNARMED, 0);
m_wepAccuracy = 60;
m_lastWepDam = -1;
@@ -657,7 +667,7 @@ CPed::AddWeaponModel(int id)
atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance();
RwFrameDestroy(RpAtomicGetFrame(atm));
RpAtomicSetFrame(atm, GetNodeFrame(PED_HANDR));
- RpClumpAddAtomic((RpClump*)m_rwObject, atm);
+ RpClumpAddAtomic(GetClump(), atm);
m_wepModelID = id;
}
}
@@ -954,10 +964,10 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
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);
+ newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU);
} else {
attackAssoc->blendDelta = -1000.0f;
- newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROW);
+ newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROW);
}
newAnim->SetFinishCallback(FinishedAttackCB, ped);
@@ -1006,7 +1016,7 @@ CPed::Attack(void)
ourWeaponType = GetWeapon()->m_eWeaponType;
ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType);
ourWeaponFire = ourWeapon->m_eWeaponFire;
- weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_AnimToPlay);
+ weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay);
lastReloadWasInFuture = m_ped_flagA4;
reloadAnimAssoc = nil;
reloadAnim = NUM_ANIMS;
@@ -1019,7 +1029,7 @@ CPed::Attack(void)
reloadAnim = ANIM_AK_RELOAD;
if (reloadAnim != NUM_ANIMS)
- reloadAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, reloadAnim);
+ reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), reloadAnim);
if (bIsDucking)
return;
@@ -1036,12 +1046,12 @@ CPed::Attack(void)
lastReloadWasInFuture = true;
if (!weaponAnimAssoc) {
- weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_Anim2ToPlay);
+ weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay);
delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire;
// Long throw granade, molotov
if (!weaponAnimAssoc && ourWeapon->m_bThrow) {
- weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU);
+ weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU);
delayBetweenAnimAndFire = 0.2f;
}
@@ -1049,14 +1059,14 @@ CPed::Attack(void)
if (lastReloadWasInFuture) {
if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !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);
+ weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
}
else {
- weaponAnimAssoc = CAnimManager::BlendAnimation((RpClump*)m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
+ weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
}
weaponAnimAssoc->SetFinishCallback(CPed::FinishedAttackCB, this);
- weaponAnimAssoc->flags |= ASSOC_RUNNING;
+ weaponAnimAssoc->SetRun();
if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength)
weaponAnimAssoc->SetCurrentTime(0.0f);
@@ -1117,7 +1127,7 @@ CPed::Attack(void)
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);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f);
ClearLookFlag();
ClearAimFlag();
m_ped_flagA4 = false;
@@ -1129,7 +1139,7 @@ CPed::Attack(void)
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);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f);
}
weaponAnimAssoc->speed = 0.5f;
@@ -1184,13 +1194,13 @@ CPed::Attack(void)
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);
+ CAnimManager::BlendAnimation(GetClump(), 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);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
}
} else {
ClearAimFlag();
@@ -1276,9 +1286,9 @@ CPed::Duck(void)
void
CPed::ClearDuck(void)
{
- CAnimBlendAssociation* animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_DUCK_DOWN);
+ CAnimBlendAssociation* animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN);
if (!animAssoc) {
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_DUCK_LOW);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW);
if (!animAssoc) {
bIsDucking = false;
@@ -1292,9 +1302,9 @@ CPed::ClearDuck(void)
if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN)
return;
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT);
if (!animAssoc || animAssoc->blendDelta < 0.0f) {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
}
}
@@ -1310,9 +1320,9 @@ CPed::ClearPointGunAt(void)
if (m_nPedState == PED_AIM_GUN) {
RestorePreviousState();
weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_AnimToPlay);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay);
if (!animAssoc || animAssoc->blendDelta < 0.0f) {
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weaponInfo->m_Anim2ToPlay);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay);
}
if (animAssoc) {
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
@@ -1330,14 +1340,14 @@ CPed::BeingDraggedFromCar(void)
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);
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT);
if (!animAssoc) {
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_LSIT);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT);
if (!animAssoc) {
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITP);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP);
if (!animAssoc)
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITPLO);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO);
}
}
if (animAssoc)
@@ -1361,7 +1371,7 @@ CPed::BeingDraggedFromCar(void)
if (!dontRunAnim)
- m_pVehicleAnim = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, enterAnim);
+ m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, enterAnim);
m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this);
lineUpType = LINE_UP_TO_CAR_START;
@@ -1380,9 +1390,9 @@ CPed::RestartNonPartialAnims(void)
{
CAnimBlendAssociation *assoc;
- for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
+ for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
if (!assoc->IsPartial())
- assoc->flags |= ASSOC_RUNNING;
+ assoc->SetRun();
}
}
@@ -1394,7 +1404,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
CPed *ped = (CPed*)arg;
eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType;
- quickJackedAssoc = RpAnimBlendClumpGetAssociation((RpClump*) ped->m_rwObject, ANIM_CAR_QJACKED);
+ quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED);
if (ped->m_nPedState != PED_ARRESTED) {
ped->m_nLastPedState = PED_NONE;
if (dragAssoc)
@@ -1432,7 +1442,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
} else {
dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped);
if (ped->CanSetPedState())
- CAnimManager::BlendAnimation((RpClump*) ped->m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
+ CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
}
// Only uzi can be used on cars, so previous weapon was stored
@@ -1444,12 +1454,12 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
} else {
ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId);
}
- ped->m_nStoredActionState = 0;
+ ped->m_nStoredMoveState = PEDMOVE_NONE;
ped->m_ped_flagI4 = false;
}
-void
-CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult)
+CVector
+CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult)
{
CVehicleModelInfo *vehModel;
CVector vehDoorPos;
@@ -1457,7 +1467,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter
float seatOffset;
vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex);
- if (veh->bIsVan && (enterType == CAR_DOOR_LR || enterType == CAR_DOOR_RR)) {
+ if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) {
seatOffset = 0.0f;
vehDoorOffset = offsetToOpenVanDoor;
} else {
@@ -1469,63 +1479,63 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter
}
}
- switch (enterType) {
+ switch (component) {
case CAR_DOOR_RF:
if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ vehDoorPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
else
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+ vehDoorPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
vehDoorPos.x += seatOffset;
vehDoorOffset.x = -vehDoorOffset.x;
break;
case CAR_DOOR_RR:
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS];
+ vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT];
vehDoorPos.x += seatOffset;
vehDoorOffset.x = -vehDoorOffset.x;
break;
case CAR_DOOR_LF:
if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ vehDoorPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
else
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+ vehDoorPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
vehDoorPos.x = -(vehDoorPos.x + seatOffset);
break;
case CAR_DOOR_LR:
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS];
+ vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT];
vehDoorPos.x = -(vehDoorPos.x + seatOffset);
break;
default:
if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ vehDoorPos = vehModel->m_positions[BOAT_POS_FRONTSEAT];
else
- vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+ vehDoorPos = vehModel->m_positions[CAR_POS_FRONTSEAT];
vehDoorOffset = CVector(0.0f, 0.0f, 0.0f);
}
- *output = vehDoorPos - vehDoorOffset;
+ return vehDoorPos - vehDoorOffset;
}
// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it.
-void
-CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType)
+CVector
+CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component)
{
CVector localPos;
CVector vehDoorPos;
- GetLocalPositionToOpenCarDoor(&localPos, veh, enterType, 1.0f);
+ localPos = GetLocalPositionToOpenCarDoor(veh, component, 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)) {
+ if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) {
localVehDoorOffset = offsetToOpenVanDoor;
} else {
if (veh->bIsLow) {
@@ -1537,19 +1547,18 @@ CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType)
vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition();
*/
- *output = vehDoorPos;
+ return vehDoorPos;
}
-void
-CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset)
+CVector
+CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset)
{
CVector doorPos;
CMatrix vehMat(veh->GetMatrix());
- GetLocalPositionToOpenCarDoor(output, veh, enterType, offset);
- doorPos = Multiply3x3(vehMat, *output);
+ doorPos = Multiply3x3(vehMat, GetLocalPositionToOpenCarDoor(veh, component, offset));
- *output = veh->GetPosition() + doorPos;
+ return veh->GetPosition() + doorPos;
}
void
@@ -1565,19 +1574,19 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
return;
if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) {
- if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) {
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT)) {
SetPedPositionInCar();
return;
}
- if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_LSIT)) {
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT)) {
SetPedPositionInCar();
return;
}
- if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITP)) {
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP)) {
SetPedPositionInCar();
return;
}
- if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITPLO)) {
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO)) {
SetPedPositionInCar();
return;
}
@@ -1597,7 +1606,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
if (vehIsUpsideDown) {
m_fRotationDest = -PI + veh->GetForward().Heading();
} else if (veh->bIsBus) {
- m_fRotationDest = 0.5 * PI + veh->GetForward().Heading();
+ m_fRotationDest = 0.5f * PI + veh->GetForward().Heading();
} else {
m_fRotationDest = veh->GetForward().Heading();
}
@@ -1605,7 +1614,17 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
if (vehIsUpsideDown) {
m_fRotationDest = veh->GetForward().Heading();
} else if (veh->bIsBus) {
- m_fRotationDest = -0.5 * PI + veh->GetForward().Heading();
+ m_fRotationDest = -0.5f * PI + veh->GetForward().Heading();
+ } else {
+ m_fRotationDest = veh->GetForward().Heading();
+ }
+ } else {
+ // I don't know will this part ever run(maybe boats?), but the game also handles that. I don't know is it intentional.
+
+ if (vehIsUpsideDown) {
+ m_fRotationDest = veh->GetForward().Heading();
+ } else if (veh->bIsBus) {
+ m_fRotationDest = 0.5f * PI + veh->GetForward().Heading();
} else {
m_fRotationDest = veh->GetForward().Heading();
}
@@ -1670,7 +1689,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
if (phase == LINE_UP_TO_CAR_2) {
neededPos = GetPosition();
} else {
- GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult);
+ neededPos = GetPositionToOpenCarDoor(veh, m_vehEnterType, seatPosMult);
}
CVector autoZPos = neededPos;
@@ -1752,9 +1771,9 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
neededPos -= timeUntilStateChange * m_vecOffsetSeek;
}
- if (limitedAngle > PI + m_fRotationCur) {
+ if (PI + m_fRotationCur < limitedAngle) {
limitedAngle -= 2 * PI;
- } else if (limitedAngle < m_fRotationCur - PI) {
+ } else if (m_fRotationCur - PI > limitedAngle) {
limitedAngle += 2 * PI;
}
m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange);
@@ -1768,11 +1787,9 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
// 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);
+ vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f));
GetMatrix() = vehDoorMat;
}
@@ -1808,7 +1825,7 @@ particleProduceFootSplash(CPed *ped, CVector *pos, float size, int times)
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);
+ CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumber() & 1, 200);
}
}
@@ -1827,7 +1844,7 @@ CPed::PlayFootSteps(void)
if (!bIsStanding)
return;
- CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject);
+ CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump());
CAnimBlendAssociation *walkRunAssoc = nil;
float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f;
@@ -1971,7 +1988,7 @@ CPed::BuildPedLists(void)
static CPed *unsortedNearPeds[10];
uint16 nextNearPedSlot = 0;
- if ((CTimer::GetFrameCounter() + m_randomSeed) % 16) {
+ if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) % 16) {
for(int i = 0; i < 10; ) {
if (m_nearPeds[i]) {
@@ -2041,13 +2058,13 @@ void
CPed::SetModelIndex(uint32 mi)
{
CEntity::SetModelIndex(mi);
- RpAnimBlendClumpInit((RpClump*) m_rwObject);
- RpAnimBlendClumpFillFrameArray((RpClump*) m_rwObject, m_pFrames);
+ RpAnimBlendClumpInit(GetClump());
+ RpAnimBlendClumpFillFrameArray(GetClump(), 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);
+ CAnimManager::AddAnimation(GetClump(), 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;
@@ -2120,9 +2137,9 @@ CPed::WorkOutHeadingForMovingFirstPerson(float offset)
angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown);
} else {
if (leftRight < 0.0f)
- angle = 0.5 * PI;
+ angle = 0.5f * PI;
else if (leftRight > 0.0f)
- angle = -0.5 * PI;
+ angle = -0.5f * PI;
}
return CGeneral::LimitRadianAngle(offset + angle);
@@ -2175,9 +2192,9 @@ CPed::CalculateNewVelocity(void)
float pedSpeed = m_moved.Magnitude();
float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur);
- if (localWalkAngle < -0.5 * PI) {
+ if (localWalkAngle < -0.5f * PI) {
localWalkAngle += PI;
- } else if (localWalkAngle > 0.5 * PI) {
+ } else if (localWalkAngle > 0.5f * PI) {
localWalkAngle -= PI;
}
@@ -2187,8 +2204,8 @@ CPed::CalculateNewVelocity(void)
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);
+ CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
+ CAnimBlendAssociation* fightAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) {
LimbOrientation newUpperLegs;
@@ -2466,7 +2483,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
case OBJECTIVE_KILL_CHAR_ANY_MEANS:
case OBJECTIVE_MUG_CHAR:
m_pLastPathNode = nil;
- m_ped_flagD20 = false;
+ bIsFleeing = false;
m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
m_pedInObjective = (CPed*)entity;
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
@@ -2637,7 +2654,7 @@ CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType)
void
CPed::ClearChat(void)
{
- CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT);
if (animAssoc) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
@@ -2698,8 +2715,8 @@ CPed::QuitEnteringCar(void)
RestartNonPartialAnims();
- if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE))
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE))
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f);
if (veh) {
if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK)
@@ -2762,7 +2779,7 @@ CPed::ReactToAttack(CEntity *attacker)
field_4E8 = CTimer::GetTimeInMilliseconds();
return;
}
- } else if (bCrouchWhenShooting || m_ped_flagE1) {
+ } else if (bCrouchWhenShooting || bKindaStayInSamePlace) {
SetDuck(CGeneral::GetRandomNumberInRange(1000,3000));
return;
}
@@ -2852,22 +2869,22 @@ CPed::Chat(void)
}
if (bIsTalking) {
if (CGeneral::GetRandomNumber() < 512) {
- CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT);
if (chatAssoc) {
chatAssoc->blendDelta = -4.0f;
- chatAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ chatAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
bIsTalking = false;
} else
Say(SOUND_PED_CHAT);
- } else if (!RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject, ASSOC_FLAG100)) {
+ } else if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG100)) {
if (CGeneral::GetRandomNumber() < 20) {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
}
if (!bIsTalking) {
- CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f);
+ CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f);
float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f);
chatAssoc->SetCurrentTime(chatTime);
@@ -2896,7 +2913,7 @@ CPed::CheckAroundForPossibleCollisions(void)
CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false);
for (int i = 0; i < maxObject; i++) {
CEntity *object = objects[i];
- if (field_31C) {
+ if (bRunningToPhone) {
if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition()))
break;
}
@@ -3146,12 +3163,12 @@ CPed::ClearAttackByRemovingAnim(void)
return;
CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
- CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_AnimToPlay);
+ CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_AnimToPlay);
if (!weaponAssoc) {
- weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, weapon->m_Anim2ToPlay);
+ weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_Anim2ToPlay);
if (!weaponAssoc && weapon->m_bThrow)
- weaponAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU);
+ weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU);
if (!weaponAssoc) {
ClearAttack();
@@ -3169,7 +3186,7 @@ CPed::StopNonPartialAnims(void)
{
CAnimBlendAssociation* assoc;
- for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
+ for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
if (!assoc->IsPartial())
assoc->flags &= ~ASSOC_RUNNING;
}
@@ -3187,8 +3204,8 @@ CPed::SetStoredState(void)
m_nMoveState = PEDMOVE_WALK;
}
m_nLastPedState = m_nPedState;
- if (m_nMoveState >= m_nPrevActionState)
- m_nPrevActionState = m_nMoveState;
+ if (m_nMoveState >= m_nPrevMoveState)
+ m_nPrevMoveState = m_nMoveState;
}
void
@@ -3224,7 +3241,7 @@ CPed::SetDie(AnimationId animId, float delta, float speed)
if (animId == NUM_ANIMS) {
bIsPedDieAnimPlaying = false;
} else {
- CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, animId, delta);
+ CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, delta);
if (speed > 0.0f)
dieAssoc->speed = speed;
@@ -3241,7 +3258,7 @@ CPed::SetDie(AnimationId animId, float delta, float speed)
if (!bInVehicle)
StopNonPartialAnims();
- // ???
+ // BUG: This is not timer.
m_bloodyFootprintCount = CTimer::GetTimeInMilliseconds();
}
@@ -3282,7 +3299,7 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
bool detectDieAnim = true;
if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) {
if (!IsPedHeadAbovePos(-0.3f)) {
- if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
+ if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG800))
dieAnim = ANIM_FLOOR_HIT_F;
else
dieAnim = ANIM_FLOOR_HIT;
@@ -3304,7 +3321,7 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
if (IsPedHeadAbovePos(-0.3f)) {
dieAnim = NUM_ANIMS;
} else {
- if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
+ if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG800))
dieAnim = ANIM_FLOOR_HIT_F;
else
dieAnim = ANIM_FLOOR_HIT;
@@ -3338,7 +3355,7 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
if (IsPedHeadAbovePos(-0.3f)) {
dieAnim = NUM_ANIMS;
} else {
- if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, 0x800u))
+ if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG800))
dieAnim = ANIM_FLOOR_HIT_F;
else
dieAnim = ANIM_FLOOR_HIT;
@@ -3374,7 +3391,7 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
return false;
bool dontRemoveLimb;
- if (IsPlayer() || m_ped_flagI2)
+ if (IsPlayer() || bNoCriticalHits)
dontRemoveLimb = true;
else {
switch (method)
@@ -3386,10 +3403,10 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
dontRemoveLimb = false;
break;
case WEAPONTYPE_SHOTGUN:
- dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,7);
+ dontRemoveLimb = CGeneral::GetRandomNumber() & 7;
break;
default:
- dontRemoveLimb = CGeneral::GetRandomNumberInRange(0,15);
+ dontRemoveLimb = CGeneral::GetRandomNumber() & 15;
break;
}
}
@@ -3513,7 +3530,7 @@ CPed::InflictDamage(CEntity* damagedBy, eWeaponType method, float damage, ePedPi
if (bCollisionProof)
return false;
- random = CGeneral::GetRandomNumberInRange(0, 3);
+ random = CGeneral::GetRandomNumber() & 3;
switch (random) {
case 0:
if ((pedPiece != PEDPIECE_LEFTARM || random <= 1)
@@ -3654,7 +3671,7 @@ void
CPed::ClearFlee(void)
{
RestorePreviousState();
- m_ped_flagD20 = false;
+ bIsFleeing = false;
m_standardTimer = 0;
m_fleeTimer = 0;
}
@@ -3668,17 +3685,17 @@ CPed::ClearFall(void)
void
CPed::SetGetUp(void)
{
- if (m_nPedState == PED_GETUP && m_ped_flagE20)
+ if (m_nPedState == PED_GETUP && bGetUpAnimStarted)
return;
if (!CanSetPedState())
return;
if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) {
- if (m_ped_flagC10) {
+ if (bUpdateAnimHeading) {
m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
- m_fRotationCur -= 0.5*PI;
- m_ped_flagC10 = false;
+ m_fRotationCur -= 0.5f*PI;
+ bUpdateAnimHeading = false;
}
if (m_nPedState != PED_GETUP) {
SetStoredState();
@@ -3694,7 +3711,7 @@ CPed::SetGetUp(void)
collidingVeh->GetMatrix(), *CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(),
&ms_tempColPoint, nil, nil) > 0)) {
- m_ped_flagE20 = false;
+ bGetUpAnimStarted = false;
if (IsPlayer())
InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
else {
@@ -3705,23 +3722,23 @@ CPed::SetGetUp(void)
}
return;
}
- m_ped_flagE20 = true;
+ bGetUpAnimStarted = true;
m_pCollidingEntity = nil;
m_ped_flagH1 = false;
- CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_SPRINT);
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
if (animAssoc) {
- if (RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RUN)) {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_RUN, 8.0f);
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN)) {
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_RUN, 8.0f);
} else {
- CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
}
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
- if (RpAnimBlendClumpGetFirstAssociation((RpClump*) m_rwObject, ASSOC_FLAG800))
- animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f);
+ if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG800))
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f);
else
- animAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
animAssoc->SetFinishCallback(PedGetupCB,this);
} else {
@@ -3733,13 +3750,13 @@ CPed::SetGetUp(void)
void
CPed::ClearInvestigateEvent(void)
{
- CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_ROAD_CROSS);
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
if (!animAssoc)
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_XPRESS_SCRATCH);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
if (!animAssoc)
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_HBHB);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
if (!animAssoc)
- animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT);
if (animAssoc) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
@@ -3770,7 +3787,7 @@ CPed::ClearLeader(void)
SetWanderPath(CGeneral::GetRandomNumberInRange(0,8));
}
} else if (m_objective != OBJECTIVE_NONE) {
- m_ped_flagH8 = true;
+ bClearObjective = true;
}
}
@@ -3799,7 +3816,7 @@ CPed::ClearObjective(void)
SetMoveState(PEDMOVE_STILL);
}
} else {
- m_ped_flagH8 = true;
+ bClearObjective = true;
}
}
@@ -3813,7 +3830,7 @@ void
CPed::ClearSeek(void)
{
SetIdle();
- field_31C = 0;
+ bRunningToPhone = false;
}
bool
@@ -3822,7 +3839,7 @@ CPed::SetWanderPath(int8 pathStateDest)
uint8 nextPathState;
if (IsPedInControl()) {
- if (m_ped_flagE1) {
+ if (bKindaStayInSamePlace) {
SetIdle();
return false;
} else {
@@ -3918,7 +3935,7 @@ CPed::RestorePreviousState(void)
if(!CanSetPedState() || m_nPedState == PED_FALL)
return;
- if (m_nPedState == PED_GETUP && !m_ped_flagE20)
+ if (m_nPedState == PED_GETUP && !bGetUpAnimStarted)
return;
if (bInVehicle && m_pMyVehicle) {
@@ -3927,7 +3944,7 @@ CPed::RestorePreviousState(void)
} else {
if (m_nLastPedState == PED_NONE) {
if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) {
- if (SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)) != 0)
+ if (SetWanderPath(CGeneral::GetRandomNumber() & 7) != 0)
return;
}
SetIdle();
@@ -3950,11 +3967,11 @@ CPed::RestorePreviousState(void)
}
}
}
- SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7));
+ SetWanderPath(CGeneral::GetRandomNumber() & 7);
break;
default:
m_nPedState = m_nLastPedState;
- SetMoveState((eMoveState) m_nPrevActionState);
+ SetMoveState((eMoveState) m_nPrevMoveState);
break;
}
m_nLastPedState = PED_NONE;
@@ -4010,15 +4027,15 @@ CPed::SetPointGunAt(CEntity *to)
CAnimBlendAssociation *aimAssoc;
if (bCrouchWhenShooting)
- aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_Anim2ToPlay);
+ aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_Anim2ToPlay);
else
- aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_AnimToPlay);
+ aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_AnimToPlay);
if (!aimAssoc || aimAssoc->blendDelta < 0.0f) {
if (bCrouchWhenShooting)
- aimAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f);
+ aimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f);
else
- aimAssoc = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_AnimToPlay);
+ aimAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay);
aimAssoc->blendAmount = 0.0f;
aimAssoc->blendDelta = 8.0f;
@@ -4039,6 +4056,18 @@ CPed::SetAmmo(eWeaponType weaponType, uint32 ammo)
}
void
+CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo)
+{
+ if (HasWeapon(weaponType)) {
+ GetWeapon(weaponType).m_nAmmoTotal += ammo;
+ }
+ else {
+ GetWeapon(weaponType).Initialise(weaponType, ammo);
+ m_maxWeaponTypeAllowed++;
+ }
+}
+
+void
CPed::SetEvasiveStep(CEntity *reason, uint8 animType)
{
AnimationId stepAnim;
@@ -4067,25 +4096,29 @@ CPed::SetEvasiveStep(CEntity *reason, uint8 animType)
}
if (neededTurn <= DEGTORAD(90.0f) || veh->m_modelIndex == MI_RCBANDIT || vehPressedHorn || animType != 0) {
SetLookFlag(veh, 1);
- if (CGeneral::GetRandomNumberInRange(0,1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) {
+ if ((CGeneral::GetRandomNumber() & 1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) {
stepAnim = ANIM_IDLE_TAXI;
} else {
- // I didn't get these things too much.
float vehDirection = CGeneral::GetRadianAngleBetweenPoints(
veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y,
0.0f, 0.0f);
- float inversedAngleToFace = angleToFace + PI;
- if (inversedAngleToFace > PI)
- inversedAngleToFace -= 2*PI;
+ // Let's turn our back to the "reason"
+ angleToFace += PI;
+
+ if (angleToFace > PI)
+ angleToFace -= 2*PI;
+
+ // We don't want to run towards car's direction
+ float dangerZone = angleToFace - vehDirection;
+ dangerZone = CGeneral::LimitRadianAngle(dangerZone);
- neededTurn = inversedAngleToFace - vehDirection;
- neededTurn = CGeneral::LimitRadianAngle(neededTurn);
- if (neededTurn <= 0.0)
- angleToFace = 0.5*PI + vehDirection;
+ // So, add or subtract 90deg (jump to left/right) according to that
+ if (dangerZone <= 0.0f)
+ angleToFace = 0.5f*PI + vehDirection;
else
- angleToFace = vehDirection - 0.5*PI;
+ angleToFace = vehDirection - 0.5f*PI;
if (animType == 2)
stepAnim = ANIM_HANDSCOWER;
@@ -4094,8 +4127,8 @@ CPed::SetEvasiveStep(CEntity *reason, uint8 animType)
else
stepAnim = NUM_ANIMS;
}
- if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, stepAnim)) {
- CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, stepAnim, 8.0f);
+ if (!RpAnimBlendClumpGetAssociation(GetClump(), stepAnim)) {
+ CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, stepAnim, 8.0f);
stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT;
stepAssoc->SetFinishCallback(PedEvadeCB, this);
@@ -4110,6 +4143,1130 @@ CPed::SetEvasiveStep(CEntity *reason, uint8 animType)
}
}
+void
+CPed::SetEvasiveDive(CPhysical* reason, uint8 onlyRandomJump)
+{
+ if (!IsPedInControl() || !bRespondsToThreats)
+ return;
+
+ CAnimBlendAssociation* animAssoc;
+ float angleToFace, neededTurn;
+ bool handsUp = false;
+
+ angleToFace = m_fRotationCur;
+ CVehicle *veh = (CVehicle*) reason;
+ if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR && veh->m_nCarHornTimer && !IsPlayer()) {
+ onlyRandomJump = true;
+ }
+
+ if (onlyRandomJump) {
+ if (reason) {
+ // Simple version of my bug fix below. Doesn't calculate "danger zone", selects jump direction randomly.
+ // Also doesn't include random hands up, sound etc. Only used on player ped and peds running from gun shots.
+
+ float vehDirection = CGeneral::GetRadianAngleBetweenPoints(
+ veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y,
+ 0.0f, 0.0f);
+ angleToFace = (CGeneral::GetRandomNumber() & 1) * PI + (-0.5f*PI) + vehDirection;
+ angleToFace = CGeneral::LimitRadianAngle(angleToFace);
+ }
+ } else {
+ if (IsPlayer()) {
+ ((CPlayerPed*)this)->m_bShouldEvade = 5;
+ ((CPlayerPed*)this)->m_pEvadingFrom = reason;
+ reason->RegisterReference((CEntity**) &((CPlayerPed*)this)->m_pEvadingFrom);
+ return;
+ }
+
+ angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ reason->GetPosition().x, reason->GetPosition().y,
+ GetPosition().x, GetPosition().y);
+ angleToFace = CGeneral::LimitRadianAngle(angleToFace);
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+
+ // FIX: Peds no more dive into cars. Taken from SetEvasiveStep, last if statement inverted
+#ifdef FIX_BUGS
+ float vehDirection = CGeneral::GetRadianAngleBetweenPoints(
+ veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y,
+ 0.0f, 0.0f);
+
+ // Let's turn our back to the "reason"
+ angleToFace += PI;
+
+ if (angleToFace > PI)
+ angleToFace -= 2 * PI;
+
+ // We don't want to dive towards car's direction
+ float dangerZone = angleToFace - vehDirection;
+ dangerZone = CGeneral::LimitRadianAngle(dangerZone);
+
+ // So, add or subtract 90deg (jump to left/right) according to that
+ if (dangerZone > 0.0f)
+ angleToFace = 0.5f * PI + vehDirection;
+ else
+ angleToFace = vehDirection - 0.5f * PI;
+#endif
+
+ neededTurn = Abs(angleToFace - m_fRotationCur);
+
+ if (neededTurn > PI)
+ neededTurn = 2 * PI - neededTurn;
+
+ if (neededTurn <= 0.5f*PI) {
+ if (CGeneral::GetRandomNumber() & 1)
+ handsUp = true;
+ } else {
+ if (CGeneral::GetRandomNumber() & 7)
+ return;
+ }
+ Say(SOUND_PED_EVADE);
+ }
+
+ if (handsUp || !IsPlayer() && m_pedStats->m_flags & STAT_NO_DIVE) {
+ m_fRotationCur = angleToFace;
+ ClearLookFlag();
+ ClearAimFlag();
+ SetLookFlag(reason, 1);
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP);
+ if (animAssoc)
+ return;
+
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP, 8.0f);
+ animAssoc->flags &= ~ASSOC_DELETEFADEDOUT;
+ animAssoc->SetFinishCallback(PedEvadeCB, this);
+ SetStoredState();
+ m_nPedState = PED_STEP_AWAY;
+ } else {
+ m_fRotationCur = angleToFace;
+ ClearLookFlag();
+ ClearAimFlag();
+ SetStoredState();
+ m_nPedState = PED_DIVE_AWAY;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_EV_DIVE, 8.0f);
+ animAssoc->SetFinishCallback(PedEvadeCB, this);
+ }
+
+ if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) {
+ if (veh->pDriver && veh->pDriver->IsPlayer()) {
+ CWanted *wanted = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted;
+ wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (int)this, false);
+ wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (int)this, false);
+ }
+ }
+}
+
+void
+CPed::SetAttack(CEntity* victim)
+{
+ CPed *victimPed = nil;
+ if (victim && victim->IsPed())
+ victimPed = (CPed*)victim;
+
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED);
+ if (animAssoc) {
+ animAssoc->blendDelta = -1000.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+
+ if (m_attackTimer > CTimer::GetTimeInMilliseconds() || m_nWaitState == WAITSTATE_SURPRISE)
+ return;
+
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) {
+ m_ped_flagA4 = false;
+ return;
+ }
+
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) {
+ if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->field_1380)
+ m_ped_flagA4 = false;
+ else
+ m_ped_flagA4 = true;
+
+ return;
+ }
+
+ CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ if (curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT && !IsPlayer()) {
+ if (GetWeapon()->HitsGround(this, nil, victim))
+ return;
+ }
+
+ if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) {
+ if (IsPlayer() ||
+ (m_nPedState != PED_FIGHT && m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL && !(m_pedStats->m_flags & STAT_SHOPPING_BAGS))) {
+
+ if (m_nPedState != PED_ATTACK) {
+ m_nPedState = PED_ATTACK;
+ m_ped_flagA4 = false;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f);
+ animAssoc->SetRun();
+ if (animAssoc->currentTime != animAssoc->hierarchy->totalLength)
+ animAssoc->SetCurrentTime(0.0f);
+
+ animAssoc->SetFinishCallback(FinishedAttackCB, this);
+ }
+ } else {
+ StartFightAttack(CGeneral::GetRandomNumber() % 256);
+ }
+ return;
+ }
+
+ m_pSeekTarget = victim;
+ if (m_pSeekTarget)
+ m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget);
+
+ if (curWeapon->m_bCanAim) {
+ CVector aimPos = GetRight() * 0.1f + GetForward() * 0.2f + GetPosition();
+ CEntity *foundEntity = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false);
+ if (foundEntity)
+ return;
+
+ m_pLookTarget = victim;
+ if (victim) {
+ m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget);
+ m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget);
+ }
+ if (m_pLookTarget) {
+ SetAimFlag(m_pLookTarget);
+ } else {
+ SetAimFlag(m_fRotationCur);
+
+ if (FindPlayerPed() == this && TheCamera.Cams[0].Using3rdPersonMouseCam())
+ ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch();
+ }
+ }
+ if (m_nPedState == PED_ATTACK) {
+ m_ped_flagA4 = true;
+ return;
+ }
+
+ if (IsPlayer() || !victimPed || victimPed->IsPedInControl()) {
+ if(IsPlayer())
+ CPad::GetPad(0)->ResetAverageWeapon();
+
+ if ((curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER)
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16FIRSTPERSON_34
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_FIRSTPERSONPEDONPC_41
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUN_AROUND
+ && CheckForPointBlankPeds(victimPed) != 0) {
+ ClearAimFlag();
+
+ // This condition is pointless, we already check it in above
+ // if (CheckForPointBlankPeds(victimPed) == 1 || !victimPed)
+ StartFightAttack(200);
+ } else {
+ if (!curWeapon->m_bCanAim)
+ m_pSeekTarget = nil;
+
+ if (m_nPedState != PED_AIM_GUN)
+ SetStoredState();
+
+ m_nPedState = PED_ATTACK;
+ SetMoveState(PEDMOVE_NONE);
+ if (bCrouchWhenShooting) {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
+ } else {
+ float animDelta = 8.0f;
+ if (curWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE)
+ animDelta = 1000.0f;
+
+ if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT
+ || CheckForPedsOnGroundToAttack((CPlayerPed*)this, nil) < PED_ON_THE_FLOOR) {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, animDelta);
+ } else {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, animDelta);
+ }
+ }
+
+ animAssoc->SetRun();
+ if (animAssoc->currentTime != animAssoc->hierarchy->totalLength)
+ animAssoc->SetCurrentTime(0.0f);
+
+ animAssoc->SetFinishCallback(FinishedAttackCB, this);
+ }
+ return;
+ }
+
+ if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && victimPed->m_nPedState == PED_GETUP)
+ SetWaitState(WAITSTATE_SURPRISE, nil);
+
+ SetLookFlag(victim, 0);
+ SetLookTimer(100);
+}
+
+void
+CPed::StartFightAttack(uint8 buttonPressure)
+{
+ if (!IsPedInControl() || m_attackTimer > CTimer::GetTimeInMilliseconds())
+ return;
+
+ if (m_nPedState == PED_FIGHT) {
+ m_fightButtonPressure = buttonPressure;
+ return;
+ }
+
+ if (m_nPedState != PED_AIM_GUN)
+ SetStoredState();
+
+ if (m_nWaitState != WAITSTATE_FALSE) {
+ m_nWaitState = WAITSTATE_FALSE;
+ RestoreHeadingRate();
+ }
+
+ m_nPedState = PED_FIGHT;
+ m_fightButtonPressure = 0;
+ RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT);
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
+
+ if (animAssoc) {
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ animAssoc->blendDelta = -1000.0f;
+ }
+
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
+
+ if (animAssoc) {
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ animAssoc->blendDelta = -1000.0f;
+ RestoreHeadingRate();
+ }
+
+ SetMoveState(PEDMOVE_NONE);
+ m_nStoredMoveState = PEDMOVE_NONE;
+
+ CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f;
+
+ CPed *pedOnGround = nil;
+ if (IsPlayer() && CheckForPedsOnGroundToAttack((CPlayerPed*)this, &pedOnGround) > PED_BELOW_PLAYER) {
+ m_lastFightMove = FIGHTMOVE_GROUNDKICK;
+ } else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) {
+ m_lastFightMove = FIGHTMOVE_ROUNDHOUSE;
+ } else {
+ m_lastFightMove = FIGHTMOVE_STDPUNCH;
+ }
+
+ if (pedOnGround && IsPlayer()) {
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(
+ pedOnGround->GetPosition().x, pedOnGround->GetPosition().y,
+ GetPosition().x, GetPosition().y);
+
+ m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest);
+ m_fRotationCur = m_fRotationDest;
+ m_lookTimer = 0;
+ SetLookFlag(pedOnGround, 1);
+ SetLookTimer(1500);
+ }
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ms_fightMoves[m_lastFightMove].animId, 4.0f);
+ animAssoc->SetFinishCallback(FinishFightMoveCB, this);
+ m_fightUnk2 = 0;
+ m_fightUnk1 = 0;
+ m_ped_flagA4 = true;
+
+ if (IsPlayer())
+ unknownFightThing = 0;
+}
+
+void
+CPed::LoadFightData(void)
+{
+ float startFireTime, endFireTime, comboFollowOnTime, strikeRadius;
+ int damage, flags;
+ char line[256], moveName[32], animName[32], hitLevel;
+ int moveId = 0;
+
+ CAnimBlendAssociation* animAssoc;
+
+ int bp, buflen;
+ int lp, linelen;
+
+ buflen = CFileMgr::LoadFile("DATA\\fistfite.dat", work_buff, sizeof(work_buff), "r");
+
+ for (bp = 0; bp < buflen; ) {
+ // read file line by line
+ for (linelen = 0; work_buff[bp] != '\n' && bp < buflen; bp++) {
+ line[linelen++] = work_buff[bp];
+ }
+ bp++;
+ line[linelen] = '\0';
+
+ // 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 %f %f %c %s %d %d",
+ &moveName,
+ &startFireTime,
+ &endFireTime,
+ &comboFollowOnTime,
+ &strikeRadius,
+ &hitLevel,
+ &animName,
+ &damage,
+ &flags);
+
+ if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0)
+ return;
+
+ ms_fightMoves[moveId].startFireTime = startFireTime / 30.0f;
+ ms_fightMoves[moveId].endFireTime = endFireTime / 30.0f;
+ ms_fightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f;
+ ms_fightMoves[moveId].strikeRadius = strikeRadius;
+ ms_fightMoves[moveId].damage = damage;
+ ms_fightMoves[moveId].flags = flags;
+
+ switch (hitLevel) {
+ case 'G':
+ ms_fightMoves[moveId].hitLevel = 1;
+ break;
+ case 'H':
+ ms_fightMoves[moveId].hitLevel = 4;
+ break;
+ case 'L':
+ ms_fightMoves[moveId].hitLevel = 2;
+ break;
+ case 'M':
+ ms_fightMoves[moveId].hitLevel = 3;
+ break;
+ case 'N':
+ ms_fightMoves[moveId].hitLevel = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (strncmp(animName, "null", 4) != 0) {
+ animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName);
+ ms_fightMoves[moveId].animId = (AnimationId)animAssoc->animId;
+ } else {
+ ms_fightMoves[moveId].animId = ANIM_WALK;
+ }
+ moveId++;
+ }
+}
+
+// Actually GetLocalDirectionTo(Turn/Look)
+int
+CPed::GetLocalDirection(CVector2D &posOffset)
+{
+ float direction;
+
+ for (direction = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); direction < 0.0f; direction += 2 * PI);
+
+ for (direction = (int)RADTODEG(direction) / 90; direction > 3; direction -= 4);
+
+ // Should be 0-east, 1-north, 2-west, 3-south. Not sure about order.
+ return direction;
+}
+
+bool
+CPed::FightStrike(CVector &touchedNodePos)
+{
+ CColModel* ourCol;
+ CVector attackDistance;
+ ePedPieceTypes closestPedPiece = PEDPIECE_TORSO;
+ float maxDistanceToBeBeaten;
+ CPed *nearPed;
+ int unk = m_fightUnk2;
+ bool pedFound = false;
+
+ if (unk == -1)
+ return false;
+
+ if (unk > 0)
+ attackDistance = touchedNodePos - m_vecHitLastPos;
+
+ for (int i = 0; i < m_numNearPeds; i++) {
+ nearPed = m_nearPeds[i];
+ if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
+ maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius + 0.1f;
+ else
+ maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius;
+
+ if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) {
+ CVector nearPedCentre;
+ nearPed->GetBoundCentre(nearPedCentre);
+ CVector potentialAttackDistance = nearPedCentre - touchedNodePos;
+
+ // He can beat us
+ if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) {
+ ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel();
+ if (nearPed->m_nPedState == PED_FALL
+ || nearPed->m_nPedState == PED_DEAD || nearPed->m_nPedState == PED_DIE
+ || !nearPed->IsPedHeadAbovePos(-0.3f)) {
+ ourCol = &CTempColModels::ms_colModelPedGroundHit;
+ }
+ for (int j = 0; j < ourCol->numSpheres; j++) {
+ attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center;
+ attackDistance -= touchedNodePos;
+ CColSphere *ourPieces = ourCol->spheres;
+ float maxDistanceToBeat = ourPieces[j].radius + ms_fightMoves[m_lastFightMove].strikeRadius;
+
+ // We can beat him too
+ if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) {
+ pedFound = true;
+ closestPedPiece = (ePedPieceTypes) ourPieces[j].piece;
+ break;
+ }
+ }
+ }
+ }
+ if (pedFound)
+ break;
+ }
+
+ if (pedFound) {
+ if (nearPed->IsPlayer() && nearPed->m_nPedState == PED_GETUP)
+ return false;
+
+ float oldVictimHealth = nearPed->m_fHealth;
+ CVector bloodPos = 0.5f * attackDistance + touchedNodePos;
+ int damageMult = ms_fightMoves[m_lastFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
+
+ CVector2D diff (GetPosition() - nearPed->GetPosition());
+ int direction = nearPed->GetLocalDirection(diff);
+ if (IsPlayer()) {
+ if (((CPlayerPed*)this)->m_bAdrenalineActive)
+ damageMult = 20;
+ } else {
+ damageMult *= m_pedStats->m_attackStrength;
+ }
+
+ // Change direction if we used kick.
+ if (m_lastFightMove == FIGHTMOVE_KICK) {
+ if (CGeneral::GetRandomNumber() & 1) {
+ direction++;
+ if (direction > 3)
+ direction -= 4;
+ }
+ }
+ nearPed->ReactToAttack(this);
+
+ // Mostly unused.
+ int unk2;
+ if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !nearPed->IsPlayer())
+ unk2 = 101;
+ else
+ unk2 = damageMult;
+
+ nearPed->StartFightDefend(direction, ms_fightMoves[m_lastFightMove].hitLevel, unk2);
+ PlayHitSound(nearPed);
+ m_fightUnk2 = -1;
+ RpAnimBlendClumpGetAssociation(GetClump(), ms_fightMoves[m_lastFightMove].animId)->speed = 0.6f;
+ if (nearPed->m_nPedState != PED_DIE && nearPed->m_nPedState != PED_DEAD) {
+ nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction);
+ }
+
+ if (CGame::nastyGame
+ && ms_fightMoves[m_lastFightMove].hitLevel > 3
+ && nearPed->m_nPedState == PED_DIE
+ && nearPed->GetIsOnScreen()) {
+
+ // Just for blood particle. We will restore it below.
+ attackDistance /= (10.0f * attackDistance.Magnitude());
+ for(int i=0; i<4; i++) {
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, attackDistance, nil, 0.0f, 0, 0, 0, 0);
+ }
+ }
+ if (nearPed->m_nPedState != PED_FALL && nearPed->m_nPedState != PED_DIE && nearPed->m_nPedState != PED_DEAD) {
+ float curVictimHealth = nearPed->m_fHealth;
+ if (curVictimHealth > 0.0f
+ && (curVictimHealth < 40.0f && oldVictimHealth > 40.0f && !nearPed->IsPlayer()
+ || nearPed->m_fHealth < 20.0f && oldVictimHealth > 20.0f
+ || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && IsPlayer()
+ || nearPed->m_pedStats->m_flags & STAT_ONE_HIT_KNOCKDOWN)) {
+
+ nearPed->SetFall(0, (AnimationId)(direction + 25), 0);
+ if (nearPed->m_nPedState == PED_FALL)
+ nearPed->bIsStanding = false;
+ }
+ }
+ if (nearPed->m_nPedState == PED_DIE || !nearPed->bIsStanding) {
+ attackDistance = nearPed->GetPosition() - GetPosition();
+ attackDistance.Normalise();
+ attackDistance.z = 1.0f;
+ nearPed->bIsStanding = false;
+
+ float moveMult;
+ if (m_lastFightMove == FIGHTMOVE_GROUNDKICK) {
+ moveMult = min(damageMult * 0.6f, 4.0f);
+ } else {
+ if (nearPed->m_nPedState != PED_DIE || damageMult >= 20) {
+ moveMult = damageMult;
+ } else {
+ moveMult = min(damageMult * 2.0f, 14.0f);
+ }
+ }
+
+ nearPed->ApplyMoveForce(moveMult * 0.6f * attackDistance);
+ }
+ CEventList::RegisterEvent(nearPed->m_nPedType == PEDTYPE_COP ? EVENT_ASSAULT_POLICE : EVENT_ASSAULT, EVENT_ENTITY_PED, nearPed, this, 2000);
+ }
+
+ if (!m_fightUnk2)
+ m_fightUnk2 = 1;
+
+ m_vecHitLastPos = *touchedNodePos;
+ return false;
+}
+
+void
+CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl)
+{
+ if (!IsPedInControl() && (!evenIfNotInControl || m_nPedState == PED_DIE || m_nPedState == PED_DEAD))
+ return;
+
+ ClearLookFlag();
+ ClearAimFlag();
+ SetStoredState();
+ m_nPedState = PED_FALL;
+ CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), animId);
+
+ if (fallAssoc) {
+ fallAssoc->SetCurrentTime(0.0f);
+ fallAssoc->blendAmount = 0.0f;
+ fallAssoc->blendDelta = 8.0f;
+ fallAssoc->SetRun();
+ } else {
+ fallAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, 8.0f);
+ }
+
+ if (extraTime == -1) {
+ m_getUpTimer = -1;
+ } else if (fallAssoc) {
+ if (IsPlayer()) {
+ m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength
+ + CTimer::GetTimeInMilliseconds()
+ + 500.0f;
+ } else {
+ m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength
+ + CTimer::GetTimeInMilliseconds()
+ + extraTime
+ + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000);
+ }
+ } else {
+ m_getUpTimer = extraTime
+ + CTimer::GetTimeInMilliseconds()
+ + 1000
+ + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000);
+ }
+ bIsFell = true;
+}
+
+void
+CPed::SetFlee(CEntity* fleeFrom, int time)
+{
+ if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom)
+ return;
+
+ SetStoredState();
+ m_nPedState = PED_FLEE_ENTITY;
+ bIsFleeing = true;
+ SetMoveState(PEDMOVE_RUN);
+ m_fleeFrom = fleeFrom;
+ m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom);
+
+ if (time <= 0)
+ m_fleeTimer = 0;
+ else
+ m_fleeTimer = CTimer::GetTimeInMilliseconds() + time;
+
+ float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ GetPosition().x, GetPosition().y,
+ fleeFrom->GetPosition().x, fleeFrom->GetPosition().y);
+
+ m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace);
+ if (m_fRotationCur - PI > m_fRotationDest) {
+ m_fRotationDest += 2 * PI;
+ } else if (PI + m_fRotationCur < m_fRotationDest) {
+ m_fRotationDest -= 2 * PI;
+ }
+}
+
+void
+CPed::SetFlee(CVector2D &from, int time)
+{
+ if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace)
+ return;
+
+ if (m_nPedState != PED_FLEE_ENTITY) {
+ SetStoredState();
+ m_nPedState = PED_FLEE_POS;
+ SetMoveState(PEDMOVE_RUN);
+ m_fleeFromPosX = from.x;
+ m_fleeFromPosY = from.y;
+ }
+
+ bIsFleeing = true;
+ m_pLastPathNode = nil;
+ m_fleeTimer = CTimer::GetTimeInMilliseconds() + time;
+
+ float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ GetPosition().x, GetPosition().y,
+ from.x, from.y);
+
+ m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace);
+ if (m_fRotationCur - PI > m_fRotationDest) {
+ m_fRotationDest += 2 * PI;
+ } else if (PI + m_fRotationCur < m_fRotationDest) {
+ m_fRotationDest -= 2 * PI;
+ }
+}
+
+void
+CPed::SetWaitState(eWaitState state, void *time)
+{
+ AnimationId waitAnim = NUM_ANIMS;
+ CAnimBlendAssociation *animAssoc;
+
+ if (!IsPedInControl())
+ return;
+
+ if (state != m_nWaitState)
+ FinishedWaitCB(nil, this);
+
+ switch (state) {
+ case WAITSTATE_TRAFFIC_LIGHTS:
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500;
+ SetMoveState(PEDMOVE_STILL);
+ break;
+ case WAITSTATE_CROSS_ROAD:
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+ break;
+ case WAITSTATE_CROSS_ROAD_LOOK:
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f);
+
+ if (time)
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+ else
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000);
+
+ break;
+ case WAITSTATE_LOOK_PED:
+ case WAITSTATE_LOOK_SHOP:
+ case WAITSTATE_LOOK_ACCIDENT:
+ case WAITSTATE_FACEOFF_GANG:
+ break;
+ case WAITSTATE_DOUBLEBACK:
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+ break;
+ case WAITSTATE_HITWALL:
+ m_headingRate = 2.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f);
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+
+ if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
+ ClearObjective();
+ RestorePreviousState();
+ }
+ break;
+ case WAITSTATE_TURN180:
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 3000.0f);
+ animAssoc->SetFinishCallback(FinishedWaitCB, this);
+ animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
+ break;
+ case WAITSTATE_SURPRISE:
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 3000.0f);
+ animAssoc->SetFinishCallback(FinishedWaitCB, this);
+ break;
+ case WAITSTATE_STUCK:
+ SetMoveState(PEDMOVE_STILL);
+ SetMoveAnim();
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f);
+
+ if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
+ ClearObjective();
+ RestorePreviousState();
+ }
+ break;
+ case WAITSTATE_LOOK_ABOUT:
+ SetMoveState(PEDMOVE_STILL);
+ SetMoveAnim();
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+ break;
+ case WAITSTATE_PLAYANIM_COWER:
+ waitAnim = ANIM_HANDSCOWER;
+ case WAITSTATE_PLAYANIM_HANDSUP:
+ if (waitAnim == NUM_ANIMS)
+ waitAnim = ANIM_HANDSUP;
+ case WAITSTATE_PLAYANIM_HANDSCOWER:
+ if (waitAnim == NUM_ANIMS)
+ waitAnim = ANIM_HANDSCOWER;
+ m_headingRate = 0.0f;
+ if (time)
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+ else
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000;
+
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f);
+ animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+ break;
+ case WAITSTATE_PLAYANIM_DUCK:
+ waitAnim = ANIM_DUCK_DOWN;
+ case WAITSTATE_PLAYANIM_TAXI:
+ if (waitAnim == NUM_ANIMS)
+ waitAnim = ANIM_IDLE_TAXI;
+ case WAITSTATE_PLAYANIM_CHAT:
+ if (waitAnim == NUM_ANIMS)
+ waitAnim = ANIM_IDLE_CHAT;
+ if (time)
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+ else
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000;
+
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f);
+ animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+ break;
+ case WAITSTATE_FINISH_FLEE:
+ SetMoveState(PEDMOVE_STILL);
+ SetMoveAnim();
+ m_headingRate = 0.0f;
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f);
+ break;
+ default:
+ m_nWaitState = WAITSTATE_FALSE;
+ RestoreHeadingRate();
+ return;
+ }
+ m_nWaitState = state;
+}
+
+
+void
+CPed::PlayHitSound(CPed *hitTo)
+{
+ // That was very complicated to reverse for me...
+ // First index is our fight move ID (from 1 to 12, total 12), second is the one of we fight with (from 13 to 22, total 10).
+
+ uint16 hitSoundsByFightMoves[12][10] = {
+ {S39,S42,S43,S43,S39,S39,S39,S39,S39,S42},
+ {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND},
+ {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND},
+ {S39,S39,S39,S39,S33,S43,S39,S39,S39,S39},
+ {S39,S39,S39,S39,S35,S39,S38,S38,S39,S39},
+ {S39,S39,S39,S39,S33,S39,S41,S36,S39,S39},
+ {S39,S39,S39,S39,S37,S40,S38,S38,S39,S39},
+ {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
+ {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
+ {S39,S39,S39,S39,S34,S43,S44,S37,S39,S40},
+ {S39,S39,S39,S39,S33,S39,S41,S37,S39,S40},
+ {S39,S39,S39,S39,S39,S39,S39,S39,S33,S33}
+ };
+
+ // This is why first dimension is between FightMove 1 and 12.
+ if (m_lastFightMove == FIGHTMOVE_NULL || m_lastFightMove >= FIGHTMOVE_HITFRONT)
+ return;
+
+ uint16 soundId;
+
+ // And this is why second dimension is between 13 and 22.
+ if (hitTo->m_lastFightMove <= FIGHTMOVE_GROUNDKICK || hitTo->m_lastFightMove >= FIGHTMOVE_IDLE2NORM) {
+
+ if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) {
+ soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT];
+ } else {
+ soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT];
+ }
+ } else {
+ soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_lastFightMove - FIGHTMOVE_HITFRONT];
+ }
+
+ if (soundId != NO_SND)
+ DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f);
+}
+
+void
+CPed::Say(uint16 audio)
+{
+ uint16 audioToPlay = audio;
+
+ if (IsPlayer()) {
+ switch (audio) {
+ case SOUND_PED_DEATH:
+ audioToPlay = SOUND_PED_DAMAGE;
+ break;
+ case SOUND_PED_DAMAGE:
+ case SOUND_PED_HIT:
+ case SOUND_PED_LAND:
+ break;
+ case SOUND_PED_BULLET_HIT:
+ case SOUND_PED_CAR_JACKED:
+ case SOUND_PED_DEFEND:
+ audioToPlay = SOUND_PED_HIT;
+ break;
+ default:
+ return;
+ }
+ } else {
+ if (3.0f + TheCamera.GetPosition().z < GetPosition().z)
+ return;
+
+ if (TheCamera.m_CameraAverageSpeed > 1.65f) {
+ return;
+ } else if (TheCamera.m_CameraAverageSpeed > 1.25f) {
+ if (audio != SOUND_PED_DEATH && audio != SOUND_PED_TAXI_WAIT && audio != SOUND_PED_EVADE)
+ return;
+
+ } else if (TheCamera.m_CameraAverageSpeed > 0.9f) {
+ switch (audio) {
+ case SOUND_PED_DEATH:
+ case SOUND_PED_BURNING:
+ case SOUND_PED_FLEE_SPRINT:
+ case SOUND_PED_TAXI_WAIT:
+ case SOUND_PED_EVADE:
+ case SOUND_PED_CAR_COLLISION:
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ if (audioToPlay < m_queuedSound) {
+ if (audioToPlay != m_lastQueuedSound || audioToPlay == SOUND_PED_DEATH
+ || PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime
+ + m_lastSoundStart
+ + (uint32) CGeneral::GetRandomNumberInRange(0, PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) {
+ m_queuedSound = audioToPlay;
+ }
+ }
+}
+
+void
+CPed::CollideWithPed(CPed *collideWith)
+{
+ CAnimBlendAssociation *animAssoc;
+ AnimationId animToRun;
+
+ bool weAreMissionChar = CharCreatedBy == MISSION_CHAR;
+ bool heIsMissionChar = collideWith->CharCreatedBy == MISSION_CHAR;
+ CVector posDiff = collideWith->GetPosition() - GetPosition();
+ int waitTime = 0;
+
+ if (weAreMissionChar || !collideWith->IsPlayer() || collideWith->m_nPedState != PED_MAKE_CALL) {
+ bool weDontLookToHim = DotProduct(posDiff, GetForward()) > 0.0f;
+ bool heLooksToUs = DotProduct(posDiff, collideWith->GetForward()) < 0.0f;
+
+ if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) {
+
+ if ((!IsPlayer() || ((CPlayerPed*)this)->m_fMoveSpeed <= 1.8f)
+ && (IsPlayer() || heIsMissionChar && weAreMissionChar || m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT)) {
+
+ if (m_objective != OBJECTIVE_FOLLOW_PED_IN_FORMATION && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT) {
+
+ if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) {
+
+ if (heIsMissionChar || !weAreMissionChar && collideWith->m_nMoveState != PEDMOVE_STILL) {
+
+ if (weAreMissionChar && ((m_nPedState == PED_SEEK_POS) || m_nPedState == PED_SEEK_ENTITY)) {
+
+ if (collideWith->m_nMoveState != PEDMOVE_STILL
+ && (!collideWith->IsPlayer() || collideWith->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled())) {
+ float weAndCarDist = (GetPosition() - m_vecSeekVehicle).MagnitudeSqr2D();
+ float heAndCarDist = (collideWith->GetPosition() - m_vecSeekVehicle).MagnitudeSqr2D();
+
+ if (weAndCarDist <= heAndCarDist) {
+ waitTime = 1000;
+ collideWith->SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime);
+ collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime;
+ } else {
+ waitTime = 500;
+ SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime);
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime;
+ }
+ } else if (collideWith->m_nMoveState == PEDMOVE_STILL) {
+ SetDirectionToWalkAroundObject(collideWith);
+ }
+ } else if (weAreMissionChar || m_pedStats->m_fear <= 100 - collideWith->m_pedStats->m_temper
+ || (collideWith->IsPlayer() || collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) &&
+ (!collideWith->IsPlayer() || ((CPlayerPed*)collideWith)->m_fMoveSpeed <= 1.0f)) {
+ SetDirectionToWalkAroundObject(collideWith);
+ if (!weAreMissionChar)
+ Say(SOUND_PED_CHAT);
+ } else {
+ SetEvasiveStep(collideWith, 2);
+ }
+ } else {
+ if (m_pedStats->m_temper <= m_pedStats->m_fear
+ || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED
+ || weAreMissionChar
+ || collideWith->m_nPedType == PEDTYPE_CIVFEMALE
+ || collideWith->m_nPedType == m_nPedType
+ || collideWith->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) {
+ SetDirectionToWalkAroundObject(collideWith);
+ Say(SOUND_PED_CHAT);
+ } else {
+ TurnBody();
+ SetAttack(collideWith);
+ }
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(250, 450);
+ }
+ }
+ } else {
+ if (m_pedInObjective && collideWith == m_pedInObjective && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) {
+ if (heLooksToUs) {
+ SetEvasiveStep(collideWith, 1);
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000;
+ }
+ } else if (weDontLookToHim && IsPedInControl()) {
+
+ if (m_pedStats != collideWith->m_pedStats) {
+
+ if (collideWith->m_pedStats->m_fear <= 100 - m_pedStats->m_temper) {
+
+ if (collideWith->IsPlayer()) {
+ // He's on our right side
+ if (DotProduct(posDiff,GetRight()) <= 0.0f)
+ m_fRotationCur -= m_headingRate;
+ else
+ m_fRotationCur += m_headingRate;
+ } else {
+ // He's on our right side
+ if (DotProduct(posDiff, GetRight()) <= 0.0f)
+ m_fRotationCur -= m_headingRate;
+ else
+ m_fRotationCur += m_headingRate;
+ }
+ } else {
+ SetLookFlag(collideWith, 0);
+ TurnBody();
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f);
+ animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ if (!heIsMissionChar) {
+ int direction = collideWith->GetLocalDirection(CVector2D(posDiff.x, posDiff.y));
+ collideWith->StartFightDefend(direction, 4, 5);
+ }
+ }
+ }
+ }
+ }
+ } else if (collideWith->m_pedStats->m_defendWeakness <= 1.5f || heIsMissionChar) {
+ // He looks us and we're not at his right side
+ if (heLooksToUs && DotProduct(posDiff,collideWith->GetRight()) > 0.0f) {
+ CVector moveForce = GetRight();
+ moveForce.z += 0.1f;
+ ApplyMoveForce(moveForce);
+ if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT)
+ animToRun = ANIM_HIT_LEFT;
+ else
+ animToRun = ANIM_SHOT_LEFT_PARTIAL;
+ } else if (heLooksToUs) {
+ CVector moveForce = GetRight() * -1.0f;
+ moveForce.z += 0.1f;
+ ApplyMoveForce(moveForce);
+ if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT)
+ animToRun = ANIM_HIT_RIGHT;
+ else
+ animToRun = ANIM_SHOT_RIGHT_PARTIAL;
+ } else {
+ if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT)
+ animToRun = ANIM_HIT_BACK;
+ else
+ animToRun = ANIM_SHOT_BACK_PARTIAL;
+ }
+
+ if (collideWith->IsPedInControl() && CTimer::GetTimeInMilliseconds() > collideWith->m_nPedStateTimer) {
+ animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToRun, 8.0f);
+ animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ if (m_nPedState == PED_ATTACK)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f);
+ }
+ } else {
+ // We're at his right side
+ if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) {
+ CVector moveForce = GetRight() * -1.0f;
+ moveForce.z += 0.1f;
+ ApplyMoveForce(moveForce);
+ if (heLooksToUs)
+ animToRun = ANIM_KO_SPIN_L;
+ else
+ animToRun = ANIM_KD_RIGHT;
+ } else {
+ CVector moveForce = GetRight();
+ moveForce.z += 0.1f;
+ ApplyMoveForce(moveForce);
+ if (heLooksToUs)
+ animToRun = ANIM_KO_SPIN_R;
+ else
+ animToRun = ANIM_KD_LEFT;
+ }
+
+ if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl())
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f);
+
+ collideWith->SetFall(3000, animToRun, 0);
+ }
+ } else {
+ if (!IsPedInControl())
+ return;
+
+ if (collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL)
+ return;
+
+ if (m_nPedType != collideWith->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) {
+
+ if (!weAreMissionChar && heLooksToUs && m_pedStats->m_fear > 100 - collideWith->m_pedStats->m_temper) {
+
+ if (CGeneral::GetRandomNumber() & 1 && CTimer::GetTimeInMilliseconds() < m_nPedStateTimer){
+ SetEvasiveStep(collideWith, 2);
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000;
+ } else if (collideWith->m_nMoveState > PEDMOVE_WALK) {
+ waitTime = 2000;
+ SetWaitState(WAITSTATE_PLAYANIM_DUCK, &waitTime);
+ }
+ }
+ } else if (heLooksToUs
+ && collideWith->m_nPedState != PED_STEP_AWAY
+ && m_nPedState != PED_STEP_AWAY
+ && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) {
+
+ SetEvasiveStep(collideWith, 1);
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000;
+ }
+ }
+
+ if (IsPlayer()) {
+ SetLookFlag(collideWith, 1);
+ SetLookTimer(800);
+ }
+ } else {
+ bool doWeRun = true;
+ if (m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT)
+ doWeRun = false;
+
+ SetFlee(collideWith, 5000);
+ bIsFleeing = true;
+ m_pLastPathNode = nil;
+ if (!doWeRun)
+ SetMoveState(PEDMOVE_WALK);
+ }
+}
+
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); }
@@ -4181,8 +5338,8 @@ STARTPATCHES
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(0x4E4660, (CVector (*)(CVehicle*, uint32, float)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP);
+ InjectHook(0x4E1A30, (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);
@@ -4237,5 +5394,19 @@ STARTPATCHES
InjectHook(0x4D6540, &CPed::RestoreHeadingRate, PATCH_JUMP);
InjectHook(0x4C69E0, (void (CPed::*)(CEntity*)) &CPed::SetAimFlag, PATCH_JUMP);
InjectHook(0x4C6960, (void (CPed::*)(float)) &CPed::SetAimFlag, PATCH_JUMP);
+ InjectHook(0x4CFAD0, &CPed::GrantAmmo, PATCH_JUMP);
InjectHook(0x4CFB20, &CPed::SetAmmo, PATCH_JUMP);
-ENDPATCHES
+ InjectHook(0x4D33A0, &CPed::SetEvasiveDive, PATCH_JUMP);
+ InjectHook(0x4D09B0, &CPed::SetFall, PATCH_JUMP);
+ InjectHook(0x4E6220, &CPed::SetAttack, PATCH_JUMP);
+ InjectHook(0x4E7530, &CPed::StartFightAttack, PATCH_JUMP);
+ InjectHook(0x4E9870, &CPed::LoadFightData, PATCH_JUMP);
+ InjectHook(0x4E8EC0, &CPed::FightStrike, PATCH_JUMP);
+ InjectHook(0x4CCE20, &CPed::GetLocalDirection, PATCH_JUMP);
+ InjectHook(0x4E8E20, &CPed::PlayHitSound, PATCH_JUMP);
+ InjectHook(0x4E5A10, &CPed::Say, PATCH_JUMP);
+ InjectHook(0x4D58D0, &CPed::SetWaitState, PATCH_JUMP);
+ InjectHook(0x4D1D70, (void (CPed::*)(CEntity*, int)) &CPed::SetFlee, PATCH_JUMP);
+ InjectHook(0x4D1C40, (void (CPed::*)(CVector2D&, int)) &CPed::SetFlee, PATCH_JUMP);
+ InjectHook(0x4EB9A0, &CPed::CollideWithPed, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 7b8bc2ce..dcbe247a 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -10,9 +10,78 @@
#include "AnimBlendAssociation.h"
#include "WeaponInfo.h"
#include "Fire.h"
+#include "DMAudio.h"
struct CPathNode;
+struct CPedAudioData
+{
+ int m_nFixedDelayTime;
+ int m_nOverrideFixedDelayTime;
+ int m_nOverrideMaxRandomDelayTime;
+ int m_nMaxRandomDelayTime;
+};
+
+// For hit sounds in fight
+enum {
+ S33 = SOUND_FIGHT_PUNCH_33,
+ S34 = SOUND_FIGHT_KICK_34,
+ S35 = SOUND_FIGHT_HEADBUTT_35,
+ S36 = SOUND_FIGHT_PUNCH_36,
+ S37 = SOUND_FIGHT_PUNCH_37,
+ S38 = SOUND_FIGHT_CLOSE_PUNCH_38,
+ S39 = SOUND_FIGHT_PUNCH_39,
+ S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 ,
+ S41 = SOUND_FIGHT_PUNCH_41,
+ S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42,
+ S43 = SOUND_FIGHT_KNEE_OR_KICK_43,
+ S44 = SOUND_FIGHT_KICK_44,
+ NO_SND = SOUND_TOTAL_PED_SOUNDS
+};
+
+struct FightMove
+{
+ AnimationId animId;
+ float startFireTime;
+ float endFireTime;
+ float comboFollowOnTime;
+ float strikeRadius;
+ uint8 hitLevel;
+ uint8 damage;
+ uint8 flags;
+};
+static_assert(sizeof(FightMove) == 0x18, "FightMove: error");
+
+enum PedFightMoves
+{
+ FIGHTMOVE_NULL,
+ // Attacker
+ FIGHTMOVE_STDPUNCH,
+ FIGHTMOVE_IDLE,
+ FIGHTMOVE_SHUFFLE_F,
+ FIGHTMOVE_KNEE,
+ FIGHTMOVE_HEADBUTT,
+ FIGHTMOVE_PUNCHJAB,
+ FIGHTMOVE_PUNCHHOOK,
+ FIGHTMOVE_KICK,
+ FIGHTMOVE_LONGKICK,
+ FIGHTMOVE_ROUNDHOUSE,
+ FIGHTMOVE_BODYBLOW,
+ FIGHTMOVE_GROUNDKICK,
+ // Opponent
+ FIGHTMOVE_HITFRONT,
+ FIGHTMOVE_HITBACK,
+ FIGHTMOVE_HITRIGHT,
+ FIGHTMOVE_HITLEFT,
+ FIGHTMOVE_HITBODY,
+ FIGHTMOVE_HITCHEST,
+ FIGHTMOVE_HITHEAD,
+ FIGHTMOVE_HITBIGSTEP,
+ FIGHTMOVE_HITONFLOOR,
+ FIGHTMOVE_HITBEHIND,
+ FIGHTMOVE_IDLE2NORM
+};
+
enum ePedPieceTypes
{
PEDPIECE_TORSO,
@@ -209,7 +278,7 @@ public:
uint8 bRespondsToThreats : 1;
uint8 bRenderPedInCar : 1;
uint8 bChangedSeat : 1;
- uint8 m_ped_flagC10 : 1; // related with phone
+ uint8 bUpdateAnimHeading : 1;
uint8 bBodyPartJustCameOff : 1;
uint8 m_ped_flagC40 : 1;
uint8 m_ped_flagC80 : 1;
@@ -219,16 +288,16 @@ public:
uint8 m_ped_flagD4 : 1;
uint8 m_ped_flagD8 : 1;
uint8 bIsPedDieAnimPlaying : 1;
- uint8 m_ped_flagD20 : 1;
+ uint8 bIsFleeing : 1;
uint8 m_ped_flagD40 : 1; // reset when objective changes
- uint8 m_bScriptObjectiveCompleted : 1;
+ uint8 bScriptObjectiveCompleted : 1;
- uint8 m_ped_flagE1 : 1;
+ uint8 bKindaStayInSamePlace : 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; // getup complete?
+ uint8 bGetUpAnimStarted : 1;
uint8 bDoBloodyFootprints : 1;
uint8 m_ped_flagE80 : 1;
@@ -253,17 +322,17 @@ public:
uint8 m_ped_flagH1 : 1;
uint8 m_ped_flagH2 : 1;
uint8 m_ped_flagH4 : 1;
- uint8 m_ped_flagH8 : 1;
+ uint8 bClearObjective : 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; // if set, limbs won't came off
+ uint8 bNoCriticalHits : 1; // if set, limbs won't came off
uint8 m_ped_flagI4 : 1;
uint8 bHasAlreadyBeenRecorded : 1;
- uint8 m_ped_flagI10 : 1;
+ uint8 bIsFell : 1;
uint8 m_ped_flagI20 : 1;
uint8 m_ped_flagI40 : 1;
uint8 m_ped_flagI80 : 1;
@@ -283,7 +352,7 @@ public:
uint32 m_pedFormation;
uint32 m_fearFlags;
CEntity *m_threatEntity;
- CVector2D m_eventOrThread;
+ CVector2D m_eventOrThreat;
uint32 m_eventType;
CEntity* m_pEventEntity;
float m_fAngleToEvent;
@@ -299,8 +368,8 @@ public:
PedState m_nPedState;
PedState m_nLastPedState;
eMoveState m_nMoveState;
- int32 m_nStoredActionState;
- int32 m_nPrevActionState;
+ int32 m_nStoredMoveState;
+ int32 m_nPrevMoveState;
eWaitState m_nWaitState;
uint32 m_nWaitTimer;
void *m_pPathNodesStates[8]; // seems unused
@@ -336,7 +405,7 @@ public:
bool bInVehicle;
uint8 pad_315[3];
float field_318;
- uint8 field_31C; // may be cutscene or phone cutscene status
+ bool bRunningToPhone;
uint8 field_31D;
int16 m_phoneId;
uint32 m_lookingForPhone; // unused
@@ -363,11 +432,12 @@ public:
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;
+ PedFightMoves m_lastFightMove;
+ uint8 m_fightButtonPressure;
+ int8 m_fightUnk2; // TODO
+ uint8 m_fightUnk1; // TODO
+ uint8 pad_4B3;
+ CFire *m_pFire;
CEntity *m_pLookTarget;
float m_fLookDirection;
int32 m_wepModelID;
@@ -382,18 +452,18 @@ public:
uint32 m_duckTimer;
uint32 field_4E8;
int32 m_bloodyFootprintCount;
- uint8 stuff9[2];
+ uint8 m_panicCounter;
+ uint8 m_deadBleeding;
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;
+ uint32 m_lastSoundStart;
+ uint32 m_soundStart;
+ uint16 m_lastQueuedSound;
+ uint16 m_queuedSound;
CVector m_vecSeekPosEx;
float m_seekExAngle;
@@ -503,11 +573,27 @@ public:
void SetAimFlag(float angle);
void SetAmmo(eWeaponType weaponType, uint32 ammo);
void SetEvasiveStep(CEntity*, uint8);
+ void GrantAmmo(eWeaponType, uint32);
+ void SetEvasiveDive(CPhysical*, uint8);
+ void SetAttack(CEntity*);
+ void StartFightAttack(uint8);
+ void LoadFightData(void);
+ void SetWaitState(eWaitState, void*);
+ bool FightStrike(CVector&);
+ int GetLocalDirection(CVector2D&);
+ void StartFightDefend(uint8, uint8, uint8);
+ void PlayHitSound(CPed*);
+ void SetFall(int, AnimationId, uint8);
+ void SetFlee(CEntity*, int);
+ void SetFlee(CVector2D&, int);
+ void RemoveInCarAnims(void);
+ void CollideWithPed(CPed*);
+ void SetDirectionToWalkAroundObject(CEntity*);
// 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);
+ static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset);
+ static CVector GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult);
+ static CVector GetPositionToOpenCarDoor(CVehicle* veh, uint32 component);
// Callbacks
static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data);
@@ -577,6 +663,9 @@ public:
static bool &bPedCheat2;
static bool &bPedCheat3;
static CColPoint &ms_tempColPoint;
+ static uint16 &unknownFightThing; // TODO
+ static FightMove (&ms_fightMoves)[24];
+ static CPedAudioData (&PedAudioData)[38];
};
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp
index 3d5bcfb5..8909fcc4 100644
--- a/src/peds/PedIK.cpp
+++ b/src/peds/PedIK.cpp
@@ -8,6 +8,7 @@ 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); }
+// TODO: Hardcoded into exe, reverse it.
LimbMovementInfo &CPedIK::ms_torsoInfo = *(LimbMovementInfo*)0x5F9F8C;
CPedIK::CPedIK(CPed *ped)
@@ -104,8 +105,7 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination)
return destination;
}
-// A helper function that adjusts "limb" parameter according to limitations. Doesn't move the limb.
-int8
+uint32
CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo)
{
int result = 1;
diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h
index 5f321280..a8d9c75d 100644
--- a/src/peds/PedIK.h
+++ b/src/peds/PedIK.h
@@ -47,7 +47,7 @@ public:
void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll);
void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*);
void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*);
- int8 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4);
+ uint32 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4);
bool RestoreGunPosn(void);
};
static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error");
diff --git a/src/render/Coronas.cpp b/src/render/Coronas.cpp
index 5ac9b149..1a6cfea3 100644
--- a/src/render/Coronas.cpp
+++ b/src/render/Coronas.cpp
@@ -203,7 +203,7 @@ CCoronas::RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 al
}
void
-CCoronas::UpdateCoronaCoors(int id, const CVector &coors, float drawDist, float someAngle)
+CCoronas::UpdateCoronaCoors(uint32 id, const CVector &coors, float drawDist, float someAngle)
{
int i;
diff --git a/src/render/Coronas.h b/src/render/Coronas.h
index ed69b1e6..359a34ed 100644
--- a/src/render/Coronas.h
+++ b/src/render/Coronas.h
@@ -93,7 +93,7 @@ public:
static void RegisterCorona(uint32 id, uint8 red, uint8 green, uint8 blue, uint8 alpha,
const CVector &coors, float size, float drawDist, uint8 type,
int8 flareType, uint8 reflection, uint8 LOScheck, uint8 drawStreak, float someAngle);
- static void UpdateCoronaCoors(int id, const CVector &coors, float drawDist, float someAngle);
+ static void UpdateCoronaCoors(uint32 id, const CVector &coors, float drawDist, float someAngle);
static void Render(void);
static void RenderReflections(void);
static void DoSunAndMoon(void);
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 7bf4593f..77489e60 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -359,10 +359,10 @@ CRenderer::SetupEntityVisibility(CEntity *ent)
ent->GetModelIndex() == MI_RHINO ||
ent->GetModelIndex() == MI_COACH ||
TheCamera.m_bInATunnelAndABigVehicle){
- ent->m_flagD40 = true;
+ ent->bNoBrightHeadLights = true;
}else{
m_pFirstPersonVehicle = (CVehicle*)ent;
- ent->m_flagD40 = false;
+ ent->bNoBrightHeadLights = false;
}
return VIS_OFFSCREEN;
}else{
diff --git a/src/render/Shadows.h b/src/render/Shadows.h
index 585518ee..c12327b1 100644
--- a/src/render/Shadows.h
+++ b/src/render/Shadows.h
@@ -177,3 +177,4 @@ public:
extern RwTexture *&gpBloodPoolTex;
extern RwTexture *&gpShadowExplosionTex;
+extern RwTexture *&gpShadowHeadLightsTex;
diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp
index fd5e7d2b..bbadd54c 100644
--- a/src/render/Skidmarks.cpp
+++ b/src/render/Skidmarks.cpp
@@ -5,3 +5,4 @@
WRAPPER void CSkidmarks::Clear(void) { EAXJMP(0x518130); }
WRAPPER void CSkidmarks::Render(void) { EAXJMP(0x5182E0); }
+WRAPPER void CSkidmarks::RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy) { EAXJMP(0x5185C0); }
diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h
index d1e1d996..280150a7 100644
--- a/src/render/Skidmarks.h
+++ b/src/render/Skidmarks.h
@@ -5,4 +5,5 @@ class CSkidmarks
public:
static void Clear(void);
static void Render(void);
+ static void RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy);
};
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 4fa2677a..bed5af50 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -11,5 +11,6 @@ CBulletTrace (&CBulletTraces::aTraces)[16] = *(CBulletTrace(*)[16])*(uintptr*)0x
WRAPPER void CBulletTraces::Init(void) { EAXJMP(0x518DE0); }
+WRAPPER void CBrightLights::RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1, uint8 unk2, uint8 unk3) { EAXJMP(0x51A410); }
WRAPPER void C3dMarkers::PlaceMarkerSet(uint32 id, uint16 type, CVector& pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate) { EAXJMP(0x51BB80); } \ No newline at end of file
diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h
index 08f0f08a..9c61c0fb 100644
--- a/src/render/SpecialFX.h
+++ b/src/render/SpecialFX.h
@@ -29,8 +29,15 @@ public:
static void Init(void);
};
+class CBrightLights
+{
+public:
+ static void RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1 = 0, uint8 unk2 = 0, uint8 unk3 = 0);
+};
+
class C3dMarkers
{
public:
static void PlaceMarkerSet(uint32 id, uint16 type, CVector& pos, float size, uint8 r, uint8 g, uint8 b, uint8 a, uint16 pulsePeriod, float pulseFraction, int16 rotateRate);
-}; \ No newline at end of file
+};
+
diff --git a/src/render/WaterCannon.cpp b/src/render/WaterCannon.cpp
index afb40f6f..9398c847 100644
--- a/src/render/WaterCannon.cpp
+++ b/src/render/WaterCannon.cpp
@@ -2,4 +2,5 @@
#include "patcher.h"
#include "WaterCannon.h"
+WRAPPER void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir) { EAXJMP(0x522470); }
WRAPPER void CWaterCannons::Render(void) { EAXJMP(0x522550); }
diff --git a/src/render/WaterCannon.h b/src/render/WaterCannon.h
index 1a18e75f..55949803 100644
--- a/src/render/WaterCannon.h
+++ b/src/render/WaterCannon.h
@@ -3,5 +3,6 @@
class CWaterCannons
{
public:
+ static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
static void Render(void);
};
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index ac0460f1..04b89803 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -2265,9 +2265,6 @@ HRESULT _InputInitialiseMouse()
return S_OK;
}
-//#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
-//#define FAILED(Status) ((HRESULT)(Status)<0)
-
RwV2d leftStickPos;
RwV2d rightStickPos;
@@ -2275,15 +2272,20 @@ HRESULT CapturePad(RwInt32 padID)
{
HRESULT hr;
DIJOYSTATE2 js;
- LPDIRECTINPUTDEVICE8 pPad = nil;
-
- pPad = ( padID == 0 ) ? PSGLOBAL(joy1) : PSGLOBAL(joy2);
+ LPDIRECTINPUTDEVICE8 *pPad = nil;
+
+ if( padID == 0 )
+ pPad = &PSGLOBAL(joy1);
+ else if( padID == 1)
+ pPad = &PSGLOBAL(joy2);
+ else
+ assert("invalid padID");
- if ( nil == pPad )
+ if ( nil == (*pPad) )
return S_OK;
// Poll the device to read the current state
- hr = pPad->Poll();
+ hr = (*pPad)->Poll();
if( FAILED(hr) )
{
@@ -2291,9 +2293,9 @@ HRESULT CapturePad(RwInt32 padID)
// interrupted. We aren't tracking any state between polls, so
// we don't have any special reset that needs to be done. We
// just re-acquire and try again.
- hr = pPad->Acquire();
+ hr = (*pPad)->Acquire();
while( hr == DIERR_INPUTLOST )
- hr = pPad->Acquire();
+ hr = (*pPad)->Acquire();
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
@@ -2302,26 +2304,26 @@ HRESULT CapturePad(RwInt32 padID)
if( FAILED(hr) )
return hr;
- hr = pPad->Poll();
+ hr = (*pPad)->Poll();
if( FAILED(hr) )
return hr;
}
// Get the input's device state
- if( FAILED( hr = pPad->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
+ if( FAILED( hr = (*pPad)->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
return hr; // The device should have been acquired during the Poll()
- if ( ControlsManager.field_0 == true )
+ if ( ControlsManager.firstCapture == true )
{
memcpy(&ControlsManager.m_OldState, &js, sizeof(DIJOYSTATE2));
memcpy(&ControlsManager.m_NewState, &js, sizeof(DIJOYSTATE2));
- ControlsManager.field_0 = false;
+ ControlsManager.firstCapture = false;
}
else
{
memcpy(&ControlsManager.m_OldState, &ControlsManager.m_NewState, sizeof(DIJOYSTATE2));
- memcpy(&ControlsManager.m_NewState, &js, sizeof(DIJOYSTATE2));
+ memcpy(&ControlsManager.m_NewState, &js, sizeof(DIJOYSTATE2));
}
RsPadButtonStatus bs;
@@ -2329,14 +2331,14 @@ HRESULT CapturePad(RwInt32 padID)
RsPadEventHandler(rsPADBUTTONUP, (void *)&bs);
- bool deviceAvailable = pPad != nil;
+ bool deviceAvailable = (*pPad) != nil;
if ( deviceAvailable )
{
leftStickPos.x = (float)js.lX / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
leftStickPos.y = (float)js.lY / (float)((DEVICE_AXIS_MAX - DEVICE_AXIS_MIN) / 2);
- if (LOWORD(js.rgdwPOV[0]) != -1)
+ if (LOWORD(js.rgdwPOV[0]) != 0xFFFF)
{
float angle = DEGTORAD((float)js.rgdwPOV[0] / 100.0f);
@@ -2548,40 +2550,49 @@ BOOL CALLBACK _InputEnumDevicesCallback( const DIDEVICEINSTANCE* pdidInstance, V
static INT Count = 0;
- LPDIRECTINPUTDEVICE8 pJoystick = nil;
+ LPDIRECTINPUTDEVICE8 *pJoystick = nil;
if ( Count == 0 )
- pJoystick = PSGLOBAL(joy1);
+ pJoystick = &PSGLOBAL(joy1);
else if ( Count == 1 )
- pJoystick = PSGLOBAL(joy2);
+ pJoystick = &PSGLOBAL(joy2);
+ else
+ assert("too many pads");
// Obtain an interface to the enumerated joystick.
- hr = PSGLOBAL(dinterface)->CreateDevice( pdidInstance->guidInstance, &pJoystick, nil );
+ hr = PSGLOBAL(dinterface)->CreateDevice( pdidInstance->guidInstance, pJoystick, nil );
// If it failed, then we can't use this joystick. (Maybe the user unplugged
// it while we were in the middle of enumerating it.)
- if( FAILED(hr) )
+ if( hr != S_OK )
return DIENUM_CONTINUE;
-
- if( FAILED( hr = pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )
+
+ hr = (*pJoystick)->SetDataFormat( &c_dfDIJoystick2 );
+ if( hr != S_OK )
{
- pJoystick->Release();
+ (*pJoystick)->Release();
return DIENUM_CONTINUE;
}
++Count;
-
- if( FAILED( hr = pJoystick->SetCooperativeLevel( PSGLOBAL(window), DISCL_NONEXCLUSIVE) ) )
+
+ hr = (*pJoystick)->SetCooperativeLevel( PSGLOBAL(window), DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
+ if( hr != S_OK )
{
- pJoystick->Release();
+ (*pJoystick)->Release();
+#ifdef FIX_BUGS
+ // BUG: enum will be called with Count == 2, which will write to a null pointer
+ // So decrement count again since we're not using this pad
+ --Count;
+#endif
return DIENUM_CONTINUE;
}
+ // Stop enumeration. Note: we're just taking the first two joysticks we get. You
+ // could store all the enumerated joysticks and let the user pick.
if ( Count == 2 )
return DIENUM_STOP;
- // Stop enumeration. Note: we're just taking the first joystick we get. You
- // could store all the enumerated joysticks and let the user pick.
return DIENUM_CONTINUE;
}
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index fb42e6e6..28ede4cd 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -7,14 +7,28 @@
#include "ModelIndices.h"
#include "VisibilityPlugins.h"
#include "DMAudio.h"
+#include "Clock.h"
+#include "TimeCycle.h"
+#include "ZoneCull.h"
#include "Camera.h"
#include "Darkel.h"
#include "Rubbish.h"
#include "Fire.h"
#include "Explosion.h"
#include "Particle.h"
+#include "ParticleObject.h"
+#include "Antennas.h"
+#include "Skidmarks.h"
+#include "Shadows.h"
+#include "PointLights.h"
+#include "Coronas.h"
+#include "SpecialFX.h"
+#include "WaterCannon.h"
+#include "WaterLevel.h"
+#include "Floater.h"
#include "World.h"
#include "SurfaceTable.h"
+#include "Weather.h"
#include "HandlingMgr.h"
#include "Record.h"
#include "Remote.h"
@@ -49,7 +63,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
bTaxiLight = m_sAllTaxiLights;
m_auto_flagA20 = false;
m_auto_flagA40 = false;
- m_auto_flagA80 = false;
+ bWaterTight = false;
SetModelIndex(id);
@@ -118,7 +132,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
bNotDamagedUpsideDown = false;
bMoreResistantToDamage = false;
m_fVelocityChangeForAudio = 0.f;
- field_4E2 = 0;
+ m_hydraulicState = 0;
for(i = 0; i < 4; i++){
m_aGroundPhysical[i] = nil;
@@ -128,7 +142,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_aWheelTimer[i] = 0.0f;
m_aWheelRotation[i] = 0.0f;
m_aWheelSpeed[i] = 0.0f;
- m_aWheelState[i] = WHEEL_STATE_0;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
m_aWheelSkidmarkMuddy[i] = false;
m_aWheelSkidmarkBloody[i] = false;
}
@@ -162,7 +176,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fCarGunLR = 0.0f;
m_fCarGunUD = 0.05f;
- m_fWindScreenRotation = 0.0f;
+ m_fPropellerRotation = 0.0f;
m_weaponDoorTimerLeft = 0.0f;
m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
@@ -201,7 +215,7 @@ CAutomobile::ProcessControl(void)
int i;
CColModel *colModel;
- if(m_veh_flagC80)
+ if(bUsingSpecialColModel)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
@@ -358,7 +372,7 @@ CAutomobile::ProcessControl(void)
pHandling->Transmission.CalculateGearForSimpleCar(AutoPilot.m_fMaxTrafficSpeed/50.0f, m_nCurrentGear);
{
- float wheelRot = ProcessWheelRotation(WHEEL_STATE_0, GetForward(), m_vecMoveSpeed, 0.35f);
+ float wheelRot = ProcessWheelRotation(WHEEL_STATE_NORMAL, GetForward(), m_vecMoveSpeed, 0.35f);
for(i = 0; i < 4; i++)
m_aWheelRotation[i] += wheelRot;
}
@@ -484,7 +498,7 @@ CAutomobile::ProcessControl(void)
m_aSuspensionSpringRatio[0] < 1.0f &&
CPad::GetPad(0)->HornJustDown()){
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRALIC_1, 0.0f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, 1.0f);
CParticle::AddParticle(PARTICLE_ENGINE_STEAM,
@@ -1179,10 +1193,6 @@ CAutomobile::ProcessControl(void)
m_vecTurnSpeed.z = 0.0f;
}
}
-
-// TEMP
-if(pDriver)
- pDriver->m_fHealth = 100.0f;
}
void
@@ -1200,9 +1210,911 @@ CAutomobile::Teleport(CVector pos)
CWorld::Add(this);
}
-WRAPPER void CAutomobile::PreRender(void) { EAXJMP(0x535B40); }
-WRAPPER void CAutomobile::Render(void) { EAXJMP(0x539EA0); }
+void
+CAutomobile::PreRender(void)
+{
+ int i, j, n;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f);
+ CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f);
+ }
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward())*180.0f;
+
+
+ // Wheel particles
+
+ if(GetModelIndex() == MI_DODO){
+ ; // nothing
+ }else if(GetModelIndex() == MI_RCBANDIT){
+ for(i = 0; i < 4; i++){
+ // Game has same code three times here
+ switch(m_aWheelState[i]){
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.05f),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.1f);
+ break;
+ }
+ }
+ }else{
+ if(m_status == STATUS_SIMPLE){
+ CMatrix mat;
+ CVector pos;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_REAR_RIGHT];
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_REAR_LEFT];
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB = SURFACE_DEFAULT;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ pos = mat.GetPosition();
+ pos.z = 1.5f*m_aWheelPosition[CARWHEEL_FRONT_LEFT];
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point = GetMatrix() * pos;
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB = SURFACE_DEFAULT;
+ }
+
+ int drawParticles = Abs(fwdSpeed) < 90.0f;
+ if(m_status == STATUS_SIMPLE || m_status == STATUS_PHYSICS ||
+ m_status == STATUS_PLAYER || m_status == STATUS_PLAYER_PLAYBACKFROMBUFFER){
+ bool rearSkidding = false;
+ if(m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SKIDDING ||
+ m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SKIDDING)
+ rearSkidding = true;
+
+ for(i = 0; i < 4; i++){
+ switch(m_aWheelState[i]){
+ case WHEEL_STATE_SPINNING:
+ if(AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles)){
+ CParticle::AddParticle(PARTICLE_BURNINGRUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_BURNINGRUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.05f));
+ }
+
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[i] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ break;
+
+ case WHEEL_STATE_SKIDDING:
+ if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT || rearSkidding){
+ // same as below
+
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[i] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ }
+ break;
+
+ case WHEEL_STATE_FIXED:
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[i] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ break;
+
+ default:
+ if(Abs(fwdSpeed) > 0.5f)
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(m_aWheelSkidmarkBloody[i] && m_aWheelTimer[i] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ }
+ }
+ }
+ }
+
+ if(m_aCarNodes[CAR_WHEEL_RM]){
+ // assume middle wheels are two units before rear ones
+ CVector offset = GetForward()*2.0f;
+
+ switch(m_aWheelState[CARWHEEL_REAR_LEFT]){
+ // Game has same code three times here
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + CVector(0.0f, 0.0f, 0.25f) + offset,
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_LEFT,
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + offset,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]);
+ break;
+ }
+
+ switch(m_aWheelState[CARWHEEL_REAR_RIGHT]){
+ // Game has same code three times here
+ case WHEEL_STATE_SPINNING:
+ case WHEEL_STATE_SKIDDING:
+ case WHEEL_STATE_FIXED:
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + CVector(0.0f, 0.0f, 0.25f) + offset,
+ CVector(0.0f, 0.0f, 0.0f));
+
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f)
+ CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_RIGHT,
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + offset,
+ GetForward().x, GetForward().y,
+ &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]);
+ break;
+ }
+ }
+
+
+ // Rain on roof
+ if(!CCullZones::CamNoRain() && !CCullZones::PlayerNoRain() &&
+ Abs(fwdSpeed) < 20.0f && CWeather::Rain > 0.02f){
+ CColModel *colModel = GetColModel();
+
+ for(i = 0; i < colModel->numTriangles; i++){
+ CVector p1, p2, p3, c;
+
+ colModel->GetTrianglePoint(p1, colModel->triangles[i].a);
+ p1 = GetMatrix() * p1;
+ colModel->GetTrianglePoint(p2, colModel->triangles[i].b);
+ p2 = GetMatrix() * p2;
+ colModel->GetTrianglePoint(p3, colModel->triangles[i].c);
+ p3 = GetMatrix() * p3;
+ c = (p1 + p2 + p3)/3.0f;
+
+ n = 6.0f*CWeather::Rain;
+ for(j = 0; j <= n; j++)
+ CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP,
+ c + CVector(CGeneral::GetRandomNumberInRange(-.04f, 0.4f), CGeneral::GetRandomNumberInRange(-.04f, 0.4f), 0.0f),
+ CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1);
+ }
+ }
+
+ AddDamagedVehicleParticles();
+
+ // Exhaust smoke
+ if(bEngineOn && fwdSpeed < 90.0f){
+ CVector exhaustPos = mi->m_positions[CAR_POS_EXHAUST];
+ CVector pos1, pos2, dir;
+
+ if(exhaustPos != CVector(0.0f, 0.0f, 0.0f)){
+ dir.z = 0.0f;
+ if(fwdSpeed < 10.0f){
+ CVector steerFwd(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f);
+ steerFwd = Multiply3x3(GetMatrix(), steerFwd);
+ float r = CGeneral::GetRandomNumberInRange(-0.06f, -0.03f);
+ dir.x = steerFwd.x * r;
+ dir.y = steerFwd.y * r;
+ }else{
+ dir.x = m_vecMoveSpeed.x;
+ dir.y = m_vecMoveSpeed.y;
+ }
+
+ bool dblExhaust = false;
+ pos1 = GetMatrix() * exhaustPos;
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST){
+ dblExhaust = true;
+ pos2 = exhaustPos;
+ pos2.x = -pos2.x;
+ pos2 = GetMatrix() * pos2;
+ }
+
+ n = 4.0f*m_fGasPedal;
+ if(dblExhaust)
+ for(i = 0; i <= n; i++){
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir);
+ }
+ else
+ for(i = 0; i <= n; i++)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
+ }
+ }
+
+
+ // Siren and taxi lights
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ case MI_AMBULAN:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ if(m_bSirenOrAlarm){
+ CVector pos1, pos2;
+ uint8 r1, g1, b1;
+ uint8 r2, g2, b2;
+ uint8 r, g, b;
+
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ pos1 = CVector(1.1f, 1.7f, 2.0f);
+ pos2 = CVector(-1.1f, 1.7f, 2.0f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 255; g2 = 255; b2 = 0;
+ break;
+ case MI_AMBULAN:
+ pos1 = CVector(1.1f, 0.9f, 1.6f);
+ pos2 = CVector(-1.1f, 0.9f, 1.6f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 255; g2 = 255; b2 = 255;
+ break;
+ case MI_POLICE:
+ pos1 = CVector(0.7f, -0.4f, 1.0f);
+ pos2 = CVector(-0.7f, -0.4f, 1.0f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 0; g2 = 0; b2 = 255;
+ break;
+ case MI_ENFORCER:
+ pos1 = CVector(1.1f, 0.8f, 1.2f);
+ pos2 = CVector(-1.1f, 0.8f, 1.2f);
+ r1 = 255; g1 = 0; b1 = 0;
+ r2 = 0; g2 = 0; b2 = 255;
+ break;
+ }
+
+ uint32 t = CTimer::GetTimeInMilliseconds() & 0x3FF; // 1023
+ if(t < 512){
+ r = r1/6;
+ g = g1/6;
+ b = b1/6;
+ }else{
+ r = r2/6;
+ g = g2/6;
+ b = b2/6;
+ }
+
+ t = CTimer::GetTimeInMilliseconds() & 0x1FF; // 511
+ if(t < 100){
+ float f = t/100.0f;
+ r *= f;
+ g *= f;
+ b *= f;
+ }else if(t > 412){
+ float f = (512-t)/100.0f;
+ r *= f;
+ g *= f;
+ b *= f;
+ }
+
+ CVector pos = GetPosition();
+ float angle = (CTimer::GetTimeInMilliseconds() & 0x3FF)*TWOPI/0x3FF;
+ float s = 8.0f*Sin(angle);
+ float c = 8.0f*Cos(angle);
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex,
+ &pos, c, s, s, -c, r, g, b, 8.0f);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos + GetUp()*2.0f, CVector(0.0f, 0.0f, 0.0f), 12.0f,
+ r*0.02f, g*0.02f, b*0.02f, CPointLights::FOG_NONE, true);
+
+ pos1 = GetMatrix() * pos1;
+ pos2 = GetMatrix() * pos2;
+
+ for(i = 0; i < 4; i++){
+ uint8 sirenTimer = ((CTimer::GetTimeInMilliseconds() + (i<<6))>>8) & 3;
+ pos = (pos1*i + pos2*(3.0f-i))/3.0f;
+
+ switch(sirenTimer){
+ case 0:
+ CCoronas::RegisterCorona((uintptr)this + 21 + i,
+ r1, g1, b1, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ i == 1 ? CCoronas::FLARE_HEADLIGHTS : CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ break;
+ case 2:
+ CCoronas::RegisterCorona((uintptr)this + 21 + i,
+ r2, g2, b2, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ break;
+ default:
+ CCoronas::UpdateCoronaCoors((uintptr)this + 21 + i, pos, 50.0f, 0.0f);
+ break;
+ }
+ }
+ }
+ break;
+
+ case MI_FBICAR:
+ if(m_bSirenOrAlarm){
+ CVector pos = GetMatrix() * CVector(0.4f, 0.6f, 0.3f);
+ if(CTimer::GetTimeInMilliseconds() & 0x100 &&
+ DotProduct(GetForward(), GetPosition() - TheCamera.GetPosition()) < 0.0f)
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 0, 0, 255, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::UpdateCoronaCoors((uintptr)this + 21, pos, 50.0f, 0.0f);
+ }
+ break;
+
+ case MI_TAXI:
+ case MI_CABBIE:
+ case MI_BORGNINE:
+ if(bTaxiLight){
+ CVector pos = GetPosition() + GetUp()*0.95f;
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 128, 128, 0, 255,
+ pos, 0.8f, 50.0f,
+ CCoronas::TYPE_NORMAL,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f), 10.0f,
+ 1.0f, 1.0f, 0.5f, CPointLights::FOG_NONE, true);
+ }
+ break;
+ }
+
+ if(GetModelIndex() == MI_RCBANDIT ||
+ GetModelIndex() == MI_DODO ||
+ GetModelIndex() == MI_RHINO)
+ goto nolights;
+
+ // Turn lights on/off
+ bool shouldLightsBeOn =
+ CClock::GetHours() > 20 ||
+ CClock::GetHours() > 19 && CClock::GetMinutes() > (m_randomSeed & 0x3F) ||
+ CClock::GetHours() < 7 ||
+ CClock::GetHours() < 8 && CClock::GetMinutes() < (m_randomSeed & 0x3F) ||
+ m_randomSeed/50000.0f < CWeather::Foggyness ||
+ m_randomSeed/50000.0f < CWeather::WetRoads;
+ if(shouldLightsBeOn != bLightsOn && m_status != STATUS_WRECKED){
+ if(m_status == STATUS_ABANDONED){
+ // Turn off lights on abandoned vehicles only when we they're far away
+ if(bLightsOn &&
+ Abs(TheCamera.GetPosition().x - GetPosition().x) + Abs(TheCamera.GetPosition().y - GetPosition().y) > 100.0f)
+ bLightsOn = false;
+ }else
+ bLightsOn = shouldLightsBeOn;
+ }
+
+ // Actually render the lights
+ bool alarmOn = false;
+ bool alarmOff = false;
+ if(IsAlarmOn()){
+ if(CTimer::GetTimeInMilliseconds() & 0x100)
+ alarmOn = true;
+ else
+ alarmOff = true;
+ }
+ if(bEngineOn && bLightsOn || alarmOn || alarmOff){
+ CVector lookVector = GetPosition() - TheCamera.GetPosition();
+ float camDist = lookVector.Magnitude();
+ if(camDist != 0.0f)
+ lookVector *= 1.0f/camDist;
+ else
+ lookVector = CVector(1.0f, 0.0f, 0.0f);
+
+ // 1.0 if directly behind car, -1.0 if in front
+ // BUG on PC: Abs of DotProduct is taken
+ float behindness = DotProduct(lookVector, GetForward());
+ behindness = clamp(behindness, -1.0f, 1.0f); // shouldn't be necessary
+ // 0.0 if behind car, PI if in front
+ // Abs not necessary
+ float angle = Abs(Acos(behindness));
+
+ // Headlights
+
+ CVector headLightPos = mi->m_positions[CAR_POS_HEADLIGHTS];
+ CVector lightR = GetMatrix() * headLightPos;
+ CVector lightL = lightR;
+ lightL -= GetRight()*2.0f*headLightPos.x;
+
+ // Headlight coronas
+ if(behindness < 0.0f){
+ // In front of car
+ float intensity = -0.5f*behindness + 0.3f;
+ float size = 1.0f - behindness;
+
+ if(behindness < -0.97f && camDist < 30.0f){
+ // Directly in front and not too far away
+ if(pHandling->Flags & HANDLING_HALOGEN_LIGHTS){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 6, 150, 150, 195, 255,
+ lightL, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 7, 150, 150, 195, 255,
+ lightR, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 6, 160, 160, 140, 255,
+ lightL, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 7, 160, 160, 140, 255,
+ lightR, 1.2f, 45.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_HEADLIGHT, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, angle);
+ }
+ }
+
+ if(alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 0, 0, 0, 0,
+ lightL, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 0, 0, 0, 0,
+ lightR, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(pHandling->Flags & HANDLING_HALOGEN_LIGHTS){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 190*intensity, 190*intensity, 255*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 190*intensity, 190*intensity, 255*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this, 210*intensity, 210*intensity, 195*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 1, 210*intensity, 210*intensity, 195*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }
+ }
+ }else{
+ // Behind car
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this, lightL, 50.0f*TheCamera.LODDistMultiplier, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 1, lightR, 50.0f*TheCamera.LODDistMultiplier, angle);
+ }
+
+ // bright lights
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4);
+
+ // Taillights
+
+ CVector tailLightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
+ lightR = GetMatrix() * tailLightPos;
+ lightL = lightR;
+ lightL -= GetRight()*2.0f*tailLightPos.x;
+
+ // Taillight coronas
+ if(behindness > 0.0f){
+ // Behind car
+ float intensity = 0.4f*behindness + 0.4;
+ float size = (behindness + 1.0f)/2.0f;
+
+ if(m_fGasPedal < 0.0f){
+ // reversing
+ intensity += 0.4f;
+ size += 0.3f;
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 128*intensity, 128*intensity, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 128*intensity, 128*intensity, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(m_fBrakePedal > 0.0){
+ intensity += 0.4f;
+ size += 0.3f;
+ }
+
+ if(alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 0, 0, 0, 0,
+ lightL, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 0, 0, 0, 0,
+ lightR, size, 0.0f,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 0, 0, 255,
+ lightL, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 0, 0, 255,
+ lightR, size, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
+ }
+ }
+ }else{
+ // In front of car
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, angle);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, angle);
+ }
+
+ // bright lights
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+
+ // Light shadows
+ if(!alarmOff){
+ CVector pos = GetPosition();
+ CVector2D fwd(GetForward());
+ fwd.Normalise();
+ float f = headLightPos.y + 6.0f;
+ pos += CVector(f*fwd.x, f*fwd.y, 2.0f);
+
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
+ 7.0f*fwd.x, 7.0f*fwd.y, 7.0f*fwd.y, -7.0f*fwd.x, 45, 45, 45, 7.0f);
+
+ f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f);
+ pos += CVector(f*fwd.x, f*fwd.y, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowExplosionTex, &pos,
+ 3.0f, 0.0f, 0.0f, -3.0f, 35, 0, 0, 4.0f);
+ }
+
+ if(this == FindPlayerVehicle() && !alarmOff){
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CPointLights::AddLight(CPointLights::LIGHT_DIRECTIONAL, GetPosition(), GetForward(),
+ 20.0f, 1.0f, 1.0f, 1.0f,
+ FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.45f) ? CPointLights::FOG_NORMAL : CPointLights::FOG_NONE,
+ false);
+ CVector pos = GetPosition() - 4.0f*GetForward();
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK ||
+ Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ if(m_fBrakePedal > 0.0f)
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
+ 10.0f, 1.0f, 0.0f, 0.0f,
+ CPointLights::FOG_NONE, false);
+ else
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
+ 7.0f, 0.6f, 0.0f, 0.0f,
+ CPointLights::FOG_NONE, false);
+ }
+ }else{
+ // Lights off
+
+ if(m_status == STATUS_ABANDONED || m_status == STATUS_WRECKED)
+ goto nolights;
+
+ CVector lightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
+ CVector lightR = GetMatrix() * lightPos;
+ CVector lightL = lightR;
+ lightL -= GetRight()*2.0f*lightPos.x;
+
+ if(m_fBrakePedal > 0.0f || m_fGasPedal < 0.0f){
+ CVector lookVector = GetPosition() - TheCamera.GetPosition();
+ lookVector.Normalise();
+ float behindness = DotProduct(lookVector, GetForward());
+ if(behindness > 0.0f){
+ if(m_fGasPedal < 0.0f){
+ // reversing
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 120, 120, 120, 255,
+ lightL, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 120, 120, 120, 255,
+ lightR, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4);
+ }else{
+ // braking
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 2, 120, 0, 0, 255,
+ lightL, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::RegisterCorona((uintptr)this + 3, 120, 0, 0, 255,
+ lightR, 1.2f, 50.0f*TheCamera.LODDistMultiplier,
+ CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
+ CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8);
+ }
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ }
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 2, lightL, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f);
+ }
+ }
+
+nolights:
+ CShadows::StoreShadowForCar(this);
+}
+
+void
+CAutomobile::Render(void)
+{
+ int i;
+ CMatrix mat;
+ CVector pos;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
+ // Rhino has no bonnet...what are we doing here?
+ CMatrix m;
+ CVector p;
+ m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ p = m.GetPosition();
+ m.SetRotateZ(m_fCarGunLR);
+ m.Translate(p);
+ m.UpdateRW();
+ }
+
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ CVector frontWheelFwd = Multiply3x3(GetMatrix(), CVector(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f));
+ CVector rearWheelFwd = GetForward();
+ for(i = 0; i < 4; i++){
+ contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], frontWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ else
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], rearWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ m_aWheelRotation[i] += m_aWheelSpeed[i];
+ }
+
+ // Rear right wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
+ if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
+ else
+ mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]));
+
+ // Rear left wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
+ if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]));
+
+ // Mid right wheel
+ if(m_aCarNodes[CAR_WHEEL_RM]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
+ if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
+ else
+ mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM]));
+ }
+
+ // Mid left wheel
+ if(m_aCarNodes[CAR_WHEEL_LM]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
+ if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM]));
+ }
+
+ if(GetModelIndex() == MI_DODO){
+ // Front wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
+ if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
+ else
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+
+ // Rotate propeller
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ pos = mat.GetPosition();
+ mat.SetRotateY(m_fPropellerRotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+
+ m_fPropellerRotation += m_fGasPedal != 0.0f ? TWOPI/13.0f : TWOPI/26.0f;
+ if(m_fPropellerRotation > TWOPI)
+ m_fPropellerRotation -= TWOPI;
+ }
+
+ // Rudder
+ if(Damage.GetDoorStatus(DOOR_BOOT) != DOOR_STATUS_MISSING && m_aCarNodes[CAR_BOOT]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BOOT]));
+ pos = mat.GetPosition();
+ mat.SetRotate(0.0f, 0.0f, -m_fSteerAngle);
+ mat.Rotate(0.0f, Sin(m_fSteerAngle)*DEGTORAD(22.0f), 0.0f);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+
+ ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ }else if(GetModelIndex() == MI_RHINO){
+ // Front right wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
+ // no damaged wheels or steering
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, 0.0f);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+
+ // Front left wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
+ // no damaged wheels or steering
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+ }else{
+ // Front right wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
+ if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
+ else
+ mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+
+ // Front left wheel
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
+ pos.x = mat.GetPosition().x;
+ pos.y = mat.GetPosition().y;
+ pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
+ if(Damage.GetWheelStatus(CARWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(-m_aWheelRotation[CARWHEEL_FRONT_LEFT]));
+ else
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle);
+ mat.Scale(mi->m_wheelScale);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ if(CVehicle::bWheelsOnlyCheat)
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+
+ ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ ProcessSwingingDoor(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
+ ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
+
+ mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+ }
+
+ if(!CVehicle::bWheelsOnlyCheat)
+ CEntity::Render();
+}
int32
CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
@@ -1213,7 +2125,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
if(m_status != STATUS_SIMPLE)
bVehicleColProcessed = true;
- if(m_veh_flagC80)
+ if(bUsingSpecialColModel)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
@@ -1416,24 +2328,594 @@ CAutomobile::ProcessControlInputs(uint8 pad)
}
}
-WRAPPER void
+void
CAutomobile::FireTruckControl(void)
-{ EAXJMP(0x522590);
+{
+ if(this == FindPlayerVehicle()){
+ if(!CPad::GetPad(0)->GetWeapon())
+ return;
+ m_fCarGunLR += CPad::GetPad(0)->GetCarGunLeftRight()*0.00025f*CTimer::GetTimeStep();
+ m_fCarGunUD += CPad::GetPad(0)->GetCarGunUpDown()*0.0001f*CTimer::GetTimeStep();
+ m_fCarGunUD = clamp(m_fCarGunUD, 0.05f, 0.3f);
+
+ CVector cannonPos(0.0f, 1.5f, 1.9f);
+ cannonPos = GetMatrix() * cannonPos;
+ CVector cannonDir(
+ Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD));
+ cannonDir = Multiply3x3(GetMatrix(), cannonDir);
+ cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
+ CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
+ }else if(m_status == STATUS_PHYSICS){
+ CFire *fire = gFireManager.FindFurthestFire_NeverMindFireMen(GetPosition(), 10.0f, 35.0f);
+ if(fire == nil)
+ return;
+
+ // Target cannon onto fire
+ float targetAngle = CGeneral::GetATanOfXY(fire->m_vecPos.x-GetPosition().x, fire->m_vecPos.y-GetPosition().y);
+ float fwdAngle = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+ float targetCannonAngle = fwdAngle - targetAngle;
+ float angleDelta = CTimer::GetTimeStep()*0.01f;
+ float cannonDelta = targetCannonAngle - m_fCarGunLR;
+ while(cannonDelta < PI) cannonDelta += TWOPI;
+ while(cannonDelta > PI) cannonDelta -= TWOPI;
+ if(Abs(cannonDelta) < angleDelta)
+ m_fCarGunLR = targetCannonAngle;
+ else if(cannonDelta > 0.0f)
+ m_fCarGunLR += angleDelta;
+ else
+ m_fCarGunLR -= angleDelta;
+
+ // Go up and down a bit
+ float upDown = Sin((float)(CTimer::GetTimeInMilliseconds() & 0xFFF)/0x1000 * TWOPI);
+ m_fCarGunUD = 0.2f + 0.2f*upDown;
+
+ // Spray water every once in a while
+ if((CTimer::GetTimeInMilliseconds()>>10) & 3){
+ CVector cannonPos(0.0f, 0.0f, 2.2f); // different position than player's firetruck!
+ cannonPos = GetMatrix() * cannonPos;
+ CVector cannonDir(
+ Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD));
+ cannonDir = Multiply3x3(GetMatrix(), cannonDir);
+ cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
+ CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
+ }
+ }
}
-WRAPPER void
+void
CAutomobile::TankControl(void)
-{ EAXJMP(0x53D530);
+{
+ int i;
+
+ // These coords are 1 unit higher then they should be relative to model center
+ CVector turrentBase(0.0f, -1.394f, 2.296f);
+ CVector gunEnd(0.0f, 1.813f, 2.979f);
+ CVector baseToEnd = gunEnd - turrentBase;
+
+ if(this != FindPlayerVehicle())
+ return;
+ if(CWorld::Players[CWorld::PlayerInFocus].m_WBState != WBSTATE_PLAYING)
+ return;
+
+ // Rotate turret
+ float prevAngle = m_fCarGunLR;
+ m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
+ if(m_fCarGunLR < 0.0f)
+ m_fCarGunLR += TWOPI;
+ if(m_fCarGunLR > TWOPI)
+ m_fCarGunLR -= TWOPI;
+ if(m_fCarGunLR != prevAngle)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_TANK_TURRET_ROTATE, Abs(m_fCarGunLR - prevAngle));
+
+ // Shoot
+ if(CPad::GetPad(0)->CarGunJustDown() &&
+ CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeTankShotGun + 800){
+ CWorld::Players[CWorld::PlayerInFocus].m_nTimeTankShotGun = CTimer::GetTimeInMilliseconds();
+
+ // more like -sin(angle), cos(angle), i.e. rotated (0,1,0)
+ CVector turretDir = CVector(Sin(-m_fCarGunLR), Cos(-m_fCarGunLR), 0.0f);
+ turretDir = Multiply3x3(GetMatrix(), turretDir);
+
+ float c = Cos(m_fCarGunLR);
+ float s = Sin(m_fCarGunLR);
+ CVector rotatedEnd(
+ c*baseToEnd.x - s*baseToEnd.y,
+ s*baseToEnd.x + c*baseToEnd.y,
+ baseToEnd.z - 1.0f); // correct offset here
+ rotatedEnd += turrentBase;
+
+ CVector point1 = GetMatrix() * rotatedEnd;
+ CVector point2 = point1 + 60.0f*turretDir;
+ m_vecMoveSpeed -= 0.06f*turretDir;
+ m_vecMoveSpeed.z += 0.05f;
+
+ CWeapon::DoTankDoomAiming(FindPlayerVehicle(), FindPlayerPed(), &point1, &point2);
+ CColPoint colpoint;
+ CEntity *entity = nil;
+ CWorld::ProcessLineOfSight(point1, point2, colpoint, entity, true, true, true, true, true, true, false);
+ if(entity)
+ point2 = colpoint.point - 0.04f*(colpoint.point - point1);
+
+ CExplosion::AddExplosion(nil, FindPlayerPed(), EXPLOSION_TANK_GRENADE, point2, 0);
+
+ // Add particles on the way to the explosion;
+ float shotDist = (point2 - point1).Magnitude();
+ int n = shotDist/4.0f;
+ RwRGBA black = { 0, 0, 0, 0 };
+ for(i = 0; i < n; i++){
+ float f = (float)i/n;
+ CParticle::AddParticle(PARTICLE_HELI_DUST,
+ point1 + f*(point2 - point1),
+ CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.1f, black);
+ }
+
+ // More particles
+ CVector shotDir = point2 - point1;
+ shotDir.Normalise();
+ for(i = 0; i < 15; i++){
+ float f = i/15.0f;
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, point1,
+ shotDir*CGeneral::GetRandomNumberInRange(0.3f, 1.0f)*f,
+ nil, CGeneral::GetRandomNumberInRange(0.5f, 1.0f)*f, black);
+ }
+
+ // And some gun flashes near the gun
+ CVector flashPos = point1;
+ CVector nullDir(0.0f, 0.0f, 0.0f);
+ int lifeSpan = 250;
+ if(m_vecMoveSpeed.Magnitude() > 0.08f){
+ lifeSpan = 125;
+ flashPos.x += 0.5f*m_vecMoveSpeed.x;
+ flashPos.y += 0.5f*m_vecMoveSpeed.y;
+ }
+ CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.4f, black, 0, 0, 0, lifeSpan);
+ flashPos += 0.3f*shotDir;
+ CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.2f, black, 0, 0, 0, lifeSpan);
+ flashPos += 0.1f*shotDir;
+ CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.15f, black, 0, 0, 0, lifeSpan);
+ }
+
+ // Actually update turret node
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ CMatrix mat;
+ CVector pos;
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_fCarGunLR);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
}
-WRAPPER void
+void
CAutomobile::HydraulicControl(void)
-{ EAXJMP(0x52D4E0);
+{
+ int i;
+ float wheelPositions[4];
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ CColModel *normalColModel = mi->GetColModel();
+ float wheelRadius = 0.5f*mi->m_wheelScale;
+ CPlayerInfo *playerInfo = &CWorld::Players[CWorld::PlayerInFocus];
+ CColModel *specialColModel = &playerInfo->m_ColModel;
+
+ if(m_status != STATUS_PLAYER){
+ // reset hydraulics for non-player cars
+
+ if(!bUsingSpecialColModel)
+ return;
+ if(specialColModel != nil) // this is always true
+ for(i = 0; i < 4; i++)
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ for(i = 0; i < 4; i++){
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
+ m_aSuspensionLineLength[i] = normalColModel->lines[i].p0.z - normalColModel->lines[i].p1.z;
+ m_aSuspensionSpringRatio[i] = (normalColModel->lines[i].p0.z - wheelPositions[i]) / m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ if(m_hydraulicState == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ else if(m_hydraulicState >= 100)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+
+ if(playerInfo->m_pVehicleEx == this)
+ playerInfo->m_pVehicleEx = nil;
+ bUsingSpecialColModel = false;
+ m_hydraulicState = 0;
+ return;
+ }
+
+ // Player car
+
+ float normalUpperLimit = pHandling->fSuspensionUpperLimit;
+ float normalLowerLimit = pHandling->fSuspensionLowerLimit;
+ float normalSpringLength = normalUpperLimit - normalLowerLimit;
+ float extendedUpperLimit = normalUpperLimit - 0.2f;
+ float extendedLowerLimit = normalLowerLimit - 0.2f;
+ float extendedSpringLength = extendedUpperLimit - extendedLowerLimit;
+
+ if(!bUsingSpecialColModel){
+ // Init special col model
+
+ if(playerInfo->m_pVehicleEx && playerInfo->m_pVehicleEx == this)
+ playerInfo->m_pVehicleEx->bUsingSpecialColModel = false;
+ playerInfo->m_pVehicleEx = this;
+ playerInfo->m_ColModel = *normalColModel;
+ bUsingSpecialColModel = true;
+ specialColModel = &playerInfo->m_ColModel;
+
+ if(m_fVelocityChangeForAudio > 0.1f)
+ m_hydraulicState = 20;
+ else{
+ m_hydraulicState = 0;
+ normalUpperLimit += -0.12f;
+ normalSpringLength = normalUpperLimit - (normalLowerLimit+0.14f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+
+ // Setup suspension
+ float normalLineLength = normalSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = normalColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += normalUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= normalLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = normalSpringLength;
+ m_aSuspensionLineLength[i] = normalLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+
+ // Adjust col model
+ mi->GetWheelPosn(0, pos);
+ float minz = pos.z + extendedLowerLimit - wheelRadius;
+ if(minz < specialColModel->boundingBox.min.z)
+ specialColModel->boundingBox.min.z = minz;
+ float radius = max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude());
+ if(specialColModel->boundingSphere.radius < radius)
+ specialColModel->boundingSphere.radius = radius;
+
+ }
+
+ if(playerInfo->m_WBState != WBSTATE_PLAYING)
+ return;
+
+ bool setPrevRatio = false;
+ if(m_hydraulicState < 20 && m_fVelocityChangeForAudio > 0.2f){
+ if(m_hydraulicState == 0){
+ m_hydraulicState = 20;
+ for(i = 0; i < 4; i++)
+ m_aWheelPosition[i] -= 0.06f;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ setPrevRatio = true;
+ }else{
+ m_hydraulicState++;
+ }
+ }else if(m_hydraulicState != 0){ // must always be true
+ if(m_hydraulicState < 21 && m_fVelocityChangeForAudio < 0.1f){
+ m_hydraulicState--;
+ if(m_hydraulicState == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+ }
+
+ if(CPad::GetPad(0)->HornJustDown()){
+ // Switch between normal and extended
+
+ if(m_hydraulicState < 100)
+ m_hydraulicState = 100;
+ else{
+ if(m_fVelocityChangeForAudio > 0.1f)
+ m_hydraulicState = 20;
+ else
+ m_hydraulicState = 0;
+ }
+
+ if(m_hydraulicState < 100){
+ if(m_hydraulicState == 0){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Reset suspension to normal
+ float normalLineLength = normalSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += normalUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= normalLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = normalSpringLength;
+ m_aSuspensionLineLength[i] = normalLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }else{
+ // Reset suspension to extended
+ float extendedLineLength = extendedSpringLength + wheelRadius;
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += extendedUpperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= extendedLineLength;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = extendedSpringLength;
+ m_aSuspensionLineLength[i] = extendedLineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+
+ setPrevRatio = true;
+ m_aWheelPosition[i] -= 0.05f;
+ }
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ }
+ }else{
+ float suspChange[4];
+ float maxDelta = 0.0f;
+ float rear = CPad::GetPad(0)->GetCarGunUpDown()/128.0f;
+ float front = -rear;
+ float right = CPad::GetPad(0)->GetCarGunLeftRight()/128.0f;
+ float left = -right;
+ suspChange[CARWHEEL_FRONT_LEFT] = max(front+left, 0.0f);
+ suspChange[CARWHEEL_REAR_LEFT] = max(rear+left, 0.0f);
+ suspChange[CARWHEEL_FRONT_RIGHT] = max(front+right, 0.0f);
+ suspChange[CARWHEEL_REAR_RIGHT] = max(rear+right, 0.0f);
+
+ if(m_hydraulicState < 100){
+ // Lowered, move wheels up
+
+ if(m_hydraulicState == 0){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Set suspension
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ if(suspChange[i] > 1.0f)
+ suspChange[i] = 1.0f;
+
+ float oldZ = specialColModel->lines[i].p1.z;
+ float upperLimit = suspChange[i]*(extendedUpperLimit-normalUpperLimit) + normalUpperLimit;
+ float springLength = suspChange[i]*(extendedSpringLength-normalSpringLength) + normalSpringLength;
+ float lineLength = springLength + wheelRadius;
+
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += upperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= lineLength;
+ if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
+ maxDelta = pos.z - specialColModel->lines[i].p1.z;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = springLength;
+ m_aSuspensionLineLength[i] = lineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aWheelPosition[i] -= (oldZ - specialColModel->lines[i].p1.z)*0.3f;
+ }
+ }
+ }else{
+ if(m_hydraulicState < 104){
+ m_hydraulicState++;
+ for(i = 0; i < 4; i++)
+ m_aWheelPosition[i] -= 0.1f;
+ }
+
+ if(m_fVelocityChangeForAudio < 0.1f){
+ normalUpperLimit += -0.12f;
+ normalLowerLimit += 0.14f;
+ normalSpringLength = normalUpperLimit - normalLowerLimit;
+ }
+
+ // Set suspension
+ CVector pos;
+ for(i = 0; i < 4; i++){
+ if(suspChange[i] > 1.0f)
+ suspChange[i] = 1.0f;
+
+ float upperLimit = suspChange[i]*(normalUpperLimit-extendedUpperLimit) + extendedUpperLimit;
+ float springLength = suspChange[i]*(normalSpringLength-extendedSpringLength) + extendedSpringLength;
+ float lineLength = springLength + wheelRadius;
+
+ wheelPositions[i] = specialColModel->lines[i].p0.z - m_aSuspensionSpringRatio[i]*m_aSuspensionLineLength[i];
+ mi->GetWheelPosn(i, pos);
+ pos.z += upperLimit;
+ specialColModel->lines[i].p0 = pos;
+ pos.z -= lineLength;
+ if(Abs(pos.z - specialColModel->lines[i].p1.z) > Abs(maxDelta))
+ maxDelta = pos.z - specialColModel->lines[i].p1.z;
+ specialColModel->lines[i].p1 = pos;
+ m_aSuspensionSpringLength[i] = springLength;
+ m_aSuspensionLineLength[i] = lineLength;
+
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ }
+ }
+ }
+
+ float limitDiff = extendedLowerLimit - normalLowerLimit;
+ if(limitDiff != 0.0f && Abs(maxDelta/limitDiff) > 0.01f){
+ float f = (maxDelta + limitDiff)/2.0f/limitDiff;
+ f = clamp(f, 0.0f, 1.0f);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_3, f);
+ if(f < 0.4f || f > 0.6f)
+ setPrevRatio = true;
+ if(f < 0.25f)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
+ else if(f > 0.75f)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
+ }
+ }
+
+ if(setPrevRatio)
+ for(i = 0; i < 4; i++){
+ // wheel radius in relation to suspension line
+ float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
+ m_aSuspensionSpringRatioPrev[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
+ }
}
-WRAPPER void
-CAutomobile::ProcessBuoyancy(void)
-{ EAXJMP(0x5308D0);
+void
+CAutomobile::ProcessBuoyancy(void)
+{
+ int i;
+ CVector impulse, point;
+
+ if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
+ m_flagD8 = true;
+ ApplyMoveForce(impulse);
+ ApplyTurnForce(impulse, point);
+
+ CVector initialSpeed = m_vecMoveSpeed;
+ float timeStep = max(CTimer::GetTimeStep(), 0.01f);
+ float impulseRatio = impulse.z / (GRAVITY * m_fMass * timeStep);
+ float waterResistance = Pow(1.0f - 0.05f*impulseRatio, CTimer::GetTimeStep());
+ m_vecMoveSpeed *= waterResistance;
+ m_vecTurnSpeed *= waterResistance;
+
+ if(impulseRatio > 0.5f){
+ bIsInWater = true;
+ if(m_vecMoveSpeed.z < -0.1f)
+ m_vecMoveSpeed.z = -0.1f;
+
+ if(pDriver){
+ pDriver->bIsInWater = true;
+ if(pDriver->IsPlayer() || !bWaterTight)
+ pDriver->InflictDamage(nil, WEAPONTYPE_WATER, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i]){
+ pPassengers[i]->bIsInWater = true;
+ if(pPassengers[i]->IsPlayer() || !bWaterTight)
+ pPassengers[i]->InflictDamage(nil, WEAPONTYPE_WATER, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
+ }else
+ bIsInWater = false;
+
+ static uint32 nGenerateRaindrops = 0;
+ static uint32 nGenerateWaterCircles = 0;
+
+ if(initialSpeed.z < -0.3f && impulse.z > 0.3f){
+ RwRGBA color;
+ color.red = (0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed())*0.45f*255;
+ color.green = (0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen())*0.45f*255;
+ color.blue = (0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue())*0.45f*255;
+ color.alpha = CGeneral::GetRandomNumberInRange(0, 32) + 128;
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition(),
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.3f)),
+ 0.0f, 75, color, true);
+
+ nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300;
+ nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60;
+ if(m_vecMoveSpeed.z < -0.2f)
+ m_vecMoveSpeed.z = -0.2f;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WATER_FALL, 0.0f);
+ }
+
+ if(nGenerateWaterCircles > 0 && nGenerateWaterCircles < CTimer::GetTimeInMilliseconds()){
+ CVector pos = GetPosition();
+ float waterLevel = 0.0f;
+ if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
+ pos.z = waterLevel;
+ static RwRGBA black;
+ if(pos.z != 0.0f){
+ nGenerateWaterCircles = 0;
+ pos.z += 1.0f;
+ for(i = 0; i < 4; i++){
+ CVector p = pos;
+ p.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f);
+ p.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f);
+ CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW,
+ p, CVector(0.0f, 0.0f, 0.0f),
+ nil, 0.0f, black, 0, 0, 0, 0);
+ }
+ }
+ }
+
+ if(nGenerateRaindrops > 0 && nGenerateRaindrops < CTimer::GetTimeInMilliseconds()){
+ CVector pos = GetPosition();
+ float waterLevel = 0.0f;
+ if(CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &waterLevel, false))
+ pos.z = waterLevel;
+ static RwRGBA black;
+ if(pos.z >= 0.0f){
+ nGenerateRaindrops = 0;
+ pos.z += 0.5;
+ CParticleObject::AddObject(POBJECT_SPLASHES_AROUND,
+ pos, CVector(0.0f, 0.0f, 0.0f), 6.5f, 2500, black, true);
+ }
+ }
+ }else{
+ bIsInWater = false;
+ m_flagD8 = false;
+
+ static RwRGBA splashCol = {155, 155, 185, 196};
+ static RwRGBA smokeCol = {255, 255, 255, 255};
+
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aWheelColPoints[i].surfaceB == SURFACE_PUDDLE){
+ CVector pos = m_aWheelColPoints[i].point + 0.3f*GetUp() - GetPosition();
+ CVector vSpeed = GetSpeed(pos);
+ vSpeed.z = 0.0f;
+ float fSpeed = vSpeed.MagnitudeSqr();
+ if(fSpeed > sq(0.05f)){
+ fSpeed = Sqrt(fSpeed);
+ float size = min((fSpeed < 0.15f ? 0.25f : 0.75f)*fSpeed, 0.6f);
+ CVector right = 0.2f*fSpeed*GetRight() + 0.2f*vSpeed;
+
+ CParticle::AddParticle(PARTICLE_PED_SPLASH,
+ pos + GetPosition(), -0.5f*right,
+ nil, size, splashCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f), 1, 0);
+
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ pos + GetPosition(), -0.6f*right,
+ nil, size, smokeCol, 0, 0, 0, 0);
+
+ if((CTimer::GetFrameCounter() & 0xF) == 0)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
+ }
+ }
+ }
+ }
}
void
@@ -1896,6 +3378,112 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
}
void
+CAutomobile::AddDamagedVehicleParticles(void)
+{
+ if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
+ return;
+
+ uint8 engineStatus = Damage.GetEngineStatus();
+ if(engineStatus < ENGINE_STATUS_STEAM1)
+ return;
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()) * 180.0f;
+ CVector direction = 0.5f*m_vecMoveSpeed;
+ CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
+
+ switch(Damage.GetDoorStatus(DOOR_BONNET)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ // Bonnet is still there, smoke comes out at the edge
+ damagePos += vecDAMAGE_ENGINE_POS_SMALL;
+ break;
+ case DOOR_STATUS_SWINGING:
+ case DOOR_STATUS_MISSING:
+ // Bonnet is gone, smoke comes out at the engine
+ damagePos += vecDAMAGE_ENGINE_POS_BIG;
+ break;
+ }
+
+ if(GetModelIndex() == MI_BFINJECT)
+ damagePos = CVector(0.3f, -1.5f, -0.1f);
+
+ damagePos = GetMatrix()*damagePos;
+ damagePos.z += 0.15f;
+
+ if(engineStatus < ENGINE_STATUS_STEAM2){
+ if(fwdSpeed < 90.0f){
+ direction.z += 0.05f;
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.1f);
+ }
+ }else if(engineStatus < ENGINE_STATUS_SMOKE){
+ if(fwdSpeed < 90.0f)
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
+ }else if(engineStatus < ENGINE_STATUS_ON_FIRE){
+ if(fwdSpeed < 90.0f){
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.3f*direction, nil, 0.0f);
+ }
+ }else if(m_fHealth > 250.0f){
+ if(fwdSpeed < 90.0f)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.2f*direction, nil, 0.0f);
+ }
+}
+
+int32
+CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
+{
+ int i;
+ CVector dir;
+ static RwRGBA grassCol = { 8, 24, 8, 255 };
+ static RwRGBA dirtCol = { 64, 64, 64, 255 };
+ static RwRGBA dirttrackCol = { 64, 32, 16, 255 };
+ static RwRGBA waterCol = { 48, 48, 64, 0 };
+
+ if(!belowEffectSpeed)
+ return 0;
+
+ switch(colpoint->surfaceB){
+ case SURFACE_GRASS:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ for(i = 0; i < 4; i++){
+ dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
+ CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.1f), grassCol);
+ }
+ return 0;
+ case SURFACE_DIRT:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ for(i = 0; i < 4; i++){
+ dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
+ CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.06f), dirtCol);
+ }
+ return 1;
+ case SURFACE_DIRTTRACK:
+ dir.x = -0.05f*m_vecMoveSpeed.x;
+ dir.y = -0.05f*m_vecMoveSpeed.y;
+ for(i = 0; i < 4; i++){
+ dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
+ CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
+ CGeneral::GetRandomNumberInRange(0.02f, 0.06f), dirttrackCol);
+ }
+ return 0;
+ default:
+ // Is this even visible?
+ if(CWeather::WetRoads > 0.01f && CTimer::GetFrameCounter() & 1){
+ CParticle::AddParticle(PARTICLE_WATERSPRAY,
+ colpoint->point + CVector(0.0f, 0.0f, 0.25f+0.25f),
+ CVector(0.0f, 0.0f, 1.0f), nil,
+ CGeneral::GetRandomNumberInRange(0.1f, 0.5f), waterCol);
+ return 0;
+ }
+ return 1;
+ }
+}
+
+void
CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos)
{
if(m_aCarNodes[component] == nil){
@@ -2192,9 +3780,9 @@ CAutomobile::BlowUpCar(CEntity *culprit)
gFireManager.StartFire(this, culprit, 0.8f, 1); // TODO
CDarkel::RegisterCarBlownUpByPlayer(this);
if(GetModelIndex() == MI_RCBANDIT)
- CExplosion::AddExplosion(this, culprit, EXPLOSION_4, GetPosition(), 0); // TODO
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR_QUICK, GetPosition(), 0);
else
- CExplosion::AddExplosion(this, culprit, EXPLOSION_3, GetPosition(), 0); // TODO
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
}
bool
@@ -2253,7 +3841,64 @@ CAutomobile::BurstTyre(uint8 wheel)
}
}
-WRAPPER bool CAutomobile::IsRoomForPedToLeaveCar(uint32, CVector *) { EAXJMP(0x53C5B0); }
+bool
+CAutomobile::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset)
+{
+ CColPoint colpoint;
+ CEntity *ent;
+ colpoint.point = CVector(0.0f, 0.0f, 0.0f);
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ CVector seatPos;
+ switch(component){
+ case CAR_DOOR_RF:
+ seatPos = mi->m_positions[mi->m_vehicleType == VEHICLE_TYPE_BOAT ? BOAT_POS_FRONTSEAT : CAR_POS_FRONTSEAT];
+ break;
+ case CAR_DOOR_LF:
+ seatPos = mi->m_positions[mi->m_vehicleType == VEHICLE_TYPE_BOAT ? BOAT_POS_FRONTSEAT : CAR_POS_FRONTSEAT];
+ seatPos.x = -seatPos.x;
+ break;
+ case CAR_DOOR_RR:
+ seatPos = mi->m_positions[CAR_POS_BACKSEAT];
+ break;
+ case CAR_DOOR_LR:
+ seatPos = mi->m_positions[CAR_POS_BACKSEAT];
+ seatPos.x = -seatPos.x;
+ break;
+ }
+ seatPos = GetMatrix() * seatPos;
+
+ CVector doorPos = CPed::GetPositionToOpenCarDoor(this, component);
+ if(doorOffset){
+ CVector off = *doorOffset;
+ if(component == CAR_DOOR_RF || component == CAR_DOOR_RR)
+ off.x = -off.x;
+ doorPos += Multiply3x3(GetMatrix(), off);
+ }
+
+ if(GetUp().z < 0.0f){
+ seatPos.z += 0.5f;
+ doorPos.z += 0.5f;
+ }
+
+ CVector dist = doorPos - seatPos;
+ float length = dist.Magnitude();
+ CVector pedPos = seatPos + dist*((length+0.6f)/length);
+
+ if(!CWorld::GetIsLineOfSightClear(seatPos, pedPos, true, false, false, true, false, false))
+ return false;
+ if(CWorld::TestSphereAgainstWorld(doorPos, 0.6f, this, true, true, false, true, false, false))
+ return false;
+ if(CWorld::ProcessVerticalLine(doorPos, 1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ if(colpoint.point.z > doorPos.z && colpoint.point.z < doorPos.z + 0.6f)
+ return false;
+ float upperZ = colpoint.point.z;
+ if(!CWorld::ProcessVerticalLine(doorPos, -1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ return false;
+ if(upperZ != 0.0f && upperZ < colpoint.point.z)
+ return false;
+ return true;
+}
float
CAutomobile::GetHeightAboveRoad(void)
@@ -2300,7 +3945,7 @@ CAutomobile::ResetSuspension(void)
m_aSuspensionSpringRatio[i] = 1.0f;
m_aWheelTimer[i] = 0.0f;
m_aWheelRotation[i] = 0.0f;
- m_aWheelState[i] = WHEEL_STATE_0;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
}
}
@@ -2867,6 +4512,8 @@ STARTPATCHES
InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP);
InjectHook(0x531470, &CAutomobile_::ProcessControl_, PATCH_JUMP);
InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP);
+ InjectHook(0x539EA0, &CAutomobile_::Render_, PATCH_JUMP);
+ InjectHook(0x535B40, &CAutomobile_::PreRender_, PATCH_JUMP);
InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP);
InjectHook(0x53B660, &CAutomobile_::ProcessControlInputs_, PATCH_JUMP);
InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP);
@@ -2881,10 +4528,13 @@ STARTPATCHES
InjectHook(0x53BC60, &CAutomobile_::BlowUpCar_, PATCH_JUMP);
InjectHook(0x53BF70, &CAutomobile_::SetUpWheelColModel_, PATCH_JUMP);
InjectHook(0x53C0E0, &CAutomobile_::BurstTyre_, PATCH_JUMP);
+ InjectHook(0x53C5B0, &CAutomobile_::IsRoomForPedToLeaveCar_, PATCH_JUMP);
InjectHook(0x437690, &CAutomobile_::GetHeightAboveRoad_, PATCH_JUMP);
InjectHook(0x53C450, &CAutomobile_::PlayCarHorn_, PATCH_JUMP);
InjectHook(0x53E090, &CAutomobile::PlaceOnRoadProperly, PATCH_JUMP);
InjectHook(0x52F030, &CAutomobile::dmgDrawCarCollidingParticles, PATCH_JUMP);
+ InjectHook(0x535450, &CAutomobile::AddDamagedVehicleParticles, PATCH_JUMP);
+ InjectHook(0x5357D0, &CAutomobile::AddWheelDirtAndWater, PATCH_JUMP);
InjectHook(0x5353A0, &CAutomobile::ResetSuspension, PATCH_JUMP);
InjectHook(0x52D210, &CAutomobile::SetupSuspensionLines, PATCH_JUMP);
InjectHook(0x53E000, &CAutomobile::BlowUpCarsInPath, PATCH_JUMP);
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index 1a103777..6226b555 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -48,13 +48,13 @@ public:
uint8 bHadDriver : 1; // for bombs
uint8 m_auto_flagA20 : 1;
uint8 m_auto_flagA40 : 1;
- uint8 m_auto_flagA80 : 1;
+ uint8 bWaterTight : 1; // no damage for non-player peds
uint8 bNotDamagedUpsideDown : 1;
uint8 bMoreResistantToDamage : 1;
uint8 field_4DB;
CEntity *m_pBombRigger;
int16 field_4E0;
- int16 field_4E2;
+ uint16 m_hydraulicState;
uint32 m_nBusDoorTimerEnd;
uint32 m_nBusDoorTimerStart;
float m_aSuspensionSpringLength[4];
@@ -71,7 +71,7 @@ public:
float m_weaponDoorTimerRight;
float m_fCarGunLR;
float m_fCarGunUD;
- float m_fWindScreenRotation;
+ float m_fPropellerRotation;
uint8 stuff4[4];
uint8 m_nWheelsOnGround;
uint8 m_nDriveWheelsOnGround;
@@ -108,7 +108,7 @@ public:
void BlowUpCar(CEntity *ent);
bool SetUpWheelColModel(CColModel *colModel);
void BurstTyre(uint8 tyre);
- bool IsRoomForPedToLeaveCar(uint32, CVector *);
+ bool IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset);
float GetHeightAboveRoad(void);
void PlayCarHorn(void);
@@ -122,6 +122,8 @@ public:
int32 RcbanditCheck1CarWheels(CPtrList &list);
void PlaceOnRoadProperly(void);
void dmgDrawCarCollidingParticles(const CVector &pos, float amount);
+ void AddDamagedVehicleParticles(void);
+ int32 AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed);
void PlayHornIfNecessary(void);
void ResetSuspension(void);
void SetupSuspensionLines(void);
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index c18bad25..f614b78f 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -5,7 +5,7 @@
float &fShapeLength = *(float*)0x600E78;
float &fShapeTime = *(float*)0x600E7C;
float &fRangeMult = *(float*)0x600E80; //0.6f; // 0.75f gta 3
-float &fTimeMult = *(float*)0xA0FCF4;
+float &fTimeMult = *(float*)0x943008;
float MAX_WAKE_LENGTH = 50.0f;
float MIN_WAKE_INTERVAL = 1.0f;
diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h
index adcd7430..bf0c59a1 100644
--- a/src/vehicles/DamageManager.h
+++ b/src/vehicles/DamageManager.h
@@ -6,6 +6,9 @@
enum eEngineStatus
{
+ ENGINE_STATUS_STEAM1 = 100,
+ ENGINE_STATUS_STEAM2 = 150,
+ ENGINE_STATUS_SMOKE = 200,
ENGINE_STATUS_ON_FIRE = 225
};
@@ -32,6 +35,12 @@ enum eWheelStatus
WHEEL_STATUS_MISSING
};
+enum eLightStatus
+{
+ LIGHT_STATUS_OK,
+ LIGHT_STATUS_BROKEN
+};
+
enum tComponent
{
COMPONENT_DEFAULT,
diff --git a/src/vehicles/Floater.cpp b/src/vehicles/Floater.cpp
index cabe00c3..6b8bf755 100644
--- a/src/vehicles/Floater.cpp
+++ b/src/vehicles/Floater.cpp
@@ -22,7 +22,7 @@ static float fBoatVolumeDistribution[9] = {
};
bool
-cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point)
+cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *point, CVector *impulse)
{
m_numSteps = 2.0f;
@@ -32,7 +32,7 @@ cBuoyancy::ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CV
PreCalcSetup(phys, buoyancy);
SimpleCalcBuoyancy();
- float f = CalcBuoyancyForce(phys, impulse, point);
+ float f = CalcBuoyancyForce(phys, point, impulse);
if(m_isBoat)
return true;
return f != 0.0f;
@@ -82,7 +82,7 @@ cBuoyancy::PreCalcSetup(CPhysical *phys, float buoyancy)
m_haveVolume = false;
m_numPartialVolumes = 1.0f;
m_volumeUnderWater = 0.0f;
- m_impulse = CVector(0.0f, 0.0f, 0.0f);
+ m_impulsePoint = CVector(0.0f, 0.0f, 0.0f);
m_position = phys->GetPosition();
m_positionZ = CVector(0.0f, 0.0f, m_position.z);
m_buoyancy = buoyancy;
@@ -148,7 +148,7 @@ cBuoyancy::SimpleSumBuoyancyData(CVector &waterLevel, tWaterLevel waterPosition)
fFraction = 1.0f/m_numPartialVolumes;
fRemainingSlice = 1.0f - fFraction;
- m_impulse = m_impulse*fRemainingSlice + AverageOfWaterLevel*fThisVolume*fFraction;
+ m_impulsePoint = m_impulsePoint*fRemainingSlice + AverageOfWaterLevel*fThisVolume*fFraction;
m_numPartialVolumes += 1.0f;
m_haveVolume = true;
return fThisVolume;
@@ -175,13 +175,13 @@ cBuoyancy::FindWaterLevel(const CVector &zpos, CVector *waterLevel, tWaterLevel
}
bool
-cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *impulse, CVector *point)
+cBuoyancy::CalcBuoyancyForce(CPhysical *phys, CVector *point, CVector *impulse)
{
if(!m_haveVolume)
return false;
- *impulse = Multiply3x3(m_matrix, m_impulse);
- *point = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep());
+ *point = Multiply3x3(m_matrix, m_impulsePoint);
+ *impulse = CVector(0.0f, 0.0f, m_volumeUnderWater*m_buoyancy*CTimer::GetTimeStep());
return true;
}
diff --git a/src/vehicles/Floater.h b/src/vehicles/Floater.h
index ede2b9d0..0a2ae809 100644
--- a/src/vehicles/Floater.h
+++ b/src/vehicles/Floater.h
@@ -1,6 +1,6 @@
#pragma once
-class Physical;
+class CPhysical;
enum tWaterLevel
{
@@ -33,7 +33,7 @@ public:
char m_field_B9;
bool m_isBoat;
float m_volumeUnderWater;
- CVector m_impulse;
+ CVector m_impulsePoint;
bool ProcessBuoyancy(CPhysical *phys, float buoyancy, CVector *impulse, CVector *point);
void PreCalcSetup(CPhysical *phys, float buoyancy);
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index cc98bbe9..36675c8b 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -59,8 +59,8 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_pBlowUpEntity = nil;
field_1FB = 0;
bComedyControls = false;
- m_veh_flagB40 = false;
- m_veh_flagB80 = false;
+ bCraneMessageDone = false;
+ bExtendedRange = false;
bTakeLessDamage = false;
bIsDamaged = false;
bFadeOut = false;
@@ -70,7 +70,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
bHasBeenOwnedByPlayer = false;
m_veh_flagC20 = false;
bCanBeDamaged = true;
- m_veh_flagC80 = false;
+ bUsingSpecialColModel = false;
m_veh_flagD1 = false;
m_veh_flagD2 = false;
m_nGunFiringTime = 0;
@@ -255,9 +255,9 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd);
float contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight);
- if(*wheelState != WHEEL_STATE_0)
+ if(*wheelState != WHEEL_STATE_NORMAL)
bAlreadySkidding = true;
- *wheelState = WHEEL_STATE_0;
+ *wheelState = WHEEL_STATE_NORMAL;
adhesion *= CTimer::GetTimeStep();
if(bAlreadySkidding)
@@ -299,7 +299,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
if(brake > adhesion){
if(Abs(contactSpeedFwd) > 0.005f)
- *wheelState = WHEEL_STATE_STATIC;
+ *wheelState = WHEEL_STATE_FIXED;
}else {
if(fwd > 0.0f){
if(fwd > brake)
@@ -312,11 +312,11 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
}
if(sq(adhesion) < sq(right) + sq(fwd)){
- if(*wheelState != WHEEL_STATE_STATIC){
+ if(*wheelState != WHEEL_STATE_FIXED){
if(bDriving && contactSpeedFwd < 0.2f)
- *wheelState = WHEEL_STATE_1;
+ *wheelState = WHEEL_STATE_SPINNING;
else
- *wheelState = WHEEL_STATE_2;
+ *wheelState = WHEEL_STATE_SKIDDING;
}
float l = Sqrt(sq(right) + sq(fwd));
@@ -343,10 +343,10 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec
{
float angularVelocity;
switch(state){
- case WHEEL_STATE_1:
+ case WHEEL_STATE_SPINNING:
angularVelocity = -1.1f; // constant speed forward
break;
- case WHEEL_STATE_STATIC:
+ case WHEEL_STATE_FIXED:
angularVelocity = 0.0f; // not moving
break;
default:
@@ -377,12 +377,13 @@ CVehicle::ProcessDelayedExplosion(void)
return;
int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
+ int16 prev = m_nBombTimer;
if(tick > m_nBombTimer)
m_nBombTimer = 0;
else
m_nBombTimer -= tick;
- if(IsCar() && ((CAutomobile*)this)->m_bombType == CARBOMB_TIMEDACTIVE && (m_nBombTimer & 0xFE00) != 0xFE00)
+ if(IsCar() && ((CAutomobile*)this)->m_bombType == CARBOMB_TIMEDACTIVE && (m_nBombTimer & 0xFE00) != (prev & 0xFE00))
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
if (m_nBombTimer != 0)
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 38d411cd..262bd62c 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -59,6 +59,11 @@ enum
CAR_POS_EXHAUST = 9,
};
+enum
+{
+ BOAT_POS_FRONTSEAT
+};
+
enum eDoors
{
DOOR_BONNET = 0,
@@ -119,10 +124,10 @@ enum
enum tWheelState
{
- WHEEL_STATE_0 = 0,
- WHEEL_STATE_1 = 1, // constant velocity
- WHEEL_STATE_2 = 2, // normal
- WHEEL_STATE_STATIC = 3, // not moving
+ WHEEL_STATE_NORMAL, // standing still or rolling normally
+ WHEEL_STATE_SPINNING, // rotating but not moving
+ WHEEL_STATE_SKIDDING,
+ WHEEL_STATE_FIXED, // not rotating
};
enum eFlightModel
@@ -176,8 +181,8 @@ public:
uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims
uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way)
uint8 bWarnedPeds : 1; // Has scan and warn peds of danger been processed?
- uint8 m_veh_flagB40 : 1;
- uint8 m_veh_flagB80 : 1;
+ uint8 bCraneMessageDone : 1; // A crane message has been printed for this car allready
+ uint8 bExtendedRange : 1; // This vehicle needs to be a bit further away to get deleted
uint8 bTakeLessDamage : 1; // This vehicle is stronger (takes about 1/4 of damage)
uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components
@@ -186,7 +191,7 @@ public:
uint8 m_veh_flagC10 : 1;
uint8 m_veh_flagC20 : 1;
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
- uint8 m_veh_flagC80 : 1;
+ uint8 bUsingSpecialColModel : 1;// Is player vehicle using special collision model, stored in player strucure
uint8 m_veh_flagD1 : 1;
uint8 m_veh_flagD2 : 1;
@@ -253,7 +258,7 @@ public:
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 bool IsRoomForPedToLeaveCar(uint32 component, CVector *forcedDoorPos) { return false;}
virtual float GetHeightAboveRoad(void);
virtual void PlayCarHorn(void) {}
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 0fc89637..f83f2271 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -3,11 +3,14 @@
#include "Weapon.h"
#include "Timer.h"
#include "WeaponInfo.h"
+#include "Ped.h"
+#include "World.h"
WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); }
WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); }
WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, float) { EAXJMP(0x55F770); }
WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
+WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); }
void
CWeapon::Initialise(eWeaponType type, int ammo)
@@ -49,7 +52,42 @@ CWeapon::IsTypeMelee(void)
return m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT;
}
+bool
+CWeapon::HitsGround(CEntity *holder, CVector *firePos, CEntity *aimingTo)
+{
+ if (!holder->IsPed() || !((CPed*)holder)->m_pSeekTarget)
+ return false;
+
+ CWeaponInfo *ourType = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
+ CVector adjustedOffset = ourType->m_vecFireOffset;
+ adjustedOffset.z += 0.6f;
+
+ CVector point1, point2;
+ CEntity *foundEnt = nil;
+ CColPoint foundCol;
+
+ if (firePos)
+ point1 = *firePos;
+ else
+ point1 = holder->GetMatrix() * adjustedOffset;
+
+ CEntity *aimEntity = aimingTo ? aimingTo : ((CPed*)holder)->m_pSeekTarget;
+ point2 = aimEntity->GetPosition();
+ point2.z += 0.6f;
+
+ CWorld::ProcessLineOfSight(point1, point2, foundCol, foundEnt, true, false, false, false, false, false, false);
+ if (foundEnt && foundEnt->IsBuilding()) {
+ // That was supposed to be Magnitude, according to leftover code in assembly
+ float diff = (foundCol.point.z - point1.z);
+ if (diff < 0.0f && diff > -3.0f)
+ return true;
+ }
+
+ return false;
+}
+
STARTPATCHES
InjectHook(0x55C330, &CWeapon::Initialise, PATCH_JUMP);
InjectHook(0x5639D0, &CWeapon::Reload, PATCH_JUMP);
+ InjectHook(0x564890, &CWeapon::HitsGround, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 71fe1f45..4916284f 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -70,5 +70,7 @@ public:
void AddGunshell(CEntity*, CVector const&, CVector2D const&, float);
bool IsTypeMelee(void);
bool IsType2Handed(void);
+ static void DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end);
+ bool HitsGround(CEntity* holder, CVector* firePos, CEntity* aimingTo);
};
static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");