#ifdef PRECOMPILEDHEADERS
	#include "Tactical All.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "Types.h"
#include "civ quotes.h"
#include "mousesystem.h"
#include "strategicmap.h"
#include "WCheck.h"
#include "FileMan.h"
#include "encrypted file.h"
#include "MessageBoxScreen.h"
#include "Queen Command.h"
#include "Overhead.h"
#include "render dirty.h"
#include "merctextbox.h"
#include "ai.h"
#include "Text.h"
#include "screenids.h"
#include "Animation Data.h"
#include "Video.h"
#include "Font Control.h"
#include "message.h"
#include "local.h"
#include "renderworld.h"
#include "Interface.h"
#include "cursors.h"
#include "Dialogue Control.h"
#include "Quests.h"
#include "Strategic Town Loyalty.h"
#include "NPC.h"
#include "Strategic Mines.h"
#include "Random.h"
#endif
#include "connect.h"

// for enemy taunts
#include "Soldier Profile.h"
#include "Campaign.h"
#include "opplist.h"
#include "Sound Control.h"	// sevenfm: voice taunts

#define			DIALOGUE_DEFAULT_WIDTH			200
#define			EXTREAMLY_LOW_TOWN_LOYALTY	20
#define			HIGH_TOWN_LOYALTY						80
#define			CIV_QUOTE_HINT							99

#define			MAX_APPLICABLE_TAUNTS			512

extern void CaptureTimerCallback( void );

BOOLEAN gfSurrendered = FALSE;

//--------------------------------------------------------------
//Not used 
typedef struct
{
	UINT16	ubNumEntries;
	UINT16	ubUnusedCurrentEntry; //Unused

} CIV_QUOTE;

CIV_QUOTE	gCivQuotes[ NUM_CIV_QUOTES]; //Not used 

UINT16	gubNumEntries[ NUM_CIV_QUOTES ] = // Not used 
{
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,

	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,

	5,
	5,
	15,
	15,
	15,
	15,
	15,
	15,
	15,
	15,

	15,
	15,
	2,
	15,
	15,
	10,
	10,
	5,
	3,
	10,

	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3,
	3
};
//--------------------------------------------------------------

typedef struct
{
	BOOLEAN				bActive;
	MOUSE_REGION	MouseRegion;
	INT32					iVideoOverlay;
	INT32					iDialogueBox;
	UINT32				uiTimeOfCreation;
	UINT32				uiDelayTime;
	SOLDIERTYPE *	pCiv;
} QUOTE_SYSTEM_STRUCT;


QUOTE_SYSTEM_STRUCT	gCivQuoteData;

CHAR16	gzCivQuote[ 320 ];
UINT16	gusCivQuoteBoxWidth;
UINT16	gusCivQuoteBoxHeight;

// anv: store times, when enemy taunt will be finished (so they won't taunt 50 times / second)
UINT32	uiTauntFinishTimes[ TOTAL_SOLDIERS ];

TAUNT_VALUES zApplicableTaunts[NUM_TAUNT];

//--------------------------------------------------------------
void CopyNumEntriesIntoQuoteStruct( ) //  Not used 
{
	INT32	cnt;

	for ( cnt = 0; cnt < NUM_CIV_QUOTES; ++cnt )
	{
		if (cnt <= 50) 
			gCivQuotes[ cnt ].ubNumEntries = gubNumEntries[ cnt ];
		else 
			gCivQuotes[ cnt ].ubNumEntries = 15;
	}

}
//--------------------------------------------------------------

BOOLEAN GetCivQuoteText(UINT16 ubCivQuoteID, UINT16 ubEntryID, STR16 zQuote )
{
	CHAR8 zFileName[164];

	// Build filename....
	if ( ubCivQuoteID == CIV_QUOTE_HINT )
	{
		if ( gbWorldSectorZ > 0 )
		{
			//sprintf( zFileName, "NPCData\\miners.edt" );
				sprintf( zFileName,"NPCDATA\\CIV%02d.edt", CIV_QUOTE_MINERS_NOT_FOR_PLAYER );
		}
		else
		{
			sprintf( zFileName, "NPCData\\%c%d.edt", 'A' + (gWorldSectorY - 1) , gWorldSectorX );
		}
	}
	else
	{
		if (ubCivQuoteID <= 9)
			sprintf( zFileName,"NPCDATA\\CIV%02d.edt",ubCivQuoteID );
		else
			sprintf( zFileName,"NPCDATA\\CIV%d.edt",ubCivQuoteID );
	}

	CHECKF( FileExists( zFileName ) );

	// Get data...
	LoadEncryptedDataFromFile( zFileName, zQuote, ubEntryID * 320, 320 );

	if( zQuote[0] == 0 )
	{
		return( FALSE );
	}

	return( TRUE );
}

void SurrenderMessageBoxCallBack( UINT8 ubExitValue )
{
	SOLDIERTYPE *pTeamSoldier;
	INT32				cnt = 0;

	if ( ubExitValue == MSG_BOX_RETURN_YES )
	{
		// CJC Dec 1 2002: fix multiple captures
		BeginCaptureSquence();

	// Do capture....
		cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;

		for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++)
		{
			// Are we active and in sector.....
			if ( pTeamSoldier->bActive && pTeamSoldier->bInSector )
			{
				if ( pTeamSoldier->stats.bLife != 0 )
				{
					EnemyCapturesPlayerSoldier( pTeamSoldier );

					RemoveSoldierFromTacticalSector( pTeamSoldier, TRUE );
				}
			}
		}

		EndCaptureSequence( );

		gfSurrendered = TRUE;
		SetCustomizableTimerCallbackAndDelay( 3000, CaptureTimerCallback, FALSE );

		ActionDone( gCivQuoteData.pCiv );
	}
	else
	{
		ActionDone( gCivQuoteData.pCiv );
	}
}

void ShutDownQuoteBox( BOOLEAN fForce )
{
	if ( !gCivQuoteData.bActive )
	{
		return;
	}

	// Check for min time....
	if ( ( GetJA2Clock( ) - gCivQuoteData.uiTimeOfCreation ) > 300 || fForce )
	{
		RemoveVideoOverlay( gCivQuoteData.iVideoOverlay );

		// Remove mouse region...
		MSYS_RemoveRegion( &(gCivQuoteData.MouseRegion) );

		RemoveMercPopupBoxFromIndex( gCivQuoteData.iDialogueBox );
		gCivQuoteData.iDialogueBox = -1;

		gCivQuoteData.bActive = FALSE;
#ifdef JA2UB
// no UB
#else
		// do we need to do anything at the end of the civ quote?
		if ( gCivQuoteData.pCiv && gCivQuoteData.pCiv->aiData.bAction == AI_ACTION_OFFER_SURRENDER )
		{
// Haydent
			if(!is_networked)
			{
				DoMessageBox( MSG_BOX_BASIC_STYLE, Message[ STR_SURRENDER ], GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, SurrenderMessageBoxCallBack, NULL );
			}
			else 
			{
				ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[39] );
				ActionDone( gCivQuoteData.pCiv );
			}
		}
#endif
	}
}

BOOLEAN ShutDownQuoteBoxIfActive( )
{
	if ( gCivQuoteData.bActive )
	{
		ShutDownQuoteBox( TRUE );

		return( TRUE );
	}

	return( FALSE );
}


INT8 GetCivType( SOLDIERTYPE *pCiv )
{
	if ( pCiv->ubProfile != NO_PROFILE )
	{
		return( CIV_TYPE_NA );
	}

	// ATE: Check if this person is married.....
	// 1 ) check sector....
	if ( gWorldSectorX == 10 && gWorldSectorY == 6 && gbWorldSectorZ == 0 )
	{
		// 2 ) the only female....
		if ( pCiv->ubCivilianGroup == 0 && pCiv->bTeam != gbPlayerNum && pCiv->ubBodyType == REGFEMALE )
		{
			// She's a ho!
			return( CIV_TYPE_MARRIED_PC );
		}
	}

	// OK, look for enemy type - MUST be on enemy team, merc bodytype
	if ( pCiv->bTeam == ENEMY_TEAM && IS_MERC_BODY_TYPE( pCiv ) )
	{
		return( CIV_TYPE_ENEMY );
	}

	if ( pCiv->bTeam == CREATURE_TEAM && pCiv->ubSoldierClass == SOLDIER_CLASS_BANDIT )
	{
		return( CIV_TYPE_ENEMY );
	}

	if ( pCiv->bTeam != CIV_TEAM && pCiv->bTeam != MILITIA_TEAM )
	{
		return( CIV_TYPE_NA );
	}

	switch( pCiv->ubBodyType )
	{
		case REGMALE:
		case BIGMALE:
		case STOCKYMALE:
		case REGFEMALE:
		case FATCIV:
		case MANCIV:
		case MINICIV:
		case DRESSCIV:
		case CRIPPLECIV:

			return( CIV_TYPE_ADULT );
			break;

		case ADULTFEMALEMONSTER:
		case AM_MONSTER:
		case YAF_MONSTER:
		case YAM_MONSTER:
		case LARVAE_MONSTER:
		case INFANT_MONSTER:
		case QUEENMONSTER:

			return( CIV_TYPE_NA );

		case HATKIDCIV:
		case KIDCIV:

			return( CIV_TYPE_KID );

		default:

			return( CIV_TYPE_NA );
	}

	//return( CIV_TYPE_NA ); // not needed when there is a default! (jonathanl)
}


