1 #ifndef __STRATEGIC_MOVEMENT_H
2 #define __STRATEGIC_MOVEMENT_H
3 
4 #include "Debug.h"
5 #include "Types.h"
6 
7 struct SOLDIERTYPE;
8 
9 
10 enum //enemy intentions,
11 {
12 	NO_INTENTIONS,			//enemy intentions are undefined.
13 	PURSUIT,						//enemy group has spotted a player group and is pursuing them.  If they lose the player group, they
14 											//will get reassigned.
15 	STAGING,						//enemy is prepare to assault a town sector, but doesn't have enough troops.
16 	PATROL,							//enemy is moving around determining safe areas.
17 	REINFORCEMENTS,			//enemy group has intentions to fortify position at final destination.
18 	ASSAULT,						//enemy is ready to fight anything they encounter.
19 	NUM_ENEMY_INTENTIONS
20 };
21 
22 enum //move types
23 {
24 	ONE_WAY,						//from first waypoint to last, deleting each waypoint as they are reached.
25 	CIRCULAR,						//from first to last, recycling forever.
26 	ENDTOEND_FORWARDS,	//from first to last -- when reaching last, change to backwards.
27 	ENDTOEND_BACKWARDS	//from last to first -- when reaching first, change to forwards.
28 };
29 
30 enum
31 {
32 	NORTH_STRATEGIC_MOVE,
33 	EAST_STRATEGIC_MOVE,
34 	SOUTH_STRATEGIC_MOVE,
35 	WEST_STRATEGIC_MOVE,
36 	THROUGH_STRATEGIC_MOVE
37 };
38 
39 //This structure contains all of the information about a group moving in the strategic
40 //layer.  This includes all troops, equipment, and waypoints, and location.
41 //NOTE:  This is used for groups that are initiating a movement to another sector.
42 struct WAYPOINT
43 {
44 	UINT8 x;											//sector x position of waypoint
45 	UINT8 y;											//sector y position of waypoint
46 	WAYPOINT* next; //next waypoint in list
47 };
48 
49 
50 struct PLAYERGROUP
51 {
52 	SOLDIERTYPE *pSoldier;				//direct access to the soldier pointer
53 	PLAYERGROUP* next;			//next player in list
54 };
55 
56 
57 struct ENEMYGROUP
58 {
59 	UINT8 ubNumTroops;						//number of regular troops in the group
60 	UINT8 ubNumElites;						//number of elite troops in the group
61 	UINT8 ubNumAdmins;						//number of administrators in the group
62 	UINT8 ubPendingReinforcements;//This group is waiting for reinforcements before attacking or attempting to fortify newly aquired sector.
63 	UINT8 ubAdminsInBattle;				//number of administrators in currently in battle.
64 	UINT8 ubIntention;						//the type of group this is:  patrol, assault, spies, etc.
65 	UINT8 ubTroopsInBattle;				//number of soldiers currently in battle.
66 	UINT8 ubElitesInBattle;				//number of elite soldiers currently in battle.
67 };
68 
69 
70 //NOTE:  ALL FLAGS ARE CLEARED WHENEVER A GROUP ARRIVES IN A SECTOR, OR ITS WAYPOINTS ARE
71 //       DELETED!!!
72 #define GROUPFLAG_SIMULTANEOUSARRIVAL_APPROVED	0x00000001
73 #define GROUPFLAG_SIMULTANEOUSARRIVAL_CHECKED		0x00000002
74 //I use this flag when traversing through a list to determine which groups meet whatever conditions,
75 //then add this marker flag.  The second time I traverse the list, I simply check for this flag,
76 //apply my modifications to the group, and remove the flag.  If you decide to use it, make sure the
77 //flag is cleared.
78 #define GROUPFLAG_MARKER												0x00000004
79 //Set whenever a group retreats from battle.  If the group arrives in the next sector and enemies are there
80 //retreat will not be an option.
81 #define GROUPFLAG_JUST_RETREATED_FROM_BATTLE		0x00000008
82 #define GROUPFLAG_HIGH_POTENTIAL_FOR_AMBUSH			0x00000010
83 #define GROUPFLAG_GROUP_ARRIVED_SIMULTANEOUSLY	0x00000020
84 
85 
86 struct GROUP
87 {
88 	BOOLEAN fDebugGroup;					//for testing purposes -- handled differently in certain cases.
89 	BOOLEAN fPlayer;							//set if this is a player controlled group.
90 	BOOLEAN fVehicle;							//vehicle controlled group?
91 	BOOLEAN fPersistant;					//This flag when set prevents the group from being automatically deleted when it becomes empty.
92 	UINT8 ubGroupID;							//the unique ID of the group (used for hooking into events and SOLDIERTYPE)
93 	UINT8 ubGroupSize;						//total number of individuals in the group.
94 	UINT8 ubSectorX, ubSectorY;		//last/curr sector occupied
95 	UINT8 ubSectorZ;
96 	UINT8 ubNextX, ubNextY;				//next sector destination
97 	UINT8 ubPrevX, ubPrevY;				//prev sector occupied (could be same as ubSectorX/Y)
98 	UINT8 ubOriginalSector;				//sector where group was created.
99 	BOOLEAN fBetweenSectors;			//set only if a group is between sector.
100 	UINT8 ubMoveType;							//determines the type of movement (ONE_WAY, CIRCULAR, ENDTOEND, etc.)
101 	UINT8 ubNextWaypointID;				//the ID of the next waypoint
102 	UINT32 uiArrivalTime;					//the arrival time in world minutes that the group will arrive at the next sector. This should not be set directly; use setArrivalTime instead
103 	UINT32 uiTraverseTime;				//the total traversal time from the previous sector to the next sector.
104 	WAYPOINT *pWaypoints;					//a list of all of the waypoints in the groups movement.
105 	UINT8 ubTransportationMask;		//the mask combining all of the groups transportation methods.
106 	UINT32 uiFlags;								//various conditions that apply to the group
107 	UINT8 ubCreatedSectorID;			//used for debugging strategic AI for keeping track of the sector ID a group was created in.
108 	UINT8 ubSectorIDOfLastReassignment;	//used for debuggin strategic AI.  Records location of any reassignments.
109 
110 	union
111 	{
112 		PLAYERGROUP *pPlayerList;		//list of players in the group
113 		ENEMYGROUP *pEnemyGroup;		//a structure containing general enemy info
114 	};
115 	GROUP* next;						//next group
116 
117 	// ARM: centralized it so we can do a comprehensive Assert on it. Causing problems with helicopter group!
118 	void setArrivalTime(UINT32 time);
119 };
120 
121 
122 extern GROUP *gpGroupList;
123 
124 
125 #define BASE_FOR_EACH_GROUP(type, iter) \
126 	for (type iter = gpGroupList; iter != NULL; iter = iter->next)
127 #define FOR_EACH_GROUP(iter)  BASE_FOR_EACH_GROUP(      GROUP*, iter)
128 #define CFOR_EACH_GROUP(iter) BASE_FOR_EACH_GROUP(const GROUP*, iter)
129 
130 #define BASE_FOR_EACH_ENEMY_GROUP(type, iter) \
131 	BASE_FOR_EACH_GROUP(type, iter)                  \
132 		if (iter->fPlayer) continue; else
133 #define FOR_EACH_ENEMY_GROUP(iter)  BASE_FOR_EACH_ENEMY_GROUP(      GROUP*, iter)
134 #define CFOR_EACH_ENEMY_GROUP(iter) BASE_FOR_EACH_ENEMY_GROUP(const GROUP*, iter)
135 
136 #define BASE_FOR_EACH_PLAYER_GROUP(type, iter) \
137 	BASE_FOR_EACH_GROUP(type, iter)              \
138 		if (!iter->fPlayer) continue; else
139 #define FOR_EACH_PLAYER_GROUP(iter)  BASE_FOR_EACH_PLAYER_GROUP(      GROUP*, iter)
140 #define CFOR_EACH_PLAYER_GROUP(iter) BASE_FOR_EACH_PLAYER_GROUP(const GROUP*, iter)
141 
142 #define FOR_EACH_GROUP_SAFE(iter)                                                    \
143 	for (GROUP* iter = gpGroupList, * iter##__next; iter != NULL; iter = iter##__next) \
144 		if (iter##__next = iter->next, FALSE) {} else                                    \
145 
146 
147 #define CFOR_EACH_PLAYER_IN_GROUP(iter, group) \
148 	for (PLAYERGROUP const* iter = (Assert((group)->fPlayer), (group)->pPlayerList); iter; iter = iter->next)
149 
150 
151 //General utility functions
152 void RemoveAllGroups(void);
153 GROUP* GetGroup( UINT8 ubGroupID );
154 
155 /* Remove a group from the list. This removes all of the waypoints as well as
156  * the members of the group. Calling this function doesn't position them in a
157  * sector. It is up to you to do that. The event system will automatically
158  * handle their updating as they arrive in sectors. */
159 void RemoveGroup(GROUP&);
160 
161 /* Clear a group's waypoints. This is necessary when sending new orders such as
162  * different routes. */
163 void RemoveGroupWaypoints(GROUP&);
164 
165 //Player grouping functions
166 
167 /* Create a new player group.  This is the first step before adding waypoints
168  * and members to the player group. */
169 GROUP* CreateNewPlayerGroupDepartingFromSector(UINT8 ubSectorX, UINT8 ubSectorY);
170 
171 //Allows you to add or remove players from the group.
172 void AddPlayerToGroup(GROUP&, SOLDIERTYPE&);
173 
174 void RemovePlayerFromGroup(SOLDIERTYPE&);
175 void RemovePlayerFromPGroup(GROUP&, SOLDIERTYPE&);
176 
177 // create a vehicle group, it is by itself,
178 GROUP* CreateNewVehicleGroupDepartingFromSector(UINT8 ubSectorX, UINT8 ubSectorY);
179 
180 
181 //Appends a waypoint to the end of the list.  Waypoint MUST be on the
182 //same horizontal xor vertical level as the last waypoint added.
183 BOOLEAN AddWaypointToPGroup( GROUP *pGroup, UINT8 ubSectorX, UINT8 ubSectorY );
184 //Same, but uses a plain sectorID (0-255)
185 BOOLEAN AddWaypointIDToPGroup( GROUP *pGroup, UINT8 ubSectorID );
186 //Same, but uses a strategic sectorID
187 BOOLEAN AddWaypointStrategicIDToPGroup( GROUP *pGroup, UINT32 uiSectorID );
188 
189 //Enemy grouping functions -- private use by the strategic AI.
190 //............................................................
191 GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites );
192 
193 /* Arrival callback -- None of these functions should be called directly.
194  * This is called whenever any group arrives in the next sector (player or
195  * enemy). This function will first check to see if a battle should start, or if
196  * they aren't at the final destination, they will move to the next sector. */
197 void GroupArrivedAtSector(GROUP&, BOOLEAN check_for_battle, BOOLEAN never_left);
198 void CalculateNextMoveIntention( GROUP *pGroup );
199 
200 
201 // Set current sector of the group, used for player controlled mercs
202 void SetGroupSectorValue(INT16 x, INT16 y, INT16 z, GROUP&);
203 
204 void SetEnemyGroupSector(GROUP&, UINT8 sector_id);
205 
206 
207 // calculate the eta time in world total mins of this group
208 INT32 CalculateTravelTimeOfGroup(GROUP const*);
209 
210 static UINT32 const TRAVERSE_TIME_IMPOSSIBLE = 0xFFFFFFFF;
211 
212 // Get travel time for this group
213 INT32 GetSectorMvtTimeForGroup(UINT8 ubSector, UINT8 ubDirection, GROUP const*);
214 
215 UINT8 PlayerMercsInSector( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
216 UINT8 PlayerGroupsInSector( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
217 
218 // Is this player group in motion?
219 BOOLEAN PlayerGroupInMotion(GROUP const*);
220 
221 // Is the player greoup with this id in motion
222 bool PlayerIDGroupInMotion(UINT8 id);
223 
224 // get number of mercs between sectors
225 BOOLEAN PlayersBetweenTheseSectors( INT16 sSource, INT16 sDest, INT32 *iCountEnter, INT32 *iCountExit, BOOLEAN *fAboutToArriveEnter );
226 
227 void MoveAllGroupsInCurrentSectorToSector( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
228 
229 //Save the strategic movemnet Group paths to the saved game file
230 void SaveStrategicMovementGroupsToSaveGameFile(HWFILE);
231 
232 //Load the strategic movement Group paths from the saved game file
233 void LoadStrategicMovementGroupsFromSavedGameFile(HWFILE);
234 
235 void HandleArrivalOfReinforcements(GROUP const*);
236 
237 //Called when all checks have been made for the group (if possible to retreat, etc.)  This function
238 //blindly determines where to move the group.
239 void RetreatGroupToPreviousSector(GROUP&);
240 
241 GROUP* FindEnemyMovementGroupInSector(UINT8 x, UINT8 y);
242 GROUP* FindPlayerMovementGroupInSector(UINT8 x, UINT8 y);
243 
244 BOOLEAN GroupAtFinalDestination(const GROUP*);
245 
246 // find the travel time between waypts for this group
247 INT32 FindTravelTimeBetweenWaypoints(WAYPOINT const* pSource, WAYPOINT const* pDest,  GROUP const*);
248 
249 BOOLEAN GroupReversingDirectionsBetweenSectors( GROUP *pGroup, UINT8 ubSectorX, UINT8 ubSectorY, BOOLEAN fBuildingWaypoints );
250 BOOLEAN GroupBetweenSectorsAndSectorXYIsInDifferentDirection( GROUP *pGroup, UINT8 ubSectorX, UINT8 ubSectorY );
251 
252 WAYPOINT* GetFinalWaypoint(const GROUP*);
253 
254 void ResetMovementForEnemyGroupsInLocation( UINT8 ubSectorX, UINT8 ubSectorY );
255 
256 //Determines if any particular group WILL be moving through a given sector given it's current
257 //position in the route and TREATS the pGroup->ubMoveType as ONE_WAY EVEN IF IT ISN'T.  If the
258 //group is currently IN the sector, or just left the sector, it will return FALSE.
259 BOOLEAN GroupWillMoveThroughSector( GROUP *pGroup, UINT8 ubSectorX, UINT8 ubSectorY );
260 
261 void RandomizePatrolGroupLocation( GROUP *pGroup );
262 
263 void PlaceGroupInSector(GROUP&, INT16 prev_x, INT16 prev_y, INT16 next_x, INT16 next_y, INT8 z, bool check_for_battle);
264 
265 void PlayerGroupArrivedSafelyInSector(GROUP&, BOOLEAN fCheckForNPCs);
266 
267 bool DoesPlayerExistInPGroup(GROUP const&, SOLDIERTYPE const&);
268 
269 bool GroupHasInTransitDeadOrPOWMercs(GROUP const&);
270 
271 void AddFuelToVehicle(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pVehicle);
272 
273 void CalculateGroupRetreatSector(GROUP*);
274 
275 void UpdatePersistantGroupsFromOldSave(UINT32 uiSavedGameVersion);
276 
277 extern BOOLEAN gfUndergroundTacticalTraversal;
278 
279 #endif
280