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