Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Nikolay Korolev 2019-08-10 10:44:39 +03:00
commit 6a7fdadeaa
13 changed files with 1599 additions and 144 deletions

File diff suppressed because it is too large Load diff

View file

@ -2,24 +2,35 @@
#include "Treadable.h" #include "Treadable.h"
enum
{
PATH_CAR = 0,
PATH_PED = 1,
};
struct CPathNode struct CPathNode
{ {
CVector pos; CVector pos;
CPathNode *prev; //? CPathNode *prev;
CPathNode *next; CPathNode *next;
int16 unknown; int16 distance; // in path search
int16 objectIndex; int16 objectIndex;
int16 firstLink; int16 firstLink;
uint8 numLinks; uint8 numLinks;
uint8 flags;
uint8 unkBits : 2;
uint8 bDeadEnd : 1;
uint8 bDisabled : 1;
uint8 bBetweenLevels : 1;
uint8 group; uint8 group;
/* VC: /* For reference VC:
int16 unk1; int16 prevIndex;
int16 nextIndex; int16 nextIndex;
int16 x; int16 x;
int16 y; int16 y;
int16 z; int16 z;
int16 unknown; int16 distance;
int16 firstLink; int16 firstLink;
int8 width; int8 width;
int8 group; int8 group;
@ -40,6 +51,15 @@ struct CPathNode
*/ */
}; };
union CConnectionFlags
{
uint8 flags;
struct {
uint8 bCrossesRoad : 1;
uint8 bTrafficLight : 1;
};
};
struct CCarPathLink struct CCarPathLink
{ {
float posX; float posX;
@ -50,10 +70,9 @@ struct CCarPathLink
int8 numLeftLanes; int8 numLeftLanes;
int8 numRightLanes; int8 numRightLanes;
int8 trafficLightType; int8 trafficLightType;
int8 field15;
// probably only padding uint8 bBridgeLights : 1;
int8 field16; // more?
int8 field17;
}; };
struct CPathInfoForObject struct CPathInfoForObject
@ -80,8 +99,6 @@ struct CTempNode
int8 numLeftLanes; int8 numLeftLanes;
int8 numRightLanes; int8 numRightLanes;
int8 linkState; int8 linkState;
// probably padding
int8 field1B;
}; };
struct CTempDetachedNode // unused struct CTempDetachedNode // unused
@ -102,41 +119,65 @@ public:
uint8 m_distances[20400]; uint8 m_distances[20400];
int16 m_carPathConnections[20400]; int16 m_carPathConnections[20400];
*/ */
CPathNode m_pathNodes[4930]; CPathNode m_pathNodes[NUM_PATHNODES];
CCarPathLink m_carPathLinks[2076]; CCarPathLink m_carPathLinks[NUM_CARPATHLINKS];
CTreadable *m_mapObjects[1250]; CTreadable *m_mapObjects[NUM_MAPOBJECTS];
uint8 m_objectFlags[1250]; uint8 m_objectFlags[NUM_MAPOBJECTS];
int16 m_connections[10260]; int16 m_connections[NUM_PATHCONNECTIONS];
int16 m_distances[10260]; int16 m_distances[NUM_PATHCONNECTIONS];
uint8 m_connectionFlags[10260]; CConnectionFlags m_connectionFlags[NUM_PATHCONNECTIONS];
int16 m_carPathConnections[10260]; int16 m_carPathConnections[NUM_PATHCONNECTIONS];
int32 m_numPathNodes; int32 m_numPathNodes;
int32 m_numCarPathNodes; int32 m_numCarPathNodes;
int32 m_numPedPathNodes; int32 m_numPedPathNodes;
int16 m_numMapObjects; int16 m_numMapObjects;
int16 m_numConnections; int16 m_numConnections;
int32 m_numCarPathLinks; int32 m_numCarPathLinks;
int32 h; int32 unk;
uint8 m_numGroups[2]; uint8 m_numGroups[2];
CPathNode m_aExtraPaths[872]; CPathNode m_searchNodes[512];
void Init(void);
void AllocatePathFindInfoMem(int16 numPathGroups);
void RegisterMapObject(CTreadable *mapObject);
void StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing);
void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight);
void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out);
bool LoadPathFindData(void);
void PreparePathData(void); void PreparePathData(void);
void CountFloodFillGroups(uint8 type); void CountFloodFillGroups(uint8 type);
void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo, void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo,
float unk, CTempDetachedNode *detachednodes, int unused); float unk, CTempDetachedNode *detachednodes, int unused);
void CalcNodeCoors(int16 x, int16 y, int16 z, int32 id, CVector *out);
void StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, bool crossing);
void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, int16 width, int8 numLeft, int8 numRight);
void RegisterMapObject(CTreadable *mapObject);
int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool disabled, bool betweenLevels);
CPathNode** FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*);
bool NewGenerateCarCreationCoors(float spawnX, float spawnY, float frontX, float frontY, float preferredDistance, float angleLimit /* angle limit between camera direction and vector to spawn */, bool invertAngleLimitTest, CVector* pSpawnPosition, int32* pNode1, int32* pNode2, float* pPositionBetweenNodes, bool ignoreSwitchedOff);
bool TestCoorsCloseness(CVector pos1, bool, CVector pos2);
bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); } bool IsPathObject(int id) { return id < PATHNODESIZE && (InfoForTileCars[id*12].type != 0 || InfoForTilePeds[id*12].type != 0); }
float CalcRoadDensity(float x, float y);
bool TestForPedTrafficLight(CPathNode *n1, CPathNode *n2);
bool TestCrossesRoad(CPathNode *n1, CPathNode *n2);
void AddNodeToList(CPathNode *node, int32 listId);
void RemoveNodeFromList(CPathNode *node);
void RemoveBadStartNode(CVector pos, CPathNode **nodes, int16 *n);
void SetLinksBridgeLights(float, float, float, float, bool); void SetLinksBridgeLights(float, float, float, float, bool);
void SwitchOffNodeAndNeighbours(int32 nodeId, bool disable);
void SwitchRoadsOffInArea(float x1, float x2, float y1, float y2, float z1, float z2, bool disable);
void SwitchPedRoadsOffInArea(float x1, float x2, float y1, float y2, float z1, float z2, bool disable);
void SwitchRoadsInAngledArea(float x1, float y1, float z1, float x2, float y2, float z2, float length, uint8 type, uint8 enable);
void MarkRoadsBetweenLevelsNodeAndNeighbours(int32 nodeId);
void MarkRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2);
void MarkPedRoadsBetweenLevelsInArea(float x1, float x2, float y1, float y2, float z1, float z2);
int32 FindNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled = false, bool ignoreBetweenLevels = false);
int32 FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, float dirX, float dirY);
float FindNodeOrientationForCarPlacement(int32 nodeId);
float FindNodeOrientationForCarPlacementFacingDestination(int32 nodeId, float x, float y, bool towards);
bool NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY, float spawnDist, float angleLimit, bool forward, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, bool ignoreDisabled = false);
bool GeneratePedCreationCoors(float x, float y, float minDist, float maxDist, float minDistOffScreen, float maxDistOffScreen, CVector *pPosition, int32 *pNode1, int32 *pNode2, float *pPositionBetweenNodes, CMatrix *camMatrix);
CTreadable *FindRoadObjectClosestToCoors(CVector coors, uint8 type);
void FindNextNodeWandering(uint8, CVector, CPathNode**, CPathNode**, uint8, uint8*);
void DoPathSearch(uint8 type, CVector start, int32 startNodeId, CVector target, CPathNode **nodes, int16 *numNodes, int16 maxNumNodes, CVehicle *vehicle, float *dist, float distLimit, int32 forcedTargetNode);
bool TestCoorsCloseness(CVector target, uint8 type, CVector start);
void Save(uint8 *buffer, uint32 *length);
void Load(uint8 *buffer, uint32 length);
}; };
static_assert(sizeof(CPathFind) == 0x4c8f4, "CPathFind: error"); static_assert(sizeof(CPathFind) == 0x49bf4, "CPathFind: error");
extern CPathFind &ThePaths; extern CPathFind &ThePaths;

