This commit is contained in:
_AG
2019-07-07 15:16:54 +02:00
159 changed files with 390 additions and 188 deletions

19
src/peds/CivilianPed.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "common.h"
#include "patcher.h"
#include "CivilianPed.h"
WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); }
CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype)
{
CPed::SetModelIndex(mi);
for (int i = 0; i < 10; i++)
{
m_nearPeds[i] = nil;
}
}
STARTPATCHES
InjectHook(0x4BFF30, &CCivilianPed::ctor, PATCH_JUMP);
InjectHook(0x4BFFC0, &CCivilianPed::dtor, PATCH_JUMP);
ENDPATCHES

16
src/peds/CivilianPed.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "Ped.h"
class CCivilianPed : public CPed
{
public:
CCivilianPed(int, int);
virtual ~CCivilianPed(void) { }
virtual void ProcessControl(void);
CCivilianPed *ctor(int pedtype, int mi) { return ::new (this) CCivilianPed(pedtype, mi); };
void dtor(void) { this->CCivilianPed::~CCivilianPed(); }
};
static_assert(sizeof(CCivilianPed) == 0x53C, "CCivilianPed: error");

14
src/peds/CopPed.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "common.h"
#include "patcher.h"
#include "CopPed.h"
CCopPed::~CCopPed()
{
ClearPursuit();
}
WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); }
STARTPATCHES
InjectHook(0x4C13E0, &CCopPed::dtor, PATCH_JUMP);
ENDPATCHES

73
src/peds/CopPed.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include "Ped.h"
enum eCrimeType
{
CRIME_NONE,
CRIME_POSSESSION_GUN,
CRIME_HIT_PED,
CRIME_HIT_COP,
CRIME_SHOOT_PED,
CRIME_SHOOT_COP,
CRIME_STEAL_CAR,
CRIME_RUN_REDLIGHT,
CRIME_RECKLESS_DRIVING,
CRIME_SPEEDING,
CRIME_RUNOVER_PED,
CRIME_RUNOVER_COP,
CRIME_SHOOT_HELI,
CRIME_PED_BURNED,
CRIME_COP_BURNED,
CRIME_VEHICLE_BURNED,
CRIME_DESTROYED_CESSNA,
};
enum eCopType
{
COP_STREET = 0,
COP_FBI = 1,
COP_SWAT = 2,
COP_ARMY = 3,
};
class CCrime
{
public:
eCrimeType m_eCrimeType;
CEntity *m_pVictim;
int32 m_nCrimeTime;
CVector m_vecCrimePos;
int8 m_bReported;
int8 m_bMultiplier;
int8 pad_20[2];
};
class CCopPed : public CPed
{
public:
int16 m_wRoadblockNode;
int8 field_1342;
int8 field_1343;
float m_fDistanceToTarget;
int8 m_bIsInPursuit;
int8 m_bIsDisabledCop;
int8 field_1350;
int8 field_1351;
int8 m_bZoneDisabledButClose;
int8 m_bZoneDisabled;
int8 field_1354;
int8 field_1355;
int32 field_1356;
eCopType m_nCopType;
int8 field_1364;
int8 field_1365;
int8 field_1366;
int8 field_1367;
~CCopPed();
void dtor(void) { this->CCopPed::~CCopPed(); }
void ClearPursuit(void);
};
static_assert(sizeof(CCopPed) == 0x558, "CCopPed: error");

11
src/peds/DummyPed.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "Dummy.h"
// actually unused
class CDummyPed : CDummy
{
int32 pedType;
int32 unknown;
};
static_assert(sizeof(CDummyPed) == 0x70, "CDummyPed: error");

View File

@ -0,0 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "EmergencyPed.h"
STARTPATCHES
InjectHook(0x4C2EF0, &CEmergencyPed::dtor, PATCH_JUMP);
ENDPATCHES

13
src/peds/EmergencyPed.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include "Ped.h"
class CEmergencyPed : public CPed
{
public:
// 0x53C
uint8 stuff[24];
void dtor(void) { this->CEmergencyPed::~CEmergencyPed(); }
};
static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error");

2950
src/peds/Ped.cpp Normal file

File diff suppressed because it is too large Load Diff

579
src/peds/Ped.h Normal file
View File

