Even more CPed

Signed-off-by: eray orçunus <erayorcunus@gmail.com>
This commit is contained in:
eray orçunus 2019-07-03 19:34:42 +03:00
parent b2d1433392
commit d4ea6912f5
10 changed files with 705 additions and 57 deletions

View File

@ -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);

View File

@ -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);

View File

@ -42,13 +42,14 @@ public:
static float LimitRadianAngle(float angle)
{
float result;
if (angle < -25.0f)
angle = -25.0f;
if (angle > 25.0f)
angle = 25.0f;
float result = angle;
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 {

View File

@ -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

View File

@ -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");

View File

@ -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)
{
@ -20,6 +22,59 @@ CPedIK::CPedIK(CPed *ped)
m_lowerArmOrient.theta = 0.0f;
}
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)
{
@ -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

View File

@ -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");

View File

@ -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();

View File

@ -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;

View File

@ -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;