View file

@ -1,5 +1,19 @@
#include "common.h" #include "common.h"
#include "patcher.h" #include "patcher.h"
#include "TrafficLights.h" #include "TrafficLights.h"
#include "Timer.h"
WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); } WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); }
uint8
CTrafficLights::LightForPeds(void)
{
uint32 period = CTimer::GetTimeInMilliseconds() & 0x3FFF; // Equals to % 16384
if (period >= 15384)
return PED_LIGHTS_WALK_BLINK;
else if (period >= 12000)
return PED_LIGHTS_WALK;
else
return PED_LIGHTS_DONT_WALK;
}

View file

@ -2,8 +2,15 @@
class CEntity; class CEntity;
enum {
PED_LIGHTS_WALK,
PED_LIGHTS_WALK_BLINK,
PED_LIGHTS_DONT_WALK,
};
class CTrafficLights class CTrafficLights
{ {
public: public:
static void DisplayActualLight(CEntity *ent); static void DisplayActualLight(CEntity *ent);
static uint8 LightForPeds(void);
}; };

View file

@ -74,6 +74,7 @@ public:
return result; return result;
} }
// Returns an angle such that x2/y2 looks at x1/y1 with its forward vector if rotated by that angle
static float GetRadianAngleBetweenPoints(float x1, float y1, float x2, float y2) static float GetRadianAngleBetweenPoints(float x1, float y1, float x2, float y2)
{ {
float x = x2 - x1; float x = x2 - x1;

View file

@ -33,6 +33,12 @@ enum Config {
NUMTEMPOBJECTS = 30, NUMTEMPOBJECTS = 30,
// Path data
NUM_PATHNODES = 4930,
NUM_CARPATHLINKS = 2076,
NUM_MAPOBJECTS = 1250,
NUM_PATHCONNECTIONS = 10260,
// Link list lengths // Link list lengths
// TODO: alpha list // TODO: alpha list
NUMCOLCACHELINKS = 200, NUMCOLCACHELINKS = 200,

View file

@ -11,6 +11,7 @@
#include "ParticleObject.h" #include "ParticleObject.h"
#include "Particle.h" #include "Particle.h"
#include "SurfaceTable.h" #include "SurfaceTable.h"
#include "PathFind.h"
#include "CarCtrl.h" #include "CarCtrl.h"
#include "DMAudio.h" #include "DMAudio.h"
#include "Automobile.h" #include "Automobile.h"
@ -56,8 +57,8 @@ CPhysical::CPhysical(void)
m_phy_flagA80 = false; m_phy_flagA80 = false;
m_fDistanceTravelled = 0.0f; m_fDistanceTravelled = 0.0f;
m_pedTreadable = nil; m_treadable[PATH_CAR] = nil;
m_carTreadable = nil; m_treadable[PATH_PED] = nil;
m_phy_flagA10 = false; m_phy_flagA10 = false;
m_phy_flagA20 = false; m_phy_flagA20 = false;
@ -267,16 +268,16 @@ CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
{ {
if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){
CTreadable *t = (CTreadable*)ent; CTreadable *t = (CTreadable*)ent;
if(t->m_nodeIndicesPeds[0] >= 0 || if(t->m_nodeIndices[PATH_PED][0] >= 0 ||
t->m_nodeIndicesPeds[1] >= 0 || t->m_nodeIndices[PATH_PED][1] >= 0 ||
t->m_nodeIndicesPeds[2] >= 0 || t->m_nodeIndices[PATH_PED][2] >= 0 ||
t->m_nodeIndicesPeds[3] >= 0) t->m_nodeIndices[PATH_PED][3] >= 0)
m_pedTreadable = t; m_treadable[PATH_PED] = t;
if(t->m_nodeIndicesCars[0] >= 0 || if(t->m_nodeIndices[PATH_CAR][0] >= 0 ||
t->m_nodeIndicesCars[1] >= 0 || t->m_nodeIndices[PATH_CAR][1] >= 0 ||
t->m_nodeIndicesCars[2] >= 0 || t->m_nodeIndices[PATH_CAR][2] >= 0 ||
t->m_nodeIndicesCars[3] >= 0) t->m_nodeIndices[PATH_CAR][3] >= 0)
m_carTreadable = t; m_treadable[PATH_CAR] = t;
} }
} }

View file

@ -19,8 +19,7 @@ public:
int32 m_audioEntityId; int32 m_audioEntityId;
float unk1; float unk1;
CTreadable *m_carTreadable; CTreadable *m_treadable[2]; // car and ped
CTreadable *m_pedTreadable;
uint32 m_nLastTimeCollided; uint32 m_nLastTimeCollided;
CVector m_vecMoveSpeed; // velocity CVector m_vecMoveSpeed; // velocity
CVector m_vecTurnSpeed; // angular velocity CVector m_vecTurnSpeed; // angular velocity

View file

@ -8,8 +8,7 @@ public:
static void *operator new(size_t); static void *operator new(size_t);
static void operator delete(void*, size_t); static void operator delete(void*, size_t);
int16 m_nodeIndicesCars[12]; int16 m_nodeIndices[2][12]; // first car, then ped
int16 m_nodeIndicesPeds[12];
bool GetIsATreadable(void) { return true; } bool GetIsATreadable(void) { return true; }
}; };

