summaryrefslogtreecommitdiffstats
path: root/src/control/PathFind.h
blob: acf9929ade613dd79a46ac9d9b80f3243b38b960 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#pragma once

#include "Treadable.h"

class CVehicle;
class CPtrList;

#define LANE_WIDTH 5.0f
#define WIDTH_TO_PED_NODE_WIDTH (31.f/(500.f * 8.f))

enum
{
	NodeTypeExtern = 1,
	NodeTypeIntern = 2,
};

enum
{
	PATH_CAR = 0,
	PATH_PED = 1,
};

enum
{
	SWITCH_OFF = 0,
	SWITCH_ON = 1,
};

enum 
{
	ROUTE_ADD_BLOCKADE = 0,
	ROUTE_NO_BLOCKADE = 1
};

struct CPedPathNode
{
	bool bBlockade;
	uint8 nodeIdX;
	uint8 nodeIdY;
	int16 id;
	CPedPathNode* prev;
	CPedPathNode* next;
};

VALIDATE_SIZE(CPedPathNode, 0x10);

class CPedPath {
public:
	static bool CalcPedRoute(int8 pathType, CVector position, CVector destination, CVector *pointPoses, int16 *pointsFound, int16 maxPoints);
	static void AddNodeToPathList(CPedPathNode *pNodeToAdd, int16 id, CPedPathNode *pNodeList);
	static void RemoveNodeFromList(CPedPathNode *pNode);
	static void AddNodeToList(CPedPathNode *pNode, int16 index, CPedPathNode *pList);
	static void AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *pPosition);
	static void AddBlockadeSectorList(CPtrList& list, CPedPathNode(*pathNodes)[40], CVector *pPosition);
	static void AddBuildingBlockade(CEntity*, CPedPathNode(*)[40], CVector*);
	static void AddBuildingBlockadeSectorList(CPtrList&, CPedPathNode(*)[40], CVector*);
};

struct CPathNode
{
	int16 prevIndex;
	int16 nextIndex;
	int16 x;
	int16 y;
	int16 z;
	int16 distance;		// in path search
	int16 firstLink;
	uint8 width;
	int8 group;

	uint8 numLinks : 4;
	uint8 bDeadEnd : 1;
	uint8 bDisabled : 1;
	uint8 bBetweenLevels : 1;
	uint8 bUseInRoadBlock : 1;

	uint8 bWaterPath : 1;
	uint8 bOnlySmallBoats : 1;
	uint8 bSelected : 1;
	uint8 speedLimit : 2;
	//uint8 flagB20 : 1;
	//uint8 flagB40 : 1;
	//uint8 flagB80 : 1;

	uint8 spawnRate : 4;
	uint8 flagsC : 4;

	CVector GetPosition(void) { return CVector(x/8.0f, y/8.0f, z/8.0f); }
	void SetPosition(const CVector &p) { x = p.x*8.0f; y = p.y*8.0f; z = p.z*8.0f; }
	float GetX(void) { return x/8.0f; }
	float GetY(void) { return y/8.0f; }
	float GetZ(void) { return z/8.0f; }
	bool HasDivider(void) { return width != 0; }
	float GetDividerWidth(void) { return width/(2*8.0f); }
	float GetPedNodeWidth(void) { return width*WIDTH_TO_PED_NODE_WIDTH; }
	CPathNode *GetPrev(void);
	CPathNode *GetNext(void);
	void SetPrev(CPathNode *node);
	void SetNext(CPathNode *node);
};

union CConnectionFlags
{
	uint8 flags;
	struct {
		uint8 bCrossesRoad : 1;
		uint8 bTrafficLight : 1;
	};
};

struct CCarPathLink
{
	int16 x;
	int16 y;
	int16 pathNodeIndex;
	int8 dirX;
	int8 dirY;
	int8 numLeftLanes : 3;
	int8 numRightLanes : 3;
	uint8 trafficLightDirection : 1;
	uint8 trafficLightType : 2;
	uint8 bBridgeLights : 1;	// at least in LCS...
	int8 width;

	CVector2D GetPosition(void) { return CVector2D(x/8.0f, y/8.0f); }
	CVector2D GetDirection(void) { return CVector2D(dirX/100.0f, dirY/100.0f); }
	float GetX(void) { return x/8.0f; }
	float GetY(void) { return y/8.0f; }
	float GetDirX(void) { return dirX/100.0f; }
	float GetDirY(void) { return dirY/100.0f; }
	float GetLaneOffset(void) { return width/(2*8.0f*LANE_WIDTH); }

	float OneWayLaneOffset()
	{
		if (numLeftLanes == 0)
			return 0.5f - 0.5f * numRightLanes;
		if (numRightLanes == 0)
			return 0.5f - 0.5f * numLeftLanes;
		return 0.5f + GetLaneOffset();
	}
};

// This is what we're reading from the files, only temporary
struct CPathInfoForObject
{
	float x;
	float y;
	float z;
	int8 type;
	int8 next;
	int8 numLeftLanes;
	int8 numRightLanes;
	int8 speedLimit;
	int8 width;

	uint8 crossing : 1;
	uint8 onlySmallBoats : 1;
	uint8 roadBlock : 1;
	uint8 disabled : 1;
	uint8 waterPath : 1;
	uint8 betweenLevels : 1;

	uint8 spawnRate : 4;