@ -0,0 +1,579 @@
#pragma once
#include "Physical.h"
#include "Weapon.h"
#include "PedStats.h"
#include "PedType.h"
#include "PedIK.h"
#include "AnimManager.h"
#include "AnimBlendClumpData.h"
#include "AnimBlendAssociation.h"
#include "WeaponInfo.h"
#include "Fire.h"
struct CPathNode;
enum eWaitState : uint32 {
WAITSTATE_FALSE,
WAITSTATE_TRAFFIC_LIGHTS,
WAITSTATE_CROSS_ROAD,
WAITSTATE_CROSS_ROAD_LOOK,
WAITSTATE_LOOK_PED,
WAITSTATE_LOOK_SHOP,
WAITSTATE_LOOK_ACCIDENT,
WAITSTATE_FACEOFF_GANG,
WAITSTATE_DOUBLEBACK,
WAITSTATE_HITWALL,
WAITSTATE_TURN180,
WAITSTATE_SURPRISE,
WAITSTATE_STUCK,
WAITSTATE_LOOK_ABOUT,
WAITSTATE_PLAYANIM_DUCK,
WAITSTATE_PLAYANIM_COWER,
WAITSTATE_PLAYANIM_TAXI,
WAITSTATE_PLAYANIM_HANDSUP,
WAITSTATE_PLAYANIM_HANDSCOWER,
WAITSTATE_PLAYANIM_CHAT,
WAITSTATE_FINISH_FLEE
};
enum eObjective : uint32 {
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 eVehEnter : uint16 {
VEHICLE_ENTER_FRONT_RIGHT = 11,
VEHICLE_ENTER_REAR_RIGHT = 12,
VEHICLE_ENTER_FRONT_LEFT = 15,
VEHICLE_ENTER_REAR_LEFT = 16,
};
enum {
RANDOM_CHAR = 1,
MISSION_CHAR,
};
enum PedLineUpPhase {
LINE_UP_TO_CAR_START,
LINE_UP_TO_CAR_END,
LINE_UP_TO_CAR_2
};
enum PedOnGroundState {
NO_PED,
PED_BELOW_PLAYER,
PED_ON_THE_FLOOR,
PED_DEAD_ON_THE_FLOOR
};
enum PedState
{
PED_NONE,
PED_IDLE,
PED_LOOK_ENTITY,
PED_LOOK_HEADING,
PED_WANDER_RANGE,
PED_WANDER_PATH,
PED_SEEK_POS,
PED_SEEK_ENTITY,
PED_FLEE_POS,
PED_FLEE_ENTITY,
PED_PURSUE,
PED_FOLLOW_PATH,
PED_SNIPER_MODE,
PED_ROCKET_ODE,
PED_DUMMY,
PED_PAUSE,
PED_ATTACK,
PED_FIGHT,
PED_FACE_PHONE,
PED_MAKE_CALL,
PED_CHAT,
PED_MUG,
PED_AIM_GUN,
PED_AI_CONTROL,
PED_SEEK_CAR,
PED_SEEK_IN_BOAT,
PED_FOLLOW_ROUTE,
PED_CPR,
PED_SOLICIT,
PED_BUY_ICECREAM,
PED_INVESTIGATE,
PED_STEP_AWAY,
PED_ON_FIRE,
PED_UNKNOWN, // HANG_OUT in Fire_Head's idb
PED_STATES_NO_AI,
PED_JUMP,
PED_FALL,
PED_GETUP,
PED_STAGGER,
PED_DIVE_AWAY,
PED_STATES_NO_ST,
PED_ENTER_TRAIN,
PED_EXIT_TRAIN,
PED_ARREST_PLAYER,
PED_DRIVING,
PED_PASSENGER,
PED_TAXI_PASSENGER,
PED_OPEN_DOOR,
PED_DIE,
PED_DEAD,
PED_CARJACK,
PED_DRAG_FROM_CAR,
PED_ENTER_CAR,
PED_STEAL_CAR,
PED_EXIT_CAR,
PED_HANDS_UP,
PED_ARRESTED,
};
enum eMoveState {
PEDMOVE_NONE,
PEDMOVE_STILL,
PEDMOVE_WALK,
PEDMOVE_RUN,
PEDMOVE_SPRINT,
};
class CVehicle;
class CPed : public CPhysical
{
public:
// 0x128
CStoredCollPoly m_collPoly;
float m_fCollisionSpeed;
// cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R*
uint8 bIsStanding : 1;
uint8 m_ped_flagA2 : 1;
uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
uint8 bIsPointingGunAt : 1;
uint8 bIsLooking : 1;
uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA
uint8 bIsRestoringLook : 1;
uint8 bIsAimingGun : 1;
uint8 bIsRestoringGun : 1;
uint8 bCanPointGunAtTarget : 1;
uint8 bIsTalking : 1;
uint8 bIsInTheAir : 1;
uint8 bIsLanding : 1;
uint8 m_ped_flagB20 : 1;
uint8 m_ped_flagB40 : 1;
uint8 m_ped_flagB80 : 1;
uint8 m_ped_flagC1 : 1;
uint8 bRespondsToThreats : 1;
uint8 m_ped_flagC4 : 1; // false when in bus, bRenderPedInCar?
uint8 m_ped_flagC8 : 1;
uint8 m_ped_flagC10 : 1;
uint8 m_ped_flagC20 : 1; // just left some body part?
uint8 m_ped_flagC40 : 1;
uint8 m_ped_flagC80 : 1;
uint8 m_ped_flagD1 : 1;
uint8 m_ped_flagD2 : 1;
uint8 m_ped_flagD4 : 1;
uint8 m_ped_flagD8 : 1;
uint8 m_ped_flagD10 : 1;
uint8 m_ped_flagD20 : 1;
uint8 m_ped_flagD40 : 1; // reset when objective changes
uint8 m_ped_flagD80 : 1;
uint8 m_ped_flagE1 : 1;
uint8 m_ped_flagE2 : 1;
uint8 bNotAllowedToDuck : 1;
uint8 bCrouchWhenShooting : 1;
uint8 bIsDucking : 1; // set if you don't want ped to attack
uint8 m_ped_flagE20 : 1;
uint8 bDoBloodyFootprints : 1;
uint8 m_ped_flagE80 : 1;
uint8 m_ped_flagF1 : 1;
uint8 m_ped_flagF2 : 1;
uint8 m_ped_flagF4 : 1;
uint8 m_ped_flagF8 : 1;
uint8 m_ped_flagF10 : 1;
uint8 m_ped_flagF20 : 1;
uint8 m_ped_flagF40 : 1;
uint8 m_ped_flagF80 : 1;
uint8 m_ped_flagG1 : 1;
uint8 m_ped_flagG2 : 1;
uint8 m_ped_flagG4 : 1;
uint8 m_ped_flagG8 : 1;
uint8 m_ped_flagG10 : 1;
uint8 m_ped_flagG20 : 1;
uint8 m_ped_flagG40 : 1;
uint8 m_ped_flagG80 : 1;
uint8 m_ped_flagH1 : 1;
uint8 m_ped_flagH2 : 1;
uint8 m_ped_flagH4 : 1;
uint8 m_ped_flagH8 : 1;
uint8 m_ped_flagH10 : 1;
uint8 m_ped_flagH20 : 1;
uint8 m_ped_flagH40 : 1;
uint8 m_ped_flagH80 : 1;
uint8 m_ped_flagI1 : 1;
uint8 m_ped_flagI2 : 1;
uint8 m_ped_flagI4 : 1;
uint8 bRecordedForReplay : 1;
uint8 m_ped_flagI10 : 1;
uint8 m_ped_flagI20 : 1;
uint8 m_ped_flagI40 : 1;
uint8 m_ped_flagI80 : 1;
uint8 stuff10[3];
uint8 CharCreatedBy;
uint8 field_161;
uint8 pad_162[2];
eObjective m_objective;
eObjective m_prevObjective;
CPed *m_pedInObjective;
CVehicle *m_carInObjective;
uint32 field_174;
uint32 field_178;
uint32 field_17C;
CPed *m_leader;
uint32 m_pedFormation;
uint32 m_fearFlags;
CEntity *m_threatEntity;
CVector2D m_eventOrThread;
uint32 m_eventType;
CEntity* m_pEventEntity;
float m_fAngleToEvent;
AnimBlendFrameData *m_pFrames[PED_NODE_MAX];
AssocGroupId m_animGroup;
CAnimBlendAssociation *m_pVehicleAnim;
CVector2D m_vecAnimMoveDelta;
CVector m_vecOffsetSeek;
CPedIK m_pedIK;
float m_actionX;
float m_actionY;
uint32 m_nPedStateTimer;
PedState m_nPedState;
PedState m_nLastPedState;
eMoveState m_nMoveState;
int32 m_nStoredActionState;
int32 m_nPrevActionState;
eWaitState m_nWaitState;
uint32 m_nWaitTimer;
void *m_pPathNodesStates[8];
CVector2D m_stPathNodeStates[10];
uint16 m_nPathNodes;
uint8 m_nCurPathNode;
int8 m_nPathState;
private:
int8 _pad2B5[3];
public:
CPathNode *m_pNextPathNode;
CPathNode *m_pLastPathNode;
float m_fHealth;
float m_fArmour;
int16 m_routeLastPoint;
uint16 m_routePoints;
int16 m_routePos;
int16 m_routeType;
int16 m_routeCurDir;
uint16 field_2D2;
CVector2D m_moved;
float m_fRotationCur;
float m_fRotationDest;
float m_headingRate;
eVehEnter m_vehEnterType;
uint16 m_walkAroundType;
CEntity *m_pCurrentPhysSurface;
CVector m_vecOffsetFromPhysSurface;
CEntity *m_pCurSurface;
CVector m_vecSeekVehicle;
CEntity *m_pSeekTarget;
CVehicle *m_pMyVehicle;
bool bInVehicle;
uint8 pad_315[3];
uint32 field_318;
uint8 field_31C;
uint8 field_31D;
int16 m_phoneId;
uint32 m_lookingForPhone;
uint32 m_phoneTalkTimer;
void *m_lastAccident;
int32 m_nPedType;
CPedStats *m_pedStats;
float m_fleeFromPosX;
float m_fleeFromPosY;
CEntity *m_fleeFrom;
uint32 m_fleeTimer;
uint32 field_344;
uint32 m_lastThreatTimer;
CEntity *m_pCollidingEntity;
uint8 m_stateUnused;
uint8 pad_351[3];
uint32 m_timerUnused;
CEntity *m_targetUnused;
CWeapon m_weapons[WEAPONTYPE_TOTAL_INVENTORY_WEAPONS];
eWeaponType m_storedWeapon;
uint8 m_currentWeapon; // eWeaponType
uint8 m_maxWeaponTypeAllowed; // eWeaponType
uint8 m_wepSkills;
uint8 m_wepAccuracy;
CEntity *m_pPointGunAt;
CVector m_vecHitLastPos;
uint32 m_lastHitState;
uint8 m_fightFlags1;
uint8 m_fightFlags2;
uint8 pad_4B2[2];
CFire* m_pFire;
CEntity *m_pLookTarget;
float m_fLookDirection;
int32 m_wepModelID;
uint32 m_leaveCarTimer;
uint32 m_getUpTimer;
uint32 m_lookTimer;
uint32 m_standardTimer;
uint32 m_attackTimer;
uint32 m_lastHitTime;
uint32 m_hitRecoverTimer;
uint32 m_objectiveTimer;
uint32 m_duckTimer;
uint32 field_4E8;
int32 m_bloodyFootprintCount;
uint8 stuff9[2];
int8 m_bodyPartBleeding; // PedNode
uint8 m_field_4F3;
CPed *m_nearPeds[10];
uint16 m_numNearPeds;
int8 m_lastWepDam;
uint8 pad_51F;
uint8 field_520;
uint8 pad_521[3];
uint32 m_talkTimer;
uint16 m_talkTypeLast;
uint16 m_talkType;
CVector m_vecSeekPosEx;
float m_seekExAngle;
static void *operator new(size_t);
static void *operator new(size_t, int);
static void operator delete(void*, size_t);
static void operator delete(void*, int);
CPed(uint32 pedType);
virtual ~CPed(void);
virtual void SetModelIndex(uint32 mi);
virtual void ProcessControl(void);
virtual void Teleport(CVector);
virtual void PreRender(void);
virtual void Render(void);
virtual bool SetupLighting(void);
virtual void RemoveLighting(bool);
virtual void FlagToDestroyWhenNextProcessed(void);
virtual int32 ProcessEntityCollision(CEntity*, CColPoint*);
virtual void SetMoveAnim(void);
CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); }
void dtor(void) { this->CPed::~CPed(); }
void AddWeaponModel(int id);
void AimGun(void);
void KillPedWithCar(CVehicle *veh, float impulse);
void Say(uint16 audio);
void SetLookFlag(CEntity *target, bool unknown);
void SetLookFlag(float direction, bool unknown);
void SetLookTimer(int time);
void SetDie(AnimationId anim, float arg1, float arg2);
void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer);
void RemoveBodyPart(PedNode nodeId, int8 unknown);
void SpawnFlyingComponent(int, int8 unknown);
bool OurPedCanSeeThisOne(CEntity *target);
void Avoid(void);
void Attack(void);
void ClearAimFlag(void);
void ClearLookFlag(void);
void RestorePreviousState(void);
void ClearAttack(void);
bool IsPedHeadAbovePos(float zOffset);
void RemoveWeaponModel(int modelId);
void SetCurrentWeapon(uint32 weaponType);
void Duck(void);
void ClearDuck(void);
void ClearPointGunAt(void);
void BeingDraggedFromCar(void);
void RestartNonPartialAnims(void);
void LineUpPedWithCar(PedLineUpPhase phase);
void SetPedPositionInCar(void);
void PlayFootSteps(void);
void QuitEnteringCar(void);
void BuildPedLists(void);
uint32 GiveWeapon(eWeaponType weaponType, uint32 ammo);
void CalculateNewOrientation(void);
float WorkOutHeadingForMovingFirstPerson(float);
void CalculateNewVelocity(void);
bool CanPedJumpThis(int32);
bool CanSeeEntity(CEntity*, float);
void RestorePreviousObjective(void);
void SetIdle(void);
void SetObjective(eObjective, void*);
void SetObjective(eObjective);
void SetObjective(eObjective, int16, int16);
void ClearChat(void);
void InformMyGangOfAttack(CEntity*);
void SetFollowRoute(int16, int16);
void ReactToAttack(CEntity*);
void SetDuck(uint32);
void RegisterThreatWithGangPeds(CEntity*);
bool TurnBody(void);
void Chat(void);
void MakeChangesForNewWeapon(int8);
// 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);
static void PedStaggerCB(CAnimBlendAssociation *assoc, void *arg);
static void PedEvadeCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg);
static void SetInCarCB(CAnimBlendAssociation *assoc, void *arg);
static void PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg);
static void PedSetDraggedOutCarCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg);
static void PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg);
static void PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishedAttackCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg);
static void PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg);
static void FinishJumpCB(CAnimBlendAssociation *assoc, void *arg);
static void PedLandCB(CAnimBlendAssociation *assoc, void *arg);
static void RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg);
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);
bool IsGangMember(void);
bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; }
CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }
CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; }
RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; }
static uint8 GetVehEnterExitFlag(eVehEnter vehEnter) {
switch (vehEnter) {
case VEHICLE_ENTER_FRONT_RIGHT:
return 4;
case VEHICLE_ENTER_REAR_RIGHT:
return 8;
case VEHICLE_ENTER_FRONT_LEFT:
return 1;
case VEHICLE_ENTER_REAR_LEFT:
return 2;
default:
return 0;
}
}
PedState GetPedState(void) { return m_nPedState; }
void SetPedState(PedState state) { m_nPedState = state; }
// 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;
static CVector &offsetToOpenRegularCarDoor;
static CVector &offsetToOpenLowCarDoor;
static CVector &offsetToOpenVanDoor;
static bool &bNastyLimbsCheat;
static bool &bPedCheat2;
static bool &bPedCheat3;
};
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error");
static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error");
static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error");
static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error");
static_assert(offsetof(CPed, m_pCollidingEntity) == 0x34C, "CPed: error");
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_pedInObjective) == 0x16C, "CPed: error");
static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error");
static_assert(sizeof(CPed) == 0x53C, "CPed: error");