View file

@ -18,7 +18,7 @@ public:
x *= invsqrt; x *= invsqrt;
y *= invsqrt; y *= invsqrt;
}else }else
x = 0.0f; x = 1.0f;
} }
const CVector2D &operator+=(CVector2D const &right) { const CVector2D &operator+=(CVector2D const &right) {
x += right.x; x += right.x;
@ -52,6 +52,9 @@ public:
CVector2D operator*(float t) const { CVector2D operator*(float t) const {
return CVector2D(x*t, y*t); return CVector2D(x*t, y*t);
} }
CVector2D operator/(float t) const {
return CVector2D(x/t, y/t);
}
}; };
inline float inline float
@ -65,3 +68,26 @@ CrossProduct2D(const CVector2D &v1, const CVector2D &v2)
{ {
return v1.x*v2.y - v1.y*v2.x; return v1.x*v2.y - v1.y*v2.x;
} }
inline float
Distance2D(const CVector2D &v, float x, float y)
{
return Sqrt((v.x-x)*(v.x-x) + (v.y-y)*(v.y-y));
}
inline float
DistanceSqr2D(const CVector2D &v, float x, float y)
{
return (v.x-x)*(v.x-x) + (v.y-y)*(v.y-y);
}
inline void
NormalizeXY(float &x, float &y)
{
float l = Sqrt(x*x + y*y);
if(l != 0.0f){
x /= l;
y /= l;
}else
x = 1.0f;
}

