diff options
Diffstat (limited to '')
-rw-r--r-- | src/peds/Ped.cpp | 323 | ||||
-rw-r--r-- | src/peds/Ped.h | 39 |
2 files changed, 347 insertions, 15 deletions
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 1e3b7394..0728777b 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -5,7 +5,6 @@ #include "Particle.h" #include "Stats.h" #include "World.h" -#include "DMAudio.h" #include "RpAnimBlend.h" #include "Ped.h" #include "PlayerPed.h" @@ -33,7 +32,6 @@ #include "TempColModels.h" WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } -WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); } WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); } WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } @@ -50,14 +48,16 @@ WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); } WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); } WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); } WRAPPER void CPed::RemoveInCarAnims(void) { EAXJMP(0x4E4E20); } -WRAPPER void CPed::SetWaitState(eWaitState, void*) { EAXJMP(0x4D58D0); } WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); } -WRAPPER void CPed::PlayHitSound(CPed*) { EAXJMP(0x4E8E20); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; bool &CPed::bPedCheat3 = *(bool*)0x95CD59; + CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14; + +CPedAudioData (&CPed::PedAudioData)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4; + uint16 &CPed::unknownFightThing = *(uint16*)0x95CC58; FightMove (&CPed::ms_fightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844; @@ -287,10 +287,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_fHealth = 100.0f; m_fArmour = 0.0f; m_nPedType = pedType; - field_520 = 0; + m_currentSoundStart = 0; m_talkTimer = 0; - m_talkTypeLast = 167; - m_talkType = 167; + m_lastQueuedSound = SOUND_TOTAL_PED_SOUNDS; + m_queuedSound = SOUND_TOTAL_PED_SOUNDS; m_objective = OBJECTIVE_NONE; m_prevObjective = OBJECTIVE_NONE; CharCreatedBy = RANDOM_CHAR; @@ -401,7 +401,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_ped_flagD4 = false; m_ped_flagD8 = false; bIsPedDieAnimPlaying = false; - m_ped_flagD20 = false; + bIsFleeing = false; m_ped_flagD40 = false; bScriptObjectiveCompleted = false; @@ -1137,7 +1137,7 @@ CPed::Attack(void) if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); } weaponAnimAssoc->speed = 0.5f; @@ -2471,7 +2471,7 @@ CPed::SetObjective(eObjective newObj, void *entity) case OBJECTIVE_KILL_CHAR_ANY_MEANS: case OBJECTIVE_MUG_CHAR: m_pLastPathNode = nil; - m_ped_flagD20 = false; + bIsFleeing = false; m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); m_pedInObjective = (CPed*)entity; m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); @@ -3659,7 +3659,7 @@ void CPed::ClearFlee(void) { RestorePreviousState(); - m_ped_flagD20 = false; + bIsFleeing = false; m_standardTimer = 0; m_fleeTimer = 0; } @@ -4748,6 +4748,302 @@ CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl) bIsFell = true; } +void +CPed::SetFlee(CEntity* fleeFrom, int time) +{ + if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom) + return; + + SetStoredState(); + m_nPedState = PED_FLEE_ENTITY; + bIsFleeing = true; + SetMoveState(PEDMOVE_RUN); + m_fleeFrom = fleeFrom; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + + if (time <= 0) + m_fleeTimer = 0; + else + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + fleeFrom->GetPosition().x, fleeFrom->GetPosition().y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::SetFlee(CVector2D &from, int time) +{ + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace) + return; + + if (m_nPedState != PED_FLEE_ENTITY) { + SetStoredState(); + m_nPedState = PED_FLEE_POS; + SetMoveState(PEDMOVE_RUN); + m_fleeFromPosX = from.x; + m_fleeFromPosY = from.y; + } + + bIsFleeing = true; + m_pLastPathNode = nil; + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + from.x, from.y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::SetWaitState(eWaitState state, void *time) +{ + AnimationId waitAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + + if (!IsPedInControl()) + return; + + if (state != m_nWaitState) + FinishedWaitCB(nil, this); + + switch (state) { + case WAITSTATE_TRAFFIC_LIGHTS: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; + SetMoveState(PEDMOVE_STILL); + break; + case WAITSTATE_CROSS_ROAD: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f); + break; + case WAITSTATE_CROSS_ROAD_LOOK: + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f); + + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000); + + break; + case WAITSTATE_LOOK_PED: + case WAITSTATE_LOOK_SHOP: + case WAITSTATE_LOOK_ACCIDENT: + case WAITSTATE_FACEOFF_GANG: + break; + case WAITSTATE_DOUBLEBACK: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f); + break; + case WAITSTATE_HITWALL: + m_headingRate = 2.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f); + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + } + break; + case WAITSTATE_TURN180: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 3000.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this); + break; + case WAITSTATE_SURPRISE: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 3000.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + break; + case WAITSTATE_STUCK: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f); + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + } + break; + case WAITSTATE_LOOK_ABOUT: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f); + break; + case WAITSTATE_PLAYANIM_COWER: + waitAnim = ANIM_HANDSCOWER; + case WAITSTATE_PLAYANIM_HANDSUP: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSUP; + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSCOWER; + m_headingRate = 0.0f; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f); + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_PLAYANIM_DUCK: + waitAnim = ANIM_DUCK_DOWN; + case WAITSTATE_PLAYANIM_TAXI: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_TAXI; + case WAITSTATE_PLAYANIM_CHAT: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_CHAT; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f); + animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_FINISH_FLEE: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f); + break; + default: + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; + } + m_nWaitState = state; +} + + +void +CPed::PlayHitSound(CPed *hitTo) +{ + // That was very complicated to reverse for me... + // First index is our fight move ID (from 1 to 12, total 12), second is the one of we fight with (from 13 to 22, total 10). + + uint16 hitSoundsByFightMoves[12][10] = { + {S39,S42,S43,S43,S39,S39,S39,S39,S39,S42}, + {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, + {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, + {S39,S39,S39,S39,S33,S43,S39,S39,S39,S39}, + {S39,S39,S39,S39,S35,S39,S38,S38,S39,S39}, + {S39,S39,S39,S39,S33,S39,S41,S36,S39,S39}, + {S39,S39,S39,S39,S37,S40,S38,S38,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S40}, + {S39,S39,S39,S39,S33,S39,S41,S37,S39,S40}, + {S39,S39,S39,S39,S39,S39,S39,S39,S33,S33} + }; + + // This is why first dimension is between FightMove 1 and 12. + if (m_lastFightMove == FIGHTMOVE_NULL || m_lastFightMove >= FIGHTMOVE_HITFRONT) + return; + + uint16 soundId; + + // And this is why second dimension is between 13 and 22. + if (hitTo->m_lastFightMove <= FIGHTMOVE_GROUNDKICK || hitTo->m_lastFightMove >= FIGHTMOVE_IDLE2NORM) { + + if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) { + soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT]; + } else { + soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT]; + } + } else { + soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_lastFightMove - FIGHTMOVE_HITFRONT]; + } + + if (soundId != NO_SND) + DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f); +} + +void +CPed::Say(uint16 audio) +{ + uint16 audioToPlay = audio; + + if (IsPlayer()) { + switch (audio) { + case SOUND_PED_DEATH: + audioToPlay = SOUND_PED_DAMAGE; + break; + case SOUND_PED_DAMAGE: + case SOUND_PED_HIT: + case SOUND_PED_LAND: + break; + case SOUND_PED_BULLET_HIT: + case SOUND_PED_CAR_JACKED: + case SOUND_PED_DEFEND: + audioToPlay = SOUND_PED_HIT; + break; + default: + return; + } + } else { + if (3.0f + TheCamera.GetPosition().z < GetPosition().z) + return; + + if (TheCamera.m_CameraAverageSpeed > 1.65f) { + return; + } else if (TheCamera.m_CameraAverageSpeed > 1.25f) { + if (audio != SOUND_PED_DEATH && audio != SOUND_PED_TAXI_WAIT && audio != SOUND_PED_EVADE) + return; + + } else if (TheCamera.m_CameraAverageSpeed > 0.9f) { + switch (audio) { + case SOUND_PED_DEATH: + case SOUND_PED_BURNING: + case SOUND_PED_FLEE_SPRINT: + case SOUND_PED_TAXI_WAIT: + case SOUND_PED_EVADE: + case SOUND_PED_CAR_COLLISION: + break; + default: + return; + } + } + } + + if (audioToPlay < m_queuedSound) { + if (audioToPlay != m_lastQueuedSound || audioToPlay == SOUND_PED_DEATH + || PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime + + m_currentSoundStart + + (uint32) CGeneral::GetRandomNumberInRange(0, PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) { + m_queuedSound = audioToPlay; + } + } +} + 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); } @@ -4884,4 +5180,9 @@ STARTPATCHES InjectHook(0x4E9870, &CPed::LoadFightData, PATCH_JUMP); InjectHook(0x4E8EC0, &CPed::FightStrike, PATCH_JUMP); InjectHook(0x4CCE20, &CPed::GetLocalDirection, PATCH_JUMP); + InjectHook(0x4E8E20, &CPed::PlayHitSound, PATCH_JUMP); + InjectHook(0x4E5A10, &CPed::Say, PATCH_JUMP); + InjectHook(0x4D58D0, &CPed::SetWaitState, PATCH_JUMP); + InjectHook(0x4D1D70, (void (CPed::*)(CEntity*, int)) &CPed::SetFlee, PATCH_JUMP); + InjectHook(0x4D1D70, (void (CPed::*)(CVector2D&, int)) &CPed::SetFlee, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index be7442b0..c526d023 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -10,9 +10,35 @@ #include "AnimBlendAssociation.h" #include "WeaponInfo.h" #include "Fire.h" +#include "DMAudio.h" struct CPathNode; +struct CPedAudioData +{ + int m_nFixedDelayTime; + int m_nOverrideFixedDelayTime; + int m_nOverrideMaxRandomDelayTime; + int m_nMaxRandomDelayTime; +}; + +// For hit sounds in fight +enum { + S33 = SOUND_FIGHT_PUNCH_33, + S34 = SOUND_FIGHT_KICK_34, + S35 = SOUND_FIGHT_HEADBUTT_35, + S36 = SOUND_FIGHT_PUNCH_36, + S37 = SOUND_FIGHT_PUNCH_37, + S38 = SOUND_FIGHT_CLOSE_PUNCH_38, + S39 = SOUND_FIGHT_PUNCH_39, + S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 , + S41 = SOUND_FIGHT_PUNCH_41, + S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42, + S43 = SOUND_FIGHT_KNEE_OR_KICK_43, + S44 = SOUND_FIGHT_KICK_44, + NO_SND = SOUND_TOTAL_PED_SOUNDS +}; + struct FightMove { AnimationId animId; @@ -29,6 +55,7 @@ static_assert(sizeof(FightMove) == 0x18, "FightMove: error"); enum PedFightMoves { FIGHTMOVE_NULL, + // Attacker FIGHTMOVE_STDPUNCH, FIGHTMOVE_IDLE, FIGHTMOVE_SHUFFLE_F, @@ -41,6 +68,7 @@ enum PedFightMoves FIGHTMOVE_ROUNDHOUSE, FIGHTMOVE_BODYBLOW, FIGHTMOVE_GROUNDKICK, + // Opponent FIGHTMOVE_HITFRONT, FIGHTMOVE_HITBACK, FIGHTMOVE_HITRIGHT, @@ -260,7 +288,7 @@ public: uint8 m_ped_flagD4 : 1; uint8 m_ped_flagD8 : 1; uint8 bIsPedDieAnimPlaying : 1; - uint8 m_ped_flagD20 : 1; + uint8 bIsFleeing : 1; uint8 m_ped_flagD40 : 1; // reset when objective changes uint8 bScriptObjectiveCompleted : 1; @@ -431,11 +459,11 @@ public: uint16 m_numNearPeds; int8 m_lastWepDam; uint8 pad_51F; - uint8 field_520; + uint8 m_currentSoundStart; uint8 pad_521[3]; uint32 m_talkTimer; - uint16 m_talkTypeLast; - uint16 m_talkType; + uint16 m_lastQueuedSound; + uint16 m_queuedSound; CVector m_vecSeekPosEx; float m_seekExAngle; @@ -556,6 +584,8 @@ public: void StartFightDefend(uint8, uint8, uint8); void PlayHitSound(CPed*); void SetFall(int, AnimationId, uint8); + void SetFlee(CEntity*, int); + void SetFlee(CVector2D&, int); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -633,6 +663,7 @@ public: static CColPoint &ms_tempColPoint; static uint16 &unknownFightThing; // TODO static FightMove (&ms_fightMoves)[24]; + static CPedAudioData (&PedAudioData)[38]; }; void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg); |