109
src/peds/PedIK.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "common.h"
#include "patcher.h"
#include "PedIK.h"
#include "Ped.h"
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)
{
m_ped = ped;
m_flags = 0;
m_headOrient.phi = 0.0f;
m_headOrient.theta = 0.0f;
m_torsoOrient.phi = 0.0f;
m_torsoOrient.theta = 0.0f;
m_upperArmOrient.phi = 0.0f;
m_upperArmOrient.theta = 0.0f;
m_lowerArmOrient.phi = 0.0f;
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)
{
RwFrame *f;
RwMatrix *mat;
f = m_ped->GetNodeFrame(node);
mat = RwFrameGetMatrix(f);
*pos = mat->pos;
for (f = RwFrameGetParent(f); f; f = RwFrameGetParent(f))
RwV3dTransformPoints(pos, pos, 1, RwFrameGetMatrix(f));
}
RwMatrix*
CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination)
{
RwFrame *i;
*destination = *RwFrameGetMatrix(source);
for (i = RwFrameGetParent(source); i; i = RwFrameGetParent(i))
RwMatrixTransform(destination, RwFrameGetMatrix(i), rwCOMBINEPOSTCONCAT);
return destination;
}
STARTPATCHES
InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP);
InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP);
InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP);
ENDPATCHES