	void CheckIntegrity(void);
	void SwapConnectionsToBeRightWayRound(void);
};
extern CPathInfoForObject *InfoForTileCars;
extern CPathInfoForObject *InfoForTilePeds;

struct CTempNode
{
	CVector pos;
	int8 dirX;	// *100
	int8 dirY;
	int16 link1;
	int16 link2;
	int8 numLeftLanes;
	int8 numRightLanes;
	int8 width;
	bool isCross;
	int8 linkState;
};

struct CTempNodeExternal	// made up name
{
	CVector pos;
	int16 next;
	int8 numLeftLanes;
	int8 numRightLanes;
	int8 width;
	bool isCross;
};

// from mobile
template<typename T>
class CRoute
{
	T m_node[8];
};


class CPathFind
{
public:
	CPathNode m_pathNodes[NUM_PATHNODES];
	CCarPathLink m_carPathLinks[NUM_CARPATHLINKS];
	CTreadable *m_mapObjects[NUM_MAPOBJECTS];
	uint16 m_connections[NUM_PATHCONNECTIONS];	// and flags
	uint8 m_distances[NUM_PATHCONNECTIONS];
	int16 m_carPathConnections[NUM_PATHCONNECTIONS];

	int32 m_numPathNodes;
	int32 m_numCarPathNodes;
	int32 m_numPedPathNodes;
	int16 m_numMapObjects;
	int16 m_numConnections;
	int32 m_numCarPathLinks;
	int32 unk;
	uint8 m_numGroups[2];
	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, float width, bool crossing, uint8 spawnRate);
	void StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, int16 y, int16 z, float width, int8 numLeft, int8 numRight,
		bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate);
	void StoreDetachedNodeInfoPed(int32 node, int8 type, int32 next, float x, float y, float z, float width, bool crossing,
		bool disabled, bool betweenLevels, uint8 spawnRate);
	void StoreDetachedNodeInfoCar(int32 node, int8 type, int32 next, float x, float y, float z, float width, int8 numLeft, int8 numRight,
		bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate, bool unk);
	void CalcNodeCoors(float x, float y, float z, int32 id, CVector *out);
	bool LoadPathFindData(void);
	void PreparePathData(void);
	void CountFloodFillGroups(uint8 type);
	void PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoForObject *objectpathinfo,
		float maxdist, CPathInfoForObject *detachednodes, int32 numDetached);

	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 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 PedMarkRoadsBetweenLevelsInArea(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, bool ignoreSelected = false, bool bWaterPath = false);
	int32 FindNodeClosestToCoorsFavourDirection(CVector coors, uint8 type, float dirX, float dirY);
	void FindNodePairClosestToCoors(CVector coors, uint8 type, int* node1, int* node2, float* angle, float minDist, float maxDist, bool ignoreDisabled = false, bool ignoreBetweenLevels = false, bool bWaterPath = false);
	int32 FindNthNodeClosestToCoors(CVector coors, uint8 type, float distLimit, bool ignoreDisabled, bool ignoreBetweenLevels, int N, bool bWaterPath = false);
	CVector FindNodeCoorsForScript(int32 id);
	float FindNodeOrientationForCarPlacement(int32 nodeId);
	float FindNodeOrientationForCarPlacementFacingDestination(int32 nodeId, float x, float y, bool towards);
	bool GenerateCarCreationCoors(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);
	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 *buf, uint32 *size);
	void Load(uint8 *buf, uint32 size);

	static CVector TakeWidthIntoAccountForWandering(CPathNode*, uint16);
	static void TakeWidthIntoAccountForCoors(CPathNode*, CPathNode*, uint16, float*, float*);

	CPathNode *GetNode(int16 index);
	int16 GetIndex(CPathNode *node);

	uint16 ConnectedNode(int id) { return m_connections[id] & 0x3FFF; }
	bool ConnectionCrossesRoad(int id) { return !!(m_connections[id] & 0x8000); }
	bool ConnectionHasTrafficLight(int id) { return !!(m_connections[id] & 0x4000); }
	void ConnectionSetTrafficLight(int id) { m_connections[id] |= 0x4000; }

	void DisplayPathData(void);

	// Following methods are present on mobile but are unused. TODO: implement them
	void SavePathFindData(void);
	void ComputeRoute(uint8, const CVector&, const CVector&, CRoute<CPathNode*>&);
	void RecordNodesClosestToCoors(CVector, uint8, int, CPathNode**, float, bool, bool, bool);
	void RecordNodesInCircle(const CVector&, float, uint8, int, CPathNode**, bool, bool, bool, bool);
	void ArrangeOneNodeList(CPathInfoForObject*, int16);
	void ArrangeNodes(int16);
	void RegisterMarker(CVector*);
	void Shutdown(void);
};

extern CPathFind ThePaths;

inline CPathNode *CPathNode::GetPrev(void) { return ThePaths.GetNode(prevIndex); }
inline CPathNode *CPathNode::GetNext(void) { return ThePaths.GetNode(nextIndex); }
inline void CPathNode::SetPrev(CPathNode *node) { prevIndex = ThePaths.GetIndex(node); }
inline void CPathNode::SetNext(CPathNode *node) { nextIndex = ThePaths.GetIndex(node); }

extern bool gbShowPedPaths;
extern bool gbShowCarPaths;
extern bool gbShowCarPathsLinks;