From e5df72a1e97af788f100c0d8bfaa842ae8bdfe7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Fri, 23 Aug 2019 01:44:38 +0300 Subject: [PATCH] Peds --- src/core/EventList.h | 7 +- src/math/Matrix.h | 1 + src/math/math.cpp | 6 + src/peds/Ped.cpp | 742 +++++++++++++++++++++++++++++++++++------ src/peds/Ped.h | 26 +- src/peds/PedIK.cpp | 85 ++++- src/peds/PedIK.h | 16 +- src/peds/PlayerPed.cpp | 8 +- 8 files changed, 764 insertions(+), 127 deletions(-) diff --git a/src/core/EventList.h b/src/core/EventList.h index 9f5756be..2799fca4 100644 --- a/src/core/EventList.h +++ b/src/core/EventList.h @@ -22,13 +22,12 @@ enum eEventType EVENT_PED_SET_ON_FIRE, EVENT_COP_SET_ON_FIRE, EVENT_CAR_SET_ON_FIRE, - EVENT_ASSAULT_NASTYWEAPON, - EVENT_ASSAULT_NASTYWEAPON_POLICE, + EVENT_ASSAULT_NASTYWEAPON, // not sure EVENT_ICECREAM, EVENT_ATM, - EVENT_SHOPSTALL, + EVENT_SHOPSTALL, // used on graffitis EVENT_SHOPWINDOW, - EVENT_LAST_EVENT + EVENT_LAST_EVENT // may be above one }; enum eEventEntity diff --git a/src/math/Matrix.h b/src/math/Matrix.h index bfe85afa..7d8c02ab 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -212,6 +212,7 @@ public: } void SetRotate(float xAngle, float yAngle, float zAngle); void Rotate(float x, float y, float z); + void RotateX(float x); void Reorthogonalise(void); void CopyOnlyMatrix(CMatrix *other){ diff --git a/src/math/math.cpp b/src/math/math.cpp index e8b7d933..66260709 100644 --- a/src/math/math.cpp +++ b/src/math/math.cpp @@ -40,6 +40,12 @@ CMatrix::Rotate(float x, float y, float z) *this = rot * *this; } +void +CMatrix::RotateX(float x) +{ + Rotate(x, 0.0f, 0.0f); +} + void CMatrix::Reorthogonalise(void) { diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 51781569..53d94d86 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -24,7 +24,6 @@ #include "PointLights.h" #include "Pad.h" #include "Phones.h" -#include "EventList.h" #include "Darkel.h" #include "PathFind.h" #include "ModelIndices.h" @@ -54,7 +53,6 @@ WRAPPER void CPed::RemoveInCarAnims(void) { EAXJMP(0x4E4E20); } WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); } WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); } WRAPPER void CPed::SetRadioStation(void) { EAXJMP(0x4D7BC0); } -WRAPPER void CPed::MakeTyresMuddySectorList(CPtrList&) { EAXJMP(0x53CFD0); } WRAPPER void CPed::ProcessObjective(void) { EAXJMP(0x4D94E0); } CPed *gapTempPedList[50]; @@ -443,7 +441,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bIsAttacking = false; bIsPointingGunAt = false; bIsLooking = false; - m_ped_flagA20 = false; + bKeepTryingToLook = false; bIsRestoringLook = false; bIsAimingGun = false; @@ -463,7 +461,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bUpdateAnimHeading = false; bBodyPartJustCameOff = false; m_ped_flagC40 = false; - m_ped_flagC80 = false; + bFindNewNodeAfterStateRestore = false; m_ped_flagD1 = false; m_ped_flagD2 = false; @@ -514,7 +512,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bNoCriticalHits = false; m_ped_flagI4 = false; bHasAlreadyBeenRecorded = false; - bIsFell = false; + bFallenDown = false; #ifdef KANGAROO_CHEAT m_ped_flagI80 = false; #endif @@ -759,7 +757,7 @@ CPed::AimGun(void) bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(&vector); if (m_pLookTarget != m_pSeekTarget) { - SetLookFlag(m_pSeekTarget, 1); + SetLookFlag(m_pSeekTarget, true); } } else { @@ -780,7 +778,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) pos.z + 0.1f ); - if (!CPed::IsPlayer() || evenOnPlayer) { + if (!IsPlayer() || evenOnPlayer) { ++CStats::HeadsPopped; // BUG: This condition will always return true. @@ -868,7 +866,7 @@ CPed::RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data) } void -CPed::SetLookFlag(CEntity *target, bool unknown) +CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) { if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { bIsLooking = true; @@ -877,15 +875,15 @@ CPed::SetLookFlag(CEntity *target, bool unknown) m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); m_fLookDirection = 999999.0f; m_lookTimer = 0; - m_ped_flagA20 = unknown; + bKeepTryingToLook = keepTryingToLook; if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::FLAG_2; + m_pedIK.m_flags &= ~CPedIK::LOOKING; } } } void -CPed::SetLookFlag(float direction, bool unknown) +CPed::SetLookFlag(float direction, bool keepTryingToLook) { if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { bIsLooking = true; @@ -893,9 +891,9 @@ CPed::SetLookFlag(float direction, bool unknown) m_pLookTarget = nil; m_fLookDirection = direction; m_lookTimer = 0; - m_ped_flagA20 = unknown; + bKeepTryingToLook = keepTryingToLook; if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::FLAG_2; + m_pedIK.m_flags &= ~CPedIK::LOOKING; } } } @@ -968,7 +966,7 @@ CPed::Avoid(void) m_fRotationDest += DEGTORAD(45.0f); if (!bIsLooking) { - CPed::SetLookFlag(nearestPed, 0); + CPed::SetLookFlag(nearestPed, false); CPed::SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); } } @@ -984,7 +982,7 @@ CPed::ClearAimFlag(void) if (bIsAimingGun) { bIsAimingGun = false; bIsRestoringGun = true; - m_pedIK.m_flags &= ~CPedIK:: FLAG_4; + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } if (IsPlayer()) @@ -998,7 +996,7 @@ CPed::ClearLookFlag(void) { bIsRestoringLook = true; bShakeFist = false; - m_pedIK.m_flags &= ~CPedIK::FLAG_2; + m_pedIK.m_flags &= ~CPedIK::LOOKING; if (IsPlayer()) m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; else @@ -1103,7 +1101,7 @@ CPed::Attack(void) return; if (reloadAnimAssoc) { - if (!CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380) + if (!IsPlayer() || ((CPlayerPed*)this)->field_1380) ClearAttack(); return; @@ -1155,9 +1153,9 @@ CPed::Attack(void) weaponAnimTime = weaponAnimAssoc->currentTime; if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { if (ourWeapon->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::FLAG_4; + m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; else - m_pedIK.m_flags &= ~CPedIK::FLAG_4; + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { @@ -2078,10 +2076,10 @@ CPed::BuildPedLists(void) } else { CVector centre = CEntity::GetBoundCentre(); CRect rect( - (centre.x - 20.0f) * 0.025f + 50.0f, - (centre.y - 20.0f) * 0.025f + 50.0f, - (centre.x + 20.0f) * 0.025f + 50.0f, - (centre.y + 20.0f) * 0.025f + 50.0f); + CWorld::GetSectorX(centre.x - 20.0f), + CWorld::GetSectorY(centre.y - 20.0f), + CWorld::GetSectorX(centre.x + 20.0f), + CWorld::GetSectorY(centre.y + 20.0f)); gnNumTempPedList = 0; for(int y = rect.top; y <= rect.bottom; y++) { @@ -2832,7 +2830,7 @@ CPed::ReactToAttack(CEntity *attacker) { if (IsPlayer() && attacker->IsPed()) { InformMyGangOfAttack(attacker); - SetLookFlag(attacker, 1); + SetLookFlag(attacker, true); SetLookTimer(700); return; } @@ -3022,7 +3020,7 @@ CPed::FacePhone(void) GetPosition().x, GetPosition().y); - SetLookFlag(phoneDir, 0); + SetLookFlag(phoneDir, false); phoneDir = CGeneral::LimitRadianAngle(phoneDir); m_moved = CVector2D(0.0f, 0.0f); @@ -3111,7 +3109,7 @@ CPed::CheckForGunShots(void) if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { int pedHandle = gaEvent[event].entityRef; if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { - // Is that a bug?!? + // Is that a bug?!? (same on VC) m_ped_flagD2 = false; return CPools::GetPed(pedHandle); } @@ -3268,7 +3266,7 @@ CPed::SetStoredState(void) return; if (m_nPedState == PED_WANDER_PATH) { - m_ped_flagC80 = true; + bFindNewNodeAfterStateRestore = true; if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) m_nMoveState = PEDMOVE_WALK; } @@ -3974,7 +3972,7 @@ void CPed::RestoreGunPosition(void) { if (bIsLooking) { - m_pedIK.m_flags &= ~CPedIK::FLAG_2; + m_pedIK.m_flags &= ~CPedIK::LOOKING; bIsRestoringGun = false; } else if (m_pedIK.RestoreGunPosn()) { bIsRestoringGun = false; @@ -4025,7 +4023,7 @@ CPed::RestorePreviousState(void) case PED_WANDER_PATH: m_nPedState = PED_WANDER_PATH; bIsRunning = false; - if (!m_ped_flagC80) { + if (!bFindNewNodeAfterStateRestore) { if (m_pNextPathNode) { CVector diff = m_pNextPathNode->pos - GetPosition(); if (diff.MagnitudeSqr() < 49.0f) { @@ -4067,16 +4065,16 @@ CPed::SetAimFlag(float angle) m_pLookTarget = nil; m_pSeekTarget = nil; if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::FLAG_4; + m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; else - m_pedIK.m_flags &= ~CPedIK::FLAG_4; + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } void CPed::SetPointGunAt(CEntity *to) { if (to) { - SetLookFlag(to,1); + SetLookFlag(to, true); SetAimFlag(to); } @@ -4161,7 +4159,7 @@ CPed::SetEvasiveStep(CEntity *reason, uint8 animType) } } if (neededTurn <= DEGTORAD(90.0f) || veh->m_modelIndex == MI_RCBANDIT || vehPressedHorn || animType != 0) { - SetLookFlag(veh, 1); + SetLookFlag(veh, true); if ((CGeneral::GetRandomNumber() & 1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) { stepAnim = ANIM_IDLE_TAXI; } else { @@ -4292,7 +4290,7 @@ CPed::SetEvasiveDive(CPhysical* reason, uint8 onlyRandomJump) m_fRotationCur = angleToFace; ClearLookFlag(); ClearAimFlag(); - SetLookFlag(reason, 1); + SetLookFlag(reason, true); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP); if (animAssoc) return; @@ -4457,7 +4455,7 @@ CPed::SetAttack(CEntity* victim) if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && victimPed->m_nPedState == PED_GETUP) SetWaitState(WAITSTATE_SURPRISE, nil); - SetLookFlag(victim, 0); + SetLookFlag(victim, false); SetLookTimer(100); } @@ -4522,7 +4520,7 @@ CPed::StartFightAttack(uint8 buttonPressure) m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); m_fRotationCur = m_fRotationDest; m_lookTimer = 0; - SetLookFlag(pedOnGround, 1); + SetLookFlag(pedOnGround, true); SetLookTimer(1500); } animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 4.0f); @@ -4834,7 +4832,7 @@ CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl) + 1000 + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); } - bIsFell = true; + bFallenDown = true; } void @@ -5153,7 +5151,7 @@ void CPed::CollideWithPed(CPed *collideWith) { CAnimBlendAssociation *animAssoc; - AnimationId animToRun; + AnimationId animToPlay; bool weAreMissionChar = CharCreatedBy == MISSION_CHAR; bool heIsMissionChar = collideWith->CharCreatedBy == MISSION_CHAR; @@ -5245,7 +5243,7 @@ CPed::CollideWithPed(CPed *collideWith) m_fRotationCur += m_headingRate; } } else { - SetLookFlag(collideWith, 0); + SetLookFlag(collideWith, false); TurnBody(); animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); animAssoc->flags |= ASSOC_FADEOUTWHENDONE; @@ -5265,26 +5263,26 @@ CPed::CollideWithPed(CPed *collideWith) moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToRun = ANIM_HIT_LEFT; + animToPlay = ANIM_HIT_LEFT; else - animToRun = ANIM_SHOT_LEFT_PARTIAL; + animToPlay = ANIM_SHOT_LEFT_PARTIAL; } else if (heLooksToUs) { CVector moveForce = GetRight() * -1.0f; moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToRun = ANIM_HIT_RIGHT; + animToPlay = ANIM_HIT_RIGHT; else - animToRun = ANIM_SHOT_RIGHT_PARTIAL; + animToPlay = ANIM_SHOT_RIGHT_PARTIAL; } else { if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToRun = ANIM_HIT_BACK; + animToPlay = ANIM_HIT_BACK; else - animToRun = ANIM_SHOT_BACK_PARTIAL; + animToPlay = ANIM_SHOT_BACK_PARTIAL; } if (collideWith->IsPedInControl() && CTimer::GetTimeInMilliseconds() > collideWith->m_nPedStateTimer) { - animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToRun, 8.0f); + animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToPlay, 8.0f); animAssoc->flags |= ASSOC_FADEOUTWHENDONE; collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 1000; if (m_nPedState == PED_ATTACK) @@ -5297,23 +5295,23 @@ CPed::CollideWithPed(CPed *collideWith) moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (heLooksToUs) - animToRun = ANIM_KO_SPIN_L; + animToPlay = ANIM_KO_SPIN_L; else - animToRun = ANIM_KD_RIGHT; + animToPlay = ANIM_KD_RIGHT; } else { CVector moveForce = GetRight(); moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (heLooksToUs) - animToRun = ANIM_KO_SPIN_R; + animToPlay = ANIM_KO_SPIN_R; else - animToRun = ANIM_KD_LEFT; + animToPlay = ANIM_KD_LEFT; } if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl()) DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); - collideWith->SetFall(3000, animToRun, 0); + collideWith->SetFall(3000, animToPlay, 0); } } else { if (!IsPedInControl()) @@ -5345,7 +5343,7 @@ CPed::CollideWithPed(CPed *collideWith) } if (IsPlayer()) { - SetLookFlag(collideWith, 1); + SetLookFlag(collideWith, true); SetLookTimer(800); } } else { @@ -5510,7 +5508,7 @@ CPed::SetChat(CEntity* chatWith, uint32 time) m_nPedState = PED_CHAT; SetMoveState(PEDMOVE_STILL); - SetLookFlag(chatWith, 1); + SetLookFlag(chatWith, true); m_standardTimer = CTimer::GetTimeInMilliseconds() + time; m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; } @@ -6219,7 +6217,7 @@ CPed::Fight(void) if (IsPlayer()) { m_fRotationCur = m_fRotationDest; m_lookTimer = 0; - SetLookFlag(nearPed, 1); + SetLookFlag(nearPed, true); SetLookTimer(1500); } break; @@ -6295,7 +6293,7 @@ CPed::Fight(void) nextFightMove = FIGHTMOVE_GROUNDKICK; m_fRotationCur = m_fRotationDest; m_lookTimer = 0; - SetLookFlag(pedOnGround, 1); + SetLookFlag(pedOnGround, true); SetLookTimer(1500); } else if (goForward) { nextFightMove = FIGHTMOVE_SHUFFLE_F; @@ -6709,28 +6707,28 @@ CPed::Wait(void) } } - AnimationId animToRun; + AnimationId animToPlay; switch (CGeneral::GetRandomNumber() & 3) { case 0: - animToRun = ANIM_ROAD_CROSS; + animToPlay = ANIM_ROAD_CROSS; break; case 1: - animToRun = ANIM_IDLE_TIRED; + animToPlay = ANIM_IDLE_TIRED; break; case 2: - animToRun = ANIM_XPRESS_SCRATCH; + animToPlay = ANIM_XPRESS_SCRATCH; break; case 3: - animToRun = ANIM_TURN_180; + animToPlay = ANIM_TURN_180; break; default: break; } - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToRun, 4.0f); + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); - if (animToRun == ANIM_TURN_180) + if (animToPlay == ANIM_TURN_180) animAssoc->SetFinishCallback(FinishedWaitCB, this); m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000); @@ -7771,7 +7769,7 @@ CPed::InvestigateEvent(void) animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; if (m_pEventEntity) - SetLookFlag(m_pEventEntity, 1); + SetLookFlag(m_pEventEntity, true); SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); @@ -7854,8 +7852,8 @@ CPed::InvestigateEvent(void) Say(SOUND_PED_CHAT_EVENT); } break; - case EVENT_ASSAULT_NASTYWEAPON_POLICE: - case EVENT_ATM: + case EVENT_ICECREAM: + case EVENT_SHOPSTALL: m_fRotationDest = m_fAngleToEvent; if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { @@ -7866,7 +7864,7 @@ CPed::InvestigateEvent(void) if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (m_eventType == EVENT_ASSAULT_NASTYWEAPON_POLICE) + if (m_eventType == EVENT_ICECREAM) animToPlay = ANIM_IDLE_CHAT; else animToPlay = ANIM_XPRESS_SCRATCH; @@ -7903,13 +7901,13 @@ CPed::InvestigateEvent(void) m_vecSeekPos.z = GetPosition().z; Seek(); - if (m_eventType < EVENT_ASSAULT_NASTYWEAPON_POLICE) { + if (m_eventType < EVENT_ICECREAM) { if (sq(5.0f + m_distanceToCountSeekDone) < distSqr) { SetMoveState(PEDMOVE_RUN); return; } } - if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_ATM) { + if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_SHOPSTALL) { SetMoveState(PEDMOVE_WALK); return; } @@ -8033,7 +8031,7 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) else nodeToDamage = PED_UPPERARMR; - if (fabs(DotProduct(distVec, car->GetForward())) < 0.85f * vehColModel->boundingBox.max.y) { + if (Abs(DotProduct(distVec, car->GetForward())) < 0.85f * vehColModel->boundingBox.max.y) { killMethod = WEAPONTYPE_RUNOVERBYCAR; m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; m_vecMoveSpeed.z = 0.0; @@ -8064,43 +8062,43 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) float vehColMinY = vehColModel->boundingBox.min.y; float vehColMaxZ = vehColModel->boundingBox.max.z; float carFrontZ = car->GetForward().z; - - // Col. Z of where? - float carColZ; - - // TODO: Figure out what these codes do - float unk1, unk2; + float carHighestZ, carLength; if (carFrontZ < -0.2f) { - carColZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; - unk1 = vehColMaxY - vehColMinY; + // Highest point of car's back + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; + carLength = vehColMaxY - vehColMinY; } else if (carFrontZ > 0.1f) { - carColZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; - float colZDist = carColZ - GetPosition().z; - if (colZDist > 0.0f) { - GetPosition().z += 0.5f * colZDist; - carColZ += colZDist * 0.25f; + // Highest point of car's front + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; + float highestZDist = carHighestZ - GetPosition().z; + if (highestZDist > 0.0f) { + GetPosition().z += 0.5f * highestZDist; + carHighestZ += highestZDist * 0.25f; } - unk1 = vehColMaxY; + carLength = vehColMaxY; } else { - carColZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; - unk1 = vehColMaxY; + // Highest point of car's front + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; + carLength = vehColMaxY; } - unk2 = (carColZ - GetPosition().z) / (unk1 / car->m_vecMoveSpeed.Magnitude()); - float moveForce = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * unk2; + float pedJumpSpeedToReachHighestZ = (carHighestZ - GetPosition().z) / (carLength / car->m_vecMoveSpeed.Magnitude()); + + // TODO: What are we doing down here? + float unknown = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * pedJumpSpeedToReachHighestZ; // After this point, distVec isn't distVec anymore. distVec = car->m_vecMoveSpeed; distVec.Normalise(); - distVec *= 0.2 * moveForce; + distVec *= 0.2 * unknown; if (damageDir != 1 && damageDir != 3) - distVec.z += moveForce; + distVec.z += unknown; else - distVec.z += 1.5f * moveForce; + distVec.z += 1.5f * unknown; m_vecMoveSpeed = distVec; damageDir += 2; @@ -8111,7 +8109,7 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) CObject *bonnet = ((CAutomobile*)car)->RemoveBonnetInPedCollision(); if (bonnet) { - if (rand() & 1) { + if (CGeneral::GetRandomNumber() & 1) { bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(0.1f, 0.0f, 0.5f)); } else { bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(-0.1f, 0.0f, 0.5f)); @@ -8146,8 +8144,7 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) CPed::InflictDamage(car, killMethod, 1000.0f, pieceToDamage, damageDir); if ((m_nPedState == PED_DIE || m_nPedState == PED_DEAD) - && bIsPedDieAnimPlaying - && !m_pCollidingEntity) { + && bIsPedDieAnimPlaying && !m_pCollidingEntity) { m_pCollidingEntity = car; } if (nodeToDamage == PED_MID) @@ -8157,6 +8154,7 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) distVec.Normalise(); car->ApplyMoveForce(distVec * -100.0f); + Say(SOUND_PED_DEFEND); } else if (m_vecDamageNormal.z < -0.8f && impulse > 3.0f || impulse > 6.0f && (!IsPlayer() || impulse > 10.0f)) { @@ -8172,7 +8170,6 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) CPed::InflictDamage(car, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, fallDirection); CPed::SetFall(1000, (AnimationId)(fallDirection + 25), true); - // float ok if ((m_nPedState == PED_FALL || m_nPedState == PED_DIE || m_nPedState == PED_DEAD) && !m_pCollidingEntity && (!IsPlayer() || m_ped_flagD2 || car->m_modelIndex == MI_TRAIN || m_vecDamageNormal.z < -0.8f)) { @@ -8187,9 +8184,9 @@ CPed::KillPedWithCar(CVehicle* car, float impulse) m_vecMoveSpeed.z = 0.0f; distVec.Normalise(); car->ApplyMoveForce(distVec * -60.0f); + Say(SOUND_PED_DEFEND); } - Say(SOUND_PED_DEFEND); #ifdef FIX_BUGS // Killing gang members with car wasn't triggering a fight, until now... Taken from VC. if (IsGangMember()) { @@ -8207,6 +8204,549 @@ CPed::Look(void) // UNUSED: This is a perfectly empty function. } +bool +CPed::LookForInterestingNodes(void) +{ + CBaseModelInfo *model; + CPtrNode *ptrNode; + CVector effectPos; + CVector effectDist; + C2dEffect *effect; + CMatrix *objMat; + + if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { + return false; + } + bool found = false; + uint8 randVal = CGeneral::GetRandomNumber() % 256; + + int minX = CWorld::GetSectorIndexX(GetPosition().x - 15.0f); + if (minX < 0) minX = 0; + int minY = CWorld::GetSectorIndexY(GetPosition().y - 15.0f); + if (minY < 0) minY = 0; + int maxX = CWorld::GetSectorIndexX(GetPosition().x + 15.0f); + if (maxX > NUMSECTORS_X) maxX = NUMSECTORS_X; + int maxY = CWorld::GetSectorIndexY(GetPosition().y + 15.0f); + if (maxY > NUMSECTORS_Y) maxY = NUMSECTORS_Y; + + for (int curY = minY; curY <= maxY && !found; curY++) { + for (int curX = minX; curX <= maxX && !found; curX++) { + for (ptrNode = CWorld::GetSector(curX, curY)->m_lists[ENTITYLIST_VEHICLES].first; ptrNode && !found; ptrNode = ptrNode->next) { + CVehicle* veh = (CVehicle*)ptrNode->item; + model = veh->GetModelInfo(); + if (model->m_num2dEffects != 0) { + for (int e = 0; e < model->m_num2dEffects; e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &veh->GetMatrix(); + effectPos = veh->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < 64.0f) { + found = true; + break; + } + } + } + } + } + for (ptrNode = CWorld::GetSector(curX, curY)->m_lists[ENTITYLIST_OBJECTS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CObject* obj = (CObject*)ptrNode->item; + model = CModelInfo::GetModelInfo(obj->m_modelIndex); + if (model->m_num2dEffects != 0) { + for (int e = 0; e < model->m_num2dEffects; e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &obj->GetMatrix(); + effectPos = obj->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < 64.0f) { + found = true; + break; + } + } + } + } + } + for (ptrNode = CWorld::GetSector(curX, curY)->m_lists[ENTITYLIST_BUILDINGS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding* building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->m_modelIndex); + if (model->m_num2dEffects != 0) { + for (int e = 0; e < model->m_num2dEffects; e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < 64.0f) { + found = true; + break; + } + } + } + } + } + for (ptrNode = CWorld::GetSector(curX, curY)->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding* building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->m_modelIndex); + if (model->m_num2dEffects != 0) { + for (int e = 0; e < model->m_num2dEffects; e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < 64.0f) { + found = true; + break; + } + } + } + } + } + } + } + + if (!found) + return false; + + CVector effectFrontLocal = Multiply3x3(*objMat, effect->attractor.dir); + float angleToFace = CGeneral::GetRadianAngleBetweenPoints(effectFrontLocal.x, effectFrontLocal.y, 0.0f, 0.0f); + randVal = CGeneral::GetRandomNumber() % 256; + if (randVal <= m_randomSeed % 256) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + SetLookFlag(angleToFace, true); + SetLookTimer(1000); + return false; + } + + switch (effect->attractor.flags) { + case 0: + SetInvestigateEvent(EVENT_ICECREAM, CVector2D(effectPos), 0.1f, 15000, angleToFace); + break; + case 1: + SetInvestigateEvent(EVENT_SHOPSTALL, CVector2D(effectPos), 1.0f, + CGeneral::GetRandomNumberInRange(8000, 10 * effect->attractor.probability + 8500), + angleToFace); + break; + default: + return true; + } + return true; +} + +void +CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCountDone, uint16 time, float angle) +{ + if (!IsPedInControl() || CharCreatedBy == MISSION_CHAR) + return; + + SetStoredState(); + bFindNewNodeAfterStateRestore = false; + m_nPedState = PED_INVESTIGATE; + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_eventType = event; + m_eventOrThreat = pos; + m_distanceToCountSeekDone = distanceToCountDone; + m_fAngleToEvent = angle; + + if (m_eventType >= EVENT_ICECREAM) + m_lookTimer = 0; + else + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 4.0f); + +} + +void +CPed::LookForSexyCars(void) +{ + CEntity *vehicles[8]; + CVehicle *veh; + int foundVehId = 0; + int bestPriceYet = 0; + int16 lastVehicle; + + if (!IsPedInControl() && m_nPedState != PED_DRIVING) + return; + + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + CWorld::FindObjectsInRange(GetPosition(), 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int vehId = 0; vehId < lastVehicle; vehId++) { + veh = (CVehicle*)vehicles[vehId]; + if (veh != m_pMyVehicle && bestPriceYet < veh->pHandling->nMonetaryValue) { + foundVehId = vehId; + bestPriceYet = veh->pHandling->nMonetaryValue; + } + } + if (lastVehicle > 0 && bestPriceYet > 40000) + SetLookFlag(vehicles[foundVehId], false); + + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; + } +} + +void +CPed::LookForSexyPeds(void) +{ + if ((!IsPedInControl() && m_nPedState != PED_DRIVING) + || m_lookTimer >= CTimer::GetTimeInMilliseconds() || m_nPedType != PEDTYPE_CIVMALE) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + + if (CanSeeEntity(m_nearPeds[i], DEGTORAD(60.0f))) { + + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 10.0f) { + + CPed *nearPed = m_nearPeds[i]; + if ((nearPed->m_pedStats->m_sexiness > m_pedStats->m_sexiness) + && nearPed->m_nPedType == PEDTYPE_CIVFEMALE) { + + SetLookFlag(nearPed, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + Say(SOUND_PED_CHAT_SEXY); + return; + } + } + } + } + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; +} + +void +CPed::MakeTyresMuddySectorList(CPtrList &list) +{ + for (CPtrNode* node = list.first; node; node = node->next) { + CVehicle* veh = (CVehicle*)node->item; + if (veh->IsCar() && veh->m_scanCode != CWorld::GetCurrentScanCode()) { + veh->m_scanCode = CWorld::GetCurrentScanCode(); + + if (Abs(GetPosition().x - veh->GetPosition().x) < 10.0f) { + + if (Abs(GetPosition().y - veh->GetPosition().y) < 10.0f + && veh->m_vecMoveSpeed.MagnitudeSqr2D() > 0.05f) { + + for(int wheel = 0; wheel < 4; wheel++) { + + if (!((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] + && ((CAutomobile*)veh)->m_aSuspensionSpringRatio[wheel] < 1.0f) { + + CColModel *vehCol = veh->GetModelInfo()->GetColModel(); + CVector approxWheelOffset; + switch (wheel) { + case 0: + approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); + break; + case 1: + approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); + break; + case 2: + approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); + break; + case 3: + approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); + break; + default: + break; + } + + // I hope so + CVector wheelPos = veh->GetMatrix() * approxWheelOffset; + if (Abs(wheelPos.z - GetPosition().z) < 2.0f) { + + if ((wheelPos - GetPosition()).MagnitudeSqr2D() < 1.0f) { + if (CGame::nastyGame) { + ((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] = true; + DMAudio.PlayOneShot(veh->m_audioEntityId, SOUND_SPLATTER, 0.0f); + } + veh->ApplyMoveForce(CVector(0.0f, 0.0f, 50.0f)); + + CVector vehAndWheelDist = wheelPos - veh->GetPosition(); + veh->ApplyTurnForce(CVector(0.0f, 0.0f, 50.0f), vehAndWheelDist); + + if (veh == FindPlayerVehicle()) { + CPad::GetPad(0)->StartShake(300, 70); + } + } + } + } + } + } + } + } + } +} + +void +CPed::Mug(void) +{ + if (m_pSeekTarget && m_pSeekTarget->IsPed()) { + + if (CTimer::GetTimeInMilliseconds() <= m_attackTimer - 2000) { + if ((m_pSeekTarget->GetPosition() - GetPosition()).Magnitude() > 3.0f) + m_wepSkills = 50; + + Say(SOUND_PED_MUGGING); + ((CPed*)m_pSeekTarget)->Say(SOUND_PED_ROBBED); + } else { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + SetFlee(m_pSeekTarget, 20000); + } + + } else { + SetIdle(); + } +} + +void +CPed::MoveHeadToLook(void) +{ + CVector lookPos; + + if (m_lookTimer && CTimer::GetTimeInMilliseconds() > m_lookTimer) { + ClearLookFlag(); + } else if (m_nPedState == PED_DRIVING) { + m_pedIK.m_flags |= CPedIK::LOOKING; + } + + if (m_pLookTarget) { + + if (!bShakeFist && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { + + CAnimBlendAssociation* fuckUAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FUCKU); + if (fuckUAssoc) { + + float animTime = fuckUAssoc->currentTime; + if (animTime > 4.0f / 30.0f && animTime - fuckUAssoc->timeStep > 4.0f / 30.0f) { + + bool lookingToCop = false; + if (m_pLookTarget->m_modelIndex == MI_POLICE + || m_pLookTarget->IsPed() && ((CPed*)m_pLookTarget)->m_nPedType == PEDTYPE_COP) { + + lookingToCop = true; + } + + if (IsPlayer() && (m_pedStats->m_temper >= 52 || lookingToCop)) { + AddWeaponModel(MI_FINGERS); + ((CPlayerPed*)this)->AnnoyPlayerPed(true); + + } else if ((CGeneral::GetRandomNumber() & 3) == 0) { + AddWeaponModel(MI_FINGERS); + } + } + } + } + + if (m_pLookTarget->IsPed()) { + ((CPed*)m_pLookTarget)->m_pedIK.GetComponentPosition((RwV3d*) &lookPos, PED_MID); + } else { + lookPos = m_pLookTarget->GetPosition(); + } + + if (!m_pedIK.LookAtPosition(lookPos)) { + if (!bKeepTryingToLook) { + ClearLookFlag(); + } + return; + } + + if (!bShakeFist || bIsAimingGun || bIsRestoringGun) + return; + + if (m_lookTimer - CTimer::GetTimeInMilliseconds() >= 1000) + return; + + bool notRocketLauncher = false; + bool notTwoHanded = false; + AnimationId animToPlay = NUM_ANIMS; + + if (!GetWeapon()->IsType2Handed()) + notTwoHanded = true; + + if (notTwoHanded && GetWeapon()->m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER) + notRocketLauncher = true; + + if (IsPlayer() && notRocketLauncher) { + + if (m_pLookTarget->IsPed()) { + + if (m_pedStats->m_temper >= 49 && ((CPed*)m_pLookTarget)->m_nPedType != PEDTYPE_COP) { + + // FIX: Unreachable and meaningless condition +#ifndef FIX_BUGS + if (m_pedStats->m_temper < 47) +#endif + animToPlay = ANIM_FIGHT_PPUNCH; + } else { + animToPlay = ANIM_FUCKU; + } + } else if (m_pedStats->m_temper > 49 || m_pLookTarget->m_modelIndex == MI_POLICE) { + animToPlay = ANIM_FUCKU; + } + } else if (notRocketLauncher && (CGeneral::GetRandomNumber() & 1)) { + animToPlay = ANIM_FUCKU; + } + + if (animToPlay != NUM_ANIMS) { + CAnimBlendAssociation *newAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); + + if (newAssoc) { + newAssoc->flags |= ASSOC_FADEOUTWHENDONE; + newAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (newAssoc->animId == ANIM_FUCKU) + newAssoc->SetDeleteCallback(FinishFuckUCB, this); + } + } + bShakeFist = false; + return; + } + + if (999999.0f == m_fLookDirection) { + ClearLookFlag(); + return; + } + + if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { + if (!bKeepTryingToLook) { + ClearLookFlag(); + return; + } + } +} + +void +FinishFuckUCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + if (animAssoc->animId == ANIM_FUCKU && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) + ped->RemoveWeaponModel(0); +} + +void +CPed::Pause(void) { + m_moved = CVector2D(0.0f, 0.0f); + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) + ClearPause(); +} + +void +CPed::PedAnimAlignCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (veh && veh->m_status != STATUS_WRECKED) { + if (ped->m_nPedState != PED_ENTER_CAR && ped->m_nPedState != PED_CARJACK) { + ped->QuitEnteringCar(); + return; + } + if (ped->m_fHealth == 0.0f) { + ped->QuitEnteringCar(); + return; + } + bool itsVan = veh->bIsVan; + bool itsBus = veh->bIsBus; + eDoors enterDoor; + AnimationId enterAnim; + + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + itsVan = false; + enterDoor = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + enterDoor = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + itsVan = false; + enterDoor = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + enterDoor = DOOR_REAR_LEFT; + break; + default: + break; + } + + if (veh->IsDoorMissing(enterDoor) || veh->IsDoorFullyOpen(enterDoor)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (ped->m_nPedState == PED_CARJACK) { + ped->PedAnimDoorOpenCB(nil, ped); + return; + } + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + enterAnim = ANIM_VAN_GETIN; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_R; + } else { + enterAnim = ANIM_CAR_GETIN_RHS; + } + } else if (itsVan) { + enterAnim = ANIM_VAN_GETIN_L; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_L; + } else { + enterAnim = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, enterAnim); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + + } else if (veh->CanPedOpenLocks(ped)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_R); + } else { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_RHS); + } + } else if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN_L); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_L); + } else { + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && veh->pDriver) { + + if (!veh->bLowVehicle + && veh->pDriver->CharCreatedBy != MISSION_CHAR + && veh->pDriver->m_nPedState == PED_DRIVING) { + + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_QJACK); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, true); + + if (veh->pDriver->IsGangMember()) + veh->pDriver->RegisterThreatWithGangPeds(ped); + return; + } + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_LHS); + } + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + + } else { + AnimationId animToPlay; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) + animToPlay = ANIM_CAR_DOORLOCKED_RHS; + else + animToPlay = ANIM_CAR_DOORLOCKED_LHS; + + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_ped_flagF20 = true; + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + } + } +} + 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); } @@ -8216,7 +8756,6 @@ WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) WRAPPER void CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF1B0); } WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF220); } WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); } -WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); } WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); } WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2480); } WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); } @@ -8224,7 +8763,6 @@ WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EA WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); } WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } -WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } class CPed_ : public CPed { @@ -8389,4 +8927,14 @@ STARTPATCHES InjectHook(0x564BB0, &CPed::IsPedDoingDriveByShooting, PATCH_JUMP); InjectHook(0x4E4D90, &CPed::IsRoomToBeCarJacked, PATCH_JUMP); InjectHook(0x4EC430, &CPed::KillPedWithCar, PATCH_JUMP); + InjectHook(0x4E9A80, &CPed::SetInvestigateEvent, PATCH_JUMP); + InjectHook(0x4D5040, &CPed::LookForInterestingNodes, PATCH_JUMP); + InjectHook(0x4D4F50, &CPed::LookForSexyCars, PATCH_JUMP); + InjectHook(0x4D4DF0, &CPed::LookForSexyPeds, PATCH_JUMP); + InjectHook(0x53CFD0, &CPed::MakeTyresMuddySectorList, PATCH_JUMP); + InjectHook(0x4C6580, &FinishFuckUCB, PATCH_JUMP); + InjectHook(0x4D11D0, &CPed::Mug, PATCH_JUMP); + InjectHook(0x4DE130, &CPed::PedAnimAlignCB, PATCH_JUMP); + InjectHook(0x4D0980, &CPed::Pause, PATCH_JUMP); + InjectHook(0x4C65B0, &CPed::MoveHeadToLook, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 96767ce1..5922e0e7 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -11,6 +11,7 @@ #include "WeaponInfo.h" #include "Fire.h" #include "DMAudio.h" +#include "EventList.h" struct CPathNode; @@ -258,7 +259,7 @@ public: uint8 bIsAttacking : 1; // doesn't reset after fist fight, also stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime) uint8 bIsPointingGunAt : 1; uint8 bIsLooking : 1; - uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA + uint8 bKeepTryingToLook : 1; // if we can't look somewhere due to unreachable angles uint8 bIsRestoringLook : 1; uint8 bIsAimingGun : 1; @@ -278,10 +279,10 @@ public: uint8 bUpdateAnimHeading : 1; uint8 bBodyPartJustCameOff : 1; uint8 m_ped_flagC40 : 1; - uint8 m_ped_flagC80 : 1; + uint8 bFindNewNodeAfterStateRestore : 1; - uint8 m_ped_flagD1 : 1; - uint8 m_ped_flagD2 : 1; // seen an event + uint8 m_ped_flagD1 : 1; // so far only used for reaction type to fire/explosion + uint8 m_ped_flagD2 : 1; // set when event has been seen uint8 m_ped_flagD4 : 1; uint8 m_ped_flagD8 : 1; uint8 bIsPedDieAnimPlaying : 1; @@ -303,7 +304,7 @@ public: uint8 m_ped_flagF4 : 1; uint8 m_ped_flagF8 : 1; uint8 bWillBeQuickJacked : 1; - uint8 m_ped_flagF20 : 1; + uint8 m_ped_flagF20 : 1; // set when couldn't open locked car door uint8 m_ped_flagF40 : 1; uint8 bDuckAndCover : 1; @@ -329,7 +330,7 @@ public: uint8 bNoCriticalHits : 1; // if set, limbs won't came off uint8 m_ped_flagI4 : 1; uint8 bHasAlreadyBeenRecorded : 1; - uint8 bIsFell : 1; + uint8 bFallenDown : 1; uint8 m_ped_flagI20 : 1; uint8 m_ped_flagI40 : 1; uint8 m_ped_flagI80 : 1; @@ -367,7 +368,7 @@ public: int32 m_nPrevMoveState; eWaitState m_nWaitState; uint32 m_nWaitTimer; - void *m_pPathNodesStates[8]; // seems unused + void *m_pPathNodesStates[8]; // seems unused, probably leftover from VC CVector2D m_stPathNodeStates[10]; uint16 m_nPathNodes; int16 m_nCurPathNode; @@ -601,7 +602,7 @@ public: void LineUpPedWithTrain(void); void ExitCar(void); void Fight(void); - bool FindBestCoordsFromNodes(CVector unused, CVector* a6); + bool FindBestCoordsFromNodes(CVector, CVector*); void Wait(void); void ProcessObjective(void); bool SeekFollowingPath(CVector*); @@ -614,13 +615,20 @@ public: uint8 GetPedRadioCategory(uint32); int GetWeaponSlot(eWeaponType); void GoToNearestDoor(CVehicle*); - bool HaveReachedNextPointOnRoute(float a2); + bool HaveReachedNextPointOnRoute(float); void Idle(void); void InTheAir(void); void SetLanding(void); void InvestigateEvent(void); bool IsPedDoingDriveByShooting(void); bool IsRoomToBeCarJacked(void); + void SetInvestigateEvent(eEventType, CVector2D, float, uint16, float); + bool LookForInterestingNodes(void); + void LookForSexyCars(void); + void LookForSexyPeds(void); + void Mug(void); + void MoveHeadToLook(void); + void Pause(void); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp index 8909fcc4..d4e4f96e 100644 --- a/src/peds/PedIK.cpp +++ b/src/peds/PedIK.cpp @@ -2,14 +2,16 @@ #include "patcher.h" #include "PedIK.h" #include "Ped.h" +#include "General.h" WRAPPER bool CPedIK::PointGunInDirection(float phi, float theta) { EAXJMP(0x4ED9B0); } WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); } WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); } WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); } -// TODO: Hardcoded into exe, reverse it. +// TODO: These are hardcoded into exe, reverse it. LimbMovementInfo &CPedIK::ms_torsoInfo = *(LimbMovementInfo*)0x5F9F8C; +LimbMovementInfo &CPedIK::ms_headInfo = *(LimbMovementInfo*)0x5F9F5C; CPedIK::CPedIK(CPed *ped) { @@ -105,10 +107,10 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) return destination; } -uint32 +LimbMoveStatus CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo) { - int result = 1; + LimbMoveStatus result = ONE_ANGLE_COULDNT_BE_SET_EXACTLY; // phi @@ -120,11 +122,12 @@ CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, Limb if (Abs(limb.phi - approxPhi) < moveInfo.yawD) { limb.phi = approxPhi; - result = 2; + result = ANGLES_SET_EXACTLY; } + if (limb.phi > moveInfo.maxYaw || limb.phi < moveInfo.minYaw) { limb.phi = clamp(limb.phi, moveInfo.minYaw, moveInfo.maxYaw); - result = 0; + result = ANGLES_SET_TO_MAX; } // theta @@ -138,11 +141,11 @@ CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, Limb if (Abs(limb.theta - approxTheta) < moveInfo.pitchD) limb.theta = approxTheta; else - result = 1; + result = ONE_ANGLE_COULDNT_BE_SET_EXACTLY; if (limb.theta > moveInfo.maxPitch || limb.theta < moveInfo.minPitch) { limb.theta = clamp(limb.theta, moveInfo.minPitch, moveInfo.maxPitch); - result = 0; + result = ANGLES_SET_TO_MAX; } return result; } @@ -150,9 +153,71 @@ CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, Limb bool CPedIK::RestoreGunPosn(void) { - int limbStatus = MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo); + LimbMoveStatus limbStatus = MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo); RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); - return limbStatus == 2; + return limbStatus == ANGLES_SET_EXACTLY; +} + +bool +CPedIK::LookInDirection(float phi, float theta) +{ + bool success = true; + AnimBlendFrameData *frameData = m_ped->m_pFrames[PED_HEAD]; + RwFrame *frame = frameData->frame; + RwMatrix *frameMat = RwFrameGetMatrix(frame); + + if (!(frameData->flag & AnimBlendFrameData::IGNORE_ROTATION)) { + frameData->flag |= AnimBlendFrameData::IGNORE_ROTATION; + CPedIK::ExtractYawAndPitchLocal(frameMat, &m_headOrient.phi, &m_headOrient.theta); + } + + RwMatrix *worldMat = RwMatrixCreate(); + worldMat = CPedIK::GetWorldMatrix(RwFrameGetParent(frame), worldMat); + + float alpha, beta; + CPedIK::ExtractYawAndPitchWorld(worldMat, &alpha, &beta); + RwMatrixDestroy(worldMat); + + alpha += m_torsoOrient.phi; + float neededPhiTurn = CGeneral::LimitRadianAngle(phi - alpha); + beta *= cos(neededPhiTurn); + + float neededThetaTurn = CGeneral::LimitRadianAngle(theta - beta); + LimbMoveStatus headStatus = CPedIK::MoveLimb(m_headOrient, neededPhiTurn, neededThetaTurn, ms_headInfo); + if (headStatus == ANGLES_SET_TO_MAX) + success = false; + + if (headStatus != ANGLES_SET_EXACTLY && !(m_flags & LOOKING)) { + float remainingTurn = CGeneral::LimitRadianAngle(phi - m_ped->m_fRotationCur); + if (CPedIK::MoveLimb(m_torsoOrient, remainingTurn, theta, ms_torsoInfo)) + success = true; + } + CMatrix nextFrame = CMatrix(frameMat); + CVector framePos = nextFrame.GetPosition(); + + nextFrame.SetRotateZ(m_headOrient.theta); + nextFrame.RotateX(m_headOrient.phi); + nextFrame.GetPosition() += framePos; + nextFrame.UpdateRW(); + + if (!(m_flags & LOOKING)) + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + + return success; +} + +bool +CPedIK::LookAtPosition(CVector const &pos) +{ + float phiToFace = CGeneral::GetRadianAngleBetweenPoints( + pos.x, pos.y, + m_ped->GetPosition().x, m_ped->GetPosition().y); + + float thetaToFace = CGeneral::GetRadianAngleBetweenPoints( + pos.z, (m_ped->GetPosition() - pos).Magnitude2D(), + m_ped->GetPosition().z, 0.0f); + + return LookInDirection(phiToFace, thetaToFace); } STARTPATCHES @@ -161,4 +226,6 @@ STARTPATCHES InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); InjectHook(0x4ED440, &CPedIK::MoveLimb, PATCH_JUMP); InjectHook(0x4EDD70, &CPedIK::RestoreGunPosn, PATCH_JUMP); + InjectHook(0x4ED620, &CPedIK::LookInDirection, PATCH_JUMP); + InjectHook(0x4ED590, &CPedIK::LookAtPosition, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h index a8d9c75d..21f8cce4 100644 --- a/src/peds/PedIK.h +++ b/src/peds/PedIK.h @@ -18,16 +18,21 @@ struct LimbMovementInfo { float pitchD; }; +enum LimbMoveStatus { + ANGLES_SET_TO_MAX, // because given angles were unreachable + ONE_ANGLE_COULDNT_BE_SET_EXACTLY, // because it can't be reached in a jiffy + ANGLES_SET_EXACTLY +}; + class CPed; class CPedIK { public: - // TODO enum { FLAG_1 = 1, - FLAG_2 = 2, // related to looking somewhere - FLAG_4 = 4, // aims with arm + LOOKING = 2, + AIMS_WITH_ARM = 4, }; CPed *m_ped; @@ -38,6 +43,7 @@ public: int32 m_flags; static LimbMovementInfo &ms_torsoInfo; + static LimbMovementInfo &ms_headInfo; CPedIK(CPed *ped); bool PointGunInDirection(float phi, float theta); @@ -47,7 +53,9 @@ public: void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); - uint32 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4); + LimbMoveStatus MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4); bool RestoreGunPosn(void); + bool LookInDirection(float phi, float theta); + bool LookAtPosition(CVector const& pos); }; static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp index 361a9098..5ae8c4be 100644 --- a/src/peds/PlayerPed.cpp +++ b/src/peds/PlayerPed.cpp @@ -57,8 +57,8 @@ CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) void CPlayerPed::ClearWeaponTarget() { - if (!m_nPedType) { - m_pPointGunAt = 0; + if (m_nPedType == PEDTYPE_PLAYER1) { + m_pPointGunAt = nil; TheCamera.ClearPlayerWeaponMode(); CWeaponEffects::ClearCrosshair(); } @@ -79,12 +79,12 @@ CPlayerPed::SetWantedLevelNoDrop(int32 level) // I don't know the actual purpose of parameter void -CPlayerPed::AnnoyPlayerPed(bool itsPolice) +CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity) { if (m_pedStats->m_temper < 52) { m_pedStats->m_temper++; } else { - if (itsPolice) { + if (annoyedByPassingEntity) { if (m_pedStats->m_temper < 55) { m_pedStats->m_temper++; } else {