#ifdef PRECOMPILEDHEADERS
	#include "Tactical All.h"
#else
	#include "sgp.h"
	//#include "ai.h"
	#include "Isometric Utils.h"
	#include "overhead.h"
	#include "math.h"
	#include "Event Pump.h"
	#include "random.h"
	#include "Overhead Types.h"
	#include "opplist.h"
	#include "ai.h"
	#include "font control.h"
	#include "Animation COntrol.h"
	#include "los.h"
	#include "fov.h"
	#include "dialogue control.h"
	#include "lighting.h"
	#include "environment.h"
	#include "interface dialogue.h"
	#include "message.h"
	#include "soldier profile.h"
	#include "TeamTurns.h"
	#include "interactive tiles.h"
	#include "render fun.h"
	#include "Text.h"
	#include "timer control.h"
	#include "soldier macros.h"
	#include "soldier functions.h"
	#include "handle ui.h"
	#include "Queen Command.h"
	#include "keys.h"
	#include "Campaign.h"
	#include "Soldier Init List.h"
	#include "music control.h"
	#include "Soldier Profile.h"
	#include "Strategicmap.h"
	#include "Quests.h"
	#include "meanwhile.h"
	#include "WorldMan.h"
	#include "SkillCheck.h"
	#include "GameSettings.h"
	#include "Smell.h"
	#include "Game Clock.h"
	#include "civ quotes.h"
	#include "Sound Control.h"
	#include "drugs and alcohol.h"
	#include "Interface.h"
	#include "Explosion Control.h"//dnl ch40 200909
	#include "Vehicles.h"
#endif

#ifdef JA2UB
#include "Ja25_Tactical.h"
#endif

#include "GameInitOptionsScreen.h"

#include "Music Control.h"

#include "connect.h"
#include "../ModularizedTacticalAI/include/Plan.h"
#include "../ModularizedTacticalAI/include/PlanFactoryLibrary.h"
#include "../ModularizedTacticalAI/include/AbstractPlanFactory.h"

//rain
//#define VIS_DIST_DECREASE_PER_RAIN_INTENSITY 20
//end rain

#define WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA

extern void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier );
// HEADROCK HAM 3.6: Moved to header
//void MakeBloodcatsHostile( void );

void OurNoise( UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume,	UINT8 ubNoiseType, STR16 zNoiseMessage );
void TheirNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage = NULL );
void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubBaseVolume, UINT8 ubNoiseType, STR16 zNoiseMessage = NULL );
UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubNoiseType, UINT8 ubBaseVolume, UINT8 ubTerrType1, UINT8 ubTerrType2);
void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 *ubSeen);
void TellPlayerAboutNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir,  STR16 zNoiseMessage = NULL );
void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumNewEnemies );

void IncrementWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel );
void SetWatchedLocAsUsed( UINT8 ubID, INT32 sGridNo, INT8 bLevel );
void DecayWatchedLocs( INT8 bTeam );

void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL );

// The_Bob - real time sneaking code 01/06/09
extern void CancelItemPointer(void);
extern BOOLEAN NobodyAlerted(void);
extern void ShowRadioLocator( UINT8 ubID, UINT8 ubLocatorSpeed );
//#define TESTOPPLIST

// for ManSeesMan()
#define MANLOOKSFORMAN		0
#define HEARNOISE		1
#define NOTICEUNSEENATTACKER	2


// for ManLooksForMan()
#define MANLOOKSFOROTHERTEAMS	0
#define OTHERTEAMSLOOKFORMAN	1
#define VERIFYANDDECAYOPPLIST	2
#define HANDLESTEPPEDLOOKAT	 3
#define LOOKANDLISTEN			4
#define UPDATEPUBLIC						5
#define CALLER_UNKNOWN					6

// this variable is a flag used in HandleSight to determine whether (while in non-combat RT)
// someone has just been seen, EITHER THE MOVER OR SOMEONE THE MOVER SEES
BOOLEAN		gfPlayerTeamSawCreatures = FALSE;
BOOLEAN	gfPlayerTeamSawJoey			= FALSE;
BOOLEAN	gfMikeShouldSayHi				= FALSE;

#ifdef JA2UB
//JA25 UB
BOOLEAN   gfMorrisShouldSayHi				 = FALSE;
#endif

UINT8			gubBestToMakeSighting[BEST_SIGHTING_ARRAY_SIZE];
UINT8			gubBestToMakeSightingSize = 0;
//BOOLEAN		gfHumanSawSomeoneInRealtime;

BOOLEAN		gfDelayResolvingBestSightingDueToDoor = FALSE;

#define SHOULD_BECOME_HOSTILE_SIZE 32

UINT8			gubShouldBecomeHostileOrSayQuote[ SHOULD_BECOME_HOSTILE_SIZE ];
UINT8			gubNumShouldBecomeHostileOrSayQuote;

// NB this ID is set for someone opening a door
UINT8			gubInterruptProvoker = NOBODY;

INT8 gbPublicOpplist[MAXTEAMS][TOTAL_SOLDIERS];
INT8 gbSeenOpponents[TOTAL_SOLDIERS][TOTAL_SOLDIERS];
INT32 gsLastKnownOppLoc[TOTAL_SOLDIERS][TOTAL_SOLDIERS];		// merc vs. merc
INT8 gbLastKnownOppLevel[TOTAL_SOLDIERS][TOTAL_SOLDIERS];
INT32 gsPublicLastKnownOppLoc[MAXTEAMS][TOTAL_SOLDIERS];	// team vs. merc
INT8 gbPublicLastKnownOppLevel[MAXTEAMS][TOTAL_SOLDIERS];
UINT8 gubPublicNoiseVolume[MAXTEAMS];
INT32 gsPublicNoiseGridNo[MAXTEAMS];
INT8	gbPublicNoiseLevel[MAXTEAMS];

UINT8 gubKnowledgeValue[10][10] =
 {
	//	P E R S O N A L	O P P L I S T	//
	// -4	-3	-2	-1	0	1	2	3	4	5	//
	{	0,	1,	2,	3,	0,	5,	4,	3,	2,	1}, // -4
	{	0,	0,	1,	2,	0,	4,	3,	2,	1,	0}, // -3	O
	{	0,	0,	0,	1,	0,	3,	2,	1,	0,	0}, // -2	P P
	{	0,	0,	0,	0,	0,	2,	1,	0,	0,	0}, // -1	U P
	{	0,	1,	2,	3,	0,	5,	4,	3,	2,	1}, //	0	B L
	{	0,	0,	0,	0,	0,	0,	0,	0,	0,	0}, //	1	L I
	{	0,	0,	0,	0,	0,	1,	0,	0,	0,	0}, //	2	I S
	{	0,	0,	0,	1,	0,	2,	1,	0,	0,	0}, //	3	C T
	{	0,	0,	1,	2,	0,	3,	2,	1,	0,	0}, //	4
	{	0,	1,	2,	3,	0,	4,	3,	2,	1,	0}	//	5

/*
	//	P E R S O N A L	O P P L I S T	//
	// -3	-2	-1	0	1	2	3	4	//
	{	0,	1,	2,	0,	4,	3,	2,	1	}, // -3	O
	{	0,	0,	1,	0,	3,	2,	1,	0	}, // -2	P P
	{	0,	0,	0,	0,	2,	1,	0,	0	}, // -1	U P
	{	1,	2,	3,	0,	5,	4,	3,	2	}, //	0	B L
	{	0,	0,	0,	0,	0,	0,	0,	0	}, //	1	L I
	{	0,	0,	0,	0,	1,	0,	0,	0	}, //	2	I S
	{	0,	0,	1,	0,	2,	1,	0,	0	}, //	3	C T
	{	0,	1,	2,	0,	3,	2,	1,	0	}	//	4
	*/
 };

#define MAX_WATCHED_LOC_POINTS 4
#define WATCHED_LOC_RADIUS 1

INT32			gsWatchedLoc[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
INT8			gbWatchedLocLevel[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
UINT8			gubWatchedLocPoints[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
BOOLEAN		gfWatchedLocReset[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];
BOOLEAN		gfWatchedLocHasBeenIncremented[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ];

INT8 gbLookDistance[8][8];

INT8 BEHIND;
INT8 SBEHIND;
INT8 SIDE;
INT8 ANGLE;
INT8 STRAIGHT;

void InitSightRange()
{
	BEHIND	 =	 (INT8)( BEHIND_RATIO	* gGameExternalOptions.ubStraightSightRange );
	SBEHIND	=	 (INT8)( SBEHIND_RATIO	* gGameExternalOptions.ubStraightSightRange );
	SIDE		=	 (INT8)( SIDE_RATIO		* gGameExternalOptions.ubStraightSightRange );
	ANGLE		=	 (INT8)( ANGLE_RATIO	* gGameExternalOptions.ubStraightSightRange );
	STRAIGHT	=	 (INT8)( STRAIGHT_RATIO * gGameExternalOptions.ubStraightSightRange );

	INT8 dummy[15][15];


	{	//Pulmu: VC6 compatibility
	for (int i=0; i<8; i++)
	{
			dummy[i][i]=STRAIGHT;
			dummy[i][i+1]=ANGLE;
			dummy[i+1][i]=ANGLE;
			dummy[i][i+2]=SIDE;
			dummy[i+2][i]=SIDE;
			dummy[i][i+3]=SBEHIND;
			dummy[i+3][i]=SBEHIND;
			dummy[i][i+4]=BEHIND;
			dummy[i+4][i]=BEHIND;
			dummy[i][i+5]=SBEHIND;
			dummy[i+5][i]=SBEHIND;
			dummy[i][i+6]=SIDE;
			dummy[i+6][i]=SIDE;
			dummy[i][i+7]=ANGLE;
			dummy[i+7][i]=ANGLE;
	}
	}
	for (int i=0; i<8; i++)
	{
		for (int j=0; j<8; j++)
		{
			gbLookDistance[i][j] = dummy[i][j];
		}
	}
	//gbLookDistance[8][8] =
	//{
	//	//	LOOKER DIR		LOOKEE DIR
	//	//					NORTH	| NORTHEAST	|	EAST	|	SOUTHEAST	|	SOUTH	|	SOUTHWEST	|	WEST	|	NORTHWEST
	//	/* NORTH		*/	 STRAIGHT,	 ANGLE,		SIDE,	 SBEHIND,	 BEHIND,	 SBEHIND,		SIDE,		ANGLE,
	//	/* NORTHEAST	*/	 ANGLE,	 STRAIGHT,		ANGLE,		SIDE,	SBEHIND,		BEHIND,	SBEHIND,		SIDE,
	//	/* EAST		*/	 SIDE,		 ANGLE,	STRAIGHT,		ANGLE,		SIDE,	 SBEHIND,	 BEHIND,	 SBEHIND,
	//	/* SOUTHEAST	*/	 SBEHIND,		SIDE,		ANGLE,	STRAIGHT,		ANGLE,		SIDE,	SBEHIND,		BEHIND,
	//	/* SOUTH		*/	 BEHIND,	 SBEHIND,		SIDE,		ANGLE,	STRAIGHT,		ANGLE,		SIDE,	 SBEHIND,
	//	/* SOUTHWEST	*/	 SBEHIND,	 BEHIND,	SBEHIND,		SIDE,		ANGLE,	STRAIGHT,		ANGLE,		SIDE,
	//	/* WEST		*/	 SIDE,		SBEHIND,	 BEHIND,	 SBEHIND,		SIDE,		ANGLE,	STRAIGHT,		ANGLE,
	//	/* NORTHWEST	*/	 ANGLE,		 SIDE,	 SBEHIND,	 BEHIND,	SBEHIND,		SIDE,		ANGLE,	STRAIGHT
	//	};
}


INT8 gbSmellStrength[3] =
{
	NORMAL_HUMAN_SMELL_STRENGTH, // normal
	NORMAL_HUMAN_SMELL_STRENGTH + 2, // slob
	NORMAL_HUMAN_SMELL_STRENGTH - 1	// snob
};


UINT16 gsWhoThrewRock = NOBODY;

// % values of sighting distance at various light levels
//DBrot: use gGameExternalOptions.ubBrightnessVisionMod instead
/*
INT8 gbLightSighting[1][SHADE_MIN+1] =
{
{ // human
	80, // brightest
	86,
	93,
	100, // normal daylight, 3
	94,
	88,
	82,
	76,
	70, // mid-dawn, 8
	64,
	58,
	51,
	43, // normal nighttime, 12 (11 tiles)
	30,
	17,
	9
}
};*/
/*
{
{ // human
	80, // brightest
	86,
	93,
	100, // normal daylight, 3
	93,
	86,
	79,
	72,
	65, // mid-dawn, 8
	58,
	53,
	43, // normal nighttime, 11	(11 tiles)
	35,
	26,
	17,
	9
}
};
*/

UINT8			gubSightFlags = 0;

void DECAY_OPPLIST_VALUE( INT8& value )
{
	if ( (value) >= SEEN_THIS_TURN)
	{
		(value)++;
		if ( (value) > OLDEST_SEEN_VALUE )
		{
			(value) = NOT_HEARD_OR_SEEN;
		}
	}
	else
	{
		if ( (value) <= HEARD_THIS_TURN)
		{
			(value)--;
			if ( (value) < OLDEST_HEARD_VALUE)
			{
				(value) = NOT_HEARD_OR_SEEN;
			}
		}
	}
}


//rain
extern BOOLEAN gfLightningInProgress;
extern BOOLEAN gfHaveSeenSomeone;
extern UINT8 ubRealAmbientLightLevel;
//end rain


INT16 AdjustMaxSightRangeForEnvEffects( SOLDIERTYPE *pSoldier, INT8 bLightLevel, INT16 sDistVisible )
{
	INT16 sNewDist = sDistVisible * gGameExternalOptions.ubBrightnessVisionMod[bLightLevel] / 100;

	// Adjust it based on weather...
	if ( !pSoldier->bSectorZ )
	{
		FLOAT weatherpenalty = gGameExternalOptions.dVisDistDecrease[SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )].usWeather];

		FLOAT appliedpenalty = 1.0f;
		if ( HAS_SKILL_TRAIT( pSoldier, SURVIVAL_NT ) && (gGameOptions.fNewTraitSystem) )
			appliedpenalty = min( 1.0f, max( 0.0f, appliedpenalty - gSkillTraitValues.dSVWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, SURVIVAL_NT ) ) );

		sNewDist -= (INT16)(sNewDist * weatherpenalty * appliedpenalty);

		//rain
		if ( gfLightningInProgress )
			sNewDist += sNewDist * (ubRealAmbientLightLevel) / 10;	// 10% per dark level
		//end rain
	}
	
	return( sNewDist );
}

void SwapBestSightingPositions( INT8 bPos1, INT8 bPos2 )
{
	UINT8		ubTemp;

	ubTemp = gubBestToMakeSighting[ bPos1 ];
	gubBestToMakeSighting[ bPos1 ] = gubBestToMakeSighting[ bPos2 ];
	gubBestToMakeSighting[ bPos2 ] = ubTemp;
}

void ReevaluateBestSightingPosition( SOLDIERTYPE * pSoldier, INT8 bInterruptDuelPts )
{
	UINT8 ubLoop, ubLoop2;
	BOOLEAN		fFound = FALSE;
	BOOLEAN		fPointsGotLower = FALSE;

	if ( bInterruptDuelPts == NO_INTERRUPT )
	{
		return;
	}

	if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER ) )
	{
		//gfHumanSawSomeoneInRealtime = TRUE;
	}

	if ( (pSoldier->aiData.bInterruptDuelPts != NO_INTERRUPT) && (bInterruptDuelPts < pSoldier->aiData.bInterruptDuelPts) )
	{
		fPointsGotLower = TRUE;
	}

	if ( fPointsGotLower )
	{
		// loop to end of array less 1 entry since we can't swap the last entry out of the array
		for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize - 1; ubLoop++ )
		{
			if ( pSoldier->ubID == gubBestToMakeSighting[ ubLoop ] )
			{
				fFound = TRUE;
				break;
			}
		}

		// this guy has fewer interrupt pts vs another enemy!	reduce position unless in last place
		if (fFound)
		{
			// set new points
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: reducing points for %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
			pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;

			// must percolate him down
			for ( ubLoop2 = ubLoop + 1; ubLoop2 < gubBestToMakeSightingSize; ubLoop2++ )
			{
				if ( gubBestToMakeSighting[ ubLoop2 ] != NOBODY && MercPtrs[ gubBestToMakeSighting[ ubLoop2 - 1 ] ]->aiData.bInterruptDuelPts < MercPtrs[ gubBestToMakeSighting[ ubLoop2 ] ]->aiData.bInterruptDuelPts )
				{
					SwapBestSightingPositions( (UINT8) (ubLoop2 - 1), ubLoop2 );
				}
				else
				{
					break;
				}
			}
		}
		else if ( pSoldier->ubID == gubBestToMakeSighting[ gubBestToMakeSightingSize - 1] )
		{
			// in list but can't be bumped down... set his new points
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: reduced points for last individual %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
			pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;
		}
	}
	else
	{
		// loop through whole array
		for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
		{
			if ( pSoldier->ubID == gubBestToMakeSighting[ ubLoop ] )
			{
				fFound = TRUE;
				break;
			}
		}

		if (!fFound)
		{
			for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
			{
				if ( pSoldier->RecognizeAsCombatant(gubBestToMakeSighting[ ubLoop ])  && (gubBestToMakeSighting[ ubLoop ] == NOBODY) || ( gubBestToMakeSighting[ ubLoop ] != NOBODY && bInterruptDuelPts > MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) )
				{
					if ( gubBestToMakeSighting[ gubBestToMakeSightingSize - 1 ] != NOBODY )
					{
						MercPtrs[ gubBestToMakeSighting[ gubBestToMakeSightingSize - 1 ] ]->aiData.bInterruptDuelPts = NO_INTERRUPT;
						DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: resetting points for %d to zilch", pSoldier->ubID ) );
					}

					// set new points
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: setting points for %d to %d", pSoldier->ubID, bInterruptDuelPts ) );
					pSoldier->aiData.bInterruptDuelPts = bInterruptDuelPts;

					// insert here!
					for ( ubLoop2 = gubBestToMakeSightingSize - 1; ubLoop2 > ubLoop; ubLoop2-- )
					{
						gubBestToMakeSighting[ ubLoop2 ] = gubBestToMakeSighting[ ubLoop2 - 1 ];
					}
					gubBestToMakeSighting[ ubLoop ] = pSoldier->ubID;
					break;
				}
			}
		}
		// else points didn't get lower, so do nothing (because we want to leave each merc with as low int points as possible)
	}

	for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
	{
		if ( (gubBestToMakeSighting[ ubLoop ] != NOBODY) )
		{
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP entry %d: %d (%d pts)", ubLoop, gubBestToMakeSighting[ ubLoop ], MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) );
		}
	}

}

void HandleBestSightingPositionInRealtime( void )
{
	// This function is called for handling interrupts when opening a door in non-combat or
	// just sighting in non-combat, deciding who gets the first turn

	UINT8 ubLoop;

	if ( gfDelayResolvingBestSightingDueToDoor )
	{
		DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: skipping due to door flag" );
		return;
	}

	// Also delay until attack busy returns
//	if (gTacticalStatus.ubAttackBusyCount > 0)
//	{
//		return;
//	}

	if (gubBestToMakeSighting[ 0 ] != NOBODY)
	{
		DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR called and there is someone in the list" );

		//if (gfHumanSawSomeoneInRealtime)
		{
			if (gubBestToMakeSighting[ 1 ] == NOBODY)
			{	// The_Bob - real time sneaking code 01/06/09
				// if real time sneaking conditions are met...
				// this is now in the preferences window - SANDRO				
				if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] && MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == OUR_TEAM && NobodyAlerted() )
				{
					// get rid of the item under cursor (we gotta react FAST)
					CancelItemPointer();
					// select (and center screen on) the merc who saw the enemy
					// HEADROCK HAM 3.6: A much-requested toggle.
					if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID &&
						!gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak)
						SelectSoldier (MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID, false, true);
					// if not quiet, emit a message warning the player
					if (!gGameExternalOptions.fQuietRealTimeSneak)
						ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_ENEMIES_SPOOTED]);

					return;	// and do nothing
				}
				else if ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam != OUR_TEAM && MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 )
				{
					// otherwise, simply award the turn to the team that saw the enemy first
					EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
				}
				else
					// otherwise, simply award the turn to the team that saw the enemy first
					EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
			}
			else
			{


				// if 1st and 2nd on same team, or 1st and 3rd on same team, or there IS no 3rd, award turn to 1st
				if (  /*MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 &&*/ ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam ) ||
							( (gubBestToMakeSighting[ 2 ] == NOBODY) || ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 2 ]]->bTeam ) )
					)
				{
					EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
				}
				else //if ( MercPtrs[gubBestToMakeSighting[ 1 ]]->aiData.bOppCnt > 0 ) // give turn to 2nd best but interrupt to 1st
				{
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Entering combat mode: turn for 2nd best, int for best" );

					EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam );
					// 2nd guy loses control
					AddToIntList( gubBestToMakeSighting[ 1 ], FALSE, TRUE);
					// 1st guy gains control
					AddToIntList( gubBestToMakeSighting[ 0 ], TRUE, TRUE);
					// done
					DoneAddingToIntList( MercPtrs[gubBestToMakeSighting[ 0 ]], TRUE, SIGHTINTERRUPT );
				}
			}
		}

		for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
		{
			if ( gubBestToMakeSighting[ ubLoop ] != NOBODY )
			{
				MercPtrs[ gubBestToMakeSighting[ ubLoop ]]->aiData.bInterruptDuelPts = NO_INTERRUPT;
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP: done, resetting points for %d to zilch", MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->ubID ) );
			}
		}

		for ( ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++ )
		{
			if ( MercSlots[ ubLoop ] )
			{
				AssertMsg( MercSlots[ ubLoop ]->aiData.bInterruptDuelPts == NO_INTERRUPT, String( "%S (%d) still has interrupt pts!", MercSlots[ ubLoop ]->name, MercSlots[ ubLoop ]->ubID ) );
			}
		}
	}


}

void HandleBestSightingPositionInTurnbased( void )
{
	// This function is called for handling interrupts when opening a door in turnbased

	UINT8 ubLoop, ubLoop2;
	BOOLEAN	fOk = FALSE;

	if ( gubBestToMakeSighting[ 0 ] != NOBODY )
	{
		if ( MercPtrs[ gubBestToMakeSighting[ 0 ] ]->bTeam != gTacticalStatus.ubCurrentTeam )
		{

			// interrupt!
			for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
			{
				if ( gubBestToMakeSighting[ ubLoop ] == NOBODY )
				{
					if (gubInterruptProvoker == NOBODY)
					{
						// do nothing (for now) - abort!
						return;
					}
					else
					{
						// use this guy as the "interrupted" fellow
						gubBestToMakeSighting[ ubLoop ] = gubInterruptProvoker;
						fOk = TRUE;
						break;
					}

				}
				else if ( MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->bTeam == gTacticalStatus.ubCurrentTeam )
				{
					fOk = TRUE;
					break;
				}
			}

			if ( fOk )
			{
				// this is the guy who gets "interrupted"; all else before him interrupted him
				AddToIntList( gubBestToMakeSighting[ ubLoop ], FALSE, TRUE);
				for ( ubLoop2 = 0; ubLoop2 < ubLoop; ubLoop2++ )
				{
					AddToIntList( gubBestToMakeSighting[ ubLoop2 ], TRUE, TRUE);
				}
				// done
				DoneAddingToIntList( MercPtrs[ gubBestToMakeSighting[ ubLoop ] ], TRUE, SIGHTINTERRUPT );
			}

		}
		for ( ubLoop = 0; ubLoop < BEST_SIGHTING_ARRAY_SIZE; ubLoop++ )
		{
			if ( gubBestToMakeSighting[ ubLoop ] != NOBODY )
			{
				MercPtrs[ gubBestToMakeSighting[ ubLoop ]]->aiData.bInterruptDuelPts = NO_INTERRUPT;
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "RBSP (TB): done, resetting points for %d to zilch", MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->ubID ) );
			}
		}

		for ( ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++ )
		{
			if ( MercSlots[ ubLoop ] )
			{
				AssertMsg( MercSlots[ ubLoop ]->aiData.bInterruptDuelPts == NO_INTERRUPT, String( "%S (%d) still has interrupt pts!", MercSlots[ ubLoop ]->name, MercSlots[ ubLoop ]->ubID ) );
			}
		}


	}

}

void InitSightArrays( void )
{
	UINT32		uiLoop;

	for ( uiLoop = 0; uiLoop < BEST_SIGHTING_ARRAY_SIZE; uiLoop++ )
	{
		gubBestToMakeSighting[ uiLoop ] = NOBODY;
	}
	//gfHumanSawSomeoneInRealtime = FALSE;

	// It is assumed that once the sight arrays are (re)initialized, the enemies should all have no
	// interrupt points.	At least a paranoia check in the HandleSightingInRealtime and HandleSightingInTurnBased
	// both make sure no interrupt points remain after they drain the sighting list.
	// I do not fully grok the interrupt system, but it IS possible for this function to be called when there are
	// still soldiers on the sighting list, which gives them lingering interrupt points.	So the best course of
	// action is to reset their points.	However, I think I'll just do a clean sweep here to make sure I get them all.
	for ( uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++ )
	{
		if (MercSlots[ uiLoop ] )
		{
			MercSlots[ uiLoop ]->aiData.bInterruptDuelPts = NO_INTERRUPT;
		}
	}
}

void AddToShouldBecomeHostileOrSayQuoteList( UINT8 ubID )
{
	UINT8 ubLoop;

	Assert( gubNumShouldBecomeHostileOrSayQuote < SHOULD_BECOME_HOSTILE_SIZE );

	if ( MercPtrs[ ubID ]->stats.bLife < OKLIFE )
	{
		return;
	}

	// make sure not already in list
	for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
	{
		if ( gubShouldBecomeHostileOrSayQuote[ ubLoop ] == ubID )
		{
			return;
		}
	}

	gubShouldBecomeHostileOrSayQuote[ gubNumShouldBecomeHostileOrSayQuote ] = ubID;
	gubNumShouldBecomeHostileOrSayQuote++;
}

UINT8 SelectSpeakerFromHostileOrSayQuoteList( void )
{
	UINT8						ubProfileList[ SHOULD_BECOME_HOSTILE_SIZE ]; // NB list of merc IDs, not profiles!
	UINT8 ubLoop, ubNumProfiles = 0;
	SOLDIERTYPE *		pSoldier;

	for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
	{
		pSoldier = MercPtrs[ gubShouldBecomeHostileOrSayQuote[ ubLoop ] ];
		if ( pSoldier->ubProfile != NO_PROFILE )
		{

			// make sure person can say quote!!!!
			gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE;

			if ( NPCHasUnusedHostileRecord( pSoldier->ubProfile, APPROACH_DECLARATION_OF_HOSTILITY ) )
			{
				ubProfileList[ ubNumProfiles ] = gubShouldBecomeHostileOrSayQuote[ ubLoop ];
				ubNumProfiles++;
			}
			else
			{
				// turn flag off again
				gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 &= ~PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE;
			}

		}
	}

	if ( ubNumProfiles == 0 )
	{
		return( NOBODY );
	}
	else
	{
		return( ubProfileList[ Random( ubNumProfiles ) ] );
	}
}

extern BOOLEAN gfWaitingForTriggerTimer;

void CheckHostileOrSayQuoteList( void )
{
	if ( gubNumShouldBecomeHostileOrSayQuote == 0 || !DialogueQueueIsEmpty() || gfInTalkPanel || gfWaitingForTriggerTimer )
	{
		return;
	}
	else
	{
		UINT8	ubSpeaker, ubLoop;
		SOLDIERTYPE * pSoldier;

		ubSpeaker = SelectSpeakerFromHostileOrSayQuoteList();
		if ( ubSpeaker == NOBODY )
		{
			// make sure everyone on this list is hostile
			for ( ubLoop = 0; ubLoop < gubNumShouldBecomeHostileOrSayQuote; ubLoop++ )
			{
				pSoldier = MercPtrs[ gubShouldBecomeHostileOrSayQuote[ ubLoop ] ];
				if ( pSoldier->aiData.bNeutral )
				{
					MakeCivHostile(pSoldier);
					// make civ group, if any, hostile
					if ( pSoldier->bTeam == CIV_TEAM && pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] == CIV_GROUP_WILL_BECOME_HOSTILE )
					{
						gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] = CIV_GROUP_HOSTILE;
					}

					// reevaluate sight - we might already see people that weren't enemies until now
					ManLooksForOtherTeams(pSoldier);

					pSoldier->aiData.bAlertStatus = STATUS_RED;
				}
			}

			// unpause all AI
			UnPauseAI();
			// reset the list
			memset( &gubShouldBecomeHostileOrSayQuote, NOBODY, SHOULD_BECOME_HOSTILE_SIZE );
			gubNumShouldBecomeHostileOrSayQuote = 0;
			//and return/go into combat
			if ( !(gTacticalStatus.uiFlags & INCOMBAT ) )
			{
				EnterCombatMode( CIV_TEAM );
			}
		}
		else
		{
			// pause all AI
			PauseAIUntilManuallyUnpaused();
			// stop everyone?

			// We want to make this guy visible to the player.
			if ( MercPtrs[ ubSpeaker ]->bVisible != TRUE )
			{
				gbPublicOpplist[ gbPlayerNum ][ ubSpeaker ] = HEARD_THIS_TURN;
				HandleSight( MercPtrs[ ubSpeaker ], SIGHT_LOOK | SIGHT_RADIO );
			}
			// trigger hater
			TriggerNPCWithIHateYouQuote( MercPtrs[ ubSpeaker ]->ubProfile );
		}
	}
}

void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags)
{
	UINT32 uiLoop;
	SOLDIERTYPE *pThem;
	INT8			bTempNewSituation;

	if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD )
	{
		// I DON'T THINK SO!
		return;
	}

	gubSightFlags = ubSightFlags;

	if ( gubBestToMakeSightingSize != BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL )
	{
		// if this is not being called as a result of all teams look for all, reset array size
		if ( (gTacticalStatus.uiFlags & INCOMBAT) )
		{
			// NB the incombat size is 0
			gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
		}
		else
		{
			gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT;
		}

		InitSightArrays();
	}

	for ( uiLoop = 0; uiLoop < NUM_WATCHED_LOCS; ++uiLoop )
	{
		gfWatchedLocHasBeenIncremented[ pSoldier->ubID ][ uiLoop ] = FALSE;
	}

	gfPlayerTeamSawCreatures = FALSE;

	// store new situation value
	bTempNewSituation = pSoldier->aiData.bNewSituation;
	pSoldier->aiData.bNewSituation = FALSE;

	// if we've been told to make this soldier look (& others look back at him)
	if (ubSightFlags & SIGHT_LOOK)
	{
		// if this soldier's under our control and well enough to look
		if (pSoldier->stats.bLife >= OKLIFE )
		{
		/*
#ifdef RECORDOPPLIST
	 fprintf(OpplistFile,"ManLooksForOtherTeams (HandleSight/Look) for %d\n",pSoldier->guynum);
#endif
		*/
			// he looks for all other soldiers not on his own team
			ManLooksForOtherTeams(pSoldier);

	 // if "Show only enemies seen" option is ON and it's this guy looking
	 //if (pSoldier->ubID == ShowOnlySeenPerson)
		//NewShowOnlySeenPerson(pSoldier);					// update the string
		}


	/*
#ifdef RECORDOPPLIST
	fprintf(OpplistFile,"OtherTeamsLookForMan (HandleSight/Look) for %d\n",ptr->guynum);
#endif
	*/

		// all soldiers under our control but not on ptr's team look for him
		OtherTeamsLookForMan(pSoldier);
	} // end of SIGHT_LOOK

	// if we've been told that interrupts are possible as a result of sighting
	if ((gTacticalStatus.uiFlags & TURNBASED) && 
		(gTacticalStatus.uiFlags & INCOMBAT) && 
		(ubSightFlags & SIGHT_INTERRUPT) && 
		(!UsingImprovedInterruptSystem() || gGameExternalOptions.fAllowInstantInterruptsOnSight ) )
	{
		ResolveInterruptsVs( pSoldier, SIGHTINTERRUPT );
	}

	if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT )
	{
		HandleBestSightingPositionInRealtime();
	}

	if ( pSoldier->aiData.bNewSituation && !(pSoldier->flags.uiStatusFlags & SOLDIER_PC) )
	{
		pSoldier->HaultSoldierFromSighting( TRUE );
	}
	pSoldier->aiData.bNewSituation = __max( pSoldier->aiData.bNewSituation, bTempNewSituation );

	// if we've been told to radio the results
	if (ubSightFlags & SIGHT_RADIO)
	{
		if (pSoldier->flags.uiStatusFlags & SOLDIER_PC )
		{
			// update our team's public knowledge
			RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam );
/*  comm by ddd
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
			RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM);
#endif*/
//ddd{
			if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
				RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM);

