From 0f9178568b3470d35ffc1d5e21a230d8cc11eef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Mon, 16 Sep 2019 20:32:58 +0300 Subject: Peds, a fix and a tad of VC --- src/control/CarCtrl.cpp | 7 +- src/control/Garages.cpp | 3 +- src/control/Garages.h | 3 +- src/core/General.h | 9 +- src/core/World.h | 3 +- src/peds/CivilianPed.cpp | 26 +- src/peds/CivilianPed.h | 1 - src/peds/Ped.cpp | 885 ++++++++++++++++++++++++++++++++++++++++++----- src/peds/Ped.h | 13 +- 9 files changed, 827 insertions(+), 123 deletions(-) diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index cae010d2..0be8a0a0 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -696,7 +696,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) } if (pVehicle->bExtendedRange) threshold *= 1.5f; - if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){ + if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ if (pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)){ pVehicle->bFadeOut = true; }else{ @@ -712,9 +712,10 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f && !IsThisVehicleInteresting(pVehicle) && !pVehicle->bIsLocked && + pVehicle->CanBeDeleted() && !CTrafficLights::ShouldCarStopForLight(pVehicle, true) && !CTrafficLights::ShouldCarStopForBridge(pVehicle) && - !CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){ + !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ CWorld::Remove(pVehicle); delete pVehicle; return; @@ -724,7 +725,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) if (CTimer::GetTimeInMilliseconds() > pVehicle->m_nTimeOfDeath + 60000 && (!pVehicle->GetIsOnScreen() || !CRenderer::IsEntityCullZoneVisible(pVehicle))){ if ((pVehicle->GetPosition() - vecPlayerPos).MagnitudeSqr() > SQR(7.5f)){ - if (!CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){ + if (!CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ CWorld::Remove(pVehicle); delete pVehicle; } diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 0e9592dc..560a9c0c 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -69,7 +69,8 @@ bool CGarages::HasCarBeenCrushed(int32 handle) } WRAPPER void CGarages::TriggerMessage(const char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); } -WRAPPER bool CGarages::IsPointWithinHideOutGarage(CVector*) { EAXJMP(0x428260); } +WRAPPER bool CGarages::IsPointWithinHideOutGarage(CVector&) { EAXJMP(0x428260); } +WRAPPER bool CGarages::IsPointWithinAnyGarage(CVector&) { EAXJMP(0x428320); } #if 0 WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); } diff --git a/src/control/Garages.h b/src/control/Garages.h index 4c35fad1..cc5fb62b 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -25,5 +25,6 @@ public: static void TriggerMessage(const char *text, int16, uint16 time, int16); static void PrintMessages(void); static bool HasCarBeenCrushed(int32); - static bool IsPointWithinHideOutGarage(CVector*); + static bool IsPointWithinHideOutGarage(CVector&); + static bool IsPointWithinAnyGarage(CVector&); }; diff --git a/src/core/General.h b/src/core/General.h index 366c571c..d73cf36f 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -54,14 +54,7 @@ public: static float LimitRadianAngle(float angle) { - float result; - - if (angle < -25.0f) - result = -25.0f; - else if (angle > 25.0f) - result = 25.0f; - else - result = angle; + float result = clamp(angle, -25.0f, 25.0f); while (result >= PI) { result -= 2 * PI; diff --git a/src/core/World.h b/src/core/World.h index b24e66f0..523585e7 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -56,9 +56,10 @@ class CWorld static CPtrList &ms_listMovingEntityPtrs; static CSector (*ms_aSectors)[NUMSECTORS_X]; // [NUMSECTORS_Y][NUMSECTORS_X]; static uint16 &ms_nCurrentScanCode; - static CColPoint &ms_testSpherePoint; public: + static CColPoint& ms_testSpherePoint; + static uint8 &PlayerInFocus; static CPlayerInfo *Players; static CEntity *&pIgnoreEntity; diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index f28a1134..93cdcb3d 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -8,34 +8,11 @@ WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) { SetModelIndex(mi); - for (int i = 0; i < 10; i++) - { + for (int i = 0; i < 10; i++) { m_nearPeds[i] = nil; } } -bool -CCivilianPed::ProcessNearestFreePhone(int unused) -{ - if (m_nPedState == PED_SEEK_POS) - return false; - - int phoneId = gPhoneInfo.FindNearestFreePhone(&GetPosition()); - - if (phoneId == -1) - return false; - - if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) - return false; - - bRunningToPhone = true; - SetMoveState(PEDMOVE_RUN); - SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); - m_phoneId = phoneId; - m_lookingForPhone = unused; - return true; -} - class CCivilianPed_ : public CCivilianPed { public: @@ -46,5 +23,4 @@ public: STARTPATCHES InjectHook(0x4BFF30, &CCivilianPed_::ctor, PATCH_JUMP); InjectHook(0x4BFFC0, &CCivilianPed_::dtor, PATCH_JUMP); - InjectHook(0x4C10C0, &CCivilianPed::ProcessNearestFreePhone, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CivilianPed.h b/src/peds/CivilianPed.h index e5e63682..14859a5c 100644 --- a/src/peds/CivilianPed.h +++ b/src/peds/CivilianPed.h @@ -9,6 +9,5 @@ public: ~CCivilianPed(void) { } void ProcessControl(void); - bool ProcessNearestFreePhone(int); }; static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 68b7579a..50385dc1 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -40,6 +40,8 @@ #include "CopPed.h" #include "Script.h" #include "CarCtrl.h" +#include "Garages.h" +#include "WaterLevel.h" WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } @@ -49,7 +51,6 @@ WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB 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::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); } WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); } WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); } @@ -60,11 +61,12 @@ WRAPPER void CPed::ServiceTalking(void) { EAXJMP(0x4E5870); } WRAPPER void CPed::UpdatePosition(void) { EAXJMP(0x4C7A00); } WRAPPER void CPed::WanderRange(void) { EAXJMP(0x4D26C0); } WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); } -WRAPPER void CPed::ReactToPointGun(CEntity*) { EAXJMP(0x4DD980); } WRAPPER void CPed::SeekCar(void) { EAXJMP(0x4D3F90); } WRAPPER void CPed::SeekBoatPosition(void) { EAXJMP(0x4E4C70); } WRAPPER bool CPed::PositionPedOutOfCollision(void) { EAXJMP(0x4E4F30); } +#define VC_PED_PORTS + CPed *gapTempPedList[50]; uint16 gnNumTempPedList; @@ -86,11 +88,11 @@ uint16 &CPed::nThreatReactionRangeMultiplier = *(uint16*)0x5F8C98; CVector vecPedCarDoorAnimOffset; CVector vecPedCarDoorLoAnimOffset; CVector vecPedVanRearDoorAnimOffset; -CVector &vecPedQuickDraggedOutCarAnimOffset = *(CVector*)0x62E06C; -CVector &vecPedDraggedOutCarAnimOffset = *(CVector*)0x62E060; -CVector &vecPedTrainDoorAnimOffset = *(CVector*)0x62E054; +CVector vecPedQuickDraggedOutCarAnimOffset; +CVector vecPedDraggedOutCarAnimOffset; +CVector vecPedTrainDoorAnimOffset; -CVector2D CPed::ms_vec2DFleePosition; // = *(CVector2D*)0x6EDF70; +CVector2D CPed::ms_vec2DFleePosition; void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); } void *CPed::operator new(size_t sz, int handle) { return CPools::GetPedPool()->New(handle); } @@ -298,6 +300,11 @@ CPed::DebugRenderOnePedText(void) CFont::PrintString(screenCoords.x, screenCoords.y + 2 * lineHeight, gUString); AsciiToUnicode(WaitStateText[m_nWaitState], gUString); CFont::PrintString(screenCoords.x, screenCoords.y + 3 * lineHeight, gUString); + if (m_nPedState == PED_SEEK_POS || m_nPedState == PED_SEEK_ENTITY) { + sprintf(gString, "Will stop when %.2f left to target", m_distanceToCountSeekDone); + AsciiToUnicode(gString, gUString); + CFont::PrintString(screenCoords.x, screenCoords.y + 4 * lineHeight, gUString); + } DefinedState(); } } @@ -513,7 +520,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bClearObjective = false; m_ped_flagH10 = false; bCollidedWithMyVehicle = false; - m_ped_flagH40 = false; + bRichFromMugging = false; m_ped_flagH80 = false; bShakeFist = false; @@ -537,8 +544,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fAngleToEvent = 0.0f; m_numNearPeds = 0; - for (int i = 0; i < 10; i++) - { + for (int i = 0; i < 10; i++) { m_nearPeds[i] = nil; if (i < 8) { m_pPathNodesStates[i] = nil; @@ -548,8 +554,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_currentWeapon = WEAPONTYPE_UNARMED; m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) - { + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { CWeapon &weapon = GetWeapon(i); weapon.m_eWeaponType = WEAPONTYPE_UNARMED; weapon.m_eWeaponState = WEAPONSTATE_READY; @@ -789,7 +794,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) if (!IsPlayer() || evenOnPlayer) { ++CStats::HeadsPopped; - // BUG: This condition will always return true. + // BUG: This condition will always return true. Even fixing it won't work, because these states are unused. if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { CPed::SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); } @@ -1474,7 +1479,6 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) CAnimBlendAssociation *quickJackedAssoc; CVehicle *vehicle; CPed *ped = (CPed*)arg; - eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType; quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED); if (ped->m_nPedState != PED_ARRESTED) { @@ -1512,15 +1516,8 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) CAnimManager::BlendAnimation(ped->GetClump(), 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 != WEAPONTYPE_UNIDENTIFIED) { - ped->SetCurrentWeapon(ped->m_storedWeapon); - ped->m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - } - } else { - ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); - } + ped->GiveWeaponBackAfterExitingCar(); + ped->m_nStoredMoveState = PEDMOVE_NONE; ped->m_ped_flagI4 = false; } @@ -1849,10 +1846,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (seatPosMult > 0.2f || vehIsUpsideDown) { GetPosition() = neededPos; - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - - // It will be all 0 after rotate. - GetPosition() = neededPos; + SetHeading(m_fRotationCur); } else { CMatrix vehDoorMat(veh->GetMatrix()); vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); @@ -2023,7 +2017,7 @@ CPed::SortPeds(CPed **list, int min, int max) int left = max; int right; for(right = min; right <= left; ){ - // Those 1.0s are to make sure loop always run for first time. + // Those 1.0s are my addition to make sure loop always run for first time. for (float rightDist = middleDist-1.0f; middleDist > rightDist; right++) { rightDiff = GetPosition() - list[right]->GetPosition(); rightDist = rightDiff.Magnitude(); @@ -2183,12 +2177,7 @@ CPed::CalculateNewOrientation(void) if (CReplay::IsPlayingBack() || !IsPedInControl()) return; - CVector pos = GetPosition(); - - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - - // Because SetRotate makes pos. all 0 - GetPosition() = pos; + SetHeading(m_fRotationCur); } float @@ -2317,8 +2306,8 @@ CPed::CanPedDriveOff(void) return false; for (int i = 0; i < m_numNearPeds; i++) { - CPed *ped = m_nearPeds[i]; - if (ped->m_nPedType == m_nPedType && ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && ped->m_carInObjective == m_carInObjective) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && nearPed->m_carInObjective == m_carInObjective) { m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; return false; } @@ -2326,17 +2315,27 @@ CPed::CanPedDriveOff(void) return true; } - -// TODO: Make this function actually work. bool CPed::CanPedJumpThis(CEntity *unused) { +#ifndef VC_PED_PORTS CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); CVector pos = GetPosition(); CVector forwardPos( forward.x + pos.x, forward.y + pos.y, pos.z); +#else + if (m_nSurfaceTouched == SURFACE_PUDDLE) + return true; + + // VC makes some other calculations if the function called with CVector. + + CVector pos = GetPosition(); + pos.z -= 0.15f; + + CVector forwardPos = pos + GetForward(); +#endif return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); } @@ -2799,15 +2798,8 @@ CPed::QuitEnteringCar(void) bUsesCollision = true; - if (IsPlayer() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { - if (IsPlayer() && m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { - SetCurrentWeapon(m_storedWeapon); - m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - } - } else { - CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(curWeapon->m_nModelId); - } + GiveWeaponBackAfterExitingCar(); + if (DyingOrDead()) { animAssoc = m_pVehicleAnim; if (animAssoc) { @@ -4382,8 +4374,8 @@ CPed::SetAttack(CEntity *victim) 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) + CEntity *thereIsSomethingBetween = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false); + if (thereIsSomethingBetween) return; m_pLookTarget = victim; @@ -4787,7 +4779,7 @@ CPed::FightStrike(CVector &touchedNodePos) CEventList::RegisterEvent(nearPed->m_nPedType == PEDTYPE_COP ? EVENT_ASSAULT_POLICE : EVENT_ASSAULT, EVENT_ENTITY_PED, nearPed, this, 2000); } - if (!m_fightState) + if (m_fightState == FIGHTSTATE_NO_MOVE) m_fightState = FIGHTSTATE_1; m_vecHitLastPos = *touchedNodePos; @@ -5175,7 +5167,7 @@ CPed::CollideWithPed(CPed *collideWith) if (heIsMissionChar || !weAreMissionChar && collideWith->m_nMoveState != PEDMOVE_STILL) { - if (weAreMissionChar && ((m_nPedState == PED_SEEK_POS) || m_nPedState == PED_SEEK_ENTITY)) { + 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())) { @@ -5382,6 +5374,7 @@ CPed::CreateDeadPedMoney(void) int moneyPerPickup = money / pickupCount; for(int i = 0; i < pickupCount; i++) { + // (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish. float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().x; float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().y; bool found = false; @@ -5475,9 +5468,7 @@ CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) bChangedSeat = false; bWillBeQuickJacked = quickJack; - CVector pos = GetPosition(); - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - GetPosition() += pos; + SetHeading(m_fRotationCur); Say(SOUND_PED_CAR_JACKED); SetRadioStation(); @@ -5955,9 +5946,7 @@ CPed::LineUpPedWithTrain(void) } GetPosition() = lineUpPos; -// CVector pedPos = GetPosition(); - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - GetPosition() += lineUpPos; + SetHeading(m_fRotationCur); } void @@ -7966,15 +7955,15 @@ CPed::IsRoomToBeCarJacked(void) if (!m_pMyVehicle) return false; - CVector2D offset; + CVector offset; if (m_pMyVehicle->bLowVehicle || m_nPedType == PEDTYPE_COP) { offset = vecPedDraggedOutCarAnimOffset; } else { offset = vecPedQuickDraggedOutCarAnimOffset; } - CVector doorPos(offset.x, offset.y, 0.0f); - if (m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, &doorPos)) { + offset.z = 0.0f; + if (m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, &offset)) { return true; } @@ -8170,6 +8159,10 @@ CPed::KillPedWithCar(CVehicle *car, float impulse) bKnockedUpIntoAir = false; distVec.Normalise(); + +#ifdef VC_PED_PORTS + distVec *= min(car->m_fMass / 1400.0f, 1.0f); +#endif car->ApplyMoveForce(distVec * -100.0f); Say(SOUND_PED_DEFEND); @@ -8200,6 +8193,9 @@ CPed::KillPedWithCar(CVehicle *car, float impulse) } m_vecMoveSpeed.z = 0.0f; distVec.Normalise(); +#ifdef VC_PED_PORTS + distVec *= min(car->m_fMass / 1400.0f, 1.0f); +#endif car->ApplyMoveForce(distVec * -60.0f); Say(SOUND_PED_DEFEND); } @@ -9097,12 +9093,179 @@ CPed::ProcessControl(void) } case ENTITY_TYPE_VEHICLE: { - CVehicle *collidingVeh = ((CVehicle*)collidingEnt); + CVehicle* collidingVeh = ((CVehicle*)collidingEnt); float collidingVehSpeedSqr = collidingVeh->m_vecMoveSpeed.MagnitudeSqr(); if (collidingVeh == m_pMyVehicle) bCollidedWithMyVehicle = true; +#ifdef VC_PED_PORTS + float oldHealth = m_fHealth; + bool playerSufferSound = false; + + if (collidingVehSpeedSqr <= 1.0f / 400.0f) { + if (IsPedInControl() + && (!IsPlayer() + || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT + || m_objective == OBJECTIVE_RUN_TO_AREA + || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)) { + + if (collidingVeh != m_pCurrentPhysSurface || IsPlayer()) { + if (!m_ped_flagB80) { + if (collidingVeh->m_status != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { + + // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. + SetDirectionToWalkAroundObject(collidingVeh); + CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; + } else { + if (CTimer::GetTimeInMilliseconds() >= CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer + || m_nPedStateTimer >= CTimer::GetTimeInMilliseconds()) { + + // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. + SetDirectionToWalkAroundObject(collidingVeh); + CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; + + } else if (m_fleeFrom != collidingVeh) { + SetFlee(collidingVeh, 4000); + bUsePedNodeSeek = false; + SetMoveState(PEDMOVE_WALK); + } + } + } + } else { + float angleLeftToCompleteTurn = Abs(m_fRotationCur - m_fRotationDest); + if (angleLeftToCompleteTurn < 0.01f && CanPedJumpThis(collidingVeh)) { + SetJump(); + } + } + } else if (IsPlayer() && !bIsInTheAir) { + + if (IsPedInControl() && ((CPlayerPed*)this)->m_fMoveSpeed == 0.0f + && !bIsLooking && CTimer::GetTimeInMilliseconds() > m_lookTimer && collidingVeh->pDriver) { + + ((CPlayerPed*)this)->AnnoyPlayerPed(false); + SetLookFlag(collidingVeh, true); + SetLookTimer(1300); + + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + if (weaponType == WEAPONTYPE_UNARMED + || weaponType == WEAPONTYPE_BASEBALLBAT + || weaponType == WEAPONTYPE_COLT45 + || weaponType == WEAPONTYPE_UZI) { + bShakeFist = true; + } + } else { + SetLookFlag(collidingVeh, true); + SetLookTimer(500); + } + } + } else { + float adjustedImpulse = m_fDamageImpulse; + if (IsPlayer()) { + if (bIsStanding) { + float forwardVecAndDamageDirDotProd = DotProduct(m_vecAnimMoveDelta.y * GetForward(), m_vecDamageNormal); + if (forwardVecAndDamageDirDotProd < 0.0f) { + adjustedImpulse = forwardVecAndDamageDirDotProd * m_fMass + m_fDamageImpulse; + if (adjustedImpulse < 0.0f) + adjustedImpulse = 0.0f; + } + } + } + if (m_fMass / 20.0f < adjustedImpulse) + DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, adjustedImpulse); + + if (IsPlayer()) { + /* VC specific + if (adjustedImpulse > 20.0f) + adjustedImpulse = 20.0f; + + if (adjustedImpulse > 5.0f) { + if (adjustedImpulse <= 13.0f) + playerSufferSound = true; + else + Say(104); + } + */ + CColModel* collidingCol = CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(); + CVector colMinVec = collidingCol->boundingBox.min; + CVector colMaxVec = collidingCol->boundingBox.max; + + CVector vehColCenterDist = collidingVeh->GetMatrix() * ((colMinVec + colMaxVec) * 0.5f) - GetPosition(); + + // TLVC = To look vehicle center + + float angleToVehFront = collidingVeh->GetForward().Heading(); + float angleDiffFromLookingFrontTLVC = angleToVehFront - vehColCenterDist.Heading(); + angleDiffFromLookingFrontTLVC = CGeneral::LimitRadianAngle(angleDiffFromLookingFrontTLVC); + + // Not sure about this one + float minNeededTurnTLVC = Atan2(colMaxVec.x - colMinVec.x, colMaxVec.y - colMinVec.y); + + CVector vehDist = GetPosition() - collidingVeh->GetPosition(); + vehDist.Normalise(); + + float vehRightVecAndSpeedDotProd; + + if (Abs(angleDiffFromLookingFrontTLVC) >= minNeededTurnTLVC && Abs(angleDiffFromLookingFrontTLVC) < PI - minNeededTurnTLVC) { + if (angleDiffFromLookingFrontTLVC <= 0.0f) { + vehRightVecAndSpeedDotProd = DotProduct(collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); + + // vehRightVecAndSpeedDotProd < 0.1f = Vehicle being overturned or spinning to it's right? + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { + + // Car's right faces towards us and isn't coming directly to us + if (DotProduct(collidingVeh->GetRight(), GetForward()) < 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(-1.0f * collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { + if (DotProduct(collidingVeh->GetRight(), GetForward()) > 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(vehDist, collidingVeh->m_vecMoveSpeed); + } + + if (vehRightVecAndSpeedDotProd <= 0.1f) { + if (m_nPedState != PED_FIGHT) { + SetLookFlag(collidingVeh, true); + SetLookTimer(700); + } + } else { + bIsStanding = false; + CVector2D collidingEntMoveDir = -collidingVeh->m_vecMoveSpeed; + int dir = GetLocalDirection(collidingEntMoveDir); + SetFall(1000, (AnimationId)(dir + 25), false); + + float damage; + if (collidingVeh->m_modelIndex == MI_TRAIN) { + damage = 50.0f; + } else { + damage = 20.0f; + } + + InflictDamage(collidingVeh, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, dir); + Say(SOUND_PED_DAMAGE); + } + } else { + KillPedWithCar(collidingVeh, m_fDamageImpulse); + } + + /* VC specific + bPushedAlongByCar = true; + */ + } + /* VC specific + if (m_fHealth < oldHealth && playerSufferSound) + Say(105); + */ +#else if (collidingVehSpeedSqr <= 1.0f / 400.0f) { if (!IsPedInControl() || IsPlayer() @@ -9134,9 +9297,8 @@ CPed::ProcessControl(void) SetLookTimer(500); } } - } else if (!m_ped_flagB80) { - // I don't remember any condition that we were STATUS_PLAYER. + } else if (!m_ped_flagB80) { if (collidingVeh->m_status != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { SetDirectionToWalkAroundObject(collidingVeh); @@ -9154,7 +9316,7 @@ CPed::ProcessControl(void) } } } else { - DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, 142, m_fDamageImpulse); + DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, m_fDamageImpulse); if (IsPlayer()) { CColModel *collidingCol = CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(); CVector colMinVec = collidingCol->boundingBox.min; @@ -9231,6 +9393,7 @@ CPed::ProcessControl(void) KillPedWithCar(collidingVeh, m_fDamageImpulse); } } +#endif break; } case ENTITY_TYPE_PED: @@ -9265,7 +9428,12 @@ CPed::ProcessControl(void) } } CVector forceDir; - if (!bIsInTheAir && m_nPedState != PED_JUMP) { + if (!bIsInTheAir && m_nPedState != PED_JUMP +#ifdef VC_PED_PORTS + && m_fDamageImpulse > 0.0f +#endif + ) { + forceDir = m_vecDamageNormal; forceDir.z = 0.0f; if (!bIsStanding) { @@ -9276,7 +9444,11 @@ CPed::ProcessControl(void) ApplyMoveForce(forceDir); } - if (bIsInTheAir && !DyingOrDead()) { + if ((bIsInTheAir && !DyingOrDead()) +#ifdef VC_PED_PORTS + || (!bIsStanding && !m_ped_flagA2 && m_nPedState == PED_FALL) +#endif + ) { if (m_nPedStateTimer <= 1000 && m_nPedStateTimer) { forceDir = GetPosition() - m_vecHitLastPos; } else { @@ -9332,19 +9504,36 @@ CPed::ProcessControl(void) m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints(offsetToCheck.x, offsetToCheck.y, 0.0f, 0.0f); m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); m_fRotationDest = m_fRotationCur; - CVector pos = GetPosition(); - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - GetPosition() += pos; + SetHeading(m_fRotationCur); if (m_nPedState != PED_FALL && !bIsPedDieAnimPlaying) { CPed::SetFall(1000, ANIM_KO_SKID_BACK, true); } bIsInTheAir = false; } else if (m_vecDamageNormal.z > 0.4f) { +#ifndef VC_PED_PORTS forceDir = m_vecDamageNormal; forceDir.z = 0.0f; forceDir.Normalise(); ApplyMoveForce(2.0f * forceDir); +#else + if (m_nPedState == PED_JUMP) { + if (m_nWaitTimer <= 2000) { + if (m_nWaitTimer < 1000) + m_nWaitTimer += CTimer::GetTimeStep() * 0.02f * 1000.0f; + } else { + m_nWaitTimer = 0; + } + } + forceDir = m_vecDamageNormal; + forceDir.z = 0.0f; + forceDir.Normalise(); + if (m_nPedState != PED_JUMP || m_nWaitTimer >= 300) { + ApplyMoveForce(2.0f * forceDir); + } else { + ApplyMoveForce(-4.0f * forceDir); + } +#endif } } else if ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 3) & 7) { if (IsPlayer() && m_nPedState != PED_JUMP && pad0->JumpJustDown()) { @@ -9355,9 +9544,7 @@ CPed::ProcessControl(void) m_fRotationDest -= TheCamera.Orientation; m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); m_fRotationCur = m_fRotationDest; - CVector pos = GetPosition(); - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - GetPosition() += pos; + SetHeading(m_fRotationCur); } SetJump(); m_nPedStateTimer = 0; @@ -9373,9 +9560,7 @@ CPed::ProcessControl(void) m_fRotationDest -= TheCamera.Orientation; m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); m_fRotationCur = m_fRotationDest; - CVector pos = GetPosition(); - GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); - GetPosition() += pos; + SetHeading(m_fRotationCur); } CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_GLIDE); @@ -9434,8 +9619,31 @@ CPed::ProcessControl(void) m_vecMoveSpeed *= airResistance; } +#ifdef VC_PED_PORTS + if (IsPlayer() || !bIsStanding || m_vecMoveSpeed.x != 0.0f || m_vecMoveSpeed.y != 0.0f || m_vecMoveSpeed.z != 0.0f + || (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) + || m_vecAnimMoveDelta.x != 0.0f || m_vecAnimMoveDelta.y != 0.0f + || m_nPedState == PED_JUMP + || bIsInTheAir + || m_pCurrentPhysSurface) { + CPhysical::ProcessControl(); + } else { + bHasContacted = false; + bIsInSafePosition = false; + bWasPostponed = false; + bHasHitWall = false; + m_nCollisionRecords = 0; + bHasCollided = false; + m_nDamagePieceType = 0; + m_fDamageImpulse = 0.0f; + m_pDamageEntity = nil; + m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); + m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + } +#else CPhysical::ProcessControl(); +#endif if (m_nPedState != PED_DIE || bIsPedDieAnimPlaying) { if (m_nPedState != PED_DEAD) { CalculateNewVelocity(); @@ -10381,11 +10589,13 @@ CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) if (!veh->bIsBus) veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); - // Duplicate and pointless code + /* + // Duplicate and only in PC for some reason if (!veh) { PedSetOutCarCB(nil, ped); return; } + */ eDoors door; switch (ped->m_vehEnterType) { case CAR_DOOR_RF: @@ -10860,10 +11070,520 @@ CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) veh->AddPassenger(ped); } -WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } -WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } -WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } -WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } +void +CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + /* + CPed *ped = (CPed*)arg; + + if (ped->m_nPedState == PED_STAGGER) + // nothing + */ +} + +// It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB, but it's not true, someone made it up. +// TO-DO: No peds run to phones to report crimes. Make this work. +bool +CPed::RunToReportCrime(eCrimeType crimeToReport) +{ + if (m_nPedState == PED_SEEK_POS) + return false; + + CVector pos = GetPosition(); + int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); + + if (phoneId == -1) + return false; + + if (gPhoneInfo.m_aPhones[phoneId].m_nState != PHONE_STATE_FREE) + return false; + + bRunningToPhone = true; + SetMoveState(PEDMOVE_RUN); + SetSeek(gPhoneInfo.m_aPhones[phoneId].m_vecPos, 0.3f); + m_phoneId = phoneId; + m_crimeToReportOnPhone = crimeToReport; + return true; +} + +void +CPed::RegisterThreatWithGangPeds(CEntity *attacker) +{ + CPed *attackerPed = nil; + if (attacker) { + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed && (attackerPed->IsPlayer() || attackerPed->IsGangMember())) { + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->IsPointerValid()) { + if (nearPed != this && nearPed->m_nPedType == m_nPedType) + nearPed->m_fearFlags |= CPedType::GetFlag(attackerPed->m_nPedType); + } + } + } + } + } + + if (attackerPed && attackerPed->IsPlayer() && (attackerPed->m_nPedState == PED_CARJACK || attackerPed->bInVehicle)) { + if (!attackerPed->m_pMyVehicle || attackerPed->m_pMyVehicle->m_modelIndex != MI_TOYZ) { + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), 30.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + if (lastVehicle > 8) + lastVehicle = 8; + + for (int j = 0; j < lastVehicle; ++j) { + CVehicle *nearVeh = (CVehicle*) vehicles[j]; + + if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { + CPed *nearVehDriver = nearVeh->pDriver; + + if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { + + if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { + nearVeh->AutoPilot.m_nCruiseSpeed = 60.0f * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; + nearVeh->m_status = STATUS_PHYSICS; + nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; + nearVeh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + } + } + } + } + } +} + +void +CPed::ReactToPointGun(CEntity *entWithGun) +{ + CPed *pedWithGun = (CPed*)entWithGun; + int waitTime; + + if (IsPlayer() || !IsPedInControl() || CharCreatedBy == MISSION_CHAR) + return; + + if (m_leader == pedWithGun) + return; + + if (m_nWaitState == WAITSTATE_PLAYANIM_HANDSUP || m_nWaitState == WAITSTATE_PLAYANIM_HANDSCOWER || + (GetPosition() - pedWithGun->GetPosition()).MagnitudeSqr2D() > 225.0f) + return; + + if (m_leader) { + if (FindPlayerPed() == m_leader) + return; + + ClearLeader(); + } + if (m_pedStats->m_flags & STAT_GUN_PANIC + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_AIM_GUN) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSCOWER, &waitTime); + Say(SOUND_PED_HANDS_COWER); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + + } else if (m_nPedType != pedWithGun->m_nPedType) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(pedWithGun); + } + + if (m_nPedType == PEDTYPE_COP) { + if (pedWithGun->IsPlayer()) { + ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); + } + if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + } + + } else if (m_nPedType != PEDTYPE_COP + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && (m_nPedState != PED_FLEE_ENTITY || pedWithGun->IsPlayer() && m_fleeFrom != pedWithGun) + && m_nPedState != PED_AIM_GUN && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSUP, &waitTime); + Say(SOUND_PED_HANDS_UP); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + if (m_nPedState == PED_FLEE_ENTITY) { + m_fleeFrom = pedWithGun; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + } + + if (FindPlayerPed() == pedWithGun && bRichFromMugging) { + int money = CGeneral::GetRandomNumberInRange(100, 300); + int pickupCount = money / 40 + 1; + int moneyPerPickup = money / pickupCount; + + for (int i = 0; i < pickupCount; i++) { + // (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish. + float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().x; + float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().y; + bool found = false; + float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; + if (found) { + CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); + } + } + bRichFromMugging = false; + } + } + } +} + +void +CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + bool startedToRun = false; + ped->bUsesCollision = true; + ped->m_actionX = 0.0f; + ped->m_actionY = 0.0f; + ped->m_ped_flagI4 = false; + if (veh && veh->IsCar()) + ped->ApplyMoveSpeed(); + + if (ped->m_objective == OBJECTIVE_LEAVE_VEHICLE) + ped->RestorePreviousObjective(); + + ped->bInVehicle = false; + if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { + ped->PositionPedOutOfCollision(); + } + + if (ped->m_nPedState == PED_EXIT_CAR) { + if (ped->m_nPedType == PEDTYPE_COP) + ped->SetIdle(); + else + ped->RestorePreviousState(); + + veh = ped->m_pMyVehicle; + if (ped->bFleeAfterExitingCar && veh) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 12000); + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->SetMoveState(PEDMOVE_RUN); + ped->Say(SOUND_PED_FLEE_RUN); + } + startedToRun = true; + + // This is not a good way to do this... + ped->m_nLastPedState = PED_WANDER_PATH; + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) + ped->SetObjectiveTimer(30000); + ped->m_nLastPedState = PED_NONE; + + } else if (ped->bGonnaKillTheCarJacker) { + + // Kill objective is already given at this point. + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective) { + if (!(CGeneral::GetRandomNumber() & 1) + && ped->m_nPedType != PEDTYPE_COP + && (!ped->m_pedInObjective->IsPlayer() || !CTheScripts::IsPlayerOnAMission())) { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1500; + } + int waitTime = 1500; + ped->SetWaitState(WAITSTATE_PLAYANIM_COWER, &waitTime); + ped->SetMoveState(PEDMOVE_RUN); + startedToRun = true; + } else if (ped->m_objective == OBJECTIVE_NONE && ped->CharCreatedBy != MISSION_CHAR && ped->m_nPedState == PED_IDLE && !ped->IsPlayer()) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } + } + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + CVector posFromZ = ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posFromZ); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->GetPosition() = posFromZ; + veh = ped->m_pMyVehicle; + if (veh) { + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { + if (veh->pDriver) { + if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= 100; + if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney < 0) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = 0; + } + } + } + veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + if (veh->pDriver == ped) { + veh->RemoveDriver(); + veh->m_status = STATUS_ABANDONED; + if (veh->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + veh->m_nDoorLock = CARLOCK_UNLOCKED; + if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) + veh->ChangeLawEnforcerState(false); + } else { + veh->RemovePassenger(ped); + } + + if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { + float angleAfterExit; + if (ped->m_vehEnterType == CAR_DOOR_LF) { + angleAfterExit = HALFPI + veh->GetForward().Heading(); + } else { + angleAfterExit = veh->GetForward().Heading() - HALFPI; + } + ped->SetHeading(angleAfterExit); + ped->m_fRotationDest = angleAfterExit; + ped->m_fRotationCur = angleAfterExit; + if (!ped->bBusJacked) + ped->SetMoveState(PEDMOVE_WALK); + } + if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) + veh->bLightsOn = false; + } + + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + + ped->GiveWeaponBackAfterExitingCar(); + + ped->m_ped_flagG10 = false; + if (ped->bBusJacked) { + ped->SetFall(1500, ANIM_KO_SKID_BACK, false); + ped->bBusJacked = false; + } + ped->m_nStoredMoveState = PEDMOVE_NONE; + if (!ped->IsPlayer()) { + // It's a shame... +#ifdef FIX_BUGS + int createdBy = ped->CharCreatedBy; +#else + int createdBy = !ped->CharCreatedBy; +#endif + + if (createdBy == MISSION_CHAR && !startedToRun) + ped->SetMoveState(PEDMOVE_WALK); + } +} + +inline void +CPed::GiveWeaponBackAfterExitingCar(void) +{ + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + + // If it's Uzi, we may have stored weapon. Uzi is the only gun we can use in car. + if (IsPlayer() && weaponType == WEAPONTYPE_UZI) { + if (m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { + SetCurrentWeapon(m_storedWeapon); + m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; + } + } else { + AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); + } +} + +void +CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; + + ped->bUsesCollision = true; + ped->m_pVehicleAnim = nil; + ped->bInVehicle = false; + ped->m_nPedState = PED_IDLE; + ped->RestorePreviousObjective(); + ped->SetMoveState(PEDMOVE_STILL); + + CMatrix pedMat(ped->GetMatrix()); + ped->m_fRotationCur = HALFPI + veh->GetForward().Heading(); + ped->m_fRotationDest = ped->m_fRotationCur; + CVector posAfterExit = Multiply3x3(pedMat, vecPedTrainDoorAnimOffset); + posAfterExit += ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posAfterExit); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->GetPosition() = posAfterExit; + ped->SetHeading(ped->m_fRotationCur); + veh->RemovePassenger(ped); +} + +bool +CPed::PlacePedOnDryLand(void) +{ + float waterLevel = 0.0f; + CEntity *foundEnt = nil; + CColPoint foundCol; + float foundColZ; + + CWaterLevel::GetWaterLevelNoWaves(GetPosition().x, GetPosition().y, GetPosition().z, &waterLevel); + + CVector potentialGround = GetPosition(); + potentialGround.z = waterLevel; + + if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) + return false; + + CVector potentialGroundDist = CWorld::ms_testSpherePoint.point - GetPosition(); + potentialGroundDist.z = 0.0f; + potentialGroundDist.Normalise(); + + CVector posToCheck = 0.5f * potentialGroundDist + CWorld::ms_testSpherePoint.point; + posToCheck.z = 3.0f + waterLevel; + + if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, false)) { + foundColZ = foundCol.point.z; + if (foundColZ >= waterLevel) { + posToCheck.z = 0.8f + foundColZ; + GetPosition() = posToCheck; + bIsStanding = true; + m_ped_flagA2 = true; + return true; + } + } + + posToCheck = 5.0f * potentialGroundDist + GetPosition(); + posToCheck.z = 3.0f + waterLevel; + + if (!CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, false)) + return false; + + foundColZ = foundCol.point.z; + if (foundColZ < waterLevel) + return false; + + posToCheck.z = 0.8f + foundColZ; + GetPosition() = posToCheck; + bIsStanding = true; + m_ped_flagA2 = true; + return true; +} + +void +CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + CVector finalPos; + CVector draggedOutOffset; + CVector finalLocalPos; + + CMatrix pedMat(ped->GetMatrix()); + ped->bUsesCollision = true; + ped->RestartNonPartialAnims(); + draggedOutOffset = vecPedQuickDraggedOutCarAnimOffset; + if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + draggedOutOffset.x = -draggedOutOffset.x; + + finalLocalPos = Multiply3x3(pedMat, draggedOutOffset); + finalPos = finalLocalPos + ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&finalPos); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->GetPosition() = finalPos; + + if (veh) { + ped->m_fRotationDest = veh->GetForward().Heading() - HALFPI; + ped->m_fRotationCur = ped->m_fRotationDest; + ped->CalculateNewOrientation(); + + if (!veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedQuickDraggedOutCarAnimOffset)) + ped->PositionPedOutOfCollision(); + } + + if (!ped->CanSetPedState()) + return; + + ped->SetIdle(); + if (veh) { + if (ped->bFleeAfterExitingCar) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 14000); + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + + } else if (ped->bGonnaKillTheCarJacker) { + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective && CGeneral::GetRandomNumber() & 1) { + if (ped->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped->m_pedInObjective); + + } else { + CPed *driver = veh->pDriver; + if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { + ped->SetFlee(veh->GetPosition(), 14000); + } else { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + ped->Say(SOUND_PED_FLEE_RUN); + } + } else { + if (ped->m_pedStats->m_temper <= ped->m_pedStats->m_fear + || ped->CharCreatedBy == MISSION_CHAR || veh->VehicleCreatedBy == MISSION_VEHICLE + || !veh->pDriver || !veh->pDriver->IsPlayer() + || CTheScripts::IsPlayerOnAMission()) { + + ped->SetFlee(veh->GetPosition(), 10000); + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->Say(SOUND_PED_FLEE_RUN); + } + } else if (CGeneral::GetRandomNumber() < 0x3FFF) { + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); + } else + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + } + if (ped->m_nLastPedState == PED_IDLE) + ped->m_nLastPedState = PED_WANDER_PATH; +} class CPed_ : public CPed { @@ -11054,4 +11774,11 @@ STARTPATCHES InjectHook(0x4E2920, &CPed::PedSetDraggedOutCarPositionCB, PATCH_JUMP); InjectHook(0x4CF220, &CPed::PedSetInCarCB, PATCH_JUMP); InjectHook(0x4E3290, &CPed::PedSetInTrainCB, PATCH_JUMP); + InjectHook(0x4C10C0, &CPed::RunToReportCrime, PATCH_JUMP); + InjectHook(0x4E3870, &CPed::RegisterThreatWithGangPeds, PATCH_JUMP); + InjectHook(0x4DD980, &CPed::ReactToPointGun, PATCH_JUMP); + InjectHook(0x4CE8F0, &CPed::PedSetOutCarCB, PATCH_JUMP); + InjectHook(0x4E36E0, &CPed::PedSetOutTrainCB, PATCH_JUMP); + InjectHook(0x4EB6E0, &CPed::PlacePedOnDryLand, PATCH_JUMP); + InjectHook(0x4E2480, &CPed::PedSetQuickDraggedOutCarPositionCB, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index a14a8c4b..177f934d 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -14,6 +14,7 @@ #include "EventList.h" struct CPathNode; +class CAccident; struct CPedAudioData { @@ -57,6 +58,7 @@ struct FightMove }; static_assert(sizeof(FightMove) == 0x18, "FightMove: error"); +// TO-DO: This is eFightState on mobile. enum PedFightMoves { FIGHTMOVE_NULL, @@ -169,7 +171,7 @@ enum { enum PedLineUpPhase { LINE_UP_TO_CAR_START, LINE_UP_TO_CAR_END, - LINE_UP_TO_CAR_2 + LINE_UP_TO_CAR_2 // Buggy. Used for cops arresting you from passenger door }; enum PedOnGroundState { @@ -330,7 +332,7 @@ public: uint8 bClearObjective : 1; uint8 m_ped_flagH10 : 1; uint8 bCollidedWithMyVehicle : 1; - uint8 m_ped_flagH40 : 1; + uint8 bRichFromMugging : 1; // ped has lots of cash from mugging people - will drop money if someone points gun to him uint8 m_ped_flagH80 : 1; uint8 bShakeFist : 1; // test shake hand at look entity @@ -411,9 +413,9 @@ public: bool bRunningToPhone; uint8 field_31D; int16 m_phoneId; - uint32 m_lookingForPhone; // unused + eCrimeType m_crimeToReportOnPhone; uint32 m_phoneTalkTimer; - void *m_lastAccident; + CAccident *m_lastAccident; int32 m_nPedType; CPedStats *m_pedStats; float m_fleeFromPosX; @@ -646,6 +648,8 @@ public: void SeekCar(void); void SeekBoatPosition(void); bool PositionPedOutOfCollision(void); + bool RunToReportCrime(eCrimeType); + bool PlacePedOnDryLand(void); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -724,6 +728,7 @@ public: PedState GetPedState(void) { return m_nPedState; } void SetPedState(PedState state) { m_nPedState = state; } bool DyingOrDead(void) { return m_nPedState == PED_DIE || m_nPedState == PED_DEAD; } + void GiveWeaponBackAfterExitingCar(void); // set by 0482:set_threat_reaction_range_multiplier opcode static uint16 &nThreatReactionRangeMultiplier; -- cgit v1.2.3