#ifdef PRECOMPILEDHEADERS #include "Tactical All.h" #include "PreBattle Interface.h" #else #include "sgp.h" //#include "soldier control.h" #include "Encrypted File.h" #include "faces.h" #include "wcheck.h" #include "gap.h" #include "overhead.h" #include "Sound Control.h" #include "dialogue control.h" #include "Message.h" #include "render dirty.h" #include "soldier profile.h" #include "wordwrap.h" #include "sysutil.h" #include "vobject_blitters.h" #include "AimMembers.h" #include "mercs.h" #include "interface dialogue.h" #include "merctextbox.h" #include "renderworld.h" #include "soldier macros.h" #include "squads.h" #include "screenids.h" #include "interface utils.h" #include "strategicmap.h" #include "PreBattle Interface.h" #include "Game Clock.h" #include "Quests.h" #include "cursors.h" #include "gamescreen.h" #include "Random.h" #include "Map Screen Helicopter.h" #include "GameSettings.h" #include "ShopKeeper Interface.h" #include "Map Screen Interface.h" #include "text.h" #include "Merc Contract.h" #include "Town Militia.h" #include "meanwhile.h" #include "SkillCheck.h" #include "Interface Control.h" #include "finances.h" #include "civ quotes.h" #include "Map Screen Interface Map.h" #include "opplist.h" #include "ai.h" #include "worldman.h" #include "Map Screen Interface Bottom.h" #include "Campaign.h" #include "end game.h" #include "los.h" #include "qarray.h" #include "Soldier Profile.h" #endif #include #include "Auto Resolve.h" #include "connect.h" #ifdef JA2UB #include "Intro.h" #include "MapScreen Quotes.h" #include "Ja25 Strategic Ai.h" #include "Ja25_Tactical.h" #include "Animation Control.h" #endif #include "ub_config.h" #include "history.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; #define DIALOGUESIZE 480 #define QUOTE_MESSAGE_SIZE 520 #define TALK_PANEL_FACE_X 6 #define TALK_PANEL_FACE_Y 9 #define TALK_PANEL_NAME_X 5 #define TALK_PANEL_NAME_Y 114 #define TALK_PANEL_NAME_WIDTH 92 #define TALK_PANEL_NAME_HEIGHT 15 #define TALK_PANEL_MENU_STARTY 8 #define TALK_PANEL_MENU_HEIGHT 24 #define TALK_MENU_WIDTH 96 #define TALK_MENU_HEIGHT 16 #define DIALOGUE_DEFAULT_SUBTITLE_WIDTH 200 #define TEXT_DELAY_MODIFIER 60 SOUND_PROFILE_VALUES gSoundProfileValue[NUM_PROFILES]; typedef struct { UINT16 usQuoteNum; UINT8 ubCharacterNum; INT8 bUIHandlerID; INT32 iFaceIndex; INT32 iTimeStamp; UINT32 uiSpecialEventFlag; UINT32 uiSpecialEventData; UINT32 uiSpecialEventData2; UINT32 uiSpecialEventData3; UINT32 uiSpecialEventData4; BOOLEAN fFromSoldier; BOOLEAN fDelayed; BOOLEAN fPauseTime; } DIALOGUE_Q_STRUCT, *DIALOGUE_Q_STRUCT_PTR; extern INT32 giMapInvPrev; extern INT32 giMapInvNext; extern BOOLEAN gfSKIScreenExit; extern SOLDIERTYPE *pProcessingSoldier; extern BOOLEAN fProcessingAMerc; extern UINT32 guiPendingScreen; extern BOOLEAN fReDrawFace; extern BOOLEAN gfWaitingForTriggerTimer; BOOLEAN fExternFacesLoaded = FALSE; // head miners' external profile ids have been moved to lua script std::vector uiExternalStaticNPCFaces; //UINT32 uiExternalStaticNPCFaces[ NUMBER_OF_EXTERNAL_NPC_FACES ]; //UINT32 uiExternalFaceProfileIds[ NUMBER_OF_EXTERNAL_NPC_FACES ]= //{ // 97, // 106, // 148, // 156, // 157, // 158, //}; #ifdef JA2UB UINT32 uiExternalStaticNPCFacesUB[ NUMBER_OF_EXTERNAL_NPC_FACES ]; UINT32 uiExternalFaceProfileIdsUB[ NUMBER_OF_EXTERNAL_NPC_FACES ]= { 97, 106, 148, 156, 157, 158, 76, //Jerry Melo }; BOOLEAN AreAllTheMercsFinishedSayingThereInitialHeliCrashQuotes(); void InitJerriesSpeechCallBack(); void HandlePlayerClosingMorrisNoteDisplayedOnScreen(); #endif UINT8 gubMercValidPrecedentQuoteID[ NUMBER_VALID_MERC_PRECEDENT_QUOTES ] = { 80, 81, 82, 83, 86, 87, 88, 95, 97, 99, 100, 101, 102 }; extern INT32 iInterfaceDialogueBox; extern BOOLEAN gfRerenderInterfaceFromHelpText; extern UINT32 guiSKI_TransactionButton; UINT16 gusStopTimeQuoteList[ ] = { QUOTE_BOOBYTRAP_ITEM, QUOTE_SUSPICIOUS_GROUND }; UINT8 gubNumStopTimeQuotes = 2; // QUEUE UP DIALOG! #define INITIAL_Q_SIZE 10 HQUEUE ghDialogueQ = NULL; FACETYPE *gpCurrentTalkingFace = NULL; UINT8 gubCurrentTalkingID = NO_PROFILE; INT8 gbUIHandlerID; INT32 giNPCReferenceCount = 0; INT32 giNPCSpecialReferenceCount = 0; INT16 gsExternPanelXPosition = DEFAULT_EXTERN_PANEL_X_POS; INT16 gsExternPanelYPosition = DEFAULT_EXTERN_PANEL_Y_POS; BOOLEAN gfDialogueQueuePaused = FALSE; UINT16 gusSubtitleBoxWidth; UINT16 gusSubtitleBoxHeight; INT32 giTextBoxOverlay = -1; BOOLEAN gfFacePanelActive = FALSE; UINT32 guiScreenIDUsedWhenUICreated; CHAR16 gzQuoteStr[ QUOTE_MESSAGE_SIZE ]; MOUSE_REGION gTextBoxMouseRegion; MOUSE_REGION gFacePopupMouseRegion; BOOLEAN gfUseAlternateDialogueFile = FALSE; // set the top position value for merc dialogue pop up boxes INT16 gsTopPosition = 20; INT32 iDialogueBox = -1; void RenderSubtitleBoxOverlay( VIDEO_OVERLAY *pBlitter ); void RenderFaceOverlay( VIDEO_OVERLAY *pBlitter ); extern BOOLEAN ContinueDialogue(SOLDIERTYPE *pSoldier, BOOLEAN fDone ); extern void HandlePendingInitConv( ); extern BOOLEAN WillMercRenew( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote ); extern void DrawFace( INT16 sCharNumber ); // the next said quote will pause time BOOLEAN fPausedTimeDuringQuote = FALSE; BOOLEAN fWasPausedDuringDialogue = FALSE; extern BOOLEAN gfLockPauseState; INT8 gubLogForMeTooBleeds = FALSE; // has the text region been created? BOOLEAN fTextBoxMouseRegionCreated = FALSE; BOOLEAN fExternFaceBoxRegionCreated = FALSE; // due to last quote system? BOOLEAN fDialogueBoxDueToLastMessage = FALSE; // last quote timers UINT32 guiDialogueLastQuoteTime = 0; UINT32 guiDialogueLastQuoteDelay = 0; void CheckForStopTimeQuotes( UINT16 usQuoteNum ); void TextOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); void FaceOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); // Handler functions for tactical ui diaplay void HandleTacticalTextUI( INT32 iFaceIndex, SOLDIERTYPE *pSoldier, STR16 zQuoteStr ); void HandleTacticalNPCTextUI( UINT8 ubCharacterNum, STR16 zQuoteStr ); void HandleTacticalSpeechUI( UINT8 ubCharacterNum, INT32 iFaceIndex ); void DisplayTextForExternalNPC( UINT8 ubCharacterNum, STR16 zQuoteStr ); void CreateTalkingUI( INT8 bUIHandlerID, INT32 iFaceIndex, UINT8 ubCharacterNum, SOLDIERTYPE *pSoldier, STR16 zQuoteStr ); #ifdef JA2UB BOOLEAN AreAllTheMercsFinishedSayingThereInitialHeliCrashQuotes(); void InitJerriesSpeechCallBack(); void HandlePlayerClosingMorrisNoteDisplayedOnScreen(); #endif void HandleExternNPCSpeechFace( INT32 iIndex ); extern BOOLEAN ContinueDialogue(SOLDIERTYPE *pSoldier, BOOLEAN fDone ); extern BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback ); void UnPauseGameDuringNextQuote( void ) { fPausedTimeDuringQuote = FALSE; return; } void PauseTimeDuringNextQuote( void ) { fPausedTimeDuringQuote = TRUE; return; } BOOLEAN DialogueActive( ) { if ( gpCurrentTalkingFace != NULL ) { return( TRUE ); } return( FALSE ); } BOOLEAN InitalizeDialogueControl() { ghDialogueQ = CreateQueue( INITIAL_Q_SIZE, sizeof( DIALOGUE_Q_STRUCT_PTR ) ); // Initalize subtitle popup box // giNPCReferenceCount = 0; if ( ghDialogueQ == NULL ) { return( FALSE ); } else { return( TRUE ); } } void ShutdownDialogueControl() { if( ghDialogueQ != NULL ) { // Empty EmptyDialogueQueue( ); // Delete DeleteQueue( ghDialogueQ ); ghDialogueQ=NULL; } // shutdown external static NPC faces ShutdownStaticExternalNPCFaces( ); // gte rid of portraits for cars UnLoadCarPortraits( ); // } void InitalizeStaticExternalNPCFaces( void ) { INT32 iCounter = 0; // go and grab all external NPC faces that are needed for the game who won't exist as soldiertypes if( fExternFacesLoaded == TRUE ) { return; } fExternFacesLoaded = TRUE; // // Code for loading miners' faces has been moved to LuaMines::InitMinerFaces ... // #ifdef JA2UB for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) { uiExternalStaticNPCFacesUB[ iCounter ] = ( UINT32 )InitFace( ( UINT8 )( uiExternalFaceProfileIdsUB[ iCounter ] ), NOBODY, FACE_FORCE_SMALL ); } #endif //for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) //{ // uiExternalStaticNPCFaces[ iCounter ] = ( UINT32 )InitFace( ( UINT8 )( uiExternalFaceProfileIds[ iCounter ] ), NOBODY, FACE_FORCE_SMALL ); //} // ... put Skyrider's face at index 0 uiExternalStaticNPCFaces.push_back(( UINT32 )InitFace( ( UINT8 )( SKYRIDER ), NOBODY, FACE_FORCE_SMALL )); // anv: and put Waldo too uiExternalStaticNPCFaces.push_back(( UINT32 )InitFace( ( UINT8 )( WALDO ), NOBODY, FACE_FORCE_SMALL )); return; } void ShutdownStaticExternalNPCFaces( void ) { INT32 iCounter = 0; if( fExternFacesLoaded == FALSE ) { return; } fExternFacesLoaded = FALSE; // remove all external npc faces //for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) //{ // DeleteFace( uiExternalStaticNPCFaces[ iCounter ] ); //} #ifdef JA2UB for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) { DeleteFace( uiExternalStaticNPCFacesUB[ iCounter ] ); } #endif for (std::vector::iterator face = uiExternalStaticNPCFaces.begin(); face != uiExternalStaticNPCFaces.end(); ++face) { DeleteFace(*face); } uiExternalStaticNPCFaces.clear(); } void EmptyDialogueQueue( ) { // If we have anything left in the queue, remove! if( ghDialogueQ != NULL ) { /* DEF: commented out because the Queue system ?? uses a contiguous memory block ??? for the queue so you cant delete a single node. The DeleteQueue, below, will free the entire memory block numDialogueItems = QueueSize( ghDialogueQ ); for ( cnt = numDialogueItems-1; cnt >= 0; cnt-- ) { if ( PeekQueue( ghDialogueQ, &QItem ) ) { MemFree( QItem ); } } */ // Delete list DeleteQueue( ghDialogueQ ); ghDialogueQ=NULL; // Recreate list ghDialogueQ = CreateQueue( INITIAL_Q_SIZE, sizeof( DIALOGUE_Q_STRUCT_PTR ) ); } gfWaitingForTriggerTimer = FALSE; } BOOLEAN DialogueQueueIsEmpty( ) { INT32 numDialogueItems; if( ghDialogueQ != NULL ) { numDialogueItems = QueueSize( ghDialogueQ ); if ( numDialogueItems == 0 ) { return( TRUE ); } } return( FALSE ); } BOOLEAN DialogueQueueIsEmptyOrSomebodyTalkingNow( ) { if ( gpCurrentTalkingFace != NULL ) { return( FALSE ); } if ( !DialogueQueueIsEmpty( ) ) { return( FALSE ); } return( TRUE ); } void DialogueAdvanceSpeech( ) { // Shut them up! InternalShutupaYoFace( gpCurrentTalkingFace->iID, FALSE ); } void StopAnyCurrentlyTalkingSpeech( ) { // ATE; Make sure guys stop talking.... if ( gpCurrentTalkingFace != NULL ) { InternalShutupaYoFace( gpCurrentTalkingFace->iID, TRUE ); } #ifdef JA2UB RemoveJerryMiloBrokenLaptopOverlay(); #endif } // ATE: Handle changes like when face goes from // 'external' to on the team panel... void HandleDialogueUIAdjustments( ) { SOLDIERTYPE *pSoldier; // OK, check if we are still taking if ( gpCurrentTalkingFace != NULL ) { if ( gpCurrentTalkingFace->fTalking ) { // ATE: Check for change in state for the guy currently talking on 'external' panel.... if ( gfFacePanelActive ) { pSoldier = FindSoldierByProfileID( gubCurrentTalkingID, FALSE ); if ( pSoldier ) { if ( 0 ) { // A change in plans here... // We now talk through the interface panel... if ( gpCurrentTalkingFace->iVideoOverlay != -1 ) { RemoveVideoOverlay( gpCurrentTalkingFace->iVideoOverlay ); gpCurrentTalkingFace->iVideoOverlay = -1; } gfFacePanelActive = FALSE; RemoveVideoOverlay( giTextBoxOverlay ); giTextBoxOverlay = -1; if ( fTextBoxMouseRegionCreated ) { MSYS_RemoveRegion( &gTextBoxMouseRegion ); fTextBoxMouseRegionCreated = FALSE; } // Setup UI again! CreateTalkingUI( gbUIHandlerID, pSoldier->iFaceIndex, pSoldier->ubProfile, pSoldier, gzQuoteStr ); } } } } } } void HandleDialogue( ) { INT32 iQSize; DIALOGUE_Q_STRUCT *QItem; static BOOLEAN fOldEngagedInConvFlagOn = FALSE; BOOLEAN fDoneTalking = FALSE; SOLDIERTYPE *pSoldier = NULL; CHAR16 zText[ 512 ]; CHAR16 zMoney[128]; // we don't want to just delay action of some events, we want to pause the whole queue, regardless of the event if( gfDialogueQueuePaused ) { return; } iQSize = QueueSize( ghDialogueQ ); if ( iQSize == 0 && gpCurrentTalkingFace == NULL ) { HandlePendingInitConv( ); } HandleCivQuote( ); // Alrighty, check for a change in state, do stuff appropriately.... // Turned on if ( fOldEngagedInConvFlagOn == FALSE && ( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) ) { // OK, we have just entered... fOldEngagedInConvFlagOn = TRUE; // pause game.. PauseGame(); LockPauseState( 14 ); } else if ( fOldEngagedInConvFlagOn == TRUE && !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) ) { // OK, we left... fOldEngagedInConvFlagOn = FALSE; // Unpause game.. UnLockPauseState(); UnPauseGame(); // if we're exiting boxing with the UI lock set then DON'T OVERRIDE THIS! if ( !(gTacticalStatus.bBoxingState == WON_ROUND || gTacticalStatus.bBoxingState == LOST_ROUND || gTacticalStatus.bBoxingState == DISQUALIFIED) && !( gTacticalStatus.uiFlags & IGNORE_ENGAGED_IN_CONV_UI_UNLOCK ) ) { guiPendingOverrideEvent = LU_ENDUILOCK; HandleTacticalUI( ); // ATE: If this is NOT the player's turn.. engage AI UI lock! if ( gTacticalStatus.ubCurrentTeam != gbPlayerNum ) { // Setup locked UI guiPendingOverrideEvent = LU_BEGINUILOCK; HandleTacticalUI( ); } } gTacticalStatus.uiFlags &= ( ~IGNORE_ENGAGED_IN_CONV_UI_UNLOCK ); } if ( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) { // Are we in here because of the dialogue system up? if ( !gfInTalkPanel ) { // ATE: NOT if we have a message box pending.... if ( guiPendingScreen != MSG_BOX_SCREEN && guiCurrentScreen != MSG_BOX_SCREEN ) { // No, so we should lock the UI! guiPendingOverrideEvent = LU_BEGINUILOCK; HandleTacticalUI( ); } } } // OK, check if we are still talking if ( gpCurrentTalkingFace != NULL ) { if ( gpCurrentTalkingFace->fTalking ) { // ATE: OK, MANAGE THE DISPLAY OF OUR CURRENTLY ACTIVE FACE IF WE / IT CHANGES STATUS // THINGS THAT CAN CHANGE STATUS: // CHANGE TO MAPSCREEN // CHANGE TO GAMESCREEN // CHANGE IN MERC STATUS TO BE IN A SQUAD // CHANGE FROM TEAM TO INV INTERFACE // Where are we and where did this face once exist? if ( guiScreenIDUsedWhenUICreated == GAME_SCREEN && guiCurrentScreen == MAP_SCREEN ) { // GO FROM GAMESCREEN TO MAPSCREEN // REMOVE OLD UI // Set face inactive! //gpCurrentTalkingFace->fCanHandleInactiveNow = TRUE; //SetAutoFaceInActive( gpCurrentTalkingFace->iID ); //gfFacePanelActive = FALSE; // delete face panel if there is one! if ( gfFacePanelActive ) { // Set face inactive! if ( gpCurrentTalkingFace->iVideoOverlay != -1 ) { RemoveVideoOverlay( gpCurrentTalkingFace->iVideoOverlay ); gpCurrentTalkingFace->iVideoOverlay = -1; } if ( fExternFaceBoxRegionCreated ) { fExternFaceBoxRegionCreated = FALSE; MSYS_RemoveRegion(&(gFacePopupMouseRegion) ); } // Set face inactive.... gpCurrentTalkingFace->fCanHandleInactiveNow = TRUE; SetAutoFaceInActive( gpCurrentTalkingFace->iID ); HandleTacticalSpeechUI( gubCurrentTalkingID, gpCurrentTalkingFace->iID ); // ATE: Force mapscreen to set face active again..... fReDrawFace = TRUE; DrawFace( bSelectedInfoChar ); gfFacePanelActive = FALSE; } guiScreenIDUsedWhenUICreated = guiCurrentScreen; } else if ( guiScreenIDUsedWhenUICreated == MAP_SCREEN && guiCurrentScreen == GAME_SCREEN ) { HandleTacticalSpeechUI( gubCurrentTalkingID, gpCurrentTalkingFace->iID ); guiScreenIDUsedWhenUICreated = guiCurrentScreen; } return; } else { // Check special flags // If we are done, check special face flag for trigger NPC! if ( gpCurrentTalkingFace->uiFlags & FACE_PCTRIGGER_NPC ) { // Decrement refrence count... giNPCReferenceCount--; TriggerNPCRecord( (UINT8)gpCurrentTalkingFace->uiUserData1, (UINT8)gpCurrentTalkingFace->uiUserData2 ); //Reset flag! gpCurrentTalkingFace->uiFlags &= (~FACE_PCTRIGGER_NPC ); } if ( gpCurrentTalkingFace->uiFlags & FACE_MODAL ) { gpCurrentTalkingFace->uiFlags &= (~FACE_MODAL ); EndModalTactical( ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Ending Modal Tactical Quote." ); } if ( gpCurrentTalkingFace->uiFlags & FACE_TRIGGER_PREBATTLE_INT ) { UnLockPauseState(); InitPreBattleInterface( (GROUP*)gpCurrentTalkingFace->uiUserData1, TRUE ); //Reset flag! gpCurrentTalkingFace->uiFlags &= (~FACE_TRIGGER_PREBATTLE_INT ); } gpCurrentTalkingFace = NULL; gubCurrentTalkingID = NO_PROFILE; gTacticalStatus.ubLastQuoteProfileNUm = NO_PROFILE; fDoneTalking = TRUE; } } if( ( fDoneTalking ) && ( fWasPausedDuringDialogue ) ) { fWasPausedDuringDialogue = FALSE; // unlock pause state UnLockPauseState(); UnPauseGame(); } #ifdef JA2UB if ( iQSize == 0 ) { if( gfMorrisShouldSayHi ) { SOLDIERTYPE * pMorris; SOLDIERTYPE * pSoldier; INT16 sPlayerGridNo; UINT8 ubPlayerID; UINT8 ubQualifiedSoldierIDArray[ NUM_MERCS_WITH_NEW_QUOTES ]; UINT8 ubNumQualifiedMercs=0; UINT8 ubCnt=0; if( !( gMercProfiles[ MORRIS_UB ].ubMiscFlags2 & PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE ) ) { pMorris = FindSoldierByProfileID( MORRIS_UB, FALSE ); if ( pMorris && pMorris->stats.bLife >= OKLIFE ) { sPlayerGridNo = ClosestPC( pMorris, NULL ); if (sPlayerGridNo != NOWHERE ) { ubPlayerID = WhoIsThere2( sPlayerGridNo, 0 ); if (ubPlayerID != NOBODY) { InitiateConversation( pMorris, MercPtrs[ ubPlayerID ], NPC_INITIAL_QUOTE, 0 ); gMercProfiles[ pMorris->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE; } } } } else { //Get the # of qualified mercs ubNumQualifiedMercs = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( ubQualifiedSoldierIDArray, NULL ); //if there is some qualified mercs if( ubNumQualifiedMercs != 0 ) { //loop through all the mercs for( ubCnt=0; ubCntusQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_EXT_MORRIS; } } //Morris should say a new quote // CharacterDialogue( MORRIS, QUOTE_ATTACKED_BY_MULTIPLE_CREATURES, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI, FALSE, FALSE ); TriggerNPCRecord( MORRIS_UB, 2 ); gfMorrisShouldSayHi = FALSE; } } return; } #else //Ja25: no mike if ( iQSize == 0 ) { if ( gfMikeShouldSayHi == TRUE ) { SOLDIERTYPE * pMike; INT32 sPlayerGridNo; UINT8 ubPlayerID; pMike = FindSoldierByProfileID( MIKE, FALSE ); if ( pMike ) { sPlayerGridNo = ClosestPC( pMike, NULL ); if (!TileIsOutOfBounds(sPlayerGridNo)) { ubPlayerID = WhoIsThere2( sPlayerGridNo, 0 ); if (ubPlayerID != NOBODY) { InitiateConversation( pMike, MercPtrs[ ubPlayerID ], NPC_INITIAL_QUOTE, 0 ); gMercProfiles[ pMike->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE; // JA2Gold: special hack value of 2 to prevent dialogue from coming up more than once gfMikeShouldSayHi = 2; } } } } return; } #endif // ATE: Remove any civ quotes.... // ShutDownQuoteBoxIfActive( TRUE ); // If here, pick current one from queue and play // Get new one RemfromQueue( ghDialogueQ, &QItem ); // If we are in auto bandage, ignore any quotes! if ( gTacticalStatus.fAutoBandageMode ) { if( QItem->fPauseTime ) { UnLockPauseState(); UnPauseGame(); } // Delete memory MemFree( QItem ); return; } // Check time delay // Alrighty, check if this one is to be delayed until we gain control. // If so, place it back in! if ( QItem->fDelayed ) { // Are we not in our turn and not interrupted if ( gTacticalStatus.ubCurrentTeam != gbPlayerNum ) { //Place back in! // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return; } } // ATE: OK: If a battle sound, and delay value was given, set time stamp // now... if ( QItem->uiSpecialEventFlag == DIALOGUE_SPECIAL_EVENT_DO_BATTLE_SND ) { if ( QItem->uiSpecialEventData2 != 0 ) { if ( ( GetJA2Clock( ) - QItem->iTimeStamp ) < QItem->uiSpecialEventData2 ) { //Place back in! // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return; } } } // Try to find soldier... pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, TRUE ); if ( pSoldier != NULL ) { if ( SoundIsPlaying( pSoldier->uiBattleSoundID ) ) { //Place back in! // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return; } } if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) && ( QItem->uiSpecialEventFlag == 0 ) ) { QItem->fPauseTime = TRUE; } if( QItem->fPauseTime ) { if( GamePaused( ) == FALSE ) { PauseGame(); LockPauseState( 15 ); fWasPausedDuringDialogue = TRUE; } } // Now play first item in queue // If it's not a 'special' dialogue event, continue if ( QItem->uiSpecialEventFlag == 0 ) { if( pSoldier ) { // wake grunt up to say if( pSoldier->flags.fMercAsleep ) { pSoldier->flags.fMercAsleep = FALSE; // refresh map screen fCharacterInfoPanelDirty = TRUE; fTeamPanelDirty = TRUE; // allow them to go back to sleep TacticalCharacterDialogueWithSpecialEvent( pSoldier, QItem->usQuoteNum, DIALOGUE_SPECIAL_EVENT_SLEEP, 1,0 ); } } gTacticalStatus.ubLastQuoteSaid = (UINT8)QItem->usQuoteNum; gTacticalStatus.ubLastQuoteProfileNUm = (UINT8)QItem->ubCharacterNum; // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; #ifdef JA2UB //Ja25: test if( QItem->ubCharacterNum == MORRIS_UB ) //MORRIS { if( QItem->usQuoteNum == 0 ) { } } #endif ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->fFromSoldier ); } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SKIP_A_FRAME ) { } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE ) { // locking or unlocking? if( QItem->uiSpecialEventData ) { switch( QItem->uiSpecialEventData2 ) { case( MAP_SCREEN ): fLockOutMapScreenInterface = TRUE; break; } } else { switch( QItem->uiSpecialEventData2 ) { case( MAP_SCREEN ): fLockOutMapScreenInterface = FALSE; break; } } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_REMOVE_EPC ) { gMercProfiles[ (UINT8) QItem->uiSpecialEventData ].ubMiscFlags &= ~PROFILE_MISC_FLAG_FORCENPCQUOTE; UnRecruitEPC( (UINT8) QItem->uiSpecialEventData ); ReBuildCharactersList(); } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CONTRACT_WANTS_TO_RENEW ) { HandleMercIsWillingToRenew( (UINT8)QItem->uiSpecialEventData ); } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CONTRACT_NOGO_TO_RENEW ) { HandleMercIsNotWillingToRenew( (UINT8)QItem->uiSpecialEventData ); } else { if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_USE_ALTERNATE_FILES ) { gfUseAlternateDialogueFile = TRUE; // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->fFromSoldier ); gfUseAlternateDialogueFile = FALSE; } // We could have a special flag, but dialogue as well else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_PCTRIGGERNPC ) { // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->fFromSoldier ); // Setup face with data! gpCurrentTalkingFace->uiFlags |= FACE_PCTRIGGER_NPC; gpCurrentTalkingFace->uiUserData1 = QItem->uiSpecialEventData; gpCurrentTalkingFace->uiUserData2 = QItem->uiSpecialEventData2; } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SHOW_CONTRACT_MENU ) { // Setup face pointer // ATE: THis is working with MARK'S STUFF :( // Need this stuff so that bSelectedInfoChar is set... SetInfoChar( pSoldier->ubID ); fShowContractMenu = TRUE; RebuildContractBoxForMerc( pSoldier ); bSelectedContractChar = bSelectedInfoChar; pProcessingSoldier = pSoldier; fProcessingAMerc = TRUE; } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_DO_BATTLE_SND ) { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, FALSE ); // Do battle snounds...... if ( pSoldier ) { pSoldier->InternalDoMercBattleSound( (UINT8)QItem->uiSpecialEventData, 0 ); } } if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SIGNAL_ITEM_LOCATOR_START ) { // Turn off item lock for locators... gTacticalStatus.fLockItemLocators = FALSE; // Slide to location! SlideToLocation( 0, QItem->uiSpecialEventData ); // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->fFromSoldier ); } if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_ENABLE_AI ) { //OK, allow AI to work now.... UnPauseAI(); } if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_TRIGGERPREBATTLEINTERFACE ) { UnLockPauseState(); // Flugente: what hideous idiocy is this? We cast a UINT32 as GROUP*? This is likely to return garbage. // Why the hell not use the id instead? InitPreBattleInterface( (GROUP*)QItem->uiSpecialEventData, TRUE ); /*GROUP* pGroup = GetGroup( (UINT8)QItem->uiSpecialEventData ); if ( pGroup ) InitPreBattleInterface( pGroup, TRUE );*/ } if( QItem->uiSpecialEventFlag & DIALOGUE_ADD_EVENT_FOR_SOLDIER_UPDATE_BOX ) { INT32 iReason = 0; SOLDIERTYPE *pUpdateSoldier = NULL; iReason = QItem->uiSpecialEventData; switch( iReason ) { case( UPDATE_BOX_REASON_ADDSOLDIER ): pUpdateSoldier = &Menptr[ QItem->uiSpecialEventData2 ]; if( pUpdateSoldier->bActive == TRUE ) { AddSoldierToUpdateBox( pUpdateSoldier ); } break; case( UPDATE_BOX_REASON_SET_REASON ): SetSoldierUpdateBoxReason( QItem->uiSpecialEventData2 ); break; case( UPDATE_BOX_REASON_SHOW_BOX ): ShowUpdateBox( ); break; } } if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_BEGINPREBATTLEINTERFACE ) { // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->fFromSoldier ); // Setup face with data! gpCurrentTalkingFace->uiFlags |= FACE_TRIGGER_PREBATTLE_INT; gpCurrentTalkingFace->uiUserData1 = QItem->uiSpecialEventData; gpCurrentTalkingFace->uiUserData2 = QItem->uiSpecialEventData2; } if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SHOPKEEPER ) { if( QItem->uiSpecialEventData < 3 ) { // post a notice if the player wants to withdraw money from thier account to cover the difference? swprintf( zMoney, L"%d", QItem->uiSpecialEventData2 ); InsertCommasForDollarFigure( zMoney ); InsertDollarSignInToString( zMoney ); } switch( QItem->uiSpecialEventData ) { case( 0 ): swprintf( zText, SkiMessageBoxText[ SKI_SHORT_FUNDS_TEXT ], zMoney ); //popup a message stating the player doesnt have enough money DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_OK, ConfirmDontHaveEnoughForTheDealerMessageBoxCallBack ); break; case( 1 ): //if the player is trading items swprintf( zText, SkiMessageBoxText[ SKI_QUESTION_TO_DEDUCT_MONEY_FROM_PLAYERS_ACCOUNT_TO_COVER_DIFFERENCE ], zMoney ); //ask them if we should deduct money out the players account to cover the difference DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack ); break; case( 2 ): swprintf( zText, SkiMessageBoxText[ SKI_QUESTION_TO_DEDUCT_MONEY_FROM_PLAYERS_ACCOUNT_TO_COVER_COST ], zMoney ); //ask them if we should deduct money out the players account to cover the difference DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zText, SHOPKEEPER_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack ); break; case( 3 ): // this means a dialogue event is in progress giShopKeepDialogueEventinProgress = QItem->uiSpecialEventData2; break; case( 4 ): // this means a dialogue event has ended giShopKeepDialogueEventinProgress = -1; break; case( 5 ): // this means a dialogue event has ended gfSKIScreenExit = TRUE; break; case( 6 ): if( guiCurrentScreen == SHOPKEEPER_SCREEN ) { DisableButton( guiSKI_TransactionButton ); } break; case( 7 ): if( guiCurrentScreen == SHOPKEEPER_SCREEN ) { EnableButton( guiSKI_TransactionButton ); } break; } } if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_EXIT_MAP_SCREEN ) { // select sector ChangeSelectedMapSector( ( INT16 )QItem->uiSpecialEventData, ( INT16 )QItem->uiSpecialEventData2, ( INT8 )QItem->uiSpecialEventData3 ); RequestTriggerExitFromMapscreen( MAP_EXIT_TO_TACTICAL ); } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_DISPLAY_STAT_CHANGE ) { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, FALSE ); if ( pSoldier ) { CHAR16 wTempString[ 128 ]; // tell player about stat increase BuildStatChangeString( wTempString, pSoldier->name, ( BOOLEAN ) QItem->uiSpecialEventData, ( INT16 ) QItem->uiSpecialEventData2, ( UINT8 ) QItem->uiSpecialEventData3 ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, wTempString ); } } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_UNSET_ARRIVES_FLAG ) { gTacticalStatus.bMercArrivingQuoteBeingUsed = FALSE; } /* else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_DISPLAY_INVASION_MESSAGE ) { HandlePlayerNotifyInvasionByEnemyForces( (INT16)(QItem->uiSpecialEventData % MAP_WORLD_X), (INT16)(QItem->uiSpecialEventData / MAP_WORLD_X), 0, NULL ); } */ else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; gubCurrentTalkingID = QItem->ubCharacterNum; // handle the monologue event HandleSkyRiderMonologueEvent( QItem->uiSpecialEventData, QItem->uiSpecialEventData2 ); } if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT ) { // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->ubCharacterNum; // set up the mine highlgith events SetUpAnimationOfMineSectors( QItem->uiSpecialEventData ); } //Switch on our special events if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_GIVE_ITEM ) { if ( QItem->bUIHandlerID == DIALOGUE_NPC_UI ) { HandleNPCItemGiven( (UINT8)QItem->uiSpecialEventData, (OBJECTTYPE*)QItem->uiSpecialEventData2, (INT8)QItem->uiSpecialEventData3 ); } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_TRIGGER_NPC ) { if ( QItem->bUIHandlerID == DIALOGUE_NPC_UI ) { HandleNPCTriggerNPC( (UINT8)QItem->uiSpecialEventData, (UINT8)QItem->uiSpecialEventData2, (BOOLEAN)QItem->uiSpecialEventData3, (UINT8)QItem->uiSpecialEventData4 ); } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_GOTO_GRIDNO ) { if ( QItem->bUIHandlerID == DIALOGUE_NPC_UI ) { HandleNPCGotoGridNo( (UINT8)QItem->uiSpecialEventData, (UINT16)QItem->uiSpecialEventData2, (UINT8)QItem->uiSpecialEventData3 );//dnl!!! } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_DO_ACTION ) { if ( QItem->bUIHandlerID == DIALOGUE_NPC_UI ) { HandleNPCDoAction( (UINT8)QItem->uiSpecialEventData, (UINT16)QItem->uiSpecialEventData2, (UINT8)QItem->uiSpecialEventData3 ); } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CLOSE_PANEL ) { if ( QItem->bUIHandlerID == DIALOGUE_NPC_UI ) { HandleNPCClosePanel( ); } } else if ( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SHOW_UPDATE_MENU ) { SetUpdateBoxFlag( TRUE ); } #ifdef JA2UB else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_JERRY_MILO ) { //switch on the quote that is being spoken switch( QItem->uiSpecialEventData ) { case JM_SE__SHOW_RADIO_LOCATOR: HandleShowingRadioLocatorsInMorrisArea(); break; case JM_SE__HEADING_TO_TRACONA: // play the heli crash video SetIntroType( INTRO_HELI_CRASH ); //Go to the intro screen RequestTriggerExitFromMapscreen( MAP_EXIT_TO_INTRO_SCREEN ); break; default: //nothing break; } } #else //Ja25: removed the flag, no militia else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CONTINUE_TRAINING_MILITIA ) { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( ( UINT8 )( QItem->uiSpecialEventData ), FALSE ); // if soldier valid... if( pSoldier != NULL ) { HandleInterfaceMessageForContinuingTrainingMilitia( pSoldier ); } } #endif else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_ENTER_MAPSCREEN ) { if( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) { gfEnteringMapScreen = TRUE; fEnterMapDueToContract = TRUE; } } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING ) { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, FALSE ); // if soldier valid... if( pSoldier != NULL ) { // .. remove the fired soldier again BeginStrategicRemoveMerc( pSoldier, (UINT8)QItem->uiSpecialEventData ); } } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING_NO_ASK_EQUIP ) { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, FALSE ); // if soldier valid... if( pSoldier != NULL ) { // .. remove the fired soldier again StrategicRemoveMerc( pSoldier ); } } else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_MULTIPURPOSE ) { // anv: handle snitch event if( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_SNITCH_DIALOGUE ) { gTacticalStatus.ubLastQuoteSaid = (UINT8)QItem->usQuoteNum; gTacticalStatus.ubLastQuoteProfileNUm = (UINT8)QItem->ubCharacterNum; // Flugente: only set up face if we can access correctly if ( QItem->iFaceIndex >= 0 ) { // Setup face pointer gpCurrentTalkingFace = &gFacesData[ QItem->iFaceIndex ]; } gubCurrentTalkingID = QItem->iFaceIndex; //ExecuteCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE ); ExecuteSnitchCharacterDialogue( QItem->ubCharacterNum, QItem->usQuoteNum, QItem->iFaceIndex, QItem->bUIHandlerID, QItem->uiSpecialEventData2, QItem->uiSpecialEventData3, QItem->uiSpecialEventData4 ); } #ifdef JA2UB //JA25 UB if ( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_TEAM_MEMBERS_DONE_TALKING ) { HandleEveryoneDoneTheirEndGameQuotes(); } else { // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( (UINT8)QItem->uiSpecialEventData, FALSE ); // Now, wake these sluts up and have them say quote... pSoldier->fIgnoreGetupFromCollapseCheck = FALSE; //Get the soldier up pSoldier->bCollapsed = FALSE; pSoldier->ChangeSoldierStance( ANIM_STAND ); //if the soldier is Jerry if( FindSoldierByProfileID( JERRY_MILO_UB, FALSE ) == pSoldier ) //JERRY { //Play the sound of the Antena breaking PlayJA2SampleFromFile( "SOUNDS\\Metal Antenna Crunch.wav", RATE_11025, HIGHVOLUME, 1, MIDDLE ); } //Turn off the flag saying we are doing the initial heli crash gfFirstTimeInGameHeliCrash = FALSE; //if all the mercs are done their talk if( AreAllTheMercsFinishedSayingThereInitialHeliCrashQuotes() ) { //Trigger Jerry Milo's script record 10 ( call action 301 ) //AA //if ( gGameUBOptions.InGameHeliCrash == TRUE ) if ( gGameUBOptions.JerryQuotes == TRUE ) DelayedMercQuote( JERRY_MILO_UB , 0xffff, 4 ); //JERRY //End the ui Lock guiPendingOverrideEvent = LU_ENDUILOCK; } } } #else //Ja25 No queen if ( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_DONE_KILLING_DEIDRANNA ) { HandleDoneLastKilledQueenQuote( ); } else if ( QItem->uiSpecialEventData & MULTIPURPOSE_SPECIAL_EVENT_TEAM_MEMBERS_DONE_TALKING ) { HandleDoneLastEndGameQuote( ); } } #endif else if( QItem->uiSpecialEventFlag & DIALOGUE_SPECIAL_EVENT_SLEEP ) { // no soldier, leave now if( pSoldier == NULL ) { return; } // wake merc up or put them back down? if( QItem->uiSpecialEventData == 1 ) { pSoldier->flags.fMercAsleep = TRUE; } else { pSoldier->flags.fMercAsleep = FALSE; } // refresh map screen fCharacterInfoPanelDirty = TRUE; fTeamPanelDirty = TRUE; } } // grab soldier ptr from profile ID pSoldier = FindSoldierByProfileID( QItem->ubCharacterNum, FALSE ); if ( pSoldier && pSoldier->bTeam == gbPlayerNum ) { CheckForStopTimeQuotes( QItem->usQuoteNum ); } if( QItem->fPauseTime ) { fWasPausedDuringDialogue = TRUE; } // Delete memory MemFree( QItem ); } BOOLEAN GetDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSoundID, CHAR8 *zSoundString ); BOOLEAN GetSnitchDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSound1ID, UINT32 *puiSound2ID, UINT32 *puiSound3ID, CHAR8 zSoundFiles[][64], UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ); BOOLEAN DelayedTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ) { if ( pSoldier->ubProfile == NO_PROFILE ) { return( FALSE ); } if (pSoldier->stats.bLife < CONSCIOUSNESS ) return( FALSE ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); if ( (AM_A_ROBOT( pSoldier )) ) { return( FALSE ); } if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) return( FALSE ); if( pSoldier->bAssignment == ASSIGNMENT_POW ) { return( FALSE ); } return( CharacterDialogue( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE, TRUE ) ); } BOOLEAN TacticalCharacterDialogueWithSpecialEvent( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum, UINT32 uiFlag, UINT32 uiData1, UINT32 uiData2 ) { if ( pSoldier->ubProfile == NO_PROFILE ) { return( FALSE ); } if ( uiFlag != DIALOGUE_SPECIAL_EVENT_DO_BATTLE_SND && uiData1 != BATTLE_SOUND_DIE1 ) { if (pSoldier->stats.bLife < CONSCIOUSNESS ) return( FALSE ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); } return( CharacterDialogueWithSpecialEvent( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE, FALSE, uiFlag, uiData1, uiData2 ) ); } BOOLEAN TacticalCharacterDialogueWithSpecialEventEx( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum, UINT32 uiFlag, UINT32 uiData1, UINT32 uiData2, UINT32 uiData3 ) { if ( pSoldier->ubProfile == NO_PROFILE ) { return( FALSE ); } if ( uiFlag != DIALOGUE_SPECIAL_EVENT_DO_BATTLE_SND && uiData1 != BATTLE_SOUND_DIE1 ) { if (pSoldier->stats.bLife < CONSCIOUSNESS ) return( FALSE ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); if ( (AM_A_ROBOT( pSoldier )) ) { return( FALSE ); } if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) return( FALSE ); if( pSoldier->bAssignment == ASSIGNMENT_POW ) { return( FALSE ); } } return( CharacterDialogueWithSpecialEventEx( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE, FALSE, uiFlag, uiData1, uiData2, uiData3 ) ); } BOOLEAN TacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ) { // Haydent if(is_client) { return(FALSE); //somewhere amongst all this it causes a puase of merc movement while making the quote which throws out the movement sync between clients... : hayden. } if ( pSoldier->ubProfile == NO_PROFILE ) { return( FALSE ); } #ifdef JA2UB //Ja25 no meanwhiles #else if ( AreInMeanwhile( ) ) { return( FALSE ); } #endif if (pSoldier->stats.bLife < CONSCIOUSNESS ) return( FALSE ); if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) return( FALSE ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); if ( (AM_A_ROBOT( pSoldier )) ) { return( FALSE ); } if( pSoldier->bAssignment == ASSIGNMENT_POW ) { return( FALSE ); } // OK, let's check if this is the exact one we just played, if so, skip. if ( pSoldier->ubProfile == gTacticalStatus.ubLastQuoteProfileNUm && usQuoteNum == gTacticalStatus.ubLastQuoteSaid ) { return( FALSE ); } // If we are a robot, play the controller's quote! if ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) { if ( pSoldier->CanRobotBeControlled( ) ) { return( TacticalCharacterDialogue( MercPtrs[ pSoldier->ubRobotRemoteHolderID ], usQuoteNum ) ); } else { return( FALSE ); } } if ( AM_AN_EPC( pSoldier ) && !(gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_FORCENPCQUOTE) ) return( FALSE ); // Check for logging of me too bleeds... if ( usQuoteNum == QUOTE_STARTING_TO_BLEED ) { if ( gubLogForMeTooBleeds ) { // If we are greater than one... if ( gubLogForMeTooBleeds > 1 ) { //Replace with me too.... usQuoteNum = QUOTE_ME_TOO; } gubLogForMeTooBleeds++; } } // Flugente: if we don't have a face index, then don't do a dialogue here... if ( pSoldier->iFaceIndex <= -1 ) return( FALSE ); return( CharacterDialogue( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_TACTICAL_UI, TRUE, FALSE ) ); } BOOLEAN SnitchTacticalCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum, UINT8 ubEventType, UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ) { // Haydent if(is_client) { return(FALSE); //somewhere amongst all this it causes a puase of merc movement while making the quote which throws out the movement sync between clients... : hayden. } if ( pSoldier->ubProfile == NO_PROFILE ) { return( FALSE ); } #if (defined JA2UB) //Ja25 no meanwhiles #else if ( AreInMeanwhile( ) ) { return( FALSE ); } #endif if (pSoldier->stats.bLife < CONSCIOUSNESS ) return( FALSE ); if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) return( FALSE ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); if ( (AM_A_ROBOT( pSoldier )) ) { return( FALSE ); } if( pSoldier->bAssignment == ASSIGNMENT_POW ) { return( FALSE ); } // OK, let's check if this is the exact one we just played, if so, skip. //if ( pSoldier->ubProfile == gTacticalStatus.ubLastQuoteProfileNUm && // usQuoteNum == gTacticalStatus.ubLastQuoteSaid ) //{ // return( FALSE ); //} if ( AM_AN_EPC( pSoldier ) && !(gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags & PROFILE_MISC_FLAG_FORCENPCQUOTE) ) return( FALSE ); return( SnitchCharacterDialogue( pSoldier->ubProfile, usQuoteNum, pSoldier->iFaceIndex, DIALOGUE_SPECIAL_EVENT_MULTIPURPOSE, MULTIPURPOSE_SPECIAL_EVENT_SNITCH_DIALOGUE, ubTargetProfile, ubTargetProfile, ubSecondaryTargetProfile, DIALOGUE_TACTICAL_UI, TRUE, FALSE ) ); } // This function takes a profile num, quote num, faceindex and a UI hander ID. // What it does is queues up the dialog to be ultimately loaded/displayed // FACEINDEX // The face index is an index into an ACTIVE face. The face is considered to // be active, and if it's not, either that has to be handled by the UI handler // ir nothing will show. What this function does is set the face to talking, // and the face sprite system should handle the rest. // bUIHandlerID // Because this could be used in any place, the UI handleID is used to differentiate // places in the game. For example, specific things happen in the tactical engine // that may not be the place where in the AIM contract screen uses..... // NB; The queued system is not yet implemented, but will be transpatent to the caller.... BOOLEAN CharacterDialogueWithSpecialEvent( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed, UINT32 uiFlag, UINT32 uiData1, UINT32 uiData2 ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->ubCharacterNum = ubCharacterNum; QItem->usQuoteNum = usQuoteNum; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); QItem->fFromSoldier = fFromSoldier; QItem->fDelayed = fDelayed; // Set flag for special event QItem->uiSpecialEventFlag = uiFlag; QItem->uiSpecialEventData = uiData1; QItem->uiSpecialEventData2 = uiData2; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); if ( uiFlag & DIALOGUE_SPECIAL_EVENT_PCTRIGGERNPC ) { // Increment refrence count... giNPCReferenceCount++; } return( TRUE ); } BOOLEAN CharacterDialogueWithSpecialEventEx( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed, UINT32 uiFlag, UINT32 uiData1, UINT32 uiData2, UINT32 uiData3 ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->ubCharacterNum = ubCharacterNum; QItem->usQuoteNum = usQuoteNum; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); QItem->fFromSoldier = fFromSoldier; QItem->fDelayed = fDelayed; // Set flag for special event QItem->uiSpecialEventFlag = uiFlag; QItem->uiSpecialEventData = uiData1; QItem->uiSpecialEventData2 = uiData2; QItem->uiSpecialEventData3 = uiData3; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); if ( uiFlag & DIALOGUE_SPECIAL_EVENT_PCTRIGGERNPC ) { // Increment refrence count... giNPCReferenceCount++; } return( TRUE ); } BOOLEAN CharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->ubCharacterNum = ubCharacterNum; QItem->usQuoteNum = usQuoteNum; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); QItem->fFromSoldier = fFromSoldier; QItem->fDelayed = fDelayed; // check if pause already locked, if so, then don't mess with it if( gfLockPauseState == FALSE ) { QItem->fPauseTime = fPausedTimeDuringQuote; } fPausedTimeDuringQuote = FALSE; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return( TRUE ); } BOOLEAN SnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, UINT32 uiSpecialEventData3, UINT32 uiSpecialEventData4, UINT8 bUIHandlerID, BOOLEAN fFromSoldier, BOOLEAN fDelayed ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->ubCharacterNum = ubCharacterNum; QItem->usQuoteNum = usQuoteNum; QItem->uiSpecialEventFlag = uiSpecialEventFlag; QItem->uiSpecialEventData = uiSpecialEventData1; QItem->uiSpecialEventData2 = uiSpecialEventData2; QItem->uiSpecialEventData3 = uiSpecialEventData3; QItem->uiSpecialEventData4 = uiSpecialEventData4; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); QItem->fFromSoldier = fFromSoldier; QItem->fDelayed = fDelayed; // check if pause already locked, if so, then don't mess with it if( gfLockPauseState == FALSE ) { QItem->fPauseTime = fPausedTimeDuringQuote; } fPausedTimeDuringQuote = FALSE; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return( TRUE ); } BOOLEAN SpecialCharacterDialogueEvent( UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, UINT32 uiSpecialEventData3, INT32 iFaceIndex, UINT8 bUIHandlerID ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->uiSpecialEventFlag = uiSpecialEventFlag; QItem->uiSpecialEventData = uiSpecialEventData1; QItem->uiSpecialEventData2 = uiSpecialEventData2; QItem->uiSpecialEventData3 = uiSpecialEventData3; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); // if paused state not already locked if( gfLockPauseState == FALSE ) { QItem->fPauseTime = fPausedTimeDuringQuote; } fPausedTimeDuringQuote = FALSE; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return( TRUE ); } BOOLEAN SpecialCharacterDialogueEventWithExtraParam( UINT32 uiSpecialEventFlag, UINT32 uiSpecialEventData1, UINT32 uiSpecialEventData2, UINT32 uiSpecialEventData3, UINT32 uiSpecialEventData4, INT32 iFaceIndex, UINT8 bUIHandlerID ) { DIALOGUE_Q_STRUCT *QItem; // Allocate new item QItem = (DIALOGUE_Q_STRUCT *) MemAlloc( sizeof( DIALOGUE_Q_STRUCT ) ); memset( QItem, 0, sizeof( DIALOGUE_Q_STRUCT ) ); QItem->uiSpecialEventFlag = uiSpecialEventFlag; QItem->uiSpecialEventData = uiSpecialEventData1; QItem->uiSpecialEventData2 = uiSpecialEventData2; QItem->uiSpecialEventData3 = uiSpecialEventData3; QItem->uiSpecialEventData4 = uiSpecialEventData4; QItem->iFaceIndex = iFaceIndex; QItem->bUIHandlerID = bUIHandlerID; QItem->iTimeStamp = GetJA2Clock( ); // if paused state not already locked if( gfLockPauseState == FALSE ) { QItem->fPauseTime = fPausedTimeDuringQuote; } fPausedTimeDuringQuote = FALSE; // Add to queue ghDialogueQ = AddtoQueue( ghDialogueQ, &QItem ); return( TRUE ); } BOOLEAN ExecuteCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, BOOLEAN fFromSoldier ) { CHAR8 zSoundString[ 164 ]; UINT32 uiSoundID; SOLDIERTYPE *pSoldier; // Check if we are dead now or not....( if from a soldier... ) // Try to find soldier... pSoldier = FindSoldierByProfileID( ubCharacterNum, TRUE ); if ( pSoldier != NULL ) { // Check vital stats if (pSoldier->stats.bLife < CONSCIOUSNESS ) { return( FALSE ); } if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) return( FALSE ); if ( (AM_A_ROBOT( pSoldier )) ) { return( FALSE ); } if (pSoldier->stats.bLife < OKLIFE && usQuoteNum != QUOTE_SERIOUSLY_WOUNDED ) { return( FALSE ); } if( pSoldier->bAssignment == ASSIGNMENT_POW ) { return( FALSE ); } // sleeping guys don't talk.. go to standby to talk if( pSoldier->flags.fMercAsleep == TRUE ) { // check if the soldier was compaining about lack of sleep and was alseep, if so, leave them alone if( ( usQuoteNum == QUOTE_NEED_SLEEP ) || ( usQuoteNum == QUOTE_OUT_OF_BREATH ) ) { // leave them alone return ( TRUE ); } // may want to wake up any character that has VERY important dialogue to say // MC to flesh out } // now being used in a different way... /* if ( ( (usQuoteNum == QUOTE_PERSONALITY_TRAIT && (gMercProfiles[ubCharacterNum].bDisability == FORGETFUL || gMercProfiles[ubCharacterNum].bDisability == CLAUSTROPHOBIC || gMercProfiles[ubCharacterNum].bDisability == NERVOUS || gMercProfiles[ubCharacterNum].bDisability == NONSWIMMER || gMercProfiles[ubCharacterNum].bDisability == FEAR_OF_INSECTS)) //usQuoteNum == QUOTE_STARTING_TO_WHINE || #ifdef JA2BETAVERSION || usQuoteNum == QUOTE_WHINE_EQUIPMENT) && (guiCurrentScreen != QUEST_DEBUG_SCREEN) ) #else ) ) #endif { // This quote might spawn another quote from someone iLoop = 0; for ( pTeamSoldier = MercPtrs[ iLoop ]; iLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; iLoop++,pTeamSoldier++ ) { if ( (pTeamSoldier->ubProfile != ubCharacterNum) && (OK_INSECTOR_MERC( pTeamSoldier )) && (SpacesAway( pSoldier->sGridNo, pTeamSoldier->sGridNo ) < 5) ) { // if this merc disliked the whining character sufficiently and hasn't already retorted if ( gMercProfiles[ pTeamSoldier->ubProfile ].bMercOpinion[ ubCharacterNum ] < -2 && !( pTeamSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_ANNOYING_MERC ) ) { // make a comment! TacticalCharacterDialogue( pTeamSoldier, QUOTE_ANNOYING_PC ); pTeamSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_ANNOYING_MERC; break; } } } } */ } else { // If from a soldier, and he does not exist anymore, donot play! if ( fFromSoldier ) { return( FALSE ); } } // anv: have to do it now for single sounds subsequentsounds.ubMaxSndCounter = 0; // Check face index CHECKF( iFaceIndex != -1 ); if ( !GetDialogue( ubCharacterNum, usQuoteNum, DIALOGUESIZE, gzQuoteStr, &uiSoundID, zSoundString) ) { return( FALSE ); } if( bUIHandlerID == DIALOGUE_EXTERNAL_NPC_UI ) { // external NPC SetFaceTalking( iFaceIndex , zSoundString, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); } else { // start "talking" system (portrait animation and start wav sample) SetFaceTalking( iFaceIndex, zSoundString, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); } // pSoldier can be null here... ( if NOT from an alive soldier ) CreateTalkingUI( bUIHandlerID, iFaceIndex, ubCharacterNum, pSoldier, gzQuoteStr ); // Set global handleer ID value, used when face desides it's done... gbUIHandlerID = bUIHandlerID; guiScreenIDUsedWhenUICreated = guiCurrentScreen; return( TRUE ); } BOOLEAN ExecuteSnitchCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 iFaceIndex, UINT8 bUIHandlerID, UINT8 ubSnitchEventType, UINT8 ubSnitchTargetID, UINT8 ubSecondarySnitchTargetID ) { UINT32 uiSound1ID; UINT32 uiSound2ID; UINT32 uiSound3ID; //if( bUIHandlerID == DIALOGUE_SNITCH_UI ) { CHAR8 zSoundFiles[10][64]; SOLDIERTYPE *pSoldier; pSoldier = FindSoldierByProfileID( ubCharacterNum, TRUE ); if ( !GetSnitchDialogue( ubCharacterNum, usQuoteNum, DIALOGUESIZE, gzQuoteStr, &uiSound1ID, &uiSound2ID, &uiSound3ID, zSoundFiles, ubSnitchTargetID, ubSecondarySnitchTargetID ) ) { return( FALSE ); } //SetFaceTalkingMultipleSounds( iFaceIndex, zSoundString1, zSoundString2, zSoundString3, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); //SetFaceTalking( iFaceIndex, zSoundString1, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); SetFaceTalkingMultipleSounds( iFaceIndex, zSoundFiles, 3, gzQuoteStr, RATE_11025, 30, 1, MIDDLEPAN ); CreateTalkingUI( DIALOGUE_TACTICAL_UI, iFaceIndex, ubCharacterNum, pSoldier, gzQuoteStr ); // Set global handleer ID value, used when face desides it's done... gbUIHandlerID = DIALOGUE_TACTICAL_UI; guiScreenIDUsedWhenUICreated = guiCurrentScreen; return( TRUE ); } } void CreateTalkingUI( INT8 bUIHandlerID, INT32 iFaceIndex, UINT8 ubCharacterNum, SOLDIERTYPE *pSoldier, STR16 zQuoteStr ) { // Show text, if on if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] || !gFacesData[ iFaceIndex ].fValidSpeech ) { switch( bUIHandlerID ) { case DIALOGUE_TACTICAL_UI: HandleTacticalTextUI( iFaceIndex, pSoldier, zQuoteStr ); break; case DIALOGUE_NPC_UI: HandleTacticalNPCTextUI( ubCharacterNum, zQuoteStr ); break; case DIALOGUE_CONTACTPAGE_UI: DisplayTextForMercFaceVideoPopUp( zQuoteStr ); break; case DIALOGUE_SPECK_CONTACT_PAGE_UI: DisplayTextForSpeckVideoPopUp( zQuoteStr ); break; case DIALOGUE_EXTERNAL_NPC_UI: DisplayTextForExternalNPC( ubCharacterNum, zQuoteStr ); break; case DIALOGUE_SHOPKEEPER_UI: InitShopKeeperSubTitledText( zQuoteStr ); break; } } if ( gGameSettings.fOptions[ TOPTION_SPEECH ] ) { switch( bUIHandlerID ) { case DIALOGUE_TACTICAL_UI: HandleTacticalSpeechUI( ubCharacterNum, iFaceIndex ); break; case DIALOGUE_CONTACTPAGE_UI: break; case DIALOGUE_SPECK_CONTACT_PAGE_UI: break; case DIALOGUE_EXTERNAL_NPC_UI: HandleExternNPCSpeechFace( iFaceIndex ); break; } } } CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile ) { static CHAR8 zFileName[164]; static CHAR8 zFileNameExists[164]; UINT8 ubFileNumID; BOOLEAN isBartenderSantos = FALSE; // Are we an NPC OR an RPC that has not been recruited? // ATE: Did the || clause here to allow ANY RPC that talks while the talking menu is up to use an npc quote file if ( gfUseAlternateDialogueFile ) { if ( fWavFile ) { // Lesh: patch to allow playback ogg speech files // build name of wav file (characternum + quotenum) //SB: curiously, there are no g_%03d_%03d audio files in all russian versions // #ifdef RUSSIAN // sprintf( zFileName,"NPC_SPEECH\\g_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); // if ( !FileExists( zFileName ) ) // { // sprintf( zFileName,"NPC_SPEECH\\g_%03d_%03d.wav",ubCharacterNum,usQuoteNum ); // } // #else if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) { sprintf( zFileName,"NPC_SPEECH\\d_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"NPC_SPEECH\\d_%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } } // #endif } else { // assume EDT files are in EDT directory on HARD DRIVE sprintf( zFileName,"NPCDATA\\d_%03d.EDT", ubCharacterNum ); } } //else if ( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && //new profiles by Jazz else if ( ( gProfilesRPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesNPC[ubCharacterNum].ProfilId == ubCharacterNum ) && //|| gProfilesVehicle[ubCharacterNum].ProfilId == ubCharacterNum ) && ( !( gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) || ProfileCurrentlyTalkingInDialoguePanel( ubCharacterNum ) || (gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_FORCENPCQUOTE) ) ) { ubFileNumID = ubCharacterNum; if ( ubCharacterNum == HERVE ) { isBartenderSantos = TRUE; ubFileNumID = HERVE; } else if ( ubCharacterNum == PETER ) { isBartenderSantos = TRUE; sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", PETER ); if ( !FileExists( zFileName ) ) ubFileNumID = HERVE; else ubFileNumID = PETER; } else if ( ubCharacterNum == ALBERTO ) { isBartenderSantos = TRUE; sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", ALBERTO ); if ( !FileExists( zFileName ) ) ubFileNumID = HERVE; else ubFileNumID = ALBERTO; } else if ( ubCharacterNum == CARLO ) { isBartenderSantos = TRUE; sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", CARLO ); if ( !FileExists( zFileName ) ) ubFileNumID = HERVE; else ubFileNumID = CARLO; } #ifdef JA2UB if ( ubCharacterNum == MANUEL_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", MANUEL_UB ); ubFileNumID = MANUEL_UB; } if ( ubCharacterNum == BIGGENS_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", BIGGENS_UB ); ubFileNumID = BIGGENS_UB; } if ( ubCharacterNum == JOHN_K_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", JOHN_K_UB ); ubFileNumID = JOHN_K_UB; } if ( ubCharacterNum == TEX_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", TEX_UB ); ubFileNumID = TEX_UB; } if ( ubCharacterNum == GASTON_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", GASTON_UB ); ubFileNumID = GASTON_UB; } if ( ubCharacterNum == STOGIE_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", STOGIE_UB ); ubFileNumID = STOGIE_UB; } if ( ubCharacterNum == JERRY_MILO_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", JERRY_MILO_UB ); ubFileNumID = JERRY_MILO_UB; } if ( ubCharacterNum == PGMALE4_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", PGMALE4_UB ); ubFileNumID = PGMALE4_UB; } if ( ubCharacterNum == BETTY_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", BETTY_UB ); ubFileNumID = BETTY_UB; } if ( ubCharacterNum == RAUL_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", RAUL_UB ); ubFileNumID = RAUL_UB; } if ( ubCharacterNum == MORRIS_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", MORRIS_UB ); ubFileNumID = MORRIS_UB; } if ( ubCharacterNum == RUDY_UB ) { sprintf( (char *)zFileNameExists,"NPCDATA\\%03d.EDT", RUDY_UB ); ubFileNumID = RUDY_UB; } #endif // If we are character #155, check fact! if ( ubCharacterNum == MANNY && !gubFact[ FACT_MANNY_IS_BARTENDER ] ) { ubFileNumID = MANNY; } if ( fWavFile ) { if ( gSoundProfileValue[ubFileNumID].EnabledSound == TRUE ) { // Lesh: patch to allow playback ogg speech files sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.ogg",ubFileNumID,usQuoteNum ); // WANNE: We do not have any speech files for the other (!= HERVE) santos bartenders, take HERVE speech files if (isBartenderSantos && HERVE != ubFileNumID && !FileExists(zFileName)) { ubFileNumID = HERVE; sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.ogg",ubFileNumID,usQuoteNum ); } // We do not have *.ogg file, take *.WAV file if ( !FileExists( zFileName ) ) { sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.wav",ubFileNumID,usQuoteNum ); } } } else { // assume EDT files are in EDT directory on HARD DRIVE sprintf( zFileName,"NPCDATA\\%03d.EDT", ubFileNumID ); // WANNE: We do not have any edt files for the other (!= HERVE) santos bartenders, take HERVE speech files if (isBartenderSantos && HERVE != ubFileNumID && !FileExists(zFileName)) { sprintf( zFileName,"NPCDATA\\%03d.EDT", HERVE ); } } } else { if ( fWavFile ) { #ifdef RUSSIAN // if( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) //new profiles by Jazz if ( ( gProfilesRPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesNPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesVehicle[ubCharacterNum].ProfilId == ubCharacterNum ) && gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) { //inshy: fix for UB-1.13 version only sprintf( zFileName,"SPEECH\\r_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) { #ifdef JA2UB sprintf( zFileName,"SPEECH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); } #else sprintf( zFileName,"SPEECH\\r_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); #endif if ( !FileExists( zFileName ) ) { //inshy: fix for UB-1.13 version only #ifdef JA2UB sprintf( zFileName,"SPEECH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } #else sprintf( zFileName,"SPEECH\\r_%03d_%03d.wav",ubCharacterNum,usQuoteNum ); #endif // Also check for Russian Gold sound files (identical to international ones) if(! FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } } // } } } else #endif { if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) { // build name of wav file (characternum + quotenum) sprintf( zFileName,"SPEECH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } } } } else { // assume EDT files are in EDT directory on HARD DRIVE sprintf( zFileName,"MERCEDT\\%03d.EDT", ubCharacterNum ); } } return( zFileName ); } CHAR8 *GetSnitchDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, BOOLEAN fName ) { static CHAR8 zFileName[164]; static CHAR8 zFileNameExists[164]; if ( fWavFile ) { if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) { // build name of wav file (characternum + quotenum) if(fName) { sprintf( zFileName,"SPEECH\\SNITCH\\NAMES\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\SNITCH\\NAMES\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } } else { sprintf( zFileName,"SPEECH\\SNITCH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\SNITCH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } } } } else { // assume EDT files are in EDT directory on HARD DRIVE if(fName) sprintf( zFileName,"MERCEDT\\SNITCH\\NAMES\\%03d.EDT", ubCharacterNum ); else sprintf( zFileName,"MERCEDT\\SNITCH\\%03d.EDT", ubCharacterNum ); } return( zFileName ); } // Used to see if the dialog text file exists BOOLEAN DialogueDataFileExistsForProfile( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, STR8 *ppStr ) { STR8 pFilename; pFilename = GetDialogueDataFilename( ubCharacterNum, usQuoteNum, fWavFile ); if ( ppStr ) { (*ppStr ) = pFilename; } return( FileExists( pFilename ) ); } BOOLEAN SnitchDialogueDataFileExistsForProfile( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN fWavFile, STR8 *ppStr, BOOLEAN fName ) { STR8 pFilename; pFilename = GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, fWavFile, fName ); if ( ppStr ) { (*ppStr ) = pFilename; } return( FileExists( pFilename ) ); } BOOLEAN GetDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSoundID, CHAR8 *zSoundString ) { STR8 pFilename; BOOLEAN fTextAvailable = FALSE; // first things first - grab the text (if player has SUBTITLE PREFERENCE ON) //if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] ) { if ( DialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename ) ) { LoadEncryptedDataFromFile( pFilename, zDialogueText, usQuoteNum * iDataSize, iDataSize ); if(zDialogueText[0] == 0) { swprintf( zDialogueText, L"I have no text in the EDT file ( %d ) %S", usQuoteNum, pFilename ); #ifndef JA2BETAVERSION return( FALSE ); #endif } else fTextAvailable = TRUE; } else { swprintf( zDialogueText, L"I have no text in the file ( %d ) %S", usQuoteNum , pFilename ); #ifndef JA2BETAVERSION return( FALSE ); #endif } } // CHECK IF THE FILE EXISTS, IF NOT, USE DEFAULT! pFilename = GetDialogueDataFilename( ubCharacterNum, usQuoteNum, TRUE ); // Copy strcpy( zSoundString, pFilename ); // Double check it exists.... //#ifndef JA2TESTVERSION /* if ( !FileExists( pFilename ) ) { CHAR8 sString[512]; sprintf( sString, "ERROR: Missing file for character # %d, quote # %d", ubCharacterNum, usQuoteNum ); ShowCursor(TRUE); ShowCursor(TRUE); ShutdownWithErrorBox( sString ); } */ //#endif *puiSoundID = NO_SAMPLE; // get speech if applicable if ( gGameSettings.fOptions[ TOPTION_SPEECH ] ) { // Load it into memory! *puiSoundID = SoundLoadSample( pFilename ); } return (*puiSoundID != NO_SAMPLE) || fTextAvailable; } BOOLEAN ReplaceTextWithOtherText( CHAR16 *pFinishedString, CHAR16 compare[32], CHAR16 replace[32] ) { CHAR16 pTempString[320]; INT32 iLength = 0; INT32 iCurLocInSourceString = 0; INT32 iLengthOfSourceString = wcslen( pFinishedString ); //Get the length of the source string CHAR16 *pNickString = NULL; CHAR16 *pSubString = NULL; BOOLEAN fReplacingMercName = TRUE; CHAR16 sSearchString[32]; //Copy the original string over to the temp string wcscpy( pTempString, pFinishedString ); //Null out the string pFinishedString[0] = L'\0'; //Keep looping through to replace all references to the keyword while ( iCurLocInSourceString < iLengthOfSourceString ) { iLength = 0; pSubString = NULL; //Find out if the $MERCNICK$ is in the string pNickString = wcsstr( &pTempString[iCurLocInSourceString], compare ); if ( pNickString != NULL ) { fReplacingMercName = TRUE; pSubString = pNickString; wcscpy( sSearchString, compare ); } else { pSubString = NULL; } // if there is a substring if ( pSubString != NULL ) { iLength = pSubString - &pTempString[iCurLocInSourceString]; //Copy the part of the source string up to the keyword wcsncat( pFinishedString, &pTempString[iCurLocInSourceString], iLength ); //increment the source string counter by how far in the keyword is and by the length of the keyword iCurLocInSourceString += iLength + wcslen( sSearchString ); if ( fReplacingMercName ) { //add the mercs name to the string wcscat( pFinishedString, replace ); } } else { //add the rest of the string wcscat( pFinishedString, &pTempString[iCurLocInSourceString] ); iCurLocInSourceString += wcslen( &pTempString[iCurLocInSourceString] ); } } return(TRUE); } // anv: special version of GetDialogue, message is put together from parts BOOLEAN GetSnitchDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, UINT32 iDataSize, STR16 zDialogueText, UINT32 *puiSound1ID, UINT32 *puiSound2ID, UINT32 *puiSound3ID, CHAR8 zSoundFiles[][64], UINT8 ubTargetProfile, UINT8 ubSecondaryTargetProfile ) { STR8 pFilename1; //STR8 pFilename2; //STR8 pFilename3; //CHAR16 zDialogueTextTemp[ QUOTE_MESSAGE_SIZE ]; BOOLEAN fTextAvailable = FALSE; // first things first - grab the text (if player has SUBTITLE PREFERENCE ON) //if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] ) { if ( SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename1, FALSE ) ) //SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename, TRUE ) && //SnitchDialogueDataFileExistsForProfile( ubCharacterNum, 0, FALSE, &pFilename, TRUE ) && ) { LoadEncryptedDataFromFile( pFilename1, zDialogueText, usQuoteNum * iDataSize, iDataSize ); // Flugente: replaced SnitchDialogueReplaceMercNicksWithProperData with ReplaceTextWithOtherText - less complicated an can be used for other things than merc names ReplaceTextWithOtherText( zDialogueText, L"$MERCNICK$", gMercProfiles[ubTargetProfile].zNickname ); ReplaceTextWithOtherText( zDialogueText, L"$MERCNICK2$", gMercProfiles[ubSecondaryTargetProfile].zNickname ); if(zDialogueText[0] == 0) { swprintf( zDialogueText, L"I have no text in the EDT file ( %d ) %S", usQuoteNum, pFilename1 ); #ifndef JA2BETAVERSION return( FALSE ); #endif } else fTextAvailable = TRUE; } else { swprintf( zDialogueText, L"I have no text in the file ( %d ) %S", usQuoteNum , pFilename1 ); #ifndef JA2BETAVERSION return( FALSE ); #endif } } // CHECK IF THE FILE EXISTS, IF NOT, USE DEFAULT! //pFilename1 = GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, TRUE, FALSE ); //pFilename2 = GetSnitchDialogueDataFilename( ubCharacterNum, ubSnitchTargetID, TRUE, TRUE ); //pFilename3 = GetSnitchDialogueDataFilename( ubCharacterNum, ubSecondarySnitchTargetID, TRUE, TRUE ); // Copy strcpy( zSoundFiles[0], GetSnitchDialogueDataFilename( ubCharacterNum, ubTargetProfile, TRUE, TRUE ) ); strcpy( zSoundFiles[1], GetSnitchDialogueDataFilename( ubCharacterNum, usQuoteNum, TRUE, FALSE ) ); strcpy( zSoundFiles[2], GetSnitchDialogueDataFilename( ubCharacterNum, ubSecondaryTargetProfile, TRUE, TRUE ) ); *puiSound1ID = NO_SAMPLE; *puiSound2ID = NO_SAMPLE; *puiSound3ID = NO_SAMPLE; // get speech if applicable if ( gGameSettings.fOptions[ TOPTION_SPEECH ] ) { // Load it into memory! *puiSound1ID = SoundLoadSample( zSoundFiles[0] ); *puiSound2ID = SoundLoadSample( zSoundFiles[0] ); *puiSound3ID = SoundLoadSample( zSoundFiles[0] ); } return (*puiSound2ID != NO_SAMPLE) || fTextAvailable; } // Handlers for tactical UI stuff void HandleTacticalNPCTextUI( UINT8 ubCharacterNum, STR16 zQuoteStr ) { CHAR16 zText[ QUOTE_MESSAGE_SIZE ]; // Setup dialogue text box if ( guiCurrentScreen != MAP_SCREEN ) { gTalkPanel.fRenderSubTitlesNow = TRUE; gTalkPanel.fSetupSubTitles = TRUE; } // post message to mapscreen message system swprintf( gTalkPanel.zQuoteStr, L"\"%s\"", zQuoteStr ); swprintf( zText, L"%s: \"%s\"", gMercProfiles[ ubCharacterNum ].zNickname, zQuoteStr ); MapScreenMessage( FONT_MCOLOR_WHITE, MSG_DIALOG, L"%s", zText ); } // Handlers for tactical UI stuff void DisplayTextForExternalNPC( UINT8 ubCharacterNum, STR16 zQuoteStr ) { CHAR16 zText[ QUOTE_MESSAGE_SIZE ]; INT16 sLeft; // Setup dialogue text box if ( guiCurrentScreen != MAP_SCREEN ) { gTalkPanel.fRenderSubTitlesNow = TRUE; gTalkPanel.fSetupSubTitles = TRUE; } // post message to mapscreen message system swprintf( gTalkPanel.zQuoteStr, L"\"%s\"", zQuoteStr ); swprintf( zText, L"%s: \"%s\"", gMercProfiles[ ubCharacterNum ].zNickname, zQuoteStr ); MapScreenMessage( FONT_MCOLOR_WHITE, MSG_DIALOG, L"%s", zText ); if ( guiCurrentScreen == MAP_SCREEN ) { sLeft = ( gsExternPanelXPosition + 97 + xResOffset ); gsTopPosition = gsExternPanelYPosition + yResOffset; } else { sLeft = ( 110 + xResOffset ); } ExecuteTacticalTextBox( sLeft, gTalkPanel.zQuoteStr ); return; } void HandleTacticalTextUI( INT32 iFaceIndex, SOLDIERTYPE *pSoldier, STR16 zQuoteStr ) { CHAR16 zText[ QUOTE_MESSAGE_SIZE ]; INT16 sLeft = 0; //BUild text // How do we do this with defines? //swprintf( zText, L"\xb4\xa2 %s: \xb5 \"%s\"", gMercProfiles[ ubCharacterNum ].zNickname, zQuoteStr ); swprintf( zText, L"\"%s\"", zQuoteStr ); // TODO.RW: Wenn wir in tactical sind, dann normal. In strategy den offset dazurechnen! if ( guiCurrentScreen == GAME_SCREEN ) { sLeft = 110; } else { sLeft = 110 + xResOffset; gsTopPosition += yResOffset; } //previous version //sLeft = 110; ExecuteTacticalTextBox( sLeft, zText ); } void ExecuteTacticalTextBoxForLastQuote( INT16 sLeftPosition, STR16 pString ) { UINT32 uiDelay = FindDelayForString( pString ); fDialogueBoxDueToLastMessage = TRUE; guiDialogueLastQuoteTime = GetJA2Clock(); guiDialogueLastQuoteDelay = ( ( uiDelay < FINAL_TALKING_DURATION ) ? FINAL_TALKING_DURATION : uiDelay ); // now execute box ExecuteTacticalTextBox(sLeftPosition, pString ); } void ExecuteTacticalTextBox( INT16 sLeftPosition, STR16 pString ) { VIDEO_OVERLAY_DESC VideoOverlayDesc; // check if mouse region created, if so, do not recreate if( fTextBoxMouseRegionCreated == TRUE ) { return; } memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); //never use it anymore //SET_USE_WINFONTS( TRUE ); //SET_WINFONT( giSubTitleWinFont ); // Prepare text box iDialogueBox = PrepareMercPopupBox( iDialogueBox , BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, pString, DIALOGUE_DEFAULT_SUBTITLE_WIDTH, 0, 0, 0, &gusSubtitleBoxWidth, &gusSubtitleBoxHeight ); //SET_USE_WINFONTS( FALSE ); VideoOverlayDesc.sLeft = sLeftPosition; VideoOverlayDesc.sTop = gsTopPosition; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusSubtitleBoxWidth; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusSubtitleBoxHeight; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderSubtitleBoxOverlay; giTextBoxOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); gsTopPosition = 20; //Define main region MSYS_DefineRegion( &gTextBoxMouseRegion, VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop, VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, TextOverlayClickCallback ); // Add region MSYS_AddRegion(&(gTextBoxMouseRegion) ); fTextBoxMouseRegionCreated = TRUE; } void HandleExternNPCSpeechFace( INT32 iIndex ) { INT32 iFaceIndex; VIDEO_OVERLAY_DESC VideoOverlayDesc; INT32 iFaceOverlay; // grab face index iFaceIndex = iIndex; // Enable it! SetAutoFaceActive( FACE_AUTO_DISPLAY_BUFFER, FACE_AUTO_RESTORE_BUFFER, iFaceIndex , 0, 0 ); // Set flag to say WE control when to set inactive! gFacesData[ iFaceIndex ].uiFlags |= FACE_INACTIVE_HANDLED_ELSEWHERE; // WDS - bug fix: VideoOverlayDesc must be initialized! - 07/16/2007 memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); if ( guiCurrentScreen != MAP_SCREEN ) { // Setup video overlay! VideoOverlayDesc.sLeft = 10 + xResOffset; VideoOverlayDesc.sTop = 20; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + 99; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + 98; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderFaceOverlay; } else { // Setup video overlay! VideoOverlayDesc.sLeft = gsExternPanelXPosition + xResOffset; VideoOverlayDesc.sTop = gsExternPanelYPosition + yResOffset; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + 99; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + 98; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderFaceOverlay; } iFaceOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); gpCurrentTalkingFace->iVideoOverlay = iFaceOverlay; RenderAutoFace( iFaceIndex ); // ATE: Create mouse region....... if ( !fExternFaceBoxRegionCreated ) { fExternFaceBoxRegionCreated = TRUE; //Define main region MSYS_DefineRegion( &gFacePopupMouseRegion, VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop, VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, FaceOverlayClickCallback ); // Add region MSYS_AddRegion(&(gFacePopupMouseRegion) ); } gfFacePanelActive = TRUE; return; } void HandleTacticalSpeechUI( UINT8 ubCharacterNum, INT32 iFaceIndex ) { VIDEO_OVERLAY_DESC VideoOverlayDesc; INT32 iFaceOverlay; SOLDIERTYPE *pSoldier; BOOLEAN fDoExternPanel = FALSE; memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); // Get soldier pointer, if there is one... // Try to find soldier... pSoldier = FindSoldierByProfileID( ubCharacterNum, FALSE ); // PLEASE NOTE: pSoldier may legally be NULL (e.g. Skyrider) !!! if ( pSoldier == NULL ) { fDoExternPanel = TRUE; } else { // If we are not an active face! if ( guiCurrentScreen != MAP_SCREEN ) { fDoExternPanel = TRUE; } } if ( fDoExternPanel ) { // Enable it! SetAutoFaceActive( FACE_AUTO_DISPLAY_BUFFER, FACE_AUTO_RESTORE_BUFFER, iFaceIndex , 0, 0 ); // Set flag to say WE control when to set inactive! gFacesData[ iFaceIndex ].uiFlags |= ( FACE_INACTIVE_HANDLED_ELSEWHERE | FACE_MAKEACTIVE_ONCE_DONE ); // IF we are in tactical and this soldier is on the current squad if ( ( guiCurrentScreen == GAME_SCREEN ) && ( pSoldier != NULL ) && ( pSoldier->bAssignment == iCurrentTacticalSquad ) ) { // Make the interface panel dirty.. // This will dirty the panel next frame... gfRerenderInterfaceFromHelpText = TRUE; } // Setup video overlay! VideoOverlayDesc.sLeft = 10; VideoOverlayDesc.sTop = 20; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + 99; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + 98; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderFaceOverlay; iFaceOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); gpCurrentTalkingFace->iVideoOverlay = iFaceOverlay; RenderAutoFace( iFaceIndex ); // ATE: Create mouse region....... if ( !fExternFaceBoxRegionCreated ) { fExternFaceBoxRegionCreated = TRUE; //Define main region MSYS_DefineRegion( &gFacePopupMouseRegion, VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop, VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, FaceOverlayClickCallback ); // Add region MSYS_AddRegion(&(gFacePopupMouseRegion) ); } gfFacePanelActive = TRUE; } else if ( guiCurrentScreen == MAP_SCREEN ) { // Are we in mapscreen? // If so, set current guy active to talk..... if ( pSoldier != NULL ) { ContinueDialogue( pSoldier, FALSE ); } } } void HandleDialogueEnd( FACETYPE *pFace ) { if ( gGameSettings.fOptions[ TOPTION_SPEECH ] ) { if ( pFace != gpCurrentTalkingFace ) { //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"HandleDialogueEnd() face mismatch." ); return; } if ( pFace->fTalking ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"HandleDialogueEnd() face still talking." ); return; } switch( gbUIHandlerID ) { case DIALOGUE_TACTICAL_UI: if ( gfFacePanelActive ) { // Set face inactive! pFace->fCanHandleInactiveNow = TRUE; SetAutoFaceInActive( pFace->iID ); gfFacePanelActive = FALSE; if ( fExternFaceBoxRegionCreated ) { fExternFaceBoxRegionCreated = FALSE; MSYS_RemoveRegion(&(gFacePopupMouseRegion) ); } } break; case DIALOGUE_NPC_UI: break; case DIALOGUE_EXTERNAL_NPC_UI: pFace->fCanHandleInactiveNow = TRUE; SetAutoFaceInActive( pFace->iID ); gfFacePanelActive = FALSE; if ( fExternFaceBoxRegionCreated ) { fExternFaceBoxRegionCreated = FALSE; MSYS_RemoveRegion(&(gFacePopupMouseRegion) ); } break; } } if ( gGameSettings.fOptions[ TOPTION_SUBTITLES ] || !pFace->fValidSpeech ) { switch( gbUIHandlerID ) { case DIALOGUE_TACTICAL_UI: case DIALOGUE_EXTERNAL_NPC_UI: // Remove if created // 0verhaul: Both of these events are more or less independent. Most often the gTextBoxOverlay fails to init. // Therefore I am removing the dependency on giTextBoxOverlay before it decides to destroy the popup box region. // This should prevent blockage of buttons and also clicks on the tactical map. if ( giTextBoxOverlay != -1 ) { RemoveVideoOverlay( giTextBoxOverlay ); giTextBoxOverlay = -1; } if ( fTextBoxMouseRegionCreated ) { RemoveMercPopupBoxFromIndex( iDialogueBox ); // reset box id iDialogueBox = -1; MSYS_RemoveRegion( &gTextBoxMouseRegion ); fTextBoxMouseRegionCreated = FALSE; } // anv: show repair prompt afer Waldo offered repairs if ( gbUIHandlerID == DIALOGUE_EXTERNAL_NPC_UI && gTacticalStatus.ubLastQuoteProfileNUm == WALDO && ( gTacticalStatus.ubLastQuoteSaid == WALDO_REPAIR_PROPOSITION || gTacticalStatus.ubLastQuoteSaid == WALDO_SERIOUS_REPAIR_PROPOSITION ) ) { CHAR16 sHelicopterRepairPromptText[ 320 ]; if( CheckFact(FACT_HELI_DAMAGED_CAN_START_REPAIR, 0) == TRUE ) { swprintf( sHelicopterRepairPromptText, pHelicopterRepairRefuelStrings[ STR_HELI_RR_REPAIR_PROMPT ], gMercProfiles[ WALDO ].zNickname, CalculateHelicopterRepairCost( FALSE ), gHelicopterSettings.ubHelicopterBasicRepairTime ); } else { swprintf( sHelicopterRepairPromptText, pHelicopterRepairRefuelStrings[ STR_HELI_RR_REPAIR_PROMPT ], gMercProfiles[ WALDO ].zNickname, CalculateHelicopterRepairCost( TRUE ), gHelicopterSettings.ubHelicopterSeriousRepairTime ); } DoMessageBox( MSG_BOX_BASIC_STYLE, sHelicopterRepairPromptText, guiCurrentScreen, ( UINT8 )MSG_BOX_FLAG_YESNO, OfferHelicopterRepairBoxCallBack, NULL ); } // anv: after merc finishes his quote, we want enemy to answer if ( gbUIHandlerID == DIALOGUE_TACTICAL_UI ) { SOLDIERTYPE *pSoldier = FindSoldierByProfileID( gTacticalStatus.ubLastQuoteProfileNUm, FALSE ); if ( pSoldier ) { UINT8 ubSeenEnemies[ MAX_NUM_SOLDIERS ]; UINT8 ubSeenEnemiesCnt = 0; switch( gTacticalStatus.ubLastQuoteSaid ) { case QUOTE_CLOSE_CALL: case QUOTE_UNDER_HEAVY_FIRE: case QUOTE_TAKEN_A_BREATING: if( pSoldier->ubPreviousAttackerID != NOBODY && !( MercPtrs[pSoldier->ubPreviousAttackerID]->bDeafenedCounter > 0 ) ) PossiblyStartEnemyTaunt( MercPtrs[pSoldier->ubPreviousAttackerID], TAUNT_RIPOSTE, gTacticalStatus.ubLastQuoteProfileNUm ); break; default: // select random enemy, who we see, who sees us and isn't deaf for(UINT8 cnt = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; cnt < gTacticalStatus.Team[ ENEMY_TEAM ].bLastID ; cnt++ ) { if( MercPtrs[cnt] != NULL && MercPtrs[cnt]->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY && MercPtrs[pSoldier->ubID]->aiData.bOppList[cnt] == SEEN_CURRENTLY && !( MercPtrs[cnt]->bDeafenedCounter > 0 ) ) { ubSeenEnemies[ubSeenEnemiesCnt] = cnt; ubSeenEnemiesCnt++; } } if( ubSeenEnemiesCnt > 0 ) PossiblyStartEnemyTaunt( MercPtrs[ubSeenEnemies[ Random(ubSeenEnemiesCnt) ]], TAUNT_RIPOSTE, gTacticalStatus.ubLastQuoteProfileNUm ); } break; } } break; case DIALOGUE_NPC_UI: // anv: "meet" Waldo when speaking with him first time if ( gTacticalStatus.ubLastQuoteProfileNUm == WALDO && CheckFact( FACT_WALDO_MET, 0 ) == FALSE && gTacticalStatus.ubLastQuoteSaid == 0 ) { AddHistoryToPlayersLog( HISTORY_WALDO, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); SetFactTrue( FACT_WALDO_MET ); } // Remove region if ( gTalkPanel.fTextRegionOn ) { MSYS_RemoveRegion(&(gTalkPanel.TextRegion) ); gTalkPanel.fTextRegionOn = FALSE; } // WANNE: This check is used, to prevent scrolling in small maps (e.g: Rebel Basement) in higher resolution (1024x768) [2007-05-14] gfDialogControl = TRUE; SetRenderFlags( RENDER_FLAG_FULL ); gTalkPanel.fRenderSubTitlesNow = FALSE; // Delete subtitle box gTalkPanel.fDirtyLevel = DIRTYLEVEL2; RemoveMercPopupBoxFromIndex( iInterfaceDialogueBox ); iInterfaceDialogueBox = -1; break; case DIALOGUE_CONTACTPAGE_UI: break; case DIALOGUE_SPECK_CONTACT_PAGE_UI: break; } } TurnOffSectorLocator(); gsExternPanelXPosition = DEFAULT_EXTERN_PANEL_X_POS; gsExternPanelYPosition = DEFAULT_EXTERN_PANEL_Y_POS; } void RenderFaceOverlay( VIDEO_OVERLAY *pBlitter ) { UINT32 uiDestPitchBYTES, uiSrcPitchBYTES; UINT8 *pDestBuf, *pSrcBuf; INT16 sFontX, sFontY; SOLDIERTYPE *pSoldier; CHAR16 zTownIDString[50]; if ( gpCurrentTalkingFace == NULL ) { return; } if ( gfFacePanelActive ) { pSoldier = FindSoldierByProfileID( gpCurrentTalkingFace->ubCharacterNum, FALSE ); // a living soldier?..or external NPC?..choose panel based on this if( pSoldier ) { BltVideoObjectFromIndex( pBlitter->uiDestBuff, guiCOMPANEL, 0, pBlitter->sX, pBlitter->sY, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( pBlitter->uiDestBuff, guiCOMPANELB, 0, pBlitter->sX, pBlitter->sY, VO_BLT_SRCTRANSPARENCY, NULL ); } // Display name, location ( if not current ) SetFont( BLOCKFONT2 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_LTGRAY ); if ( pSoldier ) { //reset the font dest buffer SetFontDestBuffer( pBlitter->uiDestBuff, 0,0,SCREEN_WIDTH,SCREEN_HEIGHT, FALSE); VarFindFontCenterCoordinates( (INT16)( pBlitter->sX + 12 ), (INT16)( pBlitter->sY + 55 ), 73, 9, BLOCKFONT2, &sFontX, &sFontY, L"%s", pSoldier->name ); mprintf( sFontX, sFontY, L"%s", pSoldier->name ); // What sector are we in, ( and is it the same as ours? ) if ( pSoldier->sSectorX != gWorldSectorX || pSoldier->sSectorY != gWorldSectorY || pSoldier->bSectorZ != gbWorldSectorZ || pSoldier->flags.fBetweenSectors ) { GetSectorIDString( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, zTownIDString, FALSE ); ReduceStringLength( zTownIDString, 64 , BLOCKFONT2 ); VarFindFontCenterCoordinates( (INT16)( pBlitter->sX + 12 ), (INT16)( pBlitter->sY + 68 ), 73, 9, BLOCKFONT2, &sFontX, &sFontY, L"%s", zTownIDString ); mprintf( sFontX, sFontY, L"%s", zTownIDString ); } //reset the font dest buffer SetFontDestBuffer(FRAME_BUFFER, 0,0,SCREEN_WIDTH,SCREEN_HEIGHT, FALSE); // Display bars DrawLifeUIBarEx( pSoldier, (INT16)( pBlitter->sX + 69 ), (INT16)( pBlitter->sY + 47 ), 3, 42, FALSE, pBlitter->uiDestBuff ); DrawBreathUIBarEx( pSoldier, (INT16)( pBlitter->sX + 75 ), (INT16)( pBlitter->sY + 47 ), 3, 42, FALSE, pBlitter->uiDestBuff ); DrawMoraleUIBarEx( pSoldier, (INT16)( pBlitter->sX + 81 ), (INT16)( pBlitter->sY + 47 ), 3, 42, FALSE, pBlitter->uiDestBuff ); } else { VarFindFontCenterCoordinates( (INT16)( pBlitter->sX + 9 ), (INT16)( pBlitter->sY + 55 ), 73, 9, BLOCKFONT2, &sFontX, &sFontY, L"%s", gMercProfiles[ gpCurrentTalkingFace->ubCharacterNum ].zNickname ); mprintf( sFontX, sFontY, L"%s", gMercProfiles[ gpCurrentTalkingFace->ubCharacterNum ].zNickname ); } //RenderAutoFace( gpCurrentTalkingFace->iID ); //BlinkAutoFace( gpCurrentTalkingFace->iID ); //MouthAutoFace( gpCurrentTalkingFace->iID ); pDestBuf = LockVideoSurface( pBlitter->uiDestBuff, &uiDestPitchBYTES); pSrcBuf = LockVideoSurface( gpCurrentTalkingFace->uiAutoDisplayBuffer, &uiSrcPitchBYTES); Blt16BPPTo16BPP((UINT16 *)pDestBuf, uiDestPitchBYTES, (UINT16 *)pSrcBuf, uiSrcPitchBYTES, (INT16)( pBlitter->sX + 14 ), (INT16)( pBlitter->sY + 6 ), 0 , 0, gpCurrentTalkingFace->usFaceWidth, gpCurrentTalkingFace->usFaceHeight ); UnLockVideoSurface( pBlitter->uiDestBuff ); UnLockVideoSurface( gpCurrentTalkingFace->uiAutoDisplayBuffer ); InvalidateRegion( pBlitter->sX, pBlitter->sY, pBlitter->sX + 99, pBlitter->sY + 98 ); } } void RenderSubtitleBoxOverlay( VIDEO_OVERLAY *pBlitter ) { if ( giTextBoxOverlay != -1 ) { RenderMercPopUpBoxFromIndex( iDialogueBox, pBlitter->sX, pBlitter->sY, pBlitter->uiDestBuff ); InvalidateRegion( pBlitter->sX, pBlitter->sY, pBlitter->sX + gusSubtitleBoxWidth, pBlitter->sY + gusSubtitleBoxHeight ); } } void SayQuoteFromAnyBodyInSector( UINT16 usQuoteNum ) { // WDS - make number of mercenaries, etc. be configurable std::vector ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_MERCS, 0); UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; SOLDIERTYPE *pTeamSoldier; INT32 cnt; // Loop through all our guys and randomly say one from someone in our sector // set up soldier ptr as first element in mercptrs list cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { // Add guy if he's a candidate... if ( OK_INSECTOR_MERC( pTeamSoldier ) && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->flags.fMercAsleep ) { if ( gTacticalStatus.bNumFoughtInBattle[ ENEMY_TEAM ] == 0 ) { #ifdef JA2UB //Ja25 No Ira, Miguel etc. #else // quotes referring to Deidranna's men so we skip quote if there were no army guys fought if ( (usQuoteNum == QUOTE_SECTOR_SAFE) && (pTeamSoldier->ubProfile == IRA || pTeamSoldier->ubProfile == MIGUEL || pTeamSoldier->ubProfile == SHANK ) ) { continue; } if ( (usQuoteNum == QUOTE_ENEMY_PRESENCE ) && (pTeamSoldier->ubProfile == IRA || pTeamSoldier->ubProfile == DIMITRI || pTeamSoldier->ubProfile == DYNAMO || pTeamSoldier->ubProfile == SHANK ) ) { continue; } #endif } ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; ubNumMercs++; } } // If we are > 0 if ( ubNumMercs > 0 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); // If we are air raid, AND red exists somewhere... if ( usQuoteNum == QUOTE_AIR_RAID ) { for ( cnt = 0; cnt < ubNumMercs; cnt++ ) { if ( ubMercsInSector[ cnt ] == 11 ) { ubChosenMerc = (UINT8)cnt; break; } } } TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum ); } } void SayQuoteFromAnyBodyInThisSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT16 usQuoteNum ) { // WDS - make number of mercenaries, etc. be configurable std::vector ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0); UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; SOLDIERTYPE *pTeamSoldier; INT32 cnt; // Loop through all our guys and randomly say one from someone in our sector // set up soldier ptr as first element in mercptrs list cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { if ( pTeamSoldier->bActive ) { // Add guy if he's a candidate... if( pTeamSoldier->sSectorX == sSectorX && pTeamSoldier->sSectorY == sSectorY && pTeamSoldier->bSectorZ == bSectorZ && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->flags.fMercAsleep ) { ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; ubNumMercs++; } } } DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("SayQuoteFromAnyBodyInThisSector: num mercs = %d",ubNumMercs)); // If we are > 0 if ( ubNumMercs > 0 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("SayQuoteFromAnyBodyInThisSector: chosen merc = %d",ubChosenMerc)); //// If we are air raid, AND red exists somewhere... //if ( usQuoteNum == QUOTE_AIR_RAID ) //{ // for ( cnt = 0; cnt < ubNumMercs; cnt++ ) // { // if ( ubMercsInSector[ cnt ] == 11 ) // { // ubChosenMerc = (UINT8)cnt; // break; // } // } //} TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum ); } } void SayQuoteFromNearbyMercInSector( INT32 sGridNo, INT8 bDistance, UINT16 usQuoteNum ) { // WDS - make number of mercenaries, etc. be configurable std::vector ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0 ); UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; SOLDIERTYPE *pTeamSoldier; INT32 cnt; // Loop through all our guys and randomly say one from someone in our sector // set up soldier ptr as first element in mercptrs list cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { // Add guy if he's a candidate... if ( OK_INSECTOR_MERC( pTeamSoldier ) && PythSpacesAway( sGridNo, pTeamSoldier->sGridNo ) < bDistance && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->flags.fMercAsleep && SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, 0, 0, TRUE ) ) { if ( usQuoteNum == 66 && (INT16) Random( 100 ) > EffectiveWisdom( pTeamSoldier ) ) { continue; } ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; ubNumMercs++; } } // If we are > 0 if ( ubNumMercs > 0 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); if (usQuoteNum == 66) { SetFactTrue( FACT_PLAYER_FOUND_ITEMS_MISSING ); } TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum ); } } void SayQuote58FromNearbyMercInSector( INT32 sGridNo, INT8 bDistance, UINT16 usQuoteNum, INT8 bSex ) { // WDS - make number of mercenaries, etc. be configurable std::vector ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0); UINT8 ubNumMercs = 0; UINT8 ubChosenMerc; SOLDIERTYPE *pTeamSoldier; INT32 cnt; // Loop through all our guys and randomly say one from someone in our sector // set up soldier ptr as first element in mercptrs list cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // run through list for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++ ) { // Add guy if he's a candidate... if ( OK_INSECTOR_MERC( pTeamSoldier ) && PythSpacesAway( sGridNo, pTeamSoldier->sGridNo ) < bDistance && !AM_AN_EPC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pTeamSoldier )) && !pTeamSoldier->flags.fMercAsleep && SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, 0, 0, TRUE ) ) { // ATE: This is to check gedner for this quote... if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpGenderCode == 0 && bSex == FEMALE ) { continue; } if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpGenderCode == 1 && bSex == MALE ) { continue; } ubMercsInSector[ ubNumMercs ] = (UINT8)cnt; ubNumMercs++; } } // If we are > 0 if ( ubNumMercs > 0 ) { ubChosenMerc = (UINT8)Random( ubNumMercs ); TacticalCharacterDialogue( MercPtrs[ ubMercsInSector[ ubChosenMerc ] ], usQuoteNum ); } } void TextOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) { static BOOLEAN fLButtonDown = FALSE; if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) { fLButtonDown = TRUE; } if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP && fLButtonDown ) { if( gpCurrentTalkingFace != NULL ) { InternalShutupaYoFace( gpCurrentTalkingFace->iID, FALSE ); // Did we succeed in shutting them up? if ( !gpCurrentTalkingFace->fTalking ) { // shut down last quote box ShutDownLastQuoteTacticalTextBox( ); } } #ifdef JA2UB //JA25 UB //if we are in the heli crash sequence else if( gJa25SaveStruct.fJerryBreakingLaptopOccuring ) { InitJerriesSpeechCallBack(); } //else the Commander morris note is being displayed else if( gJa25SaveStruct.ubDisplayCommanderMorrisNote != DMN__NOT_TO_DISPLAY_IT || gJa25SaveStruct.ubDisplayCommanderMorrisNote != DMN__FINISHED ) { HandlePlayerClosingMorrisNoteDisplayedOnScreen(); } #endif } else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { fLButtonDown = FALSE; } } void FaceOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) { static BOOLEAN fLButtonDown = FALSE; if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) { fLButtonDown = TRUE; } if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP && fLButtonDown ) { if( gpCurrentTalkingFace != NULL ) { InternalShutupaYoFace( gpCurrentTalkingFace->iID, FALSE ); } } else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { fLButtonDown = FALSE; } } void ShutDownLastQuoteTacticalTextBox( void ) { if( fDialogueBoxDueToLastMessage ) { RemoveVideoOverlay( giTextBoxOverlay ); giTextBoxOverlay = -1; if ( fTextBoxMouseRegionCreated ) { MSYS_RemoveRegion( &gTextBoxMouseRegion ); fTextBoxMouseRegionCreated = FALSE; } fDialogueBoxDueToLastMessage = FALSE; } } UINT32 FindDelayForString( STR16 sString ) { return( wcslen( sString ) * TEXT_DELAY_MODIFIER ); } void BeginLoggingForBleedMeToos( BOOLEAN fStart ) { gubLogForMeTooBleeds = fStart; } void SetEngagedInConvFromPCAction( SOLDIERTYPE *pSoldier ) { // OK, If a good give, set engaged in conv... gTacticalStatus.uiFlags |= ENGAGED_IN_CONV; gTacticalStatus.ubEngagedInConvFromActionMercID = pSoldier->ubID; } void UnSetEngagedInConvFromPCAction( SOLDIERTYPE *pSoldier ) { if ( gTacticalStatus.ubEngagedInConvFromActionMercID == pSoldier->ubID ) { // OK, If a good give, set engaged in conv... gTacticalStatus.uiFlags &= ( ~ENGAGED_IN_CONV ); } } BOOLEAN IsStopTimeQuote( UINT16 usQuoteNum ) { INT32 cnt; for ( cnt = 0; cnt < gubNumStopTimeQuotes; cnt++ ) { if ( gusStopTimeQuoteList[ cnt ] == usQuoteNum ) { return( TRUE ); } } return( FALSE ); } void CheckForStopTimeQuotes( UINT16 usQuoteNum ) { if ( IsStopTimeQuote( usQuoteNum ) ) { // Stop Time, game EnterModalTactical( TACTICAL_MODAL_NOMOUSE ); gpCurrentTalkingFace->uiFlags |= FACE_MODAL; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_TESTVERSION, L"Starting Modal Tactical Quote." ); } } void SetStopTimeQuoteCallback( MODAL_HOOK pCallBack ) { gModalDoneCallback = pCallBack; } BOOLEAN IsMercSayingDialogue( UINT8 ubProfileID ) { if ( gpCurrentTalkingFace != NULL && gubCurrentTalkingID == ubProfileID ) { return( TRUE ); } return( FALSE ); } BOOLEAN ShouldMercSayPrecedentToRepeatOneSelf( UINT8 ubMercID, UINT32 uiQuoteID ) { UINT8 ubQuoteBit=0; //If the quote is not in the array if( !IsQuoteInPrecedentArray( uiQuoteID ) ) { return( FALSE ); } ubQuoteBit = GetQuoteBitNumberFromQuoteID( uiQuoteID ); if( ubQuoteBit == 0 ) return( FALSE ); if( GetMercPrecedentQuoteBitStatus( ubMercID, ubQuoteBit ) ) { return( TRUE ); } else { SetMercPrecedentQuoteBitStatus( ubMercID, ubQuoteBit ); } return( FALSE ); } BOOLEAN GetMercPrecedentQuoteBitStatus( UINT8 ubMercID, UINT8 ubQuoteBit ) { if( gMercProfiles[ ubMercID ].uiPrecedentQuoteSaid & ( 1 << ( ubQuoteBit - 1 ) ) ) return( TRUE ); else return( FALSE ); } BOOLEAN SetMercPrecedentQuoteBitStatus( UINT8 ubMercID, UINT8 ubBitToSet ) { //Set the bit gMercProfiles[ ubMercID ].uiPrecedentQuoteSaid |= 1 << ( ubBitToSet - 1 ); return( TRUE ); } BOOLEAN IsQuoteInPrecedentArray( UINT32 uiQuoteID ) { UINT8 ubCnt; //If the quote id is above or below the ones in the array if( uiQuoteID < gubMercValidPrecedentQuoteID[ 0 ] || uiQuoteID > gubMercValidPrecedentQuoteID[ NUMBER_VALID_MERC_PRECEDENT_QUOTES-1 ] ) { return( FALSE ); } //loop through all the quotes for( ubCnt=0; ubCntiVideoOverlay ); gpCurrentTalkingFace->iVideoOverlay = -1; } } void HandleImportantMercQuote( SOLDIERTYPE * pSoldier, UINT16 usQuoteNumber ) { // wake merc up for THIS quote if( pSoldier->flags.fMercAsleep ) { TacticalCharacterDialogueWithSpecialEvent( pSoldier, usQuoteNumber, DIALOGUE_SPECIAL_EVENT_SLEEP, 0,0 ); TacticalCharacterDialogue( pSoldier, usQuoteNumber ); TacticalCharacterDialogueWithSpecialEvent( pSoldier, usQuoteNumber, DIALOGUE_SPECIAL_EVENT_SLEEP, 1,0 ); } else { TacticalCharacterDialogue( pSoldier, usQuoteNumber ); } } // handle pausing of the dialogue queue void PauseDialogueQueue( void ) { gfDialogueQueuePaused = TRUE; return; } // unpause the dialogue queue void UnPauseDialogueQueue( void ) { gfDialogueQueuePaused = FALSE; return; } void SetExternMapscreenSpeechPanelXY( INT16 sXPos, INT16 sYPos ) { gsExternPanelXPosition = sXPos; gsExternPanelYPosition = sYPos; } #ifdef JA2UB //JA25 UB BOOLEAN AreAllTheMercsFinishedSayingThereInitialHeliCrashQuotes() { INT32 cnt; SOLDIERTYPE *pSoldier; // IF IT'S THE SELECTED GUY, MAKE ANOTHER SELECTED! cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; // look for all mercs on the same team, for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pSoldier++) { //if the merc is alive, in sector, etc... if ( OK_CONTROLLABLE_MERC( pSoldier ) ) { //if the merc is still not done the initial speech, and still prone if( pSoldier->fIgnoreGetupFromCollapseCheck ) { //we arent done return( FALSE ); } } } //See if Jerry is still waiting to get up pSoldier = FindSoldierByProfileID( JERRY_MILO_UB, FALSE ); if( pSoldier ) { //if the merc is still not done the initial speech, and still prone if( pSoldier->fIgnoreGetupFromCollapseCheck ) { //we arent done return( FALSE ); } } //all mercs on the team are done return( TRUE ); } void InitJerriesSpeechCallBack() { //Trigger Jerry Milo's script record 10 ( call action 301 ) TriggerNPCRecord( JERRY_MILO_UB, 10 ); //Clear the overlay RemoveJerryMiloBrokenLaptopOverlay(); } void RemoveJerryMiloBrokenLaptopOverlay() { //if the overlay is up if( gJa25SaveStruct.fJerryBreakingLaptopOccuring ) { gJa25SaveStruct.fJerryBreakingLaptopOccuring = FALSE; RemoveVideoOverlay( giTextBoxOverlay ); giTextBoxOverlay = -1; if( fTextBoxMouseRegionCreated ) { MSYS_RemoveRegion( &gTextBoxMouseRegion ); fTextBoxMouseRegionCreated = FALSE; } } } void HandlePlayerClosingMorrisNoteDisplayedOnScreen() { RemoveVideoOverlay( giTextBoxOverlay ); giTextBoxOverlay = -1; if ( fTextBoxMouseRegionCreated ) { MSYS_RemoveRegion( &gTextBoxMouseRegion ); fTextBoxMouseRegionCreated = FALSE; } if( gJa25SaveStruct.ubDisplayCommanderMorrisNote == DMN__DISPLAY_PART_2 ) { gJa25SaveStruct.ubDisplayCommanderMorrisNote = DMN__FINISHED; HandleShowingRadioLocatorsInMorrisArea(); } else { DelayedMercQuote( gJa25SaveStruct.bNewMercProfileIDForSayingMorrisNote, DQ__MORRIS_NOTE_DISPLAY_NOTE_1, GetWorldTotalSeconds() + 1 ); } } #endif