diff options
author | Nikolay Korolev <nickvnuk@gmail.com> | 2019-06-26 22:34:14 +0200 |
---|---|---|
committer | Nikolay Korolev <nickvnuk@gmail.com> | 2019-06-26 22:34:14 +0200 |
commit | 08b053a568e15dd318dcfc46eaa6393af4a5f8c4 (patch) | |
tree | 7e6a0bc15376f347c13029b99f2f0ec1427bf2c1 /src/entities | |
parent | More replay stuff (diff) | |
parent | bla (diff) | |
download | re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.gz re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.bz2 re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.lz re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.xz re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.zst re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.zip |
Diffstat (limited to 'src/entities')
-rw-r--r-- | src/entities/Building.cpp | 1 | ||||
-rw-r--r-- | src/entities/Building.h | 2 | ||||
-rw-r--r-- | src/entities/Entity.cpp | 5 | ||||
-rw-r--r-- | src/entities/Entity.h | 1 | ||||
-rw-r--r-- | src/entities/Ped.cpp | 598 | ||||
-rw-r--r-- | src/entities/Ped.h | 38 | ||||
-rw-r--r-- | src/entities/Physical.cpp | 2 | ||||
-rw-r--r-- | src/entities/Vehicle.cpp | 52 | ||||
-rw-r--r-- | src/entities/Vehicle.h | 93 |
9 files changed, 712 insertions, 80 deletions
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp index 9e56b3a2..d69a65fe 100644 --- a/src/entities/Building.cpp +++ b/src/entities/Building.cpp @@ -22,5 +22,6 @@ CBuilding::ReplaceWithNewModel(int32 id) } STARTPATCHES + InjectHook(0x4057D0, &CBuilding::ctor, PATCH_JUMP); InjectHook(0x405850, &CBuilding::ReplaceWithNewModel, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Building.h b/src/entities/Building.h index 7b837f46..b1f96bae 100644 --- a/src/entities/Building.h +++ b/src/entities/Building.h @@ -15,5 +15,7 @@ public: void ReplaceWithNewModel(int32 id); virtual bool GetIsATreadable(void) { return false; } + + CBuilding *ctor(void) { return ::new (this) CBuilding(); } }; static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error"); diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index d2b2577d..294518c8 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -339,9 +339,9 @@ CEntity::GetBoundRect(void) return rect; } -void +WRAPPER void CEntity::PreRender(void) -{ +{ EAXJMP(0x474350); } void @@ -448,6 +448,7 @@ CEntity::PruneReferences(void) } STARTPATCHES + InjectHook(0x473C30, &CEntity::ctor, PATCH_JUMP); InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP); InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP); InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP); diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 0ce47428..8816e206 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -155,6 +155,7 @@ public: // to make patching virtual functions possible + CEntity *ctor(void) { return ::new (this) CEntity(); } void Add_(void) { CEntity::Add(); } void Remove_(void) { CEntity::Remove(); } void CreateRwObject_(void) { CEntity::CreateRwObject(); } diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp index 20a5b48c..c4109312 100644 --- a/src/entities/Ped.cpp +++ b/src/entities/Ped.cpp @@ -10,11 +10,19 @@ #include "PlayerPed.h" #include "General.h" #include "VisibilityPlugins.h" +#include "AudioManager.h" +#include "HandlingMgr.h" +#include "Replay.h" +#include "PedPlacement.h" bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; bool &CPed::bPedCheat3 = *(bool*)0x95CD59; +CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030; +CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C; +CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048; + void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); } void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); } @@ -24,6 +32,9 @@ WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4 WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); } WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); } +WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } +WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } +WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } static char ObjectiveText[34][28] = { "No Obj", @@ -183,9 +194,8 @@ static char WaitStateText[21][16] = { static RwObject* RemoveAllModelCB(RwObject *object, void *data) { - RpAtomic* atomic = (RpAtomic*)object; - if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) - { + RpAtomic *atomic = (RpAtomic*)object; + if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { RpClumpRemoveAtomic(atomic->clump, atomic); RpAtomicDestroy(atomic); } @@ -299,6 +309,14 @@ CPed::UseGroundColModel(void) m_nPedState == PED_DEAD; } +bool +CPed::CanSetPedState(void) +{ + return m_nPedState != PED_DIE && m_nPedState != PED_ARRESTED && + m_nPedState != PED_ENTER_CAR && m_nPedState != PED_CARJACK && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_STEAL_CAR; +} + + void CPed::AddWeaponModel(int id) { @@ -398,8 +416,9 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk) RecurseFrameChildrenVisibilityCB(frame, 0); pos.x = 0.0f; - pos.z = 0.0f; pos.y = 0.0f; + pos.z = 0.0f; + for (frame = RwFrameGetParent(frame); frame; frame = RwFrameGetParent(frame)) RwV3dTransformPoints(&pos, &pos, 1, RwFrameGetMatrix(frame)); @@ -490,11 +509,11 @@ CPed::OurPedCanSeeThisOne(CEntity *target) // Check if target is behind ped if (DotProduct2D(dist, CVector2D(this->GetForward())) < 0.0f) - return 0; + return false; // Check if target is too far away - if (dist.Magnitude() < 40.0f) - return 0; + if (dist.Magnitude() >= 40.0f) + return false; // Check line of sight from head CVector headPos = this->GetPosition(); @@ -589,7 +608,7 @@ CPed::IsPedHeadAbovePos(float zOffset) RwMatrix mat; CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat); - return zOffset + GetPosition().z >= mat.pos.z; + return zOffset + GetPosition().z < RwMatrixGetPos(&mat)->z; } void @@ -602,22 +621,24 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) if (attackAssoc) { switch (attackAssoc->animId) { case ANIM_WEAPON_START_THROW: - if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1376) && ped->IsPlayer()) + if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1380) && ped->IsPlayer()) { - attackAssoc->blendDelta = -1000.0; + attackAssoc->blendDelta = -1000.0f; newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROWU); } else { - attackAssoc->blendDelta = -1000.0; + attackAssoc->blendDelta = -1000.0f; newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROW); } - newAnim->SetFinishCallback(CPed::FinishedAttackCB, ped); - break; + newAnim->SetFinishCallback(FinishedAttackCB, ped); + return; + case ANIM_FIGHT_PPUNCH: - attackAssoc->blendDelta = -8.0; + attackAssoc->blendDelta = -8.0f; attackAssoc->flags |= ASSOC_DELETEFADEDOUT; ped->ClearAttack(); - break; + return; + case ANIM_WEAPON_THROW: case ANIM_WEAPON_THROWU: if (ped->GetWeapon()->m_nAmmoTotal > 0) { @@ -626,12 +647,11 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) } break; default: - if (!ped->m_ped_flagA4) - ped->ClearAttack(); - break; } - } else if (!ped->m_ped_flagA4) + } + + if (!ped->m_ped_flagA4) ped->ClearAttack(); } @@ -658,7 +678,7 @@ CPed::Attack(void) ourWeaponFire = ourWeapon->m_eWeaponFire; weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_AnimToPlay); lastReloadWasInFuture = m_ped_flagA4; - reloadAnimAssoc = 0; + reloadAnimAssoc = nil; reloadAnim = NUM_ANIMS; delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; weaponAnim = ourWeapon->m_AnimToPlay; @@ -676,7 +696,7 @@ CPed::Attack(void) if (reloadAnimAssoc) { if (!CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) - CPed::ClearAttack(); + ClearAttack(); return; } @@ -686,12 +706,13 @@ CPed::Attack(void) lastReloadWasInFuture = true; if (!weaponAnimAssoc) { - if (ourWeapon->m_bThrow) { + weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_Anim2ToPlay); + delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; + + // Long throw granade, molotov + if (!weaponAnimAssoc && ourWeapon->m_bThrow) { weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU); delayBetweenAnimAndFire = 0.2f; - } else { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ourWeapon->m_Anim2ToPlay); - delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; } } if (weaponAnimAssoc) { @@ -739,15 +760,15 @@ CPed::Attack(void) // 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); - CPed::ClearLookFlag(); - CPed::ClearAimFlag(); + ClearLookFlag(); + ClearAimFlag(); m_ped_flagA4 = false; - m_ped_flagA8 = false; + bIsPointingGunAt = false; m_lastHitTime = CTimer::GetTimeInMilliseconds(); return; } } else { - if (weaponAnimAssoc->animId <= ANIM_WEAPON_BAT_V) { + if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); @@ -814,24 +835,22 @@ CPed::Attack(void) CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); } } else { - CPed::ClearAimFlag(); + ClearAimFlag(); // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) - if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep < ourWeapon->m_fAnimLoopEnd) { - if (ourWeaponType < WEAPONTYPE_SNIPERRIFLE) { - switch (ourWeaponType) { - case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_M16: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); - break; - default: - break; - } + if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { + switch (ourWeaponType) { + case WEAPONTYPE_UZI: + DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_AK47: + DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_M16: + DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); + break; + default: + break; } } @@ -885,7 +904,7 @@ CPed::RemoveWeaponModel(int modelId) void CPed::SetCurrentWeapon(eWeaponType weaponType) { - CWeaponInfo* weaponInfo; + CWeaponInfo *weaponInfo; if (HasWeapon(weaponType)) { weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); @@ -909,9 +928,7 @@ CPed::SelectGunIfArmed(void) if (m_weapons[i].m_nAmmoTotal > 0) { weaponType = m_weapons[i].m_eWeaponType; - // Original condition was ridiculous - // if (weaponType == WEAPONTYPE_COLT45 || weaponType < WEAPONTYPE_M16 || weaponType < WEAPONTYPE_FLAMETHROWER || weaponType == WEAPONTYPE_FLAMETHROWER) - if (weaponType < WEAPONTYPE_MOLOTOV) { + if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { SetCurrentWeapon(weaponType); return true; } @@ -960,7 +977,7 @@ CPed::ClearPointGunAt(void) ClearLookFlag(); ClearAimFlag(); - m_ped_flagA8 = false; + bIsPointingGunAt = false; if (m_nPedState == PED_AIM_GUN) { RestorePreviousState(); weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); @@ -975,6 +992,477 @@ CPed::ClearPointGunAt(void) } } +void +CPed::BeingDraggedFromCar(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId enterAnim; + bool dontRunAnim = false; + PedLineUpPhase lineUpType; + + if (!m_pVehicleAnim) { + CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f); + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_LSIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITP); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITPLO); + } + } + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + if (m_ped_flagF10) { + enterAnim = ANIM_CAR_QJACKED; + } else if (m_pMyVehicle->bIsLow) { + 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) + enterAnim = ANIM_CAR_LJACKED_RHS; + else + enterAnim = ANIM_CAR_JACKED_RHS; + } else + dontRunAnim = true; + + + if (!dontRunAnim) + m_pVehicleAnim = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, enterAnim); + + m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this); + lineUpType = LINE_UP_TO_CAR_START; + } else if (m_pVehicleAnim->currentTime <= 1.4f) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + lineUpType = LINE_UP_TO_CAR_START; + } else { + lineUpType = LINE_UP_TO_CAR_2; + } + + LineUpPedWithCar(lineUpType); +} + +void +CPed::RestartNonPartialAnims(void) +{ + CAnimBlendAssociation* assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); !assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->flags |= ASSOC_RUNNING; + } +} + +void +CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) +{ + CAnimBlendAssociation *quickJackedAssoc; + CVehicle *vehicle; + CPed *ped = (CPed*)arg; + eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType; + + quickJackedAssoc = RpAnimBlendClumpGetAssociation((RpClump*) ped->m_rwObject, ANIM_CAR_QJACKED); + if (ped->m_nPedState != PED_ARRESTED) { + ped->m_nLastPedState = PED_NONE; + if (dragAssoc) + dragAssoc->blendDelta = -1000.0; + } + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + ped->m_pSeekTarget = nil; + vehicle = ped->m_pMyVehicle; + + 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; + } + + if (vehicle->pDriver == ped) { + vehicle->RemoveDriver(); + if (vehicle->m_nDoorLock == CARLOCK_COP_CAR) + vehicle->m_nDoorLock = CARLOCK_UNLOCKED; + + if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) + vehicle->ChangeLawEnforcerState(false); + } else { + for (int i = 0; i < vehicle->m_nNumMaxPassengers; i++) { + if (vehicle->pPassengers[i] == ped) { + vehicle->pPassengers[i] = nil; + vehicle->m_nNumPassengers--; + } + } + } + + ped->bInVehicle = false; + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + + if (quickJackedAssoc) { + dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); + } else { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + if (ped->CanSetPedState()) + CAnimManager::BlendAnimation((RpClump*) ped->m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + } + + // Only uzi can be used on cars, so previous weapon was stored + if (ped->IsPlayer() && weaponType == WEAPONTYPE_UZI) { + if (ped->m_storedWeapon != NO_STORED_WEAPON) { + ped->SetCurrentWeapon(ped->m_storedWeapon); + ped->m_storedWeapon = NO_STORED_WEAPON; + } + } else { + ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); + } + ped->m_nStoredActionState = 0; + ped->m_ped_flagI4 = false; +} + +void +CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult) +{ + CVehicleModelInfo *vehModel; + CVector vehDoorPos; + CVector vehDoorOffset; + float seatOffset; + + vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex); + if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { + seatOffset = 0.0f; + vehDoorOffset = offsetToOpenVanDoor; + } else { + seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult; + if (veh->bIsLow) { + vehDoorOffset = offsetToOpenLowCarDoor; + } else { + vehDoorOffset = offsetToOpenRegularCarDoor; + } + } + + switch (enterType) { + case VEHICLE_ENTER_FRONT_RIGHT: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case VEHICLE_ENTER_REAR_RIGHT: + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case VEHICLE_ENTER_FRONT_LEFT: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + case VEHICLE_ENTER_REAR_LEFT: + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS]; + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + default: + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER]; + else + vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS]; + + vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); + } + *output = vehDoorPos - vehDoorOffset; +} + +// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. +void +CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType) +{ + CVector localPos; + CVector vehDoorPos; + + GetLocalPositionToOpenCarDoor(&localPos, veh, enterType, 1.0f); + vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); + +/* + // Not used. + CVector localVehDoorOffset; + + if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) { + localVehDoorOffset = offsetToOpenVanDoor; + } else { + if (veh->bIsLow) { + localVehDoorOffset = offsetToOpenLowCarDoor; + } else { + localVehDoorOffset = offsetToOpenRegularCarDoor; + } + } + + vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); +*/ + *output = vehDoorPos; +} + +void +CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset) +{ + CVector doorPos; + CMatrix vehMat(veh->GetMatrix()); + + GetLocalPositionToOpenCarDoor(output, veh, enterType, offset); + doorPos = Multiply3x3(vehMat, *output); + + *output = *veh->GetPosition() + doorPos; +} + +void +CPed::LineUpPedWithCar(PedLineUpPhase phase) +{ + bool vehIsUpsideDown = false; + int vehAnim; + float seatPosMult = 0.0f; + float currentZ; + float adjustedTimeStep; + + if (CReplay::IsPlayingBack()) + return; + + if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) { + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_LSIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITP)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITPLO)) { + SetPedPositionInCar(); + return; + } + m_ped_flagC8 = 1; + } + if (phase == LINE_UP_TO_CAR_START) { + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + CVehicle *veh = m_pMyVehicle; + + // Not quite right, IsUpsideDown func. checks for <= -0.9f. + // Since that function is also used in this file, doesn't this variable indicate upsidedownness?! + if (veh->GetUp().z <= -0.8f) + vehIsUpsideDown = true; + + if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { + if (vehIsUpsideDown) { + m_fRotationDest = -PI + atan2(-veh->GetForward().x, veh->GetForward().y); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y); + } else { + m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + } + } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { + if (vehIsUpsideDown) { + m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + } else if (veh->bIsBus) { + m_fRotationDest = -0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y); + } else { + m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + } + } + + if (!bInVehicle) + seatPosMult = 1.0f; + + if (m_pVehicleAnim) { + vehAnim = m_pVehicleAnim->animId; + + switch (vehAnim) { + case ANIM_CAR_JACKED_RHS: + case ANIM_CAR_LJACKED_RHS: + case ANIM_CAR_JACKED_LHS: + case ANIM_CAR_LJACKED_LHS: + case ANIM_CAR_QJACKED: + case ANIM_CAR_GETOUT_LHS: + case ANIM_CAR_GETOUT_LOW_LHS: + case ANIM_CAR_GETOUT_RHS: + case ANIM_CAR_GETOUT_LOW_RHS: + case ANIM_CAR_CRAWLOUT_RHS: + case ANIM_CAR_CRAWLOUT_RHS2: + case ANIM_VAN_GETIN_L: + case ANIM_VAN_GETOUT_L: + case ANIM_VAN_GETIN: + case ANIM_VAN_GETOUT: + seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_QJACK: + case ANIM_CAR_GETIN_LHS: + case ANIM_CAR_GETIN_LOW_LHS: + case ANIM_CAR_GETIN_RHS: + case ANIM_CAR_GETIN_LOW_RHS: + case ANIM_DRIVE_BOAT: + seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_CLOSEDOOR_LHS: + case ANIM_CAR_CLOSEDOOR_LOW_LHS: + case ANIM_CAR_CLOSEDOOR_RHS: + case ANIM_CAR_CLOSEDOOR_LOW_RHS: + case ANIM_CAR_SHUFFLE_RHS: + case ANIM_CAR_LSHUFFLE_RHS: + seatPosMult = 0.0f; + break; + case ANIM_CAR_CLOSE_LHS: + case ANIM_CAR_CLOSE_RHS: + case ANIM_COACH_OPEN_L: + case ANIM_COACH_OPEN_R: + case ANIM_COACH_IN_L: + case ANIM_COACH_IN_R: + case ANIM_COACH_OUT_L: + seatPosMult = 1.0f; + break; + default: + break; + } + } + + CVector neededPos; + + if (phase == LINE_UP_TO_CAR_2) { + neededPos = *GetPosition(); + } else { + GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult); + } + + CVector autoZPos = neededPos; + + if (veh->bIsInWater) { + if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) + autoZPos.z += 1.0f; + } else { + CPedPlacement::FindZCoorForPed(&autoZPos); + } + + if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { + neededPos.z = GetPosition().z; + + // Getting out + if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { + float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep(); + + // If we're not in ground at next step, apply animation + if (neededPos.z + pedZSpeedOnExit > autoZPos.z) { + m_vecMoveSpeed.z = pedZSpeedOnExit; + ApplyMoveSpeed(); + // Removing below line breaks the animation + neededPos.z = GetPosition().z; + } else { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } + } + } + + if (autoZPos.z > neededPos.z) { + currentZ = GetPosition().z; + if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) { + neededPos.z = autoZPos.z; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) { + adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep); + } + } else { + // We may need to raise up the ped + if (phase == LINE_UP_TO_CAR_START) { + currentZ = GetPosition().z; + + if (neededPos.z > currentZ) { + + if (m_pVehicleAnim && + (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS + || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) { + adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f); + + // Smoothly change ped position + neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ; + } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) { + neededPos.z = max(currentZ, autoZPos.z); + } + } + } + } + + // I hope + bool stillGettingInOut = false; + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) + stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10; + + if (!stillGettingInOut) { + m_fRotationCur = m_fRotationDest; + } else { + float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest); + float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; + + m_vecOffsetSeek.z = 0.0; + if (timeUntilStateChange <= 0.0f) { + m_vecOffsetSeek.x = 0.0; + m_vecOffsetSeek.y = 0.0; + } else { + neededPos -= timeUntilStateChange * m_vecOffsetSeek; + } + + if (limitedAngle >= PI + m_fRotationCur) { + limitedAngle -= 2 * PI; + } else if (limitedAngle <= m_fRotationCur - PI) { + limitedAngle += 2 * PI; + } + m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange); + } + + if (seatPosMult > 0.2f || vehIsUpsideDown) { + GetPosition() = neededPos; + + GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); + + // It will be all 0 after rotate. + GetPosition() = neededPos; + } else { + CVector output; + CMatrix vehDoorMat(veh->GetMatrix()); + + GetLocalPositionToOpenCarDoor(&output, veh, m_vehEnterType, 0.0f); + *vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output); + GetMatrix() = vehDoorMat; + } + +} + 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); } @@ -989,7 +1477,6 @@ WRAPPER void CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg) { WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF220); } WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); } -WRAPPER void CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF000); } WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); } WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } @@ -999,8 +1486,6 @@ WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJM WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6620); } WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } -WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E2480); } -WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E2920); } STARTPATCHES InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); @@ -1024,4 +1509,11 @@ STARTPATCHES InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP); InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP); InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP); + InjectHook(0x4E07D0, &CPed::BeingDraggedFromCar, PATCH_JUMP); + InjectHook(0x4CF000, &CPed::PedSetDraggedOutCarCB, PATCH_JUMP); + InjectHook(0x4C5D80, &CPed::RestartNonPartialAnims, PATCH_JUMP); + InjectHook(0x4E4730, &CPed::GetLocalPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4E4660, (void (*)(CVector*, CVehicle*, uint32, float)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4E1A30, (void (*)(CVector*, CVehicle*, uint32)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP); + InjectHook(0x4DF940, &CPed::LineUpPedWithCar, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Ped.h b/src/entities/Ped.h index 43131533..34c7a485 100644 --- a/src/entities/Ped.h +++ b/src/entities/Ped.h @@ -12,6 +12,19 @@ struct CPathNode; +enum { + VEHICLE_ENTER_FRONT_RIGHT = 11, + VEHICLE_ENTER_REAR_RIGHT = 12, + VEHICLE_ENTER_FRONT_LEFT = 15, + VEHICLE_ENTER_REAR_LEFT = 16, +}; + +enum PedLineUpPhase { + LINE_UP_TO_CAR_START, + LINE_UP_TO_CAR_END, + LINE_UP_TO_CAR_2 +}; + enum PedOnGroundState { NO_PED, PED_BELOW_PLAYER, @@ -102,7 +115,7 @@ public: uint8 m_ped_flagA1 : 1; uint8 m_ped_flagA2 : 1; uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime) - uint8 m_ped_flagA8 : 1; + uint8 bIsPointingGunAt : 1; uint8 bIsLooking : 1; uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA uint8 bIsRestoringLook : 1; @@ -177,15 +190,15 @@ public: int32 m_pEventEntity; float m_fAngleToEvent; AnimBlendFrameData *m_pFrames[PED_NODE_MAX]; - int32 m_animGroup; - int32 m_pVehicleAnim; + AssocGroupId m_animGroup; + CAnimBlendAssociation *m_pVehicleAnim; CVector2D m_vecAnimMoveDelta; CVector m_vecOffsetSeek; CPedIK m_pedIK; uint8 stuff1[8]; uint32 m_nPedStateTimer; PedState m_nPedState; - int32 m_nLastPedState; + PedState m_nLastPedState; int32 m_nMoveState; int32 m_nStoredActionState; int32 m_nPrevActionState; @@ -207,7 +220,9 @@ public: uint8 stuff2[20]; float m_fRotationCur; float m_fRotationDest; - uint8 stuff13[6]; + uint32 m_headingRate; + uint16 m_vehEnterType; + uint16 m_walkAroundType; CEntity *m_pCurrentPhysSurface; CVector m_vecOffsetFromPhysSurface; CEntity *m_pCurSurface; @@ -222,7 +237,7 @@ public: CEntity *m_pCollidingEntity; uint8 stuff6[12]; CWeapon m_weapons[NUM_PED_WEAPONTYPES]; - int32 stuff7; + eWeaponType m_storedWeapon; uint8 m_currentWeapon; // eWeaponType uint8 m_maxWeaponTypeAllowed; // eWeaponType uint8 stuff[2]; @@ -253,6 +268,7 @@ public: bool IsPlayer(void); bool UseGroundColModel(void); + bool CanSetPedState(void); void AddWeaponModel(int id); void AimGun(void); void KillPedWithCar(CVehicle *veh, float impulse); @@ -278,6 +294,13 @@ public: void Duck(void); void ClearDuck(void); void ClearPointGunAt(void); + void BeingDraggedFromCar(void); + void RestartNonPartialAnims(void); + void LineUpPedWithCar(PedLineUpPhase phase); + void SetPedPositionInCar(void); + 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 RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data); static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data); static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg); @@ -311,6 +334,9 @@ public: CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; } + static CVector &offsetToOpenRegularCarDoor; + static CVector &offsetToOpenLowCarDoor; + static CVector &offsetToOpenVanDoor; static bool &bNastyLimbsCheat; static bool &bPedCheat2; static bool &bPedCheat3; diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index adc53525..b35b2d11 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -1504,7 +1504,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists) else if(A->GetUp().z > 0.3f) adhesion = 0.0f; else - adhesion *= max(5.0f, 0.03f*impulseA + 1.0f); + adhesion *= min(5.0f, 0.03f*impulseA + 1.0f); } if(A->ApplyFriction(adhesion, aColPoints[i])) diff --git a/src/entities/Vehicle.cpp b/src/entities/Vehicle.cpp index bac05f7b..ced504a3 100644 --- a/src/entities/Vehicle.cpp +++ b/src/entities/Vehicle.cpp @@ -2,6 +2,8 @@ #include "patcher.h" #include "Vehicle.h" #include "Pools.h" +#include "CarCtrl.h" +#include "ModelIndices.h" bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78; bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75; @@ -11,3 +13,53 @@ bool &CVehicle::bCheat5 = *(bool *)0x95CD64; void *CVehicle::operator new(size_t sz) { return CPools::GetVehiclePool()->New(); } void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } + +bool +CVehicle::IsLawEnforcementVehicle(void) +{ + switch (m_modelIndex) { + case MI_FBICAR: + case MI_POLICE: + case MI_ENFORCER: + case MI_PREDATOR: + case MI_RHINO: + case MI_BARRACKS: + return true; + default: + return false; + } +} + +void +CVehicle::ChangeLawEnforcerState(bool enable) +{ + if (enable) { + if (!bIsLawEnforcer) { + bIsLawEnforcer = true; + CCarCtrl::NumLawEnforcerCars++; + } + } else { + if (bIsLawEnforcer) { + bIsLawEnforcer = false; + CCarCtrl::NumLawEnforcerCars--; + } + } +} + +void +CVehicle::RemoveDriver(void) +{ + m_status = STATUS_ABANDONED; + pDriver = nil; +} + +bool +CVehicle::IsUpsideDown(void) +{ + return GetUp().z <= -0.9f; +} + +STARTPATCHES + InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP); + InjectHook(0x5520A0, &CVehicle::RemoveDriver, PATCH_JUMP); +ENDPATCHES
\ No newline at end of file diff --git a/src/entities/Vehicle.h b/src/entities/Vehicle.h index fea15d35..f11e9e97 100644 --- a/src/entities/Vehicle.h +++ b/src/entities/Vehicle.h @@ -3,26 +3,53 @@ #include "Physical.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 +}; + +enum eCarLock : uint8 { + CARLOCK_NOT_USED, + CARLOCK_UNLOCKED, + CARLOCK_LOCKED, + CARLOCK_LOCKOUT_PLAYER_ONLY, + CARLOCK_LOCKED_PLAYER_INSIDE, + CARLOCK_COP_CAR, + CARLOCK_FORCE_SHUT_DOORS, + CARLOCK_SKIP_SHUT_DOORS +}; class CVehicle : public CPhysical { public: // 0x128 - uint8 stuff1[116]; + tHandlingData *m_handling; + uint8 stuff1[112]; uint8 m_currentColour1; uint8 m_currentColour2; - uint8 m_extra1; - uint8 m_extra2; - int16 m_nAlarmState; + uint8 m_anExtras[2]; + int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22 + int16 m_nMissionValue; CPed *pDriver; CPed *pPassengers[8]; - uint8 stuff2[24]; + uint8 m_nNumPassengers; + int8 m_nNumGettingIn; + int8 m_nGettingInFlags; + int8 m_nGettingOutFlags; + uint8 m_nNumMaxPassengers; + char field_1CD[19]; CEntity *m_pCurSurface; - void* m_pFire; - float m_fWheelState; - float m_fAcceleration; - uint8 stuff4[5]; - uint8 m_veh_flagA1 : 1; + CFire *m_pCarFire; + float m_fSteerAngle; + float m_fGasPedal; + float m_fBreakPedal; + uint8 m_nCreatedBy; // eVehicleCreatedBy + uint8 bIsLawEnforcer : 1; uint8 m_veh_flagA2 : 1; uint8 m_veh_flagA4 : 1; uint8 m_veh_flagA8 : 1; @@ -30,10 +57,10 @@ public: uint8 m_veh_flagA20 : 1; uint8 m_veh_flagA40 : 1; uint8 m_veh_flagA80 : 1; - uint8 m_veh_flagB1 : 1; - uint8 m_veh_flagB2 : 1; - uint8 m_veh_flagB4 : 1; - uint8 m_veh_flagB8 : 1; + uint8 bIsVan : 1; + uint8 bIsBus : 1; + uint8 bIsBig : 1; + uint8 bIsLow : 1; uint8 m_veh_flagB10 : 1; uint8 m_veh_flagB20 : 1; uint8 m_veh_flagB40 : 1; @@ -54,10 +81,34 @@ public: uint8 m_veh_flagD20 : 1; uint8 m_veh_flagD40 : 1; uint8 m_veh_flagD80 : 1; - uint8 stuff5[7]; - float m_fHealth; - uint8 stuff6[128]; - int32 m_vehType; + int8 field_1F9; + uint8 m_nAmmoInClip[1]; // Used to make the guns on boat do a reload (20 by default) + int8 field_1FB; + int8 field_1FC[4]; + float m_fHealth; // 1000.0f = full health. 0 -> explode + uint8 m_nCurrentGear; + int8 field_205[3]; + int field_208; + uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) + uint32 m_nTimeOfDeath; + int16 field_214; + int16 m_nBombTimer; // goes down with each frame + CPed *m_pWhoDetonatedMe; + float field_21C; + float field_220; + eCarLock m_nDoorLock; + int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage + int8 m_nRadioStation; + int8 field_22A; + int8 field_22B; + uint8 m_nCarHornTimer; + int8 field_22D; + uint8 m_nSirenOrAlarm; + int8 field_22F; + CStoredCollPoly m_frontCollPoly; // poly which is under front part of car + CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car + float m_fSteerRatio; + eVehicleType m_vehType; static void *operator new(size_t); static void operator delete(void*, size_t); @@ -67,6 +118,10 @@ public: bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; } bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; } bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; } + bool IsLawEnforcementVehicle(void); + void ChangeLawEnforcerState(bool enable); + void RemoveDriver(void); + bool IsUpsideDown(void); static bool &bWheelsOnlyCheat; static bool &bAllDodosCheat; @@ -74,5 +129,7 @@ public: static bool &bCheat4; static bool &bCheat5; }; + 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"); |