View file

@ -32,6 +32,7 @@
#include "TempColModels.h" #include "TempColModels.h"
#include "Pickups.h" #include "Pickups.h"
#include "Train.h" #include "Train.h"
#include "TrafficLights.h"
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); } WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
@ -51,6 +52,7 @@ WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); }
WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); } WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); }
WRAPPER void CPed::SetRadioStation(void) { EAXJMP(0x4D7BC0); } WRAPPER void CPed::SetRadioStation(void) { EAXJMP(0x4D7BC0); }
WRAPPER void CPed::MakeTyresMuddySectorList(CPtrList&) { EAXJMP(0x53CFD0); } WRAPPER void CPed::MakeTyresMuddySectorList(CPtrList&) { EAXJMP(0x53CFD0); }
WRAPPER void CPed::ProcessObjective(void) { EAXJMP(0x4D94E0); }
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
@ -1890,7 +1892,7 @@ CPed::PlayFootSteps(void)
CVector2D top(forward * 0.26f); CVector2D top(forward * 0.26f);
CVector2D right(GetRight() * 0.14f); CVector2D right(GetRight() * 0.14f);
CShadows::AddPermanentShadow(1, gpBloodPoolTex, &footPos, CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos,
top.x, top.y, top.x, top.y,
right.x, right.y, right.x, right.y,
255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f);
@ -3854,7 +3856,7 @@ CPed::SetWanderPath(int8 pathStateDest)
if (pathStateDest == 0) if (pathStateDest == 0)
pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); pathStateDest = CGeneral::GetRandomNumberInRange(1, 7);
ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
m_nPathState, &nextPathState); m_nPathState, &nextPathState);
// Circular loop until we find a node for current m_nPathState // Circular loop until we find a node for current m_nPathState
@ -3867,7 +3869,7 @@ CPed::SetWanderPath(int8 pathStateDest)
SetIdle(); SetIdle();
return false; return false;
} }
ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode, ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
m_nPathState, &nextPathState); m_nPathState, &nextPathState);
} }
@ -6283,13 +6285,513 @@ CPed::Fight(void)
} }
} }
// Some helper function which doesn't exist in og game.
inline void
SelectClosestNodeForSeek(CPed *ped, CPathNode *node, CVector2D closeDist, CVector2D farDist, CPathNode *closeNode, CPathNode *closeNode2, int runCount = 3)
{
for (int i = 0; i < node->numLinks; i++) {
CPathNode *testNode = &ThePaths.m_pathNodes[ThePaths.m_connections[i + node->firstLink]];
if (testNode && testNode != closeNode && testNode != closeNode2) {
CVector2D posDiff(ped->m_vecSeekVehicle - testNode->pos);
float dist = posDiff.MagnitudeSqr();
if (farDist.MagnitudeSqr() > dist) {
if (closeDist.MagnitudeSqr() <= dist) {
ped->m_pLastPathNode = closeNode;
closeDist = posDiff;
} else {
ped->m_pLastPathNode = (closeNode2 ? closeNode2 : testNode);
farDist = posDiff;
}
}
if (--runCount > 0)
SelectClosestNodeForSeek(ped, testNode, closeDist, farDist, closeNode, (closeNode2 ? closeNode2 : testNode), runCount);
}
}
}
bool
CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords)
{
if (m_pLastPathNode || !bIsFleeing)
return false;
CVector ourPos = GetPosition();
int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f, false, false);
CVector seekObjPos = m_vecSeekVehicle;
seekObjPos.z += 1.0f;
if (CWorld::GetIsLineOfSightClear(ourPos, seekObjPos, true, false, false, true, false, false, false))
return false;
m_pLastPathNode = nil;
CVector2D seekObjDist (m_vecSeekVehicle - ourPos);
CPathNode *closestNode = &ThePaths.m_pathNodes[closestNodeId];
CVector2D closeDist(m_vecSeekVehicle - closestNode->pos);
SelectClosestNodeForSeek(this, closestNode, closeDist, seekObjDist, closestNode, nil);
// Above function decided that going to the next node is more logical than seeking the object.
if (m_pLastPathNode) {
CVector pathToNextNode = m_pLastPathNode->pos - ourPos;
if (pathToNextNode.MagnitudeSqr2D() < seekObjDist.MagnitudeSqr()) {
*bestCoords = m_pLastPathNode->pos;
return true;
}
m_pLastPathNode = nil;
}
return false;
}
void
CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed *ped = (CPed*)arg;
if (ped->bIsPedDieAnimPlaying)
ped->bIsPedDieAnimPlaying = false;
}
void
CPed::FinishFightMoveCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed *ped = (CPed*)arg;
if (tFightMoves[ped->m_lastFightMove].animId == animAssoc->animId) {
ped->m_fightUnk2 = -2;
animAssoc->blendDelta = -1000.0f;
}
}
void
CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed *ped = (CPed*)arg;
if (animAssoc) {
animAssoc->blendDelta = -4.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
if (ped->m_nPedState == PED_JUMP)
ped->RestorePreviousState();
ped->bIsLanding = false;
}
void
CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed* ped = (CPed*)arg;
ped->m_ped_flagG4 = true;
ped->bIsLanding = false;
animAssoc->blendDelta = -1000.0f;
}
void
CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed *ped = (CPed*)arg;
if (ped->m_nPedState != PED_JUMP)
return;
CVector forward(0.15f * ped->GetForward() + ped->GetPosition());
forward.z += CModelInfo::GetModelInfo(ped->m_modelIndex)->GetColModel()->spheres->center.z + 0.25f;
CEntity *foundEnt = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false);
if (!foundEnt) {
// Forward of forward
forward += 0.15f * ped->GetForward();
forward.z += 0.15f;
foundEnt = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false);
}
if (foundEnt) {
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 8.0f);
handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE;
handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped);
ped->bIsLanding = true;
return;
}
float velocityFromAnim = 0.1f;
CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_SPRINT);
if (sprintAssoc) {
velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f;
} else {
CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_RUN);
if (runAssoc) {
velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f;
}
}
if (ped->IsPlayer())
ped->ApplyMoveForce(0.0f, 0.0f, 8.5f);
else
ped->ApplyMoveForce(0.0f, 0.0f, 4.5f);
if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D()) {
if (TheCamera.Cams[0].Using3rdPersonMouseCam()) {
float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur);
ped->m_vecMoveSpeed.x = -velocityFromAnim * sin(fpsAngle);
ped->m_vecMoveSpeed.y = velocityFromAnim * cos(fpsAngle);
} else {
ped->m_vecMoveSpeed.x = -velocityFromAnim * sin(ped->m_fRotationCur);
ped->m_vecMoveSpeed.y = velocityFromAnim * cos(ped->m_fRotationCur);
}
}
ped->bIsStanding = false;
ped->bIsInTheAir = true;
animAssoc->blendDelta = -1000.0f;
CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE);
if (ped->bDoBloodyFootprints) {
CVector bloodPos(0.0f, 0.0f, 0.0f);
for (RwFrame *i = ped->GetNodeFrame(PED_FOOTL); i; i = RwFrameGetParent(i))
RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(i));
bloodPos.z -= 0.1f;
bloodPos += 0.2f * ped->GetForward();
CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos,
0.26f * ped->GetForward().x,
0.26f * ped->GetForward().y,
0.14f * ped->GetRight().x,
0.14f * ped->GetRight().y,
255, 255, 0, 0, 4.0f, 3000, 1.0f);
bloodPos = CVector(0.0f, 0.0f, 0.0f);
for (RwFrame* j = ped->GetNodeFrame(PED_FOOTR); j; j = RwFrameGetParent(j))
RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(j));
bloodPos.z -= 0.1f;
bloodPos += 0.2f * ped->GetForward();
CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos,
0.26f * ped->GetForward().x,
0.26f * ped->GetForward().y,
0.14f * ped->GetRight().x,
0.14f * ped->GetRight().y,
255, 255, 0, 0, 4.0f, 3000, 1.0f);
if (ped->m_bloodyFootprintCount <= 40) {
ped->m_bloodyFootprintCount = 0;
ped->bDoBloodyFootprints = false;
} else {
ped->m_bloodyFootprintCount -= 40;
}
}
}
void
CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg)
{
CPed* ped = (CPed*)arg;
ped->m_nWaitTimer = 0;
ped->RestoreHeadingRate();
ped->Wait();
}
void
CPed::Wait(void)
{
AnimationId mustHaveAnim = NUM_ANIMS;
CAnimBlendAssociation *animAssoc;
CPed *pedWeLook;
if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) {
m_nWaitState = WAITSTATE_FALSE;
RestoreHeadingRate();
return;
}
switch (m_nWaitState) {
case WAITSTATE_TRAFFIC_LIGHTS:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) {
m_nWaitState = WAITSTATE_FALSE;
SetMoveState(PEDMOVE_WALK);
}
}
break;
case WAITSTATE_CROSS_ROAD:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer)
m_nWaitState = WAITSTATE_FALSE;
else
SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil);
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
if (animAssoc) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
}
break;
case WAITSTATE_LOOK_PED:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
m_nWaitState = WAITSTATE_FALSE;
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
if (animAssoc) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
}
break;
case WAITSTATE_DOUBLEBACK:
if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) {
uint32 timeLeft = m_nWaitTimer - CTimer::GetTimeInMilliseconds();
if (timeLeft < 2500 && timeLeft > 2000) {
m_nWaitTimer -= 500;
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
}
} else {
m_nWaitState = WAITSTATE_FALSE;
SetMoveState(PEDMOVE_WALK);
}
break;
case WAITSTATE_HITWALL:
if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) {
if (m_lastThreatTimer > CTimer::GetTimeInMilliseconds()) {
m_lastThreatTimer = CTimer::GetTimeInMilliseconds() + 2500;
}
} else {
m_nWaitState = WAITSTATE_FALSE;
}
break;
case WAITSTATE_TURN180:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
m_nWaitState = WAITSTATE_FALSE;
SetMoveState(PEDMOVE_WALK);
m_fRotationCur = m_fRotationCur + PI;
if (m_nPedState == PED_INVESTIGATE)
ClearInvestigateEvent();
}
if (m_lastThreatTimer > CTimer::GetTimeInMilliseconds()) {
m_lastThreatTimer = CTimer::GetTimeInMilliseconds() + 2500;
}
break;
case WAITSTATE_SURPRISE:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HIT_WALL)) {
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
animAssoc->SetFinishCallback(FinishedWaitCB, this);
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
} else {
m_nWaitState = WAITSTATE_FALSE;
}
}
break;
case WAITSTATE_STUCK:
if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer)
break;
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
if (!animAssoc)
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_TURN_180);
if (!animAssoc)
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
if (!animAssoc)
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
if (animAssoc) {
if (animAssoc->IsPartial()) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
} else {
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
}
if (animAssoc->animId == ANIM_TURN_180) {
m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur);
m_nWaitState = WAITSTATE_FALSE;
SetMoveState(PEDMOVE_WALK);
m_nStoredMoveState = PEDMOVE_NONE;
m_panicCounter = 0;
return;
}
}
AnimationId animToRun;
switch (CGeneral::GetRandomNumber() & 3) {
case 0:
animToRun = ANIM_ROAD_CROSS;
break;
case 1:
animToRun = ANIM_IDLE_TIRED;
break;
case 2:
animToRun = ANIM_XPRESS_SCRATCH;
break;
case 3:
animToRun = ANIM_TURN_180;
break;
default:
break;
}
animAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, animToRun, 4.0f);
if (animToRun == ANIM_TURN_180)
animAssoc->SetFinishCallback(FinishedWaitCB, this);
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000);
break;
case WAITSTATE_LOOK_ABOUT:
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
m_nWaitState = WAITSTATE_FALSE;
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
if (animAssoc) {
animAssoc->blendDelta = -8.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
}
break;
case WAITSTATE_PLAYANIM_HANDSUP:
mustHaveAnim = ANIM_HANDSUP;
case WAITSTATE_PLAYANIM_HANDSCOWER:
if (mustHaveAnim == NUM_ANIMS)
mustHaveAnim = ANIM_HANDSCOWER;
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
pedWeLook = (CPed*) m_pLookTarget;
if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt)
&& m_nPedState != PED_FLEE_ENTITY
&& m_nPedState != PED_ATTACK
&& CTimer::GetTimeInMilliseconds() <= m_nWaitTimer
&& animAssoc) {
TurnBody();
} else {
m_nWaitState = WAITSTATE_FALSE;
m_nWaitTimer = 0;
if (m_pLookTarget && m_pLookTarget->IsPed()) {
if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_ATTACK) {
if (m_pedStats->m_fear <= 100 - pedWeLook->m_pedStats->m_temper) {
if (GetWeapon()->IsTypeMelee()) {
SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget);
if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) {
bIsFleeing = true;
m_pLastPathNode = nil;
}
if (m_nMoveState != PEDMOVE_RUN)
SetMoveState(PEDMOVE_WALK);
if (m_nPedType != PEDTYPE_COP) {
ProcessObjective();
SetMoveState(PEDMOVE_WALK);
}
} else {
SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_pLookTarget);
SetObjectiveTimer(20000);
}
} else {
SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget);
if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS)
{
bIsFleeing = true;
m_pLastPathNode = nil;
}
SetMoveState(PEDMOVE_RUN);
Say(SOUND_PED_FLEE_RUN);
}
}
}
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
if (animAssoc) {
animAssoc->blendDelta = -4.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
}
break;
case WAITSTATE_PLAYANIM_COWER:
mustHaveAnim = ANIM_HANDSCOWER;
case WAITSTATE_PLAYANIM_DUCK:
if (mustHaveAnim == NUM_ANIMS)
mustHaveAnim = ANIM_DUCK_DOWN;
case WAITSTATE_PLAYANIM_TAXI:
if (mustHaveAnim == NUM_ANIMS)
mustHaveAnim = ANIM_IDLE_TAXI;
case WAITSTATE_PLAYANIM_CHAT:
if (mustHaveAnim == NUM_ANIMS)
mustHaveAnim = ANIM_IDLE_CHAT;
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
if (animAssoc) {
animAssoc->blendDelta = -4.0f;
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
m_nWaitState = WAITSTATE_FALSE;
}
break;
case WAITSTATE_FINISH_FLEE:
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
if (animAssoc) {
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
int timer = 2000;
m_nWaitState = WAITSTATE_FALSE;
SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer);
}
} else {
m_nWaitState = WAITSTATE_FALSE;
}
break;
default:
break;
}
if(!m_nWaitState)
RestoreHeadingRate();
}
WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); } WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); } WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); } WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
WRAPPER void CPed::FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D3950); }
WRAPPER void CPed::FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6520); }
WRAPPER void CPed::FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7490); }
WRAPPER void CPed::FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A80); }
WRAPPER void CPed::PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEC80); } WRAPPER void CPed::PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEC80); }
WRAPPER void CPed::PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE500); } WRAPPER void CPed::PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE500); }
WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEAF0); } WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEAF0); }
@ -6302,9 +6804,7 @@ WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dra
WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); } WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); }
WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); } WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); }
WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); } WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); }
WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); }
WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); } WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); }
WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); }
WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); } WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); }
WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); } WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); }
@ -6444,4 +6944,12 @@ STARTPATCHES
InjectHook(0x4E33D0, &CPed::LineUpPedWithTrain, PATCH_JUMP); InjectHook(0x4E33D0, &CPed::LineUpPedWithTrain, PATCH_JUMP);
InjectHook(0x4E18D0, &CPed::ExitCar, PATCH_JUMP); InjectHook(0x4E18D0, &CPed::ExitCar, PATCH_JUMP);
InjectHook(0x4E7EE0, &CPed::Fight, PATCH_JUMP); InjectHook(0x4E7EE0, &CPed::Fight, PATCH_JUMP);
InjectHook(0x4D3950, &CPed::FinishDieAnimCB, PATCH_JUMP);
InjectHook(0x4E9830, &CPed::FinishFightMoveCB, PATCH_JUMP);
InjectHook(0x4D7A80, &CPed::FinishHitHeadCB, PATCH_JUMP);
InjectHook(0x4D7A50, &CPed::FinishJumpCB, PATCH_JUMP);
InjectHook(0x4D7490, &CPed::FinishLaunchCB, PATCH_JUMP);
InjectHook(0x4D6520, &CPed::FinishedWaitCB, PATCH_JUMP);
InjectHook(0x4D5D80, &CPed::Wait, PATCH_JUMP);
InjectHook(0x4E3A90, &CPed::FindBestCoordsFromNodes, PATCH_JUMP);
ENDPATCHES ENDPATCHES

