#ifdef PRECOMPILEDHEADERS
	#include "Utils All.h"
	#include "Game Clock.h"
#else
	#include "sgp.h"
	#include "font.h"
	#include "types.h"
	#include "Font Control.h"
	#include "message.h"
	#include "memory.h"
	#include "mbstring.h"
	#include "Timer Control.h"
	#include "render dirty.h"
	#include "renderworld.h"
	#include "Mutex Manager.h"
	#include "local.h"
	#include "interface.h"
	#include "Map Screen Interface Bottom.h"
	#include "WordWrap.h"
	#include "Sound Control.h"
	#include "Soundman.h"
	#include "BuildDefines.h"
	#include "Dialogue Control.h"
	#include <stdio.h>
	#include "Game Clock.h"
	#include "GameSettings.h"
	#include "sgp_logger.h"
#endif

typedef struct
{
	UINT32	uiFont;
	UINT32	uiTimeOfLastUpdate;
	UINT32	uiFlags;
	UINT32	uiPadding[ 3 ];
	UINT16	usColor;
	BOOLEAN fBeginningOfNewString;

} StringSaveStruct;


// WANNE: These lines defines the message position in tactical screen.
#define MAX_LINE_COUNT 6
#define X_START 2
#define MAX_AGE 10000
// HEADROCK HAM 3.6: Turned into a variable.
UINT16 LINE_WIDTH;
UINT16 MAP_LINE_WIDTH;
#define WIDTH_BETWEEN_NEW_STRINGS 5

#define BETAVERSION_COLOR FONT_ORANGE
#define TESTVERSION_COLOR FONT_GREEN
#define DEBUG_COLOR FONT_RED
#define DIALOGUE_COLOR FONT_WHITE
#define INTERFACE_COLOR FONT_YELLOW

#define MAP_SCREEN_MESSAGE_FONT TINYFONT1

UINT8 gubStartOfMapScreenMessageList = 0;
UINT8 gubEndOfMapScreenMessageList = 0;

// index of the current string we are looking at
UINT8 gubCurrentMapMessageString = 0;

// temp position for display of marker
//UINT8 ubTempPosition = 0;

// are allowed to beep on message scroll?
BOOLEAN fOkToBeepNewMessage = TRUE;


// HEADROCK HAM 3.6: Increased size of absolute MAXIMUM possible displayed messages to 36 (the most that can be seen
// in a 1024x768 display. There's now an INI setting that allows displaying up to 36 in the tactical screen. 
// Strategic screen not yet changed. Please note that there are also fail-safes that make sure that the actual
// maximum isn't more that can be displayed given the resolution being used.
//static ScrollStringStPtr	gpDisplayList[ MAX_LINE_COUNT ];
static ScrollStringStPtr	gpDisplayList[ 36 ];
static ScrollStringStPtr gMapScreenMessageList[ 256 ];
extern ScrollStringStPtr pStringS=NULL;

// first time adding any message to the message dialogue system
BOOLEAN fFirstTimeInMessageSystem = TRUE;
BOOLEAN fDisableJustForIan = FALSE;

BOOLEAN fScrollMessagesHidden = FALSE;
UINT32 uiStartOfPauseTime = 0;

// test extern functions
BOOLEAN RestoreExternBackgroundRectGivenID( INT32 iBack );
extern VIDEO_OVERLAY	gVideoOverlays[];

extern UINT16 gusSubtitleBoxWidth;
extern BOOLEAN gfFacePanelActive;

// region created and due to last quote box
extern BOOLEAN fTextBoxMouseRegionCreated;
extern BOOLEAN fDialogueBoxDueToLastMessage;

// OJW - 20090426
INT16 gTacticalMsgFilterPriority = -1; // filter for writing messages to the tactical log



// prototypes

BOOLEAN CreateStringVideoOverlay( ScrollStringStPtr pStringSt, UINT16 usX, UINT16 usY );
void SetStringVideoOverlayPosition(	ScrollStringStPtr pStringSt, UINT16 usX, UINT16 usY );

void BlitString( VIDEO_OVERLAY *pBlitter );
void RemoveStringVideoOverlay( ScrollStringStPtr pStringSt );
void EnableStringVideoOverlay( ScrollStringStPtr pStringSt, BOOLEAN fEnable );

ScrollStringStPtr GetNextString(ScrollStringStPtr pStringSt);
ScrollStringStPtr GetPrevString(ScrollStringStPtr pStringSt);
void AlignString(ScrollStringStPtr pPermStringSt);

INT32 GetMessageQueueSize( void );

ScrollStringStPtr AddString(STR16 string, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority );
void SetString(ScrollStringStPtr pStringSt, STR16 String);

void SetStringPosition(ScrollStringStPtr pStringSt, UINT16 x, UINT16 y);
void SetStringColor(ScrollStringStPtr pStringSt, UINT16 color);
ScrollStringStPtr SetStringNext(ScrollStringStPtr pStringSt, ScrollStringStPtr pNext);
ScrollStringStPtr SetStringPrev(ScrollStringStPtr pStringSt, ScrollStringStPtr pPrev);
void AddStringToMapScreenMessageList( STR16 pString, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority );


// clear up a linked list of wrapped strings
void ClearWrappedStrings( WRAPPED_STRING *pStringWrapperHead );
void WriteMessageToFile( const STR16 pString );

// tactical screen message
void TacticalScreenMsg( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ... );

// play bee when new message is added
void PlayNewMessageSound( void );

void HandleLastQuotePopUpTimer( void );

// HEADROCK HAM 3.6: External boolean tells game to re-render map screen message log panel.
extern BOOLEAN fMapScreenBottomDirty;

// functions


void SetStringFont(ScrollStringStPtr pStringSt, UINT32 uiFont)
{
	pStringSt->uiFont=uiFont;
}

UINT32 GetStringFont(ScrollStringStPtr pStringSt)
{
	return pStringSt->uiFont;
}


ScrollStringStPtr AddString(STR16 pString, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority )
{
	// add a new string to the list of strings
	ScrollStringStPtr pStringSt=NULL;
	pStringSt= (ScrollStringStPtr)MemAlloc(sizeof(ScrollStringSt));

	SetString(pStringSt, pString);
	SetStringColor(pStringSt, usColor);
	pStringSt->uiFont = uiFont;
	pStringSt->fBeginningOfNewString = fStartOfNewString;
	pStringSt->uiFlags = ubPriority;

	SetStringNext(pStringSt, NULL);
	SetStringPrev(pStringSt, NULL);
	pStringSt->iVideoOverlay=-1;

	// now add string to map screen strings
	//AddStringToMapScreenMessageList(pString, usColor, uiFont, fStartOfNewString, ubPriority );

	return (pStringSt);
}


void SetString(ScrollStringStPtr pStringSt, STR16 pString)
{
	// ARM: Why x2 + 4 ???
	pStringSt->pString16=(STR16)MemAlloc((wcslen(pString)+2)*sizeof(CHAR16));
	wcsncpy(pStringSt->pString16, pString, wcslen(pString));
	pStringSt->pString16[wcslen(pString)]=0;
}


void SetStringPosition(ScrollStringStPtr pStringSt, UINT16 usX, UINT16 usY)
{
	SetStringVideoOverlayPosition( pStringSt, usX, usY );
}



void SetStringColor(ScrollStringStPtr pStringSt, UINT16 usColor)
{
	pStringSt->usColor=usColor;
}

ScrollStringStPtr GetNextString(ScrollStringStPtr pStringSt)
{
	// returns pointer to next string line
	if (pStringSt==NULL)
		return NULL;
	else
		return pStringSt->pNext;
}


