summaryrefslogtreecommitdiffstats
path: root/src/entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/entities')
-rw-r--r--src/entities/Automobile.h63
-rw-r--r--src/entities/Object.cpp22
-rw-r--r--src/entities/Object.h2
-rw-r--r--src/entities/Ped.cpp434
-rw-r--r--src/entities/Ped.h100
-rw-r--r--src/entities/Physical.cpp8
-rw-r--r--src/entities/Physical.h6
-rw-r--r--src/entities/Vehicle.cpp398
-rw-r--r--src/entities/Vehicle.h154
9 files changed, 1055 insertions, 132 deletions
diff --git a/src/entities/Automobile.h b/src/entities/Automobile.h
index 64e411ce..b6617f4b 100644
--- a/src/entities/Automobile.h
+++ b/src/entities/Automobile.h
@@ -1,26 +1,61 @@
#pragma once
#include "DamageManager.h"
-#include "Door.h"
-#include "RwHelper.h"
#include "Vehicle.h"
+struct CDoor
+{
+ float m_fAngleWhenOpened;
+ float m_fAngleWhenClosed;
+ char field_8;
+ char field_9;
+ char field_10;
+ char field_11;
+ float m_fAngle;
+ float m_fPreviousAngle;
+ float m_fAngularVelocity;
+ CVector m_vecVelocity;
+};
+
class CAutomobile : public CVehicle
{
public:
// 0x288
- CDamageManager m_DamageManager;
- CDoor m_aDoors[6];
- RwFrame *m_apModelNodes[20];
- uint8 stuff1[160];
- float m_afWheelSuspDist[4];
- uint8 stuff2[44];
- float m_afWheelRotation[4];
- uint8 stuff3[200];
+ CDamageManager Damage;
+ CDoor Doors[6];
+ RwFrame *m_aCarNodes[NUM_CAR_NODES];
+ CColPoint m_aWheelColPoints[4];
+ float m_aWheelDist[4];
+ float m_aWheelDist_2[4];
+ float m_aWheelSkidThing[4];
+ int field_49C;
+ bool m_aWheelSkidmarkMuddy[4];
+ bool m_aWheelSkidmarkBloody[4];
+ float m_aWheelRotation[4];
+ float m_aWheelPosition[4];
+ float m_aWheelSpeed[4];
+ uint8 stuff3[12];
+ uint32 m_nBusDoorTimerEnd;
+ uint32 m_nBusDoorTimerStart;
+ float m_aSuspensionRange[4];
+ float m_aSuspensionLineLength[4];
+ float m_fHeightAboveRoad;
+ float m_fImprovedHandling;
+ uint8 stuff6[32];
+ CPhysical *m_aGroundPhysical[4]; // physicals touching wheels
+ CVector m_aGroundOffset[4]; // from ground object to colpoint
+ CEntity *m_pBlowUpEntity;
+ float m_weaponThingA; // TODO
+ float m_weaponThingB; // TODO
float m_fCarGunLR;
- uint8 stuff4[13];
- uint8 m_nDriveWheelsOnGround;
- uint8 stuff5[22];
+ float m_fCarGunUD;
+ float m_fWindScreenRotation;
+ uint8 stuff4[4];
+ uint8 m_nWheelsOnGround_2;
+ uint8 m_nWheelsOnGround;
+ uint8 m_nWheelsOnGroundPrev;
+ uint8 stuff5[5];
+ int32 m_aWheelState[4];
CAutomobile(int, uint8);
CAutomobile* ctor(int, uint8);
@@ -30,4 +65,4 @@ public:
void dtor() { this->CAutomobile::~CAutomobile(); }
};
static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error");
-static_assert(offsetof(CAutomobile, m_afWheelSuspDist) == 0x46C, "CAutomobile: error");
+static_assert(offsetof(CAutomobile, m_aWheelDist) == 0x46C, "CAutomobile: error");
diff --git a/src/entities/Object.cpp b/src/entities/Object.cpp
index dbc38b9d..6712d77b 100644
--- a/src/entities/Object.cpp
+++ b/src/entities/Object.cpp
@@ -1,5 +1,7 @@
#include "common.h"
#include "patcher.h"
+#include "main.h"
+#include "Lights.h"
#include "Pools.h"
#include "Radar.h"
#include "Object.h"
@@ -63,6 +65,26 @@ CObject::Render(void)
CEntity::Render();
}
+bool
+CObject::SetupLighting(void)
+{
+ DeActivateDirectional();
+ SetAmbientColours();
+
+ if(bRenderScorched){
+ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+ return true;
+ }
+ return false;
+}
+
+void
+CObject::RemoveLighting(bool reset)
+{
+ if(reset)
+ WorldReplaceScorchedLightsWithNormal(Scene.world);
+}
+
WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); }
STARTPATCHES
diff --git a/src/entities/Object.h b/src/entities/Object.h
index 3a8d62f2..de4c8e05 100644
--- a/src/entities/Object.h
+++ b/src/entities/Object.h
@@ -68,6 +68,8 @@ public:
~CObject(void);
void Render(void);
+ bool SetupLighting(void);
+ void RemoveLighting(bool reset);
void ObjectDamage(float amount);
diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp
index 2e51a5c1..2cc8e4c4 100644
--- a/src/entities/Ped.cpp
+++ b/src/entities/Ped.cpp
@@ -24,21 +24,23 @@
#include "PointLights.h"
#include "Pad.h"
-WRAPPER void CPed::QuitEnteringCar() { EAXJMP(0x4E0E00); }
-WRAPPER void CPed::KillPedWithCar(CVehicle* veh, float impulse) { EAXJMP(0x4EC430); }
+WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); }
WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4D37D0); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); }
WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); }
-WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2480); }
-WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); }
+WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); }
+WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); }
WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); }
WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); }
WRAPPER void CPed::Render(void) { EAXJMP(0x4D03F0); }
WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); }
WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); }
+WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); }
+WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); }
+WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); }
WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); }
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
@@ -61,14 +63,7 @@ CPed::~CPed(void)
CWorld::Remove(this);
CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this));
if (bInVehicle && m_pMyVehicle){
- uint8 door_flag = 0;
- switch (m_vehEnterType) {
- case VEHICLE_ENTER_FRONT_LEFT: door_flag = 1; break;
- case VEHICLE_ENTER_REAR_LEFT: door_flag = 2; break;
- case VEHICLE_ENTER_FRONT_RIGHT: door_flag = 4; break;
- case VEHICLE_ENTER_REAR_RIGHT: door_flag = 8; break;
- default: break;
- }
+ uint8 door_flag = GetVehEnterExitFlag(m_vehEnterType);
if (m_pMyVehicle->pDriver == this)
m_pMyVehicle->pDriver = nil;
else {
@@ -105,7 +100,7 @@ CPed::FlagToDestroyWhenNextProcessed(void)
}
bInVehicle = false;
m_pMyVehicle = nil;
- if (m_nCreatedBy == CREATED_BY_SCRIPT)
+ if (CharCreatedBy == MISSION_CHAR)
m_nPedState = PED_DEAD;
else
m_nPedState = PED_NONE;
@@ -284,7 +279,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_talkType = 167;
m_objective = OBJECTIVE_NONE;
m_prevObjective = OBJECTIVE_NONE;
- m_nCreatedBy = CREATED_BY_RANDOM;
+ CharCreatedBy = RANDOM_CHAR;
m_leader = nil;
m_pedInObjective = nil;
m_carInObjective = nil;
@@ -331,7 +326,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_fleeTimer = 0;
m_vecSeekPosEx = CVector(0.0f, 0.0f, 0.0f);
m_seekExAngle = 0.0f;
- m_nWaitState = 0;
+ m_nWaitState = WAITSTATE_FALSE;
m_nWaitTimer = 0;
m_pCollidingEntity = nil;
m_nPedState = PED_IDLE;
@@ -371,15 +366,15 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bIsRestoringGun = false;
bCanPointGunAtTarget = false;
- m_ped_flagB4 = false;
- m_ped_flagB8 = false;
- m_ped_flagB10 = false;
+ bIsTalking = false;
+ bIsInTheAir = false;
+ bIsLanding = false;
m_ped_flagB20 = false;
m_ped_flagB40 = false;
m_ped_flagB80 = false;
m_ped_flagC1 = false;
- m_ped_flagC2 = true;
+ bRespondsToThreats = true;
m_ped_flagC4 = true;
m_ped_flagC8 = false;
m_ped_flagC10 = false;
@@ -398,9 +393,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_ped_flagE1 = false;
m_ped_flagE2 = false;
- m_ped_flagE4 = false;
- m_ped_flagE8 = false;
- bCantFireBecauseCrouched = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bIsDucking = false;
m_ped_flagE20 = false;
bDoBloodyFootprints = false;
m_ped_flagE80 = false;
@@ -636,7 +631,7 @@ bool
CPed::IsPedInControl(void)
{
return m_nPedState <= PED_STATES_NO_AI
- && !m_ped_flagB8 && !m_ped_flagB10
+ && !bIsInTheAir && !bIsLanding
&& m_fHealth > 0.0f;
}
@@ -1020,7 +1015,7 @@ CPed::Attack(void)
if (reloadAnim != NUM_ANIMS)
reloadAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, reloadAnim);
- if (bCantFireBecauseCrouched)
+ if (bIsDucking)
return;
if (reloadAnimAssoc) {
@@ -1281,7 +1276,7 @@ CPed::ClearDuck(void)
if (animAssoc) {
- if (m_ped_flagE8) {
+ if (bCrouchWhenShooting) {
if (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN) {
animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RBLOCK_CSHOOT);
@@ -1291,7 +1286,7 @@ CPed::ClearDuck(void)
}
}
} else
- bCantFireBecauseCrouched = false;
+ bIsDucking = false;
}
void
@@ -1342,13 +1337,13 @@ CPed::BeingDraggedFromCar(void)
if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) {
if (m_ped_flagF10) {
enterAnim = ANIM_CAR_QJACKED;
- } else if (m_pMyVehicle->bIsLow) {
+ } else if (m_pMyVehicle->bLowVehicle) {
enterAnim = ANIM_CAR_LJACKED_LHS;
} else {
enterAnim = ANIM_CAR_JACKED_LHS;
}
} else if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) {
- if (m_pMyVehicle->bIsLow)
+ if (m_pMyVehicle->bLowVehicle)
enterAnim = ANIM_CAR_LJACKED_RHS;
else
enterAnim = ANIM_CAR_JACKED_RHS;
@@ -1401,20 +1396,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
ped->m_pSeekTarget = nil;
vehicle = ped->m_pMyVehicle;
- switch (ped->m_vehEnterType) {
- case VEHICLE_ENTER_FRONT_RIGHT:
- vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_FR;
- break;
- case VEHICLE_ENTER_REAR_RIGHT:
- vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_RR;
- break;
- case VEHICLE_ENTER_FRONT_LEFT:
- vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_FL;
- break;
- case VEHICLE_ENTER_REAR_LEFT:
- vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_RL;
- break;
- }
+ vehicle->m_nGettingOutFlags &= ~GetVehEnterExitFlag(ped->m_vehEnterType);
if (vehicle->pDriver == ped) {
vehicle->RemoveDriver();
@@ -1471,7 +1453,7 @@ CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enter
vehDoorOffset = offsetToOpenVanDoor;
} else {
seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult;
- if (veh->bIsLow) {
+ if (veh->bLowVehicle) {
vehDoorOffset = offsetToOpenLowCarDoor;
} else {
vehDoorOffset = offsetToOpenRegularCarDoor;
@@ -1743,7 +1725,6 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase)
}
}
- // I hope
bool stillGettingInOut = false;
if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer)
stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10;
@@ -1938,7 +1919,7 @@ CPed::IsPointerValid(void)
// Some kind of binary sort
void
-CPed::SortPeds(CPed** list, int min, int max)
+CPed::SortPeds(CPed **list, int min, int max)
{
if (min >= max)
return;
@@ -1978,7 +1959,7 @@ CPed::SortPeds(CPed** list, int min, int max)
void
CPed::BuildPedLists(void)
{
- static CPed* unsortedNearPeds[10];
+ static CPed *unsortedNearPeds[10];
uint16 nextNearPedSlot = 0;
if ((CTimer::GetFrameCounter() + m_randomSeed) & 15) {
@@ -2223,10 +2204,10 @@ CPed::CanBeDeleted(void)
if (this->bInVehicle)
return false;
- switch (m_nCreatedBy) {
- case CREATED_BY_RANDOM:
+ switch (CharCreatedBy) {
+ case RANDOM_CHAR:
return true;
- case CREATED_BY_SCRIPT:
+ case MISSION_CHAR:
return false;
default:
return true;
@@ -2522,7 +2503,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
if (newObj == OBJECTIVE_SOLICIT) {
m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000;
- } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_nCreatedBy == CREATED_BY_SCRIPT &&
+ } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR &&
(m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) {
SetObjectiveTimer(14000);
} else {
@@ -2544,6 +2525,350 @@ CPed::SetObjective(eObjective newObj, void *entity)
}
}
+void
+CPed::SetIdle(void)
+{
+ if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) {
+ m_nPedState = PED_IDLE;
+ SetMoveState(PEDMOVE_STILL);
+ }
+ if (m_nWaitState == WAITSTATE_FALSE) {
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000);
+ }
+}
+
+void
+CPed::SetObjective(eObjective newObj)
+{
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+ return;
+
+ if (newObj == OBJECTIVE_NONE) {
+ if ((m_objective == OBJECTIVE_LEAVE_VEHICLE || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)
+ && IsPedInControl()) {
+
+ m_ped_flagG8 = true;
+ return;
+ }
+ // Unused code from assembly...
+ /*
+ else if(m_objective == OBJECTIVE_FLEE_CAR) {
+
+ } else {
+
+ }
+ */
+ m_objective = newObj;
+ m_prevObjective = OBJECTIVE_NONE;
+ } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) {
+ SetObjectiveTimer(0);
+
+ if (m_objective == newObj)
+ return;
+
+ if (IsTemporaryObjective(m_objective)) {
+ m_prevObjective = newObj;
+ } else {
+ if (m_objective != newObj)
+ SetStoredObjective();
+
+ m_objective = newObj;
+ }
+ m_ped_flagD40 = false;
+
+ switch (newObj) {
+ case OBJECTIVE_NONE:
+ m_prevObjective = OBJECTIVE_NONE;
+ break;
+ case OBJECTIVE_HAIL_TAXI:
+ m_nWaitTimer = 0;
+ SetIdle();
+ SetMoveState(PEDMOVE_STILL);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode
+// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call...
+void
+CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType)
+{
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+ return;
+
+ if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE)
+ return;
+
+ SetObjectiveTimer(0);
+
+ if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType)
+ return;
+
+ m_ped_flagD40 = false;
+ if (IsTemporaryObjective(m_objective)) {
+ m_prevObjective = newObj;
+ } else {
+ if (m_objective != newObj)
+ SetStoredObjective();
+
+ m_objective = newObj;
+ }
+
+ if (newObj == OBJECTIVE_FOLLOW_ROUTE) {
+ SetFollowRoute(routePoint, routeType);
+ }
+}
+
+void
+CPed::ClearChat(void)
+{
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ if (animAssoc) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ bIsTalking = false;
+ ClearLookFlag();
+ RestorePreviousState();
+}
+
+bool
+CPed::IsGangMember(void)
+{
+ return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9;
+}
+
+void
+CPed::InformMyGangOfAttack(CEntity *attacker)
+{
+ CPed *attackerPed;
+
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS)
+ return;
+
+ if (attacker->IsPed()) {
+ attackerPed = (CPed*)attacker;
+ } else {
+ if (!attacker->IsVehicle())
+ return;
+
+ attackerPed = ((CVehicle*)attacker)->pDriver;
+ if (!attackerPed)
+ return;
+ }
+
+ if (attackerPed->m_nPedType == PEDTYPE_COP)
+ return;
+
+ for (int i = 0; i < m_numNearPeds; i++) {
+ CPed *nearPed = m_nearPeds[i];
+ if (nearPed && nearPed != this) {
+ CPed *leader = nearPed->m_leader;
+ if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper)
+ {
+ nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed);
+ nearPed->SetObjectiveTimer(30000);
+ }
+ }
+ }
+}
+
+void
+CPed::QuitEnteringCar(void)
+{
+ CAnimBlendAssociation *animAssoc = m_pVehicleAnim;
+ CVehicle *veh = m_pMyVehicle;
+ if (animAssoc)
+ animAssoc->blendDelta = -1000.0f;
+
+ RestartNonPartialAnims();
+
+ if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE))
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+
+ if (veh) {
+ if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK)
+ veh->m_veh_flagC10 = false;
+
+ if (veh->m_nNumGettingIn != 0)
+ veh->m_nNumGettingIn--;
+
+ veh->m_nGettingInFlags = GetVehEnterExitFlag(m_vehEnterType);
+ }
+
+ bUsesCollision = true;
+
+ if (IsPlayer() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) {
+ if (IsPlayer() && m_storedWeapon != NO_STORED_WEAPON) {
+ SetCurrentWeapon(m_storedWeapon);
+ m_storedWeapon = NO_STORED_WEAPON;
+ }
+ } else {
+ CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ AddWeaponModel(curWeapon->m_nModelId);
+ }
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) {
+ animAssoc = m_pVehicleAnim;
+ if (animAssoc) {
+ animAssoc->blendDelta = -4.0;
+ animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ animAssoc = m_pVehicleAnim;
+ animAssoc->flags &= ~ASSOC_RUNNING;
+ }
+ } else
+ SetIdle();
+
+ m_pVehicleAnim = nil;
+
+ if (veh) {
+ if (veh->m_autoPilot.m_nCruiseSpeed == 0)
+ veh->m_autoPilot.m_nCruiseSpeed = 17;
+ }
+}
+
+void
+CPed::ReactToAttack(CEntity *attacker)
+{
+ if (IsPlayer() && attacker->IsPed()) {
+ InformMyGangOfAttack(attacker);
+ SetLookFlag(attacker, 1);
+ SetLookTimer(700);
+ return;
+ }
+
+ if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) {
+ CPed *ourLeader = m_leader;
+ if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader)
+ && attacker->IsPed()) {
+
+ CPed *attackerPed = (CPed*)attacker;
+ if (bNotAllowedToDuck) {
+ if (!attackerPed->GetWeapon()->IsTypeMelee()) {
+ field_4E8 = CTimer::GetTimeInMilliseconds();
+ return;
+ }
+ } else if (bCrouchWhenShooting || m_ped_flagE1) {
+ SetDuck(CGeneral::GetRandomNumberInRange(1000,3000));
+ return;
+ }
+
+ if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) {
+ if (m_pedStats != attackerPed->m_pedStats) {
+ if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) {
+ RegisterThreatWithGangPeds(attackerPed);
+ }
+ if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) {
+ SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker);
+ SetMoveState(PEDMOVE_RUN);
+ } else {
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker);
+ SetObjectiveTimer(20000);
+ }
+ }
+ } else {
+ SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed);
+ SetMoveState(PEDMOVE_RUN);
+ if (attackerPed->GetWeapon()->IsTypeMelee())
+ Say(SOUND_PED_FLEE_RUN);
+ }
+ }
+ }
+}
+
+bool
+CPed::TurnBody(void)
+{
+ float lookDir;
+ bool doneSmoothly = true;
+
+ if (m_pLookTarget) {
+ CVector &lookPos = m_pLookTarget->GetPosition();
+
+ lookDir = CGeneral::GetRadianAngleBetweenPoints(
+ lookPos.x,
+ lookPos.y,
+ GetPosition().x,
+ GetPosition().y);
+ } else
+ lookDir = m_fLookDirection;
+
+ float limitedLookDir = CGeneral::LimitRadianAngle(lookDir);
+ float currentRot = m_fRotationCur;
+
+ if (currentRot - PI > limitedLookDir)
+ limitedLookDir += 2 * PI;
+ else if (PI + currentRot < limitedLookDir)
+ limitedLookDir -= 2 * PI;
+
+ float neededTurn = currentRot - limitedLookDir;
+ m_fRotationDest = limitedLookDir;
+
+ if (fabs(neededTurn) > 0.05f) {
+ doneSmoothly = false;
+ currentRot -= neededTurn * 0.2f;
+ }
+
+ m_fRotationCur = currentRot;
+ m_fLookDirection = limitedLookDir;
+ return doneSmoothly;
+}
+
+void
+CPed::Chat(void)
+{
+ if (bIsLooking && TurnBody())
+ ClearLookFlag();
+
+ if (!m_pLookTarget || !m_pLookTarget->IsPed()) {
+ ClearChat();
+ return;
+ }
+
+ CPed *partner = (CPed*) m_pLookTarget;
+
+ if (partner->m_nPedState != PED_CHAT) {
+ ClearChat();
+ if (partner->m_pedInObjective) {
+ if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT ||
+ partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE)
+ ReactToAttack(partner->m_pedInObjective);
+ }
+ return;
+ }
+ if (bIsTalking) {
+ if (CGeneral::GetRandomNumber() < 512) {
+ CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT);
+ if (chatAssoc) {
+ chatAssoc->blendDelta = -4.0f;
+ chatAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+ }
+ bIsTalking = false;
+ } else
+ Say(SOUND_PED_CHAT);
+
+ } else if (!RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject, ASSOC_FLAG100)) {
+
+ if (CGeneral::GetRandomNumber() < 20) {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
+ }
+ if (!bIsTalking) {
+ CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f);
+ float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f);
+ chatAssoc->SetCurrentTime(chatTime);
+
+ bIsTalking = true;
+ Say(SOUND_PED_CHAT);
+ }
+ }
+ if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) {
+ ClearChat();
+ m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000;
+ }
+}
+
WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
@@ -2612,5 +2937,14 @@ STARTPATCHES
InjectHook(0x4D72F0, &CPed::CanPedJumpThis, PATCH_JUMP);
InjectHook(0x4DD820, &CPed::CanSeeEntity, PATCH_JUMP);
InjectHook(0x4D9460, &CPed::RestorePreviousObjective, PATCH_JUMP);
+ InjectHook(0x4D82C0, (void (CPed::*)(eObjective)) &CPed::SetObjective, PATCH_JUMP);
InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP);
+ InjectHook(0x4D89A0, (void (CPed::*)(eObjective, int16, int16)) &CPed::SetObjective, PATCH_JUMP);
+ InjectHook(0x4DDEC0, &CPed::ReactToAttack, PATCH_JUMP);
+ InjectHook(0x4D0600, &CPed::SetIdle, PATCH_JUMP);
+ InjectHook(0x4E0E00, &CPed::QuitEnteringCar, PATCH_JUMP);
+ InjectHook(0x4E4AD0, &CPed::InformMyGangOfAttack, PATCH_JUMP);
+ InjectHook(0x4D3C80, &CPed::ClearChat, PATCH_JUMP);
+ InjectHook(0x4D1390, &CPed::TurnBody, PATCH_JUMP);
+ InjectHook(0x4D3AC0, &CPed::Chat, PATCH_JUMP);
ENDPATCHES
diff --git a/src/entities/Ped.h b/src/entities/Ped.h
index 4367dc61..c6d61df4 100644
--- a/src/entities/Ped.h
+++ b/src/entities/Ped.h
@@ -13,7 +13,31 @@
struct CPathNode;
-enum eObjective {
+enum eWaitState : uint32 {
+ WAITSTATE_FALSE,
+ WAITSTATE_TRAFFIC_LIGHTS,
+ WAITSTATE_CROSS_ROAD,
+ WAITSTATE_CROSS_ROAD_LOOK,
+ WAITSTATE_LOOK_PED,
+ WAITSTATE_LOOK_SHOP,
+ WAITSTATE_LOOK_ACCIDENT,
+ WAITSTATE_FACEOFF_GANG,
+ WAITSTATE_DOUBLEBACK,
+ WAITSTATE_HITWALL,
+ WAITSTATE_TURN180,
+ WAITSTATE_SURPRISE,
+ WAITSTATE_STUCK,
+ WAITSTATE_LOOK_ABOUT,
+ WAITSTATE_PLAYANIM_DUCK,
+ WAITSTATE_PLAYANIM_COWER,
+ WAITSTATE_PLAYANIM_TAXI,
+ WAITSTATE_PLAYANIM_HANDSUP,
+ WAITSTATE_PLAYANIM_HANDSCOWER,
+ WAITSTATE_PLAYANIM_CHAT,
+ WAITSTATE_FINISH_FLEE
+};
+
+enum eObjective : uint32 {
OBJECTIVE_NONE,
OBJECTIVE_IDLE,
OBJECTIVE_FLEE_TILL_SAFE,
@@ -52,7 +76,7 @@ enum eObjective {
OBJECTIVE_35
};
-enum {
+enum eVehEnter : uint16 {
VEHICLE_ENTER_FRONT_RIGHT = 11,
VEHICLE_ENTER_REAR_RIGHT = 12,
VEHICLE_ENTER_FRONT_LEFT = 15,
@@ -60,8 +84,8 @@ enum {
};
enum {
- CREATED_BY_RANDOM = 1,
- CREATED_BY_SCRIPT
+ RANDOM_CHAR = 1,
+ MISSION_CHAR,
};
enum PedLineUpPhase {
@@ -130,15 +154,15 @@ enum PedState
PED_PASSENGER,
PED_TAXI_PASSENGER,
PED_OPEN_DOOR,
- PED_DIE = 48,
- PED_DEAD = 49,
+ PED_DIE,
+ PED_DEAD,
PED_CARJACK,
PED_DRAG_FROM_CAR,
PED_ENTER_CAR,
PED_STEAL_CAR,
PED_EXIT_CAR,
PED_HANDS_UP,
- PED_ARRESTED = 56,
+ PED_ARRESTED,
};
enum eMoveState {
@@ -157,6 +181,8 @@ public:
// 0x128
CStoredCollPoly m_collPoly;
float m_fCollisionSpeed;
+
+ // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R*
uint8 bIsStanding : 1;
uint8 m_ped_flagA2 : 1;
uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
@@ -168,16 +194,16 @@ public:
uint8 bIsRestoringGun : 1;
uint8 bCanPointGunAtTarget : 1;
- uint8 m_ped_flagB4 : 1;
- uint8 m_ped_flagB8 : 1;
- uint8 m_ped_flagB10 : 1;
+ uint8 bIsTalking : 1;
+ uint8 bIsInTheAir : 1;
+ uint8 bIsLanding : 1;
uint8 m_ped_flagB20 : 1;
uint8 m_ped_flagB40 : 1;
uint8 m_ped_flagB80 : 1;
uint8 m_ped_flagC1 : 1;
- uint8 m_ped_flagC2 : 1;
- uint8 m_ped_flagC4 : 1;
+ uint8 bRespondsToThreats : 1;
+ uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar?
uint8 m_ped_flagC8 : 1;
uint8 m_ped_flagC10 : 1;
uint8 m_ped_flagC20 : 1; // just left some body part?
@@ -195,9 +221,9 @@ public:
uint8 m_ped_flagE1 : 1;
uint8 m_ped_flagE2 : 1;
- uint8 m_ped_flagE4 : 1;
- uint8 m_ped_flagE8 : 1; // can duck?
- uint8 bCantFireBecauseCrouched : 1; // set if you don't want ped to attack
+ uint8 bNotAllowedToDuck : 1;
+ uint8 bCrouchWhenShooting : 1;
+ uint8 bIsDucking : 1; // set if you don't want ped to attack
uint8 m_ped_flagE20 : 1;
uint8 bDoBloodyFootprints : 1;
uint8 m_ped_flagE80 : 1;
@@ -237,8 +263,9 @@ public:
uint8 m_ped_flagI20 : 1;
uint8 m_ped_flagI40 : 1;
uint8 m_ped_flagI80 : 1;
+
uint8 stuff10[3];
- uint8 m_nCreatedBy;
+ uint8 CharCreatedBy;
uint8 field_161;
uint8 pad_162[2];
eObjective m_objective;
@@ -270,7 +297,7 @@ public:
eMoveState m_nMoveState;
int32 m_nStoredActionState;
int32 m_nPrevActionState;
- int32 m_nWaitState;
+ eWaitState m_nWaitState;
uint32 m_nWaitTimer;
void *m_pPathNodesStates[8];
CVector2D m_stPathNodeStates[10];
@@ -286,15 +313,15 @@ public:
float m_fArmour;
int16 m_routeLastPoint;
uint16 m_routePoints;
- uint16 m_routePos;
- uint16 m_routeType;
- uint16 m_routeCurDir;
+ int16 m_routePos;
+ int16 m_routeType;
+ int16 m_routeCurDir;
uint16 field_2D2;
CVector2D m_moved;
float m_fRotationCur;
float m_fRotationDest;
float m_headingRate;
- uint16 m_vehEnterType;
+ eVehEnter m_vehEnterType;
uint16 m_walkAroundType;
CEntity *m_pCurrentPhysSurface;
CVector m_vecOffsetFromPhysSurface;
@@ -426,8 +453,20 @@ public:
bool CanPedJumpThis(int32);
bool CanSeeEntity(CEntity*, float);
void RestorePreviousObjective(void);
+ void SetIdle(void);
void SetObjective(eObjective, void*);
- void MakeChangesForNewWeapon(int8);
+ void SetObjective(eObjective);
+ void SetObjective(eObjective, int16, int16);
+ void ClearChat(void);
+ void InformMyGangOfAttack(CEntity*);
+ void SetFollowRoute(int16, int16);
+ void ReactToAttack(CEntity*);
+ void SetDuck(uint32);
+ void RegisterThreatWithGangPeds(CEntity*);
+ bool TurnBody(void);
+ void Chat(void);
+ void MakeChangesForNewWeapon(int8);
+
// Static methods
static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset);
@@ -483,11 +522,28 @@ public:
void SetStoredObjective(void);
void SetLeader(CEntity* leader);
void SetPedStats(ePedStats);
+ bool IsGangMember(void);
inline bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; }
inline CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }
inline CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; }
inline RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; }
+ inline static uint8 GetVehEnterExitFlag(eVehEnter vehEnter) {
+ switch (vehEnter) {
+ case VEHICLE_ENTER_FRONT_RIGHT:
+ return 4;
+ case VEHICLE_ENTER_REAR_RIGHT:
+ return 8;
+ case VEHICLE_ENTER_FRONT_LEFT:
+ return 1;
+ case VEHICLE_ENTER_REAR_LEFT:
+ return 2;
+ default:
+ return 0;
+ }
+ }
+ PedState GetPedState(void) { return m_nPedState; }
+ void SetPedState(PedState state) { m_nPedState = state; }
// to make patching virtual functions possible
void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); }
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index b570efd9..14891cd9 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -1858,10 +1858,10 @@ CPhysical::ProcessCollision(void)
CVehicle *veh = (CVehicle*)this;
if(veh->m_vehType == VEHICLE_TYPE_CAR){
CAutomobile *car = (CAutomobile*)this;
- car->m_afWheelSuspDist[0] = 1.0f;
- car->m_afWheelSuspDist[1] = 1.0f;
- car->m_afWheelSuspDist[2] = 1.0f;
- car->m_afWheelSuspDist[3] = 1.0f;
+ car->m_aWheelDist[0] = 1.0f;
+ car->m_aWheelDist[1] = 1.0f;
+ car->m_aWheelDist[2] = 1.0f;
+ car->m_aWheelDist[3] = 1.0f;
}else if(veh->m_vehType == VEHICLE_TYPE_BIKE){
assert(0 && "TODO - but unused");
}
diff --git a/src/entities/Physical.h b/src/entities/Physical.h
index 7776da92..0f517cf3 100644
--- a/src/entities/Physical.h
+++ b/src/entities/Physical.h
@@ -109,9 +109,9 @@ public:
// Force actually means Impulse here
void ApplyMoveForce(float jx, float jy, float jz);
void ApplyMoveForce(const CVector &j) { ApplyMoveForce(j.x, j.y, j.z); }
- // v(x,y,z) is direction of force, p(x,y,z) is point relative to model center where force is applied
- void ApplyTurnForce(float jx, float jy, float jz, float rx, float ry, float rz);
- // v is direction of force, p is point relative to model center where force is applied
+ // j(x,y,z) is direction of force, p(x,y,z) is point relative to model center where force is applied
+ void ApplyTurnForce(float jx, float jy, float jz, float px, float py, float pz);
+ // j is direction of force, p is point relative to model center where force is applied
void ApplyTurnForce(const CVector &j, const CVector &p) { ApplyTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
void ApplyFrictionMoveForce(float jx, float jy, float jz);
void ApplyFrictionMoveForce(const CVector &j) { ApplyFrictionMoveForce(j.x, j.y, j.z); }
diff --git a/src/entities/Vehicle.cpp b/src/entities/Vehicle.cpp
index f7c4b065..25bede65 100644
--- a/src/entities/Vehicle.cpp
+++ b/src/entities/Vehicle.cpp
@@ -1,9 +1,17 @@
#include "common.h"
+#include "main.h"
#include "patcher.h"
+#include "Timer.h"
#include "Vehicle.h"
#include "Pools.h"
+#include "HandlingMgr.h"
#include "CarCtrl.h"
+#include "Population.h"
#include "ModelIndices.h"
+#include "World.h"
+#include "Lights.h"
+#include "PointLights.h"
+#include "Renderer.h"
#include "DMAudio.h"
#include "Radar.h"
@@ -40,30 +48,238 @@ CVehicle::~CVehicle()
CCarCtrl::NumAmbulancesOnDuty--;
bIsAmbulanceOnDuty = false;
}
- if (bIsFiretruckOnDuty){
+ if (bIsFireTruckOnDuty){
CCarCtrl::NumFiretrucksOnDuty--;
- bIsFiretruckOnDuty = false;
+ bIsFireTruckOnDuty = false;
}
}
+void
+CVehicle::SetModelIndex(uint32 id)
+{
+ CEntity::SetModelIndex(id);
+ m_aExtras[0] = CVehicleModelInfo::ms_compsUsed[0];
+ m_aExtras[1] = CVehicleModelInfo::ms_compsUsed[1];
+ m_nNumMaxPassengers = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(id);
+}
+
+bool
+CVehicle::SetupLighting(void)
+{
+ ActivateDirectional();
+ SetAmbientColoursForPedsCarsAndObjects();
+
+ if(bRenderScorched){
+ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+ }else{
+ CVector coors = GetPosition();
+ float lighting = CPointLights::GenerateLightsAffectingObject(&coors);
+ if(!bHasBlip && lighting != 1.0f){
+ SetAmbientAndDirectionalColours(lighting);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+CVehicle::RemoveLighting(bool reset)
+{
+ CRenderer::RemoveVehiclePedLights(this, reset);
+}
+
+float
+CVehicle::GetHeightAboveRoad(void)
+{
+ return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z;
+}
+
+
bool
CVehicle::IsLawEnforcementVehicle(void)
{
- switch (m_modelIndex) {
- case MI_FBICAR:
+ switch(GetModelIndex()){
+ case MI_FBICAR:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_PREDATOR:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+CVehicle::UsesSiren(uint32 id)
+{
+ switch(id){
+ case MI_FIRETRUCK:
+ case MI_AMBULAN:
+ case MI_FBICAR:
+ case MI_MRWHOOP:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_PREDATOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+CVehicle::IsVehicleNormal(void)
+{
+ if(pDriver && m_nNumPassengers == 0 && m_status != STATUS_WRECKED){
+ switch(GetModelIndex())
+ case MI_FIRETRUCK:
+ case MI_AMBULAN:
+ case MI_TAXI:
case MI_POLICE:
case MI_ENFORCER:
- case MI_PREDATOR:
+ case MI_BUS:
case MI_RHINO:
case MI_BARRACKS:
- return true;
- default:
+ case MI_DODO:
+ case MI_COACH:
+ case MI_CABBIE:
+ case MI_RCBANDIT:
+ case MI_BORGNINE:
+ return false;
+ }
+ return false;
+}
+
+bool
+CVehicle::CarHasRoof(void)
+{
+ if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0)
+ return true;
+ if(m_aExtras[0] && m_aExtras[1])
+ return false;
+ return true;
+}
+
+bool
+CVehicle::IsUpsideDown(void)
+{
+ if(GetUp().z > -0.9f)
+ return false;
+ return true;
+}
+
+bool
+CVehicle::IsOnItsSide(void)
+{
+ if(GetRight().z < 0.8f && GetRight().z > -0.8f)
+ return false;
+ return true;
+}
+
+bool
+CVehicle::CanBeDeleted(void)
+{
+ int i;
+
+ if(m_nNumGettingIn || m_nGettingOutFlags)
+ return false;
+
+ if(pDriver){
+ // This looks like it was inlined
+ if(pDriver->CharCreatedBy == MISSION_CHAR)
+ return false;
+ if(pDriver->GetPedState() != PED_DRIVING &&
+ pDriver->GetPedState() != PED_DEAD)
+ return false;
+ }
+
+ for(i = 0; i < 8; i++){
+ // Same check as above
+ if(pPassengers[i]){
+ if(pPassengers[i]->CharCreatedBy == MISSION_CHAR)
+ return false;
+ if(pPassengers[i]->GetPedState() != PED_DRIVING &&
+ pPassengers[i]->GetPedState() != PED_DEAD)
+ return false;
+ }
+ // and then again... probably because something was inlined
+ if(pPassengers[i]){
+ if(pPassengers[i]->GetPedState() != PED_DRIVING &&
+ pPassengers[i]->GetPedState() != PED_DEAD)
+ return false;
+ }
+ }
+
+ switch(VehicleCreatedBy){
+ case RANDOM_VEHICLE: return true;
+ case MISSION_VEHICLE: return false;
+ case PARKED_VEHICLE: return true;
+ case PERMANENT_VEHICLE: return false;
+ }
+ return true;
+}
+
+bool
+CVehicle::CanPedOpenLocks(CPed *ped)
+{
+ if(m_nDoorLock == CARLOCK_LOCKED ||
+ m_nDoorLock == CARLOCK_COP_CAR ||
+ m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE)
+ return false;
+ if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
+ return false;
+ return true;
+}
+
+bool
+CVehicle::CanPedEnterCar(void)
+{
+ CVector up = GetUp();
+ // can't enter when car is on side
+ if(up.z > 0.1f || up.z < -0.1f){
+ // also when car is moving too fast
+ if(m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f))
+ return false;
+ if(m_vecTurnSpeed.MagnitudeSqr() > sq(0.2f))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+bool
+CVehicle::CanPedExitCar(void)
+{
+ CVector up = GetUp();
+ if(up.z > 0.1f || up.z < -0.1f){
+ // can't exit when car is moving too fast
+ if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f)
+ return false;
+ // if car is slow enough, check turn speed
+ if(fabs(m_vecTurnSpeed.x) > 0.01f ||
+ fabs(m_vecTurnSpeed.y) > 0.01f ||
+ fabs(m_vecTurnSpeed.z) > 0.01f)
+ return false;
+ return true;
+ }else{
+ // What is this? just > replaced by >= ??
+
+ // can't exit when car is moving too fast
+ if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f)
return false;
+ // if car is slow enough, check turn speed
+ if(fabs(m_vecTurnSpeed.x) >= 0.01f ||
+ fabs(m_vecTurnSpeed.y) >= 0.01f ||
+ fabs(m_vecTurnSpeed.z) >= 0.01f)
+ return false;
+ return true;
}
}
void
-CVehicle::ChangeLawEnforcerState(bool enable)
+CVehicle::ChangeLawEnforcerState(uint8 enable)
{
if (enable) {
if (!bIsLawEnforcer) {
@@ -78,6 +294,111 @@ CVehicle::ChangeLawEnforcerState(bool enable)
}
}
+CPed*
+CVehicle::SetUpDriver(void)
+{
+ if(pDriver)
+ return pDriver;
+ if(VehicleCreatedBy != RANDOM_VEHICLE)
+ return nil;
+
+ pDriver = CPopulation::AddPedInCar(this);
+ pDriver->m_pMyVehicle = this;
+ pDriver->m_pMyVehicle->RegisterReference((CEntity**)&pDriver->m_pMyVehicle);
+ pDriver->bInVehicle = true;
+ pDriver->SetPedState(PED_DRIVING);
+ if(bIsBus)
+ pDriver->m_ped_flagC4 = false;
+ return pDriver;
+}
+
+CPed*
+CVehicle::SetupPassenger(int n)
+{
+ if(pPassengers[n])
+ return pPassengers[n];
+
+ pPassengers[n] = CPopulation::AddPedInCar(this);
+ pPassengers[n]->m_pMyVehicle = this;
+ pPassengers[n]->m_pMyVehicle->RegisterReference((CEntity**)&pPassengers[n]->m_pMyVehicle);
+ pPassengers[n]->bInVehicle = true;
+ pPassengers[n]->SetPedState(PED_DRIVING);
+ if(bIsBus)
+ pPassengers[n]->m_ped_flagC4 = false;
+ return pPassengers[n];
+}
+
+void
+CVehicle::SetDriver(CPed *driver)
+{
+ pDriver = driver;
+ pDriver->RegisterReference((CEntity**)&pDriver);
+
+ if(bFreebies && driver == FindPlayerPed()){
+ if(GetModelIndex() == MI_AMBULAN)
+ FindPlayerPed()->m_fHealth = min(FindPlayerPed()->m_fHealth + 20.0f, 100.0f);
+ else if(GetModelIndex() == MI_TAXI)
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
+ else if(GetModelIndex() == MI_POLICE)
+ driver->GiveWeapon(WEAPONTYPE_SHOTGUN, 5);
+ else if(GetModelIndex() == MI_ENFORCER)
+ driver->m_fArmour = max(driver->m_fArmour, 100.0f);
+ else if(GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE)
+ CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 25;
+ bFreebies = false;
+ }
+
+ ApplyTurnForce(0.0f, 0.0f, -0.2f*driver->m_fMass,
+ driver->GetPosition().x - GetPosition().x,
+ driver->GetPosition().y - GetPosition().y,
+ 0.0f);
+}
+
+bool
+CVehicle::AddPassenger(CPed *passenger)
+{
+ int i;
+
+ ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
+ passenger->GetPosition().x - GetPosition().x,
+ passenger->GetPosition().y - GetPosition().y,
+ 0.0f);
+
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i] == nil){
+ pPassengers[i] = passenger;
+ m_nNumPassengers++;
+ return true;
+ }
+ return false;
+}
+
+bool
+CVehicle::AddPassenger(CPed *passenger, uint8 n)
+{
+ if(bIsBus)
+ return AddPassenger(passenger);
+
+ ApplyTurnForce(0.0f, 0.0f, -0.2f*passenger->m_fMass,
+ passenger->GetPosition().x - GetPosition().x,
+ passenger->GetPosition().y - GetPosition().y,
+ 0.0f);
+
+ if(n < m_nNumMaxPassengers && pPassengers[n] == nil){
+ pPassengers[n] = passenger;
+ m_nNumPassengers++;
+ return true;
+ }
+ return false;
+}
+
+void
+CVehicle::RemoveDriver(void)
+{
+ m_status = STATUS_ABANDONED;
+ pDriver = nil;
+}
+
void
CVehicle::RemovePassenger(CPed *p)
{
@@ -101,19 +422,68 @@ CVehicle::RemovePassenger(CPed *p)
}
void
-CVehicle::RemoveDriver(void)
+CVehicle::ProcessCarAlarm(void)
{
- m_status = STATUS_ABANDONED;
- pDriver = nil;
+ uint32 step;
+
+ if(m_nAlarmState == 0 || m_nAlarmState == -1)
+ return;
+
+ step = CTimer::GetTimeStep()/50.0f * 1000.0f;
+ if((uint16)m_nAlarmState < step)
+ m_nAlarmState = 0;
+ else
+ m_nAlarmState -= step;
}
bool
-CVehicle::IsUpsideDown(void)
+CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius)
{
- return GetUp().z <= -0.9f;
+ float x, y, z;
+ // sphere relative to vehicle
+ CVector sph = CVector(sx, sy, sz) - GetPosition();
+ CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel();
+
+ x = DotProduct(sph, GetRight());
+ if(colmodel->boundingBox.min.x - radius > x ||
+ colmodel->boundingBox.max.x + radius < x)
+ return false;
+ y = DotProduct(sph, GetForward());
+ if(colmodel->boundingBox.min.y - radius > y ||
+ colmodel->boundingBox.max.y + radius < y)
+ return false;
+ z = DotProduct(sph, GetUp());
+ if(colmodel->boundingBox.min.z - radius > z ||
+ colmodel->boundingBox.max.z + radius < z)
+ return false;
+
+ return true;
}
STARTPATCHES
+ InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP);
+ InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP);
+ InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP);
+ InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP);
+
+ InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP);
InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP);
+ InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP);
+ InjectHook(0x5527E0, &CVehicle::IsVehicleNormal, PATCH_JUMP);
+ InjectHook(0x552B70, &CVehicle::CarHasRoof, PATCH_JUMP);
+ InjectHook(0x552230, &CVehicle::IsUpsideDown, PATCH_JUMP);
+ InjectHook(0x552260, &CVehicle::IsOnItsSide, PATCH_JUMP);
+ InjectHook(0x5511B0, &CVehicle::CanBeDeleted, PATCH_JUMP);
+ InjectHook(0x5522A0, &CVehicle::CanPedOpenLocks, PATCH_JUMP);
+ InjectHook(0x5522F0, &CVehicle::CanPedEnterCar, PATCH_JUMP);
+ InjectHook(0x5523C0, &CVehicle::CanPedExitCar, PATCH_JUMP);
+ InjectHook(0x5520C0, &CVehicle::SetUpDriver, PATCH_JUMP);
+ InjectHook(0x552160, &CVehicle::SetupPassenger, PATCH_JUMP);
+ InjectHook(0x551F20, &CVehicle::SetDriver, PATCH_JUMP);
+ InjectHook(0x551D90, (bool (CVehicle::*)(CPed*))&CVehicle::AddPassenger, PATCH_JUMP);
+ InjectHook(0x551E10, (bool (CVehicle::*)(CPed*,uint8))&CVehicle::AddPassenger, PATCH_JUMP);
InjectHook(0x5520A0, &CVehicle::RemoveDriver, PATCH_JUMP);
-ENDPATCHES \ No newline at end of file
+ InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP);
+ InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP);
+ InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/entities/Vehicle.h b/src/entities/Vehicle.h
index ba3e568e..7b9bebef 100644
--- a/src/entities/Vehicle.h
+++ b/src/entities/Vehicle.h
@@ -1,19 +1,20 @@
#pragma once
#include "Physical.h"
+#include "AutoPilot.h"
class CPed;
class CFire;
struct tHandlingData;
enum {
- GETTING_IN_OUT_FL = 1,
- GETTING_IN_OUT_RL = 2,
- GETTING_IN_OUT_FR = 4,
- GETTING_IN_OUT_RR = 8
+ RANDOM_VEHICLE = 1,
+ MISSION_VEHICLE = 2,
+ PARKED_VEHICLE = 3,
+ PERMANENT_VEHICLE = 4,
};
-enum eCarLock : uint8 {
+enum eCarLock {
CARLOCK_NOT_USED,
CARLOCK_UNLOCKED,
CARLOCK_LOCKED,
@@ -24,15 +25,66 @@ enum eCarLock : uint8 {
CARLOCK_SKIP_SHUT_DOORS
};
+
+enum eCarNodes
+{
+ CAR_WHEEL_RF = 1,
+ CAR_WHEEL_RM,
+ CAR_WHEEL_RB,
+ CAR_WHEEL_LF,
+ CAR_WHEEL_LM,
+ CAR_WHEEL_LB,
+ CAR_BUMP_FRONT,
+ CAR_BUMP_REAR,
+ CAR_WING_RF,
+ CAR_WING_RR,
+ CAR_DOOR_RF,
+ CAR_DOOR_RR,
+ CAR_WING_LF,
+ CAR_WING_LR,
+ CAR_DOOR_LF,
+ CAR_DOOR_LR,
+ CAR_BONNET,
+ CAR_BOOT,
+ CAR_WINDSCREEN,
+ NUM_CAR_NODES,
+};
+
+enum
+{
+ CAR_POS_HEADLIGHTS,
+ CAR_POS_TAILLIGHTS,
+ CAR_POS_FRONTSEAT,
+ CAR_POS_BACKSEAT,
+ CAR_POS_EXHAUST = 9,
+};
+
+enum eDoors
+{
+ DOOR_BONNET = 0,
+ DOOR_BOOT,
+ DOOR_FRONT_LEFT,
+ DOOR_FRONT_RIGHT,
+ DOOR_REAR_LEFT,
+ DOOR_REAR_RIGHT
+};
+
+enum {
+ GETTING_IN_OUT_FL = 1,
+ GETTING_IN_OUT_RL = 2,
+ GETTING_IN_OUT_FR = 4,
+ GETTING_IN_OUT_RR = 8
+};
+
class CVehicle : public CPhysical
{
public:
// 0x128
tHandlingData *m_handling;
- uint8 stuff1[112];
+ CAutoPilot m_autoPilot;
uint8 m_currentColour1;
uint8 m_currentColour2;
- uint8 m_anExtras[2];
+ uint8 m_aExtras[2];
int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22
int16 m_nMissionValue;
CPed *pDriver;
@@ -48,23 +100,27 @@ public:
float m_fSteerAngle;
float m_fGasPedal;
float m_fBreakPedal;
- uint8 m_nCreatedBy; // eVehicleCreatedBy
- uint8 bIsLawEnforcer : 1;
- uint8 bIsAmbulanceOnDuty : 1;
- uint8 bIsFiretruckOnDuty : 1;
- uint8 m_veh_flagA8 : 1;
- uint8 m_veh_flagA10 : 1;
- uint8 m_veh_flagA20 : 1;
- uint8 m_veh_flagA40 : 1;
- uint8 m_veh_flagA80 : 1;
- uint8 bIsVan : 1;
- uint8 bIsBus : 1;
- uint8 bIsBig : 1;
- uint8 bIsLow : 1;
+ uint8 VehicleCreatedBy;
+
+ // cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R*
+ uint8 bIsLawEnforcer: 1; // Is this guy chasing the player at the moment
+ uint8 bIsAmbulanceOnDuty: 1; // Ambulance trying to get to an accident
+ uint8 bIsFireTruckOnDuty: 1; // Firetruck trying to get to a fire
+ uint8 bIsLocked: 1; // Is this guy locked by the script (cannot be removed)
+ uint8 bEngineOn: 1; // For sound purposes. Parked cars have their engines switched off (so do destroyed cars)
+ uint8 bIsHandbrakeOn: 1; // How's the handbrake doing ?
+ uint8 bLightsOn: 1; // Are the lights switched on ?
+ uint8 bFreebies: 1; // Any freebies left in this vehicle ?
+
+ uint8 bIsVan: 1; // Is this vehicle a van (doors at back of vehicle)
+ uint8 bIsBus: 1; // Is this vehicle a bus
+ uint8 bIsBig: 1; // Is this vehicle a bus
+ uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims
uint8 m_veh_flagB10 : 1;
uint8 m_veh_flagB20 : 1;
uint8 m_veh_flagB40 : 1;
uint8 m_veh_flagB80 : 1;
+
uint8 m_veh_flagC1 : 1;
uint8 m_veh_flagC2 : 1;
uint8 m_veh_flagC4 : 1;
@@ -73,6 +129,7 @@ public:
uint8 m_veh_flagC20 : 1;
uint8 m_veh_flagC40 : 1;
uint8 m_veh_flagC80 : 1;
+
uint8 m_veh_flagD1 : 1;
uint8 m_veh_flagD2 : 1;
uint8 m_veh_flagD4 : 1;
@@ -81,8 +138,9 @@ public:
uint8 m_veh_flagD20 : 1;
uint8 m_veh_flagD40 : 1;
uint8 m_veh_flagD80 : 1;
+
int8 field_1F9;
- uint8 m_nAmmoInClip[1]; // Used to make the guns on boat do a reload (20 by default)
+ uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default)
int8 field_1FB;
int8 field_1FC[4];
float m_fHealth; // 1000.0f = full health. 0 -> explode
@@ -105,6 +163,7 @@ public:
int8 field_22D;
uint8 m_nSirenOrAlarm;
int8 field_22F;
+ // TODO: this is an array
CStoredCollPoly m_frontCollPoly; // poly which is under front part of car
CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car
float m_fSteerRatio;
@@ -116,8 +175,29 @@ public:
static void operator delete(void*, int);
~CVehicle(void);
+ // from CEntity
+ void SetModelIndex(uint32 i);
+ bool SetupLighting(void);
+ void RemoveLighting(bool);
+ void FlagToDestroyWhenNextProcessed(void) {}
- void dtor(void) { this->CVehicle::~CVehicle(); }
+ virtual void ProcessControlInputs(uint8) {}
+ virtual void GetComponentWorldPosition(int32 component, CVector &pos) {}
+ virtual bool IsComponentPresent(int32 component) { return false; }
+ virtual void SetComponentRotation(int32 component, CVector rotation) {}
+ virtual void OpenDoor(int32, eDoors door, float) {}
+ virtual void ProcessOpenDoor(uint32, uint32, float) {}
+ virtual bool IsDoorReady(eDoors door) { return false; }
+ virtual bool IsDoorFullyOpen(eDoors door) { return false; }
+ virtual bool IsDoorClosed(eDoors door) { return false; }
+ virtual bool IsDoorMissing(eDoors door) { return false; }
+ virtual void RemoveRefsToVehicle(CEntity *ent) {}
+ virtual void BlowUpCar(CEntity *ent) {}
+ virtual bool SetUpWheelColModel(CColModel *colModel) { return false; }
+ virtual void BurstTyre(uint8 tyre) {}
+ virtual bool IsRoomForPedToLeaveCar(uint32, CVector *) { return false;}
+ virtual float GetHeightAboveRoad(void);
+ virtual void PlayCarHorn(void) {}
bool IsCar(void) { return m_vehType == VEHICLE_TYPE_CAR; }
bool IsBoat(void) { return m_vehType == VEHICLE_TYPE_BOAT; }
@@ -125,10 +205,26 @@ public:
bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; }
bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; }
bool IsLawEnforcementVehicle(void);
- void ChangeLawEnforcerState(bool enable);
- void RemovePassenger(CPed *);
- void RemoveDriver(void);
+ void ChangeLawEnforcerState(uint8 enable);
+ bool UsesSiren(uint32 id);
+ bool IsVehicleNormal(void);
+ bool CarHasRoof(void);
bool IsUpsideDown(void);
+ bool IsOnItsSide(void);
+ bool CanBeDeleted(void);
+ bool CanPedOpenLocks(CPed *ped);
+ bool CanPedEnterCar(void);
+ bool CanPedExitCar(void);
+ // do these two actually return something?
+ CPed *SetUpDriver(void);
+ CPed *SetupPassenger(int n);
+ void SetDriver(CPed *driver);
+ bool AddPassenger(CPed *passenger);
+ bool AddPassenger(CPed *passenger, uint8 n);
+ void RemovePassenger(CPed *passenger);
+ void RemoveDriver(void);
+ void ProcessCarAlarm(void);
+ bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
static bool &bWheelsOnlyCheat;
static bool &bAllDodosCheat;
@@ -136,8 +232,16 @@ public:
static bool &bCheat4;
static bool &bCheat5;
static bool &m_bDisableMouseSteering;
+
+
+ void dtor(void) { CVehicle::~CVehicle(); }
+ void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); }
+ bool SetupLighting_(void) { return CVehicle::SetupLighting(); }
+ void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); }
+ float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); }
};
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error");
static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error");
+static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error");