diff options
-rw-r--r-- | src/Camera.cpp | 13 | ||||
-rw-r--r-- | src/Camera.h | 1 | ||||
-rw-r--r-- | src/General.h | 15 | ||||
-rw-r--r-- | src/entities/Ped.cpp | 547 | ||||
-rw-r--r-- | src/entities/Ped.h | 108 | ||||
-rw-r--r-- | src/entities/PedIK.cpp | 56 | ||||
-rw-r--r-- | src/entities/PedIK.h | 4 | ||||
-rw-r--r-- | src/entities/PlayerPed.h | 2 | ||||
-rw-r--r-- | src/modelinfo/PedModelInfo.h | 6 | ||||
-rw-r--r-- | src/weapons/WeaponInfo.cpp | 10 |
10 files changed, 705 insertions, 57 deletions
diff --git a/src/Camera.cpp b/src/Camera.cpp index e5e50ef2..45172c44 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -1252,7 +1252,8 @@ CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors) Source.z += HeightFixerCarsObscuring; } -bool CCam::Using3rdPersonMouseCam() +bool +CCam::Using3rdPersonMouseCam() { return CCamera::m_bUseMouse3rdPerson && (Mode == MODE_FOLLOWPED || @@ -1261,6 +1262,16 @@ bool CCam::Using3rdPersonMouseCam() Mode != MODE_TOPDOWN1 && this->CamTargetEntity == FindPlayerPed()); } +bool +CCam::GetWeaponFirstPersonOn() +{ + CEntity *target = this->CamTargetEntity; + if (target && target->IsPed()) + return ((CPed*)target)->GetWeapon()->m_bAddRotOffset; + + return false; +} + STARTPATCHES InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP); InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP); diff --git a/src/Camera.h b/src/Camera.h index 6d20de72..c4bcb674 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -171,6 +171,7 @@ struct CCam void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist); void FixCamWhenObscuredByVehicle(const CVector &TargetCoors); bool Using3rdPersonMouseCam(); + bool GetWeaponFirstPersonOn(); void Process_Debug(float *vec, float a, float b, float c); void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float); diff --git a/src/General.h b/src/General.h index fd78edaa..d315d50b 100644 --- a/src/General.h +++ b/src/General.h @@ -42,13 +42,14 @@ public: static float LimitRadianAngle(float angle) { - if (angle < -25.0f) - angle = -25.0f; - - if (angle > 25.0f) - angle = 25.0f; + float result; - float result = angle; + if (angle < -25.0f) + result = -25.0f; + else if (angle > 25.0f) + result = 25.0f; + else + result = angle; while (result >= PI) { result -= 2 * PI; @@ -71,7 +72,7 @@ public: if (x > 0.0f) { if (y > 0.0f) - return 2 * PI - atan2(x / y, 1.0f); + return PI - atan2(x / y, 1.0f); else return -atan2(x / y, 1.0f); } else { diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp index e908f14c..537f089f 100644 --- a/src/entities/Ped.cpp +++ b/src/entities/Ped.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "patcher.h" +#include "main.h" #include "Pools.h" #include "Particle.h" #include "Stats.h" @@ -18,6 +19,10 @@ #include "Weather.h" #include "CullZones.h" #include "Population.h" +#include "Renderer.h" +#include "Lights.h" +#include "PointLights.h" +#include "Pad.h" WRAPPER void CPed::QuitEnteringCar() { EAXJMP(0x4E0E00); } WRAPPER void CPed::KillPedWithCar(CVehicle* veh, float impulse) { EAXJMP(0x4EC430); } @@ -30,11 +35,8 @@ WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dra 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::Teleport(CVector) { EAXJMP(0x4D3E70); } WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } WRAPPER void CPed::Render(void) { EAXJMP(0x4D03F0); } -WRAPPER bool CPed::SetupLighting(void) { EAXJMP(0x4A7D30); } -WRAPPER void CPed::RemoveLighting(bool) { EAXJMP(0x4A7DC0); } WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); } WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } @@ -102,7 +104,7 @@ CPed::FlagToDestroyWhenNextProcessed(void) } bInVehicle = false; m_pMyVehicle = nil; - if (m_nCreatedBy == 2) /* TODO: enum (MISSION) */ + if (m_nCreatedBy == CREATED_BY_SCRIPT) m_nPedState = PED_DEAD; else m_nPedState = PED_NONE; @@ -279,12 +281,12 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_talkTimer = 0; m_talkTypeLast = 167; m_talkType = 167; - m_objective = 0; - m_prevObjective = 0; - m_nCreatedBy = 1; - field_180 = 0; - m_field_16C = nil; - field_170 = 0; + m_objective = OBJECTIVE_NONE; + m_prevObjective = OBJECTIVE_NONE; + m_nCreatedBy = CREATED_BY_RANDOM; + m_leader = nil; + m_pedInObjective = nil; + m_carInObjective = nil; bInVehicle = 0; m_pMyVehicle = nil; m_pVehicleAnim = nil; @@ -307,8 +309,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_lastHitTime = 0; m_hitRecoverTimer = 0; field_4E8 = 0; - m_movedX = 0; - m_movedY = 0; + m_moved = CVector2D(0.0f, 0.0f); m_fRotationCur = 0.0f; m_headingRate = 15.0f; m_fRotationDest = 0.0f; @@ -334,13 +335,13 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) m_pCollidingEntity = nil; m_nPedState = PED_IDLE; m_nLastPedState = PED_NONE; - m_nMoveState = 1; + m_nMoveState = PEDMOVE_STILL; m_nStoredActionState = 0; m_pFire = nil; m_pPointGunAt = nil; - m_pLookTarget = 0; + m_pLookTarget = nil; m_fLookDirection = 0.0f; - m_pCurSurface = 0; + m_pCurSurface = nil; m_targetUnused = nil; m_nPathNodes = 0; m_nCurPathNode = 0; @@ -630,6 +631,21 @@ CPed::CanSetPedState(void) m_nPedState != PED_ENTER_CAR && m_nPedState != PED_DEAD && m_nPedState != PED_CARJACK && m_nPedState != PED_STEAL_CAR; } +bool +CPed::IsPedInControl(void) +{ + return m_nPedState <= PED_STATES_NO_AI + && !m_ped_flagB8 && !m_ped_flagB10 + && m_fHealth > 0.0f; +} + +bool +CPed::CanStrafeOrMouseControl(void) +{ + return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || + m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; +} + void CPed::AddWeaponModel(int id) { @@ -847,7 +863,7 @@ CPed::Avoid(void) if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { nearestPed = m_nearPeds[0]; - if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_field_16C) { + if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { // Check if this ped wants to avoid the nearest one if (CPedType::GetAvoid(this->m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { @@ -2037,15 +2053,496 @@ CPed::SetModelIndex(uint32 mi) RpAnimBlendClumpInit((RpClump*) m_rwObject); RpAnimBlendClumpFillFrameArray((RpClump*) m_rwObject, m_pFrames); CPedModelInfo *modelInfo = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex); - SetPedStats(static_cast<ePedStats>(modelInfo->m_pedStatType)); + SetPedStats((ePedStats) modelInfo->m_pedStatType); m_headingRate = m_pedStats->m_headingChangeRate; - m_animGroup = static_cast<AssocGroupId>(modelInfo->m_animGroup); + m_animGroup = (AssocGroupId) modelInfo->m_animGroup; CAnimManager::AddAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE); // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; } +void +CPed::RemoveLighting(bool reset) +{ + CRenderer::RemoveVehiclePedLights(this, reset); +} + +bool +CPed::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + if (m_ped_flagB10) { + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + } else { + // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. + float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); + if (!m_ped_flagB20 && lightMult != 1.0f) { + SetAmbientAndDirectionalColours(lightMult); + return true; + } + } + return false; +} + +void +CPed::Teleport(CVector pos) +{ + CWorld::Remove(this); + GetPosition() = pos; + bIsStanding = false; + m_nPedStateTimer = 0; + m_actionX = 0.0f; + m_actionY = 0.0f; + m_pDamageEntity = nil; + CWorld::Add(this); +} + +void +CPed::CalculateNewOrientation(void) +{ + if (CReplay::IsPlayingBack() || !IsPedInControl()) + return; + + CVector pos = *GetPosition(); + + GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur); + + // Because SetRotate makes pos. all 0 + GetPosition() = pos; +} + +float +CPed::WorkOutHeadingForMovingFirstPerson(float offset) +{ + if (!IsPlayer()) + return 0.0f; + + CPad *pad0 = CPad::GetPad(0); + float leftRight = pad0->GetPedWalkLeftRight(); + float upDown = pad0->GetPedWalkUpDown(); + float &angle = ((CPlayerPed*)this)->m_fWalkAngle; + + if (upDown != 0.0f) { + angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); + } else { + if (leftRight < 0.0f) + angle = 0.5 * PI; + else if (leftRight > 0.0f) + angle = -0.5 * PI; + } + + return CGeneral::LimitRadianAngle(offset + angle); +} + +void +CPed::CalculateNewVelocity(void) +{ + if (IsPedInControl()) { + float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep(); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest); + + if (m_fRotationCur - PI > limitedRotDest) { + limitedRotDest += 2 * PI; + } else if(PI + m_fRotationCur < limitedRotDest) { + limitedRotDest -= 2 * PI; + } + + if (IsPlayer() && m_nPedState == PED_ATTACK) + headAmount /= 4.0f; + + float neededTurn = limitedRotDest - m_fRotationCur; + if (neededTurn <= headAmount) { + if (neededTurn > (-headAmount)) + m_fRotationCur += neededTurn; + else + m_fRotationCur -= headAmount; + } else { + m_fRotationCur += headAmount; + } + } + + CVector2D forward(sin(m_fRotationCur), cos(m_fRotationCur)); + + m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * cos(m_fRotationCur)) + -sin(m_fRotationCur) * m_vecAnimMoveDelta.y; + m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * sin(m_fRotationCur)); + + if (CTimer::GetTimeStep() >= 0.01f) { + m_moved = m_moved * (1 / CTimer::GetTimeStep()); + } else { + m_moved = m_moved * (1 / 100.0f); + } + + if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) + || FindPlayerPed() != this || !CanStrafeOrMouseControl()) + return; + + float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); + float pedSpeed = m_moved.Magnitude(); + float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); + + if (localWalkAngle < -0.5 * PI) { + localWalkAngle += PI; + } else if (localWalkAngle > 0.5 * PI) { + localWalkAngle -= PI; + } + + // Interestingly this part is responsible for diagonal walking. + if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { + TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; + m_moved = CVector2D(-sin(walkAngle), cos(walkAngle)) * pedSpeed; + } + + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE); + CAnimBlendAssociation* fightAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_FIGHT_IDLE); + + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { + LimbOrientation newUpperLegs; + newUpperLegs.phi = localWalkAngle; + + if (newUpperLegs.phi < -DEGTORAD(100.0f)) { + newUpperLegs.phi += PI; + } else if (newUpperLegs.phi > DEGTORAD(100.0f)) { + newUpperLegs.phi -= PI; + } + + if (newUpperLegs.phi > -DEGTORAD(50.0f) && newUpperLegs.phi < DEGTORAD(50.0f)) { + newUpperLegs.theta = 0.0f; + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); + } + } +} + +bool +CPed::CanBeDeleted(void) +{ + if (this->bInVehicle) + return false; + + switch (m_nCreatedBy) { + case CREATED_BY_RANDOM: + return true; + case CREATED_BY_SCRIPT: + return false; + default: + return true; + } +} + +bool +CPed::CanPedDriveOff(void) +{ + if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + return false; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *ped = m_nearPeds[i]; + if (ped->m_nPedType == m_nPedType && ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && ped->m_carInObjective == m_carInObjective) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; + return false; + } + } + return true; +} + +// I couldn't find where it is used. +bool +CPed::CanPedJumpThis(int32 unused) +{ + CVector2D forward(-sin(m_fRotationCur), -cos(m_fRotationCur)); + CVector pos = GetPosition(); + // wat? + CVector forwardPos( + forward.x + pos.x, + forward.y + pos.y, + pos.z); + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} + +bool +CPed::CanPedReturnToState(void) +{ + return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && + m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; +} + +bool +CPed::CanSeeEntity(CEntity *entity, float threshold) +{ + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + entity->GetPosition().x, + entity->GetPosition().x, + GetPosition().x, + GetPosition().y); + + if (neededAngle < 0.0f) + neededAngle += 2 * PI; + else if (neededAngle > 2 * PI) + neededAngle -= 2 * PI; + + float ourAngle = m_fRotationCur; + if (ourAngle < 0.0f) + ourAngle += 2 * PI; + else if (ourAngle > 2 * PI) + ourAngle -= 2 * PI; + + float neededTurn = fabs(neededAngle - ourAngle); + + return neededTurn < threshold || 2 * PI - threshold < neededTurn; +} + +bool +CPed::IsTemporaryObjective(eObjective objective) +{ + return objective == OBJECTIVE_LEAVE_VEHICLE || objective == OBJECTIVE_SET_LEADER || + objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; +} + +void +CPed::SetMoveState(eMoveState state) +{ + m_nMoveState = state; +} + +void +CPed::SetObjectiveTimer(int time) +{ + if (time == 0) { + m_objectiveTimer = 0; + } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::ForceStoredObjective(eObjective objective) +{ + if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + m_prevObjective = m_objective; + return; + } + + switch (m_objective) + { + case OBJECTIVE_FLEE_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::SetStoredObjective(void) +{ + if (m_objective == m_prevObjective) + return; + + switch (m_objective) + { + case OBJECTIVE_FLEE_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::RestorePreviousObjective(void) +{ + if (m_objective == OBJECTIVE_NONE) + return; + + if (m_objective != OBJECTIVE_LEAVE_VEHICLE && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) + m_pedInObjective = nil; + + if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT) { + m_objective = OBJECTIVE_NONE; + if (m_pMyVehicle) + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + + } else { + m_objective = m_prevObjective; + m_prevObjective = OBJECTIVE_NONE; + } + m_ped_flagD40 = false; +} + +void +CPed::SetLeader(CEntity *leader) +{ + m_leader = (CPed*)leader; + + if(m_leader) + m_leader->RegisterReference((CEntity **)m_leader); +} + +void +CPed::SetObjective(eObjective newObj, void *entity) +{ + if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) + return; + + if (m_prevObjective == newObj) { + // Why? + if (m_prevObjective != OBJECTIVE_NONE) + return; + } + + if (entity == this) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + switch (newObj) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_FIGHT_CHAR: + if (m_pedInObjective == entity) + return; + + break; + case OBJECTIVE_LEAVE_VEHICLE: + case OBJECTIVE_FLEE_CAR: + return; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT: + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective == entity) + return; + + break; + case OBJECTIVE_SET_LEADER: + if (m_leader == entity) + return; + + break; + default: + break; + } + } else { + if (newObj == OBJECTIVE_LEAVE_VEHICLE && !bInVehicle) + return; + } + + m_ped_flagD40 = false; + if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { + if (m_objective != newObj) { + if (IsTemporaryObjective(newObj)) + ForceStoredObjective(newObj); + else + SetStoredObjective(); + } + m_objective = newObj; + } else { + m_prevObjective = newObj; + } + + switch (newObj) { + case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT: + + // In this special case, entity parameter isn't CEntity, but int. + SetObjectiveTimer((int)entity); + return; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_MUG_CHAR: + m_pLastPathNode = nil; + m_ped_flagD20 = false; + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective); + m_pLookTarget = (CEntity*)entity; + m_pLookTarget->RegisterReference((CEntity**)m_pLookTarget); + return; + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FIGHT_CHAR: + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective); + return; + case OBJECTIVE_FOLLOW_PED_IN_FORMATION: + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective); + m_pedFormation = 1; + return; + 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; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_RUN); + + if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { + RestorePreviousObjective(); + return; + } + // fall through + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT: + case OBJECTIVE_BUY_ICE_CREAM: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity**)m_carInObjective); + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**)m_pSeekTarget); + m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f); + if (newObj == OBJECTIVE_SOLICIT) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_nCreatedBy == CREATED_BY_SCRIPT && + (m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) { + SetObjectiveTimer(14000); + } else { + m_objectiveTimer = 0; + } + return; + case OBJECTIVE_SET_LEADER: + SetLeader((CEntity*)entity); + RestorePreviousObjective(); + return; + 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; + } + } +} + 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); } @@ -2084,13 +2581,12 @@ STARTPATCHES InjectHook(0x4D2BB0, &CPed::Avoid, PATCH_JUMP); InjectHook(0x4C6A50, &CPed::ClearAimFlag, PATCH_JUMP); InjectHook(0x4C64F0, &CPed::ClearLookFlag, PATCH_JUMP); - InjectHook(0x4E5BD0, &CPed::IsPedHeadAbovePos, PATCH_JUMP); + InjectHook(0x4EB670, &CPed::IsPedHeadAbovePos, PATCH_JUMP); InjectHook(0x4E68A0, &CPed::FinishedAttackCB, PATCH_JUMP); InjectHook(0x4E5BD0, &CheckForPedsOnGroundToAttack, PATCH_JUMP); InjectHook(0x4E6BA0, &CPed::Attack, PATCH_JUMP); InjectHook(0x4CF980, &CPed::RemoveWeaponModel, PATCH_JUMP); InjectHook(0x4CFA60, &CPed::SetCurrentWeapon, PATCH_JUMP); - InjectHook(0x4DD920, &CPed::SelectGunIfArmed, PATCH_JUMP); InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP); InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP); InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP); @@ -2104,7 +2600,16 @@ STARTPATCHES InjectHook(0x4CC6C0, &CPed::PlayFootSteps, PATCH_JUMP); InjectHook(0x4C5350, &CPed::BuildPedLists, PATCH_JUMP); InjectHook(0x4CF9B0, &CPed::GiveWeapon, PATCH_JUMP); - InjectHook(0x4C5330, &CPed::SetPedStats, PATCH_JUMP); InjectHook(0x4C52A0, &CPed::SetModelIndex_, PATCH_JUMP); InjectHook(0x4D6570, &CPed::FlagToDestroyWhenNextProcessed_, PATCH_JUMP); + InjectHook(0x4A7D30, &CPed::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7DC0, &CPed::RemoveLighting_, PATCH_JUMP); + InjectHook(0x4D3E70, &CPed::Teleport_, PATCH_JUMP); + InjectHook(0x4C7EA0, &CPed::CalculateNewOrientation, PATCH_JUMP); + InjectHook(0x4C78F0, &CPed::WorkOutHeadingForMovingFirstPerson, PATCH_JUMP); + InjectHook(0x4C73F0, &CPed::CalculateNewVelocity, PATCH_JUMP); + InjectHook(0x4D72F0, &CPed::CanPedJumpThis, PATCH_JUMP); + InjectHook(0x4DD820, &CPed::CanSeeEntity, PATCH_JUMP); + InjectHook(0x4D9460, &CPed::RestorePreviousObjective, PATCH_JUMP); + InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Ped.h b/src/entities/Ped.h index 92fa32c1..558ec9c1 100644 --- a/src/entities/Ped.h +++ b/src/entities/Ped.h @@ -13,6 +13,45 @@ struct CPathNode; +enum eObjective { + OBJECTIVE_NONE, + OBJECTIVE_IDLE, + OBJECTIVE_FLEE_TILL_SAFE, + OBJECTIVE_GUARD_SPOT, + OBJECTIVE_GUARD_AREA, + OBJECTIVE_WAIT_IN_CAR, + OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT, + OBJECTIVE_KILL_CHAR_ON_FOOT, + OBJECTIVE_KILL_CHAR_ANY_MEANS, + OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, + OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, + OBJECTIVE_GOTO_CHAR_ON_FOOT, + OBJECTIVE_FOLLOW_PED_IN_FORMATION, + OBJECTIVE_LEAVE_VEHICLE, + OBJECTIVE_ENTER_CAR_AS_PASSENGER, + OBJECTIVE_ENTER_CAR_AS_DRIVER, + OBJECTIVE_FOLLOW_CAR_IN_CAR, + OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE, + OBJECTIVE_DESTROY_OBJ, + OBJECTIVE_DESTROY_CAR, + OBJECTIVE_GOTO_AREA_ANY_MEANS, + OBJECTIVE_GOTO_AREA_ON_FOOT, + OBJECTIVE_RUN_TO_AREA, + OBJECTIVE_23, + OBJECTIVE_24, + OBJECTIVE_FIGHT_CHAR, + OBJECTIVE_SET_LEADER, + OBJECTIVE_FOLLOW_ROUTE, + OBJECTIVE_SOLICIT, + OBJECTIVE_HAIL_TAXI, + OBJECTIVE_CATCH_TRAIN, + OBJECTIVE_BUY_ICE_CREAM, + OBJECTIVE_STEAL_ANY_CAR, + OBJECTIVE_MUG_CHAR, + OBJECTIVE_FLEE_CAR, + OBJECTIVE_35 +}; + enum { VEHICLE_ENTER_FRONT_RIGHT = 11, VEHICLE_ENTER_REAR_RIGHT = 12, @@ -20,6 +59,11 @@ enum { VEHICLE_ENTER_REAR_LEFT = 16, }; +enum { + CREATED_BY_RANDOM = 1, + CREATED_BY_SCRIPT +}; + enum PedLineUpPhase { LINE_UP_TO_CAR_START, LINE_UP_TO_CAR_END, @@ -97,7 +141,7 @@ enum PedState PED_ARRESTED = 56, }; -enum { +enum eMoveState { PEDMOVE_NONE, PEDMOVE_STILL, PEDMOVE_WALK, @@ -146,7 +190,7 @@ public: uint8 m_ped_flagD8 : 1; uint8 m_ped_flagD10 : 1; uint8 m_ped_flagD20 : 1; - uint8 m_ped_flagD40 : 1; + uint8 m_ped_flagD40 : 1; // reset when objective changes uint8 m_ped_flagD80 : 1; uint8 m_ped_flagE1 : 1; @@ -197,14 +241,14 @@ public: uint8 m_nCreatedBy; uint8 field_161; uint8 pad_162[2]; - uint32 m_objective; - uint32 m_prevObjective; - CPed* m_field_16C; - uint32 field_170; + eObjective m_objective; + eObjective m_prevObjective; + CPed *m_pedInObjective; + CVehicle *m_carInObjective; uint32 field_174; uint32 field_178; uint32 field_17C; - uint32 field_180; + CPed *m_leader; uint32 m_pedFormation; uint32 m_fearFlags; CEntity *m_threatEntity; @@ -223,7 +267,7 @@ public: uint32 m_nPedStateTimer; PedState m_nPedState; PedState m_nLastPedState; - int32 m_nMoveState; + eMoveState m_nMoveState; int32 m_nStoredActionState; int32 m_nPrevActionState; int32 m_nWaitState; @@ -246,8 +290,7 @@ public: uint16 m_routeType; uint16 m_routeCurDir; uint16 field_2D2; - float m_movedX; - float m_movedY; + CVector2D m_moved; float m_fRotationCur; float m_fRotationDest; float m_headingRate; @@ -304,7 +347,7 @@ public: uint32 m_attackTimer; uint32 m_lastHitTime; uint32 m_hitRecoverTimer; - uint32 field_4E0; + uint32 m_objectiveTimer; uint32 m_duckTimer; uint32 field_4E8; int32 m_bloodyFootprintCount; @@ -345,9 +388,6 @@ public: CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); } void dtor(void) { this->CPed::~CPed(); } - bool IsPlayer(void); - bool UseGroundColModel(void); - bool CanSetPedState(void); void AddWeaponModel(int id); void AimGun(void); void KillPedWithCar(CVehicle *veh, float impulse); @@ -369,7 +409,6 @@ public: bool IsPedHeadAbovePos(float zOffset); void RemoveWeaponModel(int modelId); void SetCurrentWeapon(uint32 weaponType); - bool SelectGunIfArmed(void); void Duck(void); void ClearDuck(void); void ClearPointGunAt(void); @@ -379,14 +418,22 @@ public: void SetPedPositionInCar(void); void PlayFootSteps(void); void QuitEnteringCar(void); - bool IsPointerValid(void); - void SortPeds(CPed**, int, int); void BuildPedLists(void); uint32 GiveWeapon(eWeaponType weaponType, uint32 ammo); - void SetPedStats(ePedStats); + void CalculateNewOrientation(void); + float WorkOutHeadingForMovingFirstPerson(float); + void CalculateNewVelocity(void); + bool CanPedJumpThis(int32); + bool CanSeeEntity(CEntity*, float); + void RestorePreviousObjective(void); + void SetObjective(eObjective, void*); + + // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); static void GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult); static void GetPositionToOpenCarDoor(CVector* output, CVehicle* veh, uint32 enterType); + + // Callbacks static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data); static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data); static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg); @@ -416,6 +463,26 @@ public: static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); + // functions that I see unnecessary to hook + bool IsPlayer(void); + bool UseGroundColModel(void); + bool CanSetPedState(void); + bool IsPedInControl(void); + bool CanPedDriveOff(void); + bool CanBeDeleted(void); + bool CanStrafeOrMouseControl(void); + bool CanPedReturnToState(void); + void SetMoveState(eMoveState); + bool IsTemporaryObjective(eObjective objective); + void SetObjectiveTimer(int); + bool SelectGunIfArmed(void); + bool IsPointerValid(void); + void SortPeds(CPed**, int, int); + void ForceStoredObjective(eObjective); + void SetStoredObjective(void); + void SetLeader(CEntity* leader); + void SetPedStats(ePedStats); + inline bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; } inline CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; } inline CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; } @@ -424,6 +491,9 @@ public: // to make patching virtual functions possible void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); } void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); } + bool SetupLighting_(void) { return CPed::SetupLighting(); } + void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); } + void Teleport_(CVector pos) { CPed::Teleport(pos); } // set by 0482:set_threat_reaction_range_multiplier opcode static uint16 &distanceMultToCountPedNear; @@ -447,6 +517,6 @@ static_assert(offsetof(CPed, m_weapons) == 0x35C, "CPed: error"); static_assert(offsetof(CPed, m_currentWeapon) == 0x498, "CPed: error"); static_assert(offsetof(CPed, m_lookTimer) == 0x4CC, "CPed: error"); static_assert(offsetof(CPed, m_bodyPartBleeding) == 0x4F2, "CPed: error"); -static_assert(offsetof(CPed, m_field_16C) == 0x16C, "CPed: error"); +static_assert(offsetof(CPed, m_pedInObjective) == 0x16C, "CPed: error"); static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error"); static_assert(sizeof(CPed) == 0x53C, "CPed: error"); diff --git a/src/entities/PedIK.cpp b/src/entities/PedIK.cpp index fa773bbf..b9baf49c 100644 --- a/src/entities/PedIK.cpp +++ b/src/entities/PedIK.cpp @@ -5,6 +5,8 @@ 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); } CPedIK::CPedIK(CPed *ped) { @@ -21,6 +23,59 @@ CPedIK::CPedIK(CPed *ped) } void +CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool changeRoll) +{ + RwFrame *f = animBlend->frame; + RwMatrix *mat = CPedIK::GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate()); + + RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z }; + RwV3d rightVector; + RwV3d pos = RwFrameGetMatrix(f)->pos; + + // rotation == 0 -> looking in y direction + // left? vector + float c = cos(m_ped->m_fRotationCur); + float s = sin(m_ped->m_fRotationCur); + rightVector.x = -(c*mat->right.x + s*mat->right.y); + rightVector.y = -(c*mat->up.x + s*mat->up.y); + rightVector.z = -(c*mat->at.x + s*mat->at.y); + + if(changeRoll){ + // Used when aiming only involves over the legs.(canAimWithArm) + // Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs. + // Not noticeable in normal conditions... + + RwV3d forwardVector; + CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up); + inversedForward.Normalise(); + float dotProduct = DotProduct(mat->at, inversedForward); + if(dotProduct > 1.0f) dotProduct = 1.0f; + if(dotProduct < -1.0f) dotProduct = -1.0f; + float alpha = acos(dotProduct); + + if(mat->at.z < 0.0f) + alpha = -alpha; + + forwardVector.x = s * mat->right.x - c * mat->right.y; + forwardVector.y = s * mat->up.x - c * mat->up.y; + forwardVector.z = s * mat->at.x - c * mat->at.y; + + float curYaw, curPitch; + CPedIK::ExtractYawAndPitchWorld(mat, &curYaw, &curPitch); + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT); + RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT); + }else{ + // pitch + RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT); + // yaw + RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT); + } + RwFrameGetMatrix(f)->pos = pos; + RwMatrixDestroy(mat); +} + +void CPedIK::GetComponentPosition(RwV3d *pos, PedNode node) { RwFrame *f; @@ -50,4 +105,5 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination) STARTPATCHES InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP); InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP); + InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/entities/PedIK.h b/src/entities/PedIK.h index 7c798dc2..e17d52eb 100644 --- a/src/entities/PedIK.h +++ b/src/entities/PedIK.h @@ -1,6 +1,7 @@ #pragma once #include "common.h" #include "PedModelInfo.h" +#include "AnimBlendClumpData.h" struct LimbOrientation { @@ -32,5 +33,8 @@ public: bool PointGunAtPosition(CVector *position); void GetComponentPosition(RwV3d *pos, PedNode node); static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination); + void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll); + void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*); + void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*); }; static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error"); diff --git a/src/entities/PlayerPed.h b/src/entities/PlayerPed.h index d09deb49..15ad74a6 100644 --- a/src/entities/PlayerPed.h +++ b/src/entities/PlayerPed.h @@ -36,7 +36,7 @@ public: int8 field_1415; CVector field_1416[6]; int32 field_1488[6]; - float field_1512; + float m_fWalkAngle; float m_fFPSMoveHeading; ~CPlayerPed(); diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index 04d1ba02..7be2c195 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -21,9 +21,9 @@ enum PedNode { class CPedModelInfo : public CClumpModelInfo { public: - int32 m_animGroup; - int32 m_pedType; - int32 m_pedStatType; + uint32 m_animGroup; + uint32 m_pedType; + uint32 m_pedStatType; uint32 m_carsCanDrive; CColModel *m_hitColModel; RpAtomic *m_head; diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index 4830c86a..5be18c3c 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -137,7 +137,7 @@ CWeaponInfo::LoadWeaponData(void) if (strncmp(anim2ToPlay, "null", 4) != 0) { animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, anim2ToPlay); - ms_apWeaponInfos[weaponType].m_Anim2ToPlay = static_cast<AnimationId>(animAssoc->animId); + ms_apWeaponInfos[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId; } CVector vecFireOffset(fireOffsetX, fireOffsetY, fireOffsetZ); @@ -154,10 +154,10 @@ CWeaponInfo::LoadWeaponData(void) ms_apWeaponInfos[weaponType].m_fSpread = spread; ms_apWeaponInfos[weaponType].m_vecFireOffset = vecFireOffset; ms_apWeaponInfos[weaponType].m_AnimToPlay = animId; - ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart * 0.03f; - ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd * 0.03f; - ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire * 0.03f; - ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire * 0.03f; + ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f; ms_apWeaponInfos[weaponType].m_nModelId = modelId; ms_apWeaponInfos[weaponType].m_bUseGravity = flags; ms_apWeaponInfos[weaponType].m_bSlowsDown = flags >> 1; |