ScrollStringStPtr GetPrevString(ScrollStringStPtr pStringSt)
{
	// returns pointer to previous string line
	if (pStringSt==NULL)
		return NULL;
	else
		return pStringSt->pPrev;
}


ScrollStringStPtr SetStringNext(ScrollStringStPtr pStringSt, ScrollStringStPtr pNext)
{
	pStringSt->pNext=pNext;
	return pStringSt;
}


ScrollStringStPtr SetStringPrev(ScrollStringStPtr pStringSt, ScrollStringStPtr pPrev)
{
	pStringSt->pPrev=pPrev;
	return pStringSt;
}


BOOLEAN CreateStringVideoOverlay( ScrollStringStPtr pStringSt, UINT16 usX, UINT16 usY )
{
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	// WDS - bug fix: VideoOverlayDesc must be initialized! - 07/16/2007
	memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) );

	// SET VIDEO OVERLAY
	VideoOverlayDesc.sLeft			= usX;
	VideoOverlayDesc.sTop				= usY;
	VideoOverlayDesc.uiFontID	= pStringSt->uiFont;
	VideoOverlayDesc.ubFontBack	= FONT_MCOLOR_BLACK ;
	VideoOverlayDesc.ubFontFore	= (unsigned char)pStringSt->usColor;
	VideoOverlayDesc.sX					= VideoOverlayDesc.sLeft;
	VideoOverlayDesc.sY					= VideoOverlayDesc.sTop;
	swprintf( VideoOverlayDesc.pzText, pStringSt->pString16 );
	VideoOverlayDesc.BltCallback = BlitString;
	pStringSt->iVideoOverlay =	RegisterVideoOverlay( ( VOVERLAY_DIRTYBYTEXT ), &VideoOverlayDesc );

	if ( pStringSt->iVideoOverlay == -1 )
	{
		return( FALSE );
	}

	return( TRUE );
}


void RemoveStringVideoOverlay( ScrollStringStPtr pStringSt )
{

	// error check, remove one not there
	if( pStringSt->iVideoOverlay == -1 )
	{
		return;
	}


	RemoveVideoOverlay( pStringSt->iVideoOverlay );
	pStringSt->iVideoOverlay=-1;
}


void SetStringVideoOverlayPosition(	ScrollStringStPtr pStringSt, UINT16 usX, UINT16 usY )
{
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) );

	// Donot update if not allocated!
	if ( pStringSt->iVideoOverlay != -1 )
	{
		VideoOverlayDesc.uiFlags	= VOVERLAY_DESC_POSITION;
		VideoOverlayDesc.sLeft			= usX;
		VideoOverlayDesc.sTop				= usY;
		VideoOverlayDesc.sX					= VideoOverlayDesc.sLeft;
		VideoOverlayDesc.sY					= VideoOverlayDesc.sTop;
		UpdateVideoOverlay( &VideoOverlayDesc, pStringSt->iVideoOverlay, FALSE );
	}
}


void BlitString( VIDEO_OVERLAY *pBlitter )
{
	UINT8	*pDestBuf;
	UINT32 uiDestPitchBYTES;

	//gprintfdirty(pBlitter->sX,pBlitter->sY, pBlitter->zText);
	//RestoreExternBackgroundRect(pBlitter->sX,pBlitter->sY, pBlitter->sX+StringPixLength(pBlitter->zText,pBlitter->uiFontID ), pBlitter->sY+GetFontHeight(pBlitter->uiFontID ));

	if( fScrollMessagesHidden == TRUE )
	{
		return;
	}


	pDestBuf = LockVideoSurface( pBlitter->uiDestBuff, &uiDestPitchBYTES);
	SetFont(pBlitter->uiFontID);

	SetFontBackground( pBlitter->ubFontBack );
	SetFontForeground( pBlitter->ubFontFore );
	SetFontShadow( DEFAULT_SHADOW );
	mprintf_buffer_coded( pDestBuf, uiDestPitchBYTES, pBlitter->uiFontID, pBlitter->sX, pBlitter->sY, pBlitter->zText );
	UnLockVideoSurface( pBlitter->uiDestBuff );

}


void EnableStringVideoOverlay( ScrollStringStPtr pStringSt, BOOLEAN fEnable )
{
	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) );

	if ( pStringSt->iVideoOverlay != -1 )
	{
		VideoOverlayDesc.fDisabled	= !fEnable;
		VideoOverlayDesc.uiFlags	= VOVERLAY_DESC_DISABLED;
		UpdateVideoOverlay( &VideoOverlayDesc, pStringSt->iVideoOverlay, FALSE );
	}
}


void ClearDisplayedListOfTacticalStrings( void )
{
	// this function will go through list of display strings and clear them all out
	UINT32 cnt;

	// HEADROCK HAM 3.6: Number of messages to display now depends on external options.
	//for ( cnt = 0; cnt < MAX_LINE_COUNT; cnt++ )
	for ( cnt = 0; cnt < gGameExternalOptions.ubMaxMessagesTactical; cnt++ )
	{
		if ( gpDisplayList[ cnt ] != NULL )
		{
			// CHECK IF WE HAVE AGED

			// Remove our sorry ass
			RemoveStringVideoOverlay( gpDisplayList[ cnt ] );
			MemFree( gpDisplayList[ cnt ]->pString16);
			MemFree( gpDisplayList[ cnt ] );

			// Free slot
			gpDisplayList[ cnt ] = NULL;
		}
	}

	return;
}