void RenderCivQuoteBoxOverlay( VIDEO_OVERLAY *pBlitter )
{
	if ( gCivQuoteData.iVideoOverlay != -1 )
	{
		RenderMercPopUpBoxFromIndex( gCivQuoteData.iDialogueBox, pBlitter->sX, pBlitter->sY,	pBlitter->uiDestBuff );

		InvalidateRegion( pBlitter->sX, pBlitter->sY, pBlitter->sX + gusCivQuoteBoxWidth, pBlitter->sY + gusCivQuoteBoxHeight );
	}
}


void QuoteOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason )
{
	static BOOLEAN fLButtonDown = FALSE;

	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
	{
		fLButtonDown = TRUE;
	}

	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP && fLButtonDown )
	{
		// Shutdown quote box....
		ShutDownQuoteBox( FALSE );
	}
	else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
	{
		fLButtonDown = FALSE;
	}
}


void BeginCivQuote( SOLDIERTYPE *pCiv, UINT16 ubCivQuoteID, UINT16 ubEntryID, INT16 sX, INT16 sY )
{
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;
	CHAR16					zQuote[ 320 ];	
	
	// OK, do we have another on?
	if ( gCivQuoteData.bActive )
	{
		// Delete?
		ShutDownQuoteBox( TRUE );
	}
	
	// get text
	if ( !GetCivQuoteText( ubCivQuoteID, ubEntryID, zQuote ) )
	{
		return;
	}

	swprintf( gzCivQuote, L"\"%s\"", zQuote );

	if ( ubCivQuoteID == CIV_QUOTE_HINT )
	{
		MapScreenMessage( FONT_MCOLOR_WHITE, MSG_DIALOG, L"%s",	gzCivQuote );
	}

	// Create video oeverlay....
	memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) );

	//never use it anymore
	//SET_USE_WINFONTS( TRUE );
	//SET_WINFONT( giSubTitleWinFont );
	// Prepare text box
	gCivQuoteData.iDialogueBox = PrepareMercPopupBox( gCivQuoteData.iDialogueBox , BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gzCivQuote, DIALOGUE_DEFAULT_WIDTH, 0, 0, 0, &gusCivQuoteBoxWidth, &gusCivQuoteBoxHeight );
	//SET_USE_WINFONTS( FALSE );
	
	// OK, find center for box......
	sX = sX - ( gusCivQuoteBoxWidth / 2 );
	sY = sY - ( gusCivQuoteBoxHeight / 2 );

	// OK, limit to screen......
	{
		if ( sX < 0 )
		{
			sX = 0;
		}

		// CHECK FOR LEFT/RIGHT
		if ( ( sX + gusCivQuoteBoxWidth ) > SCREEN_WIDTH )
		{
			sX = SCREEN_WIDTH - gusCivQuoteBoxWidth;
		}

		// Now check for top
		if ( sY < gsVIEWPORT_WINDOW_START_Y )
		{
			sY = gsVIEWPORT_WINDOW_START_Y;
		}

		// Check for bottom
		if ( ( sY + gusCivQuoteBoxHeight ) > (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT))
		{
			sY = (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT) - gusCivQuoteBoxHeight;
		}
	}

	VideoOverlayDesc.sLeft			= sX;
	VideoOverlayDesc.sTop				= sY;
	VideoOverlayDesc.sRight			= VideoOverlayDesc.sLeft + gusCivQuoteBoxWidth;
	VideoOverlayDesc.sBottom		= VideoOverlayDesc.sTop + gusCivQuoteBoxHeight;
	VideoOverlayDesc.sX					= VideoOverlayDesc.sLeft;
	VideoOverlayDesc.sY					= VideoOverlayDesc.sTop;
	VideoOverlayDesc.BltCallback = RenderCivQuoteBoxOverlay;

	gCivQuoteData.iVideoOverlay =	RegisterVideoOverlay( 0, &VideoOverlayDesc );


	//Define main region
	MSYS_DefineRegion( &(gCivQuoteData.MouseRegion), VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop,	VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST,
						CURSOR_NORMAL, MSYS_NO_CALLBACK, QuoteOverlayClickCallback );
	// Add region
	MSYS_AddRegion( &(gCivQuoteData.MouseRegion) );
	
	gCivQuoteData.bActive = TRUE;

	gCivQuoteData.uiTimeOfCreation = GetJA2Clock( );

	gCivQuoteData.uiDelayTime = FindDelayForString( gzCivQuote ) + 500;

	gCivQuoteData.pCiv = pCiv;
}

void BeginChatQuote( SOLDIERTYPE *pCiv, INT16 sX, INT16 sY )
{
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	// OK, do we have another on?
	if ( gCivQuoteData.bActive )
	{
		// Delete?
		ShutDownQuoteBox( TRUE );
	}

	if ( pCiv->bTeam == gbPlayerNum )
		swprintf( gzCivQuote, L"\"%s\"", szChatTextSpy[Random( 24 )] );
	else
		swprintf( gzCivQuote, L"\"%s\"", szChatTextEnemy[Random( 24 )] );
	
	// Create video oeverlay....
	memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) );

	// Prepare text box
	gCivQuoteData.iDialogueBox = PrepareMercPopupBox( gCivQuoteData.iDialogueBox, BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gzCivQuote, DIALOGUE_DEFAULT_WIDTH, 0, 0, 0, &gusCivQuoteBoxWidth, &gusCivQuoteBoxHeight );
	
	// Flugente: have the box appear a bit above the soldier. Otherwise it will obstruct us from aiming at him, which is annoying if it happens very often
	sY -= 30;

	// OK, find center for box......
	sX = sX - ( gusCivQuoteBoxWidth / 2 );
	sY = sY - ( gusCivQuoteBoxHeight / 2 );

	// OK, limit to screen......
	{
		if ( sX < 0 )
		{
			sX = 0;
		}

		// CHECK FOR LEFT/RIGHT
		if ( ( sX + gusCivQuoteBoxWidth ) > SCREEN_WIDTH )
		{
			sX = SCREEN_WIDTH - gusCivQuoteBoxWidth;
		}

		// Now check for top
		if ( sY < gsVIEWPORT_WINDOW_START_Y )
		{
			sY = gsVIEWPORT_WINDOW_START_Y;
		}

		// Check for bottom
		if ( ( sY + gusCivQuoteBoxHeight ) > ( SCREEN_HEIGHT - INV_INTERFACE_HEIGHT ) )
		{
			sY = ( SCREEN_HEIGHT - INV_INTERFACE_HEIGHT ) - gusCivQuoteBoxHeight;
		}
	}

	VideoOverlayDesc.sLeft = sX;
	VideoOverlayDesc.sTop = sY;
	VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusCivQuoteBoxWidth;
	VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusCivQuoteBoxHeight;
	VideoOverlayDesc.sX = VideoOverlayDesc.sLeft;
	VideoOverlayDesc.sY = VideoOverlayDesc.sTop;
	VideoOverlayDesc.BltCallback = RenderCivQuoteBoxOverlay;

	gCivQuoteData.iVideoOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc );
	
	//Define main region
	MSYS_DefineRegion( &( gCivQuoteData.MouseRegion ), VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop, VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST,
		CURSOR_NORMAL, MSYS_NO_CALLBACK, QuoteOverlayClickCallback );
	// Add region
	MSYS_AddRegion( &( gCivQuoteData.MouseRegion ) );

	gCivQuoteData.bActive = TRUE;

	gCivQuoteData.uiTimeOfCreation = GetJA2Clock();

	gCivQuoteData.uiDelayTime = FindDelayForString( gzCivQuote ) + 500;

	gCivQuoteData.pCiv = pCiv;
}

UINT16 DetermineCivQuoteEntry( SOLDIERTYPE *pCiv, UINT16 *pubCivHintToUse, BOOLEAN fCanUseHints )
{
	UINT8	ubCivType;
#ifdef JA2UB

#else
	INT8	bTownId;
	INT8	bCivHint;
	INT8	bMineId;
#endif

	BOOLEAN	bCivLowLoyalty = FALSE;
	BOOLEAN	bCivHighLoyalty = FALSE;

	BOOLEAN bMiners = FALSE;
	UINT16 FileEDTQUoteID;
	
	(*pubCivHintToUse) = 0;

	ubCivType = GetCivType( pCiv );

	if ( pCiv->ubCivilianGroup < NUM_CIV_GROUPS )
	{
#ifdef JA2UB
		if ( pCiv->ubCivilianGroup > UNNAMED_CIV_GROUP_19 )
#else
		if ( pCiv->ubCivilianGroup > QUEENS_CIV_GROUP )
#endif
		{
			if ( pCiv->aiData.bNeutral )
			{
				return(FileEDTQUoteID = pCiv->ubCivilianGroup * 2 + 10);
			}
			else
			{
				return(FileEDTQUoteID = pCiv->ubCivilianGroup * 2 + 11);
			}
		}
	}
		
#ifdef JA2UB		
	if( ubCivType != CIV_TYPE_ENEMY )
	{
		//if the civ is not an enemy
		if ( pCiv->aiData.bNeutral )
		{
			return( CIV_QUOTE__CIV_NOT_ENEMY ); //43
		}
		else
		{
			//
			//the civ is an enemy
			//

			//if the civ can fight
			if( pCiv->ubBodyType == REGMALE || pCiv->ubBodyType == REGFEMALE || pCiv->ubBodyType == BIGMALE )
			{
				return( CIV_QUOTE__CIV_ENEMY_CAN_FIGHT); //40 
			}
			else if( pCiv->stats.bLife < pCiv->stats.bLifeMax )
			{
				return( CIV_QUOTE__CIV_HURT ); //42
			}
			else
			{
				return( CIV_QUOTE__CIV_ENEMY_GENERIC ); //41
			}
		}
	}


	if( ubCivType == CIV_TYPE_ENEMY )
	{
		// Determine what type of quote to say...
		// Are are we going to attack?

		if ( pCiv->aiData.bAction == AI_ACTION_TOSS_PROJECTILE || pCiv->aiData.bAction == AI_ACTION_FIRE_GUN ||
							pCiv->aiData.bAction == AI_ACTION_FIRE_GUN || pCiv->aiData.bAction == AI_ACTION_KNIFE_MOVE )
		{
			return( CIV_QUOTE_ENEMY_THREAT );
		}

		// Hurt?
		else if ( pCiv->stats.bLife < 30 )
		{
			return( CIV_QUOTE_ENEMY_HURT );
		}
		// elite?
		else if ( pCiv->ubSoldierClass == SOLDIER_CLASS_ELITE )
		{
			return( CIV_QUOTE_ENEMY_ELITE );
		}
		else
		{
			return( CIV_QUOTE_ENEMY_ADMIN );
		}
	}

	return( 255 );
#else	
			
	if ( ubCivType == CIV_TYPE_ENEMY )
	{
		// Determine what type of quote to say...
		// Are are we going to attack?

		if (	pCiv->aiData.bAction == AI_ACTION_TOSS_PROJECTILE 
			||	pCiv->aiData.bAction == AI_ACTION_FIRE_GUN 
			||	pCiv->aiData.bAction == AI_ACTION_THROW_KNIFE 
			||	pCiv->aiData.bAction == AI_ACTION_KNIFE_MOVE )
		{
			return( CIV_QUOTE_ENEMY_THREAT );
		}
		else if ( pCiv->aiData.bAction == AI_ACTION_OFFER_SURRENDER )
		{
			return( CIV_QUOTE_ENEMY_OFFER_SURRENDER );
		}
		// Hurt?
		else if ( pCiv->stats.bLife < 30 )
		{
			return( CIV_QUOTE_ENEMY_HURT );
		}
		// elite?
		else if ( pCiv->ubSoldierClass == SOLDIER_CLASS_ELITE )
		{
			return( CIV_QUOTE_ENEMY_ELITE );
		}
		else
		{
			return( CIV_QUOTE_ENEMY_ADMIN );
		}
	}

	// Are we in a town sector?
	// get town id
	bTownId = GetTownIdForSector( gWorldSectorX, gWorldSectorY );
	
	// If a married PC...
	if ( ubCivType == CIV_TYPE_MARRIED_PC )
	{
		return( CIV_QUOTE_PC_MARRIED );
	}

	// CIV GROUPS FIRST!
	// Hicks.....
	if ( pCiv->ubCivilianGroup == HICKS_CIV_GROUP )
	{
		// Are they friendly?
		//if ( gTacticalStatus.fCivGroupHostile[ HICKS_CIV_GROUP ] < CIV_GROUP_WILL_BECOME_HOSTILE )
		if ( pCiv->aiData.bNeutral )
		{
			return( CIV_QUOTE_HICKS_FRIENDLY );
		}
		else
		{
			return( CIV_QUOTE_HICKS_ENEMIES );
		}
	}

	// Goons.....
	if ( pCiv->ubCivilianGroup == KINGPIN_CIV_GROUP )
	{
		// Are they friendly?
		//if ( gTacticalStatus.fCivGroupHostile[ KINGPIN_CIV_GROUP ] < CIV_GROUP_WILL_BECOME_HOSTILE )
		if ( pCiv->aiData.bNeutral )
		{
			return( CIV_QUOTE_GOONS_FRIENDLY );
		}
		else
		{
			return( CIV_QUOTE_GOONS_ENEMIES );
		}
	}

	// ATE: Cowering people take precedence....
	if ( ( pCiv->flags.uiStatusFlags & SOLDIER_COWERING ) || ( pCiv->bTeam == CIV_TEAM && ( gTacticalStatus.uiFlags & INCOMBAT ) ) )
	{
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			return( CIV_QUOTE_ADULTS_COWER );
		}
		else
		{
			return( CIV_QUOTE_KIDS_COWER );
		}
	}

	// Kid slaves...
	if ( pCiv->ubCivilianGroup == FACTORY_KIDS_GROUP )
	{
		// Check fact.....
		if ( CheckFact( FACT_DOREEN_HAD_CHANGE_OF_HEART, 0 ) || !CheckFact( FACT_DOREEN_ALIVE, 0 ) )
		{
			return( CIV_QUOTE_KID_SLAVES_FREE );
		}
		else
		{
			return( CIV_QUOTE_KID_SLAVES );
		}
	}

	// BEGGERS
	if ( pCiv->ubCivilianGroup == BEGGARS_CIV_GROUP )
	{
		// Check if we are in a town...
		if( bTownId != BLANK_SECTOR && gbWorldSectorZ == 0 )
		{
			if ( bTownId == SAN_MONA && ubCivType == CIV_TYPE_ADULT )
			{
				return( CIV_QUOTE_SAN_MONA_BEGGERS );
			}
		}

		// DO normal beggers...
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			return( CIV_QUOTE_ADULTS_BEGGING );
		}
		else
		{
			return( CIV_QUOTE_KIDS_BEGGING );
		}
	}

	// REBELS
	if ( pCiv->ubCivilianGroup == REBEL_CIV_GROUP )
	{
		// DO normal beggers...
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			return( CIV_QUOTE_ADULTS_REBELS );
		}
		else
		{
			return( CIV_QUOTE_KIDS_REBELS );
		}
	}

	// Do miltitia...
	if ( pCiv->bTeam == MILITIA_TEAM )
	{
		// Different types....
		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA )
		{
			return( CIV_QUOTE_GREEN_MILITIA );
		}
		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA )
		{
			return( CIV_QUOTE_MEDIUM_MILITIA );
		}
		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA )
		{
			return( CIV_QUOTE_ELITE_MILITIA );
		}
	}

	// If we are in medunna, and queen is dead, use these...
	if ( bTownId == MEDUNA && CheckFact( FACT_QUEEN_DEAD, 0 ) )
	{
		return( CIV_QUOTE_DEIDRANNA_DEAD );
	}

	// if in a town
	if( ( bTownId != BLANK_SECTOR ) && ( gbWorldSectorZ == 0 ) && gfTownUsesLoyalty[ bTownId ] )
	{
		// Check loyalty special quotes.....
		// EXTREMELY LOW TOWN LOYALTY...
		if ( gTownLoyalty[ bTownId ].ubRating < EXTREAMLY_LOW_TOWN_LOYALTY )
		{
			bCivLowLoyalty = TRUE;
		}

		// HIGH TOWN LOYALTY...
		if ( gTownLoyalty[ bTownId ].ubRating >= HIGH_TOWN_LOYALTY )
		{
			bCivHighLoyalty = TRUE;
		}
	}

	// ATE: OK, check if we should look for a civ hint....
	if ( fCanUseHints )
	{
		bCivHint = ConsiderCivilianQuotes( gWorldSectorX, gWorldSectorY, gbWorldSectorZ,	FALSE );
	}
	else
	{
		bCivHint = -1;
	}

	// ATE: check miners......
	if ( pCiv->ubSoldierClass == SOLDIER_CLASS_MINER )
	{
		bMiners = TRUE;

		// If not a civ hint available...
		if ( bCivHint == -1 )
		{
			// Check if they are under our control...

			// Should I go talk to miner?
			// Not done yet.

			// Are they working for us?
			bMineId = GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );

			if ( PlayerControlsMine( bMineId ) )
			{
				return( CIV_QUOTE_MINERS_FOR_PLAYER );
			}
			else
			{
				return( CIV_QUOTE_MINERS_NOT_FOR_PLAYER );
			}
		}
	}

	// Is one availible?
	// If we are to say low loyalty, do chance
	if ( bCivHint != -1 && bCivLowLoyalty && !bMiners )
	{
		if ( Random( 100 ) < 25 )
		{
			// Get rid of hint...
			bCivHint = -1;
		}
	}

	// Say hint if availible...
	if ( bCivHint != -1 )
	{
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			(*pubCivHintToUse) = bCivHint;

			// Set quote as used...
			ConsiderCivilianQuotes( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE );

			// retrun value....
			return( CIV_QUOTE_HINT );
		}
	}

	if ( bCivLowLoyalty )
	{
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			return( CIV_QUOTE_ADULTS_EXTREMLY_LOW_LOYALTY );
		}
		else
		{
			return( CIV_QUOTE_KIDS_EXTREMLY_LOW_LOYALTY );
		}
	}

	if ( bCivHighLoyalty )
	{
		if ( ubCivType == CIV_TYPE_ADULT )
		{
			return( CIV_QUOTE_ADULTS_HIGH_LOYALTY );
		}
		else
		{
			return( CIV_QUOTE_KIDS_HIGH_LOYALTY );
		}
	}
	
	// All purpose quote here....
	if ( ubCivType == CIV_TYPE_ADULT )
	{
		return( CIV_QUOTE_ADULTS_ALL_PURPOSE );
	}
	else
	{
		return( CIV_QUOTE_KIDS_ALL_PURPOSE );
	}
#endif
}


void HandleCivQuote( )
{
	if ( gCivQuoteData.bActive )
	{
		// Check for min time....
		if ( ( GetJA2Clock( ) - gCivQuoteData.uiTimeOfCreation ) > gCivQuoteData.uiDelayTime )
		{
			// Stop!
			ShutDownQuoteBox( TRUE );
		}
	}
}

void StartCivQuote( SOLDIERTYPE *pCiv )
{
	UINT16 ubCivQuoteID;
	UINT16	ubEntryID = 0;
	INT16	sScreenX, sScreenY;
	UINT16	ubCivHintToUse;
	UINT16 CivQuoteDelta = 0;
	
	UINT16 ubCivQuoteID2;
	UINT16 RandomVal;
	
	// ATE: Check for old quote.....
	// This could have been stored on last attempt...
	if ( pCiv->bCurrentCivQuote == CIV_QUOTE_HINT )
	{
		// Determine which quote to say.....
		// CAN'T USE HINTS, since we just did one...
		pCiv->bCurrentCivQuote = -1;
		pCiv->bCurrentCivQuoteDelta = 0;
		ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, FALSE );
	}
	else
	{
		// Determine which quote to say.....
		ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, TRUE );
	}
	
	if (ubCivQuoteID == CIV_QUOTE_ADULTS_REBELS || ubCivQuoteID == CIV_QUOTE_KIDS_REBELS || ubCivQuoteID == CIV_QUOTE_ENEMY_OFFER_SURRENDER ) 
	{
		RandomVal = 5;
	}
	else if (ubCivQuoteID == CIV_QUOTE_PC_MARRIED) 
	{
		RandomVal = 2;
	}
	else if (ubCivQuoteID == CIV_QUOTE_HICKS_SEE_US_AT_NIGHT) 
	{
		RandomVal = 3;
	}
	else 
		RandomVal = 15;

#ifdef JA2UB		
	if( ubCivQuoteID == 255 )
	{
		return;
	}
#endif	
	
	// Determine entry id
	// ATE: Try and get entry from soldier pointer....
	if ( ubCivQuoteID != CIV_QUOTE_HINT )
	{
		if ( pCiv->bCurrentCivQuote == -1 )
		{
			// Pick random one
			//pCiv->bCurrentCivQuote = (INT8)Random( gCivQuotes[ ubCivQuoteID ].ubNumEntries - 2 );
			ubCivQuoteID2  = Random(RandomVal-2);
			pCiv->bCurrentCivQuoteDelta = 0;
		}
		else
		{
			ubCivQuoteID2 = pCiv->bCurrentCivQuote;
		}

		//ubEntryID	= pCiv->bCurrentCivQuote + pCiv->bCurrentCivQuoteDelta;
		ubEntryID	= ubCivQuoteID2 + pCiv->bCurrentCivQuoteDelta;
	}
	else
	{
		ubEntryID =ubCivHintToUse;

		// ATE: set value for quote ID.....
		//pCiv->bCurrentCivQuote			= ubCivQuoteID;
		ubCivQuoteID2 = ubCivQuoteID;
		CivQuoteDelta = ubEntryID;
		//pCiv->bCurrentCivQuoteDelta = ubEntryID;
	}

	// Flugente: if we are an assassin, we speak like the militia we emulate
	if ( pCiv->usSoldierFlagMask & SOLDIER_ASSASSIN )
	{
		switch ( pCiv->GetUniformType() )
		{
		case UNIFORM_MILITIA_REGULAR:
			ubCivQuoteID = CIV_QUOTE_MEDIUM_MILITIA;
			break;
		case UNIFORM_MILITIA_ELITE:
			ubCivQuoteID = CIV_QUOTE_ELITE_MILITIA;
			break;
		default:
			ubCivQuoteID = CIV_QUOTE_GREEN_MILITIA;
			break;
		}
	}

	// Determine location...
	// Get location of civ on screen.....
	GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY );

	// begin quote
	BeginCivQuote( pCiv, ubCivQuoteID, ubEntryID, sScreenX, sScreenY );

	// Increment use
	if ( ubCivQuoteID != CIV_QUOTE_HINT )
	{
		//pCiv->bCurrentCivQuoteDelta++;
		++CivQuoteDelta;
		/*
		if ( pCiv->bCurrentCivQuoteDelta == 2 )
		{
			pCiv->bCurrentCivQuoteDelta = 0;
		}
		*/
		if ( CivQuoteDelta == 2 )
		{
			CivQuoteDelta = 0;
		}
	}
}

void InitCivQuoteSystem( )
{
	memset( &gCivQuotes, 0, sizeof( gCivQuotes ) );  //Not used 

	memset( &gCivQuoteData, 0, sizeof( gCivQuoteData ) );
	gCivQuoteData.bActive				= FALSE;
	gCivQuoteData.iVideoOverlay	= -1;
	gCivQuoteData.iDialogueBox	= -1;
}

//--------------------------------------------------------------
//is allowed remove. Not used  and remove from SaveLoadGame.cpp.
BOOLEAN SaveCivQuotesToSaveGameFile( HWFILE hFile )
{
	UINT32	uiNumBytesWritten;

	FileWrite( hFile, &gCivQuotes, sizeof( gCivQuotes), &uiNumBytesWritten );
	if( uiNumBytesWritten != sizeof( gCivQuotes ) )
	{
		return( FALSE );
	}

	return( TRUE );
}

// anv: used now
//is allowed remove. Not used and remove from SaveLoadGame.cpp.
BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile )
{
	UINT32	uiNumBytesRead;

	// anv: reset uiTauntFinishTimes after game is loaded (so enemies can taunt after guiBaseJA2Clock is decreased)
	memset( &uiTauntFinishTimes, 0, sizeof( uiTauntFinishTimes ) );

	FileRead( hFile, &gCivQuotes, sizeof( gCivQuotes ), &uiNumBytesRead );
	if( uiNumBytesRead != sizeof( gCivQuotes ) )
	{
		return( FALSE );
	}

	CopyNumEntriesIntoQuoteStruct( ); //Not used 

	return( TRUE );
}
//--------------------------------------------------------------

// anv: start enemy taunt with probabilty depending on taunt settings
void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, UINT32 uiTargetID )
{
	SOLDIERTYPE *pTarget = NULL;
	if( uiTargetID != NOBODY )
	{
		pTarget = MercPtrs[uiTargetID];
	}
	if (is_networked)	// No taunts in multiplayer
		return;

	// taunts disabled?
	if( gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == FALSE )
	{
		return;
	}
	// uh, just in case
	if( pCiv == NULL )
	{
		return;
	}
	// is enemy blocked from taunting at the moment?
	if( uiTauntFinishTimes[pCiv->ubID] > GetJA2Clock() )
	{
		return;
	}
	// check if generated person
	if ( !(IS_MERC_BODY_TYPE( pCiv )) || !(pCiv->ubProfile == NO_PROFILE) )
	{
		return;
	}
	// only enemies and militia taunt
	// sevenfm: allow voice taunts for hostile civilians with group
	if (pCiv->bTeam != ENEMY_TEAM &&
		pCiv->bTeam != MILITIA_TEAM &&
		!(pCiv->bTeam == CIV_TEAM && pCiv->ubCivilianGroup != NON_CIV_GROUP && !pCiv->aiData.bNeutral && gTauntsSettings.fTauntVoice))
	{
		return;
	}
	/*if ( pCiv->bTeam != ENEMY_TEAM && pCiv->bTeam != MILITIA_TEAM )
	{
		return;
	}*/

	// only visible enemies taunt (unless set otherwise)
	if ( ( pCiv->bVisible == -1 ) && ( gTauntsSettings.fTauntOnlyVisibleEnemies == TRUE ) )
	{
		return;
	}
	// only enemies that are able to speak at the moment can taunt
	if ( pCiv->stats.bLife < OKLIFE || pCiv->bCollapsed || pCiv->bBreathCollapsed )
	{
		return;
	}
	// check probability
 	switch(iTauntType)
	{
		case TAUNT_FIRE_GUN:
			if( Random(100)+1 > gTauntsSettings.ubTauntFireGunChance )
				return;
			break;
		case TAUNT_FIRE_LAUNCHER:
			if( Random(100)+1 > gTauntsSettings.ubTauntFireLauncherChance )
				return;
			break;
		case TAUNT_ATTACK_BLADE:
			if( Random(100)+1 > gTauntsSettings.ubTauntAttackBladeChance)
				return;
			break;
		case TAUNT_ATTACK_HTH:
			if( Random(100)+1 > gTauntsSettings.ubTauntAttackHTHChance )
				return;
			break;

		case TAUNT_THROW_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntThrowKnifeChance )
				return;
			break;
		case TAUNT_THROW_GRENADE:
			if( Random(100)+1 > gTauntsSettings.ubTauntThrowGrenadeChance )
				return;
			break;
		case TAUNT_CHARGE_BLADE:
			if( Random(100)+1 > gTauntsSettings.ubTauntChargeKnifeChance )
				return;
			break;
		case TAUNT_CHARGE_HTH:
			if( Random(100)+1 > gTauntsSettings.ubTauntChargeFistsChance )
				return;
			break;

		case TAUNT_STEAL:
			if( Random(100)+1 > gTauntsSettings.ubTauntStealChance )
				return;
			break;

		case TAUNT_RUN_AWAY:
			if( Random(100)+1 > gTauntsSettings.ubTauntRunAwayChance)
				return;
			break;
		case TAUNT_SEEK_NOISE:
			if( Random(100)+1 > gTauntsSettings.ubTauntSeekNoiseChance )
				return;
			break;
		case TAUNT_ALERT:
			if( Random(100)+1 > gTauntsSettings.ubTauntAlertChance )
				return;
			break;
		case TAUNT_SUSPICIOUS:
			if( Random(100)+1 > gTauntsSettings.ubTauntSuspiciousChance)
				return;
			break;

		case TAUNT_GOT_HIT:
		case TAUNT_GOT_HIT_BLOODLOSS:
		case TAUNT_GOT_HIT_EXPLOSION:
		case TAUNT_GOT_HIT_FALLROOF:
		case TAUNT_GOT_HIT_GAS:
		case TAUNT_GOT_HIT_GUNFIRE:
		case TAUNT_GOT_HIT_HTH:
		case TAUNT_GOT_HIT_BLADE:
		case TAUNT_GOT_HIT_OBJECT:
		case TAUNT_GOT_HIT_STRUCTURE_EXPLOSION:
		case TAUNT_GOT_HIT_TENTACLES:
		case TAUNT_GOT_HIT_THROWING_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntGotHitChance )
				return;
			break;

		case TAUNT_GOT_BLINDED:
		case TAUNT_GOT_DEAFENED:
			if( Random(100)+1 > gTauntsSettings.ubTauntGotDeafenedBlindedChance)
				return;
			break;

		case TAUNT_GOT_ROBBED:
			if( Random(100)+1 > gTauntsSettings.ubTauntGotRobbedChance)
				return;
			break;

		case TAUNT_GOT_MISSED:
		case TAUNT_GOT_MISSED_GUNFIRE:
		case TAUNT_GOT_MISSED_BLADE:
		case TAUNT_GOT_MISSED_HTH:
		case TAUNT_GOT_MISSED_THROWING_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntGotMissedChance )
				return;
			break;

		case TAUNT_HIT:
		case TAUNT_HIT_GUNFIRE:
		case TAUNT_HIT_BLADE:
		case TAUNT_HIT_HTH:
		case TAUNT_HIT_THROWING_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntHitChance )
				return;
			break;

		case TAUNT_KILL:
		case TAUNT_KILL_GUNFIRE:
		case TAUNT_KILL_BLADE:
		case TAUNT_KILL_HTH:
		case TAUNT_KILL_THROWING_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntKillChance )
				return;
			break;

		case TAUNT_HEAD_POP:
			if( Random(100)+1 > gTauntsSettings.ubTauntHeadPopChance )
				return;
			break;

		case TAUNT_MISS:
		case TAUNT_MISS_GUNFIRE:
		case TAUNT_MISS_BLADE:
		case TAUNT_MISS_HTH:
		case TAUNT_MISS_THROWING_KNIFE:
			if( Random(100)+1 > gTauntsSettings.ubTauntMissChance )
				return;
			break;

		case TAUNT_OUT_OF_AMMO:
			if( Random(100)+1 > gTauntsSettings.ubTauntOutOfAmmoChance )
				return;
			break;
		case TAUNT_RELOAD:
			if( Random(100)+1 > gTauntsSettings.ubTauntReloadChance )
				return;
			break;

		case TAUNT_NOTICED_UNSEEN:
			if( Random(100)+1 > gTauntsSettings.ubTauntNoticedUnseenChance )
				return;
			break;
		case TAUNT_SAY_HI:
			if( Random(100)+1 > gTauntsSettings.ubTauntSayHiChance )
				return;
			break;
		case TAUNT_INFORM_ABOUT:
			if( Random(100)+1 > gTauntsSettings.ubTauntInformAboutChance )
				return;
			break;

		case TAUNT_RIPOSTE:
			if( Random(100)+1 > gTauntsSettings.ubRiposteChance)
				return;
			break;

		default:
			break;
	}
	
	StartEnemyTaunt( pCiv, iTauntType, pTarget );
}

// SANDRO - soldier taunts 
void StartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTarget )
{
	CHAR16	sTauntText[ 320 ];	
	CHAR16	gzTauntQuote[ 320 ];
	UINT16	iApplicableTaunts = 0;

	// Flugente: zombies don't talk
	if ( pCiv->IsZombie() )
		return;

	// sevenfm: play audio taunt if possible
	if (gTauntsSettings.fTauntVoice)
	{
		// try to play voice taunt, use noise if gTauntsSettings.fTauntMakeNoise is TRUE
		PlayVoiceTaunt(pCiv, iTauntType, pTarget);
		// block this enemy from taunting for a time being
		uiTauntFinishTimes[pCiv->ubID] = GetJA2Clock() + min(gTauntsSettings.sMaxDelay, max(gTauntsSettings.sMinDelay, FindDelayForString(L"You're the disease and I'm the cure!") + gTauntsSettings.sModDelay));
		return;
	}

	// anv: check all taunts, and remember those applicable
	for(UINT16 i=0; i<num_found_taunt; ++i)
	{
		// check if attitudes are ok
		switch( pCiv->aiData.bAttitude )
		{
			case CUNNINGAID:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_CUNNING_AID) )
					continue;
				break;
			case CUNNINGSOLO:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_CUNNING_SOLO) )
					continue;
				break;
			case BRAVEAID:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_BRAVE_AID) )
					continue;
			case BRAVESOLO:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_BRAVE_SOLO) )
					continue;
				break;
			case DEFENSIVE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_DEFENSIVE) )
					continue;
				break;
			case AGGRESSIVE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_A_AGGRESSIVE) )
					continue;
				break;
			default:
				break;
		}
		// check if situation is ok
		switch(iTauntType)
		{
			// actions
			case TAUNT_FIRE_GUN:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_FIRE_GUN) )
					continue;
				break;
			case TAUNT_FIRE_LAUNCHER:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_FIRE_LAUNCHER) )
					continue;
				break;
			case TAUNT_ATTACK_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_ATTACK_BLADE) )
					continue;
				break;
			case TAUNT_ATTACK_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_ATTACK_HTH) )
					continue;
				break;

			case TAUNT_THROW_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_THROW_KNIFE) )
					continue;
				break;
			case TAUNT_THROW_GRENADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_THROW_GRENADE) )
					continue;
				break;

			case TAUNT_OUT_OF_AMMO:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_OUT_OF_AMMO) )
					continue;
				break;
			case TAUNT_RELOAD:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_RELOAD) )
					continue;
				break;

			// AI routines
			case TAUNT_CHARGE_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_CHARGE_BLADE) )
					continue;
				break;
			case TAUNT_CHARGE_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_CHARGE_HTH) )
					continue;
				break;
			case TAUNT_STEAL:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_STEAL) )
					continue;
				break;
			case TAUNT_RUN_AWAY:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_RUN_AWAY) )
					continue;
				break;
			case TAUNT_SEEK_NOISE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_SEEK_NOISE) )
					continue;
				break;
			case TAUNT_ALERT:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_ALERT) )
					continue;
				break;
			case TAUNT_SUSPICIOUS:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_SUSPICIOUS) )
					continue;
				break;
			case TAUNT_NOTICED_UNSEEN:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_NOTICED_UNSEEN) )
					continue;
				break;
			case TAUNT_SAY_HI:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_SAY_HI) )
					continue;
				break;
			case TAUNT_INFORM_ABOUT:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_INFORM_ABOUT) )
					continue;
				break;

			// got_hit_xxx
			case TAUNT_GOT_HIT:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT) )
					continue;
				break;
			case TAUNT_GOT_HIT_GUNFIRE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_GUNFIRE) )
					continue;
				break;
			case TAUNT_GOT_HIT_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_BLADE) )
					continue;
				break;
			case TAUNT_GOT_HIT_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_HTH) )
					continue;
				break;
			case TAUNT_GOT_HIT_FALLROOF:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_FALLROOF) )
					continue;
				break;
			case TAUNT_GOT_HIT_BLOODLOSS:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_BLOODLOSS) )
					continue;
				break;
			case TAUNT_GOT_HIT_EXPLOSION:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_EXPLOSION) )
					continue;
				break;
			case TAUNT_GOT_HIT_GAS:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_GAS) )
					continue;
				break;
			case TAUNT_GOT_HIT_TENTACLES:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_TENTACLES) )
					continue;
				break;
			case TAUNT_GOT_HIT_STRUCTURE_EXPLOSION:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_STRUCTURE_EXPLOSION) )
					continue;
				break;
			case TAUNT_GOT_HIT_OBJECT:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT_OBJECT) )
					continue;
				break;
			case TAUNT_GOT_HIT_THROWING_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT) )
					continue;
				break;

			case TAUNT_GOT_DEAFENED:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_DEAFENED) )
					continue;
				break;
			case TAUNT_GOT_BLINDED:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_BLINDED) )
					continue;
				break;

			// got_missed_xxx
			case TAUNT_GOT_MISSED:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED) )
					continue;
				break;
			case TAUNT_GOT_MISSED_GUNFIRE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED_GUNFIRE) )
					continue;
				break;
			case TAUNT_GOT_MISSED_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED_BLADE) )
					continue;
				break;
			case TAUNT_GOT_MISSED_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED_HTH) )
					continue;
				break;
			case TAUNT_GOT_MISSED_THROWING_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED_THROWING_KNIFE) )
					continue;
				break;

			// hit_xxx
			case TAUNT_HIT:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HIT) )
					continue;
				break;
			case TAUNT_HIT_GUNFIRE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HIT_GUNFIRE) )
					continue;
				break;
			case TAUNT_HIT_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HIT_BLADE) )
					continue;
				break;
			case TAUNT_HIT_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HIT_HTH) )
					continue;
				break;
			case TAUNT_HIT_THROWING_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HIT_THROWING_KNIFE) )
					continue;
				break;

			// kill_xxx
			case TAUNT_KILL:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_KILL) )
					continue;
				break;
			case TAUNT_KILL_GUNFIRE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_KILL_GUNFIRE) )
					continue;
				break;
			case TAUNT_KILL_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_KILL_BLADE) )
					continue;
				break;
			case TAUNT_KILL_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_KILL_HTH) )
					continue;
				break;
			case TAUNT_KILL_THROWING_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_KILL_THROWING_KNIFE) )
					continue;
				break;
			case TAUNT_HEAD_POP:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_HEAD_POP) )
					continue;
				break;

			// miss_xxx
			case TAUNT_MISS:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_MISS) )
					continue;
				break;
			case TAUNT_MISS_GUNFIRE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_MISS_GUNFIRE) )
					continue;
				break;
			case TAUNT_MISS_BLADE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_MISS_BLADE) )
					continue;
				break;
			case TAUNT_MISS_HTH:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_MISS_HTH) )
					continue;
				break;
			case TAUNT_MISS_THROWING_KNIFE:
				if( !(zTaunt[ i ].uiFlags & TAUNT_S_MISS_THROWING_KNIFE) )
					continue;
				break;

			// ripostes to merc quotes
			case TAUNT_RIPOSTE:
				if( !(gTacticalStatus.ubLastQuoteSaid == zTaunt[ i ].value[TAUNT_RIPOSTE_QUOTE]) )
					continue;
				break;

			default:
				continue;
				break;
		}

		// class and predefined profiles
		switch( pCiv->ubSoldierClass )
		{
			case SOLDIER_CLASS_ADMINISTRATOR:
			case SOLDIER_CLASS_BANDIT:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ADMIN) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] == pCiv->usSoldierProfile ) )
					continue;
				break;
			case SOLDIER_CLASS_ARMY:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ARMY) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) )
					continue;
				break;
			case SOLDIER_CLASS_ELITE:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_ELITE) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_ELITE] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ELITE] == pCiv->usSoldierProfile ) )
					continue;
				break;
			case SOLDIER_CLASS_GREEN_MILITIA:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_GREEN) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_GREEN] != -1 ) && !( zTaunt[ i ].value[TAUNT_PROFILE_GREEN] == pCiv->usSoldierProfile ) )
					continue;
				break;
			case SOLDIER_CLASS_REG_MILITIA:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_REGULAR) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) )
					continue;
				break;
			case SOLDIER_CLASS_ELITE_MILITIA:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_C_VETERAN) )
					continue;
				if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) )
					continue;
				break;
			default:
				return;
				break;
		}

		// gender
		switch( pCiv->ubBodyType )
		{
			case REGMALE:
			case BIGMALE:
			case STOCKYMALE:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_G_MALE) )
					continue;
				break;
			case REGFEMALE:
				if( !(zTaunt[ i ].uiFlags2 & TAUNT_G_FEMALE) )
					continue;
				break;
			default:
				return;
				break;
		}

		// energy, health
		if( zTaunt[ i ].value[TAUNT_ENERGY_GT] != -1 )
		{
			if( pCiv->bBreath <= zTaunt[ i ].value[TAUNT_ENERGY_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_ENERGY_LT] != -1 )
		{
			if( pCiv->bBreath >= zTaunt[ i ].value[TAUNT_ENERGY_LT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_ENERGY_MAX_GT] != -1 )
		{
			if( pCiv->bBreathMax <= zTaunt[ i ].value[TAUNT_ENERGY_MAX_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_ENERGY_MAX_LT] != -1 )
		{
			if( pCiv->bBreathMax >= zTaunt[ i ].value[TAUNT_ENERGY_MAX_LT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_HEALTH_GT] != -1 )
		{
			if( pCiv->stats.bLife <= zTaunt[ i ].value[TAUNT_HEALTH_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_HEALTH_GT] != -1 )
		{
			if( pCiv->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_HEALTH_LT] != -1 )
		{
			if( pCiv->stats.bLife >= zTaunt[ i ].value[TAUNT_HEALTH_LT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_HEALTH_MAX_GT] != -1 )
		{
			if( pCiv->stats.bLifeMax <= zTaunt[ i ].value[TAUNT_HEALTH_MAX_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_HEALTH_MAX_LT] != -1 )
		{
			if( pCiv->stats.bLifeMax >= zTaunt[ i ].value[TAUNT_HEALTH_MAX_LT] )
				continue;
		}
		// morale
		if( zTaunt[ i ].value[TAUNT_MORALE_GT] != -1 )
		{
			if( pCiv->aiData.bMorale <= zTaunt[ i ].value[TAUNT_MORALE_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_MORALE_LT] != -1 )
		{
			if( pCiv->aiData.bMorale >= zTaunt[ i ].value[TAUNT_MORALE_LT] )
				continue;
		}
		// experience
		if( zTaunt[ i ].value[TAUNT_EXP_LEVEL_GT] != -1 )
		{
			if( pCiv->stats.bExpLevel <= zTaunt[ i ].value[TAUNT_EXP_LEVEL_GT] )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_EXP_LEVEL_LT] != -1 )
		{
			if( pCiv->stats.bExpLevel >= zTaunt[ i ].value[TAUNT_EXP_LEVEL_LT] )
				continue;
		}

		// game progress
		if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] != -1 )
		{
			if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] >= CurrentPlayerProgressPercentage() )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_PROGRESS_LT] != -1 )
		{
			if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] <= CurrentPlayerProgressPercentage() )
				continue;
		}

		// facts
		if( zTaunt[ i ].value[TAUNT_FACT_TRUE] != -1 )
		{
			if( gubFact[ zTaunt[ i ].value[TAUNT_FACT_TRUE] ] != TRUE )
				continue;
		}
		if( zTaunt[ i ].value[TAUNT_FACT_FALSE] != -1 )
		{
			if( gubFact[ zTaunt[ i ].value[TAUNT_FACT_FALSE] ] != FALSE )
				continue;
		}

		// target limitations
		if( pTarget != NULL )
		{
			// target should be zombie
			if( zTaunt[ i ].uiFlags2 & TAUNT_T_ZOMBIE )
			{
			// anv: moved ifdef - if zombies are off, we want to skip any taunts with TAUNT_T_ZOMBIE flag
				if( !pTarget->IsZombie() )
					continue;
			}

			// target merc profile
			if( zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] != -1 )
			{
				if( pTarget->ubProfile != zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] )
					continue;
			}
			// target type
			if( zTaunt[ i ].value[TAUNT_TARGET_TYPE] != -1 )
			{
				if( pTarget->ubProfile != zTaunt[ i ].value[TAUNT_TARGET_TYPE] )
					continue;
			}
			// target gender
			switch( pTarget->ubBodyType )
			{
				case REGMALE:
				case BIGMALE:
				case STOCKYMALE:
					if( !(zTaunt[ i ].uiFlags2 & TAUNT_T_MALE) )
						continue;
					break;
				case REGFEMALE:
					if( !(zTaunt[ i ].uiFlags2 & TAUNT_T_FEMALE) )
						continue;
					break;
				default:
					return;
					break;
			}
			// target appearance
			if( zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] != -1 )
			{
				// check if pTarget has his own predefined profile (ubProfile = 200 for generated characters)
				if( pTarget->ubProfile != NO_PROFILE )
				{
					if( gMercProfiles[pTarget->ubProfile].bAppearance != zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] )
						continue;
				}
				else
					continue;
			}

			// target type
			switch( zTaunt[ i ].value[TAUNT_TARGET_TYPE] )
			{
				case 0:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER )
						continue;
					break;
				case 1:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
						continue;
					break;
				case 2:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__MERC )
						continue;
					break;
				case 3:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__NPC )
						continue;
					break;
				case 4:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__EPC )
						continue;
					break;
				case 5:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__NPC_WITH_UNEXTENDABLE_CONTRACT )
						continue;
					break;
				case 6:
					if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__VEHICLE )
						continue;
					break;
				default:
					break;
			}

			// target energy, health
			if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] != -1 )
			{
				if( pTarget->bBreath <= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] != -1 )
			{
				if( pTarget->bBreath >= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] != -1 )
			{
				if( pTarget->bBreathMax <= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] != -1 )
			{
				if( pTarget->bBreathMax >= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 )
			{
				if( pTarget->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 )
			{
				if( pTarget->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] != -1 )
			{
				if( pTarget->stats.bLife >= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] != -1 )
			{
				if( pTarget->stats.bLifeMax <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] != -1 )
			{
				if( pTarget->stats.bLifeMax >= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] )
					continue;
			}
			// morale
			if( zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] != -1 )
			{
				if( pTarget->aiData.bMorale <= zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] != -1 )
			{
				if( pTarget->aiData.bMorale >= zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] )
					continue;
			}
			// experience
			if( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] != -1 )
			{
				if( pTarget->stats.bExpLevel <= zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] )
					continue;
			}
			if( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] != -1 )
			{
				if( pTarget->stats.bExpLevel >= zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] )
					continue;
			}
		}
		else // pTarget==NULL
		{
			if( ( zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] != -1 ) ||
				( zTaunt[ i ].value[TAUNT_TARGET_TYPE] != -1 ) || 
				( zTaunt[ i ].uiFlags2 & TAUNT_T_ZOMBIE ) )
					continue;

		}
		// everything ok, current taunt is applicable, remember it
		zApplicableTaunts[iApplicableTaunts] = zTaunt[i];
		iApplicableTaunts++;
		if(iApplicableTaunts >= MAX_APPLICABLE_TAUNTS)
			continue;
	}
	// are there any applicable taunts?
	if( iApplicableTaunts > 0 )
	{
		// use random one
		// use censored version if setting is set
		UINT16 iChosenTaunt = Random(iApplicableTaunts); 
		if( gTauntsSettings.fTauntCensoredMode == TRUE && zApplicableTaunts[ iChosenTaunt ].szCensoredText[0] != 0 )
		{
			swprintf( sTauntText, zApplicableTaunts[ iChosenTaunt ].szCensoredText );
		}
		else
		{
			swprintf( sTauntText, zApplicableTaunts[ iChosenTaunt ].szText );
		}

		swprintf( gzTauntQuote, L"\"%s\"", sTauntText );

		// block this enemy from taunting for a time being
		uiTauntFinishTimes[pCiv->ubID] = GetJA2Clock() + min( gTauntsSettings.sMaxDelay , max( gTauntsSettings.sMinDelay, FindDelayForString( gzTauntQuote ) + gTauntsSettings.sModDelay ) ); 

		if( gTauntsSettings.fTauntMakeNoise == TRUE )
			MakeNoise( pCiv->ubID, pCiv->sGridNo, pCiv->pathing.bLevel, pCiv->bOverTerrainType, (UINT8)gTauntsSettings.sVolume, NOISE_VOICE, gzTauntQuote );
		else
		{
			if(gTauntsSettings.fTauntShowPopupBox == TRUE)
			{	
				if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowPopupBox == TRUE )
				{
					ShowTauntPopupBox( pCiv, gzTauntQuote );
				}
			}
			if(gTauntsSettings.fTauntShowInLog == TRUE)
			{
				if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowInLog == TRUE )
				{
					ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pCiv->GetName(), gzTauntQuote );
				}
			}
		}
	}
	else
	{
		return;
	}

}

void ShowTauntPopupBox( SOLDIERTYPE *pCiv, STR16 gzTauntQuote )
{
	INT16	sX, sY;
	INT16	sScreenX, sScreenY;
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	// stop if other civ quote is already being shown 
	if( gCivQuoteData.bActive == TRUE )
	{
		return;
	}

	// Determine location...
	// Get location of civ on screen.....
	GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY );
	sX = sScreenX;
	// Flugente: have the box appear a bit above the soldier. Otherwise it will obstruct us from aiming at him, which is annoying if it happens very often
	sY = sScreenY - 40;

	// Create video oeverlay....
	memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) );

	// Prepare text box
	gCivQuoteData.iDialogueBox = PrepareMercPopupBox( gCivQuoteData.iDialogueBox , BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gzTauntQuote, DIALOGUE_DEFAULT_WIDTH, 0, 0, 0, &gusCivQuoteBoxWidth, &gusCivQuoteBoxHeight );

	// OK, find center for box......
	sX = sX - ( gusCivQuoteBoxWidth / 2 );
	sY = sY - ( gusCivQuoteBoxHeight / 2 );

	// OK, limit to screen......
	{
		if ( sX < 0 )
		{
			sX = 0;
		}

		// CHECK FOR LEFT/RIGHT
		if ( ( sX + gusCivQuoteBoxWidth ) > SCREEN_WIDTH )
		{
			sX = SCREEN_WIDTH - gusCivQuoteBoxWidth;
		}

		// Now check for top
		if ( sY < gsVIEWPORT_WINDOW_START_Y )
		{
			sY = gsVIEWPORT_WINDOW_START_Y;
		}

		// Check for bottom
		if ( ( sY + gusCivQuoteBoxHeight ) > (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT))
		{
			sY = (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT) - gusCivQuoteBoxHeight;
		}
	}

	VideoOverlayDesc.sLeft			= sX;
	VideoOverlayDesc.sTop				= sY;
	VideoOverlayDesc.sRight			= VideoOverlayDesc.sLeft + gusCivQuoteBoxWidth;
	VideoOverlayDesc.sBottom		= VideoOverlayDesc.sTop + gusCivQuoteBoxHeight;
	VideoOverlayDesc.sX					= VideoOverlayDesc.sLeft;
	VideoOverlayDesc.sY					= VideoOverlayDesc.sTop;
	VideoOverlayDesc.BltCallback = RenderCivQuoteBoxOverlay;

	gCivQuoteData.iVideoOverlay =	RegisterVideoOverlay( 0, &VideoOverlayDesc );

	//Define main region
	MSYS_DefineRegion( &(gCivQuoteData.MouseRegion), VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop,	VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST,
						CURSOR_NORMAL, MSYS_NO_CALLBACK, QuoteOverlayClickCallback );
	// Add region
	MSYS_AddRegion( &(gCivQuoteData.MouseRegion) );

	gCivQuoteData.bActive = TRUE;

	gCivQuoteData.uiTimeOfCreation = GetJA2Clock( );
	
	gCivQuoteData.uiDelayTime = min( gTauntsSettings.sMaxDelay , max( gTauntsSettings.sMinDelay, FindDelayForString( gzTauntQuote ) + gTauntsSettings.sModDelay ) );

	gCivQuoteData.pCiv = pCiv;
}