40
src/peds/PedIK.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include "common.h"
#include "PedModelInfo.h"
#include "AnimBlendClumpData.h"
struct LimbOrientation
{
float phi;
float theta;
};
class CPed;
class CPedIK
{
public:
// TODO
enum {
FLAG_1 = 1,
FLAG_2 = 2, // related to looking somewhere
FLAG_4 = 4, // aims with arm
};
CPed *m_ped;
LimbOrientation m_headOrient;
LimbOrientation m_torsoOrient;
LimbOrientation m_upperArmOrient;
LimbOrientation m_lowerArmOrient;
int32 m_flags;
CPedIK(CPed *ped);
bool PointGunInDirection(float phi, float theta);
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");

40
src/peds/PedPlacement.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "common.h"
#include "patcher.h"
#include "PedPlacement.h"
#include "World.h"
void
CPedPlacement::FindZCoorForPed(CVector* pos)
{
float zForPed;
float startZ = pos->z - 100.0f;
float foundColZ = -100.0f;
float foundColZ2 = -100.0f;
CColPoint foundCol;
CEntity* foundEnt;
CVector vec(
pos->x,
pos->y,
pos->z + 1.0f
);
if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil))
foundColZ = foundCol.point.z;
// Adjust coords and do a second test
vec.x += 0.1f;
vec.y += 0.1f;
if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, nil))
foundColZ2 = foundCol.point.z;
zForPed = max(foundColZ, foundColZ2);
if (zForPed > -99.0f)
pos->z = 1.04f + zForPed;
}
STARTPATCHES
InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP);
ENDPATCHES

