From 936acedcf045208afca770082771dd7e52d0c235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Sun, 21 Jul 2019 00:29:58 +0300 Subject: CPed continues, including some fixes --- src/control/PathFind.cpp | 2 +- src/control/PathFind.h | 1 + src/peds/Ped.cpp | 445 ++++++++++++++++++++++++++++++++++++++++++++--- src/peds/Ped.h | 19 +- src/peds/PedIK.cpp | 55 ++++++ src/peds/PedIK.h | 13 ++ 6 files changed, 507 insertions(+), 28 deletions(-) diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index a92882db..f90e0c8f 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -5,7 +5,7 @@ CPathFind &ThePaths = *(CPathFind*)0x8F6754; WRAPPER int32 CPathFind::FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels) { EAXJMP(0x42CC30); } - +WRAPPER CPathNode** CPathFind::FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*) { EAXJMP(0x42B9F0); } int TempListLength; enum diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 9b6be573..9d97de3f 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -129,6 +129,7 @@ public: void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight); void RegisterMapObject(CTreadable *mapObject); int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels); + CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*); bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); } diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index f2a58bc2..0c4e33d6 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -27,15 +27,13 @@ #include "Phones.h" #include "EventList.h" #include "Darkel.h" +#include "PathFind.h" +#include "ModelIndices.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::RestorePreviousState(void) { EAXJMP(0x4C5E30); } -WRAPPER void CPed::SetPointGunAt(CEntity*) { EAXJMP(0x4E5F70); } -WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); } -WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); } WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } @@ -48,7 +46,6 @@ WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); } WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); } -WRAPPER void CPed::SetWanderPath(int8) { EAXJMP(0x4D2750); } WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; @@ -2269,7 +2266,7 @@ CPed::CanSeeEntity(CEntity *entity, float threshold) { float neededAngle = CGeneral::GetRadianAngleBetweenPoints( entity->GetPosition().x, - entity->GetPosition().x, + entity->GetPosition().y, GetPosition().x, GetPosition().y); @@ -2464,7 +2461,7 @@ CPed::SetObjective(eObjective newObj, void *entity) // In this special case, entity parameter isn't CEntity, but int. SetObjectiveTimer((int)entity); - return; + break; case OBJECTIVE_KILL_CHAR_ON_FOOT: case OBJECTIVE_KILL_CHAR_ANY_MEANS: case OBJECTIVE_MUG_CHAR: @@ -2475,7 +2472,7 @@ CPed::SetObjective(eObjective newObj, void *entity) m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); m_pLookTarget = (CEntity*)entity; m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - return; + break; case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: case OBJECTIVE_GOTO_CHAR_ON_FOOT: @@ -2483,18 +2480,26 @@ CPed::SetObjective(eObjective newObj, void *entity) m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); m_pedInObjective = (CPed*)entity; m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - return; + break; case OBJECTIVE_FOLLOW_PED_IN_FORMATION: m_pedInObjective = (CPed*)entity; m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); m_pedFormation = 1; - return; + break; case OBJECTIVE_LEAVE_VEHICLE: case OBJECTIVE_FLEE_CAR: m_carInObjective = (CVehicle*)entity; m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); if (!m_carInObjective->bIsBus || m_leaveCarTimer) - return; + break; + + for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + break; + } + } + break; case OBJECTIVE_ENTER_CAR_AS_PASSENGER: case OBJECTIVE_ENTER_CAR_AS_DRIVER: @@ -2503,7 +2508,7 @@ CPed::SetObjective(eObjective newObj, void *entity) if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { RestorePreviousObjective(); - return; + break; } // fall through case OBJECTIVE_DESTROY_CAR: @@ -2522,19 +2527,13 @@ CPed::SetObjective(eObjective newObj, void *entity) } else { m_objectiveTimer = 0; } - return; + break; case OBJECTIVE_SET_LEADER: SetLeader((CEntity*)entity); RestorePreviousObjective(); - return; + break; default: - return; - } - for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) { - if (m_carInObjective->pPassengers[i] == this) { - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; - return; - } + break; } } @@ -3709,9 +3708,9 @@ CPed::SetGetUp(void) m_ped_flagE20 = true; m_pCollidingEntity = nil; m_ped_flagH1 = false; - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ASSOC_REPEAT); + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_SPRINT); if (animAssoc) { - if (RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ASSOC_RUNNING)) { + if (RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_RUN)) { CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_RUN, 8.0f); } else { CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 8.0f); @@ -3731,6 +3730,386 @@ CPed::SetGetUp(void) } } +void +CPed::ClearInvestigateEvent(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_ROAD_CROSS); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_XPRESS_SCRATCH); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_HBHB); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + if (m_eventType > EVENT_EXPLOSION) + m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; + + m_ped_flagD2 = false; + m_pEventEntity = nil; + ClearLookFlag(); + RestorePreviousState(); + if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_WALK); +} + +void +CPed::ClearLeader(void) +{ + if (!m_leader) + return; + + m_leader = nil; + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + if (CharCreatedBy == MISSION_CHAR) { + SetIdle(); + } else { + SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); + } + } else if (m_objective != OBJECTIVE_NONE) { + m_ped_flagH8 = true; + } +} + +void +CPed::ClearLook(void) +{ + RestorePreviousState(); + ClearLookFlag(); +} + +void +CPed::ClearObjective(void) +{ + if (IsPedInControl() || m_nPedState == PED_DRIVING) { + + m_objective = OBJECTIVE_NONE; + if (m_nPedState == PED_DRIVING && m_pMyVehicle) { + + if (m_pMyVehicle->pDriver != this) { + + m_ped_flagF1 = true; + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } else { + m_ped_flagH8 = true; + } +} + +void +CPed::ClearPause(void) +{ + RestorePreviousState(); +} + +void +CPed::ClearSeek(void) +{ + SetIdle(); + field_31C = 0; +} + +bool +CPed::SetWanderPath(int8 pathStateDest) +{ + uint8 nextPathState; + + if (IsPedInControl()) { + if (m_ped_flagE1) { + SetIdle(); + return false; + } else { + + // m_nPathState is pure direction for values 1,2,3 and 5,6,7 + + m_nPathState = pathStateDest; + if (pathStateDest == 0) + pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); + + ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, + m_nPathState, &nextPathState); + + // Circular loop until we find a node for current m_nPathState + while (!m_pLastPathNode) { + m_nPathState = (m_nPathState+1) % 8; + + // We're at where we started and couldn't find any node + if (m_nPathState == pathStateDest) { + ClearAll(); + SetIdle(); + return false; + } + ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, + m_nPathState, &nextPathState); + } + + // We did it, save next path state and return true + m_nPathState = nextPathState; + m_nPedState = PED_WANDER_PATH; + SetMoveState(PEDMOVE_WALK); + m_ped_flagB20 = false; + return true; + } + } else { + m_nPathState = pathStateDest; + m_ped_flagG8 = true; + return false; + } +} + +void +CPed::ClearWeapons(void) +{ + CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(currentWeapon->m_nModelId); + + m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; + m_currentWeapon = WEAPONTYPE_UNARMED; + + currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(currentWeapon->m_nModelId); + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) + { + CWeapon &weapon = GetWeapon(i); + weapon.m_eWeaponType = WEAPONTYPE_UNARMED; + weapon.m_eWeaponState = WEAPONSTATE_READY; + weapon.m_nAmmoInClip = 0; + weapon.m_nAmmoTotal = 0; + weapon.m_nTimer = 0; + } +} + +void +CPed::RestoreGunPosition(void) +{ + if (bIsLooking) { + m_pedIK.m_flags &= ~CPedIK::FLAG_2; + bIsRestoringGun = false; + } else if (m_pedIK.RestoreGunPosn()) { + bIsRestoringGun = false; + } else { + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; + } +} + +void +CPed::RestoreHeadingRate(void) +{ + m_headingRate = m_pedStats->m_headingChangeRate; +} + +void +CPed::RestoreHeadingRateCB(CAnimBlendAssociation* assoc, void* arg) +{ + ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; +} + +void +CPed::RestorePreviousState(void) +{ + if(!CanSetPedState() || m_nPedState == PED_FALL) + return; + + if (m_nPedState == PED_GETUP && !m_ped_flagE20) + return; + + if (bInVehicle && m_pMyVehicle) { + m_nPedState = PED_DRIVING; + m_nLastPedState = PED_NONE; + } else { + if (m_nLastPedState == PED_NONE) { + if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) { + if (SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)) != 0) + return; + } + SetIdle(); + return; + } + + switch (m_nLastPedState) { + case PED_IDLE: + SetIdle(); + break; + case PED_WANDER_PATH: + m_nPedState = PED_WANDER_PATH; + m_ped_flagB20 = false; + if (!m_ped_flagC80) { + if (m_pLastPathNode) { + CVector diff = m_pLastPathNode->pos - GetPosition(); + if (diff.MagnitudeSqr() < 49.0f) { + SetMoveState(PEDMOVE_WALK); + break; + } + } + } + SetWanderPath(CGeneral::GetRandomNumberInRange(0, 7)); + break; + default: + m_nPedState = m_nLastPedState; + SetMoveState((eMoveState) m_nPrevActionState); + break; + } + m_nLastPedState = PED_NONE; + } +} + +void +CPed::SetAimFlag(CEntity *to) +{ + bIsAimingGun = true; + bIsRestoringGun = false; + m_pLookTarget = to; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_pSeekTarget = to; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_lookTimer = 0; +} + +void +CPed::SetAimFlag(float angle) +{ + bIsAimingGun = true; + bIsRestoringGun = false; + m_fLookDirection = angle; + m_lookTimer = 0; + m_pLookTarget = nil; + m_pSeekTarget = nil; + if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::FLAG_4; + else + m_pedIK.m_flags &= ~CPedIK::FLAG_4; +} + +void +CPed::SetPointGunAt(CEntity *to) +{ + if (to) { + SetLookFlag(to,1); + SetAimFlag(to); + } + + if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + + if (m_nPedState != PED_ATTACK) + SetStoredState(); + + m_nPedState = PED_AIM_GUN; + bIsPointingGunAt = true; + CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + SetMoveState(PEDMOVE_NONE); + + CAnimBlendAssociation *aimAssoc; + + if (bCrouchWhenShooting) + aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_Anim2ToPlay); + else + aimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, curWeapon->m_AnimToPlay); + + if (!aimAssoc || aimAssoc->blendDelta < 0.0f) { + if (bCrouchWhenShooting) + aimAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f); + else + aimAssoc = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, curWeapon->m_AnimToPlay); + + aimAssoc->blendAmount = 0.0f; + aimAssoc->blendDelta = 8.0f; + } + if (to) + Say(SOUND_PED_ATTACK); +} + +void +CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal = ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::SetEvasiveStep(CEntity *reason, uint8 animType) +{ + AnimationId stepAnim; + + if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) + return; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float neededTurn = Abs(angleToFace - m_fRotationCur); + bool vehPressedHorn = false; + + if (neededTurn > PI) + neededTurn = 2 * PI - neededTurn; + + CVehicle *veh = (CVehicle*)reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) { + if (veh->m_nCarHornTimer) { + vehPressedHorn = true; + if (!IsPlayer()) + animType = 1; + } + } + if (neededTurn <= DEGTORAD(90.0f) || veh->m_modelIndex == MI_RCBANDIT || vehPressedHorn || animType != 0) { + SetLookFlag(veh, 1); + if (CGeneral::GetRandomNumberInRange(0,1) && veh->m_modelIndex != MI_RCBANDIT && animType == 0) { + stepAnim = ANIM_IDLE_TAXI; + } else { + + // I didn't get these things too much. + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + + float inversedAngleToFace = angleToFace + PI; + if (inversedAngleToFace > PI) + inversedAngleToFace -= 2*PI; + + neededTurn = inversedAngleToFace - vehDirection; + neededTurn = CGeneral::LimitRadianAngle(neededTurn); + if (neededTurn <= 0.0) + angleToFace = 0.5*PI + vehDirection; + else + angleToFace = vehDirection - 0.5*PI; + + if (animType == 2) + stepAnim = ANIM_HANDSCOWER; + else if (animType < 2) + stepAnim = ANIM_EV_STEP; + else + stepAnim = NUM_ANIMS; + } + if (!RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, stepAnim)) { + CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, stepAnim, 8.0f); + stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + stepAssoc->SetFinishCallback(PedEvadeCB, this); + + if (animType == 0) + Say(SOUND_PED_EVADE); + + m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } + } +} + 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); } @@ -3746,6 +4125,8 @@ WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP( 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); } WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); } @@ -3753,7 +4134,6 @@ WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); } WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } -WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); } class CPed_ : public CPed { @@ -3841,4 +4221,21 @@ STARTPATCHES InjectHook(0x4D1EA0, &CPed::ClearFlee, PATCH_JUMP); InjectHook(0x4D0BB0, &CPed::ClearFall, PATCH_JUMP); InjectHook(0x4D0F20, &CPed::SetGetUp, PATCH_JUMP); + InjectHook(0x4D6550, &CPed::RestoreHeadingRateCB, PATCH_JUMP); + InjectHook(0x4C5E30, &CPed::RestorePreviousState, PATCH_JUMP); + InjectHook(0x4E5F70, &CPed::SetPointGunAt, PATCH_JUMP); + InjectHook(0x4D2750, &CPed::SetWanderPath, PATCH_JUMP); + InjectHook(0x4D30C0, &CPed::SetEvasiveStep, PATCH_JUMP); + InjectHook(0x4EA360, &CPed::ClearInvestigateEvent, PATCH_JUMP); + InjectHook(0x4D8E80, &CPed::ClearLeader, PATCH_JUMP); + InjectHook(0x4D1360, &CPed::ClearLook, PATCH_JUMP); + InjectHook(0x4D8DF0, &CPed::ClearObjective, PATCH_JUMP); + InjectHook(0x4D0970, &CPed::ClearPause, PATCH_JUMP); + InjectHook(0x4D1620, &CPed::ClearSeek, PATCH_JUMP); + InjectHook(0x4CFB70, &CPed::ClearWeapons, PATCH_JUMP); + InjectHook(0x4C6BB0, &CPed::RestoreGunPosition, PATCH_JUMP); + InjectHook(0x4D6540, &CPed::RestoreHeadingRate, PATCH_JUMP); + InjectHook(0x4C69E0, (void (CPed::*)(CEntity*)) &CPed::SetAimFlag, PATCH_JUMP); + InjectHook(0x4C6960, (void (CPed::*)(float)) &CPed::SetAimFlag, PATCH_JUMP); + InjectHook(0x4CFB20, &CPed::SetAmmo, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 9f1858b4..7b8bc2ce 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -228,7 +228,7 @@ public: uint8 bNotAllowedToDuck : 1; uint8 bCrouchWhenShooting : 1; uint8 bIsDucking : 1; // set if you don't want ped to attack - uint8 m_ped_flagE20 : 1; + uint8 m_ped_flagE20 : 1; // getup complete? uint8 bDoBloodyFootprints : 1; uint8 m_ped_flagE80 : 1; @@ -336,7 +336,7 @@ public: bool bInVehicle; uint8 pad_315[3]; float field_318; - uint8 field_31C; + uint8 field_31C; // may be cutscene or phone cutscene status uint8 field_31D; int16 m_phoneId; uint32 m_lookingForPhone; // unused @@ -481,7 +481,7 @@ public: void ClearAll(void); void SetPointGunAt(CEntity*); bool Seek(void); - void SetWanderPath(int8); + bool SetWanderPath(int8); void SetFollowPath(CVector); void ClearAttackByRemovingAnim(void); void SetStoredState(void); @@ -490,6 +490,19 @@ public: void ClearFlee(void); void ClearFall(void); void SetGetUp(void); + void ClearInvestigateEvent(void); + void ClearLeader(void); + void ClearLook(void); + void ClearObjective(void); + void ClearPause(void); + void ClearSeek(void); + void ClearWeapons(void); + void RestoreGunPosition(void); + void RestoreHeadingRate(void); + void SetAimFlag(CEntity* to); + void SetAimFlag(float angle); + void SetAmmo(eWeaponType weaponType, uint32 ammo); + void SetEvasiveStep(CEntity*, uint8); // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); diff --git a/src/peds/PedIK.cpp b/src/peds/PedIK.cpp index 9b3f401f..3d5bcfb5 100644 --- a/src/peds/PedIK.cpp +++ b/src/peds/PedIK.cpp @@ -8,6 +8,8 @@ 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); } +LimbMovementInfo &CPedIK::ms_torsoInfo = *(LimbMovementInfo*)0x5F9F8C; + CPedIK::CPedIK(CPed *ped) { m_ped = ped; @@ -102,8 +104,61 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) return destination; } +// A helper function that adjusts "limb" parameter according to limitations. Doesn't move the limb. +int8 +CPedIK::MoveLimb(LimbOrientation &limb, float approxPhi, float approxTheta, LimbMovementInfo &moveInfo) +{ + int result = 1; + + // phi + + if (limb.phi > approxPhi) { + limb.phi -= moveInfo.yawD; + } else if (limb.phi < approxPhi) { + limb.phi += moveInfo.yawD; + } + + if (Abs(limb.phi - approxPhi) < moveInfo.yawD) { + limb.phi = approxPhi; + result = 2; + } + if (limb.phi > moveInfo.maxYaw || limb.phi < moveInfo.minYaw) { + limb.phi = clamp(limb.phi, moveInfo.minYaw, moveInfo.maxYaw); + result = 0; + } + + // theta + + if (limb.theta > approxTheta) { + limb.theta -= moveInfo.pitchD; + } else if (limb.theta < approxTheta) { + limb.theta += moveInfo.pitchD; + } + + if (Abs(limb.theta - approxTheta) < moveInfo.pitchD) + limb.theta = approxTheta; + else + result = 1; + + if (limb.theta > moveInfo.maxPitch || limb.theta < moveInfo.minPitch) { + limb.theta = clamp(limb.theta, moveInfo.minPitch, moveInfo.maxPitch); + result = 0; + } + return result; +} + +bool +CPedIK::RestoreGunPosn(void) +{ + int limbStatus = MoveLimb(m_torsoOrient, 0.0f, 0.0f, ms_torsoInfo); + RotateTorso(m_ped->m_pFrames[PED_MID], &m_torsoOrient, false); + return limbStatus == 2; +} + STARTPATCHES InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP); InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP); InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); + InjectHook(0x4ED440, &CPedIK::MoveLimb, PATCH_JUMP); + InjectHook(0x4EDD70, &CPedIK::RestoreGunPosn, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/PedIK.h b/src/peds/PedIK.h index e17d52eb..5f321280 100644 --- a/src/peds/PedIK.h +++ b/src/peds/PedIK.h @@ -9,6 +9,15 @@ struct LimbOrientation float theta; }; +struct LimbMovementInfo { + float maxYaw; + float minYaw; + float yawD; + float maxPitch; + float minPitch; + float pitchD; +}; + class CPed; class CPedIK @@ -28,6 +37,8 @@ public: LimbOrientation m_lowerArmOrient; int32 m_flags; + static LimbMovementInfo &ms_torsoInfo; + CPedIK(CPed *ped); bool PointGunInDirection(float phi, float theta); bool PointGunAtPosition(CVector *position); @@ -36,5 +47,7 @@ public: void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); + int8 MoveLimb(LimbOrientation &a1, float a2, float a3, LimbMovementInfo &a4); + bool RestoreGunPosn(void); }; static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); -- cgit v1.2.3