void ScrollString( )
{
	UINT32 suiTimer=0;
	UINT32 cnt;
	INT32 iNumberOfNewStrings = 0; // the count of new strings, so we can update position by WIDTH_BETWEEN_NEW_STRINGS pixels in the y
	INT32 iNumberOfMessagesOnQueue = 0;
	INT32 iMaxAge = 0;
	BOOLEAN fDitchLastMessage = FALSE;

	INT16 iMsgYStart = ((UsingNewInventorySystem() == false)) ? SCREEN_HEIGHT - 150 : SCREEN_HEIGHT - 210;


	// UPDATE TIMER
	suiTimer=GetJA2Clock();

	// might have pop up text timer
	HandleLastQuotePopUpTimer( );

	if( guiCurrentScreen == MAP_SCREEN )
	{
		return;
	}

	// HEADROCK HAM 3.6: This replaces the static variable MAX_LINE_COUNT for all tactical displays.
	UINT8 ubLines = gGameExternalOptions.ubMaxMessagesTactical;

	// DONOT UPDATE IF WE ARE SCROLLING!
	if ( gfScrollPending || gfScrollInertia )
	{
		return;
	}

	// messages hidden
	if( fScrollMessagesHidden )
	{
		return;
	}

	iNumberOfMessagesOnQueue = GetMessageQueueSize( );
	iMaxAge =	MAX_AGE;

	if( ( iNumberOfMessagesOnQueue > 0 )&&( gpDisplayList[ ubLines - 1 ] != NULL) )
	{
		fDitchLastMessage = TRUE;
	}
	else
	{
		fDitchLastMessage = FALSE;

	}


	if( ( iNumberOfMessagesOnQueue * 1000 ) >= iMaxAge )
	{
		iNumberOfMessagesOnQueue = ( iMaxAge / 1000 );
	}
	else if( iNumberOfMessagesOnQueue < 0 )
	{
		iNumberOfMessagesOnQueue = 0;
	}

	//AGE
	for ( cnt = 0; cnt < ubLines; cnt++ )
	{
		if ( gpDisplayList[ cnt ] != NULL )
		{
			if( ( fDitchLastMessage ) && ( cnt == ubLines - 1 ) )
			{
				gpDisplayList[ cnt ]->uiTimeOfLastUpdate = iMaxAge;
			}
				// CHECK IF WE HAVE AGED
			if ( ( suiTimer - gpDisplayList[ cnt ]->uiTimeOfLastUpdate ) > ( UINT32 )( iMaxAge - ( 1000 * iNumberOfMessagesOnQueue ) ) )
			{
				// Remove our sorry ass
				RemoveStringVideoOverlay( gpDisplayList[ cnt ] );
				MemFree( gpDisplayList[ cnt ]->pString16);
				MemFree( gpDisplayList[ cnt ] );

				// Free slot
				gpDisplayList[ cnt ] = NULL;
			}
		}
	}


	// CHECK FOR FREE SPOTS AND ADD ANY STRINGS IF WE HAVE SOME TO ADD!

	// FIRST CHECK IF WE HAVE ANY IN OUR QUEUE
	if ( pStringS != NULL )
	{
		// CHECK IF WE HAVE A SLOT!
		// CHECK OUR LAST SLOT!
		if ( gpDisplayList[ ubLines - 1 ] == NULL )
		{
			// MOVE ALL UP!

		// cpy, then move
		for( cnt = ubLines - 1; cnt > 0; cnt-- )
		{
				gpDisplayList[ cnt ] =	gpDisplayList[ cnt - 1 ];
		}

			// now add in the new string
		cnt = 0;
		gpDisplayList[ cnt ] = pStringS;
		CreateStringVideoOverlay( pStringS, X_START, iMsgYStart );
		if( pStringS->fBeginningOfNewString == TRUE )
		{
			iNumberOfNewStrings++;
		}

		// set up age
		pStringS->uiTimeOfLastUpdate = GetJA2Clock();

		// now move
		for ( cnt = 0; cnt <= (UINT8)(ubLines - 1); cnt++ )
		{

				// Adjust position!
				if ( gpDisplayList[ cnt	] != NULL )
				{

					SetStringVideoOverlayPosition( gpDisplayList[ cnt ], X_START, (INT16)( ( iMsgYStart - ( ( cnt ) * GetFontHeight( SMALLFONT1 ) ) ) - ( INT16)( WIDTH_BETWEEN_NEW_STRINGS * ( iNumberOfNewStrings ) ) ) );

					// start of new string, increment count of new strings, for spacing purposes
					if( gpDisplayList[ cnt ]->fBeginningOfNewString == TRUE )
					{
						iNumberOfNewStrings++;
					}


				}

		}


		// WE NOW HAVE A FREE SPACE, INSERT!

		// Adjust head!
		pStringS = pStringS->pNext;
		if( pStringS )
		{
			pStringS->pPrev = NULL;
		}

		//check if new meesage we have not seen since mapscreen..if so, beep
			if( ( fOkToBeepNewMessage == TRUE ) && ( gpDisplayList[ ubLines - 2 ] == NULL ) && ( ( guiCurrentScreen == GAME_SCREEN ) || ( guiCurrentScreen == MAP_SCREEN ) ) && ( gfFacePanelActive == FALSE ) )
			{
				PlayNewMessageSound( );
			}
		}
	}
}


void DisableScrollMessages( void )
{
	// will stop the scroll of messages in tactical and hide them during an NPC's dialogue
	// disble video overlay for tatcitcal scroll messages
	EnableDisableScrollStringVideoOverlay( FALSE );
	return;
}


void EnableScrollMessages( void )
{
	EnableDisableScrollStringVideoOverlay( TRUE );
	return;
}

void HideMessagesDuringNPCDialogue( void )
{
	// will stop the scroll of messages in tactical and hide them during an NPC's dialogue
	INT32 cnt;

	VIDEO_OVERLAY_DESC		VideoOverlayDesc;

	memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) );


	VideoOverlayDesc.fDisabled	= TRUE;
	VideoOverlayDesc.uiFlags	= VOVERLAY_DESC_DISABLED;


	fScrollMessagesHidden = TRUE;
	uiStartOfPauseTime = GetJA2Clock();

	UINT8 ubLines = 0;

	// HEADROCK HAM 3.6: Different number of lines shown in Tactical and Strategic modes.
	if( guiCurrentScreen == MAP_SCREEN )
	{
		ubLines = MAX_LINE_COUNT;
	}
	else
	{
		ubLines = gGameExternalOptions.ubMaxMessagesTactical;
	}

	for ( cnt = 0; cnt < ubLines; cnt++ )
	{
			if ( gpDisplayList[ cnt ] != NULL )
			{
				RestoreExternBackgroundRectGivenID( gVideoOverlays[ gpDisplayList[ cnt ]->iVideoOverlay ].uiBackground );
				UpdateVideoOverlay( &VideoOverlayDesc, gpDisplayList[ cnt ]->iVideoOverlay, FALSE );
			}
	}

	return;
}


void UnHideMessagesDuringNPCDialogue( void )
{

	VIDEO_OVERLAY_DESC		VideoOverlayDesc;
	INT32 cnt = 0;

	memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) );


	VideoOverlayDesc.fDisabled	= FALSE;
	VideoOverlayDesc.uiFlags	= VOVERLAY_DESC_DISABLED;
	fScrollMessagesHidden				= FALSE;

	UINT8 ubLines = 0;

	// HEADROCK HAM 3.6: Different number of lines shown in Tactical and Strategic modes.
	if( guiCurrentScreen == MAP_SCREEN )
	{
		ubLines = MAX_LINE_COUNT;
	}
	else
	{
		ubLines = gGameExternalOptions.ubMaxMessagesTactical;
	}

	for ( cnt = 0; cnt < ubLines; cnt++ )
	{
		if ( gpDisplayList[ cnt ] != NULL )
		{
			gpDisplayList[ cnt ]->uiTimeOfLastUpdate+= GetJA2Clock() - uiStartOfPauseTime;
			UpdateVideoOverlay( &VideoOverlayDesc, gpDisplayList[ cnt ]->iVideoOverlay, FALSE );
		}
	}


	return;
}

void ScreenMsg( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ...)
{
	//__try
	//{
		CHAR16	DestString[512];
		va_list argptr;

		if( fDisableJustForIan == TRUE )
		{
			if( ubPriority == MSG_BETAVERSION )
			{
				return;
			}
			else if( ubPriority == MSG_TESTVERSION )
			{
				return;
			}
			else if ( ubPriority == MSG_DEBUG )
			{
				return;
			}
		}

		if( ubPriority == MSG_DEBUG )
		{
			usColor = DEBUG_COLOR;
			#ifndef _DEBUG
				return;
			#endif
		}

		if( ubPriority == MSG_BETAVERSION )
		{
			usColor = BETAVERSION_COLOR;
			#ifndef JA2BETAVERSION
				#ifndef JA2TESTVERSION
					return;
				#endif
			#endif

		}

		if( ubPriority == MSG_TESTVERSION )
		{
			usColor = TESTVERSION_COLOR;

			#ifndef JA2TESTVERSION
				return;
			#endif

		}

		va_start(argptr, pStringA);
		vswprintf(DestString, pStringA, argptr);
		va_end(argptr);

		// pass onto tactical message and mapscreen message
		DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ScreenMsg start: %s", DestString));
		TacticalScreenMsg( usColor, ubPriority, DestString );
		DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ScreenMsg end: %s", DestString));

		//	if( ( ubPriority != MSG_DEBUG ) && ( ubPriority != MSG_TESTVERSION ) )
		{
			MapScreenMessage( usColor, ubPriority, DestString );
		}


		if( guiCurrentScreen == MAP_SCREEN )
		{
			PlayNewMessageSound( );
		}
		else
		{
			fOkToBeepNewMessage = TRUE;
		}

		return;
	//}
	//__except(filter(GetExceptionCode(), GetExceptionInformation()))
	//{
	//	return;
	//}
}