8
src/peds/PedPlacement.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
class CVector;
class CPedPlacement {
public:
static void FindZCoorForPed(CVector* pos);
};

125
src/peds/PedStats.cpp Normal file
View File

@ -0,0 +1,125 @@
#include "common.h"
#include "patcher.h"
#include "FileMgr.h"
#include "PedStats.h"
CPedStats *(&CPedStats::ms_apPedStats)[NUM_PEDSTATS] = *(CPedStats *(*)[NUM_PEDSTATS]) *(uintptr*)0x9404D4;
void
CPedStats::Initialise(void)
{
int i;
debug("Initialising CPedStats...\n");
for(i = 0; i < NUM_PEDSTATS; i++){
ms_apPedStats[i] = new CPedStats;
ms_apPedStats[i]->m_type = PEDSTAT_PLAYER;
ms_apPedStats[i]->m_name[8] = 'R'; // WHAT?
ms_apPedStats[i]->m_fleeDistance = 20.0f;
ms_apPedStats[i]->m_headingChangeRate = 15.0f;
ms_apPedStats[i]->m_fear = 50;
ms_apPedStats[i]->m_temper = 50;
ms_apPedStats[i]->m_lawfulness = 50;
ms_apPedStats[i]->m_sexiness = 50;
ms_apPedStats[i]->m_attackStrength = 1.0f;
ms_apPedStats[i]->m_defendWeakness = 1.0f;
ms_apPedStats[i]->m_flags = 0;
}
debug("Loading pedstats data...\n");
CPedStats::LoadPedStats();
debug("CPedStats ready\n");
}
void
CPedStats::Shutdown(void)
{
int i;
debug("Shutting down CPedStats...\n");
for(i = 0; i < NUM_PEDSTATS; i++)
delete ms_apPedStats[i];
debug("CPedStats shut down\n");
}
void
CPedStats::LoadPedStats(void)
{
char *buf;
char line[256];
char name[32];
int bp, buflen;
int lp, linelen;
int type;
float fleeDist, headingChangeRate, attackStrength, defendWeakness;
int fear, temper, lawfullness, sexiness, flags;
type = 0;
buf = new char[16 * 1024];
CFileMgr::SetDir("DATA");
buflen = CFileMgr::LoadFile("PEDSTATS.DAT", (uint8*)buf, 16 * 1024, "r");
CFileMgr::SetDir("");
for(bp = 0; bp < buflen; ){
// read file line by line
for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){
if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t')
line[linelen++] = ' ';
else
line[linelen++] = buf[bp];
line[linelen] = '\0';
}
bp++;
// skip white space
for(lp = 0; line[lp] <= ' '; lp++);
if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines
line[lp] == '#')
continue;
sscanf(&line[lp], "%s %f %f %d %d %d %d %f %f %d",
name,
&fleeDist,
&headingChangeRate,
&fear,
&temper,
&lawfullness,
&sexiness,
&attackStrength,
&defendWeakness,
&flags);
ms_apPedStats[type]->m_type = (ePedStats)type;
strncpy(ms_apPedStats[type]->m_name, name, 24); // FIX: game uses strcpy
ms_apPedStats[type]->m_fleeDistance = fleeDist;
ms_apPedStats[type]->m_headingChangeRate = headingChangeRate;
ms_apPedStats[type]->m_fear = fear;
ms_apPedStats[type]->m_temper = temper;
ms_apPedStats[type]->m_lawfulness = lawfullness;
ms_apPedStats[type]->m_sexiness = sexiness;
ms_apPedStats[type]->m_attackStrength = attackStrength;
ms_apPedStats[type]->m_defendWeakness = defendWeakness;
ms_apPedStats[type]->m_flags = flags;
type++;
}
delete[] buf;
}
int32
CPedStats::GetPedStatType(char *name)
{
int type;
for(type = 0; type < NUM_PEDSTATS; type++)
if(strcmp(ms_apPedStats[type]->m_name, name) == 0)
return type;
return NUM_PEDSTATS;
}
STARTPATCHES
InjectHook(0x4EF460, &CPedStats::Initialise, PATCH_JUMP);
InjectHook(0x4EF540, &CPedStats::Shutdown, PATCH_JUMP);
InjectHook(0x4EF580, &CPedStats::LoadPedStats, PATCH_JUMP);
InjectHook(0x4EF780, &CPedStats::GetPedStatType, PATCH_JUMP);
ENDPATCHES