#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
			//haydent
			if(is_networked &&  pSoldier->bSide == 0 && pSoldier->bTeam != OUR_TEAM)
				RadioSightings(pSoldier,EVERYBODY, OUR_TEAM);
#endif

//ddd}
			// if it's our local player's merc
			if (PTR_OURTEAM)
				// revealing roofs and looking for items handled here, too
				RevealRoofsAndItems(pSoldier,TRUE, TRUE, pSoldier->pathing.bLevel, FALSE );
		}
		// unless in easy mode allow alerted enemies to radio	
		else if ( zDiffSetting[gGameOptions.ubDifficultyLevel].bRadioSightings )
		{
			// don't allow admins to radio
			//Madd: Huh?	why not admins?	removed.
			if ( pSoldier->bTeam == ENEMY_TEAM && gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition ) //&& pSoldier->ubSoldierClass != 	SOLDIER_CLASS_ADMINISTRATOR )
			{
				RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam );
			}
		}

		pSoldier->bNewOppCnt = 0;
		pSoldier->pathing.bNeedToLook = FALSE;

// Temporary for opplist synching - disable random order radioing
#ifndef RECORDOPPLIST
		// if this soldier's NOT on our team (MAY be under our control, though!)
		if (!PTR_OURTEAM)
			OurTeamRadiosRandomlyAbout(pSoldier->ubID);	// radio about him only
#endif

		// all non-humans under our control would now radio, if they were allowed
		// to radio automatically (but they're not).	So just nuke new opp cnt
		// NEW: under LOCALOPPLIST, humans on other teams now also radio in here
		for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop)
		{
			pThem = MercSlots[ uiLoop ];

			if (pThem != NULL && pThem->stats.bLife >= OKLIFE)
			{
				// if this merc is on the same team as the target soldier
				if (pThem->bTeam == pSoldier->bTeam)
					continue;		// he doesn't look (he ALWAYS knows about him)

				// other human team's merc report sightings to their teams now
				if (pThem->flags.uiStatusFlags & SOLDIER_PC)
				{
// Temporary for opplist synching - disable random order radioing
#ifdef RECORDOPPLIST
					// do our own team, too, since we've bypassed random radioing
					if (TRUE)
#else
					// exclude our own team, we've already done them, randomly
					if (pThem->bTeam != gbPlayerNum)
#endif
						RadioSightings(pThem,pSoldier->ubID, pThem->bTeam);
				}
				// unless in easy mode allow alerted enemies to radio		
				else if ( zDiffSetting[gGameOptions.ubDifficultyLevel].bRadioSightings2 )
				{
					// don't allow admins to radio
					// silversurfer: Why not? Removed just like above.
					if ( pThem->bTeam == ENEMY_TEAM && gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition ) //&& pThem->ubSoldierClass != SOLDIER_CLASS_ADMINISTRATOR )
					{
						RadioSightings(pThem,EVERYBODY, pThem->bTeam );
					}
				}

				pThem->bNewOppCnt = 0;
				pThem->pathing.bNeedToLook = FALSE;
			}
		}
	}

	// CJC August 13 2002: at the end of handling sight, reset sight flags to allow interrupts in case an audio cue should
	// cause someone to see an enemy
	gubSightFlags |= SIGHT_INTERRUPT;
}


void OurTeamRadiosRandomlyAbout(UINT8 ubAbout)
{
 INT32				iLoop;
 // WDS - make number of mercenaries, etc. be configurable
INT8					radioCnt = 0,radioMan[CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS];
 SOLDIERTYPE	*pSoldier;


// Temporary for opplist synching - disable random order radioing
#ifdef RECORDOPPLIST
 for (iLoop = Status.team[Net.pnum].guystart,ourPtr = MercPtrs[iLoop]; iLoop < Status.team[Net.pnum].guyend; iLoop++,ourPtr++)
	{
	// if this merc is active, in this sector, and well enough to look
	if (pSoldier->active && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE))
	{
	 RadioSightings(pSoldier,ubAbout,pSoldier->bTeam);
	 pSoldier->bNewOppCnt = 0;
	}
	}

 return;
#endif


 // All mercs on our local team check if they should radio about him
 iLoop = gTacticalStatus.Team[gbPlayerNum].bFirstID;

 // make a list of all of our team's mercs
 for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; iLoop++,pSoldier++)
	{
	// if this merc is active, in this sector, and well enough to look
	if (pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE))
	 // put him on our list, and increment the counter
	 radioMan[radioCnt++] = (INT8)iLoop;
	}


 // now RANDOMLY handle each of the mercs on our list, until none remain
 // (this is all being done ONLY so that the mercs in the earliest merc
 //	slots do not arbitrarily get the bulk of the sighting speech quote
 //	action, while the later ones almost never pipe up, and is NOT
 //	strictly necessary, but a nice improvement over original JA)
 while (radioCnt)
	{
	// pick a merc from one of the remaining slots at random
	iLoop = Random(radioCnt);

	// handle radioing for that merc
	RadioSightings(MercPtrs[radioMan[iLoop]],ubAbout,MercPtrs[radioMan[iLoop]]->bTeam);
	Menptr[radioMan[iLoop]].bNewOppCnt = 0;

	// unless it WAS the last used slot that we happened to pick
	if (iLoop != (radioCnt - 1))
	 // move the contents of the last slot into the one just handled
	 radioMan[iLoop] = radioMan[radioCnt - 1];

	radioCnt--;
	}
}










INT16 TeamNoLongerSeesMan( UINT8 ubTeam, SOLDIERTYPE *pOpponent, UINT8 ubExcludeID, INT8 bIteration )
{
	UINT16 bLoop;
	SOLDIERTYPE *pMate;


	bLoop = gTacticalStatus.Team[ubTeam].bFirstID;

	// look for all mercs on the same team, check opplists for this soldier
	for (pMate = MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[ubTeam].bLastID; ++bLoop,pMate++)
	{
		// if this "teammate" is me, myself, or I (whom we want to exclude)
		if (bLoop == ubExcludeID)
	 continue;			// skip to next teammate, I KNOW I don't see him...

	// if this merc is not on the same team
	if (pMate->bTeam != ubTeam)
	 continue;	// skip him, he's no teammate at all!

	// if this merc is not active, at base, on assignment, dead, unconscious
	if (!pMate->bActive || !pMate->bInSector || (pMate->stats.bLife < OKLIFE))
	 continue;	// next merc

	// if this teammate currently sees this opponent
	if (pMate->aiData.bOppList[pOpponent->ubID] == SEEN_CURRENTLY)
	 return(FALSE);	 // that's all I need to know, get out of here
	}

/* comm by ddd
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
	if ( bIteration == 0 )
	{
		if ( ubTeam == gbPlayerNum && gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive )
		{
			// check militia team as well
			return( TeamNoLongerSeesMan( MILITIA_TEAM, pOpponent, ubExcludeID, 1 ) );
		}
		else if ( ubTeam == MILITIA_TEAM && gTacticalStatus.Team[ gbPlayerNum ].bTeamActive )
		{
			// check player team as well
			return( TeamNoLongerSeesMan( gbPlayerNum, pOpponent, ubExcludeID, 1 ) );
		}
	}
#endif
*/
//ddd
if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
{
	if ( bIteration == 0 )
	{
		if ( ubTeam == gbPlayerNum && gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive )
		{
			// check militia team as well
			return( TeamNoLongerSeesMan( MILITIA_TEAM, pOpponent, ubExcludeID, 1 ) );
		}
		else if ( ubTeam == MILITIA_TEAM && gTacticalStatus.Team[ gbPlayerNum ].bTeamActive )
		{
			// check player team as well
			return( TeamNoLongerSeesMan( gbPlayerNum, pOpponent, ubExcludeID, 1 ) );
		}
	}

}
//ddd

 // none of my friends is currently seeing the guy, so return success
 return(TRUE);
}

INT16 DistanceSmellable( SOLDIERTYPE *pSoldier, SOLDIERTYPE * pSubject )
{
	INT16 sDistVisible = STRAIGHT; // as a base

	//if (gTacticalStatus.uiFlags & TURNBASED)
	//{
		sDistVisible *= 2;
	//}
	//else
	//{

	//	sDistVisible += 3;
	//}

	if (pSubject)
	{
		if (pSubject->flags.uiStatusFlags & SOLDIER_MONSTER)
		{
			// trying to smell a friend; change nothing
		}
		else
		{
			// smelling a human or animal; if they are coated with monster smell, distance shrinks
			sDistVisible = sDistVisible * (pSubject->aiData.bNormalSmell - pSubject->aiData.bMonsterSmell) / NORMAL_HUMAN_SMELL_STRENGTH;
			if (sDistVisible < 0)
			{
				sDistVisible = 0;
			}
		}
	}
	return( sDistVisible );
}

INT16 MaxNormalDistanceVisible( void )
{
	return( STRAIGHT * 2 );
}

INT16 SOLDIERTYPE::GetMaxDistanceVisible(INT32 sGridNo, INT8 bLevel, int calcAsType)
{
	if (sGridNo == NOWHERE)
	{
		return MaxNormalDistanceVisible();
	}

	if (bLevel == -1)
	{
		bLevel = this->pathing.bLevel;
	}

	if (calcAsType == CALC_FROM_ALL_DIRS)
	{
		return DistanceVisible( this, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sGridNo, bLevel, this->IsCowering(), GetPercentTunnelVision(this) );
	}

	return DistanceVisible( this, (SoldierHasLimitedVision(this) ? this->pathing.bDesiredDirection : DIRECTION_IRRELEVANT), DIRECTION_IRRELEVANT, sGridNo, bLevel, this->IsCowering(), GetPercentTunnelVision(this));
}

INT16 DistanceVisible(SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, INT32 sSubjectGridNo, INT8 bLevel, const BOOLEAN& isCowering, const UINT8& tunnelVision)
{
	INT16	sDistVisible;
	INT8	bLightLevel;
	BOOLEAN sideViewLimit = FALSE;
	SOLDIERTYPE* pSubject = SimpleFindSoldier( sSubjectGridNo, bLevel );
	INT16 tunnelVisionInPercent = 0;

	if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
	{
		if ( !pSubject )
		{
			return( FALSE );
		}

		return( DistanceSmellable( pSoldier, pSubject ) );
	}

	if (pSoldier->bBlindedCounter > 0)
	{
		// we're bliiiiiiiiind!!!
		return( 0 );
	}

	// sevenfm: if soldier is unconscious, he can't see anything
	if ( pSoldier->bCollapsed && pSoldier->bBreath == 0 )
	{
		return( 0 );
	}

	// Bob: if gridNo isn't set, this would cause a access violation later on
	if (pSoldier->sGridNo < 0) {
		// ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"DistanceVisible(): Caught bad LOS distance check!");
		return(0);
	}

	// anv: some places in vehicle don't give passenger any view outside
	INT8 bSeatIndex = GetSeatIndexFromSoldier( pSoldier );
	if( bSeatIndex != (-1) )
	{	
		SOLDIERTYPE *pVehicle = GetSoldierStructureForVehicle( pSoldier ->iVehicleId );
		// need to check this even if bSubjectDir is DIRECTION_IRRELEVANT
		if( gNewVehicle[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ].VehicleSeats[ bSeatIndex ].fBlockedView )
		{
			return( 0 );
		}
	}

	if ( bFacingDir == DIRECTION_IRRELEVANT && ARMED_VEHICLE( pSoldier ) )
	{
		// always calculate direction for tanks so we have something to work with
		bFacingDir = pSoldier->pathing.bDesiredDirection;
		bSubjectDir = (INT8) GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, sSubjectGridNo );
		//bSubjectDir = atan8(pSoldier->sX,pSoldier->sY,pOpponent->sX,pOpponent->sY);
	}

	if ( !ARMED_VEHICLE( pSoldier ) && (bFacingDir == DIRECTION_IRRELEVANT || (pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT) || (pSubject && pSubject->flags.fMuzzleFlash)) )
	{
		sDistVisible = MaxNormalDistanceVisible();
	}
	else
	{
		if (pSoldier->sGridNo == sSubjectGridNo)
		{
			// looking up or down or two people accidentally in same tile... don't want it to be 0!
			sDistVisible = MaxNormalDistanceVisible();
		}
		else
		{
			// Flugente: no need to calculate this multiple times
			BOOLEAN fLimitedVision = SoldierHasLimitedVision(pSoldier);

			// Lesh: added this
			if( fLimitedVision )
			{
				bSubjectDir = (INT8) GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, sSubjectGridNo );
			}

			if (bFacingDir == DIRECTION_IRRELEVANT)
			{
				bFacingDir = pSoldier->ubDirection;
			}

			sDistVisible = gbLookDistance[bFacingDir][bSubjectDir];

			// Lesh: and this
			if ( sDistVisible == 0 && fLimitedVision )
				return 0;

			if ( sDistVisible == ANGLE && (pSoldier->bTeam == OUR_TEAM || pSoldier->aiData.bAlertStatus >= STATUS_RED ) )
			{
				sDistVisible = STRAIGHT;
			}

			if ( sDistVisible != STRAIGHT || ( fLimitedVision && (bFacingDir != bSubjectDir) ) )
			{
				tunnelVisionInPercent = tunnelVision;
			}

			sDistVisible *= 2;

			if ( pSoldier->usAnimState == RUNNING )
			{
				if ( gbLookDistance[bFacingDir][bSubjectDir] != STRAIGHT )
				{
					// reduce sight when we're not looking in that direction...
					sDistVisible = (INT16) (sDistVisible * ANGLE_RATIO);
				}
			}

			// Flugente: we only apply tunnelvision now, after we've possibly extended the sight range, which results in finer differentiation of effects
			if ( tunnelVisionInPercent > 0 )
			{
				sideViewLimit = TRUE;
				sDistVisible = sDistVisible * (100 - tunnelVisionInPercent) / 100;
			}
		}
	}

	if (pSoldier->pathing.bLevel != bLevel)
	{
		// add two tiles distance to visibility to/from roofs
		// sDistVisible += (STRAIGHT_RATIO * 2); //2;
		sDistVisible += ( sDistVisible / 6 ); //lal changed distance to 1/6 from visible range
	}

	// now reduce based on light level; SHADE_MIN is the define for the
	// highest number the light can be

	// If we're about to ask for a light level for a location outside of our
	// valid map references then use the ambient light level instead.	
	if ( TileIsOutOfBounds( sSubjectGridNo ) )
	{
		DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("113/UC Warning! Tried to detect the light level when character %ls[%d] looks at a location outside of the valid map (gridno %d). Assigning default %d",
				pSoldier->name, pSoldier->ubID, pSoldier->sGridNo, ubAmbientLightLevel));

		bLightLevel = ubAmbientLightLevel;
	}
	else
	{
		bLightLevel = LightTrueLevel(sSubjectGridNo, bLevel);
	}

	// Snap: I think this was intended to give maximum visibility to targets with muzzle flash...
	// Corrected accordingly:
	//if ( pSubject && !( pSubject->flags.fMuzzleFlash && (bLightLevel > NORMAL_LIGHTLEVEL_DAY) ) )
	if ( !( pSubject && pSubject->flags.fMuzzleFlash && (bLightLevel > NORMAL_LIGHTLEVEL_DAY) ) )
	{
		// ATE: Made function to adjust light distance...
		sDistVisible = AdjustMaxSightRangeForEnvEffects( pSoldier, bLightLevel, sDistVisible );
	}

	// Snap: this takes care of all equipment bonuses at all light levels
	// The rest is special code for robots, bloodcats and NO specialists
	// Lalien: change to % instead of tiles, add bonus only to front view when using scope
	if (!sideViewLimit)
	{
		sDistVisible += sDistVisible * GetTotalVisionRangeBonus(pSoldier, bLightLevel) / 100;

		// HEADROCK HAM 3.2: Further reduce sightrange for cowering characters.
		// SANDRO - this calls many sub-functions over and over, we should at least skip this for civilians and such  
		// Flugente: we can check for more conditions before calculating suppression tolerance
		if ( (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 2) &&
			IS_MERC_BODY_TYPE(pSoldier) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) && 
			gGameExternalOptions.ubMaxSuppressionShock > 0 && sDistVisible > 0 )
		{
			// Make sure character is cowering.
			if (isCowering)
			{
				sDistVisible = __max(1,(sDistVisible * (gGameExternalOptions.ubMaxSuppressionShock - pSoldier->aiData.bShock)) / gGameExternalOptions.ubMaxSuppressionShock);
			}
		}
	}

	// give one step better vision for people with nightops
	// old/new traits check - SANDRO
	if (gGameOptions.fNewTraitSystem)
	{
		if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
			sDistVisible += NightBonusScale( gSkillTraitValues.ubNOeSightRangeBonusInDark, bLightLevel);
	}
	else
	{
		if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
			sDistVisible += NightBonusScale( 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ), bLightLevel);
	}
	// Bloodcat bonus only works above ground
	if ( pSoldier->ubBodyType == BLOODCAT && gbWorldSectorZ == 0 )
	{
		sDistVisible += NightBonusScale( UVGOGGLES_BONUS, bLightLevel);
	}
	else if ( AM_A_ROBOT( pSoldier ) )
	{
		sDistVisible += NightBonusScale( NIGHTSIGHTGOGGLES_BONUS, bLightLevel);
	}

	// let tanks see and be seen further (at night)
	if ( (ARMED_VEHICLE( pSoldier ) && sDistVisible > 0) || (pSubject && ARMED_VEHICLE( pSubject )) )
	{
#if 0
		if ( ARMED_VEHICLE(pSoldier) && sDistVisible > 0 && pSubject)
		{
			sDistVisible = __max( sDistVisible + 5, pSubject->GetMaxDistanceVisible(pSoldier->sGridNo, pSoldier->pathing.bLevel) );
		}
		else
		{
			sDistVisible = __max( sDistVisible + 5, pSoldier->GetMaxDistanceVisible() );
		}
#endif
		// 0verhaul:  This bit of code 1) seems to have no real reason to exist (MaxDistVisible just calls this function anyway), 
		// and 2) causes infinite recursion because MaxDistVisible just calls this function, which comes right back here.  Just
		// add 5 to sDistVisible and go on.
		sDistVisible = sDistVisible + 5;
	}

	if ( gpWorldLevelData[ pSoldier->sGridNo ].ubExtFlags[ bLevel ] & (MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS) )
	{
		//dnl ch40 200909
		INT8 bPosOfMask = FindGasMask(pSoldier);
		if(bPosOfMask == HEAD1POS || bPosOfMask == HEAD2POS)
		{
			if(pSoldier->inv[bPosOfMask][0]->data.objectStatus < GASMASK_MIN_STATUS)
				sDistVisible = __min(sDistVisible, 2+pSoldier->inv[bPosOfMask][0]->data.objectStatus/15);
		}
		else
			sDistVisible = __min(sDistVisible, 2);
	}
	if ( gpWorldLevelData[ pSoldier->sGridNo ].ubExtFlags[ bLevel ] & MAPELEMENT_EXT_BURNABLEGAS )
	{
		{
			// in FLAMETHERgas ; reduce max distance visible to 2 tiles at most
			sDistVisible = __min( sDistVisible, 2 );
		}
	}

	return(sDistVisible);
}



void EndMuzzleFlash( SOLDIERTYPE * pSoldier )
{
	UINT32					uiLoop;
	SOLDIERTYPE *		pOtherSoldier;

	pSoldier->flags.fMuzzleFlash = FALSE;
/*comm by ddd
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
	if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM )
#else
	if ( pSoldier->bTeam != gbPlayerNum )
#endif

	{
		pSoldier->bVisible = 0; // indeterminate state
	}
*/	


#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
//haydent
if(is_networked &&  pSoldier->bSide == 0)
{
	//stay visible
}
else
#endif
{
	if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)	
	{	if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM )
			pSoldier->bVisible = 0; // indeterminate state
	}
	else
	{
		if ( pSoldier->bTeam != gbPlayerNum )
			pSoldier->bVisible = 0; // indeterminate state
	}
}//haydent



	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pOtherSoldier = MercSlots[ uiLoop ];

		if ( pOtherSoldier != NULL )
		{
			if ( pOtherSoldier->aiData.bOppList[ pSoldier->ubID ] == SEEN_CURRENTLY )
			{				
				if (!TileIsOutOfBounds(pOtherSoldier->sGridNo))
				{
					if ( PythSpacesAway( pOtherSoldier->sGridNo, pSoldier->sGridNo ) > pOtherSoldier->GetMaxDistanceVisible(pSoldier->sGridNo, pSoldier->pathing.bLevel, CALC_FROM_WANTED_DIR ) )
					{
						// if this guy can no longer see us, change to seen this turn
						HandleManNoLongerSeen( pOtherSoldier, pSoldier, &(pOtherSoldier->aiData.bOppList[ pSoldier->ubID ]), &(gbPublicOpplist[ pOtherSoldier->bTeam ][ pSoldier->ubID ] ) );
					}

					// else this person is still seen, if the looker is on our side or the militia the person should stay visible
/* comm by ddd
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
					else if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM )
#else
					else if ( pOtherSoldier->bTeam == gbPlayerNum )
#endif

					{
						pSoldier->bVisible = TRUE; // yes, still seen
					}
*/					
					//ddd{
					else if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
					{
						if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM )
							{pSoldier->bVisible = TRUE;} // yes, still seen
					}
					else
					{
						if ( pOtherSoldier->bTeam == gbPlayerNum )
							pSoldier->bVisible = TRUE; // yes, still seen
					}
					//ddd}

					
#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
					//haydent
					if(is_networked &&  pOtherSoldier->bSide == 0 && pOtherSoldier->bTeam != OUR_TEAM)
						pSoldier->bVisible = TRUE; // yes, still seen
#endif
				}
			}
		}
	}
	DecideTrueVisibility( pSoldier, FALSE );

}

void TurnOffEveryonesMuzzleFlashes( void )
{
	UINT32					uiLoop;
	SOLDIERTYPE *		pSoldier;

	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pSoldier = MercSlots[ uiLoop ];

		if ( pSoldier != NULL && pSoldier->flags.fMuzzleFlash )
		{
			EndMuzzleFlash( pSoldier );
		}
	}
}

void TurnOffTeamsMuzzleFlashes( UINT8 ubTeam )
{
	UINT8 ubLoop;
	SOLDIERTYPE *		pSoldier;

	for (ubLoop = gTacticalStatus.Team[ ubTeam ].bFirstID; ubLoop <= gTacticalStatus.Team[ ubTeam ].bLastID; ubLoop++)
	{
		pSoldier = MercPtrs[ ubLoop ];

		if ( pSoldier->flags.fMuzzleFlash )
		{
			EndMuzzleFlash( pSoldier );
		}
	}
}

INT8 DecideHearing( SOLDIERTYPE * pSoldier )
{
	// calculate the hearing value for the merc...
	INT8		bHearing;

	if ( ARMED_VEHICLE( pSoldier ) || ENEMYROBOT( pSoldier ) )
	{
		return( -5 );
	}
	else if ( pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER )
	{
		return( -10 );
	}

	bHearing = 0;

	if (EffectiveExpLevel( pSoldier ) > 3) // SANDRO - changed to calculate effective level
	{
		bHearing++;
	}

	// old/new traits check - SANDRO
	if (gGameOptions.fNewTraitSystem)
	{
		if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
			bHearing += gSkillTraitValues.ubNOHearingRangeBonus;
		if (HAS_SKILL_TRAIT( pSoldier, SNITCH_NT ))
			bHearing += gSkillTraitValues.ubSNTHearingRangeBonus;
	}
	else
	{
		if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
			bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT );
	}

	bHearing += pSoldier->GetHearingBonus();

	// adjust for dark conditions
	switch ( ubAmbientLightLevel )
	{
		case 8:
		case 9:
			bHearing += 1;
			break;
		case 10:
			bHearing += 2;
			break;
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
			bHearing += 3;
			// yet another bonus for nighttime
			// old/new traits check - SANDRO
			if (gGameOptions.fNewTraitSystem)
			{
				if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ))
					bHearing += gSkillTraitValues.ubNOHearingRangeBonusInDark;
			}
			else
			{
				if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ))
					bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT );
			}
			break;
		default:
			break;
	}

	// adjust for weather
	if ( !pSoldier->bSectorZ )
	{
		FLOAT weatherpenalty = gGameExternalOptions.dHearingReduction[SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )].usWeather];

		// Added a feature to reduce rain effect on regaining breath with Ranger trait - SANDRO
		FLOAT appliedpenalty = 1.0f;
		if ( HAS_SKILL_TRAIT( pSoldier, SURVIVAL_NT ) && gGameOptions.fNewTraitSystem )
			appliedpenalty = min( 1.0f, max( 0.0f, appliedpenalty - gSkillTraitValues.dSVWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, SURVIVAL_NT ) ) );

		bHearing -= (INT16)(bHearing * weatherpenalty * appliedpenalty);
	}

	return( bHearing );
}

void InitOpplistForDoorOpening( void )
{
	// this is called before generating a noise for opening a door so that
	// the results of hearing the noise are lumped in with the results from AllTeamsLookForAll
	gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL;
	gfDelayResolvingBestSightingDueToDoor = TRUE; // will be turned off in allteamslookforall
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: setting door flag on" );
	// must init sight arrays here
	InitSightArrays();
}


void AllTeamsLookForAll(UINT8 ubAllowInterrupts)
{
 UINT32 uiLoop;
 SOLDIERTYPE *pSoldier;

	if( ( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
	{
		return;
	}

	if (ubAllowInterrupts || !(gTacticalStatus.uiFlags & INCOMBAT) )
	{
		gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL;
		if ( gfDelayResolvingBestSightingDueToDoor )
		{
			// turn off flag now, and skip init of sight arrays
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "HBSPIR: turning door flag off" );
			gfDelayResolvingBestSightingDueToDoor = FALSE;
		}
		else
		{
			InitSightArrays();
		}
	}

	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pSoldier = MercSlots[ uiLoop ];

		if ( pSoldier != NULL && pSoldier->stats.bLife >= OKLIFE )
		{
			HandleSight(pSoldier,SIGHT_LOOK);	// no radio or interrupts yet
		}
	}

	// the player team now radios about all sightings
	for ( uiLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; uiLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; uiLoop++ )
	{
		HandleSight( MercPtrs[ uiLoop ], SIGHT_RADIO );		// looking was done above
	}

	if ( !(gTacticalStatus.uiFlags & INCOMBAT) )
	{
		// decide who should get first turn
		HandleBestSightingPositionInRealtime();
		// this could have made us switch to combat mode
		if ( (gTacticalStatus.uiFlags & INCOMBAT) )
		{
			gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
		}
		else
		{
			gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_NONCOMBAT;
		}
	}
	else if ( ubAllowInterrupts )
	{
		HandleBestSightingPositionInTurnbased();
		// reset sighting size to 0
		gubBestToMakeSightingSize = BEST_SIGHTING_ARRAY_SIZE_INCOMBAT;
	}

 /*

 // do this here as well as in overhead so the looks/interrupts are combined!

 // if a door was recently opened/closed (doesn't matter if we could see it)
 // this is done here so we can first handle everyone looking through the
 // door, and deal with the resulting opplist changes, interrupts, etc.
 if ( !TileIsOutOfBounds(Status.doorCreakedGridno))
	{
	// opening/closing a door makes a bit of noise (constant volume)
	MakeNoise(Status.doorCreakedGuynum,Status.doorCreakedGridno,TTypeList[Grid[Status.doorCreakedGridno].land],DOOR_NOISE_VOLUME,NOISE_CREAKING,EXPECTED_NOSEND);

	Status.doorCreakedGridno = NOWHERE;
	Status.doorCreakedGuynum = NOBODY;
	}


 // all soldiers now radio their findings (NO interrupts permitted this early!)
 // NEW: our entire team must radio first, so that they radio about EVERYBODY
 // rather radioing about individuals one a a time (repeats see 1 enemy quote)
 for (cnt = Status.team[Net.pnum].guystart,ptr = MercPtrs[cnt]; cnt < Status.team[Net.pnum].guyend; cnt++,ptr++)
	{
	if (ptr->active && ptr->in_sector && (ptr->life >= OKLIFE))
	 HandleSight(ptr,SIGHT_RADIO);		// looking was done above
	}

 for (cnt = 0,ptr = Menptr; cnt < MAXMERCS; cnt++,ptr++)
	{
	if (ptr->active && ptr->in_sector && (ptr->life >= OKLIFE) && !PTR_OURTEAM)
	 HandleSight(ptr,SIGHT_RADIO);		// looking was done above
	}


 // if interrupts were allowed
 if (allowInterrupts)
	// resolve interrupts against the selected character (others disallowed)
	HandleSight(MercPtrs[Status.allLookCharacter],SIGHT_INTERRUPT);


 // revert to normal interrupt operation
 InterruptOnlyGuynum = NOBODY;
 InterruptsAllowed = TRUE;
 */

 // reset interrupt only guynum which may have been used
 gubInterruptProvoker = NOBODY;
}




void ManLooksForOtherTeams(SOLDIERTYPE *pSoldier)
{
 UINT32 uiLoop;
 SOLDIERTYPE *pOpponent;


#ifdef TESTOPPLIST
 DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
	String("MANLOOKSFOROTHERTEAMS ID %d(%S) team %d side %d",pSoldier->ubID,pSoldier->name,pSoldier->bTeam,pSoldier->bSide));
#endif


	// one soldier (pSoldier) looks for every soldier on another team (pOpponent)


 for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
 {
	pOpponent = MercSlots[ uiLoop ];

	// if this soldier is around and alive
	if (pOpponent && pOpponent->stats.bLife)
	{
	 // and if he's on another team...
	 if (pSoldier->bTeam != pOpponent->bTeam)
	 {

			// use both sides actual x,y co-ordinates (neither side's moving)
			// if he sees this opponent...
			ManLooksForMan(pSoldier,pOpponent,MANLOOKSFOROTHERTEAMS);

			// OK, We now want to , if in non-combat, set visiblity to 0 if not visible still....
			// This allows us to walk away from buddy and have them disappear instantly
			if ( gTacticalStatus.uiFlags & TURNBASED && !( gTacticalStatus.uiFlags & INCOMBAT ) )
			{
				if ( pOpponent->bVisible == 0)
				{
					pOpponent->bVisible = -1;
				}
			}

		}
	}
 }
}