void ClearWrappedStrings( WRAPPED_STRING *pStringWrapperHead )
{
	WRAPPED_STRING *pNode = pStringWrapperHead;
	WRAPPED_STRING *pDeleteNode = NULL;
	// clear out a link list of wrapped string structures

	// error check, is there a node to delete?
	if( pNode == NULL )
	{
		// leave,
		return;
	}

	do
	{

		// set delete node as current node
		pDeleteNode = pNode;

		// set current node as next node
		pNode = pNode->pNextWrappedString;

		//delete the string
		MemFree( pDeleteNode->sString );
		pDeleteNode->sString = NULL;

		// clear out delete node
		MemFree( pDeleteNode );
		pDeleteNode = NULL;

	}	while( pNode );


//	MemFree( pNode );

	pStringWrapperHead = NULL;

}


// new tactical and mapscreen message system
void TacticalScreenMsg( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ... )
{
	// this function sets up the string into several single line structures

	ScrollStringStPtr pStringSt;
	UINT32 uiFont = TINYFONT1;
	//STR16pString;
	va_list argptr;

	CHAR16	DestString[512];//, DestStringA[ 512 ];
	//STR16pStringBuffer;
	ScrollStringStPtr pTempStringSt=NULL;
	WRAPPED_STRING *pStringWrapper=NULL;
	WRAPPED_STRING *pStringWrapperHead=NULL;
	BOOLEAN fNewString = FALSE;
	UINT16	usLineWidthIfWordIsWiderThenWidth=0;


	if( giTimeCompressMode > TIME_COMPRESS_X1 )
	{
		return;
	}

	if( fDisableJustForIan == TRUE && ubPriority != MSG_ERROR && ubPriority != MSG_INTERFACE )
	{
		return;
	}

	// OJW - 20090426 - Filter tactical messages
	if ( gTacticalMsgFilterPriority != -1 && gTacticalMsgFilterPriority != ubPriority )
	{
		return;
	}

	if( ubPriority == MSG_BETAVERSION )
	{
		usColor = BETAVERSION_COLOR;
		#ifndef JA2BETAVERSION
			#ifndef JA2TESTVERSION
				return;
			#endif
		#endif
		va_start(argptr, pStringA);					// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);
		WriteMessageToFile( DestString );
	}

	if( ubPriority == MSG_TESTVERSION )
	{
		usColor = TESTVERSION_COLOR;

		#ifndef JA2TESTVERSION
			return;
		#endif
		va_start(argptr, pStringA);					// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);
		WriteMessageToFile( DestString );
	}


	if ( fFirstTimeInMessageSystem )
	{
		// Init display array!
		memset( gpDisplayList, 0, sizeof( gpDisplayList ) );
		fFirstTimeInMessageSystem = FALSE;
		//if(!(InitializeMutex(SCROLL_MESSAGE_MUTEX,"ScrollMessageMutex" )))
		//	return;
	}


	pStringSt=pStringS;
	while(GetNextString(pStringSt))
		 pStringSt=GetNextString(pStringSt);

	va_start(argptr, pStringA);			// Set up variable argument pointer
	vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
	va_end(argptr);

	if ( ubPriority == MSG_DEBUG )
	{
		#ifndef _DEBUG
			return;
		#else
		usColor = DEBUG_COLOR;
		//wcscpy( DestStringA, DestString );
		//swprintf( DestString, L"Debug: %s", DestStringA );
		//WriteMessageToFile( DestStringA );
		#endif
	}

	if ( ubPriority == MSG_DIALOG )
	{
		usColor = DIALOGUE_COLOR;
	}

	// HEADROCK HAM 3.6: Why force yellow? Let's not.
	/*if ( ubPriority == MSG_INTERFACE )
	{
		usColor = INTERFACE_COLOR;
	}*/

	// HEADROCK HAM 3.6: Allow for longer lines.
	LINE_WIDTH = (SCREEN_WIDTH - 320);

	pStringWrapperHead=LineWrap(uiFont, LINE_WIDTH, &usLineWidthIfWordIsWiderThenWidth, DestString);
	pStringWrapper=pStringWrapperHead;
	if(!pStringWrapper)
		return;

	fNewString = TRUE;
	while(pStringWrapper->pNextWrappedString!=NULL)
	{
		if(!pStringSt)
		{
			pStringSt=AddString(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority );
			fNewString = FALSE;
			pStringSt->pNext=NULL;
			pStringSt->pPrev=NULL;
			pStringS=pStringSt;
		}
		else
		{
			pTempStringSt=AddString(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority);
			fNewString = FALSE;
			pTempStringSt->pPrev=pStringSt;
			pStringSt->pNext=pTempStringSt;
			pStringSt=pTempStringSt;
			pTempStringSt->pNext=NULL;
		}
		pStringWrapper=pStringWrapper->pNextWrappedString;
	}
	pTempStringSt=AddString(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority );
	if(pStringSt)
	{
		pStringSt->pNext=pTempStringSt;
		pTempStringSt->pPrev=pStringSt;
		pStringSt=pTempStringSt;
		pStringSt->pNext=NULL;
	}
	else
	{
		pStringSt=pTempStringSt;
		pStringSt->pNext=NULL;
		pStringSt->pPrev=NULL;
		pStringS=pStringSt;
	}

	// clear up list of wrapped strings
	ClearWrappedStrings( pStringWrapperHead );

	//LeaveMutex(SCROLL_MESSAGE_MUTEX, __LINE__, __FILE__);
	return;
}


void MapScreenMessage( UINT16 usColor, UINT8 ubPriority, STR16 pStringA, ... )
{
	// this function sets up the string into several single line structures

	ScrollStringStPtr pStringSt;
	UINT32 uiFont = MAP_SCREEN_MESSAGE_FONT;
	//STR16pString;
	va_list argptr;
	CHAR16	DestString[512], DestStringA[ 512 ];
	//STR16pStringBuffer;
	WRAPPED_STRING *pStringWrapper=NULL;
	WRAPPED_STRING *pStringWrapperHead=NULL;
	BOOLEAN fNewString = FALSE;
	UINT16	usLineWidthIfWordIsWiderThenWidth;

	if( fDisableJustForIan == TRUE )
	{
		if( ubPriority == MSG_BETAVERSION )
		{
			return;
		}
		else if( ubPriority == MSG_TESTVERSION )
		{
			return;
		}
		else if ( ubPriority == MSG_DEBUG )
		{
			return;
		}
	}

	if( ubPriority == MSG_BETAVERSION )
	{
		usColor = BETAVERSION_COLOR;
		#ifndef JA2BETAVERSION
			#ifndef JA2TESTVERSION
				return;
			#endif
		#endif

		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);
		WriteMessageToFile( DestString );
	}

	if( ubPriority == MSG_TESTVERSION )
	{
		usColor = TESTVERSION_COLOR;
		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);

		#ifndef JA2TESTVERSION
			return;
		#endif
		WriteMessageToFile( DestString );
	}
	// OK, check if we are ani imeediate feedback message, if so, do something else!
	if ( ubPriority == MSG_UI_FEEDBACK )
	{
		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);

		BeginUIMessage( DestString );
		return;
	}

	if ( ubPriority == MSG_SKULL_UI_FEEDBACK )
	{
		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);

		InternalBeginUIMessage( TRUE, DestString );
		return;
	}

	// check if error
	if ( ubPriority == MSG_ERROR )
	{
		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);

		swprintf( DestStringA, L"DEBUG: %s", DestString );

		BeginUIMessage( DestStringA );
		WriteMessageToFile( DestStringA );

		return;
	}


		// OK, check if we are an immediate MAP feedback message, if so, do something else!
	if ( ( ubPriority == MSG_MAP_UI_POSITION_UPPER	) ||
			( ubPriority == MSG_MAP_UI_POSITION_MIDDLE ) ||
			( ubPriority == MSG_MAP_UI_POSITION_LOWER	) )
	{
		va_start(argptr, pStringA);			// Set up variable argument pointer
		vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
		va_end(argptr);

		BeginMapUIMessage( ubPriority, DestString );
		return;
	}


	if ( fFirstTimeInMessageSystem )
	{
		// Init display array!
		memset( gpDisplayList, 0, sizeof( gpDisplayList ) );
		fFirstTimeInMessageSystem = FALSE;
		//if(!(InitializeMutex(SCROLL_MESSAGE_MUTEX,"ScrollMessageMutex" )))
		//	return;
	}


	pStringSt=pStringS;
	while(GetNextString(pStringSt))
		 pStringSt=GetNextString(pStringSt);

	va_start(argptr, pStringA);			// Set up variable argument pointer
	vswprintf(DestString, pStringA, argptr);	// process gprintf string (get output str)
	va_end(argptr);

	if ( ubPriority == MSG_DEBUG )
	{
		#ifndef _DEBUG
			return;
		#endif
		usColor = DEBUG_COLOR;
		wcscpy( DestStringA, DestString );
		swprintf( DestString, L"Debug: %s", DestStringA );
	}

	if ( ubPriority == MSG_DIALOG )
	{
		usColor = DIALOGUE_COLOR;
	}

	// HEADROCK HAM 3.6: Why force yellow? Let's not.
	/*if ( ubPriority == MSG_INTERFACE )
	{		
		usColor = INTERFACE_COLOR;
	}*/

	// HEADROCK HAM 3.6: Allow for longer lines.
	// Lejardo ARSProject
	MAP_LINE_WIDTH = (INTERFACE_WIDTH - 330);
	if (iResolution == _1280x720)
	{
		MAP_LINE_WIDTH = 685;
	}
	pStringWrapperHead=LineWrap(uiFont, MAP_LINE_WIDTH, &usLineWidthIfWordIsWiderThenWidth, DestString);
	pStringWrapper=pStringWrapperHead;
	if(!pStringWrapper)
	return;

	fNewString = TRUE;

	while(pStringWrapper->pNextWrappedString!=NULL)
	{
		AddStringToMapScreenMessageList(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority );
		fNewString = FALSE;

		pStringWrapper=pStringWrapper->pNextWrappedString;
	}

	AddStringToMapScreenMessageList(pStringWrapper->sString, usColor, uiFont, fNewString, ubPriority );
	// HEADROCK HAM 3.6: Refresh screen bottom.
	fMapScreenBottomDirty = TRUE;
	//RenderMapScreenInterfaceBottom ( TRUE );

	// clear up list of wrapped strings
	ClearWrappedStrings( pStringWrapperHead );

	// play new message beep
	//PlayNewMessageSound( );

	MoveToEndOfMapScreenMessageList( );

	//LeaveMutex(SCROLL_MESSAGE_MUTEX, __LINE__, __FILE__);
}



// add string to the map screen message list
void AddStringToMapScreenMessageList( STR16 pString, UINT16 usColor, UINT32 uiFont, BOOLEAN fStartOfNewString, UINT8 ubPriority )
{
	ScrollStringStPtr pStringSt = NULL;


	pStringSt = (ScrollStringStPtr) MemAlloc(sizeof(ScrollStringSt));

	SetString(pStringSt, pString);
	SetStringColor(pStringSt, usColor);
	pStringSt->uiFont = uiFont;
	pStringSt->fBeginningOfNewString = fStartOfNewString;
	pStringSt->uiFlags = ubPriority;
	pStringSt->iVideoOverlay = -1;

	// next/previous are not used, it's strictly a wraparound queue
	SetStringNext(pStringSt, NULL);
	SetStringPrev(pStringSt, NULL);


	// Figure out which queue slot index we're going to use to store this
	// If queue isn't full, this is easy, if is is full, we'll re-use the oldest slot
	// Must always keep the wraparound in mind, although this is easy enough with a static, fixed-size queue.


	// always store the new message at the END index

	// check if slot is being used, if so, clear it up
	if( gMapScreenMessageList[ gubEndOfMapScreenMessageList ] != NULL )
	{
		MemFree( gMapScreenMessageList[ gubEndOfMapScreenMessageList ]->pString16 );
		MemFree( gMapScreenMessageList[ gubEndOfMapScreenMessageList ] );
	}

	// store the new message there
	gMapScreenMessageList[ gubEndOfMapScreenMessageList ] = pStringSt;

	// increment the end
	gubEndOfMapScreenMessageList = ( gubEndOfMapScreenMessageList + 1 ) % 256;

	// if queue is full, end will now match the start
	if ( gubEndOfMapScreenMessageList == gubStartOfMapScreenMessageList )
	{
		// if that's so, increment the start
		gubStartOfMapScreenMessageList = ( gubStartOfMapScreenMessageList + 1 ) % 256;
	}
}


void DisplayStringsInMapScreenMessageList( void )
{
	UINT8 ubCurrentStringIndex;
	UINT8	ubLinesPrinted;
	INT16 sY;
	UINT16 usSpacing;
	UINT16 MessageStartX = (SCREEN_WIDTH - INTERFACE_WIDTH) / 2;
	UINT16 MessageEndX = MessageStartX + (INTERFACE_WIDTH - 330);
	if (iResolution == _1280x720)
	{
		MessageStartX = 0;
		MessageEndX = 705;
	}
	//SetFontDestBuffer( FRAME_BUFFER, 17, 360 + 6, 407, 360 + 101, FALSE );

	// CHRISL: Change both X paramters so they dynamically generate from right edge of screen
	//SetFontDestBuffer( FRAME_BUFFER, (SCREEN_WIDTH - 509), (SCREEN_HEIGHT - 114), (SCREEN_WIDTH - 233), (SCREEN_HEIGHT - 114) + 101, FALSE );
	// CHRISL: Use this setup if we want message box on the left side
	// HEADROCK HAM 3.6: Message window now as wide as possible. The money screen has been moved to the right side.
	SetFontDestBuffer( FRAME_BUFFER, MessageStartX + 17, (SCREEN_HEIGHT - 114), MessageEndX, (SCREEN_HEIGHT - 114) + 101, FALSE );

	SetFont( MAP_SCREEN_MESSAGE_FONT );		// no longer supports variable fonts
	SetFontBackground( FONT_BLACK );
	SetFontShadow( DEFAULT_SHADOW );

	ubCurrentStringIndex = gubCurrentMapMessageString;

	//sY = 377;
	sY = (SCREEN_HEIGHT - 103);

	usSpacing = GetFontHeight( MAP_SCREEN_MESSAGE_FONT );

	for ( ubLinesPrinted = 0; ubLinesPrinted < MAX_MESSAGES_ON_MAP_BOTTOM; ubLinesPrinted++ )
	{
		// reached the end of the list?
		if ( ubCurrentStringIndex == gubEndOfMapScreenMessageList )
		{
			break;
		}

		// nothing stored there?
		if ( gMapScreenMessageList[ ubCurrentStringIndex ] == NULL )
		{
			break;
		}

		// set font color
		SetFontForeground( ( UINT8 )( gMapScreenMessageList[ ubCurrentStringIndex ]->usColor ) );

		// print this line
		// CHRISL: Change X parameter to dynamically generate from right edge of screen
		//mprintf_coded( (SCREEN_WIDTH - 506), sY, gMapScreenMessageList[ ubCurrentStringIndex ]->pString16 );
		// CHRISL: Use this line if we want to display from the left edge
		mprintf_coded(MessageStartX + 20, sY, gMapScreenMessageList[ ubCurrentStringIndex ]->pString16 );

		sY = sY + usSpacing;

		// next message index to print (may wrap around)
		ubCurrentStringIndex = ( ubCurrentStringIndex + 1 ) % 256;
	}

	SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
}


void EnableDisableScrollStringVideoOverlay( BOOLEAN fEnable )
{
	// will go through the list of video overlays for the tactical scroll message system, and enable/disable
	// video overlays depending on fEnable
	INT8 bCounter = 0;
	UINT8 ubLines = 0;

	if( guiCurrentScreen == MAP_SCREEN )
	{
		ubLines = MAX_LINE_COUNT;
	}
	else
	{
		ubLines = gGameExternalOptions.ubMaxMessagesTactical;
	}
	
	for( bCounter = 0; bCounter < ubLines; bCounter++ )
	{

		// if valid, enable/disable
		if( gpDisplayList[ bCounter ] != NULL )
		{
			EnableVideoOverlay( fEnable ,gpDisplayList[ bCounter ]->iVideoOverlay );
		}
	}

	return;

}


void PlayNewMessageSound( void )
{
	// play a new message sound, if there is one playing, do nothing
	static UINT32 uiSoundId = NO_SAMPLE;

	if( uiSoundId != NO_SAMPLE )
	{
		// is sound playing?..don't play new one
		if( SoundIsPlaying( uiSoundId ) == TRUE )
		{
			return;
		}
	}

	// otherwise no sound playing, play one
	uiSoundId = PlayJA2SampleFromFile( "Sounds\\newbeep.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN );

	return;
}


BOOLEAN SaveMapScreenMessagesToSaveGameFile( HWFILE hFile )
{
	UINT32	uiNumBytesWritten;
	UINT32	uiCount;
	UINT32	uiSizeOfString;
	StringSaveStruct StringSave;


	//	write to the begining of the message list
	FileWrite( hFile, &gubEndOfMapScreenMessageList, sizeof( UINT8 ), &uiNumBytesWritten );
	if( uiNumBytesWritten != sizeof( UINT8 ) )
	{
		return(FALSE);
	}

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

	//	write the current message string
	FileWrite( hFile, &gubCurrentMapMessageString, sizeof( UINT8 ), &uiNumBytesWritten );
	if( uiNumBytesWritten != sizeof( UINT8 ) )
	{
		return(FALSE);
	}


	//Loopthrough all the messages
	for( uiCount=0; uiCount<256; uiCount++)
	{
		if( gMapScreenMessageList[ uiCount ] )
		{
			uiSizeOfString = ( wcslen( gMapScreenMessageList[ uiCount ]->pString16 ) + 1 ) * 2;
		}
		else
			uiSizeOfString = 0;

		//	write to the file the size of the message
		FileWrite( hFile, &uiSizeOfString, sizeof( UINT32 ), &uiNumBytesWritten );
		if( uiNumBytesWritten != sizeof( UINT32 ) )
		{
			return(FALSE);
		}

		//if there is a message
		if( uiSizeOfString )
		{
			//	write the message to the file
			FileWrite( hFile, gMapScreenMessageList[ uiCount ]->pString16, uiSizeOfString, &uiNumBytesWritten );
			if( uiNumBytesWritten != uiSizeOfString )
			{
				return(FALSE);
			}

			// Create	the saved string struct
			StringSave.uiFont = gMapScreenMessageList[ uiCount ]->uiFont;
			StringSave.usColor = gMapScreenMessageList[ uiCount ]->usColor;
			StringSave.fBeginningOfNewString = gMapScreenMessageList[ uiCount ]->fBeginningOfNewString;
			StringSave.uiTimeOfLastUpdate = gMapScreenMessageList[ uiCount ]->uiTimeOfLastUpdate;
			StringSave.uiFlags= gMapScreenMessageList[ uiCount ]->uiFlags;


			//Write the rest of the message information to the saved game file
			FileWrite( hFile, &StringSave, sizeof( StringSaveStruct ), &uiNumBytesWritten );
			if( uiNumBytesWritten != sizeof( StringSaveStruct ) )
			{
				return(FALSE);
			}
		}

	}

	return( TRUE );
}


BOOLEAN LoadMapScreenMessagesFromSaveGameFile( HWFILE hFile )
{
	UINT32	uiNumBytesRead;
	UINT32	uiCount;
	UINT32	uiSizeOfString;
	StringSaveStruct StringSave;
	CHAR16	SavedString[ 512 ];

	// clear tactical message queue
	ClearTacticalMessageQueue( );

	gubEndOfMapScreenMessageList = 0;
	gubStartOfMapScreenMessageList = 0;
	gubCurrentMapMessageString = 0;

	//	Read to the begining of the message list
	FileRead( hFile, &gubEndOfMapScreenMessageList, sizeof( UINT8 ), &uiNumBytesRead );
	if( uiNumBytesRead != sizeof( UINT8 ) )
	{
		return(FALSE);
	}

	//	Read the current message string
	FileRead( hFile, &gubStartOfMapScreenMessageList, sizeof( UINT8 ), &uiNumBytesRead );
	if( uiNumBytesRead != sizeof( UINT8 ) )
	{
		return(FALSE);
	}

	//	Read the current message string
	FileRead( hFile, &gubCurrentMapMessageString, sizeof( UINT8 ), &uiNumBytesRead );
	if( uiNumBytesRead != sizeof( UINT8 ) )
	{
		return(FALSE);
	}

	//Loopthrough all the messages
	for( uiCount=0; uiCount<256; uiCount++)
	{
		//	Read to the file the size of the message
		FileRead( hFile, &uiSizeOfString, sizeof( UINT32 ), &uiNumBytesRead );
		if( uiNumBytesRead != sizeof( UINT32 ) )
		{
			return(FALSE);
		}

		//if there is a message
		if( uiSizeOfString )
		{
			//	Read the message from the file
			FileRead( hFile, SavedString, uiSizeOfString, &uiNumBytesRead );
			if( uiNumBytesRead != uiSizeOfString )
			{
				return(FALSE);
			}

			//if there is an existing string,delete it
			if( gMapScreenMessageList[ uiCount ] )
			{
				if( gMapScreenMessageList[ uiCount ]->pString16 )
				{
					MemFree( gMapScreenMessageList[ uiCount ]->pString16 );
					gMapScreenMessageList[ uiCount ]->pString16 = NULL;
				}
			}
			else
			{
				// There is now message here, add one
				ScrollStringSt	*sScroll;


				sScroll = (ScrollStringSt *) MemAlloc( sizeof( ScrollStringSt ) );
				if( sScroll == NULL )
					return( FALSE );

				memset( sScroll, 0, sizeof( ScrollStringSt ) );

				gMapScreenMessageList[ uiCount ] = sScroll;
			}

			//allocate space for the new string
			gMapScreenMessageList[ uiCount ]->pString16 = (STR16) MemAlloc( uiSizeOfString );
			if( gMapScreenMessageList[ uiCount ]->pString16 == NULL )
				return( FALSE );

			memset( gMapScreenMessageList[ uiCount ]->pString16, 0, uiSizeOfString);

			//copy the string over
			wcscpy( gMapScreenMessageList[ uiCount ]->pString16, SavedString );


			//Read the rest of the message information to the saved game file
			FileRead( hFile, &StringSave, sizeof( StringSaveStruct ), &uiNumBytesRead );
			if( uiNumBytesRead != sizeof( StringSaveStruct ) )
			{
				return(FALSE);
			}

			// Create	the saved string struct
			gMapScreenMessageList[ uiCount ]->uiFont = StringSave.uiFont;
			gMapScreenMessageList[ uiCount ]->usColor = StringSave.usColor;
			gMapScreenMessageList[ uiCount ]->uiFlags = StringSave.uiFlags;
			gMapScreenMessageList[ uiCount ]->fBeginningOfNewString = StringSave.fBeginningOfNewString;
			gMapScreenMessageList[ uiCount ]->uiTimeOfLastUpdate = StringSave.uiTimeOfLastUpdate;
		}
		else
			gMapScreenMessageList[ uiCount ] = NULL;

	}


	// this will set a valid value for gubFirstMapscreenMessageIndex, which isn't being saved/restored
	MoveToEndOfMapScreenMessageList();

	return( TRUE );
}


void HandleLastQuotePopUpTimer( void )
{
	if( ( fTextBoxMouseRegionCreated == FALSE ) || ( fDialogueBoxDueToLastMessage == FALSE ) )
	{
		return;
	}

	// check if timed out
	if( GetJA2Clock() - guiDialogueLastQuoteTime >	guiDialogueLastQuoteDelay )
	{
		// done clear up
		ShutDownLastQuoteTacticalTextBox( );
		guiDialogueLastQuoteTime = 0;
		guiDialogueLastQuoteDelay = 0;

	}
}


ScrollStringStPtr MoveToBeginningOfMessageQueue( void )
{
	ScrollStringStPtr pStringSt = pStringS;

	if( pStringSt == NULL )
	{
		return( NULL );
	}

	while( pStringSt->pPrev )
	{
		pStringSt = pStringSt->pPrev;
	}

	return( pStringSt );
}



INT32 GetMessageQueueSize( void )
{
	ScrollStringStPtr pStringSt = pStringS;
	INT32 iCounter = 0;

	pStringSt = MoveToBeginningOfMessageQueue( );

	while( pStringSt )
	{
		iCounter++;
		pStringSt = pStringSt->pNext;
	}

	return( iCounter );
}



void ClearTacticalMessageQueue( void )
{

	ScrollStringStPtr pStringSt = pStringS, pOtherStringSt = pStringS;

	ClearDisplayedListOfTacticalStrings( );

	// now run through all the tactical messages
	while( pStringSt )
	{
		pOtherStringSt = pStringSt;
		pStringSt = pStringSt->pNext;
		MemFree( pOtherStringSt->pString16 );
		MemFree( pOtherStringSt );
	}

	pStringS = NULL;

	return;
}

static struct DebugMessageLog {
	sgp::Logger_ID id;
	DebugMessageLog() {
		id = sgp::Logger::instance().createLogger();
		sgp::Logger::instance().connectFile(id, L"DebugMessage.txt", true, sgp::Logger::FLUSH_ON_ENDL);
	}
} s_DebugMessageLog;
void WriteMessageToFile( const STR16 pString )
{
#ifdef JA2BETAVERSION
#ifndef USE_VFS
	FILE *fp;

	fp = fopen( "DebugMessage.txt", "a" );

	if( fp == NULL )
	{
		return;
	}

	fprintf( fp, "%S\n", pString );
	fclose( fp );
#else
	SGP_LOG(s_DebugMessageLog.id, pString);
#endif
#endif
}



void InitGlobalMessageList( void )
{
	INT32 iCounter = 0;

	for( iCounter = 0; iCounter < 256; iCounter++ )
	{
		gMapScreenMessageList[ iCounter ] = NULL;
	}

	gubEndOfMapScreenMessageList = 0;
	gubStartOfMapScreenMessageList = 0;
	gubCurrentMapMessageString = 0;
//	ubTempPosition = 0;

	return;
}


void FreeGlobalMessageList( void )
{
	INT32 iCounter = 0;

	for( iCounter = 0; iCounter < 256; iCounter++ )
	{
		// check if next unit is empty, if not...clear it up
		if( gMapScreenMessageList[ iCounter ] != NULL )
		{
			MemFree( gMapScreenMessageList[ iCounter ]->pString16 );
			MemFree( gMapScreenMessageList[ iCounter ] );
		}
	}

	InitGlobalMessageList( );

	return;
}


UINT8 GetRangeOfMapScreenMessages( void )
{
	UINT8 ubRange = 0;

	// NOTE: End is non-inclusive, so start/end 0/0 means no messages, 0/1 means 1 message, etc.
	if( gubStartOfMapScreenMessageList <= gubEndOfMapScreenMessageList )
	{
		ubRange = gubEndOfMapScreenMessageList - gubStartOfMapScreenMessageList;
	}
	else
	{
		// this should always be 255 now, since this only happens when queue fills up, and we never remove any messages
		ubRange = ( gubEndOfMapScreenMessageList + 256 ) - gubStartOfMapScreenMessageList;
	}

	return ( ubRange );
}

// OJW - 20090426 - only show certain messages in the tactical / message overlay
void SetTacticalMessageFilter( UINT ubPriority )
{
	gTacticalMsgFilterPriority = ubPriority;
}

void RemoveTacticalMessageFilter ( void )
{
	gTacticalMsgFilterPriority = -1;
}



/*
BOOLEAN IsThereAnEmptySlotInTheMapScreenMessageList( void )
{
	// find if there is an empty slot

	if( gMapScreenMessageList[ ( UINT8 )( gubEndOfMapScreenMessageList + 1 ) ] != NULL )
	{
		return ( FALSE );
	}
	else
	{
		return( TRUE );
	}
}


UINT8 GetFirstEmptySlotInTheMapScreenMessageList( void )
{
	UINT8 ubSlotId = 0;

	// find first empty slot in list

	if( IsThereAnEmptySlotInTheMapScreenMessageList(	) == FALSE)
	{
		ubSlotId = gubEndOfMapScreenMessageList;
		return( ubSlotId );
	}
	else
	{
		// start at head of list
		ubSlotId = gubEndOfMapScreenMessageList;

		// run through list
		while( gMapScreenMessageList[ ubSlotId ] != NULL )
		{
			ubSlotId++;
		}

	}
	return( ubSlotId );
}



void SetCurrentMapScreenMessageString( UINT8 ubCurrentStringPosition )
{
	// will attempt to set current string to this value, or the closest one
	UINT8 ubCounter = 0;

	if( gMapScreenMessageList[ ubCurrentStringPosition ] == NULL )
	{
		// no message here, run down to nearest
		ubCounter = ubCurrentStringPosition;
		ubCounter--;

		while(	( gMapScreenMessageList[ ubCounter ] == NULL )&&( ubCounter != ubCurrentStringPosition ) )
		{
			if( ubCounter == 0 )
			{
				ubCounter = 255;
			}
			else
			{
				ubCounter--;
			}
		}

		ubCurrentStringPosition = ubCounter;

	}
	return;
}


UINT8 GetTheRelativePositionOfCurrentMessage( void )
{
	UINT8 ubPosition = 0;

	if( gubEndOfMapScreenMessageList > gubStartOfMapScreenMessageList)
	{
		ubPosition = gubCurrentMapMessageString - gubStartOfMapScreenMessageList;
	}
	else
	{
		ubPosition = ( 255 - gubStartOfMapScreenMessageList ) + gubCurrentMapMessageString;
	}


	return( ubPosition );
}




void MoveCurrentMessagePointerDownList( void )
{
	// check to see if we can move 'down' to newer messages?
	if( gMapScreenMessageList[ ( UINT8 )( gubCurrentMapMessageString	+ 1 )	] != NULL )
	{
		if(	( UINT8 ) ( gubCurrentMapMessageString + 1 ) != gubEndOfMapScreenMessageList )
		{
			if( ( AreThereASetOfStringsAfterThisIndex( gubCurrentMapMessageString, MAX_MESSAGES_ON_MAP_BOTTOM ) == TRUE ) )
			{
				gubCurrentMapMessageString++;
			}
		}
	}
}


void MoveCurrentMessagePointerUpList(void )
{
		// check to see if we can move 'down' to newer messages?
	if( gMapScreenMessageList[ ( UINT8 )( gubCurrentMapMessageString	- 1 )	] != NULL )
	{
		if( ( UINT8 ) ( gubCurrentMapMessageString - 1 ) != gubEndOfMapScreenMessageList )
		{
			gubCurrentMapMessageString--;
		}
	}

}



void ScrollToHereInMapScreenMessageList( UINT8 ubPosition )
{
	// a position ranging from 0 to 255 where 0 is top and 255 is bottom
	// get the range of messages, * ubPosition /255 and set current to this position
	UINT8 ubTestPosition = gubCurrentMapMessageString;
	UINT8 ubRange = 0;

	ubRange = GetRangeOfMapScreenMessages( );

	if( ubRange > 1 )
	{
		ubRange += 9;
	}

	ubTestPosition = ( UINT8 )( gubEndOfMapScreenMessageList - ( UINT8 )(	ubRange	) + (	( ( UINT8 )( ubRange )	* ubPosition ) / 256 ) );

	if( AreThereASetOfStringsAfterThisIndex( ubTestPosition, MAX_MESSAGES_ON_MAP_BOTTOM ) == TRUE )
	{
		gubCurrentMapMessageString = ubTestPosition;
	}

	ubTempPosition = ubTestPosition;

	return;
}


BOOLEAN AreThereASetOfStringsAfterThisIndex( UINT8 ubMsgIndex, INT32 iNumberOfStrings )
{
	INT32 iCounter;

	// go through this number of strings, if they pass, then we have at least iNumberOfStrings after index ubMsgIndex
	for( iCounter = 0; iCounter < iNumberOfStrings; iCounter++ )
	{
		// start checking AFTER this index, so skip ahead to the next index BEFORE checking
		if( ubMsgIndex < 255 )
		{
			ubMsgIndex++;
		}
		else
		{
			ubMsgIndex = 0;
		}

		if( gMapScreenMessageList[ ubMsgIndex ] == NULL )
		{
			return ( FALSE );
		}

		if( ubMsgIndex == gubEndOfMapScreenMessageList )
		{
			return( FALSE );
		}
	}

	return( TRUE );
}



UINT8 GetCurrentMessageValue( void )
{
	// return the value of the current message in the list, relative to the start of the list

	if( GetRangeOfMapScreenMessages( ) >= 255	)
	{
	return( gubCurrentMapMessageString - gubStartOfMapScreenMessageList );
	}
	else
	{
		return( gubCurrentMapMessageString );
	}
}



UINT8 GetCurrentTempMessageValue( void )
{
	if( GetRangeOfMapScreenMessages( ) >= 255	)
	{
		return( ubTempPosition - gubEndOfMapScreenMessageList );
	}
	else
	{
		return( ubTempPosition );
	}
}


UINT8 GetNewMessageValueGivenPosition( UINT8 ubPosition )
{
	// if we were to scroll to this position, what would current message index value be?

	return( ( UINT8 )( ( gubEndOfMapScreenMessageList - ( UINT8 )( GetRangeOfMapScreenMessages( ) ) ) + ( UINT8 )( ( GetRangeOfMapScreenMessages( ) * ubPosition ) / 255 ) ) );

}


BOOLEAN IsThisTheLastMessageInTheList( void )
{
	// is the current message the last message in the list?

	if( ( ( UINT8 )( gubCurrentMapMessageString + 1 ) ) == ( gubEndOfMapScreenMessageList ) && ( GetRangeOfMapScreenMessages( ) < 255 ) )
	{
		return( TRUE );
	}
	else if( gMapScreenMessageList[ ( UINT8 )( gubCurrentMapMessageString + 1 ) ] == NULL )
	{
		return( TRUE );
	}
	else
	{
		if( AreThereASetOfStringsAfterThisIndex( gubCurrentMapMessageString, MAX_MESSAGES_ON_MAP_BOTTOM ) == FALSE )
		{
			return( TRUE );
		}
		else
		{
			return ( FALSE );
		}
	}
}


BOOLEAN IsThisTheFirstMessageInTheList( void )
{
	// is the current message the first message in the list?

	if( ( gubCurrentMapMessageString ) == ( gubEndOfMapScreenMessageList ) )
	{
		return( TRUE );
	}
	else
	{
		return ( FALSE );
	}
}


void DisplayLastMessage( void )
{
	// start at end of list go back until message flag says dialogue
	UINT8 ubCounter = 0;
	BOOLEAN fNotDone = TRUE;
	BOOLEAN fFound = FALSE;
	BOOLEAN fSecondNewString = FALSE;
	CHAR16 sString[ 256 ];

	sString[ 0 ] = 0;


	// set counter to end of list
	while( ( gMapScreenMessageList[ ( UINT8 )( ubCounter	+ 1 )	] != NULL ) && ( ( UINT8 ) ( ubCounter + 1 ) != gubEndOfMapScreenMessageList ) )
	{
		ubCounter++;
	}

	// now start moving back until dialogue is found
	while( fNotDone )
	{
		if( ubCounter == gubEndOfMapScreenMessageList )
		{
			fNotDone = FALSE;
			fFound = FALSE;
			continue;
		}

		if( gMapScreenMessageList[ ubCounter ] == NULL )
		{
			fNotDone = FALSE;
			fFound = FALSE;
			continue;
		}
		// check if message if dialogue
		if( gMapScreenMessageList[ ubCounter ]->uiFlags == MSG_DIALOG )
		{
			if( gMapScreenMessageList[ ubCounter ]->fBeginningOfNewString == TRUE )
			{
				// yup
				fNotDone = FALSE;
				fFound = TRUE;

				// now display message
				continue;
			}
		}

		ubCounter--;
	}

	if( fFound == TRUE )
	{
		fNotDone = TRUE;

		while( fNotDone )
		{
			if( gMapScreenMessageList[ ubCounter ] )
			{
				if( ( fSecondNewString ) && ( gMapScreenMessageList[ ubCounter ]-> fBeginningOfNewString ) )
				{
					fNotDone = FALSE;
				}
				else if( gMapScreenMessageList[ ubCounter ]->uiFlags == MSG_DIALOG )
				{
					wcscat( sString, gMapScreenMessageList[ ubCounter ]->pString16 );
					wcscat( sString, L" " );
				}

				if( ( gMapScreenMessageList[ ubCounter ]-> fBeginningOfNewString ) )
				{
					fSecondNewString = TRUE;
				}

			}
			else
			{
				fNotDone = FALSE;
			}

			// the next string
			ubCounter++;
		}
		// execute text box
		ExecuteTacticalTextBoxForLastQuote( ( INT16 )( ( 640 - gusSubtitleBoxWidth ) / 2 ),	sString );
	}

	return;
}

*/