79
src/peds/PedStats.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
enum ePedStats
{
PEDSTAT_PLAYER,
PEDSTAT_COP,
PEDSTAT_MEDIC,
PEDSTAT_FIREMAN,
PEDSTAT_GANG1,
PEDSTAT_GANG2,
PEDSTAT_GANG3,
PEDSTAT_GANG4,
PEDSTAT_GANG5,
PEDSTAT_GANG6,
PEDSTAT_GANG7,
PEDSTAT_STREET_GUY,
PEDSTAT_SUIT_GUY,
PEDSTAT_SENSIBLE_GUY,
PEDSTAT_GEEK_GUY,
PEDSTAT_OLD_GUY,
PEDSTAT_TOUGH_GUY,
PEDSTAT_STREET_GIRL,
PEDSTAT_SUIT_GIRL,
PEDSTAT_SENSIBLE_GIRL,
PEDSTAT_GEEK_GIRL,
PEDSTAT_OLD_GIRL,
PEDSTAT_TOUGH_GIRL,
PEDSTAT_TRAMP_MALE,
PEDSTAT_TRAMP_FEMALE,
PEDSTAT_TOURIST,
PEDSTAT_PROSTITUTE,
PEDSTAT_CRIMINAL,
PEDSTAT_BUSKER,
PEDSTAT_TAXIDRIVER,
PEDSTAT_PSYCHO,
PEDSTAT_STEWARD,
PEDSTAT_SPORTSFAN,
PEDSTAT_SHOPPER,
PEDSTAT_OLDSHOPPER,
NUM_PEDSTATS
};
// flags
enum
{
STAT_PUNCH_ONLY = 1,
STAT_CAN_KNEE_HEAD = 2,
STAT_CAN_KICK = 4,
STAT_CAN_ROUNDHOUSE = 8,
STAT_NO_DIVE = 0x10,
STAT_ONE_HIT_KNOCKDOWN = 0x20,
STAT_SHOPPING_BAGS = 0x40,
STAT_GUN_PANIC = 0x80
};
class CPedStats
{
public:
ePedStats m_type;
char m_name[24];
float m_fleeDistance;
float m_headingChangeRate;
int8 m_fear;
int8 m_temper;
int8 m_lawfulness;
int8 m_sexiness;
float m_attackStrength;
float m_defendWeakness;
int16 m_flags;
static CPedStats* (&ms_apPedStats)[NUM_PEDSTATS];
static void Initialise(void);
static void Shutdown(void);
static void LoadPedStats(void);
static int32 GetPedStatType(char *name);
};
static_assert(sizeof(CPedStats) == 0x34, "CPedStats: error");

243
src/peds/PedType.cpp Normal file
View File