void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL )
{
	// if neither side is neutral AND
	// if this soldier is an opponent (fights for different side)
	if (pSoldier->bActive && pOpponent->bActive && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
	{
		RemoveOneOpponent(pSoldier);
	}

	// change personal opplist to indicate "seen this turn"
	// don't use UpdatePersonal() here, because we're changing to a *lower*
	// opplist value (which UpdatePersonal ignores) and we're not updating
	// the lastKnown gridno at all, we're keeping it at its previous value
	/*
#ifdef RECORDOPPLIST
	fprintf(OpplistFile,"ManLooksForMan: changing personalOpplist to %d for guynum %d, opp %d\n",SEEN_THIS_TURN,ptr->guynum,oppPtr->guynum);
#endif
	*/

	*pPersOL = SEEN_THIS_TURN;

	if ( (pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP) && (pOpponent->bTeam == gbPlayerNum ) )
	{
		//DBrot: More Rooms
		//UINT8 ubRoom;
		UINT16 usRoom;

		if ( InARoom( pOpponent->sGridNo, &usRoom ) && IN_BROTHEL( usRoom ) && ( IN_BROTHEL_GUARD_ROOM( usRoom ) ) )
		{
			// unauthorized!
			// make guard run to block guard room
			DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: make guard run to block guard room"));			CancelAIAction( pSoldier, TRUE );
			RESETTIMECOUNTER( pSoldier->timeCounters.AICounter, 0 );
			pSoldier->aiData.bNextAction = AI_ACTION_RUN;
			pSoldier->aiData.usNextActionData = 13250;
		}
	}

	// if opponent was seen publicly last time
	if (*pbPublOL == SEEN_CURRENTLY)
	{
		// check if I was the only one who was seeing this guy (exlude ourselves)
		// THIS MUST HAPPEN EVEN FOR ENEMIES, TO MAKE THEIR PUBLIC opplist DECAY!
		if (TeamNoLongerSeesMan(pSoldier->bTeam,pOpponent,pSoldier->ubID, 0 ))
		{
#ifdef TESTOPPLIST
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "TeamNoLongerSeesMan: ID %d(%S) to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
#endif


#ifdef RECORDOPPLIST
			fprintf(OpplistFile,"TeamNoLongerSeesMan returns TRUE for team %d, opp %d\n",ptr->team,oppPtr->guynum);
			fprintf(OpplistFile,"ManLooksForMan: changing publicOpplist to %d for team %d, opp %d\n",SEEN_THIS_TURN,ptr->team,oppPtr->guynum);
#endif

			// don't use UpdatePublic() here, because we're changing to a *lower*
			// opplist value (which UpdatePublic ignores) and we're not updating
			// the lastKnown gridno at all, we're keeping it at its previous value
			*pbPublOL = SEEN_THIS_TURN;

			// ATE: Set visiblity to 0
/*comm by ddd			
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
			if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) )
#else
			if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum )
#endif
			{
				pOpponent->bVisible = 0;
			}
*/			


#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
			//haydent
			if(is_networked && pSoldier->bSide == 0)
			{
				//stay visible
			}
			else
#endif
			{
				if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
				{
					if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) )
						pOpponent->bVisible = 0;
				}
				else
				{ 
					if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum )
						pOpponent->bVisible = 0;
				}
			}//haydent
		}
	}
#ifdef TESTOPPLIST
	else
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("ManLooksForMan: ID %d(%S) to ID %d Personally seen, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pbPublOL) );
#endif

	// if we had only seen the guy for an instant and now lost sight of him
	if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] == -1)
		// we can't leave it -1, because InterruptDuel() uses the special -1
		// value to know if we're only JUST seen the guy and screw up otherwise
		// it's enough to know we have seen him before
		gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE;

}


INT16 ManLooksForMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, UINT8 ubCaller)
{
 INT8 bDir,bAware = FALSE,bSuccess = FALSE;
 INT16 sDistVisible,sDistAway;
 INT8	*pPersOL,*pbPublOL;


 /*
 if (ptr->guynum >= TOTAL_SOLDIERS)
	{
#ifdef BETAVERSION
	NumMessage("ManLooksForMan: ERROR - ptr->guynum = ",ptr->guynum);
#endif
	return(success);
	}

 if (oppPtr->guynum >= TOTAL_SOLDIERS)
	{
#ifdef BETAVERSION
	NumMessage("ManLooksForMan: ERROR - oppPtr->guynum = ",oppPtr->guynum);
#endif
	return(success);
	}
*/

	// if we're somehow looking while inactive, at base, dead or dying
	if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE))
	{
/*
#ifdef BETAVERSION
	sprintf(tempstr,"ManLooksForMan: ERROR - %s is looking while inactive/at base/dead/dying.	Caller %s",
			ExtMen[ptr->guynum].name,LastCaller2Text[caller]);

#ifdef RECORDNET
	fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
#endif

	PopMessage(tempstr);
#endif
*/

#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("ERROR: ManLooksForMan - WE are inactive/dead etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
#endif

		return(FALSE);
	}

	// if we're somehow looking for a guy who is inactive, at base, or already dead 
	if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0 || TileIsOutOfBounds(pOpponent->sGridNo))
	{
/*
#ifdef BETAVERSION
	sprintf(tempstr,"ManLooksForMan: ERROR - %s looks for %s, who is inactive/at base/dead.	Caller %s",
		ExtMen[ptr->guynum].name,ExtMen[oppPtr->guynum].name,LastCaller2Text[caller]);

#ifdef RECORDNET
	fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
#endif

	PopMessage(tempstr);
#endif
*/

#ifdef TESTOPPLIST
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("ERROR: ManLooksForMan - TARGET is inactive etc ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
#endif

		return(FALSE);
	}


	// if he's looking for a guy who is on the same team
	if (pSoldier->bTeam == pOpponent->bTeam)
	{
/*
#ifdef BETAVERSION
	sprintf(tempstr,"ManLooksFormMan: ERROR - on SAME TEAM.	ptr->guynum = %d, oppPtr->guynum = %d",
					ptr->guynum,oppPtr->guynum);
#ifdef RECORDNET
	fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
#endif

	PopMessage(tempstr);
#endif
*/

#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("ERROR: ManLooksForMan - SAME TEAM ID %d(%S)to ID %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
#endif

		return(FALSE);
	}

	// Flugente: we already checked for OKLIFE above..
	if ( pSoldier->flags.fMercAsleep )
	{
		return( FALSE );
	}

 // NEED TO CHANGE THIS
 /*
 // don't allow unconscious persons to look, but COLLAPSED, etc. is OK
 if (ptr->anitype[ptr->anim] == UNCONSCIOUS)
	return(success);
*/

	if ( pSoldier->ubBodyType == LARVAE_MONSTER || (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM) )
	{
		// don't do sight for these
		return( FALSE );
	}


 /*
 if (ptrProjected)
	{
	// use looker's PROJECTED x,y co-ordinates (those of his next gridno)
	fromX = ptr->destx;
	fromY = ptr->desty;
	fromGridno = ExtMen[ptr->guynum].nextGridno;
	}
 else
	{
	// use looker's ACTUAL x,y co-ordinates (those of gridno he's in now)
	fromX = ptr->x;
	fromY = ptr->y;
	fromGridno = ptr->sGridNo;
	}


 if (oppPtrProjected)
	{
	// use target's PROJECTED x,y co-ordinates (those of his next gridno)
	toX = oppPtr->destx;
	toY = oppPtr->desty;
	toGridno = ExtMen[oppPtr->guynum].nextGridno;
	}
 else
	{
	// use target's ACTUAL x,y co-ordinates (those of gridno he's in now)
	toX = oppPtr->x;
	toY = oppPtr->y;
	toGridno = oppPtr->gridno;
	}
*/

	pPersOL = &(pSoldier->aiData.bOppList[pOpponent->ubID]);
	pbPublOL = &(gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]);

	// if soldier is known about (SEEN or HEARD within last few turns)
	if (*pPersOL || *pbPublOL)
	{
		bAware = TRUE;

		// then we look for him full viewing distance in EVERY direction

		//ADB the comment above says EVERY direction but the code used to be:
		//sDistVisible = DistanceVisible(pSoldier, (SoldierHasLimitedVision(pSoldier) ? pSoldier->bDesiredDirection : DIRECTION_IRRELEVANT), 0, pOpponent->sGridNo, pOpponent->bLevel, pOpponent );
		//if the code below says CALC_FROM_ALL_DIRS, then the opponent will NOT be greyed out if a merc sees him and a second merc turns away from him
		//calcing from the wanted dir will make the opponent be greyed out, which I think is the intended effect
		sDistVisible = pSoldier->GetMaxDistanceVisible( pOpponent->sGridNo, pOpponent->pathing.bLevel, CALC_FROM_WANTED_DIR );
		//if (pSoldier->ubID == 0)
		//sprintf(gDebugStr,"ALREADY KNOW: ME %d him %d val %d",pSoldier->ubID,pOpponent->ubID,pSoldier->bOppList[pOpponent->ubID]);
	}
	else   // soldier is not currently known about
	{
		// distance we "see" then depends on the direction he is located from us
		bDir = atan8(pSoldier->sX,pSoldier->sY,pOpponent->sX,pOpponent->sY);
		// BIG NOTE: must use desdir instead of direction, since in a projected
		// situation, the direction may still be changing if it's one of the first
		// few animation steps when this guy's turn to do his stepped look comes up
		sDistVisible = DistanceVisible(pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pOpponent->sGridNo, pOpponent->pathing.bLevel, pSoldier->IsCowering(), GetPercentTunnelVision(pSoldier));
		//if (pSoldier->ubID == 0)
		//sprintf(gDebugStr,"dist visible %d: my dir %d to him %d",sDistVisible,pSoldier->bDesiredDirection,bDir);
	}

	// calculate how many spaces away soldier is (using Pythagoras' theorem)
	sDistAway = PythSpacesAway(pSoldier->sGridNo,pOpponent->sGridNo);

#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "MANLOOKSFORMAN: ID %d(%S) to ID %d: sDistAway %d sDistVisible %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,sDistAway,sDistVisible) );
#endif

	// if we see close enough to see the soldier
	if (sDistAway <= sDistVisible)
	{
		// and we can trace a line of sight to his x,y coordinates
		// must use the REAL opplist value here since we may or may not know of him
		if (SoldierToSoldierLineOfSightTest(pSoldier,pOpponent,bAware,sDistVisible))
		{
			ManSeesMan(pSoldier,pOpponent,pOpponent->sGridNo,pOpponent->pathing.bLevel,MANLOOKSFORMAN,ubCaller);
			bSuccess = TRUE;
		}
#ifdef TESTOPPLIST
	else
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("FAILED LINEOFSIGHT: ID %d (%S)to ID %d Personally %d, public %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL) );
#endif

/*
	// if we're looking for a local merc, and changed doors were in the way
	if (PTR_OURTEAM && (NextFreeDoorIndex > 0))
	 // make or fail, if we passed through any "changed" doors along the way,
	 // reveal their true status (change the structure to its real value)
	 // (do this even if we don't have LOS, to close doors that *BREAK* LOS)
	 RevealDoorsAlongLOS();
*/
	}



/*
#ifdef RECORDOPPLIST
 fprintf(OpplistFile,"MLFM: %s by %2d(g%4d,x%3d,y%3d,%s) at %2d(g%4d,x%3d,y%3d,%s), aware %d, dA=%d,dV=%d, desDir=%d, %s\n",
		(success) ? "SCS" : "FLR",
		ptr->guynum,fromGridno,fromX,fromY,(ptrProjected)?"PROJ":"REG.",
		oppPtr->guynum,toGridno,toX,toY,(oppPtrProjected)?"PROJ":"REG.",
		aware,distAway,distVisible,ptr->desdir,
		LastCaller2Text[caller]);
#endif
*/

	// if soldier seen personally LAST time could not be seen THIS time
	if (!bSuccess && (*pPersOL == SEEN_CURRENTLY))
	{
		HandleManNoLongerSeen( pSoldier, pOpponent, pPersOL, pbPublOL );
	}
#ifdef TESTOPPLIST
	else
	{
		if (!bSuccess)
		{
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("NO LONGER VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) );

			// we didn't see the opponent, but since we didn't last time, we should be
			//if (*pbPublOL)
				//pOpponent->bVisible = TRUE;
		}
		else
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("COOL. STILL VISIBLE ID %d (%S)to ID %d Personally %d, public %d success: %d",pSoldier->ubID,pSoldier->name,pOpponent->ubID,*pPersOL,*pbPublOL,bSuccess) );
	}
#endif
	
	return(bSuccess);
}




void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, INT8 bOppLevel, UINT8 ubCaller, UINT8 ubCaller2)
{
	INT8 bDoLocate = FALSE;
	BOOLEAN fNewOpponent = FALSE;
	BOOLEAN fNotAddedToList = TRUE;
	INT8 bOldOppList = pSoldier->aiData.bOppList[pOpponent->ubID];
	DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ManSeesMan");

	if (pSoldier->ubID >= TOTAL_SOLDIERS)
		return;
	if (pOpponent->ubID >= TOTAL_SOLDIERS)
		return;
	// if we're somehow looking while inactive, at base, dying or already dead
	if (!pSoldier->bActive || !pSoldier->bInSector || (pSoldier->stats.bLife < OKLIFE))
		return;
	// if we're somehow seeing a guy who is inactive, at base, or already dead
	if (!pOpponent->bActive || !pOpponent->bInSector || pOpponent->stats.bLife <= 0)
		return;
	// if we're somehow seeing a guy who is on the same team
	if (pSoldier->bTeam == pOpponent->bTeam)
		return;
	// Flugente: if the other guy is in med or deep water and wearing scua gear, then we cannot see him as he is submerged
	if ( pOpponent->UsesScubaGear() )
		return;
	// Flugente: update our sight concerning this guy, otherwise we could get way with open attacks because this does not get updated
	if ( pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
	{
		// Flugente: note that this enemy has been seen by mercs this turn
		if ( pOpponent->bTeam == ENEMY_TEAM && pSoldier->bTeam == OUR_TEAM )
			pOpponent->usSoldierFlagMask |= SOLDIER_ENEMY_OBSERVEDTHISTURN;
	}
	// sevenfm: if soldier is unconscious, he can't see anybody
	if ( pSoldier->bCollapsed && pSoldier->bBreath == 0 )
	{
		return;
	}

	// if we're seeing a guy we didn't see on our last chance to look for him
	if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY)
	{
		if ( pOpponent->bTeam == gbPlayerNum )
		{
			if ( pSoldier->ubProfile != NO_PROFILE )
			{
				if ( pSoldier->bTeam == CIV_TEAM )
				{
					// if this person doing the sighting is a member of a civ group that hates us but
					// this fact hasn't been revealed, change the side of these people now. This will
					// make them non-neutral so AddOneOpponent will be called, and the guy will say his
					// "I hate you" quote
					if ( pSoldier->aiData.bNeutral )
					{
						if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE )
						{
							AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
							fNotAddedToList = FALSE;
						}
					}
					else if ( NPCHasUnusedRecordWithGivenApproach( pSoldier->ubProfile, APPROACH_DECLARATION_OF_HOSTILITY ) )
					{
						// only add if have something to say
						AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
						fNotAddedToList = FALSE;
					}

					if ( fNotAddedToList )
					{
						switch( pSoldier->ubProfile )
						{
						case CARMEN:
#ifdef JA2UB
// no UB 
#else
							if (pOpponent->ubProfile == SLAY ) // 64
							{
								// Carmen goes to war (against Slay)
								if ( pSoldier->aiData.bNeutral )
								{
									//SetSoldierNonNeutral( pSoldier );
									pSoldier->aiData.bAttitude = ATTACKSLAYONLY;
									TriggerNPCRecord( pSoldier->ubProfile, 28 );
								}
								/*
								if ( ! gTacticalStatus.uiFlags & INCOMBAT )
								{
								EnterCombatMode( pSoldier->bTeam );
								}
								*/

							}
#endif								

							
							break;
						case ELDIN:
							if ( pSoldier->aiData.bNeutral )
							{
								//DBrot: More Rooms
								//UINT8 ubRoom = 0;
								UINT16 usRoom = 0;
								// if player is in behind the ropes of the museum display
								// or if alarm has gone off (status red)
								InARoom( pOpponent->sGridNo, &usRoom );

								if ( ( CheckFact( FACT_MUSEUM_OPEN, 0 ) == FALSE && usRoom >= 22 && usRoom <= 41 ) || CheckFact( FACT_MUSEUM_ALARM_WENT_OFF, 0 ) || ( usRoom == 39 || usRoom == 40 ) || ( FindObj( pOpponent, CHALICE ) != NO_SLOT ) )
								{
									SetFactTrue( FACT_MUSEUM_ALARM_WENT_OFF );
									AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );	
								}
							}
							break;	
						case JIM:
						case JACK:
						case OLAF:
						case RAY:
						case OLGA:
						case TYRONE:
							// change orders, reset action!
							if ( pSoldier->aiData.bOrders != SEEKENEMY )
							{
								pSoldier->aiData.bOrders = SEEKENEMY;
								if ( pSoldier->aiData.bOppCnt == 0 )
								{
									// didn't see anyone before!
									DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: NPC with profile: change orders, reset action"));
									CancelAIAction( pSoldier, TRUE );
									SetNewSituation( pSoldier );
								}
							}
							break;
						case ANGEL:
							if ( pOpponent->ubProfile == MARIA )
							{
								if ( CheckFact( FACT_MARIA_ESCORTED_AT_LEATHER_SHOP, MARIA ) == TRUE )
								{
									// she was rescued! yay!
									TriggerNPCRecord( ANGEL, 12 );
								}
							}
							else if ( ( CheckFact( FACT_ANGEL_LEFT_DEED, ANGEL ) == TRUE ) && ( CheckFact( FACT_ANGEL_MENTIONED_DEED, ANGEL ) == FALSE ) )
							{
								DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: NPC: Angel code"));
								CancelAIAction( pSoldier, TRUE );
								pSoldier->sAbsoluteFinalDestination = NOWHERE;
								pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection );
								TriggerNPCRecord( ANGEL, 20 );
								// trigger Angel to walk off afterwards
								//TriggerNPCRecord( ANGEL, 24 );
							}
							break;
							//case QUEEN:
#ifdef JA2UB
//Ja25
//No Queen,Joe, or elliot
#else
						case JOE:
						case ELLIOT:
							if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
							{
								if ( !AreInMeanwhile() )
								{
									TriggerNPCRecord( pSoldier->ubProfile, 4 );
									gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE;
								}
							}
							break;
#endif
						default:
							break;
						}
					}
				}
				else
				{
					switch( pSoldier->ubProfile )
					{
					case IGGY:
						if ( ! ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
						{
							TriggerNPCRecord( pSoldier->ubProfile, 9 );
							gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE;
							gbPublicOpplist[ gbPlayerNum ][ pSoldier->ubID ] = HEARD_THIS_TURN;
						}
						break;
					}
				}
			}
			// Flugente: for assassins without profiles
			else if ( pSoldier->IsAssassin() && pSoldier->bTeam == CIV_TEAM )
			{
				// if we are an assassin and still neutral and undercover, approach target and then become hostile
				if ( pSoldier->aiData.bNeutral && pSoldier->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
				{
					// only if this guy isn't disguised himself!
					if ( (pOpponent->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0)
					{
						if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE )
						{
							// measure distance to our opponent, only go hostile if he is close enough
							if ( PythSpacesAway( pSoldier->sGridNo, pOpponent->sGridNo ) <= NPC_TALK_RADIUS * 2 )
							{
								AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
								fNotAddedToList = FALSE;
							}
						}
					}
				}

				if ( fNotAddedToList )
				{
					// change orders, reset action!
					if ( pSoldier->aiData.bOrders != SEEKENEMY )
					{
						pSoldier->aiData.bOrders = SEEKENEMY;
						if ( pSoldier->aiData.bOppCnt == 0 )
						{
							// didn't see anyone before!
							DebugAI(AI_MSG_INFO, pSoldier, String("CancelAIAction: assasin: didn't see anyone before!"));
							CancelAIAction( pSoldier, TRUE );
							SetNewSituation( pSoldier );
						}
					}
				}
			}
			else
			{
				if ( pSoldier->bTeam == CIV_TEAM )
				{
					if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] >= CIV_GROUP_WILL_BECOME_HOSTILE && pSoldier->aiData.bNeutral )
					{
						AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID );
					}
					else if ( pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP )
					{
						// generic kingpin goon...

						// check to see if we are looking at Maria or unauthorized personnel in the brothel
						if (pOpponent->ubProfile == MARIA)
						{
							MakeCivHostile(pSoldier);
							if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
							{
								EnterCombatMode( pSoldier->bTeam );
							}
							SetFactTrue( FACT_MARIA_ESCAPE_NOTICED );
						}
						else
						{
							//DBrot: More Rooms
							//UINT8 ubRoom;
							UINT16 usRoom;

							// JA2 Gold: only go hostile if see player IN guard room
							//if ( InARoom( pOpponent->sGridNo, &ubRoom ) && IN_BROTHEL( ubRoom ) && ( gMercProfiles[ MADAME ].bNPCData == 0 || IN_BROTHEL_GUARD_ROOM( ubRoom ) ) )
							if ( InARoom( pOpponent->sGridNo, &usRoom ) && IN_BROTHEL_GUARD_ROOM( usRoom ) )
							{
								// unauthorized!
								MakeCivHostile(pSoldier);
								if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
								{
									EnterCombatMode( pSoldier->bTeam );
								}
							}
						}
					}
					else if ( pSoldier->ubCivilianGroup == HICKS_CIV_GROUP && CheckFact( FACT_HICKS_MARRIED_PLAYER_MERC, 0 ) == FALSE && pSoldier->RecognizeAsCombatant( pOpponent->ubID ) )
					{
						UINT32	uiTime;
						INT16	sX, sY;

						// if before 6:05 or after 22:00, make hostile and enter combat
						uiTime = GetWorldMinutesInDay();
						if ( uiTime < 365 || uiTime > 1320 )
						{
							// get off our farm!
							MakeCivHostile(pSoldier);
							if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
							{
								EnterCombatMode( pSoldier->bTeam );

								LocateSoldier( pSoldier->ubID, TRUE );
								GetSoldierScreenPos( pSoldier, &sX, &sY );
								// begin quote
								BeginCivQuote( pSoldier, CIV_QUOTE_HICKS_SEE_US_AT_NIGHT, 0, sX, sY );
							}
						}
					}
				}
			}
		}
		else if ( pSoldier->bTeam == gbPlayerNum )
		{
#ifdef JA2UB		
			if ( (pOpponent->ubProfile == MORRIS_UB ) &&
				 ( GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( NULL, NULL ) > 0 ) && 
				 !( pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MORRIS ) && 
				 !( gMercProfiles[ MORRIS_UB ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) )
			{
				gfMorrisShouldSayHi = TRUE;
			}
#else		  
			if ( (pOpponent->ubProfile == MIKE) && ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC || pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) && !(pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_EXT_MIKE) )
			{
				if (gfMikeShouldSayHi == FALSE)
				{
					gfMikeShouldSayHi = TRUE;
				}
				TacticalCharacterDialogue( pSoldier, QUOTE_AIM_SEEN_MIKE );
				pSoldier->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_EXT_MIKE;
			}
#endif
			else if ( pOpponent->ubProfile == JOEY && gfPlayerTeamSawJoey == FALSE )
			{
				TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_JOEY );
				gfPlayerTeamSawJoey = TRUE;
			}
		}

		// as soon as a bloodcat sees someone, it becomes hostile
		// this is safe to do here because we haven't made this new person someone we've seen yet
		// (so we are assured we won't count 'em twice for oppcnt purposes)
		if ( pSoldier->ubBodyType == BLOODCAT )
		{
			if ( pSoldier->aiData.bNeutral )
			{
				MakeBloodcatsHostile();
				/*
				SetSoldierNonNeutral( pSoldier );
				RecalculateOppCntsDueToNoLongerNeutral( pSoldier );
				if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
				{
				CheckForPotentialAddToBattleIncrement( pSoldier );
				}
				*/

				//PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
				PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME +10, 1, MIDDLEPAN );
			}
			else
			{
				if ( pSoldier->aiData.bOppCnt == 0 )
				{
					if ( Random( 2 ) == 0 )
					{
						//PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
						PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME + 10, 1, MIDDLEPAN );
					}
				}
			}
		}
		else if ( pOpponent->ubBodyType == BLOODCAT && pOpponent->aiData.bNeutral)
		{
			// HEADROCK HAM 3.6: If bloodcats are set as affiliated with civilians, do not trigger hostilities.
			UINT8 DiffLevel;
			if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
				DiffLevel = 1;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
				DiffLevel = 2;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
				DiffLevel = 3;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
				DiffLevel = 4;	
			else
				DiffLevel = 1;
				
			if ( gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ 0 ].PlacementType != BLOODCAT_PLACEMENT_STATIC ||
				gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ DiffLevel - 1 ].ubFactionAffiliation == NON_CIV_GROUP ||
				gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ DiffLevel - 1 ].ubFactionAffiliation == QUEENS_CIV_GROUP )			
			/*
			if ( gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ 0 ].PlacementType != BLOODCAT_PLACEMENT_STATIC ||
				gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == NON_CIV_GROUP ||
				gBloodcatPlacements[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][ gGameOptions.ubDifficultyLevel - 1 ].ubFactionAffiliation == QUEENS_CIV_GROUP )
			*/
			{
				MakeBloodcatsHostile();
			}
			/*
			SetSoldierNonNeutral( pOpponent );
			RecalculateOppCntsDueToNoLongerNeutral( pOpponent );
			if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
			{
			CheckForPotentialAddToBattleIncrement( pOpponent );
			}
			*/
		}

		// Flugente: reworked this to account for covert ops and assassin mechanisms
		// if we are not neutral against this guy, we are truly opponents (we're not on the same side) and recognize him as an opponent...
		BOOLEAN fAddAsOpponent = FALSE;
		if ( !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
		{
			// ... check wether he is not neutral against us (account for the fact that we might be covert!)
			// if we are an NPC assassin
			if ( pSoldier->IsAssassin() && pSoldier->usSoldierFlagMask & (SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER) )
			{
				// check wether our opponent would see us as an opponent if we weren't covert
				if ( !( (pSoldier->aiData.bNeutral || pSoldier->usSoldierFlagMask & SOLDIER_POW) && ( pOpponent->bTeam != CREATURE_TEAM || pOpponent->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) )
					fAddAsOpponent = TRUE;
			}
			else
			{
				// simply check wether this guy sees us as an opponent too
				if ( !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) )
					fAddAsOpponent = TRUE;
			}
		}


		if ( fAddAsOpponent )
		{
			AddOneOpponent(pSoldier);

#ifdef TESTOPPLIST
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "ManSeesMan: ID %d(%S) to ID %d NEW TO ME",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );	
#endif
			// SANDRO - if this is an enemy guy, who was unaware of us till now, and the combat didn't started yet, throw "taunt" and indicator we have been seen
			if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN &&	pSoldier->aiData.bAlertStatus != STATUS_RED && pSoldier->aiData.bAlertStatus != STATUS_BLACK )
			{
				PossiblyStartEnemyTaunt( pSoldier, TAUNT_NOTICED_UNSEEN, pOpponent->ubID );
			}
			// anv: we're already in fight, but we still can say hi to new enemy
			else if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN )
			{
				PossiblyStartEnemyTaunt( pSoldier, TAUNT_SAY_HI, pOpponent->ubID );
			}

			ShowRadioLocator( pSoldier->ubID, 1 );


			// if we also haven't seen him earlier this turn
			if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN)
			{
				fNewOpponent = TRUE;
				pSoldier->bNewOppCnt++;        // increment looker's NEW opponent count
				//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Soldier %d sees soldier %d!", pSoldier->ubID, pOpponent->ubID );

				//ExtMen[ptr->guynum].lastCaller = caller;
				//ExtMen[ptr->guynum].lastCaller2 = caller2;

				IncrementWatchedLoc( pSoldier->ubID, pOpponent->sGridNo, pOpponent->pathing.bLevel );

				if ( pSoldier->bTeam == OUR_TEAM && pOpponent->bTeam == ENEMY_TEAM )
				{
					if ( CheckFact( FACT_FIRST_BATTLE_FOUGHT, 0 ) == FALSE )
					{
						SetFactTrue( FACT_FIRST_BATTLE_BEING_FOUGHT );
					}
				}
			}
			else
			{
				SetWatchedLocAsUsed( pSoldier->ubID, pOpponent->sGridNo, pOpponent->pathing.bLevel );
			}

			// we already know the soldier isn't SEEN_CURRENTLY,
			// now check if he is really "NEW" ie. not expected to be there

			// if the looker hasn't seen this opponent at all earlier this turn, OR
			// if the opponent is not where the looker last thought him to be
			// sevenfm: only call SetNewSituation if location is different to reduce frequency of AI re-evaluation
			//if ((pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN) || (gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID] != sOppGridNo))
			if (KnownLocation(pSoldier, pOpponent->ubID) != sOppGridNo || KnownLevel(pSoldier, pOpponent->ubID) != bOppLevel)
			{
				SetNewSituation( pSoldier );  // force the looker to re-evaluate
				// anv: simulate informing buddies about detected enemy's position
				// sevenfm: check that he is really new
				//if( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_CURRENTLY && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] != SEEN_THIS_TURN )
				if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] < 1 && gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] < SEEN_CURRENTLY)
					PossiblyStartEnemyTaunt( pSoldier, TAUNT_INFORM_ABOUT, pOpponent->ubID );
			}
			else
			{
				// if we in a non-combat movement decision, presumably this is not
				// something we were quite expecting, so make a new decision.  For
				// other (combat) movement decisions, we took his position into account
				// when we made it, so don't make us think again & slow things down.
				switch (pSoldier->aiData.bAction)
				{
				case AI_ACTION_RANDOM_PATROL:
				case AI_ACTION_SEEK_OPPONENT:
				case AI_ACTION_SEEK_FRIEND:
				case AI_ACTION_POINT_PATROL:
				case AI_ACTION_LEAVE_WATER_GAS:
				case AI_ACTION_SEEK_NOISE:
					SetNewSituation( pSoldier );  // force the looker to re-evaluate
					break;
				}
			}
		}

	}
#ifdef TESTOPPLIST
	else
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "ManSeesMan: ID %d(%S) to ID %d ALREADYSEENCURRENTLY",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );	
#endif
	//bOldOppValue = pSoldier->aiData.bOppList[ pOpponent->ubID ];
	// remember that the soldier is currently seen and his new location
 UpdatePersonal(pSoldier,pOpponent->ubID,SEEN_CURRENTLY,sOppGridNo,bOppLevel);

	if ( ubCaller2 == MANLOOKSFOROTHERTEAMS || ubCaller2 == OTHERTEAMSLOOKFORMAN || ubCaller2 == CALLER_UNKNOWN ) // unknown->hearing
	{

		if ( gubBestToMakeSightingSize != BEST_SIGHTING_ARRAY_SIZE_INCOMBAT && gTacticalStatus.bBoxingState == NOT_BOXING )
		{
			if ( fNewOpponent )
			{
				if ( gTacticalStatus.uiFlags & INCOMBAT )
				{
					// presumably a door opening... we do require standard interrupt conditions				
					if (StandardInterruptConditionsMet(pSoldier,pOpponent->ubID,bOldOppList))
					{
						ReevaluateBestSightingPosition( pSoldier, CalcInterruptDuelPts( pSoldier, pOpponent->ubID, TRUE ) );
					}
				}
				// require the enemy not to be dying if we are the sighter; in other words,
				// always add for AI guys, and always add for people with life >= OKLIFE
				else if ( !(pSoldier->bTeam == gbPlayerNum && pOpponent->stats.bLife < OKLIFE ) )
				{
					ReevaluateBestSightingPosition( pSoldier, CalcInterruptDuelPts( pSoldier, pOpponent->ubID, TRUE ) );
				}
			}
		}
	}

	// if this man has never seen this opponent before in this sector
	if (gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] == FALSE)
		// remember that he is just seeing him now for the first time (-1)
		gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = -1;
	else
		// man is seeing an opponent AGAIN whom he has seen at least once before
		gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE;

