From 39223901bf459e0548605f64ae030e89fedb9949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Sat, 17 Aug 2019 22:03:57 +0300 Subject: [PATCH] AnimViewer messages, Particle fix, Peds --- src/core/AnimViewer.cpp | 47 +++- src/core/Stats.cpp | 2 +- src/core/Stats.h | 2 +- src/core/World.cpp | 6 +- src/core/config.h | 1 + src/core/main.cpp | 3 + src/modelinfo/PedModelInfo.cpp | 39 +++ src/modelinfo/PedModelInfo.h | 1 + src/objects/ParticleObject.cpp | 8 +- src/peds/Ped.cpp | 496 ++++++++++++++++++++++++++++++++- src/peds/Ped.h | 5 + 11 files changed, 595 insertions(+), 15 deletions(-) diff --git a/src/core/AnimViewer.cpp b/src/core/AnimViewer.cpp index 30773889..86b22ec5 100644 --- a/src/core/AnimViewer.cpp +++ b/src/core/AnimViewer.cpp @@ -34,6 +34,8 @@ #include "Timecycle.h" #include "RpAnimBlend.h" #include "Shadows.h" +#include "Radar.h" +#include "Hud.h" int CAnimViewer::animTxdSlot = 0; CEntity *CAnimViewer::pTarget = nil; @@ -70,7 +72,8 @@ CAnimViewer::Initialise(void) { } gbModelViewer = true; - + CHud::m_Wants_To_Draw_Hud = false; + ThePaths.Init(); ThePaths.AllocatePathFindInfoMem(4500); CCollision::Init(); @@ -90,6 +93,8 @@ CAnimViewer::Initialise(void) { CStreaming::RequestSpecialModel(MI_PLAYER, "player", STREAMFLAGS_DONT_REMOVE); CStreaming::LoadAllRequestedModels(false); CRenderer::Init(); + CRadar::Initialise(); + CRadar::LoadTextures(); CVehicleModelInfo::LoadVehicleColours(); CAnimManager::LoadAnimFiles(); CWorld::PlayerInFocus = 0; @@ -297,10 +302,15 @@ CAnimViewer::Update(void) if (pad->NewState.LeftShoulder1 && !pad->OldState.LeftShoulder1) { nextModelId = LastPedModelId(modelId); + AsciiToUnicode("Switched to peds", gUString); + CMessages::AddMessage(gUString, 1000, 0); } else { // Start in mobile - if (pad->NewState.Square && !pad->OldState.Square) + if (pad->NewState.Square && !pad->OldState.Square) { CVehicleModelInfo::LoadVehicleColours(); + AsciiToUnicode("Carcols.dat reloaded", gUString); + CMessages::AddMessage(gUString, 1000, 0); + } } } } else { @@ -309,12 +319,18 @@ CAnimViewer::Update(void) // Triangle in mobile if (pad->NewState.Square && !pad->OldState.Square) { reloadIFP = 1; + AsciiToUnicode("IFP reloaded", gUString); + CMessages::AddMessage(gUString, 1000, 0); } else if (pad->NewState.Cross && !pad->OldState.Cross) { PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId); + AsciiToUnicode("Animation restarted", gUString); + CMessages::AddMessage(gUString, 1000, 0); } else if (pad->NewState.Circle && !pad->OldState.Circle) { PlayAnimation(pTarget->GetClump(), animGroup, ANIM_IDLE_STANCE); + AsciiToUnicode("Idle animation playing", gUString); + CMessages::AddMessage(gUString, 1000, 0); } else if (pad->NewState.DPadUp && pad->OldState.DPadUp == 0) { animId--; @@ -323,19 +339,33 @@ CAnimViewer::Update(void) } PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId); + sprintf(gString, "Current anim: %d", animId); + AsciiToUnicode(gString, gUString); + CMessages::AddMessage(gUString, 1000, 0); + } else if (pad->NewState.DPadDown && !pad->OldState.DPadDown) { animId = (animId == (NUM_ANIMS - 1) ? 0 : animId + 1); PlayAnimation(pTarget->GetClump(), animGroup, (AnimationId)animId); + sprintf(gString, "Current anim: %d", animId); + AsciiToUnicode(gString, gUString); + CMessages::AddMessage(gUString, 1000, 0); + } else { if (pad->NewState.Start && !pad->OldState.Start) { } else { if (pad->NewState.LeftShoulder1 && !pad->OldState.LeftShoulder1) { nextModelId = LastVehicleModelId(modelId); + AsciiToUnicode("Switched to vehicles", gUString); + CMessages::AddMessage(gUString, 1000, 0); } else { -// if (CPad::GetPad(1)->NewState.LeftShoulder2) -// CPedModelInfo::AnimatePedColModelSkinned(CModelInfo::ms_modelInfoPtrs[(pTarget + 96)], pTarget->GetClump())); + // Originally it was GetPad(1)->LeftShoulder2 + if (pad->NewState.Triangle) { + CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(pTarget->m_modelIndex))->GetHitColModel(), RpClumpGetFrame(pTarget->GetClump())); + AsciiToUnicode("Ped Col model will be animated as long as you hold the button", gUString); + CMessages::AddMessage(gUString, 100, 0); + } } } } @@ -344,8 +374,17 @@ CAnimViewer::Update(void) if (pad->NewState.DPadLeft && pad->OldState.DPadLeft == 0) { nextModelId = FindMeAModelID(modelId, -1); + + sprintf(gString, "Current model ID: %d", nextModelId); + AsciiToUnicode(gString, gUString); + CMessages::AddMessage(gUString, 1000, 0); + } else if (pad->NewState.DPadRight && pad->OldState.DPadRight == 0) { nextModelId = FindMeAModelID(modelId, 1); + + sprintf(gString, "Current model ID: %d", nextModelId); + AsciiToUnicode(gString, gUString); + CMessages::AddMessage(gUString, 1000, 0); } // There were extra codes here to let us change model id by 50, but xbox CPad struct is different, so I couldn't port. diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp index 9d0e7df1..d4d91dac 100644 --- a/src/core/Stats.cpp +++ b/src/core/Stats.cpp @@ -2,7 +2,7 @@ #include "Stats.h" int32 &CStats::DaysPassed = *(int32*)0x8F2BB8; -int32 &CStats::HeadShots = *(int32*)0x8F647C; +int32 &CStats::HeadsPopped = *(int32*)0x8F647C; bool& CStats::CommercialPassed = *(bool*)0x8F4334; bool& CStats::IndustrialPassed = *(bool*)0x8E2A68; int32 &CStats::NumberKillFrenziesPassed = *(int32*)0x8E287C; diff --git a/src/core/Stats.h b/src/core/Stats.h index 90db25e8..53c40ca3 100644 --- a/src/core/Stats.h +++ b/src/core/Stats.h @@ -4,7 +4,7 @@ class CStats { public: static int32 &DaysPassed; - static int32 &HeadShots; + static int32 &HeadsPopped; static bool& CommercialPassed; static bool& IndustrialPassed; static int32 &NumberKillFrenziesPassed; diff --git a/src/core/World.cpp b/src/core/World.cpp index 9c3aafcf..150e87d5 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -294,10 +294,14 @@ CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColP if(e->IsPed()){ if(e->bUsesCollision || deadPeds && ((CPed*)e)->m_nPedState == PED_DEAD){ - if(((CPed*)e)->UseGroundColModel()) + if (((CPed*)e)->UseGroundColModel()) colmodel = &CTempColModels::ms_colModelPedGroundHit; else +#ifdef ANIMATE_PED_COL_MODEL + colmodel = CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(), RpClumpGetFrame(e->GetClump())); +#else colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(); +#endif }else colmodel = nil; }else if(e->bUsesCollision) diff --git a/src/core/config.h b/src/core/config.h index 8eda6187..de89f7c3 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -130,3 +130,4 @@ enum Config { #define ASPECT_RATIO_SCALE #define USE_DEBUG_SCRIPT_LOADER #define EXPLODING_AIRTRAIN // can blow up jumbo jet with rocket launcher +#define ANIMATE_PED_COL_MODEL diff --git a/src/core/main.cpp b/src/core/main.cpp index 7d60291c..50494ef3 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -121,9 +121,12 @@ TheModelViewer(void) CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), 255); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); DefinedState(); CVisibilityPlugins::InitAlphaEntityList(); CAnimViewer::Render(); + Render2dStuff(); DoRWStuffEndOfFrame(); } #endif diff --git a/src/modelinfo/PedModelInfo.cpp b/src/modelinfo/PedModelInfo.cpp index c5242ef6..afe177c2 100644 --- a/src/modelinfo/PedModelInfo.cpp +++ b/src/modelinfo/PedModelInfo.cpp @@ -189,6 +189,45 @@ CPedModelInfo::CreateHitColModel(void) m_hitColModel = colmodel; } +CColModel* +CPedModelInfo::AnimatePedColModel(CColModel* colmodel, RwFrame* frame) +{ + RwObjectNameAssociation nameAssoc; + RwObjectIdAssociation idAssoc; + RwMatrix* mat = RwMatrixCreate(); + CColSphere* spheres = colmodel->spheres; + + for (int i = 0; i < NUMPEDINFONODES; i++) { + RwFrame* f = nil; + if (m_pColNodeInfos[i].name) { + nameAssoc.name = m_pColNodeInfos[i].name; + nameAssoc.frame = nil; + RwFrameForAllChildren(frame, FindFrameFromNameCB, &nameAssoc); + f = nameAssoc.frame; + } + else { + idAssoc.id = m_pColNodeInfos[i].pedNode; + idAssoc.frame = nil; + RwFrameForAllChildren(frame, FindFrameFromIdCB, &idAssoc); + f = idAssoc.frame; + } + if (f) { + RwMatrixCopy(mat, RwFrameGetMatrix(f)); + + for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f)) { + RwMatrixTransform(mat, &f->modelling, rwCOMBINEPOSTCONCAT); + if (RwFrameGetParent(f) == frame) + break; + } + + spheres[i].center.x = mat->pos.x + m_pColNodeInfos[i].x; + spheres[i].center.y = mat->pos.y + 0.0f; + spheres[i].center.z = mat->pos.z + m_pColNodeInfos[i].z; + } + } + + return colmodel; +} class CPedModelInfo_ : public CPedModelInfo { diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index 483d13f8..a2d58d6e 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -39,5 +39,6 @@ public: void SetLowDetailClump(RpClump*); void CreateHitColModel(void); CColModel *GetHitColModel(void) { return m_hitColModel; } + static CColModel *AnimatePedColModel(CColModel* colmodel, RwFrame* frame); }; static_assert(sizeof(CPedModelInfo) == 0x54, "CPedModelInfo: error"); diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index 32d305c6..2171cd76 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -442,13 +442,13 @@ void CParticleObject::UpdateClose(void) { this->m_nFrameCounter = 0; - int32 randVal; // BUG: unitialised can be used ??!! + int32 randVal; if ( this->m_nCreationChance != 0 ) randVal = CGeneral::GetRandomNumber() % this->m_nCreationChance; - if ( randVal != 0 && this->m_nCreationChance > 0 - || randVal == 0 && (this->m_nCreationChance & 128) != 0 - || this->m_nCreationChance == 0 ) + if ( this->m_nCreationChance == 0 + || randVal == 0 && this->m_nCreationChance < 0 + || randVal != 0 && this->m_nCreationChance > 0) { switch ( this->m_Type ) { diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index e2c63d9c..f5ab4ea4 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -39,7 +39,6 @@ #include "Font.h" #include "Text.h" -WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); } @@ -782,7 +781,7 @@ CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) ); if (!CPed::IsPlayer() || evenOnPlayer) { - ++CStats::HeadShots; + ++CStats::HeadsPopped; // BUG: This condition will always return true. if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { @@ -4367,7 +4366,7 @@ CPed::SetAttack(CEntity* victim) bIsAttacking = false; animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f); animAssoc->SetRun(); - if (animAssoc->currentTime != animAssoc->hierarchy->totalLength) + if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) animAssoc->SetCurrentTime(0.0f); animAssoc->SetFinishCallback(FinishedAttackCB, this); @@ -4668,12 +4667,19 @@ CPed::FightStrike(CVector &touchedNodePos) // He can beat us if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) { - ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel(); + if (nearPed->m_nPedState == PED_FALL || nearPed->m_nPedState == PED_DEAD || nearPed->m_nPedState == PED_DIE || !nearPed->IsPedHeadAbovePos(-0.3f)) { ourCol = &CTempColModels::ms_colModelPedGroundHit; + } else { +#ifdef ANIMATE_PED_COL_MODEL + ourCol = CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel(), RpClumpGetFrame(GetClump())); +#else + ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel(); +#endif } + for (int j = 0; j < ourCol->numSpheres; j++) { attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center; attackDistance -= touchedNodePos; @@ -7723,6 +7729,484 @@ CPed::SetAnimOffsetForEnterOrExitVehicle(void) } } +void +CPed::InvestigateEvent(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId animToPlay; + AssocGroupId animGroup; + + if (m_nWaitState == WAITSTATE_TURN180) + return; + + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + if (m_standardTimer) { + if (m_eventType < EVENT_ASSAULT_NASTYWEAPON) + SetWaitState(WAITSTATE_TURN180, nil); + + m_standardTimer = 0; + } else { + ClearInvestigateEvent(); + } + return; + } + + CVector2D vecDist = m_eventOrThreat - GetPosition(); + float distSqr = vecDist.MagnitudeSqr(); + if (sq(m_distanceToCountSeekDone) >= distSqr) { + + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(vecDist.x, vecDist.y, 0.0f, 0.0f); + SetMoveState(PEDMOVE_STILL); + + switch (m_eventType) { + case EVENT_DEAD_PED: + case EVENT_HIT_AND_RUN: + case EVENT_HIT_AND_RUN_COP: + + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (m_pEventEntity) + SetLookFlag(m_pEventEntity, 1); + + SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); + + } else if (CGeneral::GetRandomNumber() & 3) { + ClearLookFlag(); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); + + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + Say(SOUND_PED_CHAT_EVENT); + + } else { + ClearInvestigateEvent(); + } + } + break; + case EVENT_FIRE: + case EVENT_EXPLOSION: + + if (m_ped_flagD1 && CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CAM); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + + if (animAssoc && animAssoc->animId == ANIM_IDLE_CAM) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 14.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + + } else if (CGeneral::GetRandomNumber() & 3) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CAM, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(2500, 5000)); + Say(SOUND_PED_CHAT_EVENT); + + } else { + m_standardTimer = 0; + } + + } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + + if (animAssoc && animAssoc->animId == ANIM_IDLE_STANCE) { + if (CGeneral::GetRandomNumber() & 1) + animToPlay = ANIM_IDLE_HBHB; + else + animToPlay = ANIM_XPRESS_SCRATCH; + + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + + } else if (animAssoc && animAssoc->animId == ANIM_IDLE_HBHB) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (CGeneral::GetRandomNumber() & 1) { + animToPlay = ANIM_IDLE_STANCE; + animGroup = m_animGroup; + } else { + animToPlay = ANIM_XPRESS_SCRATCH; + animGroup = ASSOCGRP_STD; + } + + CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + + } else { + if (CGeneral::GetRandomNumber() & 1) { + animToPlay = ANIM_IDLE_STANCE; + animGroup = m_animGroup; + } else { + animToPlay = ANIM_IDLE_HBHB; + animGroup = ASSOCGRP_STD; + } + + CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + } + Say(SOUND_PED_CHAT_EVENT); + } + break; + case EVENT_ASSAULT_NASTYWEAPON_POLICE: + case EVENT_ATM: + + m_fRotationDest = m_fAngleToEvent; + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + + if (m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (m_eventType == EVENT_ASSAULT_NASTYWEAPON_POLICE) + animToPlay = ANIM_IDLE_CHAT; + else + animToPlay = ANIM_XPRESS_SCRATCH; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay,4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + ClearInvestigateEvent(); + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + ClearInvestigateEvent(); + } + } + } else { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + } + } + break; + default: + return; + } + } else { + m_vecSeekPos.x = m_eventOrThreat.x; + m_vecSeekPos.y = m_eventOrThreat.y; + m_vecSeekPos.z = GetPosition().z; + Seek(); + + if (m_eventType < EVENT_ASSAULT_NASTYWEAPON_POLICE) { + if (sq(5.0f + m_distanceToCountSeekDone) < distSqr) { + SetMoveState(PEDMOVE_RUN); + return; + } + } + if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_ATM) { + SetMoveState(PEDMOVE_WALK); + return; + } + if (distSqr > 1.44f) { + SetMoveState(PEDMOVE_WALK); + return; + } + + for (int i = 0; i < m_numNearPeds; i++) { + if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < 0.16f) { + SetMoveState(PEDMOVE_STILL); + return; + } + } + + SetMoveState(PEDMOVE_WALK); + } +} + +bool +CPed::IsPedDoingDriveByShooting(void) +{ + if (this == FindPlayerPed() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { + + if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight) + return true; + } + return false; +} + +bool +CPed::IsPedShootable(void) +{ + return m_nPedState <= PED_STATES_NO_ST; +} + +bool +CPed::IsRoomToBeCarJacked(void) +{ + if (!m_pMyVehicle) + return false; + + CVector2D 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)) { + return true; + } + + return false; +} + +void +CPed::KillPedWithCar(CVehicle* car, float impulse) +{ + CVehicleModelInfo* vehModel; + CColModel* vehColModel; + uint8 damageDir; + PedNode nodeToDamage; + eWeaponType killMethod; + + if (m_nPedState == PED_FALL || m_nPedState == PED_DIE) { + if (!this->m_pCollidingEntity || car->m_status == STATUS_PLAYER) + this->m_pCollidingEntity = car; + return; + } + + if (m_nPedState == PED_DEAD) + return; + + if (m_pCurSurface) { + if (m_pCurSurface->IsVehicle() && (((CVehicle*)m_pCurSurface)->m_vehType == VEHICLE_TYPE_BOAT || IsPlayer())) + return; + } + CVector distVec = GetPosition() - car->GetPosition(); + + if ((impulse > 12.0f || car->m_modelIndex == MI_TRAIN) && !IsPlayer()) { + nodeToDamage = PED_TORSO; + killMethod = WEAPONTYPE_RAMMEDBYCAR; + uint8 randVal = CGeneral::GetRandomNumber() & 3; + + if (car == FindPlayerVehicle()) { + float carSpeed = car->m_vecMoveSpeed.Magnitude(); + uint8 shakeFreq; + if (100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f <= 250.0f) { + shakeFreq = 100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f; + } else { + shakeFreq = 250.0f; + } + CPad::GetPad(0)->StartShake(40000 / shakeFreq, shakeFreq); + } + bIsStanding = false; + damageDir = CPed::GetLocalDirection(-m_vecMoveSpeed); + vehModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(car->m_modelIndex); + vehColModel = vehModel->GetColModel(); + float carRightAndDistDotProd = DotProduct(distVec, car->GetRight()); + + if (car->m_modelIndex == MI_TRAIN) { + killMethod = WEAPONTYPE_RUNOVERBYCAR; + nodeToDamage = PED_HEAD; + m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; + m_vecMoveSpeed.z = 0.0; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + // Car doesn't look to us + } else if (DotProduct(car->m_vecMoveSpeed, car->GetForward()) >= 0.0f){ + + if (0.99f * vehColModel->boundingBox.max.x < Abs(carRightAndDistDotProd)) { + + // We're at the right of the car + if (carRightAndDistDotProd <= 0.0f) + nodeToDamage = PED_UPPERARML; + else + nodeToDamage = PED_UPPERARMR; + + if (fabs(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; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + } + } else { + float carFrontAndDistDotProd = DotProduct(distVec, car->GetForward()); + + // carFrontAndDistDotProd <= 0.0 car looks to us + if ((carFrontAndDistDotProd <= 0.1 || randVal == 1) && randVal != 0) { + killMethod = WEAPONTYPE_RUNOVERBYCAR; + nodeToDamage = PED_HEAD; + m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; + m_vecMoveSpeed.z = 0.0; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + } else { + nodeToDamage = PED_MID; + float vehColMaxY = vehColModel->boundingBox.max.y; + 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; + + if (carFrontZ < -0.2f) { + carColZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; + unk1 = 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; + } + unk1 = vehColMaxY; + + } else { + carColZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; + unk1 = vehColMaxY; + } + + unk2 = (carColZ - GetPosition().z) / (unk1 / car->m_vecMoveSpeed.Magnitude()); + float moveForce = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * unk2; + + // After this point, distVec isn't distVec anymore. + distVec = car->m_vecMoveSpeed; + distVec.Normalise(); + distVec *= 0.2 * moveForce; + + if (damageDir != 1 && damageDir != 3) + distVec.z += moveForce; + else + distVec.z += 1.5f * moveForce; + + m_vecMoveSpeed = distVec; + damageDir += 2; + if (damageDir > 3) + damageDir = damageDir - 4; + + if (car->m_vehType == VEHICLE_TYPE_CAR) { + CObject *bonnet = ((CAutomobile*)car)->RemoveBonnetInPedCollision(); + + if (bonnet) { + if (rand() & 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)); + } + CVector forceDir = car->GetUp() * 10.0f; + bonnet->ApplyTurnForce(forceDir, car->GetForward()); + } + } + } + } + } + + if (car->pDriver) { + CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); + } + + ePedPieceTypes pieceToDamage; + switch (nodeToDamage) { + case PED_HEAD: + pieceToDamage = PEDPIECE_HEAD; + break; + case PED_UPPERARML: + pieceToDamage = PEDPIECE_LEFTARM; + break; + case PED_UPPERARMR: + pieceToDamage = PEDPIECE_RIGHTARM; + break; + default: + pieceToDamage = PEDPIECE_MID; + break; + } + CPed::InflictDamage(car, killMethod, 1000.0f, pieceToDamage, damageDir); + + if ((m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + && bIsPedDieAnimPlaying + && !m_pCollidingEntity) { + m_pCollidingEntity = car; + } + if (nodeToDamage == PED_MID) + m_ped_flagH1 = true; + else + m_ped_flagH1 = false; + + distVec.Normalise(); + car->ApplyMoveForce(distVec * -100.0f); + + } else if (m_vecDamageNormal.z < -0.8f && impulse > 3.0f + || impulse > 6.0f && (!IsPlayer() || impulse > 10.0f)) { + + bIsStanding = false; + uint8 fallDirection = GetLocalDirection(-car->m_vecMoveSpeed); + float damage; + if (IsPlayer() && car->m_modelIndex == MI_TRAIN) + damage = 150.0f; + else + damage = 30.0f; + + 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)) { + + m_pCollidingEntity = car; + } + + m_ped_flagH1 = false; + if (car->m_modelIndex != MI_TRAIN && !m_ped_flagD2) { + m_vecMoveSpeed = car->m_vecMoveSpeed * 0.75f; + } + m_vecMoveSpeed.z = 0.0f; + distVec.Normalise(); + car->ApplyMoveForce(distVec * -60.0f); + } + + Say(SOUND_PED_DEFEND); +#ifdef FIX_BUGS + // Killing gang members with car wasn't triggering a fight, until now... Taken from VC. + if (IsGangMember()) { + CPed *driver = car->pDriver; + if (driver && driver->IsPlayer()) { + RegisterThreatWithGangPeds(driver); + } + } +#endif +} + +void +CPed::Look(void) +{ + // UNUSED: This is a perfectly empty function. +} + 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); } @@ -7901,4 +8385,8 @@ STARTPATCHES InjectHook(0x4D0D10, &CPed::InTheAir, PATCH_JUMP); InjectHook(0x4C5270, &CPed::Initialise, PATCH_JUMP); InjectHook(0x4D0E40, &CPed::SetLanding, PATCH_JUMP); + InjectHook(0x4E9B50, &CPed::InvestigateEvent, PATCH_JUMP); + InjectHook(0x564BB0, &CPed::IsPedDoingDriveByShooting, PATCH_JUMP); + InjectHook(0x4E4D90, &CPed::IsRoomToBeCarJacked, PATCH_JUMP); + InjectHook(0x4EC430, &CPed::KillPedWithCar, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 459d0601..e876a2a6 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -618,6 +618,9 @@ public: void Idle(void); void InTheAir(void); void SetLanding(void); + void InvestigateEvent(void); + bool IsPedDoingDriveByShooting(void); + bool IsRoomToBeCarJacked(void); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -681,6 +684,8 @@ public: void EnterTrain(void); void ExitTrain(void); void Fall(void); + bool IsPedShootable(void); + void Look(void); bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }