#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 #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); 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; //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, (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + 17, (SCREEN_HEIGHT - 114), (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + (INTERFACE_WIDTH - 330), (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( (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + 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; } */