//ddd{
BOOLEAN SEE_MENT = FALSE;

if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
{
	if ( ( PTR_OURTEAM || (pSoldier->bTeam == MILITIA_TEAM) ) && (pOpponent->bVisible <= 0))
	SEE_MENT = TRUE;
}
else
{
	if (PTR_OURTEAM && (pOpponent->bVisible <= 0))
	SEE_MENT = TRUE;
}

#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
	//haydent
	if((is_networked &&  pSoldier->bSide == 0 && pSoldier->bTeam != OUR_TEAM) && (pOpponent->bVisible <= 0))
		SEE_MENT = TRUE;
#endif

//ddd}

/*comm by ddd
	// if looker is on local team, and the enemy was invisible or "maybe"
	// visible just prior to this
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
	if ( ( PTR_OURTEAM || (pSoldier->bTeam == MILITIA_TEAM) ) && (pOpponent->bVisible <= 0))
#else
	if (PTR_OURTEAM && (pOpponent->bVisible <= 0))
#endif
*/
if(SEE_MENT)
	{
		// if opponent was truly invisible, not just turned off temporarily (FALSE)
		if (pOpponent->bVisible == -1)
		{
			// then locate to him and set his locator flag
			bDoLocate = TRUE;

			//rain
			if( gfLightningInProgress ) gfHaveSeenSomeone = TRUE;
			//end rain
		}

		// make opponent visible (to us)
		// must do this BEFORE the locate since it checks for visibility
		pOpponent->bVisible = TRUE;

		//ATE: Cancel any fading going on!
		// ATE: Added for fade in.....
		if ( pOpponent->flags.fBeginFade == 1 || pOpponent->flags.fBeginFade == 2 )
		{
			pOpponent->flags.fBeginFade = FALSE;

			if ( pOpponent->pathing.bLevel > 0 && gpWorldLevelData[ pOpponent->sGridNo ].pRoofHead != NULL )
			{
				pOpponent->ubFadeLevel = gpWorldLevelData[ pOpponent->sGridNo ].pRoofHead->ubShadeLevel;
			}
			else
			{
				pOpponent->ubFadeLevel = gpWorldLevelData[ pOpponent->sGridNo ].pLandHead->ubShadeLevel;
			}

			// Set levelnode shade level....
			if ( pOpponent->pLevelNode )
			{
				pOpponent->pLevelNode->ubShadeLevel = pOpponent->ubFadeLevel;
			}
		}


#ifdef TESTOPPLIST
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("!!! ID %d (%S) MAKING %d VISIBLE",pSoldier->ubID,pSoldier->name,pOpponent->ubID) );
#endif

		// update variable for STATUS screen
		//pOpponent->bLastKnownLife = pOpponent->life;

		if (bDoLocate)
		{

			// Change his anim speed!
			SetSoldierAniSpeed( pOpponent );

			// if show enemies is ON, then we must have already revealed these roofs
			// and we're also following his movements, so don't bother sliding
			if (!gbShowEnemies)
			{
				//DoSoldierRoofs(pOpponent);

				// slide to the newly seen opponent, and if appropriate, start his locator
				//SlideToMe = oppPtr->guynum;
			}

			//LastOpponentLocatedTo = oppPtr->guynum;

			/*
			#ifdef RECORDNET
			fprintf(NetDebugFile,"\tManSeesMan - LOCATE\n");
			#endif
			*/


			if ( gTacticalStatus.uiFlags & TURNBASED && ( ( gTacticalStatus.uiFlags & INCOMBAT ) | gTacticalStatus.fVirginSector ) )
			{
				if (!pOpponent->aiData.bNeutral && (pSoldier->bSide != pOpponent->bSide))
				{
					//SlideTo(0,pOpponent->ubID, pSoldier->ubID, SETLOCATOR);
					//rain
					SlideTo(0,pOpponent->ubID, pSoldier->ubID, SETLOCATORFAST);
					//end rain
				}
			}
		}


	}
	else if (!PTR_OURTEAM)
	{
		// ATE: Check stance, change to threatending
		ReevaluateEnemyStance( pSoldier, pSoldier->usAnimState );
	}
    AI::tactical::AIInputData ai_input(AI::tactical::AIInputData::Visual(), pOpponent, sOppGridNo, bOppLevel, ubCaller, ubCaller2);
    AI::tactical::PlanInputData plan_input((gTacticalStatus.uiFlags & TURNBASED)!=0, gTacticalStatus);
    AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
    plan_lib->update_plan(pSoldier->bAIIndex, pSoldier, ai_input);
}


void DecideTrueVisibility(SOLDIERTYPE *pSoldier, UINT8 ubLocate)
{
 // if his visibility is still in the special "limbo" state (FALSE)
 if (pSoldier->bVisible == FALSE)
 {
	// then none of our team's merc turned him visible,
	// therefore he now becomes truly invisible
	pSoldier->bVisible = -1;

	// Don;t adjust anim speed here, it's done once fade is over!
	}


 // If soldier is not visible, make sure his red "locator" is turned off
 //if ((pSoldier->bVisible < 0) && !gbShowEnemies)
	//	pSoldier->bLocator = FALSE;


 if (ubLocate)
	{
	// if he remains visible (or ShowEnemies ON)
	if ((pSoldier->bVisible >= 0) || gbShowEnemies)
	{
		/*
#ifdef RECORDNET
	 fprintf(NetDebugFile,"\tDecideTrueVisibility - LOCATE\n");
#endif
	*/

	if (PTR_OURTEAM)
	 {
		//if (ConfigOptions[FOLLOWMODE] && Status.stopSlidingAt == NOBODY)
		//	LocateMember(ptr->guynum,DONTSETLOCATOR);
	 }
	else // not our team - if we're NOT allied then locate...
	 //if (pSoldier->side != gTacticalStatus.Team[gbPlayerNum].side && ConfigOptions[FOLLOWMODE])
		//if (Status.stopSlidingAt == NOBODY)
				if (gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) )
			//LocateSoldier(pSoldier->ubID,DONTSETLOCATOR);
					SlideTo(0,pSoldier->ubID, NOBODY, DONTSETLOCATOR);

	 // follow his movement on our screen as he moves around...
	 //LocateMember(ptr->guynum,DONTSETLOCATOR);
	}
	}
}





void OtherTeamsLookForMan(SOLDIERTYPE *pOpponent)
{
	UINT32 uiLoop;
	INT8 bOldOppList;
	SOLDIERTYPE *pSoldier;


	//NumMessage("OtherTeamsLookForMan, guy#",oppPtr->guynum);

/* comm by ddd	
	// if the guy we're looking for is NOT on our team AND is currently visible
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
	if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
#else
	if ((pOpponent->bTeam != gbPlayerNum) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
#endif
	{
		// assume he's no longer visible, until one of our mercs sees him again
		pOpponent->bVisible = 0;
	}
*/	


#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
//haydent
if(is_networked &&  pOpponent->bSide == 0)
{
	//stay visible
}
else
#endif
{

	if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
	{	
		if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
			pOpponent->bVisible = 0;
	}
	else
	{
	if ((pOpponent->bTeam != gbPlayerNum) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife)
		pOpponent->bVisible = 0;
	}

}//haydent

#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("OTHERTEAMSLOOKFORMAN ID %d(%S) team %d side %d",pOpponent->ubID,pOpponent->name,pOpponent->bTeam,pOpponent->bSide ));
#endif


	// all soldiers not on oppPtr's team now look for him
	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pSoldier = MercSlots[ uiLoop ];

		// if this merc is active, in this sector, and well enough to look
		if (pSoldier != NULL && pSoldier->stats.bLife >= OKLIFE	&& (pSoldier->ubBodyType != LARVAE_MONSTER))
		{
			// if this merc is on the same team as the target soldier
			if (pSoldier->bTeam == pOpponent->bTeam)
			{
				continue;		// he doesn't look (he ALWAYS knows about him)
			}

			bOldOppList = pSoldier->aiData.bOppList[pOpponent->ubID];

			// this merc looks for the soldier in question
			// use both sides actual x,y co-ordinates (neither side's moving)
			if (ManLooksForMan(pSoldier,pOpponent,OTHERTEAMSLOOKFORMAN))
			{
				// if a new opponent is seen (which must be oppPtr himself)
				//if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && pSoldier->bNewOppCnt)
				// Calc interrupt points in non-combat because we might get an interrupt or be interrupted
				// on our first turn

				// if doing regular in-combat sighting (not on opening doors!)
				if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_INCOMBAT )
				{
					if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && pSoldier->bNewOppCnt )
					{
						// as long as viewer meets minimum interrupt conditions
						if ( gubSightFlags & SIGHT_INTERRUPT && StandardInterruptConditionsMet(pSoldier,pOpponent->ubID,bOldOppList))
						{
							// calculate the interrupt duel points
							pSoldier->aiData.bInterruptDuelPts = CalcInterruptDuelPts(pSoldier, pOpponent->ubID, TRUE);
							DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in OtherTeamsLookForMan, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
						}
						else
						{
							pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
						}
					}
				}
			}

			// if "Show only enemies seen" option is ON and it's this guy looking
			//if (ptr->guynum == ShowOnlySeenPerson)
			//NewShowOnlySeenPerson(ptr);					// update the string
		}
	}


	// if he's not on our team
	if (pOpponent->bTeam != gbPlayerNum)
	{
	// don't do a locate here, it's already done by Man Sees Man for new opps.
	DecideTrueVisibility(pOpponent,NOLOCATE);
	}
}

void AddOneOpponent(SOLDIERTYPE *pSoldier)
{
	INT8 bOldOppCnt = pSoldier->aiData.bOppCnt;

	pSoldier->aiData.bOppCnt++;

	if (!bOldOppCnt)
	{
		// if we hadn't known about opponents being here for sure prior to this
		if (pSoldier->ubBodyType == LARVAE_MONSTER)
		{
			// never become aware of you!
			return;
		}

		if (pSoldier->aiData.bAlertStatus < STATUS_RED)
		{
			CheckForChangingOrders(pSoldier);
		}

		pSoldier->aiData.bAlertStatus = STATUS_BLACK;	// force black AI status right away

		if (pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER)
		{
			pSoldier->aiData.ubCaller = NOBODY;
			pSoldier->aiData.bCallPriority = 0;
		}
	}

	if (pSoldier->bTeam == gbPlayerNum)
	{
		// adding an opponent for player; reset # of turns that we haven't seen an enemy
		gTacticalStatus.bConsNumTurnsNotSeen = 0;
	}

}



void RemoveOneOpponent(SOLDIERTYPE *pSoldier)
{
 pSoldier->aiData.bOppCnt--;

 if ( pSoldier->aiData.bOppCnt < 0 )
 {
	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Oppcnt for %d (%s) tried to go below 0", pSoldier->ubID, pSoldier->name ) );
	#ifdef JA2BETAVERSION
		ScreenMsg( MSG_FONT_YELLOW, MSG_UI_FEEDBACK,	L"Opponent counter dropped below 0 for person %d (%s). Please inform Sir-tech of this, and what has just been happening in the game.", pSoldier->ubID, pSoldier->name );
	#endif
	pSoldier->aiData.bOppCnt = 0;
 }

 // if no opponents remain in sight, drop status to RED (but NOT newSit.!)
 if (!pSoldier->aiData.bOppCnt)
	pSoldier->aiData.bAlertStatus = STATUS_RED;
}




void RemoveManAsTarget(SOLDIERTYPE *pSoldier)
{

 SOLDIERTYPE *pOpponent;
 UINT8 ubTarget,ubLoop;


 ubTarget = pSoldier->ubID;

 // clean up the public opponent lists and locations
 for (ubLoop = 0; ubLoop < MAXTEAMS; ubLoop++)
	// never causes any additional looks
	UpdatePublic(ubLoop,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);

/*


IAN COMMENTED THIS OUT MAY 1997 - DO WE NEED THIS?

 // make sure this guy is no longer a possible target for anyone
 for (cnt = 0, pOpponent = Menptr; cnt < MAXMERCS; cnt++,pOpponent++)
	{
	if (pOpponent->bOppNum == ubTarget)
		pOpponent->bOppNum = NOBODY;
	}

	*/


	// clean up all opponent's opplists
	for (ubLoop = 0; ubLoop < guiNumMercSlots; ubLoop++)
	{
		pOpponent = MercSlots[ ubLoop ];

	// if the target is active, a true opponent and currently seen by this merc
		if (pOpponent)
		{
			// check to see if OPPONENT considers US neutral
			if ( (pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY) && !pOpponent->aiData.bNeutral && (pSoldier->bSide != pOpponent->bSide) )
			{
				// Flugente: we consider enemies to be neutral if they are prisoners of war (otherwise the AI would kill prisoners). Bu as we want to remove them, we have to account for that
				// we also move RecognizeAsCombatant to be the last condition checked, because it is the most computationally expensive one
				if ( ( !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) || pSoldier->usSoldierFlagMask & SOLDIER_POW ) && pOpponent->RecognizeAsCombatant(pSoldier->ubID) )
					RemoveOneOpponent(pOpponent);
			}
			UpdatePersonal(pOpponent,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);
			gbSeenOpponents[ubLoop][ubTarget] = FALSE;
		}
	}

/*

 for (ubLoop = 0,pOpponent = Menptr; ubLoop < MAXMERCS; ubLoop++,pOpponent++)
	{
	// if the target is a true opponent and currently seen by this merc
	if (!pSoldier->aiData.bNeutral && !pSoldier->aiData.bNeutral &&
		(pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY)

			)
			///*** UNTIL ANDREW GETS THE SIDE PARAMETERS WORKING
		// && (pSoldier->side != pOpponent->side))
	{
	 RemoveOneOpponent(pOpponent);
	}

	UpdatePersonal(pOpponent,ubTarget,NOT_HEARD_OR_SEEN,NOWHERE,0);

	gbSeenOpponents[ubLoop][ubTarget] = FALSE;
	}
*/

 ResetLastKnownLocs(pSoldier);

 if (gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio == ubTarget)
	gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio = NOBODY;


}






void UpdatePublic(UINT8 ubTeam, UINT8 ubID, INT8 bNewOpplist, INT32 sGridNo, INT8 bLevel)
{
 INT32 cnt;
 INT8 *pbPublOL;
 UINT8 ubTeamMustLookAgain = FALSE, ubMadeDifference = FALSE;
 SOLDIERTYPE *pSoldier;


 pbPublOL = &(gbPublicOpplist[ubTeam][ubID]);

 // if new opplist is more up-to-date, or we are just wiping it for some reason
 if ((gubKnowledgeValue[*pbPublOL - OLDEST_HEARD_VALUE][bNewOpplist - OLDEST_HEARD_VALUE] > 0) ||
	 (bNewOpplist == NOT_HEARD_OR_SEEN))
	{
	// if this team is becoming aware of a soldier it wasn't previously aware of
	if ((bNewOpplist != NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
	 ubTeamMustLookAgain = TRUE;

	// change the public opplist *BEFORE* anyone looks again or we'll recurse!
	*pbPublOL = bNewOpplist;
	}


 // always update the gridno, no matter what
 gsPublicLastKnownOppLoc[ubTeam][ubID] = sGridNo;
 gbPublicLastKnownOppLevel[ubTeam][ubID] = bLevel;

 // if team has been told about a guy the team was completely unaware of
 if (ubTeamMustLookAgain)
	{
		// then everyone on team who's not aware of guynum must look for him
		cnt = gTacticalStatus.Team[ubTeam].bFirstID;

		for (pSoldier = MercPtrs[cnt]; cnt <= gTacticalStatus.Team[ubTeam].bLastID; ++cnt, pSoldier++)
		{
			// if this soldier is active, in this sector, and well enough to look
			if (pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE) && !( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) )
	 {
		// if soldier isn't aware of guynum, give him another chance to see
		if (pSoldier->aiData.bOppList[ubID] == NOT_HEARD_OR_SEEN)
			{
					if (ManLooksForMan(pSoldier,MercPtrs[ubID],UPDATEPUBLIC))
						// then he actually saw guynum because of our new public knowledge
						ubMadeDifference = TRUE;

					// whether successful or not, whack newOppCnt.	Since this is a
					// delayed reaction to a radio call, there's no chance of interrupt!
					pSoldier->bNewOppCnt = 0;

					// if "Show only enemies seen" option is ON and it's this guy looking
					//if (pSoldier->ubID == ShowOnlySeenPerson)
						// NewShowOnlySeenPerson(pSoldier);					// update the string
			}
		}
	}
 }
}




void UpdatePersonal(SOLDIERTYPE *pSoldier, UINT8 ubID, INT8 bNewOpplist, INT32 sGridNo, INT8 bLevel)
{
	/*
#ifdef RECORDOPPLIST
	fprintf(OpplistFile,"UpdatePersonal - for %d about %d to %d (was %d) at g%d\n",	ptr->guynum,guynum,newOpplist,ptr->opplist[guynum],gridno);
#endif
	*/
	
	// if new opplist is more up-to-date, or we are just wiping it for some reason
	if ((gubKnowledgeValue[pSoldier->aiData.bOppList[ubID] - OLDEST_HEARD_VALUE][bNewOpplist - OLDEST_HEARD_VALUE] > 0) || (bNewOpplist == NOT_HEARD_OR_SEEN))
	{
		pSoldier->aiData.bOppList[ubID] = bNewOpplist;
	}

	// always update the gridno, no matter what
	gsLastKnownOppLoc[pSoldier->ubID][ubID] = sGridNo;
	gbLastKnownOppLevel[pSoldier->ubID][ubID] = bLevel;
}





INT8 OurMaxPublicOpplist()
{
 UINT32 uiLoop;
 INT8 bHighestOpplist = 0;
 UINT8 ubOppValue,ubHighestValue = 0;
 SOLDIERTYPE * pSoldier;

 for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
	pSoldier = MercSlots[ uiLoop ];

	// if this merc is inactive, at base, on assignment, or dead
	if (!pSoldier || !pSoldier->stats.bLife)
		continue;		// next merc

	// if this man is NEUTRAL / on our side, he's not an opponent
	if (pSoldier->aiData.bNeutral || (gTacticalStatus.Team[gbPlayerNum].bSide == Menptr[pSoldier->ubID].bSide))
	 continue;		// next merc

	// opponent, check our public opplist value for him
	ubOppValue = gubKnowledgeValue[0 - OLDEST_HEARD_VALUE][gbPublicOpplist[gbPlayerNum][pSoldier->ubID] - OLDEST_HEARD_VALUE];

	if (ubOppValue > ubHighestValue)
	{
	 ubHighestValue = ubOppValue;
	 bHighestOpplist = gbPublicOpplist[gbPlayerNum][pSoldier->ubID];
	}
	}

 return(bHighestOpplist);
}




/*
BOOLEAN VisibleAnywhere(SOLDIERTYPE *pSoldier)
{
 INT8 team,cnt;
 SOLDIERTYPE *pOpponent;


 // this takes care of any mercs on our own team
 if (pSoldier->bVisible >= 0)
	return(TRUE);

 // if playing alone, "anywhere" is just over here!
 //if (!Net.multiType || Net.activePlayers < 2)
	//return(FALSE);


 for (bTeam = 0; bTeam < MAXTEAMS; bTeam++)
	{
	// skip our team (local visible flag will do for them)
	if (bTeam == gbPlayerNum)
	 continue;

	// skip any inactive teams
	if (!gTacticalStatus.team[bTeam].teamActive)
	 continue;

	// skip non-human teams (they don't communicate for their machines!)
	if (!gTacticalStatus.Team[bTeam].human)
	 continue;

	// so we're left with another human player's team of mercs...

	// check if soldier is currently visible to any human mercs on other teams
	for (cnt = Status.team[team].guystart,oppPtr = Menptr + cnt; cnt < Status.team[team].guyend; cnt++,oppPtr++)
	{
	 // if this merc is inactive, or in no condition to care
	 if (!oppPtr->active || !oppPtr->in_sector || oppPtr->deadAndRemoved || (oppPtr->life < OKLIFE))
		continue;			// skip him!

	 if (oppPtr->opplist[ptr->guynum] == SEEN_CURRENTLY)
		return(TRUE);
	}
	}


 // nobody anywhere sees him
 return(FALSE);
}

*/


void ResetLastKnownLocs(SOLDIERTYPE *pSoldier)
{
	UINT32 uiLoop;

	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		if (MercSlots[uiLoop])
		{
			gsLastKnownOppLoc[pSoldier->ubID][MercSlots[uiLoop]->ubID] = NOWHERE;

			// IAN added this June 14/97
			gsPublicLastKnownOppLoc[pSoldier->bTeam][MercSlots[uiLoop]->ubID] = NOWHERE;
		}
	}
}



/*
// INITIALIZATION STUFF
-------------------------
// Upon loading a scenario, call these:
InitOpponentKnowledgeSystem();

// loop through all soldiers and for each soldier call
InitSoldierOpplist(pSoldier);

// call this once
AllTeamsLookForAll(NO_INTERRUPTS);	// no interrupts permitted this early


// for each additional soldier created, call
InitSoldierOpplist(pSoldier);
HandleSight(pSoldier,SIGHT_LOOK);



MOVEMENT STUFF
-----------------
// whenever new tile is reached, call
HandleSight(pSoldier,SIGHT_LOOK);

*/

void InitOpponentKnowledgeSystem(void)
{
	INT32	iTeam, cnt, cnt2;

	memset(gbSeenOpponents,0,sizeof(gbSeenOpponents));
	memset(gbPublicOpplist,NOT_HEARD_OR_SEEN,sizeof(gbPublicOpplist));

	for (iTeam=0; iTeam < MAXTEAMS; iTeam++)
	{
		gubPublicNoiseVolume[iTeam] = 0;
		gsPublicNoiseGridNo[iTeam] = NOWHERE;
		gbPublicNoiseLevel[iTeam] = 0;
		for (cnt = 0; cnt < MAX_NUM_SOLDIERS; cnt++)
		{
			gsPublicLastKnownOppLoc[ iTeam ][ cnt ] = NOWHERE;
		}
	}

	// initialize public last known locations for all teams
	for (cnt = 0; cnt < MAX_NUM_SOLDIERS; cnt++)
	{
		for (cnt2 = 0; cnt2 < NUM_WATCHED_LOCS; cnt2++ )
		{
			gsWatchedLoc[ cnt ][ cnt2 ] = NOWHERE;
			gubWatchedLocPoints[ cnt ][ cnt2 ] = 0;
			gfWatchedLocReset[ cnt ][ cnt2 ] = FALSE;
		}
	}

	for ( cnt = 0; cnt < SHOULD_BECOME_HOSTILE_SIZE; cnt++ )
	{
		gubShouldBecomeHostileOrSayQuote[ cnt ] = NOBODY;
	}

	gubNumShouldBecomeHostileOrSayQuote = 0;
}



void InitSoldierOppList(SOLDIERTYPE *pSoldier)
{
	memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
	pSoldier->aiData.bOppCnt = 0;
	ResetLastKnownLocs(pSoldier);
	memset(gbSeenOpponents[pSoldier->ubID], 0, TOTAL_SOLDIERS);
}


void BetweenTurnsVisibilityAdjustments(void)
{
	INT32 cnt;
	SOLDIERTYPE *pSoldier;


	// make all soldiers on other teams that are no longer seen not visible
	for (cnt = 0, pSoldier = Menptr; cnt < MAXMERCS; cnt++,pSoldier++)
	{
		if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife)
		{
			BOOLEAN SEE_MENT = FALSE;

#ifdef ENABLE_MP_FRIENDLY_PLAYERS_SHARE_SAME_FOV
		if(is_networked &&  pSoldier->bSide == 0)//haydent
		{
			//stay visible
		}
		else
#endif
		{
			
			if (gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa)
			{if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM)
			SEE_MENT = TRUE;
			}
			else
			{ if (!PTR_OURTEAM) SEE_MENT = TRUE;
			}

		}//haydent
			
/*comm by ddd
#ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA
			if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM)
#else
			if (!PTR_OURTEAM)
#endif
				*/

			if(SEE_MENT)
			{
				// check if anyone on our team currently sees him (exclude NOBODY)
				if (TeamNoLongerSeesMan(gbPlayerNum,pSoldier,NOBODY,0))
				{
					// then our team has lost sight of him
					pSoldier->bVisible = -1;		// make him fully invisible

					// Allow fade to adjust anim speed
				}
			}
		}
	}
}


void SaySeenQuote( SOLDIERTYPE *pSoldier, BOOLEAN fSeenCreature, BOOLEAN fVirginSector, BOOLEAN fSeenJoey )
{
	SOLDIERTYPE		*pTeamSoldier;
	UINT8				ubNumEnemies = 0;
	UINT8				ubNumAllies = 0;
	UINT32			cnt;
#ifdef JA2UB
//Ja25 No meanwhiles
#else
	if ( AreInMeanwhile( ) )
	{
		return;
	}
#endif
	// Check out for our under large fire quote
	if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_IN_SHIT ) )
	{
		// Get total enemies.
		// Loop through all mercs in sector and count # of enemies
		for ( cnt = 0; cnt < guiNumMercSlots; ++cnt )
		{
			pTeamSoldier = MercSlots[ cnt ];

			if ( pTeamSoldier != NULL )
			{
				if ( OK_ENEMY_MERC( pTeamSoldier ) )
				{
					++ubNumEnemies;
				}
			}
		}

		// OK, after this, check our guys
		for ( cnt = 0; cnt < guiNumMercSlots; ++cnt )
		{
			pTeamSoldier = MercSlots[ cnt ];

			if ( pTeamSoldier != NULL )
			{
				if ( !OK_ENEMY_MERC( pTeamSoldier ) )
				{
					if ( pTeamSoldier->aiData.bOppCnt >= ( ubNumEnemies / 2 ) )
					{
						++ubNumAllies;
					}
				}
			}
		}

		// now check!
		if ( ( pSoldier->aiData.bOppCnt - ubNumAllies ) > 2 )
		{
			// Say quote!
			TacticalCharacterDialogue( pSoldier, QUOTE_IN_TROUBLE_SLASH_IN_BATTLE );
			//pSoldier->ubLastEnemyAttackingProvokingQuote = 
			pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_IN_SHIT;

			return;
		}
	}

	if ( fSeenCreature == 1 )
	{
		// Is this our first time seeing them?
		if ( gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_HAVESEENCREATURE )
		{
			// Are there multiplaes and we have not said this quote during this battle?
			if ( !(	pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES ) )
			{
				// Check for multiples!
				ubNumEnemies = 0;

				// Get total enemies.
				// Loop through all mercs in sector and count # of enemies
				for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
				{
					pTeamSoldier = MercSlots[ cnt ];

					if ( pTeamSoldier != NULL )
					{
						if ( OK_ENEMY_MERC( pTeamSoldier ) )
						{
							if ( pTeamSoldier->flags.uiStatusFlags & SOLDIER_MONSTER && pSoldier->aiData.bOppList[ pTeamSoldier->ubID ] == SEEN_CURRENTLY )
							{
								ubNumEnemies++;
							}
						}
					}
				}

				if ( ubNumEnemies > 2 )
				{
					// Yes, set flag
					pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_MULTIPLE_CREATURES;

					// Say quote
					TacticalCharacterDialogue( pSoldier, QUOTE_ATTACKED_BY_MULTIPLE_CREATURES );
				}
				else
				{
					TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE );
				}
			}
			else
			{
				TacticalCharacterDialogue( pSoldier, QUOTE_SEE_CREATURE );
			}
		}
		else
		{
			// Yes, set flag
			gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_HAVESEENCREATURE;

			TacticalCharacterDialogue( pSoldier, QUOTE_FIRSTTIME_GAME_SEE_CREATURE );
		}
	}
	// 2 is for bloodcat...
	else if ( fSeenCreature == 2 )
	{
		TacticalCharacterDialogue( pSoldier, QUOTE_SPOTTED_BLOODCAT );
	}
	else
	{
		if ( fVirginSector )
		{
			// First time we've seen a guy this sector
			TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY_VARIATION );
		}
		else
		{
			// Flugente: no quotes on seeing enemy when covert
			if ( (pSoldier->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) ) == 0 )
			{
				// Flugente: apparently the goal was to have mercs only announce enemies shorter occasionally
				if ( Chance( gGameExternalOptions.iChanceSayAnnoyingPhrase ) )
				{
					TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
				}
				else
				{
					pSoldier->DoMercBattleSound( BATTLE_SOUND_ENEMY );
				}
			}
		}
	}
}

void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumNewEnemies )
{
	if ( gTacticalStatus.fVirginSector )
	{
		// If we are in NPC dialogue now... stop!
		DeleteTalkingMenu( );

		// Say quote!
		SaySeenQuote( pSoldier, gfPlayerTeamSawCreatures, TRUE, gfPlayerTeamSawJoey );

		pSoldier->HaultSoldierFromSighting( TRUE );

		// Set virgin sector to false....
		gTacticalStatus.fVirginSector = FALSE;
	}
	else
	{
		// if this merc is selected and he's actually moving
		//if ((pSoldier->ubID == gusSelectedSoldier) && !pSoldier->pathing.bLevel)
		// ATE: Change this to if the guy is ours....
		// How will this feel?
		if ( pSoldier->bTeam == gbPlayerNum )
		{
			// Flugente: disguised mercs do not alert us if they see an enemy, as otherwise one has to continously give them new orders
			if ( !(pSoldier->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) )
			{
				// STOP IF WE WERE MOVING....
				/// Speek up!
				if ( bNumReRevealed > 0 && bNumNewEnemies == 0 )
				{
					pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
				}
				else
				{
					SaySeenQuote( pSoldier, gfPlayerTeamSawCreatures, FALSE, gfPlayerTeamSawJoey );
				}

				pSoldier->HaultSoldierFromSighting( TRUE );

				if ( gTacticalStatus.fEnemySightingOnTheirTurn )
				{
					// Locate to our guy, then slide to enemy
					LocateSoldier( pSoldier->ubID, SETLOCATOR );

					// Now slide to other guy....
					SlideTo( NOWHERE, gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID, NOBODY ,SETLOCATOR);

				}

				// Unset User's turn UI
				UnSetUIBusy( pSoldier->ubID );
			}
		}
	}

	// OK, check what music mode we are in, change to battle if we're in battle
	// If we are in combat....
	if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
	{
		// If we are NOT in any music mode...
		if ( GetMusicMode() == MUSIC_NONE )
		{
			#ifdef NEWMUSIC
			GlobalSoundID  = MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ];
			if ( MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ] != -1 )
				SetMusicModeID( MUSIC_TACTICAL_BATTLE, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalBattle[gbWorldSectorZ] );
			else
			#endif
			SetMusicMode( MUSIC_TACTICAL_BATTLE );
		}
	}


}

