1 #include "Animation_Data.h"
2 #include "Cursors.h"
3 #include "Font_Control.h"
4 #include "HImage.h"
5 #include "Isometric_Utils.h"
6 #include "TileDef.h"
7 #include "VObject.h"
8 #include "SysUtil.h"
9 #include "RenderWorld.h"
10 #include "Interface.h"
11 #include "Sound_Control.h"
12 #include "WorldDef.h"
13 #include "Interactive_Tiles.h"
14 #include "WorldMan.h"
15 #include "Structure.h"
16 #include "Animation_Control.h"
17 #include "Points.h"
18 #include "Overhead.h"
19 #include "Structure_Wrap.h"
20 #include "Tile_Animation.h"
21 #include "Tile_Cache.h"
22 #include "Handle_Doors.h"
23 #include "StrategicMap.h"
24 #include "Quests.h"
25 #include "Dialogue_Control.h"
26 #include "Random.h"
27 #include "English.h"
28 #include "Handle_Items.h"
29 #include "Message.h"
30 #include "Handle_UI.h"
31 #include "NPC.h"
32 #include "Explosion_Control.h"
33 #include "Text.h"
34 #include "GameSettings.h"
35 #include "Environment.h"
36 #include "Debug.h"
37 #include "UILayout.h"
38 
39 #include "Soldier.h"
40 #include "GameInstance.h"
41 #include "ContentManager.h"
42 #include "ShippingDestinationModel.h"
43 
44 #define MAX_INTTILE_STACK 10
45 
46 
47 struct CUR_INTERACTIVE_TILE
48 {
49 	INT16            sGridNo;
50 	INT16            sTileIndex;
51 	INT16            sHeighestScreenY;
52 	BOOLEAN          fFound;
53 	LEVELNODE const* pFoundNode;
54 	INT16            sFoundGridNo;
55 	UINT16           usStructureID;
56 	BOOLEAN          fStructure;
57 };
58 
59 
60 struct INTERACTIVE_TILE_STACK_TYPE
61 {
62 	INT8                 bNum;
63 	CUR_INTERACTIVE_TILE bTiles[MAX_INTTILE_STACK];
64 	INT8                 bCur;
65 };
66 
67 
68 static INTERACTIVE_TILE_STACK_TYPE gCurIntTileStack;
69 static BOOLEAN                     gfCycleIntTile = FALSE;
70 
71 
72 static CUR_INTERACTIVE_TILE gCurIntTile;
73 static BOOLEAN              gfOverIntTile = FALSE;
74 
75 // Values to determine if we should check or not
76 static INT16  gsINTOldRenderCenterX = 0;
77 static INT16  gsINTOldRenderCenterY = 0;
78 static UINT16 gusINTOldMousePosX    = 0;
79 static UINT16 gusINTOldMousePosY    = 0;
80 
81 
StartInteractiveObject(GridNo const gridno,STRUCTURE const & structure,SOLDIERTYPE & s,UINT8 const direction)82 void StartInteractiveObject(GridNo const gridno, STRUCTURE const& structure, SOLDIERTYPE& s, UINT8 const direction)
83 {
84 	// ATE: Patch fix: Don't allow if alreay in animation
85 	if (s.usAnimState == OPEN_STRUCT)               return;
86 	if (s.usAnimState == OPEN_STRUCT_CROUCHED)      return;
87 	if (s.usAnimState == BEGIN_OPENSTRUCT)          return;
88 	if (s.usAnimState == BEGIN_OPENSTRUCT_CROUCHED) return;
89 
90 	SoldierSP soldier = GetSoldier(&s);
91 
92 	// Add soldier event for opening door/struct
93 	soldier->setPendingAction(structure.fFlags & STRUCTURE_ANYDOOR ? MERC_OPENDOOR : MERC_OPENSTRUCT);
94 	s.uiPendingActionData1     = structure.usStructureID;
95 	s.sPendingActionData2      = gridno;
96 	s.bPendingActionData3      = direction;
97 }
98 
99 
SoldierHandleInteractiveObject(SOLDIERTYPE & s)100 bool SoldierHandleInteractiveObject(SOLDIERTYPE& s)
101 {
102 	GridNo     const gridno       = s.sPendingActionData2;
103 	UINT16     const structure_id = (UINT16)s.uiPendingActionData1;
104 	STRUCTURE* const structure    = FindStructureByID(gridno, structure_id);
105 	if (!structure) return false;
106 	return HandleOpenableStruct(&s, gridno, structure);
107 }
108 
109 
HandleStructChangeFromGridNo(SOLDIERTYPE * const s,GridNo const grid_no)110 void HandleStructChangeFromGridNo(SOLDIERTYPE* const s, GridNo const grid_no)
111 {
112 	STRUCTURE* const structure = FindStructure(grid_no, STRUCTURE_OPENABLE);
113 	if (!structure)
114 	{
115 		SLOGW("Told to handle struct that does not exist at %d.", grid_no);
116 		return;
117 	}
118 
119 	// Do sound...
120 	bool const closing = structure->fFlags & STRUCTURE_OPEN;
121 	PlayLocationJA2Sample(grid_no, GetStructureOpenSound(structure, closing), HIGHVOLUME, 1);
122 
123 	// ATE: Don't handle switches!
124 	if (!(structure->fFlags & STRUCTURE_SWITCH))
125 	{
126 		bool did_missing_quote = false;
127 		if (s->bTeam == OUR_TEAM)
128 		{
129 			auto primaryDest = GCM->getPrimaryShippingDestination();
130 			if (grid_no        == primaryDest->deliverySectorGridNo  &&
131 			    gWorldSectorX  == primaryDest->deliverySectorX       &&
132 			    gWorldSectorY  == primaryDest->deliverySectorY       &&
133 			    gbWorldSectorZ == primaryDest->deliverySectorZ       &&
134 					CheckFact(FACT_PABLOS_STOLE_FROM_LATEST_SHIPMENT, 0) &&
135 					!CheckFact(FACT_PLAYER_FOUND_ITEMS_MISSING, 0))
136 			{
137 				SayQuoteFromNearbyMercInSector(grid_no, 3, QUOTE_STUFF_MISSING_DRASSEN);
138 				did_missing_quote = true;
139 			}
140 		}
141 		else if (s->bTeam == CIV_TEAM)
142 		{
143 			if (s->ubProfile != NO_PROFILE)
144 			{
145 				TriggerNPCWithGivenApproach(s->ubProfile, APPROACH_DONE_OPEN_STRUCTURE);
146 			}
147 		}
148 
149 		ITEM_POOL* const item_pool = GetItemPool(grid_no, s->bLevel);
150 		if (item_pool)
151 		{
152 			// Update visiblity
153 			if (!closing)
154 			{
155 				bool do_humm     = true;
156 				bool do_locators = true;
157 
158 				if (s->bTeam != OUR_TEAM)
159 				{
160 					do_humm     = false;
161 					do_locators = false;
162 				}
163 
164 				// Look for ownership here
165 				if (GetWorldItem(item_pool->iItemIndex).o.usItem == OWNERSHIP)
166 				{
167 					do_humm = false;
168 					MakeCharacterDialogueEventDoBattleSound(*s, BATTLE_SOUND_NOTHING, 500);
169 				}
170 
171 				// If now open, set visible
172 				SetItemsVisibilityOn(grid_no, s->bLevel, ANY_VISIBILITY_VALUE, do_locators);
173 
174 				// ATE: Check now many things in pool
175 				if (!did_missing_quote)
176 				{
177 					if (item_pool->pNext && item_pool->pNext->pNext)
178 					{
179 						MakeCharacterDialogueEventDoBattleSound(*s, BATTLE_SOUND_COOL1, 500);
180 					}
181 				else if (do_humm)
182 				{
183 					MakeCharacterDialogueEventDoBattleSound(*s, BATTLE_SOUND_HUMM, 500);
184 				}
185 				}
186 			}
187 			else
188 			{
189 				SetItemsVisibilityHidden(grid_no, s->bLevel);
190 			}
191 		}
192 		else
193 		{
194 			if (!closing)
195 			{
196 				MakeCharacterDialogueEventDoBattleSound(*s, BATTLE_SOUND_NOTHING, 500);
197 			}
198 		}
199 	}
200 
201 	STRUCTURE* const new_structure = SwapStructureForPartner(structure);
202 	if (new_structure)
203 	{
204 		RecompileLocalMovementCosts(grid_no);
205 		SetRenderFlags(RENDER_FLAG_FULL);
206 		if (new_structure->fFlags & STRUCTURE_SWITCH)
207 		{ // Just turned a switch on!
208 			ActivateSwitchInGridNo(s, grid_no);
209 		}
210 	}
211 }
212 
213 
GetInteractiveTileCursor(UICursorID const old_cursor,BOOLEAN const confirm)214 UICursorID GetInteractiveTileCursor(UICursorID const old_cursor, BOOLEAN const confirm)
215 {
216 	GridNo                 grid_no;
217 	STRUCTURE*             structure;
218 	LEVELNODE const* const int_node = GetCurInteractiveTileGridNoAndStructure(&grid_no, &structure);
219 	if (!int_node || !structure) return old_cursor;
220 
221 	if (structure->fFlags & STRUCTURE_ANYDOOR)
222 	{
223 		SetDoorString(grid_no);
224 	}
225 	else if (structure->fFlags & STRUCTURE_SWITCH)
226 	{
227 		SetIntTileLocationText(gzLateLocalizedString[STR_LATE_25]);
228 	}
229 	return confirm ? OKHANDCURSOR_UICURSOR : NORMALHANDCURSOR_UICURSOR;
230 }
231 
232 
SetActionModeDoorCursorText()233 void SetActionModeDoorCursorText()
234 {
235 	// If we are over a merc, don't
236 	if (gUIFullTarget) return;
237 
238 	GridNo     grid_no;
239 	STRUCTURE* structure;
240 	LEVELNODE const* const int_node = GetCurInteractiveTileGridNoAndStructure(&grid_no, &structure);
241 	if (!int_node || !structure)                  return;
242 	if (!(structure->fFlags & STRUCTURE_ANYDOOR)) return;
243 	SetDoorString(grid_no);
244 }
245 
246 
GetLevelNodeScreenRect(LEVELNODE const & n,SGPRect & rect,INT16 const x,INT16 const y,GridNo const gridno)247 static void GetLevelNodeScreenRect(LEVELNODE const& n, SGPRect& rect, INT16 const x, INT16 const y, GridNo const gridno)
248 {
249 	// Get 'TRUE' merc position
250 	INT16 sTempX_S;
251 	INT16 sTempY_S;
252 	INT16 const offset_x = x - gsRenderCenterX;
253 	INT16 const offset_y = y - gsRenderCenterY;
254 	FromCellToScreenCoordinates(offset_x, offset_y, &sTempX_S, &sTempY_S);
255 
256 	ETRLEObject const* pTrav;
257 	if (n.uiFlags & LEVELNODE_CACHEDANITILE)
258 	{
259 		ANITILE const& a = *n.pAniTile;
260 		pTrav = &gpTileCache[a.sCachedTileID].pImagery->vo->SubregionProperties(a.sCurrentFrame);
261 	}
262 	else
263 	{
264 		TILE_ELEMENT const* te = &gTileDatabase[n.usIndex];
265 		// Adjust for current frames and animations
266 		if (te->uiFlags & ANIMATED_TILE)
267 		{
268 			TILE_ANIMATION_DATA const& a = *te->pAnimData;
269 			te = &gTileDatabase[a.pusFrames[a.bCurrentFrame]];
270 		}
271 		else if (n.uiFlags & LEVELNODE_ANIMATION && n.sCurrentFrame != -1)
272 		{
273 			te = &gTileDatabase[te->pAnimData->pusFrames[n.sCurrentFrame]];
274 		}
275 		pTrav = &te->hTileSurface->SubregionProperties(te->usRegionIndex);
276 	}
277 
278 	INT16 sScreenX = (g_ui.m_tacticalMapCenterX) + (INT16)sTempX_S;
279 	INT16 sScreenY = (g_ui.m_tacticalMapCenterY) + (INT16)sTempY_S;
280 
281 	// Adjust for offset position on screen
282 	sScreenX -= gsRenderWorldOffsetX;
283 	sScreenY -= gsRenderWorldOffsetY;
284 	sScreenY -=	gpWorldLevelData[gridno].sHeight;
285 
286 	// Adjust based on interface level
287 	if (gsInterfaceLevel > 0)
288 	{
289 		sScreenY += ROOF_LEVEL_HEIGHT;
290 	}
291 
292 	// Adjust for render height
293 	sScreenY += gsRenderHeight;
294 
295 	// Add to start position of dest buffer
296 	sScreenX += pTrav->sOffsetX - WORLD_TILE_X / 2;
297 	sScreenY += pTrav->sOffsetY - WORLD_TILE_Y / 2;
298 
299 	// Adjust y offset!
300 	sScreenY += WORLD_TILE_Y / 2;
301 
302 	rect.iLeft   = sScreenX;
303 	rect.iTop    = sScreenY;
304 	rect.iRight  = sScreenX + pTrav->usWidth;
305 	rect.iBottom = sScreenY + pTrav->usHeight;
306 }
307 
308 
309 static bool RefineLogicOnStruct(GridNo, LEVELNODE const&);
310 static BOOLEAN RefinePointCollisionOnStruct(INT16 sTestX, INT16 sTestY, INT16 sSrcX, INT16 sSrcY, LEVELNODE const&);
311 
312 
LogMouseOverInteractiveTile(INT16 const sGridNo)313 void LogMouseOverInteractiveTile(INT16 const sGridNo)
314 {
315 	// OK, for now, don't allow any interactive tiles on higher interface level!
316 	if (gsInterfaceLevel > 0) return;
317 
318 	// Also, don't allow for mercs who are on upper level
319 	SOLDIERTYPE const* const sel = GetSelectedMan();
320 	if (sel && sel->bLevel == 1) return;
321 
322 	// Get World XY From gridno
323 	INT16 sXMapPos;
324 	INT16 sYMapPos;
325 	ConvertGridNoToCellXY(sGridNo, &sXMapPos, &sYMapPos);
326 
327 	// Set mouse stuff
328 	INT16 const sScreenX = gusMouseXPos;
329 	INT16 const sScreenY = gusMouseYPos;
330 
331 	for (LEVELNODE const* n = gpWorldLevelData[sGridNo].pStructHead; n; n = n->pNext)
332 	{
333 		SGPRect aRect;
334 		GetLevelNodeScreenRect(*n, aRect, sXMapPos, sYMapPos, sGridNo);
335 
336 		// Make sure we are always on guy if we are on same gridno
337 		if (!IsPointInScreenRect(sScreenX, sScreenY, aRect)) continue;
338 
339 		if (!RefinePointCollisionOnStruct(sScreenX, sScreenY, aRect.iLeft, aRect.iBottom, *n)) continue;
340 
341 		if (!RefineLogicOnStruct(sGridNo, *n)) continue;
342 
343 		gCurIntTile.fFound = TRUE;
344 
345 		if (gfCycleIntTile) continue;
346 
347 		// Accumulate them!
348 		gCurIntTileStack.bTiles[gCurIntTileStack.bNum].pFoundNode   = n;
349 		gCurIntTileStack.bTiles[gCurIntTileStack.bNum].sFoundGridNo = sGridNo;
350 		gCurIntTileStack.bNum++;
351 
352 		// Determine if it's the best one
353 		if (aRect.iBottom <= gCurIntTile.sHeighestScreenY) continue;
354 
355 		gCurIntTile.sHeighestScreenY = aRect.iBottom;
356 
357 		gCurIntTile.pFoundNode   = n;
358 		gCurIntTile.sFoundGridNo = sGridNo;
359 
360 		// Set stack current one
361 		gCurIntTileStack.bCur = gCurIntTileStack.bNum - 1;
362 	}
363 }
364 
365 
InternalGetCurInteractiveTile(const BOOLEAN fRejectItemsOnTop)366 static LEVELNODE* InternalGetCurInteractiveTile(const BOOLEAN fRejectItemsOnTop)
367 {
368 	if (_KeyDown(SHIFT)) return NULL;
369 	if (!gfOverIntTile)  return NULL;
370 
371 	LEVELNODE* n = gpWorldLevelData[gCurIntTile.sGridNo].pStructHead;
372 	for (; n != NULL; n = n->pNext)
373 	{
374 		if (n->usIndex != gCurIntTile.sTileIndex) continue;
375 		if (fRejectItemsOnTop && gCurIntTile.fStructure)
376 		{
377 			// get strucuture here...
378 			STRUCTURE* const s = FindStructureByID(gCurIntTile.sGridNo, gCurIntTile.usStructureID);
379 			if (s == NULL || s->fFlags & STRUCTURE_HASITEMONTOP) return NULL;
380 		}
381 		break;
382 	}
383 	return n;
384 }
385 
386 
GetCurInteractiveTile(void)387 LEVELNODE* GetCurInteractiveTile(void)
388 {
389 	return InternalGetCurInteractiveTile(TRUE);
390 }
391 
392 
GetCurInteractiveTileGridNo(INT16 * const psGridNo)393 LEVELNODE* GetCurInteractiveTileGridNo(INT16* const psGridNo)
394 {
395 	LEVELNODE* const n = GetCurInteractiveTile();
396 	*psGridNo = (n != NULL ? gCurIntTile.sGridNo : NOWHERE);
397 	return n;
398 }
399 
400 
ConditionalGetCurInteractiveTileGridNoAndStructure(INT16 * const psGridNo,STRUCTURE ** const ppStructure,const BOOLEAN fRejectOnTopItems)401 LEVELNODE* ConditionalGetCurInteractiveTileGridNoAndStructure(INT16* const psGridNo, STRUCTURE** const ppStructure, const BOOLEAN fRejectOnTopItems)
402 {
403 	GridNo     g = NOWHERE;
404 	STRUCTURE* s = NULL;
405 	LEVELNODE* n = InternalGetCurInteractiveTile(fRejectOnTopItems);
406 	if (n != NULL)
407 	{
408 		g = gCurIntTile.sGridNo;
409 		if (gCurIntTile.fStructure)
410 		{
411 			s = FindStructureByID(g, gCurIntTile.usStructureID);
412 			if (s == NULL) n = NULL;
413 		}
414 	}
415 	*ppStructure = s;
416 	*psGridNo    = g;
417 	return n;
418 }
419 
420 
GetCurInteractiveTileGridNoAndStructure(INT16 * const psGridNo,STRUCTURE ** const ppStructure)421 LEVELNODE* GetCurInteractiveTileGridNoAndStructure(INT16* const psGridNo, STRUCTURE** const ppStructure)
422 {
423 	return ConditionalGetCurInteractiveTileGridNoAndStructure(psGridNo, ppStructure, TRUE);
424 }
425 
426 
BeginCurInteractiveTileCheck(void)427 void BeginCurInteractiveTileCheck(void)
428 {
429 	gfOverIntTile = FALSE;
430 
431 	// OK, release our stack, stuff could be different!
432 	gfCycleIntTile = FALSE;
433 
434 	// Reset some highest values
435 	gCurIntTile.sHeighestScreenY = 0;
436 	gCurIntTile.fFound           = FALSE;
437 
438 	// Reset stack values
439 	gCurIntTileStack.bNum = 0;
440 
441 }
442 
443 
EndCurInteractiveTileCheck()444 void EndCurInteractiveTileCheck()
445 {
446 	if (gCurIntTile.fFound)
447 	{ // We are over this cycled node or levelnode
448 		CUR_INTERACTIVE_TILE const& cur_int_tile =
449 			gfCycleIntTile ? gCurIntTileStack.bTiles[gCurIntTileStack.bCur] :
450 			gCurIntTile;
451 
452 		gCurIntTile.sGridNo    = cur_int_tile.sFoundGridNo;
453 		gCurIntTile.sTileIndex = cur_int_tile.pFoundNode->usIndex;
454 
455 		if (cur_int_tile.pFoundNode->pStructureData)
456 		{
457 			gCurIntTile.usStructureID = cur_int_tile.pFoundNode->pStructureData->usStructureID;
458 			gCurIntTile.fStructure    = TRUE;
459 		}
460 		else
461 		{
462 			gCurIntTile.fStructure = FALSE;
463 		}
464 
465 		gfOverIntTile = TRUE;
466 	}
467 	else
468 	{ // If we are in cycle mode, end it
469 		gfCycleIntTile = FALSE;
470 	}
471 }
472 
473 
RefineLogicOnStruct(INT16 gridno,LEVELNODE const & n)474 static bool RefineLogicOnStruct(INT16 gridno, LEVELNODE const& n)
475 {
476 	if (n.uiFlags & LEVELNODE_CACHEDANITILE) return false;
477 
478 	// See if we are on an interactable tile!
479 	// Try and get struct data from levelnode pointer
480 	if (!n.pStructureData) return false; // If no data, quit
481 	STRUCTURE const& structure = *n.pStructureData;
482 
483 	if (!(structure.fFlags & (STRUCTURE_OPENABLE | STRUCTURE_HASITEMONTOP))) return false;
484 
485 	SOLDIERTYPE const* const sel = GetSelectedMan();
486 	if (sel && sel->ubBodyType == ROBOTNOWEAPON) return false;
487 
488 	if (structure.fFlags & STRUCTURE_ANYDOOR)
489 	{ // A door, we need a different definition of being visible than other structs
490 		if (!IsDoorVisibleAtGridNo(gridno)) return false;
491 
492 		// For a OPENED door, addition requirements are: need to be in 'HAND CURSOR' mode
493 		if (structure.fFlags & STRUCTURE_OPEN &&
494 			gCurrentUIMode != HANDCURSOR_MODE &&
495 			gCurrentUIMode != ACTION_MODE)
496 		{
497 			return false;
498 		}
499 
500 		if (!gGameSettings.fOptions[TOPTION_SNAP_CURSOR_TO_DOOR] &&
501 			gCurrentUIMode != HANDCURSOR_MODE)
502 		{
503 			return false;
504 		}
505 
506 		return true;
507 	}
508 	else if (structure.fFlags & STRUCTURE_SWITCH)
509 	{ // A switch, reject in another direction
510 		// Find a new gridno based on switch's orientation
511 		switch (structure.pDBStructureRef->pDBStructure->ubWallOrientation)
512 		{
513 			case OUTSIDE_TOP_LEFT:
514 			case INSIDE_TOP_LEFT:
515 				// Move south
516 				gridno = NewGridNo(gridno, DirectionInc(SOUTH));
517 				break;
518 
519 			case OUTSIDE_TOP_RIGHT:
520 			case INSIDE_TOP_RIGHT:
521 				// Move east
522 				gridno = NewGridNo(gridno, DirectionInc(EAST));
523 				break;
524 
525 			default: return true; // XXX exception?
526 		}
527 	}
528 
529 	// If we are hidden by a roof, reject it!
530 	if (!gfBasement && IsRoofVisible(gridno) && !(gTacticalStatus.uiFlags & SHOW_ALL_ITEMS))
531 	{
532 		return false;
533 	}
534 
535 	return true;
536 }
537 
538 
RefinePointCollisionOnStruct(INT16 const test_x,INT16 const test_y,INT16 const src_x,INT16 const src_y,LEVELNODE const & n)539 static BOOLEAN RefinePointCollisionOnStruct(INT16 const test_x, INT16 const test_y, INT16 const src_x, INT16 const src_y, LEVELNODE const& n)
540 {
541 	HVOBJECT vo;
542 	UINT16   idx;
543 	if (n.uiFlags & LEVELNODE_CACHEDANITILE)
544 	{
545 		ANITILE const& a = *n.pAniTile;
546 		vo  = gpTileCache[a.sCachedTileID].pImagery->vo;
547 		idx = a.sCurrentFrame;
548 	}
549 	else
550 	{
551 		TILE_ELEMENT const* te = &gTileDatabase[n.usIndex];
552 		// Adjust for current frames and animations
553 		if (te->uiFlags & ANIMATED_TILE)
554 		{
555 			TILE_ANIMATION_DATA const& a = *te->pAnimData;
556 			te = &gTileDatabase[a.pusFrames[a.bCurrentFrame]];
557 		}
558 		else if (n.uiFlags & LEVELNODE_ANIMATION && n.sCurrentFrame != -1)
559 		{
560 			te = &gTileDatabase[te->pAnimData->pusFrames[n.sCurrentFrame]];
561 		}
562 		vo  = te->hTileSurface;
563 		idx = te->usRegionIndex;
564 	}
565 	return CheckVideoObjectScreenCoordinateInData(vo, idx, test_x - src_x, -(test_y - src_y));
566 }
567 
568 
569 // This function will check the video object at SrcX and SrcY for the lack of transparency
570 // will return true if data found, else false
CheckVideoObjectScreenCoordinateInData(HVOBJECT hSrcVObject,UINT16 usIndex,INT32 iTestX,INT32 iTestY)571 BOOLEAN CheckVideoObjectScreenCoordinateInData(HVOBJECT hSrcVObject, UINT16 usIndex, INT32 iTestX, INT32 iTestY)
572 {
573 	BOOLEAN fDataFound = FALSE;
574 	INT32   iTestPos, iStartPos;
575 
576 	// Assertions
577 	Assert( hSrcVObject != NULL );
578 
579 	// Get Offsets from Index into structure
580 	ETRLEObject const& pTrav    = hSrcVObject->SubregionProperties(usIndex);
581 	UINT32             usHeight = pTrav.usHeight;
582 	UINT32      const  usWidth  = pTrav.usWidth;
583 
584 	// Calculate test position we are looking for!
585 	// Calculate from 0, 0 at top left!
586 	iTestPos	= ( ( usHeight - iTestY ) * usWidth ) + iTestX;
587 	iStartPos	= 0;
588 
589 	UINT8 const* SrcPtr = hSrcVObject->PixData(pTrav);
590 
591 	do
592 	{
593 		for (;;)
594 		{
595 			UINT8 PxCount = *SrcPtr++;
596 			if (PxCount == 0) break;
597 			if (PxCount & 0x80)
598 			{
599 				PxCount &= 0x7F;
600 			}
601 			else
602 			{
603 				if (iStartPos < iTestPos && iTestPos <= iStartPos + PxCount) return TRUE;
604 				SrcPtr += PxCount;
605 			}
606 			iStartPos += PxCount;
607 		}
608 		if (iStartPos >= iTestPos) break;
609 	}
610 	while (--usHeight > 0);
611 	return(fDataFound);
612 
613 }
614 
615 
ShouldCheckForMouseDetections()616 BOOLEAN ShouldCheckForMouseDetections( )
617 {
618 	BOOLEAN fOK = FALSE;
619 
620 	if (gsINTOldRenderCenterX != gsRenderCenterX || gsINTOldRenderCenterY != gsRenderCenterY ||
621 		gusINTOldMousePosX != gusMouseXPos || gusINTOldMousePosY != gusMouseYPos)
622 	{
623 		fOK = TRUE;
624 	}
625 
626 	// Set old values
627 	gsINTOldRenderCenterX = gsRenderCenterX;
628 	gsINTOldRenderCenterY = gsRenderCenterY;
629 
630 	gusINTOldMousePosX		= gusMouseXPos;
631 	gusINTOldMousePosY		= gusMouseYPos;
632 
633 	return( fOK );
634 }
635 
636 
CycleIntTileFindStack(UINT16 usMapPos)637 void CycleIntTileFindStack( UINT16 usMapPos )
638 {
639 	gfCycleIntTile = TRUE;
640 
641 	// Cycle around!
642 	gCurIntTileStack.bCur++;
643 
644 	//PLot new movement
645 	gfPlotNewMovement = TRUE;
646 
647 	if ( gCurIntTileStack.bCur == gCurIntTileStack.bNum )
648 	{
649 		gCurIntTileStack.bCur = 0;
650 	}
651 }
652