@ -0,0 +1,243 @@
#include "common.h"
#include "patcher.h"
#include "FileMgr.h"
#include "PedType.h"
CPedType *(&CPedType::ms_apPedType)[NUM_PEDTYPES] = *(CPedType *(*)[NUM_PEDTYPES]) *(uintptr*)0x941594;
void
CPedType::Initialise(void)
{
int i;
debug("Initialising CPedType...\n");
for(i = 0; i < NUM_PEDTYPES; i++){
ms_apPedType[i] = new CPedType;
ms_apPedType[i]->m_flag = PED_FLAG_PLAYER1;
ms_apPedType[i]->unknown1 = 0.0f;
ms_apPedType[i]->unknown2 = 0.0f;
// unknown3 not initialized
ms_apPedType[i]->unknown4 = 0.0f;
ms_apPedType[i]->unknown5 = 0.0f;
ms_apPedType[i]->m_threats = 0;
ms_apPedType[i]->m_avoid = 0;
}
debug("Loading ped data...\n");
LoadPedData();
debug("CPedType ready\n");
}
void
CPedType::Shutdown(void)
{
int i;
debug("Shutting down CPedType...\n");
for(i = 0; i < NUM_PEDTYPES; i++)
delete ms_apPedType[i];
debug("CPedType shut down\n");
}
void
CPedType::LoadPedData(void)
{
char *buf;
char line[256];
char word[32];
int bp, buflen;
int lp, linelen;
int type;
uint32 flags;
float f1, f2, f3, f4, f5;
type = NUM_PEDTYPES;
buf = new char[16 * 1024];
CFileMgr::SetDir("DATA");
buflen = CFileMgr::LoadFile("PED.DAT", (uint8*)buf, 16 * 1024, "r");
CFileMgr::SetDir("");
for(bp = 0; bp < buflen; ){
// read file line by line
for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){
if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t')
line[linelen++] = ' ';
else
line[linelen++] = buf[bp];
line[linelen] = '\0';
}
bp++;
// skip white space
for(lp = 0; line[lp] <= ' '; lp++);
if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines
line[lp] == '#')
continue;
// FIX: game just uses line here
sscanf(&line[lp], "%s", word);
if(strncmp(word, "Threat", 7) == 0){
flags = 0;
lp += 7;
while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){
flags |= FindPedFlag(word);
// skip word
while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0')
lp++;
// skip white space
while(line[lp] == ' ')
lp++;
}
ms_apPedType[type]->m_threats = flags;
}else if(strncmp(word, "Avoid", 6) == 0){
flags = 0;
lp += 6;
while(sscanf(&line[lp], "%s", word) == 1 && lp <= linelen){
flags |= FindPedFlag(word);
// skip word
while(line[lp] != ' ' && line[lp] != '\n' && line[lp] != '\0')
lp++;
// skip white space
while(line[lp] == ' ')
lp++;
}
ms_apPedType[type]->m_avoid = flags;
}else{
sscanf(line, "%s %f %f %f %f %f", word, &f1, &f2, &f3, &f4, &f5);
type = FindPedType(word);
ms_apPedType[type]->m_flag = FindPedFlag(word);
// unknown values
ms_apPedType[type]->unknown1 = f1 / 50.0f;
ms_apPedType[type]->unknown2 = f2 / 50.0f;
ms_apPedType[type]->unknown3 = f3 / 50.0f;
ms_apPedType[type]->unknown4 = f4;
ms_apPedType[type]->unknown5 = f5;
}
}
delete[] buf;
}
int32
CPedType::FindPedType(char *type)
{
if(strcmp(type, "PLAYER1") == 0) return PEDTYPE_PLAYER1;
if(strcmp(type, "PLAYER2") == 0) return PEDTYPE_PLAYER2;
if(strcmp(type, "PLAYER3") == 0) return PEDTYPE_PLAYER3;
if(strcmp(type, "PLAYER4") == 0) return PEDTYPE_PLAYER4;
if(strcmp(type, "CIVMALE") == 0) return PEDTYPE_CIVMALE;
if(strcmp(type, "CIVFEMALE") == 0) return PEDTYPE_CIVFEMALE;
if(strcmp(type, "COP") == 0) return PEDTYPE_COP;
if(strcmp(type, "GANG1") == 0) return PEDTYPE_GANG1;
if(strcmp(type, "GANG2") == 0) return PEDTYPE_GANG2;
if(strcmp(type, "GANG3") == 0) return PEDTYPE_GANG3;
if(strcmp(type, "GANG4") == 0) return PEDTYPE_GANG4;
if(strcmp(type, "GANG5") == 0) return PEDTYPE_GANG5;
if(strcmp(type, "GANG6") == 0) return PEDTYPE_GANG6;
if(strcmp(type, "GANG7") == 0) return PEDTYPE_GANG7;
if(strcmp(type, "GANG8") == 0) return PEDTYPE_GANG8;
if(strcmp(type, "GANG9") == 0) return PEDTYPE_GANG9;
if(strcmp(type, "EMERGENCY") == 0) return PEDTYPE_EMERGENCY;
if(strcmp(type, "FIREMAN") == 0) return PEDTYPE_FIREMAN;
if(strcmp(type, "CRIMINAL") == 0) return PEDTYPE_CRIMINAL;
if(strcmp(type, "SPECIAL") == 0) return PEDTYPE_SPECIAL;
if(strcmp(type, "PROSTITUTE") == 0) return PEDTYPE_PROSTITUTE;
Error("Unknown ped type, Pedtype.cpp");
return NUM_PEDTYPES;
}
uint32
CPedType::FindPedFlag(char *type)
{
if(strcmp(type, "PLAYER1") == 0) return PED_FLAG_PLAYER1;
if(strcmp(type, "PLAYER2") == 0) return PED_FLAG_PLAYER2;
if(strcmp(type, "PLAYER3") == 0) return PED_FLAG_PLAYER3;
if(strcmp(type, "PLAYER4") == 0) return PED_FLAG_PLAYER4;
if(strcmp(type, "CIVMALE") == 0) return PED_FLAG_CIVMALE;
if(strcmp(type, "CIVFEMALE") == 0) return PED_FLAG_CIVFEMALE;
if(strcmp(type, "COP") == 0) return PED_FLAG_COP;
if(strcmp(type, "GANG1") == 0) return PED_FLAG_GANG1;
if(strcmp(type, "GANG2") == 0) return PED_FLAG_GANG2;
if(strcmp(type, "GANG3") == 0) return PED_FLAG_GANG3;
if(strcmp(type, "GANG4") == 0) return PED_FLAG_GANG4;
if(strcmp(type, "GANG5") == 0) return PED_FLAG_GANG5;
if(strcmp(type, "GANG6") == 0) return PED_FLAG_GANG6;
if(strcmp(type, "GANG7") == 0) return PED_FLAG_GANG7;
if(strcmp(type, "GANG8") == 0) return PED_FLAG_GANG8;
if(strcmp(type, "GANG9") == 0) return PED_FLAG_GANG9;
if(strcmp(type, "EMERGENCY") == 0) return PED_FLAG_EMERGENCY;
if(strcmp(type, "FIREMAN") == 0) return PED_FLAG_FIREMAN;
if(strcmp(type, "CRIMINAL") == 0) return PED_FLAG_CRIMINAL;
if(strcmp(type, "SPECIAL") == 0) return PED_FLAG_SPECIAL;
if(strcmp(type, "GUN") == 0) return PED_FLAG_GUN;
if(strcmp(type, "COP_CAR") == 0) return PED_FLAG_COP_CAR;
if(strcmp(type, "FAST_CAR") == 0) return PED_FLAG_FAST_CAR;
if(strcmp(type, "EXPLOSION") == 0) return PED_FLAG_EXPLOSION;
if(strcmp(type, "PROSTITUTE") == 0) return PED_FLAG_PROSTITUTE;
if(strcmp(type, "DEADPEDS") == 0) return PED_FLAG_DEADPEDS;
return 0;
}
void
CPedType::Save(uint8 *buffer, uint32 *length)
{
int i;
*length = 8 + NUM_PEDTYPES*32;
buffer[0] = 'P';
buffer[1] = 'T';
buffer[2] = 'P';
buffer[3] = '\0';
*(uint32*)(buffer+4) = *length - 8;
buffer += 8;
for(i = 0; i < NUM_PEDTYPES; i++){
*(uint32*)(buffer) = ms_apPedType[i]->m_flag;
*(float*)(buffer+4) = ms_apPedType[i]->unknown1;
*(float*)(buffer+8) = ms_apPedType[i]->unknown2;
*(float*)(buffer+12) = ms_apPedType[i]->unknown3;
*(float*)(buffer+16) = ms_apPedType[i]->unknown4;
*(float*)(buffer+20) = ms_apPedType[i]->unknown5;
*(uint32*)(buffer+24) = ms_apPedType[i]->m_threats;
*(uint32*)(buffer+28) = ms_apPedType[i]->m_avoid;
buffer += 32;
}
}
void
CPedType::Load(uint8 *buffer, uint32 length)
{
int i;
assert(length == 8 + NUM_PEDTYPES*32);
assert(buffer[0] == 'P');
assert(buffer[1] == 'T');
assert(buffer[2] == 'P');
assert(buffer[3] == '\0');
assert(*(uint32*)(buffer+4) == length - 8);
buffer += 8;
for(i = 0; i < NUM_PEDTYPES; i++){
ms_apPedType[i]->m_flag = *(uint32*)(buffer);
ms_apPedType[i]->unknown1 = *(float*)(buffer+4);
ms_apPedType[i]->unknown2 = *(float*)(buffer+8);
ms_apPedType[i]->unknown3 = *(float*)(buffer+12);
ms_apPedType[i]->unknown4 = *(float*)(buffer+16);
ms_apPedType[i]->unknown5 = *(float*)(buffer+20);
ms_apPedType[i]->m_threats = *(uint32*)(buffer+24);
ms_apPedType[i]->m_avoid = *(uint32*)(buffer+28);
buffer += 32;
}
}
STARTPATCHES
InjectHook(0x4EE7E0, &CPedType::Initialise, PATCH_JUMP);
InjectHook(0x4EE890, &CPedType::Shutdown, PATCH_JUMP);
InjectHook(0x4EEC10, &CPedType::FindPedType, PATCH_JUMP);
InjectHook(0x4EEF40, &CPedType::FindPedFlag, PATCH_JUMP);
InjectHook(0x4EF320, &CPedType::Save, PATCH_JUMP);
InjectHook(0x4EF3D0, &CPedType::Load, PATCH_JUMP);
ENDPATCHES