void RadioSightings(SOLDIERTYPE *pSoldier, UINT8 ubAbout, UINT8 ubTeamToRadioTo )
{
 SOLDIERTYPE *pOpponent;
 INT32 	iLoop;
 UINT8 	start,end,revealedEnemies = 0,unknownEnemies = 0,stillUnseen=TRUE;
 UINT8 	scrollToGuynum = NOBODY,sightedHatedOpponent = FALSE;
 //UINT8 	oppIsCivilian;
 INT8 	*pPersOL,*pbPublOL; //,dayQuote;
 BOOLEAN	fContactSeen;
 BOOLEAN fSawCreatureForFirstTime = FALSE;


#ifdef TESTOPPLIST
DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RADIO SIGHTINGS: for %d about %d",pSoldier->ubID,ubAbout) );
#endif



#ifdef RECORDNET
 if (!ptr->human)
	fprintf(NetDebugFile,"\tNPC %d(%s) radios his sightings to his team\n",ptr->guynum,ExtMen[ptr->guynum].name);
#endif

 gTacticalStatus.Team[pSoldier->bTeam].ubLastMercToRadio = pSoldier->ubID;






 // who are we radioing about?
 if (ubAbout == EVERYBODY)
	{
	start	= 0;
	end		= MAXMERCS;
	}
 else
	{
	start	= ubAbout;
	end 		= ubAbout + 1;
	}


 // hang a pointer to the start of our this guy's personal opplist
 pPersOL = &(pSoldier->aiData.bOppList[start]);

 // hang a pointer to the start of this guy's opponents in the public opplist
 pbPublOL = &(gbPublicOpplist[ubTeamToRadioTo][start]);

	pOpponent = MercPtrs[start];

	// loop through every one of this guy's opponents
	for (iLoop = start; iLoop < end; ++iLoop,pOpponent++,pPersOL++,pbPublOL++)
	{
		fContactSeen = FALSE;

#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: checking %d",pOpponent->ubID) );
#endif


	// make sure this merc is active, here & still alive (unconscious OK)
	if (!pOpponent->bActive || !pOpponent->bInSector || !pOpponent->stats.bLife)
	{
#ifdef TESTOPPLIST
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: inactive/notInSector/life %d",pOpponent->ubID) );
#endif


	 continue;							// skip to the next merc
	}

	// if these two mercs are on the same SIDE, then they're NOT opponents
	// NEW: Apr. 21 '96: must allow ALL non-humans to get radioed about
	if ((pSoldier->bSide == pOpponent->bSide) && (pOpponent->flags.uiStatusFlags & SOLDIER_PC))
	{
#ifdef TESTOPPLIST
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: same side %d",pSoldier->bSide) );
#endif

	 continue;							// skip to the next merc
	}

	// determine whether we think we're still unseen or if "our cover's blown"
	// if we know about this opponent's location for any reason
	if ((pOpponent->bVisible >= 0) || gbShowEnemies)
	{
	 // and he can see us, then gotta figure we KNOW that he can see us
	 if (pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY)
		stillUnseen = FALSE;
	}


	// if we personally don't know a thing about this opponent
	if (*pPersOL == NOT_HEARD_OR_SEEN)
	{
#ifdef RECORDOPPLIST
	 //fprintf(OpplistFile,"not heard or seen\n");
#endif

#ifdef TESTOPPLIST
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: not heard or seen") );
#endif

	 continue;							// skip to the next opponent
	}

	// if personal knowledge is NOT more up to date and NOT the same as public
	if ((!gubKnowledgeValue[*pbPublOL - OLDEST_HEARD_VALUE][*pPersOL - OLDEST_HEARD_VALUE]) &&
		(*pbPublOL != *pPersOL))
	{
#ifdef RECORDOPPLIST
	 //fprintf(OpplistFile,"no new knowledge (per %d, pub %d)\n",*pPersOL,*pbPublOL);
#endif

#ifdef TESTOPPLIST
			DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: no new knowledge per %d pub %d",*pPersOL,*pbPublOL) );
#endif



		continue;							// skip to the next opponent
	}

#ifdef RECORDOPPLIST
	//fprintf(OpplistFile,"made it!\n");
#endif

#ifdef TESTOPPLIST
		DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("RS: made it!") );
#endif



	// if it's our merc, and he currently sees this opponent
	if (PTR_OURTEAM && (*pPersOL == SEEN_CURRENTLY) && !(( pOpponent->bSide == pSoldier->bSide) || pOpponent->aiData.bNeutral))
	{
	// used by QueueDayMessage() to scroll to one of the new enemies
	// scroll to the last guy seen, unless we see a hated guy, then use him!
	if (!sightedHatedOpponent)
		scrollToGuynum = pOpponent->ubID;

	// don't care whether and how many new enemies are seen if everyone visible
	// and he's healthy enough to be a threat (so is worth talking about)

		// do the following if we're radioing to our own team; if radioing to militia
		// then alert them instead
		if ( ubTeamToRadioTo != MILITIA_TEAM )
		{
			if (!gbShowEnemies && (pOpponent->stats.bLife >= OKLIFE))
			{
				// if this enemy has not been publicly seen or heard recently
				if (*pbPublOL == NOT_HEARD_OR_SEEN)
			{
				// chalk up another "unknown" enemy
				unknownEnemies++;

					fContactSeen = TRUE;
					// if this enemy is hated by the merc doing the sighting
				//if (MercHated(Proptr[ptr->characternum].p_bias,oppPtr->characternum))
					//sightedHatedOpponent = TRUE;

				// now the important part: does this enemy see him/her back?
				if (pOpponent->aiData.bOppList[pSoldier->ubID] != SEEN_CURRENTLY)
	 		{
					// EXPERIENCE GAIN (10): Discovered a new enemy without being seen
					StatChange(pSoldier,EXPERAMT,10,FALSE);
	 		}
				}
				else
			{

				// if he has publicly not been seen now, or anytime during this turn
				if ((*pbPublOL != SEEN_CURRENTLY) && (*pbPublOL != SEEN_THIS_TURN))
						{
							// chalk up another "revealed" enemy
							++revealedEnemies;
							fContactSeen = TRUE;
						}
					else
					{
						if ( MercPtrs[0]->stats.bLife < 10 )
						{
							//int breakpoint = 0;
						}
					}
			}

				if ( fContactSeen )
				{
					if ( pSoldier->bTeam == gbPlayerNum )
					{
						if ( gTacticalStatus.ubCurrentTeam != gbPlayerNum )
						{
							// Save some stuff!
							if (gTacticalStatus.fEnemySightingOnTheirTurn)
							{
								// this has already come up so turn OFF the pause-all-anims flag for the previous
								// person and set it for this next person
								MercPtrs[gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID]->flags.fPauseAllAnimation = FALSE;
							}
							else
							{
								gTacticalStatus.fEnemySightingOnTheirTurn = TRUE;
							}
							gTacticalStatus.ubEnemySightingOnTheirTurnEnemyID = pOpponent->ubID;
							gTacticalStatus.ubEnemySightingOnTheirTurnPlayerID = pSoldier->ubID;
							gTacticalStatus.uiTimeSinceDemoOn = GetJA2Clock( );

							pOpponent->flags.fPauseAllAnimation = TRUE;

						}
					}

					if ( pOpponent->flags.uiStatusFlags & SOLDIER_MONSTER )
					{
						gfPlayerTeamSawCreatures = TRUE;
					}

					// ATE: Added for bloodcat...
					if ( pOpponent->ubBodyType == BLOODCAT )
					{
						// 2 is for bloodcat
						gfPlayerTeamSawCreatures = 2;
					}

				}

				if ( pOpponent->flags.uiStatusFlags & SOLDIER_MONSTER )
				{
					if ( !(gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_HAVESEENCREATURE) )
					{
						fSawCreatureForFirstTime = TRUE;
					}
				}

			}
		}
		else
		{
			// radioing to militia that we saw someone! alert them!
			if ( gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive && !gTacticalStatus.Team[ MILITIA_TEAM ].bAwareOfOpposition )
			{
				HandleInitialRedAlert( MILITIA_TEAM, FALSE );
			}
		}
	} 	// end of our team's merc sees new opponent

	// IF WE'RE HERE, OUR PERSONAL INFORMATION IS AT LEAST AS UP-TO-DATE
	// AS THE PUBLIC KNOWLEDGE, SO WE WILL REPLACE THE PUBLIC KNOWLEDGE
#ifdef RECORDOPPLIST
	fprintf(OpplistFile,"UpdatePublic (RadioSightings) for team %d about %d\n",ptr->team,oppPtr->guynum);
#endif


#ifdef TESTOPPLIST
	DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3,
			String("...............UPDATE PUBLIC: soldier %d SEEING soldier %d",pSoldier->ubID,pOpponent->ubID) );
#endif



	UpdatePublic(ubTeamToRadioTo,pOpponent->ubID,*pPersOL,gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID],gbLastKnownOppLevel[pSoldier->ubID][pOpponent->ubID]);
	}


 // if soldier heard a misc noise more important that his team's public one
 if (pSoldier->aiData.ubNoiseVolume > gubPublicNoiseVolume[ubTeamToRadioTo])
	{
	// replace the soldier's team's public noise with his
	gsPublicNoiseGridNo[ubTeamToRadioTo] 	= pSoldier->aiData.sNoiseGridno;
	gbPublicNoiseLevel[ubTeamToRadioTo] 	= pSoldier->bNoiseLevel;
	gubPublicNoiseVolume[ubTeamToRadioTo] 	= pSoldier->aiData.ubNoiseVolume;
	}


 // if this soldier is on the local team
	if (PTR_OURTEAM)
	{
	// don't trigger sighting quotes or stop merc's movement if everyone visible
	//if (!(gTacticalStatus.uiFlags & SHOW_ALL_MERCS))
	{
	 // if we've revealed any enemies, or seen any previously unknown enemies
	 if (revealedEnemies || unknownEnemies)
		{
				// First check for a virgin map and set to false if we see our first guy....
				// Only if this guy is an ememy!

				OurTeamSeesSomeone( pSoldier, revealedEnemies, unknownEnemies );
			}
			else if (fSawCreatureForFirstTime)
			{
				gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_HAVESEENCREATURE;
				TacticalCharacterDialogue( pSoldier, QUOTE_FIRSTTIME_GAME_SEE_CREATURE );
			}

	}
	}
}



#define COLOR1 FONT_MCOLOR_BLACK<<8 | FONT_MCOLOR_LTGREEN
#define COLOR2 FONT_MCOLOR_BLACK<<8 | FONT_MCOLOR_LTGRAY2

#define LINE_HEIGHT 15


extern UINT32 guiNumBackSaves;

void DebugSoldierPage1( )
{
	SOLDIERTYPE				*pSoldier;
	UINT16						usSoldierIndex;
	UINT32						uiMercFlags;
	INT32 usMapPos;
	UINT8							ubLine=0;

	if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
	{
		// Get Soldier
		GetSoldier( &pSoldier, usSoldierIndex );

		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG SOLDIER PAGE ONE, GRIDNO %d", pSoldier->sGridNo );
		SetFont( LARGEFONT1 );

		ubLine = 2;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"TEAM:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bTeam );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SIDE:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bSide );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"STATUS FLAGS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%x", pSoldier->flags.uiStatusFlags );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"HUMAN:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gTacticalStatus.Team[pSoldier->bTeam].bHuman);
		ubLine++;
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"APs:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bActionPoints );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Breath:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBreath );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Life:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bLife );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"LifeMax:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bLifeMax );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Bleeding:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBleeding );

		ubLine = 2;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Agility:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bAgility, EffectiveAgility( pSoldier, FALSE ) );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Dexterity:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d( %d )", pSoldier->stats.bDexterity, EffectiveDexterity( pSoldier, FALSE ) );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Strength:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bStrength );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Wisdom:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bWisdom, EffectiveWisdom( pSoldier ) );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Exp Lvl:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel( pSoldier ) );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Mrksmnship:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bMarksmanship, EffectiveMarksmanship( pSoldier ) );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Mechanical:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bMechanical);
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Explosive:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bExplosive);
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Medical:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 350, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bMedical);
		ubLine++;

		/*SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Drug Effects:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugEffect[0] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Drug Side Effects:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugSideEffect[0] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Booze Effects:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugEffect[1] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"Hangover Side Effects:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->drugs.bDrugSideEffect[1] );
		ubLine++;*/

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 200, LINE_HEIGHT * ubLine, L"AI has Keys:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 400, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.bHasKeys );
		ubLine++;
	}
	else if ( GetMouseMapPos( &usMapPos ) )
	{
		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG LAND PAGE ONE" );
		SetFont( LARGEFONT1 );

		ubLine++;
		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Num dirty rects:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 200, LINE_HEIGHT * ubLine, L"%d", guiNumBackSaves );
		ubLine++;


	}

}

void DebugSoldierPage2( )
{
	SOLDIERTYPE				*pSoldier;
	UINT16						usSoldierIndex;
	UINT32						uiMercFlags;
	INT32 usMapPos;
	TILE_ELEMENT							TileElem;
	LEVELNODE					*pNode;
	UINT8							ubLine;

	if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
	{
		// Get Soldier
		GetSoldier( &pSoldier, usSoldierIndex );

		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG SOLDIER PAGE TWO, GRIDNO %d", pSoldier->sGridNo );
		SetFont( LARGEFONT1 );

		ubLine = 2;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Body Type:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubBodyType );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Opp Cnt:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.bOppCnt);
		ubLine++;

		if (pSoldier->bTeam == OUR_TEAM || pSoldier->bTeam == MILITIA_TEAM)	// look at 8 to 15 opplist entries
		{
			SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
			gprintf( 0, LINE_HEIGHT * ubLine, L"Opplist B:");
			SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
			gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d %d %d %d %d %d", pSoldier->aiData.bOppList[20],pSoldier->aiData.bOppList[21],pSoldier->aiData.bOppList[22],
							pSoldier->aiData.bOppList[23],pSoldier->aiData.bOppList[24],pSoldier->aiData.bOppList[25],pSoldier->aiData.bOppList[26],pSoldier->aiData.bOppList[27]);
			ubLine++;
		}
		else	// team 1 - enemies so look at first 8 (0-7) opplist entries
		{
			SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
			gprintf( 0, LINE_HEIGHT * ubLine, L"OppList A:");
			SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
			gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d %d %d %d %d %d", pSoldier->aiData.bOppList[0],pSoldier->aiData.bOppList[1],pSoldier->aiData.bOppList[2],
							pSoldier->aiData.bOppList[3],pSoldier->aiData.bOppList[4],pSoldier->aiData.bOppList[5],pSoldier->aiData.bOppList[6],
							pSoldier->aiData.bOppList[7]);
			ubLine++;
		}

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Visible:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bVisible);
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Direction:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzDirectionStr[ pSoldier->ubDirection] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"DesDirection:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzDirectionStr[ pSoldier->pathing.bDesiredDirection] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"GridNo:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sGridNo );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Dest:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.sFinalDestination );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Path Size:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.usPathDataSize);
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Path Index:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->pathing.usPathIndex );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"First 3 Steps:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d", pSoldier->pathing.usPathingData[0],
		pSoldier->pathing.usPathingData[1],
		pSoldier->pathing.usPathingData[2] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Next 3 Steps:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d %d %d", pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex],
		pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex + 1],
		pSoldier->pathing.usPathingData[pSoldier->pathing.usPathIndex + 2] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"FlashInd:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fFlashLocator );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ShowInd:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fShowLocator );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Main hand:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HANDPOS].usItem] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Second hand:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SECONDHANDPOS].usItem] );
		ubLine++;

		if ( GetMouseMapPos( &usMapPos ) )
		{
			SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
			gprintf( 0, LINE_HEIGHT * ubLine, L"CurrGridNo:");
			SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
			gprintf( 150, LINE_HEIGHT * ubLine, L"%d", usMapPos );
			ubLine++;
		}

	}
	else if ( GetMouseMapPos( &usMapPos ) )
	{
		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG LAND PAGE TWO" );
		SetFont( LARGEFONT1 );

		ubLine = 1;

		SetFontColors(COLOR1);
		mprintf( 0, LINE_HEIGHT * ubLine, L"Land Raised:");
		SetFontColors(COLOR2);
		mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gpWorldLevelData[ usMapPos ].sHeight );
		ubLine++;

		SetFontColors(COLOR1);
		mprintf( 0, LINE_HEIGHT * ubLine, L"Land Node:");
		SetFontColors(COLOR2);
		mprintf( 150, LINE_HEIGHT * ubLine, L"%x", gpWorldLevelData[ usMapPos ].pLandHead );
		ubLine++;

		if ( gpWorldLevelData[ usMapPos ].pLandHead != NULL )
		{
			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Land Node:");
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gpWorldLevelData[ usMapPos ].pLandHead->usIndex );
			ubLine++;

			TileElem = gTileDatabase[ gpWorldLevelData[ usMapPos ].pLandHead->usIndex	];

			// Check for full tile
			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Full Land:");
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"%d", TileElem.ubFullTile );
			ubLine++;
		}

		SetFontColors(COLOR1);
		mprintf( 0, LINE_HEIGHT * ubLine, L"Land St Node:");
		SetFontColors(COLOR2);
		mprintf( 150, LINE_HEIGHT * ubLine, L"%x", gpWorldLevelData[ usMapPos ].pLandStart );
		ubLine++;

		SetFontColors(COLOR1);
		mprintf( 0, LINE_HEIGHT * ubLine, L"GRIDNO:");
		SetFontColors(COLOR2);
		//dnl ch85 060214
		INT16 sX, sY;
		ConvertGridNoToXY(usMapPos, &sX, &sY);
		mprintf( 150, LINE_HEIGHT * ubLine, L"%d (%d,%d)", usMapPos, sX, sY );
		ubLine++;

		if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_MOVEMENT_RESERVED )
		{
			SetFontColors(COLOR2);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Merc: %d",	gpWorldLevelData[ usMapPos ].ubReservedSoldierID );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"RESERVED MOVEMENT FLAG ON:" );
			ubLine++;
		}


		pNode =	GetCurInteractiveTile( );

		if ( pNode != NULL )
		{
			SetFontColors(COLOR2);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Tile: %d",	pNode->usIndex );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"ON INT TILE" );
			ubLine++;
		}


		if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_REVEALED )
		{
			SetFontColors(COLOR2);
			//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d",	gpWorldLevelData[ sMapPos ].ubReservedSoldierID );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"REVEALED" );
			ubLine++;
		}

		if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_RAISE_LAND_START )
		{
			SetFontColors(COLOR2);
			//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d",	gpWorldLevelData[ sMapPos ].ubReservedSoldierID );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"Land Raise Start" );
			ubLine++;
		}

		if ( gpWorldLevelData[ usMapPos ].uiFlags & MAPELEMENT_RAISE_LAND_END )
		{
			SetFontColors(COLOR2);
			//mprintf( 0, LINE_HEIGHT * 9, L"Merc: %d",	gpWorldLevelData[ usMapPos ].ubReservedSoldierID );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"Raise Land End" );
			ubLine++;
		}

		if (gusWorldRoomInfo[ usMapPos ] != NO_ROOM )
		{
			SetFontColors(COLOR2);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Room Number" );
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusWorldRoomInfo[ usMapPos ] );
			ubLine++;
		}

		if ( gpWorldLevelData[ usMapPos ].ubExtFlags[0] & MAPELEMENT_EXT_NOBURN_STRUCT )
		{
			SetFontColors(COLOR2);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Don't Use Burn Through For Soldier" );
			ubLine++;
		}

	}

}


void DebugSoldierPage3( )
{
	SOLDIERTYPE				*pSoldier;
	UINT16						usSoldierIndex;
	UINT32						uiMercFlags;
	INT32 usMapPos;
	UINT8							ubLine;

	if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
	{
		// Get Soldier
		GetSoldier( &pSoldier, usSoldierIndex );

		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG SOLDIER PAGE THREE, GRIDNO %d", pSoldier->sGridNo );
		SetFont( LARGEFONT1 );

		ubLine = 2;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Action:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzActionStr[ pSoldier->aiData.bAction ] );
		if (pSoldier->flags.uiStatusFlags & SOLDIER_ENEMY )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Alert %S", gzAlertStr[ pSoldier->aiData.bAlertStatus ] );
		}
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Action Data:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.usActionData );

		if (pSoldier->flags.uiStatusFlags & SOLDIER_ENEMY )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"AIMorale %d", pSoldier->aiData.bAIMorale );
		}
		else
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Morale %d", pSoldier->aiData.bMorale );
		}
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Delayed Movement:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fDelayedMovement );
		if ( gubWatchedLocPoints[ pSoldier->ubID ][ 0 ] > 0 )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
				gsWatchedLoc[ pSoldier->ubID ][ 0 ],
				gbWatchedLocLevel[ pSoldier->ubID ][ 0 ],
				gubWatchedLocPoints[ pSoldier->ubID ][ 0 ]
				);
		}

		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ActionInProg:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->aiData.bActionInProgress);
		ubLine++;
		if ( gubWatchedLocPoints[ pSoldier->ubID ][ 1 ] > 0 )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
				gsWatchedLoc[ pSoldier->ubID ][ 1 ],
				gbWatchedLocLevel[ pSoldier->ubID ][ 1 ],
				gubWatchedLocPoints[ pSoldier->ubID ][ 1 ]
				);
		}

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Last Action:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gzActionStr[ pSoldier->aiData.bLastAction ]	);
		ubLine++;

		if ( gubWatchedLocPoints[ pSoldier->ubID ][ 2 ] > 0 )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
				gsWatchedLoc[ pSoldier->ubID ][ 2 ],
				gbWatchedLocLevel[ pSoldier->ubID ][ 2 ],
				gubWatchedLocPoints[ pSoldier->ubID ][ 2 ]
				);
		}

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Animation:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gAnimControl[ pSoldier->usAnimState ].zAnimStr );
		ubLine++;

/*
		if ( gubWatchedLocPoints[ pSoldier->ubID ][ 3 ] > 0 )
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Watch %d/%d for %d pts",
				gsWatchedLoc[ pSoldier->ubID ][ 3 ],
				gbWatchedLocLevel[ pSoldier->ubID ][ 3 ],
				gubWatchedLocPoints[ pSoldier->ubID ][ 3 ]
				);
		}
*/

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Getting Hit:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fGettingHit );

		if (pSoldier->ubCivilianGroup != 0)
		{
			gprintf( 350, LINE_HEIGHT * ubLine, L"Civ group %d", pSoldier->ubCivilianGroup );
		}
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Suppress pts:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubSuppressionPoints );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Attacker ID:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubAttackerID );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"EndAINotCalled:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fTurnInProgress );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"PrevAnimation:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%S", gAnimControl[ pSoldier->usOldAniState ].zAnimStr );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"PrevAniCode:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusAnimInst[ pSoldier->usOldAniState ][ pSoldier->sOldAniCode ] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"GridNo:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sGridNo);
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"AniCode:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gusAnimInst[ pSoldier->usAnimState ][ pSoldier->usAniCode ] );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"No APS To fin Move:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fNoAPToFinishMove );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Reload Delay:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->sReloadDelay );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Reloading:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fReloading );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Bullets out:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->bBulletsLeft );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Anim non-int:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fInNonintAnim );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"RT Anim non-int:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->flags.fRTInNonintAnim );
		ubLine++;
		
		// OPIONION OF SELECTED MERC
		if ( gusSelectedSoldier != NOBODY && pSoldier->ubProfile != NO_PROFILE && (
			gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_AIM ||
			gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_MERC ||
			gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_RPC ||
			gMercProfiles[MercPtrs[gusSelectedSoldier]->ubProfile].Type == PROFILETYPE_IMP ) )
		{
			SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
			gprintf( 0, LINE_HEIGHT * ubLine, L"NPC Opinion:");
			SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
			if (OKToCheckOpinion(MercPtrs[ gusSelectedSoldier ]->ubProfile))
				gprintf( 150, LINE_HEIGHT * ubLine, L"%d", gMercProfiles[ pSoldier->ubProfile ].bMercOpinion[ MercPtrs[ gusSelectedSoldier ]->ubProfile ] );
			ubLine++;
		}
	}
	else if ( GetMouseMapPos( &usMapPos ) )
	{
		DOOR_STATUS	*pDoorStatus;
		STRUCTURE *pStructure;

		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG LAND PAGE THREE" );
		SetFont( LARGEFONT1 );

		// OK, display door information here.....
		pDoorStatus = GetDoorStatus( usMapPos );

		ubLine = 1;

		if ( pDoorStatus == NULL )
		{
			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Status");
			ubLine++;
			ubLine++;
			ubLine++;
		}
		else
		{
			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Door Status Found:");
			SetFontColors(COLOR2);
			mprintf( 150, LINE_HEIGHT * ubLine, L" %d", usMapPos );
			ubLine++;

			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Actual Status:");
			SetFontColors(COLOR2);

			if ( pDoorStatus->ubFlags & DOOR_OPEN )
			{
				mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
			}
			else
			{
				mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
			}
			ubLine++;


			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"Perceived Status:");
			SetFontColors(COLOR2);

			if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_NOTSET )
			{
				mprintf( 200, LINE_HEIGHT * ubLine, L"NOT SET" );
			}
			else
			{
				if ( pDoorStatus->ubFlags & DOOR_PERCEIVED_OPEN )
				{
					mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
				}
				else
				{
					mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
				}
			}
			ubLine++;
		}

		//Find struct data and se what it says......
		pStructure = FindStructure( usMapPos, STRUCTURE_ANYDOOR );

		if ( pStructure == NULL )
		{
			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"No Door Struct Data");
			ubLine++;
		}
		else
		{

			SetFontColors(COLOR1);
			mprintf( 0, LINE_HEIGHT * ubLine, L"State:");
			SetFontColors(COLOR2);
			if ( !(pStructure->fFlags & STRUCTURE_OPEN) )
			{
				mprintf( 200, LINE_HEIGHT * ubLine, L"CLOSED" );
			}
			else
			{
				mprintf( 200, LINE_HEIGHT * ubLine, L"OPEN" );
			}
			ubLine++;
		}
	}

}

void AppendAttachmentCode( UINT16 usItem, STR16 str )
{
	switch( usItem )
	{
		case SILENCER:
			wcscat( str, L" Sil" );
			break;
		case SNIPERSCOPE:
			wcscat( str, L" Scp" );
			break;
		case BIPOD:
			wcscat( str, L" Bip" );
			break;
		case LASERSCOPE:
			wcscat( str, L" Las" );
			break;
	}
}

void WriteQuantityAndAttachments( OBJECTTYPE *pObject, INT32 yp )
{
	CHAR16 szAttach[30];
	BOOLEAN fAttachments;
	//100%	Qty: 2	Attach:
	//100%	Qty: 2
	//100%	Attach:
	//100%
	if( pObject->exists() == false )
		return;
	//Build attachment string
	fAttachments = FALSE;
	if( (*pObject)[0]->AttachmentListSize() > 0 )
	{
		fAttachments = TRUE;
		swprintf( szAttach, L"(" );
		for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) {
			if(iter->exists())
				AppendAttachmentCode( iter->usItem, szAttach );
		}
		wcscat( szAttach, L" )" );
	}

	if( Item[pObject->usItem].usItemClass == IC_AMMO )
	{ //ammo
		if( pObject->ubNumberOfObjects > 1 )
		{
			CHAR16 str[100];
			CHAR16 temp[10];
			UINT8 i;
			swprintf( str, L"Clips:	%d	(%d", pObject->ubNumberOfObjects, (*pObject)[0]->data.objectStatus );
			for( i = 1; i < pObject->ubNumberOfObjects; i++ )
			{
				swprintf( temp, L", %d", (*pObject)[0]->data.objectStatus );
				wcscat( str, temp );
			}
			wcscat( str, L")" );
			gprintf( 320, yp, str );
		}
		else
			gprintf( 320, yp, L"%d rounds", (*pObject)[0]->data.objectStatus );
		return;
	}
	if( pObject->ubNumberOfObjects > 1 && fAttachments )
	{ //everything
		gprintf( 320, yp, L"%d%%	Qty:	%d	%s",
			(*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects, szAttach );
	}
	else if( pObject->ubNumberOfObjects > 1 )
	{ //condition and quantity
		gprintf( 320, yp, L"%d%%	Qty:	%d	",
			(*pObject)[0]->data.objectStatus, pObject->ubNumberOfObjects );
	}
	else if( fAttachments )
	{ //condition and attachments
		gprintf( 320, yp, L"%d%%	%s", (*pObject)[0]->data.objectStatus, szAttach );
	}
	else
	{ //condition
		gprintf( 320, yp, L"%d%%", (*pObject)[0]->data.objectStatus );
	}
}

