1 #include "MouseSystem.h"
2 #include "Structure.h"
3 #include "WorldDef.h"
4 #include "RenderWorld.h"
5 #include "Isometric_Utils.h"
6 #include "Interface.h"
7 #include "math.h"
8 #include "WorldMan.h"
9 #include "Structure_Wrap.h"
10 #include "Sys_Globals.h"
11 #include "Overhead.h"
12 #include "Random.h"
13 #include "PathAI.h"
14 #include "UILayout.h"
15 
16 
17 UINT32 guiForceRefreshMousePositionCalculation = 0;
18 
19 // GLOBALS
20 const INT16 DirIncrementer[8] =
21 {
22 	-MAPWIDTH,        //N
23 	1-MAPWIDTH,       //NE
24 	1,                //E
25 	1+MAPWIDTH,       //SE
26 	MAPWIDTH,         //S
27 	MAPWIDTH-1,       //SW
28 	-1,               //W
29 	-MAPWIDTH-1       //NW
30 };
31 
32 
33 // DIRECTION FACING    DIRECTION WE WANT TO GOTO
34 UINT8 const gPurpendicularDirection[NUM_WORLD_DIRECTIONS][NUM_WORLD_DIRECTIONS] =
35 {
36 	{ // NORTH
37 		WEST,		// EITHER
38 		NORTHWEST,
39 		NORTH,
40 		NORTHEAST,
41 		EAST,		// EITHER
42 		NORTHWEST,
43 		NORTH,
44 		NORTHEAST
45 	},
46 
47 	{ // NORTH EAST
48 		NORTHWEST,
49 		NORTHWEST,	// EITHER
50 		SOUTH,
51 		NORTHEAST,
52 		EAST,
53 		SOUTHEAST,	// EITHER
54 		NORTH,
55 		NORTHEAST
56 	},
57 
58 	{ // EAST
59 		EAST,
60 		SOUTHEAST,
61 		NORTH,		// EITHER
62 		NORTHEAST,
63 		EAST,
64 		SOUTHEAST,
65 		NORTH,		// EITHER
66 		NORTHEAST
67 	},
68 
69 	{ // SOUTHEAST
70 		EAST,
71 		SOUTHEAST,
72 		SOUTH,
73 		SOUTHWEST,	// EITHER
74 		SOUTHWEST,
75 		SOUTHEAST,
76 		SOUTH,
77 		SOUTHWEST	// EITHER
78 	},
79 
80 	{ // SOUTH
81 		WEST,		// EITHER
82 		SOUTHEAST,
83 		SOUTH,
84 		SOUTHWEST,
85 		EAST,		// EITHER
86 		SOUTHEAST,
87 		SOUTH,
88 		SOUTHWEST
89 	},
90 
91 	{ // SOUTHWEST
92 		WEST,
93 		NORTHWEST,	// EITHER
94 		SOUTH,
95 		SOUTHWEST,
96 		WEST,
97 		SOUTHEAST,	// EITHER
98 		SOUTH,
99 		SOUTHWEST
100 	},
101 
102 	{ // WEST
103 		WEST,
104 		NORTHWEST,
105 		NORTH,		// EITHER
106 		SOUTHWEST,
107 		WEST,
108 		NORTHWEST,
109 		SOUTH,		// EITHER
110 		SOUTHWEST
111 	},
112 
113 	{ // NORTHWEST
114 		WEST,
115 		NORTHWEST,
116 		NORTH,
117 		SOUTHWEST,	// EITHER
118 		SOUTHWEST,
119 		NORTHWEST,
120 		NORTH,
121 		NORTHEAST	// EITHER
122 	}
123 };
124 
125 
FromCellToScreenCoordinates(INT16 sCellX,INT16 sCellY,INT16 * psScreenX,INT16 * psScreenY)126 void FromCellToScreenCoordinates( INT16 sCellX, INT16 sCellY, INT16 *psScreenX, INT16 *psScreenY )
127 {
128 	// cartesian to isometric
129 	*psScreenX = (sCellX - sCellY) * HALF_TILE_WIDTH;
130 	*psScreenY = (sCellX + sCellY) * HALF_TILE_HEIGHT;
131 }
132 
FromScreenToCellCoordinates(INT16 sScreenX,INT16 sScreenY,INT16 * psCellX,INT16 * psCellY)133 void FromScreenToCellCoordinates( INT16 sScreenX, INT16 sScreenY, INT16 *psCellX, INT16 *psCellY )
134 {
135 	// isometric to cartesian
136 	*psCellX = floor((FLOAT(sScreenX) / HALF_TILE_WIDTH + FLOAT(sScreenY) / HALF_TILE_HEIGHT) / 2.0f);
137 	*psCellY = floor((FLOAT(sScreenY) / HALF_TILE_HEIGHT - FLOAT(sScreenX) / HALF_TILE_WIDTH) / 2.0f);
138 }
139 
140 // These two functions take into account that our world is projected and attached
141 // to the screen (0,0) in a specific way, and we MUSt take that into account then
142 // determining screen coords
143 
FloatFromCellToScreenCoordinates(FLOAT dCellX,FLOAT dCellY,FLOAT * pdScreenX,FLOAT * pdScreenY)144 void FloatFromCellToScreenCoordinates( FLOAT dCellX, FLOAT dCellY, FLOAT *pdScreenX, FLOAT *pdScreenY )
145 {
146 	FLOAT dScreenX, dScreenY;
147 
148 	dScreenX = ( 2 * dCellX ) - ( 2 * dCellY );
149 	dScreenY = dCellX + dCellY;
150 
151 	*pdScreenX = dScreenX;
152 	*pdScreenY = dScreenY;
153 }
154 
155 
GetMouseXY(INT16 * psMouseX,INT16 * psMouseY)156 BOOLEAN GetMouseXY( INT16 *psMouseX, INT16 *psMouseY )
157 {
158 	INT16 sWorldX, sWorldY;
159 
160 	if ( !GetMouseWorldCoords( &sWorldX, &sWorldY ) )
161 	{
162 		(*psMouseX) = 0;
163 		(*psMouseY) = 0;
164 		return( FALSE );
165 	}
166 
167 	// Find start block
168 	(*psMouseX) = ( sWorldX / CELL_X_SIZE );
169 	(*psMouseY) = ( sWorldY / CELL_Y_SIZE );
170 
171 	return( TRUE );
172 }
173 
174 
GetMouseWorldCoords(INT16 * psMouseX,INT16 * psMouseY)175 BOOLEAN GetMouseWorldCoords( INT16 *psMouseX, INT16 *psMouseY )
176 {
177 	INT16 sOffsetX, sOffsetY;
178 	INT16 sTempPosX_W, sTempPosY_W;
179 	INT16 sStartPointX_W, sStartPointY_W;
180 
181 	// Convert mouse screen coords into offset from center
182 	if ( ! ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) )
183 	{
184 		*psMouseX = 0;
185 		*psMouseY = 0;
186 		return( FALSE );
187 	}
188 
189 	sOffsetX = gViewportRegion.MouseXPos - ( g_ui.m_tacticalMapCenterX ); // + gsRenderWorldOffsetX;
190 	sOffsetY = gViewportRegion.MouseYPos - ( g_ui.m_tacticalMapCenterY ) + 10;// + gsRenderWorldOffsetY;
191 
192 	// OK, Let's offset by a value if our interfac level is changed!
193 	if ( gsInterfaceLevel != 0 )
194 	{
195 		//sOffsetY -= 50;
196 	}
197 
198 
199 	FromScreenToCellCoordinates( sOffsetX, sOffsetY, &sTempPosX_W, &sTempPosY_W );
200 
201 	// World start point is Render center plus this distance
202 	sStartPointX_W = gsRenderCenterX + sTempPosX_W;
203 	sStartPointY_W = gsRenderCenterY + sTempPosY_W;
204 
205 
206 	// check if we are out of bounds..
207 	if ( sStartPointX_W < 0 || sStartPointX_W >= WORLD_COORD_ROWS || sStartPointY_W < 0 || sStartPointY_W >= WORLD_COORD_COLS )
208 	{
209 		*psMouseX = 0;
210 		*psMouseY = 0;
211 		return( FALSE );
212 	}
213 
214 	// Determine Start block and render offsets
215 	// Find start block
216 	// Add adjustment for render origin as well
217 	(*psMouseX) = sStartPointX_W;
218 	(*psMouseY) = sStartPointY_W;
219 
220 	return( TRUE );
221 }
222 
223 
GetMouseMapPos(void)224 GridNo GetMouseMapPos(void)
225 {
226 	static GridNo sSameCursorPos   = NOWHERE;
227 	static UINT32 uiOldFrameNumber = 99999;
228 
229 	// Check if this is the same frame as before, return already calculated value if so!
230 	if (uiOldFrameNumber == guiGameCycleCounter && !guiForceRefreshMousePositionCalculation)
231 	{
232 		return sSameCursorPos;
233 	}
234 
235 	uiOldFrameNumber                        = guiGameCycleCounter;
236 	guiForceRefreshMousePositionCalculation = FALSE;
237 
238 	GridNo pos;
239 	INT16  sWorldX;
240 	INT16  sWorldY;
241 	if (GetMouseXY(&sWorldX, &sWorldY))
242 	{
243 		pos = MAPROWCOLTOPOS(sWorldY, sWorldX);
244 	}
245 	else
246 	{
247 		pos = NOWHERE;
248 	}
249 	sSameCursorPos = pos;
250 	return pos;
251 }
252 
253 
GetAbsoluteScreenXYFromMapPos(const GridNo pos,INT16 * const psWorldScreenX,INT16 * const psWorldScreenY)254 void GetAbsoluteScreenXYFromMapPos(const GridNo pos, INT16* const psWorldScreenX, INT16* const psWorldScreenY)
255 {
256 	INT16 sScreenCenterX, sScreenCenterY;
257 
258 	INT16 sWorldCellX;
259 	INT16 sWorldCellY;
260 	ConvertGridNoToCellXY(pos, &sWorldCellX, &sWorldCellY);
261 
262 	// Find the diustance from render center to true world center
263 	const INT16 sDistToCenterX = sWorldCellX - gCenterWorldX;
264 	const INT16 sDistToCenterY = sWorldCellY - gCenterWorldY;
265 
266 
267 	// From render center in world coords, convert to render center in "screen" coords
268 
269 	// ATE: We should call the fowllowing function but I'm putting it here verbatim for speed
270 	//FromCellToScreenCoordinates( sDistToCenterX , sDistToCenterY, &sScreenCenterX, &sScreenCenterY );
271 	sScreenCenterX = ( 2 * sDistToCenterX ) - ( 2 * sDistToCenterY );
272 	sScreenCenterY = sDistToCenterX + sDistToCenterY;
273 
274 	// Subtract screen center
275 	*psWorldScreenX = sScreenCenterX + gsCX - gsLeftX;
276 	*psWorldScreenY = sScreenCenterY + gsCY - gsTopY;
277 
278 }
279 
280 
GetMapPosFromAbsoluteScreenXY(const INT16 sWorldScreenX,const INT16 sWorldScreenY)281 GridNo GetMapPosFromAbsoluteScreenXY(const INT16 sWorldScreenX, const INT16 sWorldScreenY)
282 {
283 	INT16 sWorldCenterX, sWorldCenterY;
284 	INT16 sDistToCenterY, sDistToCenterX;
285 
286 	// Subtract screen center
287 	sDistToCenterX = sWorldScreenX - gsCX + gsLeftX;
288 	sDistToCenterY = sWorldScreenY - gsCY + gsTopY;
289 
290 	// From render center in world coords, convert to render center in "screen" coords
291 
292 	// ATE: We should call the fowllowing function but I'm putting it here verbatim for speed
293 	//FromCellToScreenCoordinates( sDistToCenterX , sDistToCenterY, &sScreenCenterX, &sScreenCenterY );
294 	sWorldCenterX = ( ( sDistToCenterX + ( 2 * sDistToCenterY ) ) / 4 );
295 	sWorldCenterY = ( ( 2 * sDistToCenterY ) - sDistToCenterX ) / 4;
296 
297 	// Goto center again
298 	sWorldCenterX += gCenterWorldX;
299 	sWorldCenterY += gCenterWorldY;
300 
301 	return GETWORLDINDEXFROMWORLDCOORDS(sWorldCenterY, sWorldCenterX);
302 }
303 
304 
305 // UTILITY FUNTIONS
306 
OutOfBounds(INT16 sGridno,INT16 sProposedGridno)307 INT32 OutOfBounds(INT16 sGridno, INT16 sProposedGridno)
308 {
309 	INT16 sMod,sPropMod;
310 
311 	// get modulas of our origin
312 	sMod = sGridno % MAXCOL;
313 
314 	if (sMod != 0)  		// if we're not on leftmost grid
315 		if (sMod != RIGHTMOSTGRID)	// if we're not on rightmost grid
316 			if (sGridno < LASTROWSTART)	// if we're above bottom row
317 				if (sGridno > MAXCOL)	// if we're below top row
318 				// Everything's OK - we're not on the edge of the map
319 					return(FALSE);
320 
321 
322 	// if we've got this far, there's a potential problem - check it out!
323 
324 	if (sProposedGridno < 0)
325 		return(TRUE);
326 
327 	sPropMod = sProposedGridno % MAXCOL;
328 
329 	if (sMod == 0 && sPropMod == RIGHTMOSTGRID)
330 		return(TRUE);
331 	else if (sMod == RIGHTMOSTGRID && sPropMod == 0)
332 		return TRUE;
333 	else
334 		return (sGridno >= LASTROWSTART && sProposedGridno >= GRIDSIZE);
335 }
336 
337 
338 
NewGridNo(INT16 sGridno,INT16 sDirInc)339 INT16 NewGridNo(INT16 sGridno, INT16 sDirInc)
340 {
341 	INT16 sProposedGridno = sGridno + sDirInc;
342 
343 	// now check for out-of-bounds
344 	if (OutOfBounds(sGridno,sProposedGridno))
345 		// return ORIGINAL gridno to user
346 		sProposedGridno = sGridno;
347 
348 	return(sProposedGridno);
349 }
350 
351 
DirectionInc(UINT8 ubDirection)352 INT16 DirectionInc(UINT8 ubDirection)
353 {
354 	if (ubDirection > 7)
355 	{
356 		//direction = random(8);	// replace garbage with random direction
357 		ubDirection = 1;
358 	}
359 	return(DirIncrementer[ubDirection]);
360 }
361 
362 
CellXYToScreenXY(INT16 const sCellX,INT16 const sCellY,INT16 * const sScreenX,INT16 * const sScreenY)363 void CellXYToScreenXY(INT16 const sCellX, INT16 const sCellY, INT16* const sScreenX, INT16* const sScreenY)
364 {
365 	INT16 sDeltaCellX, sDeltaCellY;
366 	INT16 sDeltaScreenX, sDeltaScreenY;
367 
368 	sDeltaCellX=sCellX-gsRenderCenterX;
369 	sDeltaCellY=sCellY-gsRenderCenterY;
370 
371 	FromCellToScreenCoordinates(sDeltaCellX, sDeltaCellY, &sDeltaScreenX, &sDeltaScreenY);
372 
373 	*sScreenX=((g_ui.m_tacticalMapCenterX)+sDeltaScreenX);
374 	*sScreenY=((g_ui.m_tacticalMapCenterY)+sDeltaScreenY);
375 }
376 
377 
ConvertGridNoToXY(INT16 sGridNo,INT16 * sXPos,INT16 * sYPos)378 void ConvertGridNoToXY( INT16 sGridNo, INT16 *sXPos, INT16 *sYPos )
379 {
380 	*sYPos = sGridNo / WORLD_COLS;
381 	*sXPos = ( sGridNo - ( *sYPos * WORLD_COLS ) );
382 }
383 
ConvertGridNoToCellXY(INT16 sGridNo,INT16 * sXPos,INT16 * sYPos)384 void ConvertGridNoToCellXY( INT16 sGridNo, INT16 *sXPos, INT16 *sYPos )
385 {
386 	*sYPos = ( sGridNo / WORLD_COLS );
387 	*sXPos = sGridNo - ( *sYPos * WORLD_COLS );
388 
389 	*sYPos = ( *sYPos * CELL_Y_SIZE );
390 	*sXPos = ( *sXPos * CELL_X_SIZE );
391 }
392 
393 
ConvertGridNoToCenterCellXY(const INT16 gridno,INT16 * const x,INT16 * const y)394 void ConvertGridNoToCenterCellXY(const INT16 gridno, INT16* const x, INT16* const y)
395 {
396 	*x = gridno % WORLD_COLS * CELL_X_SIZE + CELL_X_SIZE / 2;
397 	*y = gridno / WORLD_COLS * CELL_Y_SIZE + CELL_Y_SIZE / 2;
398 }
399 
400 
GetRangeFromGridNoDiff(INT16 sGridNo1,INT16 sGridNo2)401 INT32 GetRangeFromGridNoDiff( INT16 sGridNo1, INT16 sGridNo2 )
402 {
403 	INT32 uiDist;
404 	INT16 sXPos, sYPos, sXPos2, sYPos2;
405 
406 	// Convert our grid-not into an XY
407 	ConvertGridNoToXY( sGridNo1, &sXPos, &sYPos );
408 
409 	// Convert our grid-not into an XY
410 	ConvertGridNoToXY( sGridNo2, &sXPos2, &sYPos2 );
411 
412 	uiDist = (INT16)sqrt(double(( sXPos2 - sXPos )*( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos )));
413 
414 	return( uiDist );
415 }
416 
GetRangeInCellCoordsFromGridNoDiff(INT16 sGridNo1,INT16 sGridNo2)417 INT32 GetRangeInCellCoordsFromGridNoDiff( INT16 sGridNo1, INT16 sGridNo2 )
418 {
419 	INT16 sXPos, sYPos, sXPos2, sYPos2;
420 
421 	// Convert our grid-not into an XY
422 	ConvertGridNoToXY( sGridNo1, &sXPos, &sYPos );
423 
424 	// Convert our grid-not into an XY
425 	ConvertGridNoToXY( sGridNo2, &sXPos2, &sYPos2 );
426 
427 	return( (INT32)( sqrt(double(( sXPos2 - sXPos ) * ( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos ) )) ) * CELL_X_SIZE );
428 }
429 
430 
IsPointInScreenRect(INT16 const x,INT16 const y,SGPRect const & r)431 bool IsPointInScreenRect(INT16 const x, INT16 const y, SGPRect const& r)
432 {
433 	return r.iLeft <= x && x <= r.iRight && r.iTop <= y && y <= r.iBottom;
434 }
435 
436 
IsPointInScreenRectWithRelative(INT16 sXPos,INT16 sYPos,SGPRect * pRect,INT16 * sXRel,INT16 * sYRel)437 BOOLEAN IsPointInScreenRectWithRelative( INT16 sXPos, INT16 sYPos, SGPRect *pRect, INT16 *sXRel, INT16 *sYRel )
438 {
439 	if ( (sXPos >= pRect->iLeft) && (sXPos <= pRect->iRight) && (sYPos >= pRect->iTop) && (sYPos <= pRect->iBottom) )
440 	{
441 		(*sXRel) = pRect->iLeft - sXPos;
442 		(*sYRel) = sYPos - (INT16)pRect->iTop;
443 
444 		return( TRUE );
445 	}
446 	else
447 	{
448 		return( FALSE );
449 	}
450 }
451 
452 
PythSpacesAway(INT16 sOrigin,INT16 sDest)453 INT16 PythSpacesAway(INT16 sOrigin, INT16 sDest)
454 {
455 	INT16 sRows,sCols,sResult;
456 
457 	sRows = ABS((sOrigin / MAXCOL) - (sDest / MAXCOL));
458 	sCols = ABS((sOrigin % MAXROW) - (sDest % MAXROW));
459 
460 
461 	// apply Pythagoras's theorem for right-handed triangle:
462 	// dist^2 = rows^2 + cols^2, so use the square root to get the distance
463 	sResult = (INT16)sqrt(double((sRows * sRows) + (sCols * sCols)));
464 
465 	return(sResult);
466 }
467 
468 
SpacesAway(INT16 sOrigin,INT16 sDest)469 INT16 SpacesAway(INT16 sOrigin, INT16 sDest)
470 {
471 	INT16 sRows,sCols;
472 
473 	sRows = ABS((sOrigin / MAXCOL) - (sDest / MAXCOL));
474 	sCols = ABS((sOrigin % MAXROW) - (sDest % MAXROW));
475 
476 	return( __max( sRows, sCols ) );
477 }
478 
CardinalSpacesAway(INT16 sOrigin,INT16 sDest)479 INT16 CardinalSpacesAway(INT16 sOrigin, INT16 sDest)
480 // distance away, ignoring diagonals!
481 {
482 	INT16 sRows,sCols;
483 
484 	sRows = ABS((sOrigin / MAXCOL) - (sDest / MAXCOL));
485 	sCols = ABS((sOrigin % MAXROW) - (sDest % MAXROW));
486 
487 	return( (INT16)( sRows + sCols ) );
488 }
489 
490 
FindNumTurnsBetweenDirs(INT8 sDir1,INT8 sDir2)491 static INT8 FindNumTurnsBetweenDirs(INT8 sDir1, INT8 sDir2)
492 {
493 	INT16 sDirection;
494 	INT16 sNumTurns = 0;
495 
496 	sDirection = sDir1;
497 
498 	do
499 	{
500 
501 		sDirection = sDirection + QuickestDirection( sDir1, sDir2 );
502 
503 		if (sDirection > 7)
504 		{
505 			sDirection = 0;
506 		}
507 		else
508 		{
509 			if ( sDirection < 0 )
510 			{
511 				sDirection = 7;
512 			}
513 		}
514 
515 		if ( sDirection == sDir2 )
516 		{
517 			break;
518 		}
519 
520 		sNumTurns++;
521 
522 		// SAFEGUARD ! - if we (somehow) do not get to were we want!
523 		if ( sNumTurns > 100 )
524 		{
525 			sNumTurns = 0;
526 			break;
527 		}
528 	} while( TRUE );
529 
530 	return( (INT8)sNumTurns );
531 }
532 
533 
FindHigherLevel(SOLDIERTYPE const * const s,UINT8 * const out_direction)534 bool FindHigherLevel(SOLDIERTYPE const* const s, UINT8* const out_direction)
535 {
536 	if (s->bLevel > 0) return false;
537 
538 	GridNo const grid_no = s->sGridNo;
539 	// If there is a roof over our heads, this is an ivalid
540 	if (FindStructure(grid_no, STRUCTURE_ROOF)) return false;
541 
542 	bool       found         = false;
543 	UINT8      min_turns     = 100;
544 	INT8       min_direction = 0;
545 	INT8 const starting_dir  = s->bDirection;
546 	for (INT32 cnt = 0; cnt != 8; cnt += 2)
547 	{
548 		GridNo const new_grid_no = NewGridNo(grid_no, DirectionInc(cnt));
549 		if (!NewOKDestination(s, new_grid_no, TRUE, 1)) continue;
550 
551 		// Check if this tile has a higher level
552 		if (!IsHeigherLevel(new_grid_no)) continue;
553 
554 		// FInd how many turns we should go to get here
555 		INT8 const n_turns =  FindNumTurnsBetweenDirs(cnt, starting_dir);
556 		if (min_turns <= n_turns) continue;
557 
558 		found         = true;
559 		min_turns     = n_turns;
560 		min_direction = cnt;
561 	}
562 
563 	if (!found) return false;
564 
565 	if (out_direction) *out_direction = min_direction;
566 	return true;
567 }
568 
569 
FindLowerLevel(SOLDIERTYPE const * const s,UINT8 * const out_direction)570 bool FindLowerLevel(SOLDIERTYPE const* const s, UINT8* const out_direction)
571 {
572 	if (s->bLevel == 0) return false;
573 
574 	bool         found         = false;
575 	UINT8        min_turns     = 100;
576 	INT8         min_direction = 0;
577 	GridNo const grid_no       = s->sGridNo;
578 	INT8   const starting_dir  = s->bDirection;
579 	for (INT32 dir = 0; dir != 8; dir += 2)
580 	{
581 		GridNo const new_grid_no = NewGridNo(grid_no, DirectionInc(dir));
582 		if (!NewOKDestination(s, new_grid_no, TRUE, 0)) continue;
583 		// Make sure there is NOT a roof here
584 		if (FindStructure(new_grid_no, STRUCTURE_ROOF)) continue;
585 
586 		// Find how many turns we should go to get here
587 		INT8 const n_turns = FindNumTurnsBetweenDirs(dir, starting_dir);
588 		if (min_turns <= n_turns) continue;
589 
590 		found         = true;
591 		min_turns     = n_turns;
592 		min_direction = dir;
593 	}
594 
595 	if (!found) return false;
596 
597 	if (out_direction) *out_direction = min_direction;
598 	return true;
599 }
600 
601 
QuickestDirection(INT16 origin,INT16 dest)602 INT16 QuickestDirection(INT16 origin, INT16 dest)
603 {
604 	INT16 v1,v2;
605 
606 	if (origin==dest)
607 		return(0);
608 
609 	if ((ABS(origin - dest)) == 4)
610 	{
611 		return(1);		// this could be made random
612 	}
613 	else
614 	{
615 		if (origin > dest)
616 		{
617 			v1 = ABS(origin - dest);
618 			v2 = (8 - origin) + dest;
619 			if (v1 > v2)
620 				return(1);
621 			else
622 				return(-1);
623 		}
624 		else
625 		{
626 			v1 = ABS(origin - dest);
627 			v2 = (8 - dest) + origin;
628 			if (v1 > v2)
629 				return(-1);
630 			else
631 				return(1);
632 		}
633 	}
634 }
635 
636 
ExtQuickestDirection(INT16 origin,INT16 dest)637 INT16 ExtQuickestDirection(INT16 origin, INT16 dest)
638 {
639 	INT16 v1,v2;
640 
641 	if (origin==dest)
642 		return(0);
643 
644 	if ((ABS(origin - dest)) == 16)
645 	{
646 		return(1);		// this could be made random
647 	}
648 	else
649 	{
650 		if (origin > dest)
651 		{
652 			v1 = ABS(origin - dest);
653 			v2 = (32 - origin) + dest;
654 			if (v1 > v2)
655 				return(1);
656 			else
657 				return(-1);
658 		}
659 		else
660 		{
661 			v1 = ABS(origin - dest);
662 			v2 = (32 - dest) + origin;
663 			if (v1 > v2)
664 				return(-1);
665 			else
666 				return(1);
667 		}
668 	}
669 }
670 
671 
672 // Returns the (center ) cell coordinates in X
CenterX(INT16 sGridNo)673 INT16 CenterX( INT16 sGridNo )
674 {
675 	INT16 sXPos;
676 
677 	sXPos = sGridNo % WORLD_COLS;
678 
679 	return( ( sXPos * CELL_X_SIZE ) + ( CELL_X_SIZE / 2 ) );
680 }
681 
682 
683 // Returns the (center ) cell coordinates in Y
CenterY(INT16 sGridNo)684 INT16 CenterY( INT16 sGridNo )
685 {
686 	INT16 sYPos;
687 
688 	sYPos = sGridNo / WORLD_COLS;
689 
690 	return( ( sYPos * CELL_Y_SIZE ) + ( CELL_Y_SIZE / 2 ) );
691 }
692 
693 
GridNoOnVisibleWorldTile(INT16 sGridNo)694 BOOLEAN GridNoOnVisibleWorldTile( INT16 sGridNo )
695 {
696 	INT16 sWorldX;
697 	INT16 sWorldY;
698 	GetAbsoluteScreenXYFromMapPos(sGridNo, &sWorldX, &sWorldY);
699 
700 	if (sWorldX > 0 && sWorldX < (gsRightX - gsLeftX - 20) &&
701 		sWorldY > 20 && sWorldY < (gsBottomY - gsTopY - 20))
702 	{
703 		return( TRUE );
704 	}
705 
706 	return( FALSE );
707 }
708 
709 
GridNoOnEdgeOfMap(INT16 sGridNo,INT8 * pbDirection)710 BOOLEAN GridNoOnEdgeOfMap( INT16 sGridNo, INT8 * pbDirection )
711 {
712 	INT8 bDir;
713 
714 	// check NE, SE, SW, NW because of tilt of isometric display
715 
716 	for (bDir = NORTHEAST; bDir < NUM_WORLD_DIRECTIONS; bDir += 2 )
717 	{
718 		if (gubWorldMovementCosts[ (sGridNo + DirectionInc( bDir ) ) ][ bDir ][ 0 ] == TRAVELCOST_OFF_MAP)
719 		//if ( !GridNoOnVisibleWorldTile( (INT16) (sGridNo + DirectionInc( bDir ) ) ) )
720 		{
721 			*pbDirection = bDir;
722 			return( TRUE );
723 		}
724 	}
725 	return( FALSE );
726 }
727 
IsFacingClimableWindow(SOLDIERTYPE const * const pSoldier)728 BOOLEAN IsFacingClimableWindow( SOLDIERTYPE const* const pSoldier )
729 {
730 	GridNo sNewGridNo, sOtherSideOfWindow;
731 
732 	GridNo const sGridNo = pSoldier->sGridNo;
733 	INT8 const bStartingDir=pSoldier->bDirection;
734 
735 	// WANNE: No need to check on SOUTH and EAST tile, because it is the tile that has the fence we are standing on!
736 	if (bStartingDir == NORTH || bStartingDir == WEST)
737 	{
738 		// IF there is a fence in this gridno, return false!
739 		if ( IsJumpableWindowPresentAtGridNo( sGridNo, bStartingDir ) )
740 		{
741 			return( FALSE );
742 		}
743 
744 		sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)bStartingDir ) );
745 		sOtherSideOfWindow = sNewGridNo;
746 	}
747 	else
748 	{
749 		// current tile we are standing is the fence tile
750 		sNewGridNo = sGridNo;
751 		sOtherSideOfWindow = NewGridNo( sNewGridNo, (UINT16)DirectionInc( (UINT8)bStartingDir ) );
752 	}
753 
754 	// ATE: Check if there is somebody waiting here.....
755 	if (! NewOKDestination( pSoldier, sOtherSideOfWindow, TRUE, 0 ) ) return false;
756 
757 	// Check if we have a window here
758 	if (!IsJumpableWindowPresentAtGridNo( sNewGridNo , bStartingDir) ) return false;
759 
760 	return true;
761 }
762 
FindFenceJumpDirection(SOLDIERTYPE const * const pSoldier,UINT8 * const out_direction)763 BOOLEAN FindFenceJumpDirection(SOLDIERTYPE const* const pSoldier, UINT8* const out_direction)
764 {
765 	UINT8   cnt;
766 	INT16   sNewGridNo, sOtherSideOfFence;
767 	BOOLEAN fFound = FALSE;
768 	UINT8   bMinNumTurns = 100;
769 	INT8    bNumTurns;
770 	UINT8   bMinDirection = 0;
771 
772 	GridNo const sGridNo = pSoldier->sGridNo;
773 	// IF there is a fence in this gridno, return false!
774 	if ( IsJumpableFencePresentAtGridno( sGridNo ) )
775 	{
776 		return( FALSE );
777 	}
778 
779 	// LOOP THROUGH ALL 8 DIRECTIONS
780 	INT8 const bStartingDir = pSoldier->bDirection;
781 	for ( cnt = 0; cnt < 8; cnt+= 2 )
782 	{
783 		// go out *2* tiles
784 		sNewGridNo = NewGridNo( (UINT16)sGridNo, DirectionInc( cnt ) );
785 		sOtherSideOfFence = NewGridNo( (UINT16)sNewGridNo, DirectionInc( cnt ) );
786 
787 		if ( NewOKDestination( pSoldier, sOtherSideOfFence, TRUE, 0 ) )
788 		{
789 			// ATE: Check if there is somebody waiting here.....
790 
791 
792 			// Check if we have a fence here
793 			if ( IsJumpableFencePresentAtGridno( sNewGridNo ) )
794 			{
795 				fFound = TRUE;
796 
797 				// FInd how many turns we should go to get here
798 				bNumTurns =  FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir );
799 
800 				if ( bNumTurns < bMinNumTurns )
801 				{
802 					bMinNumTurns = bNumTurns;
803 					bMinDirection = cnt;
804 				}
805 			}
806 		}
807 	}
808 
809 	if ( fFound )
810 	{
811 		if (out_direction) *out_direction = bMinDirection;
812 		return( TRUE );
813 	}
814 
815 	return( FALSE );
816 }
817 
818 //Simply chooses a random gridno within valid boundaries (for dropping things in unloaded sectors)
RandomGridNo()819 INT16 RandomGridNo()
820 {
821 	INT32 iMapXPos, iMapYPos, iMapIndex;
822 	do
823 	{
824 		iMapXPos = Random( WORLD_COLS );
825 		iMapYPos = Random( WORLD_ROWS );
826 		iMapIndex = iMapYPos * WORLD_COLS + iMapXPos;
827 	} while( !GridNoOnVisibleWorldTile( (INT16)iMapIndex ) );
828 	return (INT16)iMapIndex;
829 }
830