90
src/peds/PedType.h Normal file
View File

@ -0,0 +1,90 @@
#pragma once
// Index into the PedType array
enum
{
PEDTYPE_PLAYER1,
PEDTYPE_PLAYER2,
PEDTYPE_PLAYER3,
PEDTYPE_PLAYER4,
PEDTYPE_CIVMALE,
PEDTYPE_CIVFEMALE,
PEDTYPE_COP,
PEDTYPE_GANG1,
PEDTYPE_GANG2,
PEDTYPE_GANG3,
PEDTYPE_GANG4,
PEDTYPE_GANG5,
PEDTYPE_GANG6,
PEDTYPE_GANG7,
PEDTYPE_GANG8,
PEDTYPE_GANG9,
PEDTYPE_EMERGENCY,
PEDTYPE_FIREMAN,
PEDTYPE_CRIMINAL,
PEDTYPE_UNUSED1,
PEDTYPE_PROSTITUTE,
PEDTYPE_SPECIAL,
PEDTYPE_UNUSED2,
NUM_PEDTYPES
};
enum
{
PED_FLAG_PLAYER1 = 1 << 0,
PED_FLAG_PLAYER2 = 1 << 1,
PED_FLAG_PLAYER3 = 1 << 2,
PED_FLAG_PLAYER4 = 1 << 3,
PED_FLAG_CIVMALE = 1 << 4,
PED_FLAG_CIVFEMALE = 1 << 5,
PED_FLAG_COP = 1 << 6,
PED_FLAG_GANG1 = 1 << 7,
PED_FLAG_GANG2 = 1 << 8,
PED_FLAG_GANG3 = 1 << 9,
PED_FLAG_GANG4 = 1 << 10,
PED_FLAG_GANG5 = 1 << 11,
PED_FLAG_GANG6 = 1 << 12,
PED_FLAG_GANG7 = 1 << 13,
PED_FLAG_GANG8 = 1 << 14,
PED_FLAG_GANG9 = 1 << 15,
PED_FLAG_EMERGENCY = 1 << 16,
PED_FLAG_PROSTITUTE = 1 << 17,
PED_FLAG_CRIMINAL = 1 << 18,
PED_FLAG_SPECIAL = 1 << 19,
PED_FLAG_GUN = 1 << 20,
PED_FLAG_COP_CAR = 1 << 21,
PED_FLAG_FAST_CAR = 1 << 22,
PED_FLAG_EXPLOSION = 1 << 23,
PED_FLAG_FIREMAN = 1 << 24,
PED_FLAG_DEADPEDS = 1 << 25,
};
class CPedType
{
uint32 m_flag;
float unknown1;
float unknown2;
float unknown3;
float unknown4;
float unknown5;
uint32 m_threats;
uint32 m_avoid;
static CPedType *(&ms_apPedType)[NUM_PEDTYPES];
public:
static void Initialise(void);
static void Shutdown(void);
static void LoadPedData(void);
static int32 FindPedType(char *type);
static uint32 FindPedFlag(char *type);
static void Save(uint8 *buffer, uint32 *length);
static void Load(uint8 *buffer, uint32 length);
static uint32 GetFlag(int type) { return ms_apPedType[type]->m_flag; }
static uint32 GetAvoid(int type) { return ms_apPedType[type]->m_avoid; }
static uint32 GetThreats(int type) { return ms_apPedType[type]->m_threats; }
};
static_assert(sizeof(CPedType) == 0x20, "CPedType: error");

28
src/peds/PlayerPed.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "common.h"
#include "patcher.h"
#include "PlayerPed.h"
#include "Camera.h"
#include "WeaponEffects.h"
CPlayerPed::~CPlayerPed()
{
delete m_pWanted;
}
WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); }
void CPlayerPed::ClearWeaponTarget()
{
if (!m_nPedType) {
m_pPointGunAt = 0;
TheCamera.ClearPlayerWeaponMode();
CWeaponEffects::ClearCrosshair();
}
ClearPointGunAt();
}
STARTPATCHES
InjectHook(0x4EFB30, &CPlayerPed::dtor, PATCH_JUMP);
InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
ENDPATCHES

49
src/peds/PlayerPed.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include "Ped.h"
#include "Wanted.h"
class CPlayerPed : public CPed
{
public:
CWanted *m_pWanted;
CCopPed *m_pArrestingCop;
float m_fMoveSpeed;
float m_fCurrentStamina;
float m_fMaxStamina;
float m_fStaminaProgress;
bool m_bWeaponSlot;
bool m_bSpeedTimerFlag;
bool m_bShouldEvade;
int8 field_1367;
int32 m_nSpeedTimer;
int32 m_nShotDelay;
float field_1376;
int8 field_1380; // set if can't attack, why?
int8 field_1381;
int8 field_1382;
int8 field_1383;
CEntity *m_pEvadingFrom;
int32 m_nTargettableObjects[4];
bool m_bAdrenalineActive;
bool m_bHasLockOnTarget;
int8 field_1406;
int8 field_1407;
bool m_bAdrenalineTime;
bool m_bCanBeDamaged;
int8 field_1413;
int8 field_1414;
int8 field_1415;
CVector field_1416[6];
int32 field_1488[6];
float m_fWalkAngle;
float m_fFPSMoveHeading;
~CPlayerPed();
void dtor(void) { this->CPlayerPed::~CPlayerPed(); }
void ReApplyMoveAnims(void);
void ClearWeaponTarget();
};
static_assert(sizeof(CPlayerPed) == 0x5F0, "CPlayerPed: error");