void DebugSoldierPage4( )
{
	SOLDIERTYPE				*pSoldier;
	UINT32						uiMercFlags;
	CHAR16 szOrders[20];
	CHAR16 szAttitude[20];
	UINT16						usSoldierIndex;
	UINT8							ubLine;

	if ( FindSoldierFromMouse( &usSoldierIndex, &uiMercFlags ) )
	{
		// Get Soldier
		GetSoldier( &pSoldier, usSoldierIndex );

		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG SOLDIER PAGE FOUR, GRIDNO %d", pSoldier->sGridNo );
		SetFont( LARGEFONT1 );
		ubLine = 2;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"Exp. Level:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel(pSoldier) ); // SANDRO - added effective level calc
		switch( pSoldier->ubSoldierClass )
		{
			case SOLDIER_CLASS_ADMINISTRATOR:		gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" );	break;
			case SOLDIER_CLASS_ELITE:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Elite)" );		break;
			case SOLDIER_CLASS_ARMY:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Troop)" );		break;
			case SOLDIER_CLASS_CREATURE:			gprintf( 320, LINE_HEIGHT * ubLine, L"(Creature)" );		break;
			case SOLDIER_CLASS_GREEN_MILITIA:		gprintf( 320, LINE_HEIGHT * ubLine, L"(Green Militia)" );	break;
			case SOLDIER_CLASS_REG_MILITIA:			gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" );		break;
			case SOLDIER_CLASS_ELITE_MILITIA:		gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" );	break;
			case SOLDIER_CLASS_MINER:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" );			break;
			case SOLDIER_CLASS_ZOMBIE:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" );			break;
			case SOLDIER_CLASS_BANDIT:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Bandit)" );			break;
			case SOLDIER_CLASS_ROBOT:				gprintf( 320, LINE_HEIGHT * ubLine, L"(Army Robot)" );		break;

			default:	break; //don't care (don't write anything)
		}
		++ubLine;

		if( pSoldier->bTeam != OUR_TEAM )
		{
			SOLDIERINITNODE		*pNode;
			switch( pSoldier->aiData.bOrders )
			{
				case STATIONARY:	swprintf( szOrders, L"STATIONARY" );			break;
				case ONGUARD:			swprintf( szOrders, L"ON GUARD" );				break;
				case ONCALL:			swprintf( szOrders, L"ON CALL" );					break;
				case SEEKENEMY:		swprintf( szOrders, L"SEEK ENEMY" );			break;
				case CLOSEPATROL:	swprintf( szOrders, L"CLOSE PATROL" );		break;
				case FARPATROL:		swprintf( szOrders, L"FAR PATROL" );			break;
				case POINTPATROL:	swprintf( szOrders, L"POINT PATROL" );		break;
				case RNDPTPATROL:	swprintf( szOrders, L"RND PT PATROL" );		break;
				case SNIPER:		swprintf( szOrders, L"SNIPER" );		break;
				default:					swprintf( szOrders, L"UNKNOWN" );					break;
			}
			switch( pSoldier->aiData.bAttitude )
			{
				case DEFENSIVE:		swprintf( szAttitude, L"DEFENSIVE" );			break;
				case BRAVESOLO:		swprintf( szAttitude, L"BRAVE SOLO" );		break;
				case BRAVEAID:		swprintf( szAttitude, L"BRAVE AID" );			break;
				case AGGRESSIVE:	swprintf( szAttitude, L"AGGRESSIVE" );		break;
				case CUNNINGSOLO:	swprintf( szAttitude, L"CUNNING SOLO" );	break;
				case CUNNINGAID:	swprintf( szAttitude, L"CUNNING AID"	);	break;
				default:					swprintf( szAttitude, L"UNKNOWN" );				break;
			}
			pNode = gSoldierInitHead;
			while( pNode )
			{
				if( pNode->pSoldier == pSoldier )
					break;
				pNode = pNode->next;
			}
			SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
			if( pNode )
			{
				gprintf( 0, LINE_HEIGHT * ubLine, L"%s, %s, REL EQUIP: %d, REL ATTR: %d",
					szOrders, szAttitude, pNode->pBasicPlacement->bRelativeEquipmentLevel,
					pNode->pBasicPlacement->bRelativeAttributeLevel );
			}
			else
			{
				gprintf( 0, LINE_HEIGHT * ubLine, L"%s, %s", szOrders, szAttitude );
			}
			ubLine++;
		}

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"ID:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->ubID );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"HELMETPOS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[HELMETPOS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HELMETPOS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[HELMETPOS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"VESTPOS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[VESTPOS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[VESTPOS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[VESTPOS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"LEGPOS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[LEGPOS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[LEGPOS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[LEGPOS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"HEAD1POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[HEAD1POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HEAD1POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[HEAD1POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"HEAD2POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[HEAD2POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HEAD2POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[HEAD2POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"HANDPOS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[HANDPOS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[HANDPOS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[HANDPOS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SECONDHANDPOS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SECONDHANDPOS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SECONDHANDPOS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SECONDHANDPOS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK1POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK1POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK1POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK1POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK2POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK2POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK2POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK2POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK3POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK3POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK3POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK3POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK4POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK4POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK4POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK4POS], LINE_HEIGHT*ubLine );
		ubLine++;

		// CHRISL: Added entries for all the new inventory pockets.
		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK5POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK5POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK5POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK5POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK6POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK6POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK6POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK6POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"BIGPOCK7POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[BIGPOCK7POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[BIGPOCK7POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[BIGPOCK7POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK1POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[MEDPOCK1POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK1POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK1POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK2POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[MEDPOCK2POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK2POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK2POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK3POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[MEDPOCK3POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK3POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK3POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"MEDPOCK4POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[MEDPOCK4POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[MEDPOCK4POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[MEDPOCK4POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK1POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK1POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK1POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK1POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK2POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK2POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK2POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK2POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK3POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK3POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK3POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK3POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK4POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK4POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK4POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK4POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK5POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK5POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK5POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK5POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK6POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK6POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK6POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK6POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK7POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK7POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK7POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK7POS], LINE_HEIGHT*ubLine );
		ubLine++;

		// CHRISL: Added entries for all the new inventory pockets
		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK8POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK8POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK8POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK8POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK9POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK9POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK9POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK9POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK10POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK10POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK10POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK10POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK11POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK11POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK11POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK11POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK12POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK12POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK12POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK12POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK13POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK13POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK13POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK13POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK14POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK14POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK14POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK14POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK15POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK15POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK15POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK15POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK16POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK16POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK16POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK16POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK17POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK17POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK17POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK17POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK18POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK18POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK18POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK18POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK19POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK19POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK19POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK19POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK20POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK20POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK20POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK20POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK21POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK21POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK21POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK21POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK22POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK22POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK22POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK22POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK23POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK23POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK23POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK23POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK24POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK24POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK24POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK24POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK25POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK25POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK25POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK25POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK26POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK26POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK26POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK26POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK27POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK27POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK27POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK27POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK28POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK28POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK28POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK28POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK29POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK29POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK29POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK29POS], LINE_HEIGHT*ubLine );
		ubLine++;

		SetFontShade(LARGEFONT1, FONT_SHADE_GREEN);
		gprintf( 0, LINE_HEIGHT * ubLine, L"SMALLPOCK30POS:");
		SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL);
		if( pSoldier->inv[SMALLPOCK30POS].usItem )
			gprintf( 150, LINE_HEIGHT * ubLine, L"%s", ShortItemNames[pSoldier->inv[SMALLPOCK30POS].usItem] );
		WriteQuantityAndAttachments( &pSoldier->inv[SMALLPOCK30POS], LINE_HEIGHT*ubLine );
		ubLine++;
	}
	else
	{
		SetFont( LARGEFONT1 );
		gprintf( 0,0,L"DEBUG LAND PAGE FOUR" );
		SetFont( LARGEFONT1 );
	}
}

//
// Noise stuff
//

#define MAX_MOVEMENT_NOISE 9
#define VEHICLE_FAST_MOVEMENT_NOISE 25
#define VEHICLE_NORMAL_MOVEMENT_NOISE 15

UINT8 MovementNoise(SOLDIERTYPE *pSoldier)
{
	INT32	iStealthSkill, iRoll;
	INT16	sMaxVolume, sVolume;
	INT8	bBandaged, bEffLife;

	// anv: vehicle and passengers
	if (pSoldier->flags.uiStatusFlags & (SOLDIER_DRIVER | SOLDIER_PASSENGER))
	{
		return(0);
	}
	else if (pSoldier->flags.uiStatusFlags & (SOLDIER_VEHICLE))
	{
		if (pSoldier->usAnimState == RUNNING)
		{
			// driving fast makes engine work louder
			return(VEHICLE_FAST_MOVEMENT_NOISE);
		}
		else
		{
			return(VEHICLE_NORMAL_MOVEMENT_NOISE);
		}
	}

	// anv: additional tile properties
	// modify amount of noise and stealth difficulty depending on surface type

	INT8 bGroundVolumeModifier = 0;
	INT8 bGroundStealthDifficultyModifier = 0;
	ADDITIONAL_TILE_PROPERTIES_VALUES zGivenTileProperties;
	memset(&zGivenTileProperties, 0, sizeof(zGivenTileProperties));
	if (gGameExternalOptions.fAdditionalTileProperties)
	{
		zGivenTileProperties = GetAllAdditonalTilePropertiesForGrid(pSoldier->sGridNo, pSoldier->pathing.bLevel);
		bGroundVolumeModifier = zGivenTileProperties.bSoundModifier;
		bGroundStealthDifficultyModifier = zGivenTileProperties.bStealthDifficultyModifer;
	}
	if (pSoldier->bTeam == ENEMY_TEAM)
	{
		return((UINT8)(MAX_MOVEMENT_NOISE - PreRandom(2)) + bGroundVolumeModifier);
	}

	// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
	iStealthSkill = 20 + 4 * EffectiveExpLevel(pSoldier) + ((EffectiveAgility(pSoldier, FALSE) * 4) / 10); // 24-100

	// big bonus for those "extra stealthy" mercs
	if (pSoldier->ubBodyType == BLOODCAT)
	{
		iStealthSkill += 50;
	}
	// SANDRO - new/old traits
	else if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, STEALTHY_NT))
	{
		iStealthSkill += gSkillTraitValues.ubSTBonusToMoveQuietly;
	}
	else if (!gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, STEALTHY_OT))
	{
		iStealthSkill += 25 * NUM_SKILL_TRAITS(pSoldier, STEALTHY_OT);
	}

	INT16 wornstealth = GetWornStealth(pSoldier);
	if (wornstealth > 0)
		iStealthSkill += wornstealth / 2;

	bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
	bEffLife = pSoldier->stats.bLife + (bBandaged / 2);

	// IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
	if (bEffLife < 50)
	{
		// reduce effective stealth skill by up to 50% for low life
		iStealthSkill -= (iStealthSkill * (50 - bEffLife)) / 100;
	}

	// if breath is below 50%
	if (pSoldier->bBreath < 50)
	{
		// reduce effective stealth skill by up to 50%
		iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100;
	}

	// if sneaker is moving through water
	if (Water(pSoldier->sGridNo, pSoldier->pathing.bLevel))
	{
		iStealthSkill -= 10; // 10% penalty
	}
	else if (DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
	{
		iStealthSkill -= 20; // 20% penalty
	}

	iStealthSkill = __max(iStealthSkill, 0);

	if (!pSoldier->bStealthMode)	// REGULAR movement
	{
		//ubMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16);	// 9 - (0 to 6) => 3 to 9
		sMaxVolume = MAX_MOVEMENT_NOISE - (iStealthSkill / 16) + bGroundVolumeModifier;	// 9 - (0 to 6) => 3 to 9

		if (Water(pSoldier->sGridNo, pSoldier->pathing.bLevel))
		{
			sMaxVolume++;		// in water, can be even louder
		}
		switch (pSoldier->usUIMovementMode)
		{
		case CRAWLING:
			sMaxVolume -= 2;
			break;
		case SWATTING:
		case SWATTING_WK:
			sMaxVolume -= 1;
			break;
		case RUNNING:
			sMaxVolume += 3;
			break;
		}

		if (sMaxVolume < 2)
		{
			sVolume = sMaxVolume;
		}
		else
		{
			sVolume = 1 + (UINT8)PreRandom(sMaxVolume);	// actual volume is 1 to max volume
		}
	}
	else			// in STEALTH mode
	{
		iRoll = (INT32)PreRandom(100) + bGroundStealthDifficultyModifier;	// roll them bones!

		if (iRoll >= iStealthSkill)	// v1.13 modification: give a second chance!
		{
			iRoll = (INT32)PreRandom(100) + bGroundStealthDifficultyModifier;
		}

		if (iRoll < iStealthSkill)
		{
			sVolume = 0;	// made it, stayed quiet moving through this tile
		}
		else	// OOPS!
		{
			sVolume = 1 + ((iRoll - iStealthSkill + 1) / 16);	// volume is 1 - 7 ...
			switch (pSoldier->usUIMovementMode)
			{
			case CRAWLING:
				sVolume -= 2;
				break;
			case SWATTING:
			case SWATTING_WK:
				sVolume -= 1;
				break;
			case RUNNING:
				sVolume += 3;
				break;
			}
		}
	}

	// sevenfm: if dragging something, add dragging sound volume
	if(pSoldier->IsDraggingSomeone())
	{
		sVolume = max(sVolume, MAX_MOVEMENT_NOISE / 2 + Random(MAX_MOVEMENT_NOISE) + bGroundVolumeModifier);
	}

	sVolume = max(0, sVolume);
	sVolume = min(255, sVolume);

	return (UINT8)sVolume;
}

UINT8 DoorOpeningNoise( SOLDIERTYPE *pSoldier )
{
	// door being opened gridno is always the pending-action-data2 value
	INT32 sGridNo = pSoldier->aiData.sPendingActionData2;
	DOOR_STATUS	*pDoorStatus = GetDoorStatus( sGridNo );
	UINT8 ubDoorNoise = 0;

	// Find the base tile for the door structure and use that gridno
	STRUCTURE *pStructure = FindStructure(sGridNo, STRUCTURE_ANYDOOR);
	if (pStructure)
	{
		ubDoorNoise = 8;//shadooow: this indicates at how many tiles can be the noise heard (was 2 originally)
		// OK, check if this door is sliding and is multi-tiled...
		if (pStructure->fFlags & STRUCTURE_SLIDINGDOOR)
		{
			// Get database value...
			if (pStructure->pDBStructureRef->pDBStructure->ubNumberOfTiles > 1)
			{
				// garage doors
				ubDoorNoise += 4;
			}
			else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_CLOTH)
			{
				// curtains
				ubDoorNoise -= 4;
			}
		}
		else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_LIGHT_METAL ||
			pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_THICKER_METAL ||
			pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_HEAVY_METAL)
		{
			// metal doors
			ubDoorNoise += 2;
		}

		if (pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN)
		{
			//shadooow: do not allow stealth to work if there is can attached to doors
			ubDoorNoise += 4;
		}
		else if (pSoldier->bStealthMode)
		{
			// CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE
			INT32 iStealthSkill = 20 + 4 * EffectiveExpLevel(pSoldier) + ((EffectiveAgility(pSoldier, FALSE) * 4) / 10); // 24-100

			INT8 bEffLife = pSoldier->stats.bLife + ((pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding) / 2);

			// IF "SNEAKER'S" "EFFECTIVE LIFE" IS AT LESS THAN 50
			if (bEffLife < 50)
			{
				// reduce effective stealth skill by up to 50% for low life
				iStealthSkill -= (iStealthSkill * (50 - bEffLife)) / 100;
			}

			// if breath is below 50%
			if (pSoldier->bBreath < 50)
			{
				// reduce effective stealth skill by up to 50%
				iStealthSkill -= (iStealthSkill * (50 - pSoldier->bBreath)) / 100;
			}

			iStealthSkill = __max(iStealthSkill, 0);

			INT32 iRoll = (INT32)PreRandom(100);	// roll them bones!

			if (iRoll >= iStealthSkill)	// v1.13 modification: give a second chance!
			{
				iRoll = (INT32)PreRandom(100);
			}

			// succeeded in being stealthy!
			if (iRoll < iStealthSkill)
			{
				ubDoorNoise = 0;
			}
		}
	}

	return( ubDoorNoise );
}

void MakeNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType,  STR16 zNoiseMessage )
{
	EV_S_NOISE	SNoise;

	SNoise.ubNoiseMaker = ubNoiseMaker;
	SNoise.sGridNo = sGridNo;
	SNoise.bLevel = bLevel;
	SNoise.ubTerrType = ubTerrType;
	SNoise.ubVolume = ubVolume;
	SNoise.ubNoiseType = ubNoiseType;
	swprintf( SNoise.zNoiseMessage, L"%s", zNoiseMessage );
	//SNoise.zNoiseMessage = zNoiseMessage;

	if ( gTacticalStatus.ubAttackBusyCount )
	{
		// delay these events until the attack is over!
		AddGameEvent( S_NOISE, DEMAND_EVENT_DELAY, &SNoise );
	}
	else
	{
		// AddGameEvent( S_NOISE, 0, &SNoise );

		// now call directly
		OurNoise( SNoise.ubNoiseMaker, SNoise.sGridNo, SNoise.bLevel, SNoise.ubTerrType, SNoise.ubVolume, SNoise.ubNoiseType, SNoise.zNoiseMessage );
	}

/*
	INT8 bWeControlNoise = FALSE;

	if (ubNoiseMode == UNEXPECTED)
	{
		bWeControlNoise = TRUE;
	}
	else	// EXPECTED noise
	{
		if (ubNoiseMaker < TOTAL_SOLDIERS)
		{
			if (Menptr[ubNoiseMaker].controller == Net.pnum)
			{
				bWeControlNoise = TRUE;
			}
		}
		else
		{
			// expected noise by NOBODY is sent by LEADER, received by others
			if (Net.pnum == LEADER)
			{
				bWeControlNoise = TRUE;
			}
		}
	}

	if (bWeControlNoise)
	{
		OurNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode);
	}
	else
	{
		// can't be UNEXPECTED, check if it's a SEND or NO_SEND
		if (ubNoiseMode == EXPECTED_NOSEND)
		{
			// no NET_NOISE message is required, trigger TheirNoise() right here
			TheirNoise(ubNoiseMaker,sGridNo,ubTerrType,ubVolume,ubNoiseType,ubNoiseMode);
		}
		else
		{

			// EXPECTED_SEND, TheirNoise() will be triggered by the arrival of the
			// NET_NOISE message, not by us.	Wait here until that's all done...

			// wait for the NET_NOISE to arrive (it will set noiseReceived flag)
			//stopAction = TRUE;		// prevent real-time events from passing us by
			MarkTime(&LoopTime);
			while (Status.noiseReceived != ubNoiseType)
			{
				LoopTimePast = Elapsed(&LoopTime);
				if (LoopTimePast > 50 && LoopTimePast < 2000)
				{
					KeepInterfaceGoing(19); // xxx yyy zzz experimental Aug 16/96 9:15 pm
				}
				else
				{
					KeyHitReport("MakeNoise: Waiting for NET_NOISE, need ubNoiseType ",ubNoiseType);
				}
				CheckForNetIncoming();
			};
			//stopAction = FALSE;	// re-enable real-time events

			// turn off the oppChk flag again
			Status.noiseReceived = -1;

		}
	}
*/
}


void OurNoise( UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume, UINT8 ubNoiseType, STR16 zNoiseMessage )
{
#ifdef BYPASSNOISE
	return;
#endif

#ifdef BETAVERSION
	tempstr = String("OurNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d",
			NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume);
#ifdef RECORDNET
	fprintf(NetDebugFile,"\t%s\n",tempstr);
#endif
#ifdef TESTNOISE
	PopMessage(tempstr);
#endif
#endif

	// see if anyone actually hears this noise, sees ubNoiseMaker, etc.
	ProcessNoise(ubNoiseMaker, sGridNo, bLevel, ubTerrType,	ubVolume,	ubNoiseType, zNoiseMessage );

	if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (ubNoiseMaker < TOTAL_SOLDIERS) && !gfDelayResolvingBestSightingDueToDoor )
	{
		// interrupts are possible, resolve them now (we're in control here)
		// (you can't interrupt NOBODY, even if you hear the noise)

		ResolveInterruptsVs(MercPtrs[ubNoiseMaker],NOISEINTERRUPT);
	}
}



void TheirNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubVolume,
	UINT8 ubNoiseType, STR16 zNoiseMessage )
{
//	SOLDIERTYPE *pSoldier;


#ifdef BYPASSNOISE
	return;
#endif


#ifdef BETAVERSION
	tempstr = String("TheirNoise: ubNoiseType = %s, ubNoiseMaker = %d, ubNoiseMode = %d, sGridNo = %d, ubVolume = %d",
			NoiseTypeStr[ubNoiseType],ubNoiseMaker,ubNoiseMode,sGridNo,ubVolume);
#ifdef RECORDNET
	fprintf(NetDebugFile,"\t%s\n",tempstr);
#endif

#ifdef TESTNOISE
	PopMessage(tempstr);
#endif
#endif

	// see if anyone actually hears this noise, sees noiseMaker, etc.
	ProcessNoise(ubNoiseMaker,sGridNo,bLevel,ubTerrType,ubVolume,ubNoiseType,zNoiseMessage);

	// if noiseMaker is SOMEBODY
	if (ubNoiseMaker < TOTAL_SOLDIERS)
	{
		/*
		pSoldier = MercPtrs[ubNoiseMaker];

		//stopAction = TRUE;		// prevent real-time events from passing us by
		MarkTime(&LoopTime);
		do
		{
			LoopTimePast = Elapsed(&LoopTime);
			if (LoopTimePast > 50 && LoopTimePast < 2000)
			{
				KeepInterfaceGoing(20); // xxx yyy zzz experimental Aug 16/96 9:15 pm
			}
			else
			{
				// the gridno is added to end of the string by KeyHitReport itself...
				tempstr = String("TheirNoise: Waiting for NOISE_INT_DONE for guynum %d, ubNoiseType %d(%s), sGridNo ",
					pSoldier->guynum,ubNoiseType,NoiseTypeStr[ubNoiseType]);
				KeyHitReport(tempstr,sGridNo);
			}

			CheckForNetIncoming();
		} while ((ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] != sGridNo) && pSoldier->in_sector);
		//stopAction = FALSE;	// re-enable real-time events

		// reset the gridno flag for next time
		ExtMen[pSoldier->guynum].noiseRcvdGridno[ubNoiseType] = NOWHERE;
		*/
	}
	// else if noiseMaker's NOBODY, no opplist changes or interrupts are possible
}

void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrType, UINT8 ubBaseVolume, UINT8 ubNoiseType, STR16 zNoiseMessage )
{
	SOLDIERTYPE *pSoldier;
	UINT8 bLoop, bTeam;
	UINT8 ubLoudestEffVolume, ubEffVolume;
//	UINT8 ubPlayVolume;
	UINT8 ubSourceTerrType, ubSource;
	INT8 bTellPlayer = FALSE, bHeard, bSeen;
	UINT8 ubHeardLoudestBy = NOBODY, ubNoiseDir = 0xff, ubLoudestNoiseDir = 0xff;


#ifdef RECORDOPPLIST
	fprintf(OpplistFile,"PN: nType=%s, nMaker=%d, g=%d, tType=%d, bVol=%d\n",
		NoiseTypeStr[noiseType],ubNoiseMaker,sGridNo,ubTerrType,baseVolume);
#endif

	// if the base volume itself was negligible
	if (!ubBaseVolume)
		return;


	// EXPLOSIONs are special, because they COULD be caused by a merc who is
	// no longer alive (but he placed the bomb or flaky grenade in the past).
	// Later noiseMaker gets whacked to NOBODY anyway, so that's OK.	So a
	// dead noiseMaker is only used here to decide WHICH soldiers HearNoise().

	// if noise is made by a person, AND it's not noise from an explosion
	if ((ubNoiseMaker < TOTAL_SOLDIERS) && (ubNoiseType != NOISE_EXPLOSION))
	{
		// inactive/not in sector/dead soldiers, shouldn't be making noise!
		if (!Menptr[ubNoiseMaker].bActive || !Menptr[ubNoiseMaker].bInSector ||
		Menptr[ubNoiseMaker].flags.uiStatusFlags & SOLDIER_DEAD)
		{
#ifdef BETAVERSION
			NumMessage("ProcessNoise: ERROR - Noisemaker is inactive/not in sector/dead, Guy #",ubNoiseMaker);
#endif
			return;
		}

		// if he's out of life, and this isn't just his "dying scream" which is OK
		if (!Menptr[ubNoiseMaker].stats.bLife && (ubNoiseType != NOISE_SCREAM))
		{
#ifdef BETAVERSION
			NumMessage("ProcessNoise: ERROR - Noisemaker is lifeless, Guy #",ubNoiseMaker);
#endif
			return;
		}
	}


	// DETERMINE THE TERRAIN TYPE OF THE GRIDNO WHERE NOISE IS COMING FROM

	ubSourceTerrType = gpWorldLevelData[sGridNo].ubTerrainID;
/*
	// start with the terrain type passed in to us
	ubSourceTerrType = ubTerrType;

	// if this isn't enough to get a valid terrain type
	if ((ubSourceTerrType < GROUNDTYPE) || (ubSourceTerrType > OCEANTYPE))
	{
		// use the source gridno of the noise itself
		ubSourceTerrType = TTypeList[Terrain(sGridNo)];
	}
	*/

	// DETERMINE THE *PERCEIVED* SOURCE OF THE NOISE
	switch (ubNoiseType)
	{
		// for noise generated by an OBJECT shot/thrown/dropped by the noiseMaker
		case NOISE_ROCK_IMPACT:
			gsWhoThrewRock = ubNoiseMaker;
			//fall through here!!!
		case NOISE_BULLET_IMPACT:
		case NOISE_GRENADE_IMPACT:
		case NOISE_EXPLOSION:
			// the source of the noise is not at all obvious, so hide it from
			// the listener and maintain noiseMaker's cover by making source NOBODY
			ubSource = NOBODY;
			break;

		default:
			// normal situation: the noiseMaker is obviously the source of the noise
			ubSource = ubNoiseMaker;
			break;
	}

	// LOOP THROUGH EACH TEAM
	for (bTeam = 0; bTeam < MAXTEAMS; bTeam++)
	{
		// skip any inactive teams
		if (!gTacticalStatus.Team[bTeam].bTeamActive)
		{
			continue;
		}

		// if a the noise maker is a person, not just NOBODY
		if (ubNoiseMaker < TOTAL_SOLDIERS)
		{
			// if this team is the same TEAM as the noise maker's
			// (for now, assume we will report noises by unknown source on same SIDE)
			// OR, if the noise maker is currently in sight to this HUMAN team

			// CJC: changed to if the side is the same side as the noise maker's!
			// CJC: changed back!

			if (bTeam == Menptr[ubNoiseMaker].bTeam)
			{
				continue;
			}

			if (gTacticalStatus.Team[bTeam].bHuman)
			{
				if (gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY && ubNoiseType != NOISE_VOICE)
				{
					continue;
				}
			}
		}

#ifdef REPORTTHEIRNOISE
		// if this is any team
		if (TRUE)
#else
		// if this is our team
		if (TRUE)
		//if (bTeam == Net.pnum)
#endif
		{
			// tell player about noise if enemies are present
			bTellPlayer = gTacticalStatus.fEnemyInSector && ( !(gTacticalStatus.uiFlags & INCOMBAT) || (gTacticalStatus.ubCurrentTeam) );

#ifndef TESTNOISE
			switch (ubNoiseType)
			{
				case NOISE_GUNFIRE:
				case NOISE_BULLET_IMPACT:
				case NOISE_ROCK_IMPACT:
				case NOISE_GRENADE_IMPACT:
					// It's noise caused by a projectile.	If the projectile was seen by
					// the local player while in flight (PublicBullet), then don't bother
					// giving him a message about the noise it made, he's obviously aware.
					if (1 /*PublicBullet*/)
					{
						bTellPlayer = FALSE;
					}

					break;

				case NOISE_EXPLOSION:
					// if center of explosion is in visual range of team, don't report
					// noise, because the player is already watching the thing go BOOM!
					if (TeamMemberNear(bTeam,sGridNo,STRAIGHT))
					{
						bTellPlayer = FALSE;
					}
					break;

				case NOISE_SILENT_ALARM:
				case NOISE_CREAKING://shadooow: doors will make sound of being opened/closed so I see no reason to write it to player
					bTellPlayer = FALSE;
					break;
			}

			// if noise was made by a person
			if (ubNoiseMaker < TOTAL_SOLDIERS)
			{
				// if noisemaker has been *PUBLICLY* SEEN OR HEARD during THIS TURN
				if ((gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_CURRENTLY) || // seen now
					(gbPublicOpplist[bTeam][ubNoiseMaker] == SEEN_THIS_TURN) || // seen this turn
					(gbPublicOpplist[bTeam][ubNoiseMaker] == HEARD_THIS_TURN))	// heard this turn
				{
					// then don't bother reporting any noise made by him to the player
					bTellPlayer = FALSE;
				}
				/*
				else if ( (Menptr[ubNoiseMaker].bVisible == TRUE) && (bTeam == gbPlayerNum) )
				{
					ScreenMsg( MSG_FONT_YELLOW, MSG_TESTVERSION, L"Handling noise from person not currently seen in player's public opplist" );
				}
				*/

				// anv: special exception: we want to report enemy taunt, because of text content
				if ( ubNoiseType == NOISE_VOICE )
				{
					bTellPlayer = TRUE;
				}

				if ( MercPtrs[ ubNoiseMaker ]->stats.bLife == 0 )
				{
					// this guy is dead (just dying) so don't report to player
					bTellPlayer = FALSE;
				}

			}
		}
#endif

		// refresh flags for this new team
		bHeard = FALSE;
		bSeen = FALSE;
		ubLoudestEffVolume = 0;
		ubHeardLoudestBy = NOBODY;

		// All mercs on this team check if they are eligible to hear this noise
		for (bLoop = gTacticalStatus.Team[bTeam].bFirstID,pSoldier = Menptr + bLoop; bLoop <= gTacticalStatus.Team[bTeam].bLastID; bLoop++,pSoldier++)
		{
			// if this "listener" is inactive, or in no condition to care
			if (!pSoldier->bActive || !pSoldier->bInSector || pSoldier->flags.uiStatusFlags & SOLDIER_DEAD || (pSoldier->stats.bLife < OKLIFE) || pSoldier->ubBodyType == LARVAE_MONSTER)
			{
				continue;			// skip him!
			}

			if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && pSoldier->bTeam == OUR_TEAM	)
			{
				continue; // skip
			}

			if ( bTeam == gbPlayerNum && (pSoldier->bAssignment == ASSIGNMENT_POW || pSoldier->bAssignment == ASSIGNMENT_MINIEVENT) )
			{
				// POWs should not be processed for noise
				continue;
			}

			// Can the listener hear noise of that volume given his circumstances?
			ubEffVolume = CalcEffVolume(pSoldier, sGridNo, bLevel, ubNoiseType, ubBaseVolume, pSoldier->bOverTerrainType, ubSourceTerrType);

			// if a the noise maker is a person, not just NOBODY
			if (ubNoiseMaker < TOTAL_SOLDIERS)
			{
				// if this listener can see this noise maker
				if (pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY)
				{
					// civilians care about gunshots even if they come from someone they can see
					// ChrisL: Crows will fly away if they hear any noise
					if ( !( pSoldier->aiData.bNeutral && ubNoiseType == NOISE_GUNFIRE ) && pSoldier->ubBodyType != CROW )
					{
						// anv: we want to report taunt even if we see noisemaker
						if(ubNoiseType != NOISE_VOICE)
						{
							continue;		// then who cares whether he can also hear the guy?
						}
					}
				}

				// screen out allied militia from hearing us
				switch( MercPtrs[ ubNoiseMaker ]->bTeam )
				{
					case OUR_TEAM:
						// if the listener is militia and still on our side, ignore noise from us
						if ( pSoldier->bTeam == MILITIA_TEAM && pSoldier->bSide == 0 )
						{
							continue;
						}
						break;
					case ENEMY_TEAM:
						switch( pSoldier->ubProfile )
						{
							case WARDEN:
							case GENERAL:
							case SERGEANT:
							case CONRAD:	
								// WANNE: This fixes the bug, that Conrad, when he is in OUR team, cannot interrupt enemies!!!
								if (pSoldier->bTeam == OUR_TEAM)
								{
									// WANNE: Allow interrupt, if one of those guys is in OUR team!
									break;
								}
								else
								{
									// No interrupt for those 4 guys
									continue;
								}
							default:
								break;
						}
						break;
					case MILITIA_TEAM:
						// if the noisemaker is militia and still on our side, ignore noise if we're listening
						// sevenfm: allow taunts from militia
						if (pSoldier->bTeam == OUR_TEAM && MercPtrs[ubNoiseMaker]->bSide == 0 && (ubNoiseType != NOISE_VOICE || !gTauntsSettings.fTauntVoice))
						//if ( pSoldier->bTeam == OUR_TEAM && MercPtrs[ ubNoiseMaker ]->bSide == 0 )
						{
							continue;
						}
						break;
				}

				// HEADROCK HAM 3.6: Bloodcat "static" sectors have been externalized, and there can be more than one.
				// Also, there's a toggle that determines whether or not bloodcats can sense enemies in this sector.
				UINT8 ubSectorID = SECTOR(gWorldSectorX, gWorldSectorY);
				UINT8 PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType;

			UINT8 DiffLevel;
			if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY )
				DiffLevel = 1;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM )
				DiffLevel = 2;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD )
				DiffLevel = 3;
			else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE )
				DiffLevel = 4;	
			else
				DiffLevel = 1;
				
				if (PlacementType == BLOODCAT_PLACEMENT_STATIC)
				{
					if (gBloodcatPlacements[ ubSectorID ][ DiffLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)
					//if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation == QUEENS_CIV_GROUP)				
					{
						// skip noises between army & bloodcats
						if ( pSoldier->bTeam == ENEMY_TEAM && MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM )
						{
							continue;
						}
						if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == ENEMY_TEAM )
						{
							continue;
						}
					}				
					else if (gBloodcatPlacements[ ubSectorID ][ DiffLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
					//else if (gBloodcatPlacements[ ubSectorID ][ gGameOptions.ubDifficultyLevel-1 ].ubFactionAffiliation > NON_CIV_GROUP)
					{
						if ( MercPtrs[ ubNoiseMaker ]->ubBodyType == BLOODCAT && MercPtrs[ ubNoiseMaker ]->bTeam == CREATURE_TEAM && pSoldier->bSide != gbPlayerNum)
						{
							// Target is a bloodcat. He can't be heard by civilians no matter what.
							{
								continue;
							}
						}
						else if ( pSoldier->bTeam == CREATURE_TEAM && pSoldier->ubBodyType == BLOODCAT )
						{
							// Source is a bloodcat. He can only hear player-side soldiers, and only if hostile.
							if ( MercPtrs[ ubNoiseMaker ]->bSide != gbPlayerNum || pSoldier->aiData.bNeutral )
							{
								continue;
							}
						}
					}
				}
			}
			else
			{
				// screen out allied militia from hearing us
				if ( (ubNoiseMaker == NOBODY) && pSoldier->bTeam == MILITIA_TEAM && pSoldier->bSide == 0 )
				{
					continue;
				}
			}

			if ( (pSoldier->bTeam == CIV_TEAM) && (ubNoiseType == NOISE_GUNFIRE || ubNoiseType == NOISE_EXPLOSION) )
			{
				pSoldier->ubMiscSoldierFlags |= SOLDIER_MISC_HEARD_GUNSHOT;
			}

#ifdef RECORDOPPLIST
			fprintf(OpplistFile,"PN: guy %d - effVol=%d,pSoldier->tType=%d,srcTType=%d\n",
			bLoop,effVolume,pSoldier->terrtype,ubSourceTerrType);
#endif

			if (ubEffVolume > 0)
			{
				// ALL RIGHT!	Passed all the tests, this listener hears this noise!!!
				HearNoise(pSoldier,ubSource,sGridNo,bLevel,ubEffVolume,ubNoiseType, (UINT8 *)&bSeen);

				bHeard = TRUE;

				ubNoiseDir = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sGridNo),CenterY(sGridNo));

				// check the 'noise heard & reported' bit for that soldier & direction
				if ( ubNoiseType != NOISE_MOVEMENT || bTeam != OUR_TEAM || (pSoldier->aiData.bInterruptDuelPts != NO_INTERRUPT) || !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) )
				{
					if (ubEffVolume > ubLoudestEffVolume)
					{
						ubLoudestEffVolume = ubEffVolume;
						ubHeardLoudestBy = pSoldier->ubID;
						ubLoudestNoiseDir = ubNoiseDir;
					}
				}

			}
			else
			{
				//NameMessage(pSoldier," can't hear this noise",2500);
				ubEffVolume = 0;
			}
		}


		// if the noise was heard at all
		if (bHeard)
		{
			// and we're doing our team
			if (bTeam == OUR_TEAM)
			/*
			if (team == Net.pnum)
			*/
			{
				// if we are to tell the player about this type of noise
				if (bTellPlayer && ubHeardLoudestBy != NOBODY )
				{
					// the merc that heard it the LOUDEST is the one to comment
					// should add level to this function call
					TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir, zNoiseMessage);

					if ( ubNoiseType == NOISE_MOVEMENT)
					{
						MercPtrs[ ubHeardLoudestBy ]->ubMovementNoiseHeard |= (1 << ubNoiseDir);
					}

				}
				else if (ubNoiseType == NOISE_CREAKING)
				{
					DOOR_STATUS	*pDoorStatus = GetDoorStatus(sGridNo);
					//shadooow: show locator when there is can with string attached to doors
					if (pDoorStatus && pDoorStatus->ubFlags & DOOR_HAS_TIN_CAN)
						BeginMultiPurposeLocator(sGridNo, bLevel, (INT8)((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT)));
				}
				//if ( !(pSoldier->ubMovementNoiseHeard & (1 << ubNoiseDir) ) )
			}