View file

@ -303,7 +303,7 @@ public:
uint8 m_ped_flagG1 : 1; uint8 m_ped_flagG1 : 1;
uint8 m_ped_flagG2 : 1; uint8 m_ped_flagG2 : 1;
uint8 m_ped_flagG4 : 1; uint8 m_ped_flagG4 : 1;
uint8 m_ped_flagG8 : 1; uint8 m_ped_flagG8 : 1; // ped starts to go somewhere when set
uint8 m_ped_flagG10 : 1; uint8 m_ped_flagG10 : 1;
uint8 m_ped_flagG20 : 1; uint8 m_ped_flagG20 : 1;
uint8 m_ped_flagG40 : 1; uint8 m_ped_flagG40 : 1;
@ -408,7 +408,7 @@ public:
CEntity *m_fleeFrom; CEntity *m_fleeFrom;
uint32 m_fleeTimer; uint32 m_fleeTimer;
uint32 field_344; uint32 field_344;
uint32 m_lastThreatTimer; uint32 m_lastThreatTimer; // I don't think so
CEntity *m_pCollidingEntity; CEntity *m_pCollidingEntity;
uint8 m_stateUnused; uint8 m_stateUnused;
uint8 pad_351[3]; uint8 pad_351[3];
@ -597,6 +597,9 @@ public:
void LineUpPedWithTrain(void); void LineUpPedWithTrain(void);
void ExitCar(void); void ExitCar(void);
void Fight(void); void Fight(void);
bool FindBestCoordsFromNodes(CVector unused, CVector* a6);
void Wait(void);
void ProcessObjective(void);
// Static methods // Static methods
static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset);

View file

@ -200,9 +200,9 @@ CRenderer::RenderRoads(void)
if(gbShowCarRoadGroups || gbShowPedRoadGroups){ if(gbShowCarRoadGroups || gbShowPedRoadGroups){
int ind = 0; int ind = 0;
if(gbShowCarRoadGroups) if(gbShowCarRoadGroups)
ind += ThePaths.m_pathNodes[t->m_nodeIndicesCars[0]].group; ind += ThePaths.m_pathNodes[t->m_nodeIndices[PATH_CAR][0]].group;
if(gbShowPedRoadGroups) if(gbShowPedRoadGroups)
ind += ThePaths.m_pathNodes[t->m_nodeIndicesPeds[0]].group; ind += ThePaths.m_pathNodes[t->m_nodeIndices[PATH_PED][0]].group;
SetAmbientColoursToIndicateRoadGroup(ind); SetAmbientColoursToIndicateRoadGroup(ind);
} }
#endif #endif