1 #include "Handle_Items.h"
2 #include "Isometric_Utils.h"
3 #include "Structure.h"
4 #include "TileDat.h"
5 #include "WorldDef.h"
6 #include "Render_Fun.h"
7 #include "RenderWorld.h"
8 #include "Dialogue_Control.h"
9 #include "Structure_Wrap.h"
10 #include "PathAI.h"
11 #include "Overhead.h"
12 #include "Smell.h"
13 #include "FOV.h"
14 #include "Rotting_Corpses.h"
15 #include "Keys.h"
16 #include "Random.h"
17 #include "Input.h"
18 #include "Exit_Grids.h"
19 #include "Environment.h"
20 #include "WorldMan.h"
21 #include "Fog_Of_War.h"
22 #include "StrategicMap.h"
23 #include "Boxing.h"
24 #include "OppList.h"
25 #include "Lighting.h"
26 #include "Soldier_Macros.h"
27 
28 #ifdef _DEBUG
29 #include "Font.h"
30 #include "Font_Control.h"
31 #include "Timer_Control.h"
32 #include "Video.h"
33 #endif
34 
35 #include <string_theory/format>
36 
37 #include <algorithm>
38 #include <iterator>
39 
40 /* view directions */
41 #define DLEFT           0
42 #define DRIGHT          1
43 #define UP              2
44 #define LEFT            3
45 #define RIGHT           4
46 #define NOVIEW          5
47 #define MAXVIEWPATHS    17
48 #define VIEWPATHLENGTH  13
49 
50 UINT8 gubGridNoMarkers[ WORLD_MAX ];
51 UINT8 gubGridNoValue          = 254;
52 
53 #ifdef _DEBUG
54 UINT8 gubFOVDebugInfoInfo[ WORLD_MAX ];
55 #endif
56 
57 
58 UINT8  ViewPath[MAXVIEWPATHS][VIEWPATHLENGTH] = {
59 	{NOVIEW,  UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
60 	{UP,      UP,     UP,     UP,     DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
61 	{UP,      UP,     UP,     UP,     DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
62 	{UP,      UP,     DLEFT,  UP,     DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
63 	{UP,      UP,     DRIGHT, UP,     DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
64 	{UP,      UP,     DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
65 	{UP,      UP,     DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
66 	{UP,      RIGHT,  UP,     DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP    },
67 	{UP,      LEFT,   UP,     DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP    },
68 	{DLEFT,   DLEFT,  DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
69 	{DRIGHT,  DRIGHT, DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP,     UP    },
70 	{RIGHT,   DRIGHT, DRIGHT, DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP,     UP    },
71 	{LEFT,    DLEFT,  DLEFT,  DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP,     UP    },
72 	{DLEFT,   LEFT,   LEFT,   UP,     NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
73 	{LEFT,    LEFT,   LEFT,   UP,     LEFT,   NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
74 	{DRIGHT,  RIGHT,  RIGHT,  UP,     NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
75 	{RIGHT,   RIGHT,  RIGHT,  UP,     RIGHT,  NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW}
76 };
77 
78 UINT8  ViewPath2[MAXVIEWPATHS][VIEWPATHLENGTH]= {
79 	{NOVIEW,  UP,     UP,     UP,     UP,     UP,     UP,     NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
80 	{UP,      UP,     DLEFT,  UP,     UP,     UP,     DLEFT,  DRIGHT, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
81 	{UP,      UP,     DLEFT,  UP,     UP,     UP,     DRIGHT, DLEFT,  NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
82 	{UP,      UP,     DLEFT,  UP,     UP,     DLEFT,  DLEFT,  UP,     NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
83 	{UP,      UP,     DRIGHT, UP,     UP,     DRIGHT, DRIGHT, UP,     NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
84 	{UP,      DLEFT,  UP,     UP,     DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP    },
85 	{UP,      DRIGHT, UP,     UP,     DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP    },
86 	{DLEFT,   DLEFT,  UP,     UP,     DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP    },
87 	{DRIGHT,  DRIGHT, UP,     UP,     DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP    },
88 	{DLEFT,   DLEFT,  UP,     DLEFT,  DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP    },
89 	{DRIGHT,  DRIGHT, UP,     DRIGHT, DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP    },
90 	{DLEFT,   DLEFT,  DLEFT,  DLEFT,  DLEFT,  DLEFT,  DLEFT,  UP,     UP,     UP,     UP,     UP,     UP    },
91 	{DRIGHT,  DRIGHT, DRIGHT, DRIGHT, DRIGHT, DRIGHT, DRIGHT, UP,     UP,     UP,     UP,     UP,     UP    },
92 	{DLEFT,   LEFT,   DLEFT,  NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
93 	{DRIGHT,  RIGHT,  DRIGHT, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
94 	{LEFT,    LEFT,   DLEFT,  NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW},
95 	{RIGHT,   RIGHT,  DRIGHT, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW, NOVIEW}
96 };
97 
98 
BuildSightDir(UINT32 dir,UINT32 * One,UINT32 * Two,UINT32 * Three,UINT32 * Four,UINT32 * Five)99 static void BuildSightDir(UINT32 dir, UINT32* One, UINT32* Two, UINT32* Three, UINT32* Four, UINT32* Five)
100 {
101 	switch(dir)
102 	{
103 		case NORTH:
104 			*One   = NORTHWEST;
105 			*Two   = NORTHEAST;
106 			*Three = NORTH;
107 			*Four  = WEST;
108 			*Five  = EAST;
109 			break;
110 		case NORTHEAST:
111 			*One = NORTH;
112 			*Two = EAST;
113 			*Three = NORTHEAST;
114 			*Four   = NORTHWEST;
115 			*Five  = SOUTHEAST;
116 			break;
117 		case EAST:
118 			*One  = NORTHEAST;
119 			*Two = SOUTHEAST;
120 			*Three = EAST;
121 			*Four = NORTH;
122 			*Five = SOUTH;
123 			break;
124 		case SOUTHEAST:
125 			*One = EAST;
126 			*Two = SOUTH;
127 			*Three = SOUTHEAST;
128 			*Four = NORTHEAST;
129 			*Five = SOUTHWEST;
130 			break;
131 		case SOUTH:
132 			*One = SOUTHEAST;
133 			*Two = SOUTHWEST;
134 			*Three = SOUTH;
135 			*Four = EAST;
136 			*Five = WEST;
137 			break;
138 		case SOUTHWEST:
139 			*One = SOUTH;
140 			*Two = WEST;
141 			*Three = SOUTHWEST;
142 			*Four = SOUTHEAST;
143 			*Five = NORTHWEST;
144 			break;
145 		case WEST:
146 			*One = SOUTHWEST;
147 			*Two = NORTHWEST;
148 			*Three = WEST;
149 			*Four = SOUTH;
150 			*Five = NORTH;
151 			break;
152 		case NORTHWEST:
153 			*One = WEST;
154 			*Two = NORTH;
155 			*Three = NORTHWEST;
156 			*Four = SOUTHWEST;
157 			*Five = NORTHEAST;
158 			break;
159 		default:
160 			break;
161 	}
162 }
163 
164 #define NUM_SLANT_ROOF_SLOTS  200
165 
166 struct SLANT_ROOF_FOV_TYPE
167 {
168 	INT16   sGridNo;
169 	BOOLEAN fAllocated;
170 };
171 
172 SLANT_ROOF_FOV_TYPE gSlantRoofData[ NUM_SLANT_ROOF_SLOTS ];
173 UINT32              guiNumSlantRoofs = 0;
174 
GetFreeSlantRoof(void)175 static INT32 GetFreeSlantRoof(void)
176 {
177 	UINT32 uiCount;
178 
179 	for(uiCount=0; uiCount < guiNumSlantRoofs; uiCount++)
180 	{
181 		if( gSlantRoofData[uiCount].fAllocated==FALSE  )
182 			return( (INT32)uiCount );
183 	}
184 
185 	if( guiNumSlantRoofs < NUM_SLANT_ROOF_SLOTS )
186 		return( (INT32) guiNumSlantRoofs++ );
187 
188 	return( -1 );
189 }
190 
ClearSlantRoofs(void)191 void ClearSlantRoofs( void )
192 {
193 	UINT32 uiCount;
194 
195 	for( uiCount = 0; uiCount < guiNumSlantRoofs; uiCount++ )
196 	{
197 		if( ( gSlantRoofData[uiCount].fAllocated ) )
198 		{
199 			gSlantRoofData[uiCount].fAllocated = FALSE;
200 		}
201 	}
202 	guiNumSlantRoofs = 0;
203 }
204 
FindSlantRoofSlot(INT16 sGridNo)205 static BOOLEAN FindSlantRoofSlot(INT16 sGridNo)
206 {
207 	UINT32 uiCount;
208 
209 	for( uiCount = 0; uiCount < guiNumSlantRoofs; uiCount++ )
210 	{
211 		if( ( gSlantRoofData[uiCount].fAllocated ) )
212 		{
213 			if ( gSlantRoofData[uiCount].sGridNo == sGridNo )
214 			{
215 				return( TRUE );
216 			}
217 		}
218 	}
219 	return( FALSE );
220 }
221 
AddSlantRoofFOVSlot(INT16 sGridNo)222 void AddSlantRoofFOVSlot( INT16 sGridNo )
223 {
224 	INT32               iSlantRoofSlot;
225 	SLANT_ROOF_FOV_TYPE *pSlantRoof;
226 
227 	// Check if this is a duplicate!
228 	if ( FindSlantRoofSlot( sGridNo ) )
229 	{
230 		return;
231 	}
232 
233 	iSlantRoofSlot = GetFreeSlantRoof( );
234 
235 	if ( iSlantRoofSlot != -1 )
236 	{
237 		pSlantRoof = &gSlantRoofData[ iSlantRoofSlot ];
238 		pSlantRoof->sGridNo = sGridNo;
239 		pSlantRoof->fAllocated = TRUE;
240 	}
241 }
242 
ExamineSlantRoofFOVSlots()243 void ExamineSlantRoofFOVSlots( )
244 {
245 	UINT32 uiCount;
246 
247 	for( uiCount = 0; uiCount < guiNumSlantRoofs; uiCount++ )
248 	{
249 		if( ( gSlantRoofData[uiCount].fAllocated ) )
250 		{
251 			ExamineGridNoForSlantRoofExtraGraphic( gSlantRoofData[uiCount].sGridNo );
252 		}
253 	}
254 	ClearSlantRoofs( );
255 }
256 
257 
RevealRoofsAndItems(SOLDIERTYPE * const pSoldier,const BOOLEAN fShowLocators)258 void RevealRoofsAndItems(SOLDIERTYPE* const pSoldier, const BOOLEAN fShowLocators)
259 {
260 	const UINT8 ubLevel = pSoldier->bLevel;
261 	STRUCTURE*  pStructure, *pDummy;
262 	UINT32  maincnt,markercnt,marker,tilesLeftToSee,cnt,prevmarker;
263 	INT8    Blocking, markerDir;
264 	INT8    nextDir = 0;
265 	UINT8   dir,range,Path2;
266 	UINT8   ubRoomNo;
267 	UINT8   ubMovementCost;
268 	BOOLEAN fTravelCostObs;
269 	BOOLEAN fGoneThroughDoor = FALSE;
270 	BOOLEAN fThroughWindow = FALSE;
271 	BOOLEAN fItemsQuoteSaid = FALSE;
272 	BOOLEAN fRevealItems = TRUE;
273 	BOOLEAN fStopRevealingItemsAfterThisTile = FALSE;
274 	INT8    bTallestStructureHeight;
275 	INT32   iDoorGridNo;
276 	INT8    bStructHeight;
277 	INT8    bThroughWindowDirection = -1; // XXX HACK000E
278 
279 	if ( pSoldier->uiStatusFlags & SOLDIER_ENEMY )
280 	{
281 		//pSoldier->needToLookForItems = FALSE;
282 		return;
283 	}
284 
285 	if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
286 	{
287 		return;
288 	}
289 
290 	// Return if this guy has no gridno, has bad life, etc
291 	if( pSoldier->sGridNo == NOWHERE || !pSoldier->bInSector || pSoldier->bLife < OKLIFE )
292 	{
293 		return;
294 	}
295 
296 	if (pSoldier->bBlindedCounter > 0)
297 	{
298 		return;
299 	}
300 	gubGridNoValue++;
301 
302 	if ( gubGridNoValue == 255 )
303 	{
304 		//Reset!
305 		std::fill(std::begin(gubGridNoMarkers), std::end(gubGridNoMarkers), 0);
306 		gubGridNoValue = 1;
307 	}
308 
309 	// OK, look for doors
310 	MercLooksForDoors(*pSoldier);
311 
312 	dir = pSoldier->bDirection;
313 
314 	// a gassed merc can only see 1 tile away due to blurred vision
315 	if ( pSoldier->uiStatusFlags & SOLDIER_GASSED )
316 	{
317 		range = GASSED_VIEW_RANGE;
318 	}
319 	else
320 	{
321 		range = NORMAL_VIEW_RANGE;
322 		// balance item viewing range between normal and the limit set by opplist-type functions -- CJC
323 		range = (AdjustMaxSightRangeForEnvEffects(LightTrueLevel(pSoldier->sGridNo, pSoldier->bLevel), range) + range) / 2;
324 	}
325 
326 	UINT32 Dir[6];
327 	BuildSightDir(dir,&Dir[0],&Dir[1],&Dir[2],&Dir[3],&Dir[4]);
328 	INT32 Inc[6];
329 	for (cnt = 0; cnt < 5; cnt++)
330 		Inc[cnt] = DirectionInc(Dir[cnt]);
331 
332 	// create gridno increment for NOVIEW - in other words, no increment!
333 	Inc[5] = 0;
334 	Dir[5] = pSoldier->bDirection;
335 
336 	if (dir % 2 == 1)     /* even numbers use ViewPath2 */
337 		Path2 = TRUE;
338 	else
339 		Path2 = FALSE;
340 
341 
342 	// ATE: if in this special cercumstance... our guys are moving on their own...
343 	// Stop sighting items
344 	// IN the future, we may want to do something else here...
345 	const BOOLEAN itemsToo = !(gTacticalStatus.uiFlags & OUR_MERCS_AUTO_MOVE);
346 
347 	for (maincnt = 0; maincnt < MAXVIEWPATHS; maincnt++)
348 	{
349 		marker = pSoldier->sGridNo;
350 		Blocking = FALSE;
351 		tilesLeftToSee = 99;
352 		fRevealItems = TRUE;
353 		fStopRevealingItemsAfterThisTile = FALSE;
354 
355 #ifdef _DEBUG
356 		if (_KeyDown(SDLK_NUMLOCKCLEAR))
357 		{
358 			std::fill(std::begin(gubFOVDebugInfoInfo), std::end(gubFOVDebugInfoInfo), 0);
359 			SetRenderFlags( RENDER_FLAG_FULL );
360 			RenderWorld( );
361 		}
362 #endif
363 
364 		for (markercnt = 0; markercnt < range; markercnt++)
365 		{
366 			//fGoneThroughDoor = FALSE;
367 			//fThroughWindow   = FALSE;
368 			prevmarker = marker;
369 
370 			nextDir = 99;
371 			fTravelCostObs = FALSE;
372 			if ( fStopRevealingItemsAfterThisTile )
373 			{
374 				fRevealItems = FALSE;
375 				fStopRevealingItemsAfterThisTile = FALSE;
376 			}
377 			if (Path2)
378 			{
379 				markerDir = ViewPath2[maincnt][markercnt];
380 				if (markercnt < 12)
381 					nextDir = ViewPath2[maincnt][markercnt+1];
382 			}
383 			else
384 			{
385 				markerDir = ViewPath[maincnt][markercnt];
386 				if (markercnt < 12)
387 					nextDir = ViewPath[maincnt][markercnt+1];
388 			}
389 
390 			// OK, check flags for going through door/window last tile
391 			if ( fThroughWindow == 1 )
392 			{
393 				// ATE: Make sure we are going through the same direction!
394 				// THis is to solve the drassen SAM problem with seeing through walls
395 				if ( static_cast<INT8>(Dir[markerDir]) == bThroughWindowDirection)
396 				{
397 					fThroughWindow = 2;
398 				}
399 				else
400 				{
401 					fThroughWindow = 0;
402 				}
403 			}
404 			else if ( fThroughWindow == 2 )
405 			{
406 				// We've overstayed our welcome - remove!
407 				fThroughWindow = 0;
408 			}
409 
410 			if ( fGoneThroughDoor == 1 )
411 			{
412 				fGoneThroughDoor = 2;
413 			}
414 			else if ( fGoneThroughDoor == 2 )
415 			{
416 				// We've overstayed our welcome - remove!
417 				fGoneThroughDoor = 0;
418 			}
419 
420 			//ATE CHECK FOR NOVIEW!
421 			if ( nextDir == NOVIEW )
422 			{
423 				nextDir = 99;
424 			}
425 
426 			marker = NewGridNo((INT16)marker,(INT16)Inc[markerDir]);
427 
428 			// End if this is a no view...
429 			if ( markerDir == NOVIEW && markercnt != 0 )
430 			{
431 				break;
432 			}
433 
434 #ifdef _DEBUG
435 			if (_KeyDown(SDLK_NUMLOCKCLEAR))
436 			{
437 				int cnt = GetJA2Clock( );
438 
439 				gubFOVDebugInfoInfo[ marker ] = (UINT8)markercnt;
440 				RenderFOVDebug( );
441 				SetFontAttributes(LARGEFONT1, FONT_MCOLOR_WHITE);
442 				MPrint( 10,  10 , ST::format("{}", maincnt) );
443 				//MPrint( 10,  20 , ST::format("{}", marker) );
444 				//MPrint( 50,  20 , ST::format("{}", pSoldier->sGridNo) );
445 				InvalidateScreen( );
446 				RefreshScreen();
447 				do
448 				{}
449 				while( ( GetJA2Clock( ) - cnt ) < 250 );
450 			}
451 #endif
452 
453 			// Check if we can get to this gridno from our direction in
454 			ubMovementCost = gubWorldMovementCosts[ marker ][ Dir[ markerDir ] ][ ubLevel ];
455 
456 			// ATE: Added: If our current sector is below ground, ignore any blocks!
457 			if ( gfCaves && ubMovementCost != TRAVELCOST_CAVEWALL )
458 			{
459 				ubMovementCost = TRAVELCOST_FLAT;
460 			}
461 
462 			if ( IS_TRAVELCOST_DOOR( ubMovementCost ) )
463 			{
464 				ubMovementCost = DoorTravelCost(pSoldier, marker, ubMovementCost, pSoldier->bTeam == OUR_TEAM, &iDoorGridNo);
465 				pStructure = FindStructure( (INT16) iDoorGridNo, STRUCTURE_ANYDOOR );
466 				if ( pStructure != NULL && pStructure->fFlags & STRUCTURE_TRANSPARENT)
467 				{
468 					// cell door or somehow otherwise transparent; allow merc to see through
469 					ubMovementCost = TRAVELCOST_FLAT;
470 				}
471 			}
472 
473 			// If we have hit an obstacle, STOP HERE
474 			if ( ubMovementCost >= TRAVELCOST_BLOCKED )
475 			{
476 				// We have an obstacle here...
477 				// If it is bigger than a breadbox... err... taller than a man...
478 				// Then stop path altogether
479 				// otherwise just stop revealing items
480 
481 				// CJC:  only do this when the direction is horizontal; easier and faster to check
482 				// and the effect should still be good enough
483 
484 				if ( ubMovementCost == TRAVELCOST_WALL || ubMovementCost == TRAVELCOST_DOOR || ubMovementCost == TRAVELCOST_EXITGRID )
485 				{
486 					fTravelCostObs = TRUE;
487 					fRevealItems = FALSE;
488 				}
489 				else
490 				{
491 					// walls are handled above, so the blocking object is guaranteed not to be a wall
492 					bTallestStructureHeight = GetTallestStructureHeight( (INT16) marker, FALSE );
493 					if (bTallestStructureHeight >= 3)
494 					{
495 						fTravelCostObs = TRUE;
496 						fStopRevealingItemsAfterThisTile = TRUE;
497 					}
498 					else if ( bTallestStructureHeight != 0 )
499 					{
500 						// stop revealing items after this tile but keep going
501 						fStopRevealingItemsAfterThisTile = TRUE;
502 					}
503 				}
504 
505 				if ( (Dir[markerDir] % 2) == 1 )
506 				{
507 					// diagonal
508 					fTravelCostObs = TRUE;
509 					// cheap hack... don't reveal items
510 					fRevealItems = FALSE;
511 				}
512 				else
513 				{
514 					bTallestStructureHeight = GetTallestStructureHeight( (INT16) marker, FALSE );
515 					if (bTallestStructureHeight >= 3)
516 					{
517 						fTravelCostObs = TRUE;
518 						fStopRevealingItemsAfterThisTile = TRUE;
519 					}
520 					else if ( bTallestStructureHeight != 0 )
521 					{
522 						// stop revealing items after this tile but keep going
523 						fStopRevealingItemsAfterThisTile = TRUE;
524 					}
525 				}
526 			}
527 
528 			// Check if it's been done already!
529 			if ( gubGridNoMarkers[ marker ] != gubGridNoValue )
530 			{
531 				// Mark gridno
532 				gubGridNoMarkers[ marker ] = gubGridNoValue;
533 
534 				// check and see if the gridno changed
535 				// if the gridno is the same, avoid redundancy and break
536 				if (marker==prevmarker && markercnt != 0 )
537 				{
538 
539 				}
540 				else   // it changed
541 				{
542 					// Skip others if we have gone through a door but are too far away....
543 					if ( fGoneThroughDoor )
544 					{
545 						if (markercnt > 5 )   // Are we near the door?
546 						{
547 							break;
548 						}
549 					}
550 					// DO MINE FINDING STUFF
551 					// GET INDEX FOR ITEM HERE
552 					// if there IS a direction after this one, nextdir WILL NOT be 99
553 					if (nextDir != 99)
554 					{
555 						Blocking = GetBlockingStructureInfo( (INT16)marker, (INT8)Dir[ markerDir ], (INT8)Dir[ nextDir ], ubLevel, &bStructHeight, &pDummy, FALSE );
556 					}
557 					else
558 					{
559 						// no "next" direction, so pass in a NOWHERE so that
560 						// "SpecialViewObstruction" will know not to take it UINT32o consideration
561 						Blocking = GetBlockingStructureInfo( (INT16)marker, (INT8)Dir[markerDir], (INT8)30, ubLevel, &bStructHeight, &pDummy, FALSE  );
562 					}
563 
564 					if ( gfCaves )
565 					{
566 						Blocking = NOTHING_BLOCKING;
567 					}
568 
569 					// CHECK FOR ROOMS
570 					if ( Blocking == BLOCKING_TOPLEFT_WINDOW || Blocking == BLOCKING_TOPLEFT_OPEN_WINDOW )
571 					{
572 						// CHECK FACING DIRECTION!
573 						if ( Dir[markerDir] == NORTH || Dir[markerDir] == SOUTH )
574 						{
575 							if (markercnt <= 1 )   // Are we right beside it?
576 							{
577 								fThroughWindow = TRUE;
578 								bThroughWindowDirection = ( INT8 ) Dir[ markerDir ];
579 							}
580 						}
581 					}
582 					if ( Blocking == BLOCKING_TOPRIGHT_WINDOW || Blocking == BLOCKING_TOPRIGHT_OPEN_WINDOW )
583 					{
584 						// CHECK FACING DIRECTION!
585 						if ( Dir[markerDir] == EAST || Dir[markerDir] == WEST )
586 						{
587 							if (markercnt <= 1 )   // Are we right beside it?
588 							{
589 								fThroughWindow = TRUE;
590 								bThroughWindowDirection = ( INT8 ) Dir[ markerDir ];
591 							}
592 						}
593 					}
594 
595 					if ( Blocking == BLOCKING_TOPLEFT_DOOR )
596 					{
597 						fGoneThroughDoor = TRUE;
598 					}
599 					if ( Blocking == BLOCKING_TOPRIGHT_DOOR )
600 					{
601 						fGoneThroughDoor = TRUE;
602 					}
603 
604 					// ATE: If we hit this tile, find item always!
605 					//if (Blocking < FULL_BLOCKING )
606 					{
607 						// Handle special things for our mercs, like uncovering roofs
608 						// and revealing objects...
609 						//gpSoldier->shad |= SEENBIT;
610 
611 						// NOTE: don't allow object viewing if gassed XXX
612 
613 						if (itemsToo && fRevealItems ) // && itemIndex < MAXOBJECTLIST)
614 						{
615 							// OK, look for corpses...
616 							LookForAndMayCommentOnSeeingCorpse( pSoldier, (INT16)marker, ubLevel );
617 
618 							if (SetItemsVisibilityOn(marker, ubLevel, INVISIBLE, fShowLocators))
619 							{
620 								SetRenderFlags(RENDER_FLAG_FULL);
621 
622 								if ( fShowLocators )
623 								{
624 									// Set makred render flags
625 									//gpWorldLevelData[marker].uiFlags|=MAPELEMENT_REDRAW;
626 									//gpWorldLevelData[gusCurMousePos].pTopmostHead->uiFlags |= LEVELNODE_DYNAMIC;
627 									//SetRenderFlags(RENDER_FLAG_MARKED);
628 									SetRenderFlags(RENDER_FLAG_FULL);
629 
630 									// Hault soldier
631 									// ATE: Only if in combat...
632 									if ( gTacticalStatus.uiFlags & INCOMBAT )
633 									{
634 										HaultSoldierFromSighting( pSoldier, FALSE );
635 									}
636 									else
637 									{
638 										// ATE: Make sure we show locators...
639 										gTacticalStatus.fLockItemLocators = FALSE;
640 									}
641 									if (!fItemsQuoteSaid && !gTacticalStatus.fLockItemLocators)
642 									{
643 										gTacticalStatus.fLockItemLocators = TRUE;
644 
645 										if ( gTacticalStatus.ubAttackBusyCount > 0 && ( gTacticalStatus.uiFlags & INCOMBAT ) )
646 										{
647 											gTacticalStatus.fItemsSeenOnAttack           = TRUE;
648 											gTacticalStatus.items_seen_on_attack_soldier = pSoldier;
649 											gTacticalStatus.usItemsSeenOnAttackGridNo    = (INT16)marker;
650 										}
651 										else
652 										{
653 											// Display quote!
654 											if ( !AM_AN_EPC( pSoldier ) )
655 											{
656 												MakeCharacterDialogueEventSignalItemLocatorStart(*pSoldier, marker);
657 											}
658 											else
659 											{
660 												// Turn off item lock for locators...
661 												gTacticalStatus.fLockItemLocators = FALSE;
662 												SlideToLocation((INT16)marker);
663 											}
664 										}
665 										fItemsQuoteSaid = TRUE;
666 									}
667 								}
668 							}
669 						}
670 						tilesLeftToSee--;
671 					}
672 
673 					if (tilesLeftToSee <= 0)
674 						break;
675 
676 					if ( Blocking == FULL_BLOCKING || ( fTravelCostObs && !fThroughWindow ) )
677 					{
678 						break;
679 					}
680 
681 					// CHECK FOR SLANT ROOF!
682 					{
683 						STRUCTURE* pStructure;
684 						pStructure = FindStructure( (INT16)marker, STRUCTURE_SLANTED_ROOF );
685 
686 						if ( pStructure != NULL )
687 						{
688 							// ADD TO SLANTED ROOF LIST!
689 							AddSlantRoofFOVSlot( (INT16)marker );
690 						}
691 					}
692 
693 					// Set gridno as revealed
694 					if ( ubLevel == FIRST_LEVEL )
695 					{
696 						if ( gfBasement || gfCaves )
697 						{
698 							// OK, if we are underground, we don't want to reveal stuff if
699 							// 1 ) there is a roof over us and
700 							// 2 ) we are not in a room
701 							if (gubWorldRoomInfo[marker] != NO_ROOM || TypeRangeExistsInRoofLayer(marker, FIRSTROOF, FOURTHROOF) == NULL)
702 							{
703 								gpWorldLevelData[ marker ].uiFlags |= MAPELEMENT_REVEALED;
704 								if( gfCaves )
705 								{
706 									RemoveFogFromGridNo( marker );
707 								}
708 							}
709 						}
710 						else
711 						{
712 							gpWorldLevelData[ marker ].uiFlags |= MAPELEMENT_REVEALED;
713 						}
714 
715 						// CHECK FOR ROOMS
716 						{
717 							if ( InAHiddenRoom( (INT16)marker, &ubRoomNo ) )
718 							{
719 								RemoveRoomRoof( (INT16)marker, ubRoomNo, pSoldier );
720 								if ( ubRoomNo == ROOM_SURROUNDING_BOXING_RING && gWorldSectorX == BOXING_SECTOR_X && gWorldSectorY == BOXING_SECTOR_Y && gbWorldSectorZ == BOXING_SECTOR_Z )
721 								{
722 									// reveal boxing ring at same time
723 									RemoveRoomRoof( (INT16)marker, BOXING_RING, pSoldier );
724 								}
725 							}
726 						}
727 					}
728 					else
729 					{
730 						gpWorldLevelData[ marker ].uiFlags |= MAPELEMENT_REVEALED_ROOF;
731 					}
732 
733 					// Check for blood....
734 					UpdateBloodGraphics( (INT16)marker, ubLevel );
735 
736 					if (Blocking != NOTHING_BLOCKING &&
737 						Blocking != BLOCKING_TOPLEFT_DOOR &&
738 						Blocking != BLOCKING_TOPRIGHT_DOOR &&
739 						Blocking != BLOCKING_TOPLEFT_WINDOW &&
740 						Blocking != BLOCKING_TOPRIGHT_WINDOW &&
741 						Blocking != BLOCKING_TOPRIGHT_OPEN_WINDOW &&
742 						Blocking != BLOCKING_TOPLEFT_OPEN_WINDOW)
743 					{
744 						break;
745 					}
746 					//gpWorldLevelData[ marker ].uiFlags |= MAPELEMENT_SHADELAND;
747 
748 				}
749 			} // End of duplicate check
750 			else
751 			{
752 				if ( fTravelCostObs )
753 				{
754 					break;
755 				}
756 			}
757 		} // end of one path
758 	} // end of path loop
759 	// Loop through all availible slant roofs we collected and perform cool stuff on them
760 	ExamineSlantRoofFOVSlots( );
761 	//pSoldier->needToLookForItems = FALSE;
762 	//LookForDoors(pSoldier,UNAWARE);
763 }
764