#ifdef REPORTTHEIRNOISE
			else	// debugging: report noise heard by other team's soldiers
			{
				if (bTellPlayer)
				{
					TellPlayerAboutNoise(MercPtrs[ubHeardLoudestBy],ubNoiseMaker,sGridNo,bLevel,ubLoudestEffVolume,ubNoiseType, ubLoudestNoiseDir);
				}
			}
#endif
		}
		else if(bTeam == OUR_TEAM && ubNoiseType == NOISE_CREAKING)
		{
			//shadooow: this will indicate doors not to make animation/sound of doors opening or closing
			Menptr[ubNoiseMaker].ubDoorOpeningNoise = 0;
		}
		// if the listening team is human-controlled AND
		// the noise's source is another soldier
		// (computer-controlled teams don't radio or automatically report NOISE)
		if (gTacticalStatus.Team[bTeam].bHuman && (ubSource < TOTAL_SOLDIERS))
		{
			// if ubNoiseMaker was seen by at least one member of this team
			if (bSeen)
			{
// Temporary for opplist synching - disable random order radioing
#ifdef RECORDOPPLIST
				// insure all machines radio in synch to keep logs the same
				for (bLoop = Status.team[team].guystart,pSoldier = Menptr + bLoop; bLoop < Status.team[team].guyend; bLoop++,pSoldier++)
				{
					// if this merc is active, in this sector, and well enough to look
					if (pSoldier->active && pSoldier->in_sector && (pSoldier->life >= OKLIFE))
					{
						RadioSightings(pSoldier,ubSource);
						pSoldier->newOppCnt = 0;
					}
				}
#else
				// if this human team is OURS
				if (1 /* bTeam == Net.pnum */)
				{
					// this team is now allowed to report sightings and set Public flags
					OurTeamRadiosRandomlyAbout(ubSource);
				}
				else	// noise was heard by another human-controlled team (not ours)
				{
					// mark noise maker as being seen currently
					//UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,NOUPDATE,ACTUAL);
					UpdatePublic(bTeam,ubSource,SEEN_CURRENTLY,sGridNo,bLevel);
				}
#endif
			}
			else // not seen
			{
				if (bHeard)
				{
#ifdef RECORDOPPLIST
					fprintf(OpplistFile,"UpdatePublic (ProcessNoise/heard) for team %d about %d\n",team,ubSource);
#endif

					// mark noise maker as having been PUBLICLY heard THIS TURN
					//UpdatePublic(team,ubSource,HEARD_THIS_TURN,sGridNo,NOUPDATE,ACTUAL);
					UpdatePublic(bTeam,ubSource,HEARD_THIS_TURN,sGridNo,bLevel);
				}
			}
		}
	}

	gsWhoThrewRock = NOBODY;
}



UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubNoiseType, UINT8 ubBaseVolume, UINT8 ubTerrType1, UINT8 ubTerrType2)
{
	INT32 iEffVolume, iDistance;

	// Lesh: deafness
	if ( pSoldier->bDeafenedCounter > 0 )
	{
		return( 0 );
	}

	if ( FindWalkman(pSoldier) != ITEM_NOT_FOUND	)
	{
		return( 0 );
	}

	if ( gTacticalStatus.uiFlags & INCOMBAT )
	{
		// ATE: Funny things happen to ABC stuff if bNewSituation set....
		// anv: added exception to NOISE_VOICE
		if ( gTacticalStatus.ubCurrentTeam == pSoldier->bTeam && ubNoiseType != NOISE_VOICE )
		{
			return( 0 );
		}
	}

	//sprintf(tempstr,"CalcEffVolume BY %s for gridno %d, baseVolume = %d",pSoldier->name,gridno,baseVolume);
	//PopMessage(tempstr);

	// adjust default noise volume by listener's hearing capability
	iEffVolume = (INT32) ubBaseVolume + (INT32) DecideHearing( pSoldier );


	// effective volume reduced by listener's number of opponents in sight
	iEffVolume -= pSoldier->aiData.bOppCnt;


 // calculate the distance (in adjusted pixels) between the source of the
 // noise (gridno) and the location of the would-be listener (pSoldier->gridno)
 iDistance = (INT32) PythSpacesAway( pSoldier->sGridNo, sGridNo );
 /*
 distance = AdjPixelsAway(pSoldier->x,pSoldier->y,CenterX(sGridNo),CenterY(sGridNo));

	distance /= 15;		// divide by 15 to convert from adj. pixels to tiles
	*/
	//NumMessage("Distance = ",distance);

 // effective volume fades over distance beyond 1 tile away
 iEffVolume -= (iDistance - 1);

 //ddd{ civilians have bad hearing ;)
 if(gGameExternalOptions.bLazyCivilians)
 	if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW )
		if (pSoldier->ubCivilianGroup == 0 && pSoldier->ubProfile == NO_PROFILE)
			iEffVolume =-100;
	//ddd}

	/*
	if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW )
	{
		if (pSoldier->ubCivilianGroup == 0 && pSoldier->ubProfile == NO_PROFILE)
		{
			// nameless civs reduce effective volume by 2 for gunshots etc
			// (double the reduction due to distance)
			// so that they don't cower from attacks that are really far away
			switch (ubNoiseType)
			{
				case NOISE_GUNFIRE:
				case NOISE_BULLET_IMPACT:
				case NOISE_GRENADE_IMPACT:
				case NOISE_EXPLOSION:
					iEffVolume -= iDistance;
					break;
				default:
					break;
			}
		}
		else if (pSoldier->aiData.bNeutral)
		{
			// NPCs and people in groups ignore attack noises unless they are no longer neutral
			switch (ubNoiseType)
			{
				case NOISE_GUNFIRE:
				case NOISE_BULLET_IMPACT:
				case NOISE_GRENADE_IMPACT:
				case NOISE_EXPLOSION:
					iEffVolume = 0;
					break;
				default:
					break;
			}
		}
	}
	*/

	if (pSoldier->usAnimState == RUNNING)
	{
		iEffVolume -= 5;
	}

	//if (pSoldier->bAssignment == SLEEPING )
	if( pSoldier->flags.fMercAsleep )
	{
		// decrease effective volume since we're asleep!
		iEffVolume -= 5;
	}

	// check for floor/roof difference
	if (bLevel > pSoldier->pathing.bLevel)
	{
		// sound is amplified by roof
		iEffVolume += 5;
	}
	else if (bLevel < pSoldier->pathing.bLevel)
	{
		// sound is muffled
		iEffVolume -= 5;
	}

	// if we still have a chance of hearing this, and the terrain types are known
	if (iEffVolume > 0)
	{
		// if, between noise and listener, one is outside and one is inside

		// NOTE: This is a pretty dumb way of doing things, since it won't detect
		// the presence of walls between 2 spots both inside or both outside, but
		// given our current system it's the best that we can do

		if (((ubTerrType1 == FLAT_FLOOR) && (ubTerrType2 != FLAT_FLOOR)) ||
			((ubTerrType1 != FLAT_FLOOR) && (ubTerrType2 == FLAT_FLOOR)))
		{
			//PopMessage("Sound is muffled by wall(s)");

			// sound is muffled, reduce the effective volume of the noise
			iEffVolume -= 5;
		}
	}

	//NumMessage("effVolume = ",ubEffVolume);
	if (iEffVolume > 0)
	{
		return( (UINT8) iEffVolume );
	}
	else
	{
		return( 0 );
	}
}




void HearNoise(SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume,
		UINT8 ubNoiseType, UINT8 *ubSeen)
{
	INT16		sNoiseX, sNoiseY;
	INT8		bHadToTurn = FALSE, bSourceSeen = FALSE;
	INT8		bOldOpplist;
	INT8		bDirection;
	BOOLEAN fMuzzleFlash = FALSE;

	if ( pSoldier->ubBodyType == CROW )
	{
		CrowsFlyAway( pSoldier->bTeam );
		return;
	}
//	DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "%d hears noise from %d (%d/%d) volume %d", pSoldier->ubID, ubNoiseMaker, sGridNo, bLevel, ubVolume ) );

	// sevenfm: scale ubVolume to remember noise
	UINT8 ubVolumeScaled = (UINT8)sqrt((float)ubVolume);

	// "Turn head" towards the source of the noise and try to see what's there

	// don't use DistanceVisible here, but use maximum visibility distance
	// in as straight line instead.	Represents guy "turning just his head"

	// CJC 97/10: CHANGE!	Since STRAIGHT can not reliably be used as a
	// max sighting distance (varies based on realtime/turnbased), call
	// the function with the new DIRECTION_IRRELEVANT define

	// is he close enough to see that gridno if he turns his head?

	// ignore muzzle flashes when turning head to see noise
	if ( ubNoiseType == NOISE_GUNFIRE && ubNoiseMaker != NOBODY && MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash )
	{
		sNoiseX = CenterX(sGridNo);
		sNoiseY = CenterY(sGridNo);
		bDirection = atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY);
		if ( pSoldier->ubDirection != bDirection && pSoldier->ubDirection != gOneCDirection[ bDirection ] && pSoldier->ubDirection != gOneCCDirection[ bDirection ] )
		{
			// temporarily turn off muzzle flash so DistanceVisible can be calculated without it
			MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = FALSE;
			fMuzzleFlash = TRUE;
		}
	}

    int sDistVisible = pSoldier->GetMaxDistanceVisible(sGridNo, bLevel, CALC_FROM_WANTED_DIR );

	if ( fMuzzleFlash )
	{
		// turn flash on again
		MercPtrs[ ubNoiseMaker ]->flags.fMuzzleFlash = TRUE;
	}

	if (PythSpacesAway(pSoldier->sGridNo,sGridNo) <= sDistVisible )
	{
		// just use the XXadjustedXX center of the gridno
		sNoiseX = CenterX(sGridNo);
		sNoiseY = CenterY(sGridNo);

		if (pSoldier->ubDirection != atan8(pSoldier->sX,pSoldier->sY,sNoiseX,sNoiseY))
		{
			bHadToTurn = TRUE;
		}
		else
		{
			bHadToTurn = FALSE;
		}

		// and we can trace a line of sight to his x,y coordinates?
		// (taking into account we are definitely aware of this guy now)

		// skip LOS check if we had to turn and we're a tank.	sorry Mr Tank, no looking out of the sides for you!
		if ( !(bHadToTurn && ARMED_VEHICLE( pSoldier )) )
		{
			if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, bLevel, 0, TRUE, sDistVisible ) )
			{
				// he can actually see the spot where the noise came from!
				bSourceSeen = TRUE;

				// if this sounds like a door opening/closing (could also be a crate)
				// Flugente: unused check
				/*if (ubNoiseType == NOISE_CREAKING)
				{
					// then look around and update ALL doors that have secretly changed
					//LookForDoors(pSoldier,AWARE);
				}*/
			}
		}

#ifdef RECORDOPPLIST
		fprintf(OpplistFile,"HN: %s by %2d(g%4d,x%3d,y%3d) at %2d(g%4d,x%3d,y%3d), hTT=%d\n",
			(bSourceSeen) ? "SCS" : "FLR",
			pSoldier->guynum,pSoldier->sGridNo,pSoldier->sX,pSoldier->sY,
			ubNoiseMaker,sGridNo,sNoiseX,sNoiseY,
			bHadToTurn);
#endif
	}

	// if noise is made by a person
	if (ubNoiseMaker < TOTAL_SOLDIERS)
	{
		bOldOpplist = pSoldier->aiData.bOppList[ubNoiseMaker];

		// WE ALREADY KNOW THAT HE'S ON ANOTHER TEAM, AND HE'S NOT BEING SEEN
		// ProcessNoise() ALREADY DID THAT WORK FOR US

		if (bSourceSeen)
		{
			ManSeesMan(pSoldier,MercPtrs[ubNoiseMaker],Menptr[ubNoiseMaker].sGridNo,Menptr[ubNoiseMaker].pathing.bLevel,HEARNOISE,CALLER_UNKNOWN);

			// if it's an AI soldier, he is not allowed to automatically radio any
			// noise heard, but manSeesMan has set his newOppCnt, so clear it here
			if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC))
			{
				pSoldier->bNewOppCnt = 0;
			}

			*ubSeen = TRUE;
			// RadioSightings() must only be called later on by ProcessNoise() itself
			// because we want the soldier who heard noise the LOUDEST to report it

			if ( pSoldier->aiData.bNeutral )
			{
				// could be a civilian watching us shoot at an enemy
				if (((ubNoiseType == NOISE_GUNFIRE) || (ubNoiseType == NOISE_BULLET_IMPACT)) && (ubVolume >= 3))
				{
					// if status is only GREEN or YELLOW
					if (pSoldier->aiData.bAlertStatus < STATUS_RED)
					{
						// then this soldier goes to status RED, has proof of enemy presence
						pSoldier->aiData.bAlertStatus = STATUS_RED;
						CheckForChangingOrders(pSoldier);
					}
				}
			}
			// sevenfm: remember noise even for seen opponents
			if( pSoldier->flags.uiStatusFlags & SOLDIER_PC && ubVolumeScaled > pSoldier->aiData.ubNoiseVolume )
			{
				// yes it is, so remember this noise INSTEAD (old noise is forgotten)
				pSoldier->aiData.sNoiseGridno = sGridNo;
				pSoldier->bNoiseLevel = bLevel;

				// no matter how loud noise was, don't remember it for more than 12 turns!
				pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);
			}

		}
		else		 // noise maker still can't be seen
		{
			SetNewSituation( pSoldier ); // re-evaluate situation

			// if noise type was unmistakably that of gunfire
			if (((ubNoiseType == NOISE_GUNFIRE) || (ubNoiseType == NOISE_BULLET_IMPACT)) && (ubVolume >= 3))
			{
				// if status is only GREEN or YELLOW
				if (pSoldier->aiData.bAlertStatus < STATUS_RED)
				{
					// then this soldier goes to status RED, has proof of enemy presence
					pSoldier->aiData.bAlertStatus = STATUS_RED;
					CheckForChangingOrders(pSoldier);
				}
			}

			// remember that the soldier has been heard and his new location
			UpdatePersonal(pSoldier,ubNoiseMaker,HEARD_THIS_TURN,sGridNo, bLevel);

			// sevenfm: increment watched location when soldier hears enemy
			if ((ubNoiseType == NOISE_GUNFIRE || ubNoiseType == NOISE_MOVEMENT || ubNoiseType == NOISE_SCREAM || ubNoiseType == NOISE_VOICE) &&
				!TileIsOutOfBounds(sGridNo) &&
				!(pSoldier->flags.uiStatusFlags & SOLDIER_PC) &&
				!pSoldier->aiData.bNeutral &&
				MercPtrs[ubNoiseMaker] &&
				!MercPtrs[ubNoiseMaker]->aiData.bNeutral &&
				!pSoldier->IsFlanking())
			{
				// check that we can see enemy if we raise weapon
				gbForceWeaponReady = TRUE;
				if (SoldierToVirtualSoldierLineOfSightTest(pSoldier, sGridNo, bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS))
					IncrementWatchedLoc(pSoldier->ubID, sGridNo, bLevel);
				gbForceWeaponReady = FALSE;
			}

			// Public info is not set unless EVERYONE on the team fails to see the
			// ubnoisemaker, leaving the 'seen' flag FALSE.	See ProcessNoise().

			// CJC: set the noise gridno for the soldier, if appropriate - this is what is looked at by the AI!
			if (ubVolumeScaled >= pSoldier->aiData.ubNoiseVolume)
			{
				// yes it is, so remember this noise INSTEAD (old noise is forgotten)
				pSoldier->aiData.sNoiseGridno = sGridNo;
				pSoldier->bNoiseLevel = bLevel;

				// no matter how loud noise was, don't remember it for more than 12 turns!
				pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);

				SetNewSituation( pSoldier );	// force a fresh AI decision to be made
			}

		}

		if ( pSoldier->aiData.fAIFlags & AI_ASLEEP )
		{
			switch( ubNoiseType )
			{
				case NOISE_BULLET_IMPACT:
				case NOISE_GUNFIRE:
				case NOISE_EXPLOSION:
				case NOISE_SCREAM:
				case NOISE_WINDOW_SMASHING:
				case NOISE_DOOR_SMASHING:
					// WAKE UP!
					pSoldier->aiData.fAIFlags &= (~AI_ASLEEP);
					break;
				default:
					break;
			}
		}

		// FIRST REQUIRE MUTUAL HOSTILES!
		if (!CONSIDERED_NEUTRAL( MercPtrs[ ubNoiseMaker ], pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, MercPtrs[ ubNoiseMaker ] ) && (pSoldier->bSide != MercPtrs[ ubNoiseMaker ]->bSide))
		{
			// regardless of whether the noisemaker (who's not NOBODY) was seen or not,
			// as long as listener meets minimum interrupt conditions
			if ( gfDelayResolvingBestSightingDueToDoor)
			{
				if ( bSourceSeen && (!( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) || (gubSightFlags & SIGHTINTERRUPT && StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist)) ) )
				{
					// we should be adding this to the array for the AllTeamLookForAll to handle
					// since this is a door opening noise, add a bonus equal to half the door volume
					UINT8	ubPoints;

					ubPoints = CalcInterruptDuelPts( pSoldier, ubNoiseMaker, TRUE );
					if ( ubPoints != NO_INTERRUPT )
					{
						// require the enemy not to be dying if we are the sighter; in other words,
						// always add for AI guys, and always add for people with life >= OKLIFE
						if ( pSoldier->bTeam != gbPlayerNum || MercPtrs[ ubNoiseMaker ]->stats.bLife >= OKLIFE )
						{
							ReevaluateBestSightingPosition( pSoldier, (UINT8) (ubPoints + (ubVolume / 2)) );
						}
					}
				}
			}
			else
			{
				if ( (gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) )
				{
					if (StandardInterruptConditionsMet(pSoldier,ubNoiseMaker,bOldOpplist))
					{
						// he gets a chance to interrupt the noisemaker
						pSoldier->aiData.bInterruptDuelPts = CalcInterruptDuelPts(pSoldier,ubNoiseMaker, TRUE );
						DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
					}
					else
					{
						pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
					}
				}
				else if ( bSourceSeen )
				{
					// seen source, in realtime, so check for sighting stuff
					HandleBestSightingPositionInRealtime();
				}
			}

		}
	}
	else	// noise made by NOBODY
	{
		// if noise type was unmistakably that of an explosion (seen or not) or alarm
		if (!(pSoldier->flags.uiStatusFlags & SOLDIER_PC))
		{
			if ( ( ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SILENT_ALARM ) && (ubVolume >= 3) )
			{
				if ( ubNoiseType == NOISE_SILENT_ALARM )
				{
					WearGasMaskIfAvailable( pSoldier );
				}
				// if status is only GREEN or YELLOW
				if (pSoldier->aiData.bAlertStatus < STATUS_RED)
				{
					// then this soldier goes to status RED, has proof of enemy presence
					pSoldier->aiData.bAlertStatus = STATUS_RED;
					CheckForChangingOrders(pSoldier);
				}
			}
		}
		// if the source of the noise can't be seen,
		// OR if it's a rock and the listener had to turn so that by the time he
		// looked all his saw was a bunch of rocks lying still
		if (!bSourceSeen || ((ubNoiseType == NOISE_ROCK_IMPACT) && (bHadToTurn) ) || ubNoiseType == NOISE_SILENT_ALARM )
		{
			// check if the effective volume of this new noise is greater than or at
			// least equal to the volume of the currently noticed noise stored
			if (ubVolumeScaled >= pSoldier->aiData.ubNoiseVolume)
			{
				// yes it is, so remember this noise INSTEAD (old noise is forgotten)
				pSoldier->aiData.sNoiseGridno = sGridNo;
				pSoldier->bNoiseLevel = bLevel;

				// no matter how loud noise was, don't remember it for more than 12 turns!
				pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);

				SetNewSituation( pSoldier );	// force a fresh AI decision to be made
			}
		}
		else
		// if listener sees the source of the noise, AND it's either a grenade,
		//	or it's a rock that he watched land (didn't need to turn)
		{
			// sevenfm: allow player mercs to hear all noises
			if ( pSoldier->flags.uiStatusFlags & SOLDIER_PC && ubVolumeScaled > pSoldier->aiData.ubNoiseVolume)
			{
				// yes it is, so remember this noise INSTEAD (old noise is forgotten)
				pSoldier->aiData.sNoiseGridno = sGridNo;
				pSoldier->bNoiseLevel = bLevel;

				// no matter how loud noise was, don't remember it for more than 12 turns!
				pSoldier->aiData.ubNoiseVolume = min(ubVolumeScaled, MAX_MISC_NOISE_DURATION);
			}

			SetNewSituation( pSoldier );	// re-evaluate situation

			// if status is only GREEN or YELLOW
			if (pSoldier->aiData.bAlertStatus < STATUS_RED)
			{
				// then this soldier goes to status RED, has proof of enemy presence
				pSoldier->aiData.bAlertStatus = STATUS_RED;
				CheckForChangingOrders(pSoldier);
			}
		}

		if ( gubBestToMakeSightingSize == BEST_SIGHTING_ARRAY_SIZE_INCOMBAT )
		{
			// if the noise heard was the fall of a rock
			if ((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT ) && ubNoiseType == NOISE_ROCK_IMPACT )
			{
				// give every ELIGIBLE listener an automatic interrupt, since it's
				// reasonable to assume the guy throwing wants to wait for their reaction!
				if (StandardInterruptConditionsMet(pSoldier,NOBODY,FALSE))
				{
					pSoldier->aiData.bInterruptDuelPts = AUTOMATIC_INTERRUPT;			// force automatic interrupt
					DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Calculating int duel pts in noise code, %d has %d points", pSoldier->ubID, pSoldier->aiData.bInterruptDuelPts ) );
				}
				else
				{
					pSoldier->aiData.bInterruptDuelPts = NO_INTERRUPT;
				}
			}
		}
	}
    AI::tactical::AIInputData ai_input(AI::tactical::AIInputData::Auditive(), ubNoiseMaker, sGridNo, bLevel, ubVolume, ubNoiseType);
    AI::tactical::PlanInputData plan_input((gTacticalStatus.uiFlags & TURNBASED)!=0, gTacticalStatus);
    AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
    plan_lib->update_plan(pSoldier->bAIIndex, pSoldier, ai_input);
}

void TellPlayerAboutNoise( SOLDIERTYPE *pSoldier, UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubVolume, UINT8 ubNoiseType, UINT8 ubNoiseDir, STR16 zNoiseMessage )
{
	UINT8 ubVolumeIndex;

	// CJC: tweaked the noise categories upwards a bit because our movement noises can be louder now.
	if (ubVolume < 4)
	{
		ubVolumeIndex = 0;		// 1-3: faint noise
	}
	else if (ubVolume < 8)	// 4-7: definite noise
	{
		ubVolumeIndex = 1;
	}
	else if (ubVolume < 12)	// 8-11: loud noise
	{
		ubVolumeIndex = 2;
	}
	else										// 12+: very loud noise
	{
		ubVolumeIndex = 3;
	}

	// display a message about a noise...
	// e.g. Sidney hears a loud splash from/to? the north.

	if ( ubNoiseMaker != NOBODY && pSoldier->bTeam == gbPlayerNum && pSoldier->bTeam == Menptr[ubNoiseMaker].bTeam )
	{
		#ifdef JA2BETAVERSION
			ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"ERROR! TAKE SCREEN CAPTURE AND TELL CAMFIELD NOW!" );
			ScreenMsg( MSG_FONT_RED, MSG_ERROR, L"%s (%d) heard noise from %s (%d), noise at %dL%d, type %d", pSoldier->name, pSoldier->ubID, Menptr[ubNoiseMaker].name, ubNoiseMaker, sGridNo, bLevel, ubNoiseType );
		#endif
	}

	// anv: special treatment of NOISE_VOICE - also display taunt message
	if (ubNoiseType == NOISE_VOICE && ubNoiseMaker != NOBODY)
	{
		// information about direction etc. only displayed if we don't see noise maker
		// sevenfm: don't show noise messages from militia (if on our side)
		if (gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY &&	pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY &&
			!(MercPtrs[ubNoiseMaker]->bTeam == MILITIA_TEAM && MercPtrs[ubNoiseMaker]->bSide == 0))
		//if( gbPublicOpplist[gbPlayerNum][ubNoiseMaker] != SEEN_CURRENTLY && pSoldier->aiData.bOppList[ubNoiseMaker] != SEEN_CURRENTLY )
		{
			if (bLevel == pSoldier->pathing.bLevel)
			{
				ScreenMsg(MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir]);
			}
			else if (bLevel > pSoldier->pathing.bLevel)
			{
				// from above!
				ScreenMsg(MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6]);
			}
			else
			{
				// from below!
				ScreenMsg(MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7]);
			}
		}

		if( ubVolumeIndex > 0 ) // definite noise - we're able to recognize words
		{
			CHAR8 filename[1024];

			if (gTauntsSettings.fTauntVoiceShowInfo)
				ScreenMsg(FONT_ORANGE, MSG_INTERFACE, zNoiseMessage);

			// convert wchar to char			
			wcstombs(filename, zNoiseMessage, wcslen(zNoiseMessage) + 1);
			// sevenfm: play voice taunt (check that noise string is a filename)
			if (gTauntsSettings.fTauntVoice	 &&
				strlen(filename) != 0 &&
				strstr(filename, "VoiceTaunts\\") != NULL)
			{
				UINT32 playResult = PlayJA2SampleFromFile(filename, RATE_11025, SoundVolume(HIGHVOLUME, pSoldier->sGridNo), 1, SoundDir(pSoldier->sGridNo));
				if (playResult == SOUND_ERROR && gTauntsSettings.fTauntVoiceShowInfo)
					ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Noise: Failed to play taunt");
			}
			else
			{
				// do we know who said that?
				if (gbPublicOpplist[gbPlayerNum][ubNoiseMaker] == SEEN_CURRENTLY || pSoldier->aiData.bOppList[ubNoiseMaker] == SEEN_CURRENTLY)
				{
					if (gTauntsSettings.fTauntShowPopupBox == TRUE)
						ShowTauntPopupBox(MercPtrs[ubNoiseMaker], zNoiseMessage);
					if (gTauntsSettings.fTauntShowInLog == TRUE)
						ScreenMsg(FONT_GRAY2, MSG_INTERFACE, L"%s: %s", MercPtrs[ubNoiseMaker]->GetName(), zNoiseMessage);
				}
				else
				{
					if (gTauntsSettings.fTauntShowPopupBox == TRUE && gTauntsSettings.fTauntShowPopupBoxIfHeard == TRUE)
						ShowTauntPopupBox(MercPtrs[ubNoiseMaker], zNoiseMessage);
					if (gTauntsSettings.fTauntShowInLog == TRUE && gTauntsSettings.fTauntShowInLogIfHeard == TRUE)
						ScreenMsg(FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pTauntUnknownVoice[0], zNoiseMessage);
				}
			}			
		}
	}
	else if ( bLevel == pSoldier->pathing.bLevel || ubNoiseType == NOISE_EXPLOSION || ubNoiseType == NOISE_SCREAM || ubNoiseType == NOISE_ROCK_IMPACT || ubNoiseType == NOISE_GRENADE_IMPACT )
	{
		ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], pDirectionStr[ubNoiseDir] );
	}
	else if ( bLevel > pSoldier->pathing.bLevel )
	{
		// from above!
		ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[6] );
	}
	else
	{
		// from below!
		ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, pNewNoiseStr[ubNoiseType], pSoldier->name, pNoiseVolStr[ubVolumeIndex], gzLateLocalizedString[7] );
	}

	// if the quote was faint, say something
	if (ubVolumeIndex == 0)
	{
#ifdef JA2UB
//Ja25 No meanwhiles
#else
		if ( !AreInMeanwhile( ) && !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV) && pSoldier->ubTurnsUntilCanSayHeardNoise == 0)
#endif
		{
			TacticalCharacterDialogue( pSoldier, QUOTE_HEARD_SOMETHING );
			if ( gTacticalStatus.uiFlags & INCOMBAT )
			{
				pSoldier->ubTurnsUntilCanSayHeardNoise = 2;
			}
			else
			{
				pSoldier->ubTurnsUntilCanSayHeardNoise = 5;
			}
		}
	}


	//DIGICRAB: Loud Sound Locator
	//show a locator for very loud noises if we have an extended ear
	if(ubVolumeIndex >= 2)
	{
		if ( FindHearingAid(pSoldier) )
			BeginMultiPurposeLocator(sGridNo, bLevel, (INT8)((gTacticalStatus.uiFlags & TURNBASED) && ( gTacticalStatus.uiFlags & INCOMBAT )));
	}

	// flag soldier as having reported noise in a particular direction
}