BOOLEAN CivQuoteActive()
{
	return gCivQuoteData.bActive;
}

STR VoiceTauntFileName[] =
{
	"FIRE_GUN",
	"FIRE_LAUNCHER",
	"ATTACK_BLADE",
	"ATTACK_HTH",

	"THROW_KNIFE",
	"THROW_GRENADE",

	"OUT_OF_AMMO",
	"RELOAD",

	"STEAL",

	// AI routines
	"CHARGE_BLADE",
	"CHARGE_HTH",
	"RUN_AWAY",
	"SEEK_NOISE",
	"ALERT",
	"SUSPICIOUS",
	"NOTICED_UNSEEN",
	"SAY_HI",
	"INFORM_ABOUT",

	// got_hit_xxx
	"GOT_HIT",
	"GOT_HIT_GUNFIRE",
	"GOT_HIT_BLADE",
	"GOT_HIT_HTH",
	"GOT_HIT_FALLROOF",
	"GOT_HIT_BLOODLOSS",
	"GOT_HIT_EXPLOSION",
	"GOT_HIT_GAS",
	"GOT_HIT_TENTACLES",
	"GOT_HIT_STRUCTURE_EXPLOSION",
	"GOT_HIT_OBJECT",
	"GOT_HIT_THROWING_KNIFE",

	"GOT_DEAFENED",
	"GOT_BLINDED",

	"GOT_ROBBED",

	// got_missed_xxx
	"GOT_MISSED",
	"GOT_MISSED_GUNFIRE",
	"GOT_MISSED_BLADE",
	"GOT_MISSED_HTH",
	"GOT_MISSED_THROWING_KNIFE",

	// hit_xxx
	"HIT",
	"HIT_GUNFIRE",
	"HIT_BLADE",
	"HIT_HTH",
	"HIT_EXPLOSION",
	"HIT_THROWING_KNIFE",

	// kill_xxx
	"KILL",
	"KILL_GUNFIRE",
	"KILL_BLADE",
	"KILL_HTH",
	"KILL_THROWING_KNIFE",
	"HEAD_POP",

	// miss_xxx
	"MISS",
	"MISS_GUNFIRE",
	"TAUNT_MISS_BLADE",
	"MISS_HTH",
	"MISS_THROWING_KNIFE",

	// ripostes to merc quotes
	"RIPOSTE"
};

// sevenfm: voice taunts
BOOLEAN PlayVoiceTaunt(SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTarget)
{
	CHAR8 filename[1024];
	CHAR8 filenameExtra[1024];
	CHAR16 noise[1024];
	CHAR8 buf[1024];
	INT32 iRandomTaunt = 0;
	UINT8 ubExtraTaunts = 0;

	CHECKF(pCiv);

	if (!gTauntsSettings.fTauntVoice)
	{
		return FALSE;
	}

	// show some information about taunts
	if (gTauntsSettings.fTauntVoiceShowInfo)
		ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Soldier [%d] TauntType %d", pCiv->ubID, iTauntType);

	// cannot taunt when dead or collapsed
	if (pCiv->stats.bLife < OKLIFE || pCiv->bCollapsed || pCiv->bBreathCollapsed)
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
			ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Bad soldier state (dying or collapsed)");

		return FALSE;
	}

	if (iTauntType < TAUNT_FIRE_GUN || iTauntType > TAUNT_RIPOSTE)
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
			ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Bad taunt");

		return FALSE;
	}

	strcpy(filename, "VoiceTaunts");

	// prepare team
	if (pCiv->bTeam == ENEMY_TEAM)
	{
		strcat(filename, "\\Army\\");
	}
	else if (pCiv->bTeam == MILITIA_TEAM)
	{
		strcat(filename, "\\Militia\\");
	}
	else if (pCiv->bTeam == CIV_TEAM && pCiv->ubCivilianGroup != NON_CIV_GROUP)
	{
		sprintf(buf, "\\Civgroup%d\\", pCiv->ubCivilianGroup);
		strcat(filename, buf);
	}
	else
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
			ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Bad soldier team");

		return FALSE;
	}

	// prepare gender
	if (pCiv->ubBodyType <= STOCKYMALE)
	{
		strcat(filename, "Male\\");
	}
	else if (pCiv->ubBodyType == REGFEMALE)
	{
		strcat(filename, "Female\\");
	}
	else
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
			ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Incorrect bodytype");

		return FALSE;
	}

	// count possible voices
	UINT8 ubVoiceCount;
	for (ubVoiceCount = 1; ubVoiceCount < 100; ubVoiceCount++)
	{
		sprintf(buf, "%s%02d", filename, ubVoiceCount);
		strcat(buf, "\\alert.ogg");		

		// check that folder exists
		if (!FileExists(buf))
		{
			if (gTauntsSettings.fTauntVoiceShowInfo)
			{
				mbstowcs(noise, buf, strlen(buf) + 1);
				ScreenMsg(FONT_GREEN, MSG_INTERFACE, noise);
			}

			break;
		}
	}
	// find last good number
	ubVoiceCount--;

	if (ubVoiceCount < 1)
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
			ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"Could not find any voice folder");

		return FALSE;
	}

	if (gTauntsSettings.fTauntVoiceShowInfo)
		ScreenMsg(FONT_MCOLOR_LTGREEN, MSG_INTERFACE, L"found %d voices", ubVoiceCount);

	// prepare voice folder name
	sprintf(buf, "%02d", 1 + pCiv->ubID % ubVoiceCount);
	strcat(filename, buf);
	strcat(filename, "\\");

	// prepare base taunt filename
	strcat(filename, VoiceTauntFileName[iTauntType]);

	// count possible extra filenames
	ubExtraTaunts = 0;
	for (UINT8 ubCheck = 1; ubCheck <= 10; ubCheck++)
	{
		// check extra taunt file
		strcpy(filenameExtra, filename);
		sprintf(buf, " %d", ubExtraTaunts);
		strcat(filenameExtra, buf);
		strcat(filenameExtra, ".ogg");
		if (!FileExists(filenameExtra))
		{
			break;
		}
		ubExtraTaunts = ubCheck;
	}

	// possibly use extra taunt
	iRandomTaunt = Random(ubExtraTaunts + 1);
	if (iRandomTaunt > 0)
	{
		sprintf(buf, " %d", iRandomTaunt);
		strcat(filename, buf);
	}

	strcat(filename, ".ogg");

	// log taunt file names
	if (gTauntsSettings.fTauntVoiceShowInfo)
	{
		FILE	*OutFile;
		if ((OutFile = fopen("VoiceTauntLog.txt", "a+t")) != NULL)
		{
			fprintf(OutFile, "Soldier [%d] TauntType %d %s\n",
				pCiv->ubID,
				iTauntType,
				filename);
			fclose(OutFile);
		}

		// show some information about taunts	
		mbstowcs(noise, filename, strlen(filename) + 1);
		ScreenMsg(FONT_GREEN, MSG_INTERFACE, noise);
	}

	// check that taunt file exists
	if (!FileExists(filename))
	{
		if (gTauntsSettings.fTauntVoiceShowInfo)
		{
			mbstowcs(noise, filename, strlen(filename) + 1);
			ScreenMsg(FONT_GREEN, MSG_INTERFACE, noise);
			ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Taunt: no file %s", noise);
		}

		return FALSE;
	}

	if (gTauntsSettings.fTauntMakeNoise == TRUE)
	{
		// convert char to char16
		mbstowcs(noise, filename, strlen(filename) + 1);
		// use filename as taunt text, play sound later
		MakeNoise(pCiv->ubID, pCiv->sGridNo, pCiv->pathing.bLevel, pCiv->bOverTerrainType, (UINT8)gTauntsSettings.sVolume, NOISE_VOICE, noise);
	}
	else
	{
		// play voice taunt
		if (PlayJA2SampleFromFile(filename, RATE_11025, SoundVolume(HIGHVOLUME, pCiv->sGridNo), 1, SoundDir(pCiv->sGridNo)) == SOUND_ERROR)
		{
			if (gTauntsSettings.fTauntVoiceShowInfo)
				ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Failed to play taunt");

			return FALSE;
		}
	}

	return TRUE;
}