void VerifyAndDecayOpplist(SOLDIERTYPE *pSoldier)
{
	UINT32 uiLoop;
	INT8 *pPersOL;			// pointer into soldier's opponent list
	SOLDIERTYPE *pOpponent;

	// reduce all seen/known opponent's turn counters by 1 (towards 0)
	// 1) verify accuracy of the opplist by testing sight vs known opponents
	// 2) increment opplist value if opponent is known but not currenly seen
	// 3) forget about known opponents who haven't been noticed in some time

	// if soldier is unconscious, make sure his opplist is wiped out & bail out
	if (pSoldier->stats.bLife < OKLIFE)
	{
		memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
		pSoldier->aiData.bOppCnt = 0;
		return;
	}

	// if any new opponents were seen earlier and not yet radioed
	if (pSoldier->bNewOppCnt)
	{
#ifdef BETAVERSION
		tempstr = String("VerifyAndDecayOpplist: WARNING - %d(%s) still has %d NEW OPPONENTS - lastCaller %s/%s",
			pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt,
			LastCallerText[ExtMen[pSoldier->guynum].lastCaller],
			LastCaller2Text[ExtMen[pSoldier->guynum].lastCaller2]);

#ifdef TESTVERSION	// make this ERROR/BETA again when it's fixed!
		PopMessage(tempstr);
#endif

#ifdef RECORDNET
		fprintf(NetDebugFile,"\n\t%s\n\n",tempstr);
#endif

#endif

		if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
		{
			RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);
		}

		pSoldier->bNewOppCnt = 0;
	}

	// man looks for each of his opponents WHO ARE ALREADY KNOWN TO HIM
	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pOpponent = MercSlots[ uiLoop ];

		// if this merc is active, here, and alive
		if (pOpponent != NULL && pOpponent->stats.bLife)
		{
			// if this merc is on the same team, he's no opponent, so skip him
			if (pSoldier->bTeam == pOpponent->bTeam)
			{
				continue;
			}

		pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;

	 // if this opponent is "known" in any way (seen or heard recently)
	 if (*pPersOL != NOT_HEARD_OR_SEEN)
		{
		// use both sides actual x,y co-ordinates (neither side's moving)
		ManLooksForMan(pSoldier,pOpponent,VERIFYANDDECAYOPPLIST);

			// decay opplist value if necessary
			DECAY_OPPLIST_VALUE( *pPersOL );
			/*
		// if opponent was SEEN recently but is NOT visible right now
		if (*pPersOL >= SEEN_THIS_TURN)
		{
		 (*pPersOL)++;			// increment #turns it's been since last seen

		 // if it's now been longer than the maximum we care to remember
		 if (*pPersOL > SEEN_2_TURNS_AGO)
			*pPersOL = 0;		// forget that we knew this guy
		}
		else
		{
		 // if opponent was merely HEARD recently, not actually seen
		 if (*pPersOL <= HEARD_THIS_TURN)
			{
			(*pPersOL)--;		// increment #turns it's been since last heard

	// if it's now been longer than the maximum we care to remember
	if (*pPersOL < HEARD_2_TURNS_AGO)
		*pPersOL = 0;		// forget that we knew this guy
			}
				}
			*/
		}

	}
	}


 // if any new opponents were seen
 if (pSoldier->bNewOppCnt)
	{
	// turns out this is NOT an error!	If this guy was gassed last time he
	// looked, his sight limit was 2 tiles, and now he may no longer be gassed
	// and thus he sees opponents much further away for the first time!
	// - Always happens if you STUNGRENADE an opponent by surprise...
#ifdef RECORDNET
	fprintf(NetDebugFile,"\tVerifyAndDecayOpplist: d(%s) saw %d new opponents\n",
		pSoldier->guynum,ExtMen[pSoldier->guynum].name,pSoldier->newOppCnt);
#endif

	if (pSoldier->flags.uiStatusFlags & SOLDIER_PC)
	 RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);

	pSoldier->bNewOppCnt = 0;
	}
}

void DecayIndividualOpplist(SOLDIERTYPE *pSoldier)
{
	UINT32 uiLoop;
	INT8 *pPersOL;			// pointer into soldier's opponent list
	SOLDIERTYPE *pOpponent;

	// reduce all currently seen opponent's turn counters by 1 (towards 0)

	// if soldier is unconscious, make sure his opplist is wiped out & bail out
	if (pSoldier->stats.bLife < OKLIFE)
	{
		// must make sure that public opplist is kept to match...
		for (uiLoop = 0; uiLoop < MAX_NUM_SOLDIERS; ++uiLoop)
		{
			if ( pSoldier->aiData.bOppList[ uiLoop ] == SEEN_CURRENTLY )
			{
				HandleManNoLongerSeen( pSoldier, MercPtrs[ uiLoop ], &(pSoldier->aiData.bOppList[ uiLoop ]), &(gbPublicOpplist[ pSoldier->bTeam ][ uiLoop ]) );
			}
		}
	//void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT8 * pPersOL, INT8 * pbPublOL )

		memset(pSoldier->aiData.bOppList,NOT_HEARD_OR_SEEN,sizeof(pSoldier->aiData.bOppList));
		pSoldier->aiData.bOppCnt = 0;
		return;
	}

	// man looks for each of his opponents WHO IS CURRENTLY SEEN
	for (uiLoop = 0; uiLoop < guiNumMercSlots; ++uiLoop)
	{
		pOpponent = MercSlots[ uiLoop ];

		// if this merc is active, here, and alive
		if (pOpponent != NULL && pOpponent->stats.bLife)
		{
			// if this merc is on the same team, he's no opponent, so skip him
			if (pSoldier->bTeam == pOpponent->bTeam)
			{
				continue;
			}

			pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;

			 // if this opponent is seen currently
			 if (*pPersOL == SEEN_CURRENTLY)
			{
				// they are NOT visible now!
				(*pPersOL)++;
				if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
				{
					RemoveOneOpponent(pSoldier);
				}
			}
		}
	}
}



void VerifyPublicOpplistDueToDeath(SOLDIERTYPE *pSoldier)
{
	UINT32 uiLoop,uiTeamMateLoop;
	INT8 *pPersOL,*pMatePersOL;	// pointers into soldier's opponent list
	SOLDIERTYPE *pOpponent,*pTeamMate;
	BOOLEAN bOpponentStillSeen;


	// OK, someone died. Anyone that the deceased ALONE saw has to decay
	// immediately in the Public Opplist.


	// If deceased didn't see ANYONE, don't bother
	if (pSoldier->aiData.bOppCnt == 0)
	{
		return;
	}


	// Deceased looks for each of his opponents who is "seen currently"
	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		// first, initialize flag since this will be a "new" opponent
		bOpponentStillSeen = FALSE;

		// grab a pointer to the "opponent"
		pOpponent = MercSlots[ uiLoop ];

		// if this opponent is active, here, and alive
		if (pOpponent != NULL && pOpponent->stats.bLife)
		{
			// if this opponent is on the same team, he's no opponent, so skip him
			if (pSoldier->bTeam == pOpponent->bTeam)
			{
				continue;
			}

			// point to what the deceased's personal opplist value is
			pPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;

			// if this opponent was CURRENTLY SEEN by the deceased (before his
			// untimely demise)
			if (*pPersOL == SEEN_CURRENTLY)
			{
				// then we need to know if any teammates ALSO see this opponent, so loop through
				// trying to find ONE witness to the death...
				for (uiTeamMateLoop = 0; uiTeamMateLoop < guiNumMercSlots; uiTeamMateLoop++)
				{
					// grab a pointer to the potential teammate
					pTeamMate = MercSlots[ uiTeamMateLoop ];

					// if this teammate is active, here, and alive
					if (pTeamMate != NULL && pTeamMate->stats.bLife)
					{
						// if this opponent is NOT on the same team, then skip him
						if (pTeamMate->bTeam != pSoldier->bTeam)
						{
							continue;
						}

						// point to what the teammate's personal opplist value is
						pMatePersOL = pTeamMate->aiData.bOppList + pOpponent->ubID;

						// test to see if this value is "seen currently"
						if (*pMatePersOL == SEEN_CURRENTLY)
						{
							// this opponent HAS been verified!
							bOpponentStillSeen = TRUE;

							// we can stop looking for other witnesses now
							break;
						}
					}
				}
			}

			// if no witnesses for this opponent, then decay the Public Opplist
			if ( !bOpponentStillSeen )
			{
				DECAY_OPPLIST_VALUE( gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID] );
			}
		}
	}
}


void DecayPublicOpplist(INT8 bTeam)
{
	UINT32 uiLoop;
	INT8 bNoPubliclyKnownOpponents = TRUE;
	SOLDIERTYPE *pSoldier;
	INT8 *pbPublOL;


	//NumMessage("Decay for team #",team);

	// decay the team's public noise volume, forget public noise gridno if <= 0
	// used to be -1 per turn but that's not fast enough!
	if (gubPublicNoiseVolume[bTeam] > 0)
	{
		if ( gTacticalStatus.uiFlags & INCOMBAT )
		{
			gubPublicNoiseVolume[bTeam] = (UINT8) ( (UINT32) (gubPublicNoiseVolume[bTeam] * 7) / 10 );
		}
		else
		{
			gubPublicNoiseVolume[bTeam] = gubPublicNoiseVolume[bTeam] / 2;
		}

		if (gubPublicNoiseVolume[bTeam] <= 0)
		{
			gsPublicNoiseGridNo[bTeam] = NOWHERE;
		}
	}

	// decay the team's Public Opplist
	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pSoldier = MercSlots[uiLoop];

		// for every active, living soldier on ANOTHER team
		if (pSoldier && pSoldier->stats.bLife && (pSoldier->bTeam != bTeam))
		{
			// hang a pointer to the byte holding team's public opplist for this merc
			pbPublOL = &gbPublicOpplist[bTeam][pSoldier->ubID];

			if (*pbPublOL == NOT_HEARD_OR_SEEN)
			{
				continue;
			}

			// well, that make this a "publicly known opponent", so nuke that flag
			bNoPubliclyKnownOpponents = FALSE;

			// if this person has been SEEN recently, but is not currently visible
			if (*pbPublOL >= SEEN_THIS_TURN)
			{
				(*pbPublOL)++;		// increment how long it's been
			}
			else
			{
				// if this person has been only HEARD recently
				if (*pbPublOL <= HEARD_THIS_TURN)
				{
					(*pbPublOL)--;	// increment how long it's been
				}
			}

			// if it's been longer than the maximum we care to remember
			if ((*pbPublOL > OLDEST_SEEN_VALUE) || (*pbPublOL < OLDEST_HEARD_VALUE))
			{
#ifdef RECORDOPPLIST
				fprintf(OpplistFile,"UpdatePublic (DecayPublicOpplist) for team %d about %d\n",team,pSoldier->guynum);
#endif

				// forget about him,
				// and also forget where he was last seen (it's been too long)
				// this is mainly so POINT_PATROL guys don't SEEK_OPPONENTs forever
				UpdatePublic(bTeam,pSoldier->ubID,NOT_HEARD_OR_SEEN,NOWHERE,0);
			}
		}
	}

	// if all opponents are publicly unknown (NOT_HEARD_OR_SEEN)
	if (bNoPubliclyKnownOpponents)
	{
		// forget about the last radio alert (ie. throw away who made the call)
		// this is mainly so POINT_PATROL guys don't SEEK_FRIEND forever after
		gTacticalStatus.Team[bTeam].ubLastMercToRadio = NOBODY;
	}

	// decay watched locs as well
	DecayWatchedLocs( bTeam );
}

// bit of a misnomer; this is now decay all opplists
void NonCombatDecayPublicOpplist( UINT32 uiTime )
{
	UINT32	cnt;

	if ( uiTime - gTacticalStatus.uiTimeSinceLastOpplistDecay >= TIME_BETWEEN_RT_OPPLIST_DECAYS)
	{
		// decay!
		for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
		{
			if ( MercSlots[ cnt ] )
			{
				VerifyAndDecayOpplist( MercSlots[ cnt ] );
			}
		}


		for( cnt = 0; cnt < MAXTEAMS; cnt++ )
		{
			if ( gTacticalStatus.Team[ cnt ].bMenInSector > 0 )
			{
				// decay team's public opplist
				DecayPublicOpplist( (INT8)cnt );
			}
		}
		// update time
		gTacticalStatus.uiTimeSinceLastOpplistDecay = uiTime;
	}
}

void RecalculateOppCntsDueToNoLongerNeutral( SOLDIERTYPE * pSoldier )
{
	UINT32					uiLoop;
	SOLDIERTYPE *		pOpponent;

	pSoldier->aiData.bOppCnt = 0;

	if (!pSoldier->aiData.bNeutral)
	{
		for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
		{
			pOpponent = MercSlots[uiLoop];

			// for every active, living soldier on ANOTHER team
			if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide)) )
			{
				if ( pSoldier->aiData.bOppList[pOpponent->ubID] == SEEN_CURRENTLY )
				{
					AddOneOpponent( pSoldier );
				}
				if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY )
				{
					// WANNE: Chris, I reverted BUGZILLA #338 fix, because this leads to big problems on opponent count with enemies!
					// have to add to opponent's oppcount as well since we just became non-neutral
					//CHRISL: If we do this, Bloodcats get counted at opponents multiple times and never get removed from the OppCnt variable.
					AddOneOpponent( pOpponent );
				}
			}
		}
	}
}

void RecalculateOppCntsDueToBecomingNeutral( SOLDIERTYPE * pSoldier )
{
	UINT32					uiLoop;
	SOLDIERTYPE *		pOpponent;

	if (pSoldier->aiData.bNeutral)
	{
		pSoldier->aiData.bOppCnt = 0;

		for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
		{
			pOpponent = MercSlots[uiLoop];

			// for every active, living soldier on ANOTHER team
			if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
			{
				if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY )
				{
					// have to rem from opponent's oppcount as well since we just became neutral
					RemoveOneOpponent( pOpponent );
				}
			}
		}
	}
}

void NoticeUnseenAttacker( SOLDIERTYPE * pAttacker, SOLDIERTYPE * pDefender, INT8 bReason )
{
	INT8		bOldOppList;
	BOOLEAN fSeesAttacker = FALSE;
	INT8		bDirection;
	BOOLEAN	fMuzzleFlash = FALSE;

	if (!(gTacticalStatus.uiFlags & INCOMBAT))
	{
		return;
	}

	if (AmmoTypes[pAttacker->inv[pAttacker->ubAttackingHand][0]->data.gun.ubGunAmmoType].dart)
	{
		// rarely noticed
		if (SkillCheck(pDefender, NOTICE_DART_CHECK, 0) < 0)
		{
			return;
		}
	}

	// do we need to do checks for life/breath here?
	if (pDefender->ubBodyType == LARVAE_MONSTER || (pDefender->flags.uiStatusFlags & SOLDIER_VEHICLE && pDefender->bTeam == OUR_TEAM))
	{
		return;
	}

	bOldOppList = pDefender->aiData.bOppList[ pAttacker->ubID ];
	// check LOS, considering we are now aware of the attacker
	// ignore muzzle flashes when must turning head
	if ( pAttacker->flags.fMuzzleFlash )
	{
		bDirection = atan8( pDefender->sX,pDefender->sY, pAttacker->sX, pAttacker->sY );
		if ( pDefender->ubDirection != bDirection && pDefender->ubDirection != gOneCDirection[ bDirection ] && pDefender->ubDirection != gOneCCDirection[ bDirection ] )
		{
			// temporarily turn off muzzle flash so DistanceVisible can be calculated without it
			pAttacker->flags.fMuzzleFlash = FALSE;
			fMuzzleFlash = TRUE;
		}
	}

	if (SoldierToSoldierLineOfSightTest( pDefender, pAttacker, TRUE, CALC_FROM_WANTED_DIR ) != 0)
	{
		fSeesAttacker = TRUE;
	}
	if ( fMuzzleFlash )
	{
		pAttacker->flags.fMuzzleFlash = TRUE;
	}

	if (fSeesAttacker)
	{
		ManSeesMan( pDefender, pAttacker, pAttacker->sGridNo, pAttacker->pathing.bLevel, NOTICEUNSEENATTACKER, CALLER_UNKNOWN );

		// newOppCnt not needed here (no radioing), must get reset right away
		// CJC: Huh? well, leave it in for now
		pDefender->bNewOppCnt = 0;


		if (pDefender->bTeam == gbPlayerNum)
		{
			// EXPERIENCE GAIN (5): Victim notices/sees a previously UNSEEN attacker
			StatChange( pDefender, EXPERAMT, 5, FALSE );

			// mark attacker as being SEEN right now
			RadioSightings( pDefender, pAttacker->ubID, pDefender->bTeam );

		}
		// NOTE: ENEMIES DON'T REPORT A SIGHTING PUBLICLY UNTIL THEY RADIO IT IN!
		else
		{
			// go to threatening stance
			ReevaluateEnemyStance( pDefender, pDefender->usAnimState );
		}
	}
	else	// victim NOTICED the attack, but CAN'T SEE the actual attacker
	{
		SetNewSituation( pDefender );			// re-evaluate situation

		// if victim's alert status is only GREEN or YELLOW
		if (pDefender->aiData.bAlertStatus < STATUS_RED)
		{
			// then this soldier goes to status RED, has proof of enemy presence
			pDefender->aiData.bAlertStatus = STATUS_RED;
			CheckForChangingOrders( pDefender );
		}

		UpdatePersonal( pDefender, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel );

		// if the victim is a human-controlled soldier, instantly report publicly
		if (pDefender->flags.uiStatusFlags & SOLDIER_PC)
		{
			// mark attacker as having been PUBLICLY heard THIS TURN & remember where
			UpdatePublic( pDefender->bTeam, pAttacker->ubID, HEARD_THIS_TURN, pAttacker->sGridNo, pAttacker->pathing.bLevel );
		}
	}

	if ( !UsingImprovedInterruptSystem() || gGameExternalOptions.fAllowInstantInterruptsOnSight )
	{
		if ( StandardInterruptConditionsMet( pDefender, pAttacker->ubID, bOldOppList ) )
		{
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, standard conditions are met; defender %d, attacker %d", pDefender->ubID, pAttacker->ubID ) );

			// calculate the interrupt duel points
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for defender in NUA" );
			pDefender->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pDefender, pAttacker->ubID, FALSE);
		}
		else
		{
			pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT;
		}

		// say quote

		if (pDefender->aiData.bInterruptDuelPts != NO_INTERRUPT)
		{
			// check for possible interrupt and handle control change if it happens
			// this code is basically ResolveInterruptsVs for 1 man only...

			// calculate active soldier's dueling pts for the upcoming interrupt duel
			DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for attacker in NUA" );
			pAttacker->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pAttacker, pDefender->ubID, FALSE );
			if ( InterruptDuel( pDefender, pAttacker ) )
			{
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, defender pts %d, attacker pts %d, defender gets interrupt", pDefender->aiData.bInterruptDuelPts, pAttacker->aiData.bInterruptDuelPts ) );
				AddToIntList( pAttacker->ubID, FALSE, TRUE);
				AddToIntList( pDefender->ubID, TRUE, TRUE);
				DoneAddingToIntList( pDefender, TRUE, SIGHTINTERRUPT );
			}
			// either way, clear out both sides' duelPts fields to prepare next duel
			pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT;
			#ifdef DEBUG_INTERRUPTS
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pDefender->ubID ) );
			#endif
			pAttacker->aiData.bInterruptDuelPts = NO_INTERRUPT;
			#ifdef DEBUG_INTERRUPTS
				DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pAttacker->ubID ) );
			#endif

		}
	}
}

void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier )
{
	UINT8						ubID;
	SOLDIERTYPE *		pSoldier;
	INT8						bDir;
	INT16						sDistAway, sDistVisible;

	for ( ubID = gTacticalStatus.Team[ pDyingSoldier->bTeam ].bFirstID; ubID <= gTacticalStatus.Team[ pDyingSoldier->bTeam ].bLastID; ubID++ )
	{

		pSoldier = MercPtrs[ ubID ];

		if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier != pDyingSoldier) && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus < STATUS_RED ) )
		{
			// this guy might have seen the man die

			// distance we "see" then depends on the direction he is located from us
			bDir = atan8(pSoldier->sX,pSoldier->sY,pDyingSoldier->sX,pDyingSoldier->sY);
			sDistVisible = DistanceVisible( pSoldier, pSoldier->pathing.bDesiredDirection, bDir, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel, pSoldier->IsCowering(), GetPercentTunnelVision(pSoldier));
			sDistAway = PythSpacesAway( pSoldier->sGridNo, pDyingSoldier->sGridNo );

			// if we see close enough to see the soldier
			if (sDistAway <= sDistVisible)
			{
				// and we can trace a line of sight to his x,y coordinates
				// assume enemies are always aware of their buddies...
				if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pDyingSoldier->sGridNo, pDyingSoldier->pathing.bLevel, 0, TRUE, sDistVisible ) )
				{
					pSoldier->aiData.bAlertStatus = STATUS_RED;
					CheckForChangingOrders( pSoldier );
				}
			}
		}

	}

}

BOOLEAN ArmyKnowsOfPlayersPresence( void )
{
	UINT8						ubID;
	SOLDIERTYPE *		pSoldier;

	// if anyone is still left...
	if (gTacticalStatus.Team[ ENEMY_TEAM ].bTeamActive && gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector > 0 )
	{
		for ( ubID = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; ubID++ )
		{
			pSoldier = MercPtrs[ ubID ];

			if ( pSoldier->bActive && pSoldier->bInSector && (pSoldier->stats.bLife >= OKLIFE) && (pSoldier->aiData.bAlertStatus >= STATUS_RED ) )
			{
				return( TRUE );
			}
		}
	}
	return( FALSE );
}

BOOLEAN MercSeesCreature( SOLDIERTYPE * pSoldier )
{
	UINT8						ubID;

	if (pSoldier->aiData.bOppCnt > 0)
	{
		for ( ubID = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; ubID <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ubID++ )
		{
			if ( (pSoldier->aiData.bOppList[ ubID ] == SEEN_CURRENTLY) && (MercPtrs[ ubID ]->flags.uiStatusFlags & SOLDIER_MONSTER) )
			{
				return( TRUE );
			}
		}
	}
	return( FALSE );
}


INT8 FindUnusedWatchedLoc( UINT8 ubID )
{
	INT8 bLoop;

	for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
	{
		// WANNE: I think this was a bug, should be != NOWHERE!
		// sevenfm: the original code is ok, as we search for unused WatchedLoc which is initialized with NOWHERE value
		if ( gsWatchedLoc[ ubID ][ bLoop ] == NOWHERE )
		//if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]))
		{
			return( bLoop );
		}
	}
	return( -1 );
}

INT8 FindWatchedLocWithLessThanXPointsLeft( UINT8 ubID, UINT8 ubPointLimit )
{
	INT8 bLoop;

	for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
	{		
		if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] <= ubPointLimit )
		{
			return( bLoop );
		}
	}
	return( -1 );
}

INT8 FindWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
{
	INT8	bLoop;

	for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
	{		
		if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) &&	gbWatchedLocLevel[ ubID ][ bLoop ] == bLevel )
		{
			if ( SpacesAway( gsWatchedLoc[ ubID ][ bLoop ], sGridNo ) <= WATCHED_LOC_RADIUS )
			{
				return( bLoop );
			}
		}
	}
	return( -1 );
}

INT8 GetWatchedLocPoints( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
{
	INT8	bLoc;

	bLoc = FindWatchedLoc( ubID, sGridNo, bLevel );
	if (bLoc != -1)
	{
		#ifdef JA2BETAVERSION
			/*
			if (gubWatchedLocPoints[ ubID ][ bLoc ] > 1)
			{
				ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Soldier %d getting %d points for interrupt in watched location", ubID, gubWatchedLocPoints[ ubID ][ bLoc ] - 1 );
			}
			*/
		#endif
		// one loc point is worth nothing, so return number minus 1

		// experiment with 1 loc point being worth 1 point
		return( gubWatchedLocPoints[ ubID ][ bLoc ] );
	}

	return( 0 );
}


INT8 GetHighestVisibleWatchedLoc( UINT8 ubID )
{
	INT8	bLoop;
	INT8	bHighestLoc = -1;
	INT8	bHighestPoints = 0;

	for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
	{		
		if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] > bHighestPoints )
		{
			// look at standing height
			if ( SoldierTo3DLocationLineOfSightTest( MercPtrs[ ubID ], gsWatchedLoc[ ubID ][ bLoop ], gbWatchedLocLevel[ ubID ][ bLoop ], 3, TRUE, CALC_FROM_WANTED_DIR ) )
			{
				bHighestLoc = bLoop;
				bHighestPoints = gubWatchedLocPoints[ ubID ][ bLoop ];
			}
		}
	}
	return( bHighestLoc );
}

INT8 GetHighestWatchedLocPoints( UINT8 ubID )
{
	INT8	bLoop;
	INT8	bHighestPoints = 0;

	for ( bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++ )
	{		
		if (!TileIsOutOfBounds(gsWatchedLoc[ ubID ][ bLoop ]) && gubWatchedLocPoints[ ubID ][ bLoop ] > bHighestPoints )
		{
			bHighestPoints = gubWatchedLocPoints[ ubID ][ bLoop ];
		}
	}
	return( bHighestPoints );
}


void CommunicateWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel, UINT8 ubPoints )
{
	UINT8 ubLoop;
	INT8		bTeam, bLoopPoint, bPoint;

	bTeam = MercPtrs[ ubID ]->bTeam;

	for ( ubLoop = gTacticalStatus.Team[ bTeam ].bFirstID; ubLoop <= gTacticalStatus.Team[ bTeam ].bLastID; ubLoop++ )
	{
		if ( ubLoop == ubID || MercPtrs[ ubLoop ]->bActive == FALSE || MercPtrs[ ubLoop ]->bInSector == FALSE || MercPtrs[ ubLoop ]->stats.bLife < OKLIFE )
		{
			continue;
		}
		bLoopPoint = FindWatchedLoc( ubLoop, sGridNo, bLevel );
		if ( bLoopPoint == -1 )
		{
			// add this as a watched point
			bPoint = FindUnusedWatchedLoc( ubLoop );
			if (bPoint == -1)
			{
				// if we have a point with only 1 point left, replace it
				bPoint = FindWatchedLocWithLessThanXPointsLeft( ubLoop, ubPoints );
			}
			if (bPoint != -1)
			{
				gsWatchedLoc[ ubLoop ][ bPoint ] = sGridNo;
				gbWatchedLocLevel[ ubLoop ][ bPoint ] = bLevel;
				gubWatchedLocPoints[ ubLoop ][ bPoint ] = ubPoints;
				gfWatchedLocReset[ ubLoop ][ bPoint ] = FALSE;
				gfWatchedLocHasBeenIncremented[ ubLoop ][ bPoint ] = TRUE;
			}
			// else no points available!
		}
		else
		{
			// increment to max
			gubWatchedLocPoints[ ubLoop ][ bLoopPoint ] = __max( gubWatchedLocPoints[ ubLoop ][ bLoopPoint ], ubPoints );

			gfWatchedLocReset[ ubLoop ][ bLoopPoint ] = FALSE;
			gfWatchedLocHasBeenIncremented[ ubLoop ][ bLoopPoint ] = TRUE;
		}
	}
}


void IncrementWatchedLoc( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
{
	INT8	bPoint;

	bPoint = FindWatchedLoc( ubID, sGridNo, bLevel );
	if (bPoint == -1)
	{
		// try adding point
		bPoint = FindUnusedWatchedLoc( ubID );
		if (bPoint == -1)
		{
			// if we have a point with only 1 point left, replace it
			bPoint = FindWatchedLocWithLessThanXPointsLeft( ubID, 1 );
		}

		if (bPoint != -1)
		{
			gsWatchedLoc[ ubID ][ bPoint ] = sGridNo;
			gbWatchedLocLevel[ ubID ][ bPoint ] = bLevel;
			gubWatchedLocPoints[ ubID ][ bPoint ] = 1;
			gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
			gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] = TRUE;

			CommunicateWatchedLoc( ubID, sGridNo, bLevel, 1 );
		}
		// otherwise abort; no points available
	}
	else
	{
		if ( !gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] && gubWatchedLocPoints[ ubID ][ bPoint ] < MAX_WATCHED_LOC_POINTS )
		{
			gubWatchedLocPoints[ ubID ][ bPoint ]++;
			CommunicateWatchedLoc( ubID, sGridNo, bLevel, gubWatchedLocPoints[ ubID ][ bPoint ] );
		}
		gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
		gfWatchedLocHasBeenIncremented[ ubID ][ bPoint ] = TRUE;
	}
}

void SetWatchedLocAsUsed( UINT8 ubID, INT32 sGridNo, INT8 bLevel )
{
	INT8	bPoint;

	bPoint = FindWatchedLoc( ubID, sGridNo, bLevel );
	if (bPoint != -1)
	{
		gfWatchedLocReset[ ubID ][ bPoint ] = FALSE;
	}
}

BOOLEAN WatchedLocLocationIsEmpty( INT32 sGridNo, INT8 bLevel, INT8 bTeam )
{
	// look to see if there is anyone near the watched loc who is not on this team
	UINT8	ubID;
	INT32	sTempGridNo;
	INT16	sX, sY;

	for ( sY = -WATCHED_LOC_RADIUS; sY <= WATCHED_LOC_RADIUS; sY++ )
	{
		for ( sX = -WATCHED_LOC_RADIUS; sX <= WATCHED_LOC_RADIUS; sX++ )
		{
			sTempGridNo = sGridNo + sX + sY * WORLD_ROWS;
			if ( sTempGridNo < 0 || sTempGridNo >= WORLD_MAX )
			{
				continue;
			}
			ubID = WhoIsThere2( sTempGridNo, bLevel );
			if ( ubID != NOBODY && MercPtrs[ ubID ]->bTeam != bTeam )
			{
				return( FALSE );
			}
		}
	}
	return( TRUE );
}

void DecayWatchedLocs( INT8 bTeam )
{
	UINT8	cnt, cnt2;

	// loop through all soldiers
	for ( cnt = gTacticalStatus.Team[ bTeam ].bFirstID; cnt <= gTacticalStatus.Team[ bTeam ].bLastID; cnt++ )
	{
		// for each watched location
		for ( cnt2 = 0; cnt2 < NUM_WATCHED_LOCS; cnt2++ )
		{			
			if (!TileIsOutOfBounds(gsWatchedLoc[ cnt ][ cnt2 ]) && WatchedLocLocationIsEmpty( gsWatchedLoc[ cnt ][ cnt2 ], gbWatchedLocLevel[ cnt ][ cnt2 ], bTeam ) )
			{
				// if the reset flag is still set, then we should decay this point
				if (gfWatchedLocReset[ cnt ][ cnt2 ])
				{
					// turn flag off again
					gfWatchedLocReset[ cnt ][ cnt2 ] = FALSE;

					// halve points
					gubWatchedLocPoints[ cnt ][ cnt2 ] /= 2;
					// if points have reached 0, then reset the location
					if (gubWatchedLocPoints[ cnt ][ cnt2 ] == 0)
					{
						gsWatchedLoc[ cnt ][ cnt2 ] = NOWHERE;
					}
				}
				else
				{
					// flag was false so set to true (will be reset if new people seen there next turn)
					gfWatchedLocReset[ cnt ][ cnt2 ] = TRUE;
				}
			}
		}
	}
}

void MakeBloodcatsHostile( void )
{
	INT32						iLoop;
	SOLDIERTYPE *		pSoldier;

	iLoop = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID;

	for (pSoldier = MercPtrs[iLoop]; iLoop <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; ++iLoop, ++pSoldier )
	{
		if ( pSoldier->ubBodyType == BLOODCAT && pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 )
		{
			SetSoldierNonNeutral( pSoldier );
			RecalculateOppCntsDueToNoLongerNeutral( pSoldier );

			if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
			{
				CheckForPotentialAddToBattleIncrement( pSoldier );
			}
		}
	}
}

BOOLEAN SoldierHasLimitedVision(SOLDIERTYPE * pSoldier)
{
	if ( gGameExternalOptions.gfAllowLimitedVision || GetPercentTunnelVision(pSoldier) > 0 )
		return TRUE;
	else
		return FALSE;
}

#ifdef JA2UB
INT32 MaxDistanceVisible( void )
{
	return( STRAIGHT * 2 );
}
#endif
