#include "builddefines.h" #include #include "sgp.h" #include "faces.h" #include "WCheck.h" #include "Soldier Profile.h" #include "WordWrap.h" #include "sysutil.h" #include "vobject_blitters.h" #include "interface Dialogue.h" #include "Font Control.h" #include "Dialogue Control.h" #include "renderworld.h" #include "NPC.h" #include "MercTextBox.h" #include "message.h" #include "Items.h" #include "Text.h" #include "Overhead.h" #include "Assignments.h" #include "strategic.h" #include "strategicmap.h" #include "gamescreen.h" #include "ai.h" #include "AIInternals.h" #include "Interactive Tiles.h" #include "Interface Panels.h" #include "Quests.h" #include "Squads.h" #include "Game Event Hook.h" #include "Game Clock.h" #include "MessageBoxScreen.h" #include "Tactical Save.h" #include "Interface Control.h" #include "Cursors.h" #include "Fade Screen.h" #include "gameloop.h" #include "finances.h" #include "SaveLoadMap.h" #include "Arms Dealer Init.h" #include "ShopKeeper Interface.h" #include "Strategic Town Loyalty.h" #include "Meanwhile.h" #include "GameSettings.h" #include "Strategic Mines.h" #include "Boxing.h" #include "worldman.h" #include "Render Fun.h" #include "Strategic Movement.h" #include "Soldier Create.h" #include "SkillCheck.h" #include "Sound Control.h" #include "opplist.h" #include "PreBattle Interface.h" #include "history.h" #include "Keys.h" #include "Morale.h" #include "personnel.h" #include "Map Screen Interface.h" #include "Campaign.h" #include "BobbyRMailOrder.h" #include "End Game.h" #include "Map Screen Helicopter.h" #include "Soldier Control.h" #include "LuaInitNPCs.h" #include "Luaglobal.h" #ifdef JA2UB #include "Explosion Control.h" #include "Ja25_Tactical.h" #include "Ja25 Strategic Ai.h" #include "Soldier macros.h" #include "LOS.h" #include "Ja25Update.h" #include "ub_config.h" #else // anv: for playable Speck #include "Speck Quotes.h" #include "mercs.h" #endif #ifndef _DEBUG #include "Cheats.h" #endif //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; //DBrot: not needed anymore, got an option for those //INT32 sBasementEnterGridNos[ ] = { 13362, 13363, 13364, 13365, 13525, 13524 }; //INT32 sBasementExitGridNos[ ] = { 8047, 8207, 8208, 8048, 7888, 7728, 7727, 7567 }; extern UINT8 gubWaitingForAllMercsToExitCode; extern BOOLEAN fFoundTixa; void DoneFadeOutActionBasement( void ); void DoneFadeOutActionSex( void ); void DoneFadeInActionBasement( void ); void DoneFadeOutActionLeaveBasement( void ); void DoneFadeInActionLeaveBasement( void ); BOOLEAN NPCOpenThing( SOLDIERTYPE *pSoldier, BOOLEAN fDoor ); UINT16 gusDialogueMessageBoxType; void StartDialogueMessageBox( UINT8 ubProfileID, UINT16 usMessageBoxType ); void DialogueMessageBoxCallBack( UINT8 ubExitValue ); void CarmenLeavesSectorCallback( void ); #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_REGION_STARTX 102 #define TALK_PANEL_REGION_STARTY 14 #define TALK_PANEL_REGION_SPACEY 16 #define TALK_PANEL_REGION_HEIGHT 12 #define TALK_PANEL_REGION_WIDTH 95 #define TALK_PANEL_MENUTEXT_STARTX 102 #define TALK_PANEL_MENUTEXT_STARTY 16 #define TALK_PANEL_MENUTEXT_SPACEY 16 #define TALK_PANEL_MENUTEXT_HEIGHT 13 #define TALK_PANEL_MENUTEXT_WIDTH 95 #define TALK_PANEL_BUTTON_X 112 #define TALK_PANEL_BUTTON_Y 114 #define TALK_PANEL_SHADOW_AREA_X 97 #define TALK_PANEL_SHADOW_AREA_Y 9 #define TALK_PANEL_SHADOW_AREA_WIDTH 107 #define TALK_PANEL_SHADOW_AREA_HEIGHT 102 #define TALK_PANEL_START_OFFSET_X 10 #define TALK_PANEL_DEFAULT_SUBTITLE_WIDTH 200 #define TALK_PANEL_CALC_SUBTITLE_WIDTH 280 #define TALK_PANEL_CALC_SUBTITLE_HEIGHT 125 #define TALK_PANEL_POPUP_LEFT 0 #define TALK_PANEL_POPUP_TOP 1 #define TALK_PANEL_POPUP_BOTTOM 2 #define TALK_PANEL_POPUP_RIGHT 3 // chance vince will say random quote to player during conv. #define CHANCE_FOR_DOCTOR_TO_SAY_RANDOM_QUOTE 20 // NPC talk panel UI stuff void TalkPanelMoveCallback( MOUSE_REGION * pRegion, INT32 iReason ); void TalkPanelClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); void TextRegionClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); void TalkPanelBaseRegionClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); void TalkPanelNameRegionMoveCallback( MOUSE_REGION * pRegion, INT32 iReason ); void TalkPanelNameRegionClickCallback( MOUSE_REGION * pRegion, INT32 iReason ); void DoneTalkingButtonClickCallback(GUI_BUTTON *btn, INT32 reason ); void CalculatePopupTextPosition( INT16 sWidth, INT16 sHeight ); void CalculatePopupTextOrientation( INT16 sWidth, INT16 sHeight ); void HandleNPCTrigger( ); BOOLEAN InternalInitiateConversation( SOLDIERTYPE *pDestSoldier, SOLDIERTYPE *pSrcSoldier, INT8 bApproach, UINT32 uiApproachData ); extern void EndGameMessageBoxCallBack( UINT8 ubExitValue ); extern INT32 FindNearestOpenableNonDoor( INT32 sStartGridNo ); extern void RecalculateOppCntsDueToBecomingNeutral( SOLDIERTYPE * pSoldier ); extern UINT16 NumCapableEnemyInSector( ); #ifdef JA2UB //JA25 UB void PerformJerryMiloAction301(); void PerformJerryMiloAction302(); void DelayedMercQuote( UINT16 usProfileID, UINT32 uiQuoteNum, UINT32 uiTimeTillQuoteSaid ); void DelayedSayingOfMercQuote( UINT32 uiParam ); void HandleSpecificQuoteWhenLeavingNpcTalkMenu(); void HaveQualifiedMercSayQuoteAboutNpcWhenLeavingTalkScreen( UINT8 ubNpcProfileID, UINT32 uiQuoteNum ); void CheckForValidQuotesWhenLeavingDealer( UINT8 ubProfile ); BOOLEAN IsMineEntranceInSectorI13AtThisGridNo( UINT32 sGridNo ); void HaveBiggensDetonatingExplosivesByTheMine(); void ReplaceMineEntranceGraphicWithCollapsedEntrance(); void HandleCannotAffordNpcMsgBox(); void CantAffordMercCallback( UINT8 ubExitValue ); void HandleMercArrivesQuotesFromHeliCrashSequence(); void HandleRaulBlowingHimselfUp(); void HandleTexFlushingToilet(); void HandleTexMakingHimselfAlreadyBeIntroduced(); void DisplayJerryBreakingLaptopTransmitterPopup(); void HaveNpcOpenUpDealerScreen( UINT8 ubProfileID ); void HandleTexBecomingCamoed(); #endif UINT8 ubTalkMenuApproachIDs[] = { APPROACH_REPEAT, APPROACH_FRIENDLY, APPROACH_DIRECT, APPROACH_THREATEN, APPROACH_BUYSELL, APPROACH_RECRUIT }; enum { DIALOG_DONE, DIALOG_BUY_SELL, }; // GLOBAL NPC STRUCT NPC_DIALOGUE_TYPE gTalkPanel; BOOLEAN gfInTalkPanel = FALSE; SOLDIERTYPE *gpSrcSoldier = NULL; SOLDIERTYPE *gpDestSoldier = NULL; UINT8 gubSrcSoldierProfile; UINT8 gubNiceNPCProfile = NO_PROFILE; UINT8 gubNastyNPCProfile = NO_PROFILE; UINT8 gubTargetNPC; UINT8 gubTargetRecord; UINT8 gubTargetApproach; BOOLEAN gfShowDialogueMenu; BOOLEAN gfWaitingForTriggerTimer; UINT32 guiWaitingForTriggerTime; INT32 iInterfaceDialogueBox = -1; UINT8 ubRecordThatTriggeredLiePrompt; BOOLEAN gfConversationPending = FALSE; SOLDIERTYPE *gpPendingDestSoldier; SOLDIERTYPE *gpPendingSrcSoldier; INT8 gbPendingApproach; UINT32 guiPendingApproachData; extern BOOLEAN fMapPanelDirty; INT32 giHospitalTempBalance; // stores amount of money for current doctoring INT32 giHospitalRefund; // stores amount of money given to hospital for doctoring that wasn't used INT8 gbHospitalPriceModifier; // stores discount being offered void StartDialogueMessageBox( UINT8 ubProfileID, UINT16 usMessageBoxType ); #ifdef JA2UB //ja25 ub BOOLEAN gfDisplayMsgBoxSayingCantAffordNPC=FALSE; #endif enum { HOSPITAL_UNSET = 0, HOSPITAL_NORMAL, HOSPITAL_BREAK, HOSPITAL_COST, HOSPITAL_FREEBIE, HOSPITAL_RANDOM_FREEBIE, }; BOOLEAN InitiateConversation( SOLDIERTYPE *pDestSoldier, SOLDIERTYPE *pSrcSoldier, INT8 bApproach, UINT32 uiApproachData ) { DebugQuestInfo(String("InitiateConversation: from [%d] to [%d] %d data %d", pSrcSoldier->ubID, pDestSoldier->ubID, bApproach, uiApproachData)); // ATE: OK, let's check the status of the Q // If it has something in it....delay this until after.... if ( DialogueQueueIsEmptyOrSomebodyTalkingNow( ) ) { gfConversationPending = FALSE; // Initiate directly.... return( InternalInitiateConversation( pDestSoldier, pSrcSoldier, bApproach, uiApproachData ) ); } else { // Wait..... gfConversationPending = TRUE; gpPendingDestSoldier = pDestSoldier; gpPendingSrcSoldier = pSrcSoldier; gbPendingApproach = bApproach; guiPendingApproachData= uiApproachData; //Engaged on conv... gTacticalStatus.uiFlags |= ENGAGED_IN_CONV; // Turn off lock UI ( if on ) guiPendingOverrideEvent = LU_ENDUILOCK; HandleTacticalUI( ); // Turn on talking ui guiPendingOverrideEvent = TA_TALKINGMENU; HandleTacticalUI( ); return( FALSE ); } } void HandlePendingInitConv( ) { if ( gfConversationPending ) { // OK, if pending, remove and now call........ InternalInitiateConversation( gpPendingDestSoldier, gpPendingSrcSoldier, gbPendingApproach, guiPendingApproachData ); } } BOOLEAN InternalInitiateConversation( SOLDIERTYPE *pDestSoldier, SOLDIERTYPE *pSrcSoldier, INT8 bApproach, UINT32 uiApproachData ) { // OK, init talking menu BOOLEAN fFromPending; fFromPending = gfConversationPending; // Set pending false gfConversationPending = FALSE; // ATE: If we are already in menu, delete! if ( gfInTalkPanel ) { DeleteTalkingMenu( ); } if ( !InitTalkingMenu( pDestSoldier->ubProfile, pDestSoldier->sGridNo ) ) { // If failed, and we were pending, unlock UI if ( fFromPending ) { gTacticalStatus.uiFlags &= (~ENGAGED_IN_CONV); } #ifdef JA2TESTVERSION ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"Cannot initiate conversation menu.. check for face file for ID: %d.", pDestSoldier->ubProfile ); #endif return( FALSE ); } // Set soldier pointer gpSrcSoldier = pSrcSoldier; gpDestSoldier = pDestSoldier; // Say first line... // CHRIS LOOK HERE if ( gpSrcSoldier != NULL ) { gubSrcSoldierProfile = gpSrcSoldier->ubProfile; } else { gubSrcSoldierProfile = NO_PROFILE; } // find which squad this guy is, then set selected squad to this guy if ( pSrcSoldier->bTeam == gbPlayerNum && gTacticalStatus.ubCurrentTeam == gbPlayerNum ) { SetCurrentSquad( gpSrcSoldier->bAssignment, FALSE ); SelectSoldier( pSrcSoldier->ubID, FALSE, FALSE ); } Converse( gTalkPanel.ubCharNum, gubSrcSoldierProfile, bApproach, uiApproachData ); // If not from pedning... if ( !fFromPending ) { //Engaged on conv... gTacticalStatus.uiFlags |= ENGAGED_IN_CONV; // Turn off lock UI ( if on ) guiPendingOverrideEvent = LU_ENDUILOCK; HandleTacticalUI( ); // Turn on talking ui guiPendingOverrideEvent = TA_TALKINGMENU; HandleTacticalUI( ); } else { guiPendingOverrideEvent = TA_TALKINGMENU; HandleTacticalUI( ); } return( TRUE ); } BOOLEAN InitTalkingMenu( UINT8 ubCharacterNum, INT32 sGridNo ) { INT16 sXMapPos, sYMapPos, sScreenX, sScreenY; INT16 sX, sY; // Get XY values { // Get XY locations for gridno. ConvertGridNoToXY( sGridNo, &sXMapPos, &sYMapPos ); // Get screen XY pos from map XY // Be carefull to convert to cell cords CellXYToScreenXY( (INT16)((sXMapPos*CELL_X_SIZE)), (INT16)((sYMapPos*CELL_Y_SIZE)), &sScreenX, &sScreenY); // First get mouse xy screen location sX = sScreenX; sY = sScreenY; return( InternalInitTalkingMenu( ubCharacterNum, sX, sY ) ); } } BOOLEAN InternalInitTalkingMenu( UINT8 ubCharacterNum, INT16 sX, INT16 sY ) { INT32 iFaceIndex, cnt; VSURFACE_DESC vs_desc; FACETYPE *pFace; UINT16 usWidth; UINT16 usHeight; VOBJECT_DESC VObjectDesc; INT16 sCenterYVal, sCenterXVal; CHAR8 ubString[48]; // disable scroll messages HideMessagesDuringNPCDialogue( ); //ATE: OK, let go of any other dialogues up..... EraseInterfaceMenus( FALSE ); gTalkPanel.ubCharNum = ubCharacterNum; gTalkPanel.bCurSelect = -1; gTalkPanel.bOldCurSelect = -1; gTalkPanel.fHandled = FALSE; gTalkPanel.fOnName = FALSE; // Load Video gTempObject! VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; sprintf( VObjectDesc.ImageFile, "INTERFACE\\talkbox1.sti" ); // Load if( AddVideoObject( &VObjectDesc, &( gTalkPanel.uiPanelVO ) ) == FALSE ) { return( 0 ); } // Get ETRLE Properties GetVideoObjectETRLESubregionProperties( gTalkPanel.uiPanelVO, 0, &usWidth, &usHeight ); // Set values into structure gTalkPanel.usWidth = usWidth; gTalkPanel.usHeight = usHeight; // Check coords { // CHECK FOR LEFT/RIGHT sCenterXVal = gTalkPanel.usWidth / 2; sX -= sCenterXVal; // Check right if ( ( sX + gTalkPanel.usWidth ) > SCREEN_WIDTH ) { sX = SCREEN_WIDTH - gTalkPanel.usWidth; } // Check left if ( sX < 0 ) { sX = 0; } // Now check for top // Center in the y sCenterYVal = gTalkPanel.usHeight / 2; sY -= sCenterYVal; if ( sY < gsVIEWPORT_WINDOW_START_Y ) { sY = gsVIEWPORT_WINDOW_START_Y; } // Check for bottom if ( ( sY + gTalkPanel.usHeight ) > INV_INTERFACE_START_Y ) { sY = INV_INTERFACE_START_Y - gTalkPanel.usHeight; } } //Set values gTalkPanel.sX = sX; gTalkPanel.sY = sY; CalculatePopupTextOrientation( TALK_PANEL_CALC_SUBTITLE_WIDTH, TALK_PANEL_CALC_SUBTITLE_HEIGHT ); // Create face ( a big face! ).... iFaceIndex = InitFace( ubCharacterNum, NOBODY, FACE_BIGFACE | FACE_POTENTIAL_KEYWAIT ); CHECKF( iFaceIndex != -1 ); // Set face gTalkPanel.iFaceIndex = iFaceIndex; // Init face to auto..., create video overlay.... pFace = &gFacesData[ iFaceIndex ]; // Create mouse regions... sX = gTalkPanel.sX + TALK_PANEL_REGION_STARTX; sY = gTalkPanel.sY + TALK_PANEL_REGION_STARTY; //Define main region MSYS_DefineRegion( &(gTalkPanel.ScreenRegion), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT , MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK ); // Add region MSYS_AddRegion(&(gTalkPanel.ScreenRegion) ); //Define main region MSYS_DefineRegion( &(gTalkPanel.BackRegion), (INT16)(gTalkPanel.sX), (INT16)(gTalkPanel.sY), (INT16)(gTalkPanel.sX + gTalkPanel.usWidth ),(INT16)( gTalkPanel.sY + gTalkPanel.usHeight ), MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, TalkPanelBaseRegionClickCallback ); // Add region MSYS_AddRegion(&(gTalkPanel.BackRegion) ); //Define name region MSYS_DefineRegion( &(gTalkPanel.NameRegion), (INT16)(gTalkPanel.sX + TALK_PANEL_NAME_X ), (INT16)(gTalkPanel.sY + TALK_PANEL_NAME_Y), (INT16)(gTalkPanel.sX + TALK_PANEL_NAME_WIDTH + TALK_PANEL_NAME_X ),(INT16)( gTalkPanel.sY + TALK_PANEL_NAME_HEIGHT + TALK_PANEL_NAME_Y ), MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, TalkPanelNameRegionMoveCallback, TalkPanelNameRegionClickCallback ); // Add region MSYS_AddRegion(&(gTalkPanel.NameRegion) ); for ( cnt = 0; cnt < 6; cnt++ ) { // Build a mouse region here that is over any others..... MSYS_DefineRegion( &(gTalkPanel.Regions[cnt]), (INT16)(sX), (INT16)(sY), (INT16)(sX + TALK_PANEL_REGION_WIDTH ),(INT16)( sY + TALK_PANEL_REGION_HEIGHT ), MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, TalkPanelMoveCallback, TalkPanelClickCallback ); // Add region MSYS_AddRegion( &(gTalkPanel.Regions[cnt])); MSYS_SetRegionUserData( &(gTalkPanel.Regions[cnt]), 0, cnt ); sY += TALK_PANEL_REGION_SPACEY; } // Build save buffer // Create a buffer for him to go! // OK, ignore screen widths, height, only use BPP vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE; vs_desc.usWidth = pFace->usFaceWidth; vs_desc.usHeight = pFace->usFaceHeight; vs_desc.ubBitDepth = 16; CHECKF( AddVideoSurface( &vs_desc, &(gTalkPanel.uiSaveBuffer ) ) ); // Set face to auto SetAutoFaceActive( gTalkPanel.uiSaveBuffer, FACE_AUTO_RESTORE_BUFFER, iFaceIndex , 0, 0 ); gFacesData[ iFaceIndex ].uiFlags |= FACE_INACTIVE_HANDLED_ELSEWHERE; // Load buttons, create button sprintf( ubString, "INTERFACE\\talkbox2.sti" ); gTalkPanel.iButtonImages = LoadButtonImage( ubString, -1,3,-1,4,-1 ); gTalkPanel.uiCancelButton = CreateIconAndTextButton( gTalkPanel.iButtonImages, zDialogActions[ DIALOG_DONE ], MILITARYFONT1, 33, DEFAULT_SHADOW, 33, DEFAULT_SHADOW, TEXT_CJUSTIFIED, (INT16)(gTalkPanel.sX + TALK_PANEL_BUTTON_X), (INT16)(gTalkPanel.sY + TALK_PANEL_BUTTON_Y), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)DoneTalkingButtonClickCallback ); SpecifyButtonHilitedTextColors( gTalkPanel.uiCancelButton, FONT_MCOLOR_WHITE, DEFAULT_SHADOW ); // Turn off dirty flags ButtonList[ gTalkPanel.uiCancelButton ]->uiFlags &= (~BUTTON_DIRTY); // Render once! RenderAutoFace( gTalkPanel.iFaceIndex ); gfInTalkPanel = TRUE; gfIgnoreScrolling = TRUE; // return OK.... return( TRUE ); } void DoneTalkingButtonClickCallback(GUI_BUTTON *btn, INT32 reason ) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) { btn->uiFlags |= BUTTON_CLICKED_ON; } else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { btn->uiFlags &= (~BUTTON_CLICKED_ON ); // OK, pickup item.... gTalkPanel.fHandled = TRUE; gTalkPanel.fHandledTalkingVal = gFacesData[ gTalkPanel.iFaceIndex ].fTalking; gTalkPanel.fHandledCanDeleteVal = TRUE; } } void DeleteTalkingMenu( ) { INT32 cnt; if ( !gfInTalkPanel ) return; // Delete sound if playing.... ShutupaYoFace( gTalkPanel.iFaceIndex ); // Delete screen region MSYS_RemoveRegion( &(gTalkPanel.ScreenRegion)); // Delete main region MSYS_RemoveRegion( &(gTalkPanel.BackRegion)); // Delete name region MSYS_RemoveRegion( &(gTalkPanel.NameRegion)); // Delete mouse regions for ( cnt = 0; cnt < 6; cnt++ ) { MSYS_RemoveRegion( &(gTalkPanel.Regions[cnt])); } if ( gTalkPanel.fTextRegionOn ) { // Remove MSYS_RemoveRegion( &(gTalkPanel.TextRegion) ); gTalkPanel.fTextRegionOn = FALSE; } // Delete save buffer DeleteVideoSurfaceFromIndex( gTalkPanel.uiSaveBuffer ); // Remove video object DeleteVideoObjectFromIndex( gTalkPanel.uiPanelVO ); // Remove face.... DeleteFace( gTalkPanel.iFaceIndex ); // Remove button RemoveButton( gTalkPanel.uiCancelButton ); // Remove button images UnloadButtonImage( gTalkPanel.iButtonImages ); // Set cursor back to normal mode... guiPendingOverrideEvent = A_CHANGE_TO_MOVE; // 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 ); gfInTalkPanel = FALSE; gfIgnoreScrolling = FALSE; // Set this guy up as NOT engaged in conversation gpDestSoldier->flags.uiStatusFlags &= (~SOLDIER_ENGAGEDINACTION); //NOT Engaged on conv... if ( !giNPCReferenceCount ) { gTacticalStatus.uiFlags &= (~ENGAGED_IN_CONV); } // restore scroll messages in tactical UnHideMessagesDuringNPCDialogue( ); if ( CheckFact( FACT_NEED_TO_SAY_SOMETHING, 0 ) ) { if ( DialogueQueueIsEmpty() && !gfWaitingForTriggerTimer ) { UINT8 ubNPC; BOOLEAN fNice = FALSE; SOLDIERTYPE * pNPC; if ( gubNiceNPCProfile != NO_PROFILE ) { ubNPC = gubNiceNPCProfile; fNice = TRUE; } else { ubNPC = gubNastyNPCProfile; } if ( ubNPC != NO_PROFILE ) { pNPC = FindSoldierByProfileID( ubNPC, FALSE ); if (pNPC) { // find someone to say their "nice guy" line if ( fNice ) { SayQuote58FromNearbyMercInSector( pNPC->sGridNo, 10, QUOTE_LISTEN_LIKABLE_PERSON, gMercProfiles[ ubNPC ].bSex ); } else { SayQuoteFromNearbyMercInSector( pNPC->sGridNo, 10, QUOTE_ANNOYING_PC ); } gubNiceNPCProfile = NO_PROFILE; gubNastyNPCProfile = NO_PROFILE; SetFactFalse( FACT_NEED_TO_SAY_SOMETHING ); } } } } if ( iInterfaceDialogueBox != -1 ) { RemoveMercPopupBoxFromIndex( iInterfaceDialogueBox ); iInterfaceDialogueBox = -1; } // Save time for give item gTacticalStatus.uiTimeCounterForGiveItemSrc = GetJA2Clock( ); } void RenderTalkingMenu( ) { INT32 cnt; FACETYPE *pFace; INT16 sFontX, sFontY, sX, sY; UINT8 ubCharacterNum = gTalkPanel.ubCharNum; UINT32 uiDestPitchBYTES, uiSrcPitchBYTES; UINT8 *pDestBuf, *pSrcBuf; UINT16 usTextBoxWidth, usTextBoxHeight; CHAR16 zTempString[128]; if ( !gfInTalkPanel ) { return; } pFace = &gFacesData[ gTalkPanel.iFaceIndex ]; if ( gTalkPanel.fDirtyLevel == DIRTYLEVEL2 ) { SetFont( MILITARYFONT1 ); // Render box! BltVideoObjectFromIndex( FRAME_BUFFER, gTalkPanel.uiPanelVO, 0, gTalkPanel.sX, gTalkPanel.sY, VO_BLT_SRCTRANSPARENCY, NULL ); // Render name if ( gTalkPanel.fOnName ) { SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_WHITE ); } else { SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( 33 ); } VarFindFontCenterCoordinates( (INT16)(gTalkPanel.sX + TALK_PANEL_NAME_X), (INT16)(gTalkPanel.sY + TALK_PANEL_NAME_Y), TALK_PANEL_NAME_WIDTH, TALK_PANEL_NAME_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s", gMercProfiles[ gTalkPanel.ubCharNum ].zNickname ); mprintf( sFontX, sFontY, L"%s", gMercProfiles[ ubCharacterNum ].zNickname ); // Set font settings back SetFontShadow( DEFAULT_SHADOW ); pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES); pSrcBuf = LockVideoSurface( gTalkPanel.uiSaveBuffer, &uiSrcPitchBYTES); Blt16BPPTo16BPP((UINT16 *)pDestBuf, uiDestPitchBYTES, (UINT16 *)pSrcBuf, uiSrcPitchBYTES, (INT16)(gTalkPanel.sX + TALK_PANEL_FACE_X), (INT16)(gTalkPanel.sY + TALK_PANEL_FACE_Y), 0 , 0, pFace->usFaceWidth, pFace->usFaceHeight ); UnLockVideoSurface( FRAME_BUFFER ); UnLockVideoSurface( gTalkPanel.uiSaveBuffer ); MarkButtonsDirty( ); // If guy is talking.... shadow area if ( pFace->fTalking || !DialogueQueueIsEmpty( ) ) { ShadowVideoSurfaceRect( FRAME_BUFFER, (INT16)(gTalkPanel.sX + TALK_PANEL_SHADOW_AREA_X),(INT16)(gTalkPanel.sY + TALK_PANEL_SHADOW_AREA_Y), (INT16)(gTalkPanel.sX + TALK_PANEL_SHADOW_AREA_X + TALK_PANEL_SHADOW_AREA_WIDTH) , (INT16)(gTalkPanel.sY + TALK_PANEL_SHADOW_AREA_Y + TALK_PANEL_SHADOW_AREA_HEIGHT) ); // Disable mouse regions.... for ( cnt = 0; cnt < 6; cnt++ ) { MSYS_DisableRegion( &(gTalkPanel.Regions[cnt])); } DisableButton( gTalkPanel.uiCancelButton ); gTalkPanel.bCurSelect = -1; } else { // Enable mouse regions.... for ( cnt = 0; cnt < 6; cnt++ ) { MSYS_EnableRegion( &(gTalkPanel.Regions[cnt])); } // Restore selection.... gTalkPanel.bCurSelect = gTalkPanel.bOldCurSelect; EnableButton( gTalkPanel.uiCancelButton ); } InvalidateRegion( gTalkPanel.sX, gTalkPanel.sY, gTalkPanel.sX + gTalkPanel.usWidth, gTalkPanel.sY + gTalkPanel.usHeight ); if ( gTalkPanel.fSetupSubTitles ) { if ( iInterfaceDialogueBox != -1 ) { // Remove any old ones.... RemoveMercPopupBoxFromIndex( iInterfaceDialogueBox ); iInterfaceDialogueBox = -1; } iInterfaceDialogueBox = PrepareMercPopupBox( iInterfaceDialogueBox,BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gTalkPanel.zQuoteStr, TALK_PANEL_DEFAULT_SUBTITLE_WIDTH, 0, 0, 0, &usTextBoxWidth, &usTextBoxHeight ); gTalkPanel.fSetupSubTitles = FALSE; CalculatePopupTextOrientation( usTextBoxWidth, usTextBoxHeight ); CalculatePopupTextPosition( usTextBoxWidth, usTextBoxHeight ); //Define main region if ( gTalkPanel.fTextRegionOn ) { // Remove MSYS_RemoveRegion( &(gTalkPanel.TextRegion) ); gTalkPanel.fTextRegionOn = FALSE; } MSYS_DefineRegion( &(gTalkPanel.TextRegion), gTalkPanel.sPopupX, gTalkPanel.sPopupY, (INT16)( gTalkPanel.sPopupX + usTextBoxWidth ), (INT16)( gTalkPanel.sPopupY + usTextBoxHeight ), MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, TextRegionClickCallback ); // Add region MSYS_AddRegion(&(gTalkPanel.TextRegion) ); // Set to true gTalkPanel.fTextRegionOn = TRUE; } if ( gTalkPanel.fRenderSubTitlesNow ) { RenderMercPopUpBoxFromIndex( iInterfaceDialogueBox, gTalkPanel.sPopupX, gTalkPanel.sPopupY, FRAME_BUFFER ); } } if ( gTalkPanel.fDirtyLevel > DIRTYLEVEL0 ) { SetFont( MILITARYFONT1 ); // Set some font settings SetFontForeground( FONT_BLACK ); SetFontShadow( MILITARY_SHADOW ); // Create menu selections.... sX = gTalkPanel.sX + TALK_PANEL_MENUTEXT_STARTX; sY = gTalkPanel.sY + TALK_PANEL_MENUTEXT_STARTY; for ( cnt = 0; cnt < 6; cnt++ ) { if ( gTalkPanel.bCurSelect == cnt ) { SetFontForeground( FONT_WHITE ); SetFontShadow( DEFAULT_SHADOW ); } else { SetFontForeground( FONT_BLACK ); SetFontShadow( MILITARY_SHADOW ); } { #ifdef _DEBUG if (gubSrcSoldierProfile != NO_PROFILE && ubCharacterNum != NO_PROFILE) #else if ( CHEATER_CHEAT_LEVEL() && gubSrcSoldierProfile != NO_PROFILE && ubCharacterNum != NO_PROFILE) #endif { switch( cnt ) { case 0: VarFindFontCenterCoordinates( sX, sY, TALK_PANEL_MENUTEXT_WIDTH, TALK_PANEL_MENUTEXT_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s", zTalkMenuStrings[ cnt ] ); mprintf( sFontX, sFontY, L"%s", zTalkMenuStrings[ cnt ] ); break; case 4: //if its an arms dealer if( IsMercADealer( ubCharacterNum ) ) { UINT8 ubType; //determine the 'kind' of arms dealer ubType = GetTypeOfArmsDealer( GetArmsDealerIDFromMercID( ubCharacterNum ) ); wcscpy( zTempString, zDealerStrings[ ubType ] ); } else wcscpy( zTempString, zTalkMenuStrings[ cnt ] ); VarFindFontCenterCoordinates( sX, sY, TALK_PANEL_MENUTEXT_WIDTH, TALK_PANEL_MENUTEXT_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s", zTempString ); mprintf( sFontX, sFontY, L"%s", zTempString ); break; default: VarFindFontCenterCoordinates( sX, sY, TALK_PANEL_MENUTEXT_WIDTH, TALK_PANEL_MENUTEXT_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s (%d)", zTalkMenuStrings[ cnt ], ubTalkMenuApproachIDs[ cnt ] ); mprintf( sFontX, sFontY, L"%s (%d)", zTalkMenuStrings[ cnt ], CalcDesireToTalk( ubCharacterNum, gubSrcSoldierProfile, ubTalkMenuApproachIDs[ cnt ] ) ); break; } } else { if( cnt == 4 ) { //if its an arms dealer if( IsMercADealer( ubCharacterNum ) ) { UINT8 ubType; //determine the 'kind' of arms dealer ubType = GetTypeOfArmsDealer( GetArmsDealerIDFromMercID( ubCharacterNum ) ); wcscpy( zTempString, zDealerStrings[ ubType ] ); } else wcscpy( zTempString, zTalkMenuStrings[ cnt ] ); VarFindFontCenterCoordinates( sX, sY, TALK_PANEL_MENUTEXT_WIDTH, TALK_PANEL_MENUTEXT_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s", zTempString ); mprintf( sFontX, sFontY, L"%s", zTempString ); } else { VarFindFontCenterCoordinates( sX, sY, TALK_PANEL_MENUTEXT_WIDTH, TALK_PANEL_MENUTEXT_HEIGHT, MILITARYFONT1, &sFontX, &sFontY, L"%s", zTalkMenuStrings[ cnt ] ); mprintf( sFontX, sFontY, L"%s", zTalkMenuStrings[ cnt ] ); } } } sY += TALK_PANEL_MENUTEXT_SPACEY; } } // Set font settings back SetFontShadow( DEFAULT_SHADOW ); gTalkPanel.fDirtyLevel = 0; } void TalkPanelMoveCallback( MOUSE_REGION * pRegion, INT32 iReason ) { UINT32 uiItemPos; uiItemPos = MSYS_GetRegionUserData( pRegion, 0 ); if (iReason & MSYS_CALLBACK_REASON_MOVE) { // Set current selected guy.... gTalkPanel.bCurSelect =(INT8)uiItemPos; gTalkPanel.bOldCurSelect = gTalkPanel.bCurSelect; } else if ( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { gTalkPanel.bCurSelect = -1; gTalkPanel.bOldCurSelect = -1; } } void TalkPanelClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) { UINT32 uiItemPos; BOOLEAN fDoConverse = TRUE; uiItemPos = MSYS_GetRegionUserData( pRegion, 0 ); if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) { // Donot do this if we are talking already if ( !gFacesData[ gTalkPanel.iFaceIndex ].fTalking ) { if ( ubTalkMenuApproachIDs[ uiItemPos ] == APPROACH_BUYSELL ) { //if its an arms dealer if( IsMercADealer( gTalkPanel.ubCharNum ) ) { if ( NPCHasUnusedRecordWithGivenApproach( gTalkPanel.ubCharNum, APPROACH_BUYSELL ) ) { TriggerNPCWithGivenApproach( gTalkPanel.ubCharNum, APPROACH_BUYSELL, TRUE ); } else { DeleteTalkingMenu( ); //Enter the shopkeeper interface EnterShopKeeperInterfaceScreen( gTalkPanel.ubCharNum ); } /* // check if this is a shopkeeper who has been shutdown if( HandleShopKeepHasBeenShutDown( gTalkPanel.ubCharNum ) == FALSE ) { DeleteTalkingMenu( ); EnterShopKeeperInterfaceScreen( gTalkPanel.ubCharNum ); } */ } else { // Do something different if we selected the 'give' approach // Close panel, set UI guy to wait a sec, open inv if not done so yet gTalkPanel.fHandled = TRUE; gTalkPanel.fHandledTalkingVal = gFacesData[ gTalkPanel.iFaceIndex ].fTalking; gTalkPanel.fHandledCanDeleteVal = TRUE; // open inv panel... gfSwitchPanel = TRUE; gbNewPanel = SM_PANEL; gubNewPanelParam = gpSrcSoldier->ubID; // Wait! gpDestSoldier->aiData.bNextAction = AI_ACTION_WAIT; gpDestSoldier->aiData.usNextActionData = 10000; // UNless he's has a pending action, delete what he was doing! // Cancel anything he was doing if ( gpDestSoldier->aiData.bAction != AI_ACTION_PENDING_ACTION ) { CancelAIAction( gpDestSoldier, TRUE ); } } } else { if ( fDoConverse ) { //Speak Converse( gTalkPanel.ubCharNum, gubSrcSoldierProfile, (INT8)ubTalkMenuApproachIDs[ uiItemPos ], 0 ); } } } } else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP) { } } void TalkPanelBaseRegionClickCallback( 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 ) { // Only do this if we are talking already if ( gFacesData[ gTalkPanel.iFaceIndex ].fTalking ) { // Stop speech, cancel InternalShutupaYoFace( gTalkPanel.iFaceIndex, FALSE ); fLButtonDown = FALSE; } } else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { fLButtonDown = FALSE; } } void TalkPanelNameRegionClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) { // Donot do this if we are talking already if ( !gFacesData[ gTalkPanel.iFaceIndex ].fTalking ) { // Say who are you? Converse( gTalkPanel.ubCharNum, gubSrcSoldierProfile, NPC_WHOAREYOU, 0 ); } } else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP) { } } void TalkPanelNameRegionMoveCallback( MOUSE_REGION * pRegion, INT32 iReason ) { // Donot do this if we are talking already if ( gFacesData[ gTalkPanel.iFaceIndex ].fTalking ) { return; } if (iReason & MSYS_CALLBACK_REASON_MOVE) { // Set current selected guy.... gTalkPanel.fOnName = TRUE; } else if ( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { gTalkPanel.fOnName = FALSE; } } // Dirty menu void SetTalkingMenuDirty( BOOLEAN fDirtyLevel ) { gTalkPanel.fDirtyLevel = fDirtyLevel; } BOOLEAN HandleTalkingMenu( ) { if ( !gfInTalkPanel ) { return( FALSE ); } if ( gTalkPanel.fHandled ) { return( HandleTalkingMenuEscape( gTalkPanel.fHandledCanDeleteVal, FALSE ) ); } return( FALSE ); } BOOLEAN TalkingMenuDialogue( UINT16 usQuoteNum ) { // Set back current select.... gTalkPanel.bCurSelect = -1; gTalkPanel.fOnName = FALSE; //gTalkPanel.fHandled = FALSE; CHECKF( CharacterDialogue( gTalkPanel.ubCharNum, usQuoteNum, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI, FALSE, FALSE ) != FALSE ); return( TRUE ); } BOOLEAN ProfileCurrentlyTalkingInDialoguePanel( UINT8 ubProfile ) { if ( gfInTalkPanel ) { if ( gpDestSoldier != NULL ) { if ( gpDestSoldier->ubProfile == ubProfile ) { return( TRUE ); } } } return( FALSE ); } BOOLEAN HandleTalkingMenuEscape( BOOLEAN fCanDelete , BOOLEAN fFromEscKey ) { FACETYPE *pFace; BOOLEAN fTalking = FALSE; if ( !gfInTalkPanel ) { return( FALSE ); } pFace = &gFacesData[ gTalkPanel.iFaceIndex ]; // If we are in the process of speaking, stop this quote an move on... // If we have been 'handled' by an outside source, check what was our talking value at the time if ( gTalkPanel.fHandled ) { fTalking = gTalkPanel.fHandledTalkingVal; } else { fTalking = pFace->fTalking; } // Set to false gTalkPanel.fHandled = FALSE; if ( !fFromEscKey ) { if ( fTalking ) { ShutupaYoFace( gTalkPanel.iFaceIndex ); } // Else if our queue is empty, delete menu else { if ( DialogueQueueIsEmpty( ) && fCanDelete ) { // Delete panel DeleteTalkingMenu( ); // reset records which are on a can-say-once-per-convo basis ResetOncePerConvoRecordsForNPC( gpDestSoldier->ubProfile ); return( TRUE ); } } } else { if ( DialogueQueueIsEmpty( ) && fCanDelete ) { // Delete panel DeleteTalkingMenu( ); // reset records which are on a can-say-once-per-convo basis ResetOncePerConvoRecordsForNPC( gpDestSoldier->ubProfile ); return( TRUE ); } } return( FALSE ); } void HandleTalkingMenuBackspace( void ) { FACETYPE *pFace; if ( !gfInTalkPanel ) { return; } pFace = &gFacesData[ gTalkPanel.iFaceIndex ]; // If we are in the process of speaking, stop this quote an move on... // If we have been 'handled' by an outside source, check what was our talking value at the time /* if ( gTalkPanel.fHandled ) { fTalking = gTalkPanel.fHandledTalkingVal; } else { fTalking = pFace->fTalking; } // Set to false gTalkPanel.fHandled = FALSE; if ( fTalking ) */ if ( pFace->fTalking ) { ShutupaYoFace( gTalkPanel.iFaceIndex ); } } void CalculatePopupTextOrientation( INT16 sWidth, INT16 sHeight ) { BOOLEAN fOKLeft = FALSE, fOKTop = FALSE, fOKBottom = FALSE, fOK = FALSE; INT16 sX, sY; // Check Left sX = gTalkPanel.sX - sWidth; if ( sX > 0 ) { fOKLeft = TRUE; } // Check bottom sY = gTalkPanel.sY + sHeight + gTalkPanel.usHeight; if ( sY < INV_INTERFACE_START_Y ) { fOKBottom = TRUE; } // Check top sY = gTalkPanel.sY - sHeight; if ( sY > gsVIEWPORT_WINDOW_START_Y ) { fOKTop = TRUE; } // OK, now decide where to put it! // First precidence is bottom if ( fOKBottom ) { gTalkPanel.ubPopupOrientation = TALK_PANEL_POPUP_BOTTOM; fOK = TRUE; } if ( !fOK ) { // Try left if ( fOKLeft ) { // Our panel should not be heigher than our dialogue talking panel, so don't bother with the height checks! gTalkPanel.ubPopupOrientation = TALK_PANEL_POPUP_LEFT; fOK = TRUE; } } // Now at least top should work if ( !fOK ) { // Try top! if ( fOKTop ) { gTalkPanel.ubPopupOrientation = TALK_PANEL_POPUP_TOP; fOK = TRUE; } } // failed all the above if( !fOK ) { // when all else fails go right gTalkPanel.ubPopupOrientation = TALK_PANEL_POPUP_RIGHT; fOK = TRUE; } // If we don't have anything here... our viewport/box is too BIG! ( which should never happen //DebugMsg } void CalculatePopupTextPosition( INT16 sWidth, INT16 sHeight ) { switch( gTalkPanel.ubPopupOrientation ) { case TALK_PANEL_POPUP_LEFT: // Set it here! gTalkPanel.sPopupX = gTalkPanel.sX - sWidth; // Center in height! gTalkPanel.sPopupY = gTalkPanel.sY + ( gTalkPanel.usHeight / 2 ) - ( sHeight / 2 ); break; case TALK_PANEL_POPUP_RIGHT: // Set it here! gTalkPanel.sPopupX = gTalkPanel.sX + gTalkPanel.usWidth + 1; // Center in height! gTalkPanel.sPopupY = gTalkPanel.sY + ( gTalkPanel.usHeight / 2 ) - ( sHeight / 2 ); break; case TALK_PANEL_POPUP_BOTTOM: // Center in X gTalkPanel.sPopupX = gTalkPanel.sX + ( gTalkPanel.usWidth / 2 ) - ( sWidth / 2 ); // Calc height gTalkPanel.sPopupY = gTalkPanel.sY + gTalkPanel.usHeight; break; case TALK_PANEL_POPUP_TOP: // Center in X gTalkPanel.sPopupX = gTalkPanel.sX + ( gTalkPanel.usWidth / 2 ) - ( sWidth / 2 ); // Calc height gTalkPanel.sPopupY = gTalkPanel.sY - sHeight; break; } } BOOLEAN TalkingMenuGiveItem( UINT8 ubNPC, OBJECTTYPE *pObject, INT8 bInvPos ) { CHECKF( SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_GIVE_ITEM, (UINT32) ubNPC, (UINT32)pObject, (UINT32) bInvPos, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI ) != FALSE ); return( TRUE ); } BOOLEAN NPCTriggerNPC( UINT8 ubTargetNPC, UINT8 ubTargetRecord, UINT8 ubTargetApproach, BOOLEAN fShowDialogueMenu ) { //CHECKF( SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_TRIGGER_NPC, ubTargetNPC, ubTargetRecord, fShowDialogueMenu, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI ) != FALSE ); CHECKF( SpecialCharacterDialogueEventWithExtraParam( DIALOGUE_SPECIAL_EVENT_TRIGGER_NPC, ubTargetNPC, ubTargetRecord, fShowDialogueMenu, ubTargetApproach, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI ) != FALSE ); DebugQuestInfo(String("NPCTriggerNPC: <%d>, record %d, %d, display %d", ubTargetNPC, ubTargetRecord, ubTargetApproach, fShowDialogueMenu)); return( TRUE ); } BOOLEAN NPCGotoGridNo( UINT8 ubTargetNPC, INT32 usGridNo, UINT8 ubRecordNum ) { CHECKF( SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_GOTO_GRIDNO, ubTargetNPC, usGridNo, ubRecordNum, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI ) != FALSE ); DebugQuestInfo(String("NPCGotoGridNo: <%d>, rec %d, usGridNo %d", ubTargetNPC, ubRecordNum, usGridNo)); return( TRUE ); } BOOLEAN NPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum ) { CHECKF( SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_DO_ACTION, ubTargetNPC, usActionCode, ubQuoteNum, gTalkPanel.iFaceIndex, DIALOGUE_NPC_UI ) != FALSE ); DebugQuestInfo(String("NPCDoAction:<%d>, action code %d, quote num %d", ubTargetNPC, usActionCode, ubQuoteNum)); return( TRUE ); } BOOLEAN NPCClosePanel( ) { CHECKF( SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_CLOSE_PANEL, 0, 0, 0, 0, DIALOGUE_NPC_UI ) != FALSE ); DebugQuestInfo(String("NPCClosePanel")); return( TRUE ); } BOOLEAN SourceSoldierPointerIsValidAndReachableForGive( SOLDIERTYPE * pGiver ) { INT32 sAdjGridNo; if ( !gpSrcSoldier ) { return( FALSE ); } if ( !gpSrcSoldier->bActive || !gpSrcSoldier->bInSector ) { return( FALSE ); } if ( gpSrcSoldier->stats.bLife < OKLIFE || ( gpSrcSoldier->bBreath < OKBREATH && gpSrcSoldier->bCollapsed ) ) { return( FALSE ); } if ( !pGiver ) { return( FALSE ); } // pointer should always be valid anyhow if( PythSpacesAway( pGiver->sGridNo, gpSrcSoldier->sGridNo ) > gpSrcSoldier->GetMaxDistanceVisible(pGiver->sGridNo, gpSrcSoldier->pathing.bLevel) ) { return FALSE; } sAdjGridNo = FindAdjacentGridEx( pGiver, gpSrcSoldier->sGridNo, NULL, NULL, FALSE, FALSE ); if ( sAdjGridNo == -1 ) { return( FALSE ); } return( TRUE ); } void HandleNPCItemGiven( UINT8 ubNPC, OBJECTTYPE *pObject, INT8 bInvPos ) { DebugQuestInfo(String("HandleNPCItemGiven: <%d> item %d inv %d", ubNPC, pObject->usItem, bInvPos)); // Give it to the NPC soldier // AutoPlaceObject( gpDestSoldier, pObject, FALSE ); // OK< if the timer is < 5000, use who was last in the talk panel box. if ( !SourceSoldierPointerIsValidAndReachableForGive( gpDestSoldier ) ) { // just drop it // have to walk up to the merc closest to ubNPC SOLDIERTYPE * pNPC; pNPC = FindSoldierByProfileID( ubNPC, FALSE ); if ( pNPC ) { AddItemToPool( pNPC->sGridNo, &(pNPC->inv[bInvPos]), TRUE, 0, 0, 0 ); TriggerNPCWithGivenApproach( ubNPC, APPROACH_DONE_GIVING_ITEM, TRUE ); } } else { // Remove dialogue! DeleteTalkingMenu( ); // Give this to buddy! SoldierGiveItem( gpDestSoldier, gpSrcSoldier, pObject, bInvPos ); } } void HandleNPCTriggerNPC( UINT8 ubTargetNPC, UINT8 ubTargetRecord, BOOLEAN fShowDialogueMenu, UINT8 ubTargetApproach ) { DebugQuestInfo(String("HandleNPCTriggerNPC: <%d>, record %d, %d, display %d", ubTargetNPC, ubTargetRecord, ubTargetApproach, fShowDialogueMenu)); SOLDIERTYPE *pSoldier; pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier == NULL ) { return; } // Save values for trigger function gubTargetNPC = ubTargetNPC; gubTargetRecord = ubTargetRecord; gubTargetApproach = ubTargetApproach; gfShowDialogueMenu = fShowDialogueMenu; if ( pSoldier->bTeam == gbPlayerNum ) { // make sure they are in the right alert status to receive orders (it's a bug that // this could be set for the player...) pSoldier->aiData.bAlertStatus = STATUS_GREEN; pSoldier->flags.uiStatusFlags &= (~SOLDIER_ENGAGEDINACTION ); } // OH BOY, CHECK IF THIS IS THE SAME PERSON WHO IS ON THE MENU // RIGHT NOW, IF SO , HANDLE DIRECTLY WITHOUT THIS DELAY! // IF WE ARE TO DISPLAY MENU AS WELL.... if ( gfInTalkPanel ) { if ( gpDestSoldier == pSoldier && fShowDialogueMenu ) { HandleNPCTrigger( ); return; } } if ( fShowDialogueMenu ) { // ALRIGHTY, NOW DO THIS! // WAIT IN NON-INTERACTIVE MODE UNTIL TIMER IS DONE // SO WE CAN SEE NPC RADIO LOCATOR // THEN AFTER THIS IS DONE, DO THE STUFF // Setup timer! gfWaitingForTriggerTimer = TRUE; guiWaitingForTriggerTime = GetJA2Clock( ); // Setup locator! ShowRadioLocator( pSoldier->ubID, SHOW_LOCATOR_FAST ); // If he's visible, locate... if ( pSoldier->bVisible != -1 ) { LocateSoldier( pSoldier->ubID, FALSE ); } guiPendingOverrideEvent = LU_BEGINUILOCK; } else { HandleNPCTrigger( ); } // Being already here, we know that this is not the guy whose panel is up. // Only close the panel if dialogue is involved in the new record. if ( RecordHasDialogue( ubTargetNPC, ubTargetRecord ) ) { // Shutdown any panel we had up... DeleteTalkingMenu( ); } } void HandleNPCTrigger( ) { SOLDIERTYPE *pSoldier; INT32 sPlayerGridNo; UINT16 ubPlayerID; pSoldier = FindSoldierByProfileID( gubTargetNPC, FALSE ); if (!pSoldier) { return; } if ( gfInTalkPanel ) { if ( pSoldier == gpDestSoldier ) { if ( gfShowDialogueMenu ) { // Converse another way! Converse( gubTargetNPC, NO_PROFILE, gubTargetApproach, gubTargetRecord ); } else if (gpSrcSoldier != NULL) // if we can, reinitialize menu { InitiateConversation( gpDestSoldier, gpSrcSoldier, gubTargetApproach, gubTargetRecord ); } } else { Converse( gubTargetNPC, NO_PROFILE, gubTargetApproach, gubTargetRecord ); } } else { // Now start new one... if ( gfShowDialogueMenu ) { if ( SourceSoldierPointerIsValidAndReachableForGive( pSoldier ) ) { InitiateConversation( pSoldier, gpSrcSoldier, gubTargetApproach, gubTargetRecord ); return; } else { sPlayerGridNo = ClosestPC( pSoldier, NULL ); if (!TileIsOutOfBounds(sPlayerGridNo)) { ubPlayerID = WhoIsThere2( sPlayerGridNo, 0 ); if (ubPlayerID != NOBODY) { InitiateConversation( pSoldier, MercPtrs[ ubPlayerID ], gubTargetApproach, gubTargetRecord ); return; } } } // else InitiateConversation( pSoldier, pSoldier, gubTargetApproach, gubTargetRecord ); } else { // Converse another way! Converse( gubTargetNPC, NO_PROFILE, gubTargetApproach, gubTargetRecord ); } } } void HandleWaitTimerForNPCTrigger( ) { if ( gfWaitingForTriggerTimer ) { if ( ( GetJA2Clock( ) - guiWaitingForTriggerTime ) > 500 ) { guiPendingOverrideEvent = LU_ENDUILOCK; UIHandleLUIEndLock( NULL ); HandleNPCTrigger( ); gfWaitingForTriggerTimer = FALSE; } } } void HandleNPCGotoGridNo( UINT8 ubTargetNPC, INT32 usGridNo, UINT8 ubQuoteNum ) { DebugQuestInfo(String("HandleNPCItemGiven:<%d> GridNo %d quote num %d", ubTargetNPC, usGridNo, ubQuoteNum)); SOLDIERTYPE *pSoldier; // OK, Move to gridNo! // Shotdown any panel we had up... DeleteTalkingMenu( ); // Get merc id for NPC pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } // zap any delay in this soldier ZEROTIMECOUNTER( pSoldier->timeCounters.AICounter ); if (pSoldier->aiData.bNextAction == AI_ACTION_WAIT) { pSoldier->aiData.bNextAction = AI_ACTION_NONE; pSoldier->aiData.usNextActionData = 0; } // if player controlled, set under AI control flag if (pSoldier->bTeam == gbPlayerNum) { pSoldier->flags.uiStatusFlags |= SOLDIER_PCUNDERAICONTROL; } // OK, set in motion! pSoldier->aiData.bNextAction = AI_ACTION_WALK; // Set dest! pSoldier->aiData.usNextActionData = usGridNo; // UNless he's has a pending action, delete what he was doing! // Cancel anything he was doing if ( pSoldier->aiData.bAction != AI_ACTION_PENDING_ACTION ) { CancelAIAction( pSoldier, TRUE ); } // Go for it! // Set flags to do stuff once there... pSoldier->ubQuoteRecord = ( ubQuoteNum + 1 ); pSoldier->ubQuoteActionID = ActionIDForMovementRecord( ubTargetNPC, ubQuoteNum ); // Set absolute dest pSoldier->sAbsoluteFinalDestination = usGridNo; // handle this guy's AI right away so that we can get him moving pSoldier->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; } void HandleNPCClosePanel( ) { // Remove dialogue! DeleteTalkingMenu( ); } void HandleStuffForNPCEscorted( UINT8 ubNPC ) { #ifdef LUA_INTERFACE_DIALOGUE LetLuaInterfaceDialogue(ubNPC,1); #else SOLDIERTYPE * pSoldier; switch( ubNPC ) { case MARIA: break; case JOEY: break; case SKYRIDER: SetFactTrue( FACT_SKYRIDER_EVER_ESCORTED ); if ( gubQuest[ QUEST_ESCORT_SKYRIDER ] == QUESTNOTSTARTED ) { StartQuest( QUEST_ESCORT_SKYRIDER, gWorldSectorX, gWorldSectorY ); } break; case JOHN: // recruit Mary as well RecruitEPC( MARY ); pSoldier = FindSoldierByProfileID( MARY, TRUE ); if ( pSoldier ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ NOW_BING_ESCORTED_STR ], gMercProfiles[ MARY ].zNickname, ( pSoldier->bAssignment + 1 ) ); } if ( gubQuest[ QUEST_ESCORT_TOURISTS ] == QUESTNOTSTARTED ) { StartQuest( QUEST_ESCORT_TOURISTS, gWorldSectorX, gWorldSectorY ); } break; case MARY: // recruit John as well RecruitEPC( JOHN ); pSoldier = FindSoldierByProfileID( JOHN, TRUE ); if ( pSoldier ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ NOW_BING_ESCORTED_STR ], gMercProfiles[ JOHN ].zNickname, ( pSoldier->bAssignment + 1 ) ); } if ( gubQuest[ QUEST_ESCORT_TOURISTS ] == QUESTNOTSTARTED ) { StartQuest( QUEST_ESCORT_TOURISTS, gWorldSectorX, gWorldSectorY ); } break; } #endif } void HandleFactForNPCUnescorted( UINT8 ubNPC ) { // obsolete! /* switch( ubNPC ) { case MARIA: SetFactFalse( FACT_MARIA_ESCORTED ); break; case JOEY: SetFactFalse( FACT_JOEY_ESCORTED ); break; case SKYRIDER: SetFactFalse( FACT_ESCORTING_SKYRIDER ); break; case MARY: SetFactFalse( FACT_JOHN_AND_MARY_EPCS ); break; case JOHN: SetFactFalse( FACT_JOHN_AND_MARY_EPCS ); break; } */ } void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum ) { SoldierID cnt; SOLDIERTYPE *pSoldier, *pSoldier2; INT8 bNumDone = 0; INT32 sGridNo = NOWHERE, sAdjustedGridNo; INT8 bItemIn; UINT8 ubDesiredMercDir; EXITGRID ExitGrid; INT32 iRandom = 0; UINT8 ubMineIndex; INT16 sX, sY, sX2, sY2; pSoldier2 = NULL; //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Handling %s, action %d at %ld", gMercProfiles[ ubTargetNPC ].zNickname, usActionCode, GetJA2Clock() ); // Switch on action code! if (usActionCode > NPC_ACTION_TURN_TO_FACE_NEAREST_MERC && usActionCode < NPC_ACTION_LAST_TURN_TO_FACE_PROFILE) { pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); pSoldier2 = FindSoldierByProfileID( (UINT8) (usActionCode - NPC_ACTION_TURN_TO_FACE_NEAREST_MERC), FALSE ); if (pSoldier && pSoldier2) { // see if we are facing this person ConvertGridNoToCenterCellXY(pSoldier->sGridNo, &sX, &sY); ConvertGridNoToCenterCellXY(pSoldier2->sGridNo, &sX2, &sY2); ubDesiredMercDir = atan8(sX, sY, sX2, sY2); // if not already facing in that direction, if (pSoldier->ubDirection != ubDesiredMercDir) { pSoldier->EVENT_SetSoldierDesiredDirection( ubDesiredMercDir ); } } } else { switch( usActionCode ) { case NPC_ACTION_DONT_ACCEPT_ITEM: // do nothing; this is just to skip annoying debug msgs break; case NPC_ACTION_GOTO_HIDEOUT: // OK, we want to goto the basement level! //DEF: First thing, Add the exit grid to the map temps file //DBrot: Grids ExitGrid.ubGotoSectorX = gModSettings.ubHideoutSectorX; ExitGrid.ubGotoSectorY = gModSettings.ubHideoutSectorY; ExitGrid.ubGotoSectorZ = gModSettings.ubHideoutSectorZ; ExitGrid.usGridNo = gModSettings.iHideoutExitGrid; //dnl!!! ApplyMapChangesToMapTempFile( TRUE ); AddExitGridToWorld( gModSettings.iHideoutEntryGrid, &ExitGrid ); ApplyMapChangesToMapTempFile( FALSE ); // For one, loop through our current squad and move them over cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; //ATE:Alrighty, instead of being a dufuss here, let's actually use the current // Squad here to search for... // look for all mercs on the same team, for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt ) { pSoldier = cnt; // Are we in this sector, On the current squad? if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bInSector && pSoldier->bAssignment == CurrentSquad( ) ) { gfTacticalTraversal = TRUE; SetGroupSectorValue( gModSettings.ubHideoutSectorX, gModSettings.ubHideoutSectorY, gModSettings.ubHideoutSectorZ, pSoldier->ubGroupID ); // Set insertion gridno if ( bNumDone < 10 ) { // Set next sectore //DBrot: Grids pSoldier->sSectorX = gModSettings.ubHideoutSectorX; pSoldier->sSectorY = gModSettings.ubHideoutSectorY; pSoldier->bSectorZ = gModSettings.ubHideoutSectorZ; // Set gridno pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; //pSoldier->usStrategicInsertionData = sBasementEnterGridNos[ bNumDone ]; pSoldier->usStrategicInsertionData = gModSettings.iBasementEntry[ bNumDone ]; } bNumDone++; } } // MOVE NPCS! // Fatima /* gMercProfiles[ 101 ].sSectorX = 10; gMercProfiles[ 101 ].sSectorY = 1; gMercProfiles[ 101 ].bSectorZ = 1; */ ChangeNpcToDifferentSector( FATIMA, gModSettings.ubHideoutSectorX, gModSettings.ubHideoutSectorY, gModSettings.ubHideoutSectorZ); // Dimitri /* gMercProfiles[ 60 ].sSectorX = 10; gMercProfiles[ 60 ].sSectorY = 1; gMercProfiles[ 60 ].bSectorZ = 1; */ ChangeNpcToDifferentSector( DIMITRI, gModSettings.ubHideoutSectorX, gModSettings.ubHideoutSectorY, gModSettings.ubHideoutSectorZ); gFadeOutDoneCallback = DoneFadeOutActionBasement; FadeOutGameScreen( ); break; case NPC_ACTION_FATIMA_GIVE_LETTER: // Delete menu, give item to megual DeleteTalkingMenu( ); // Get pointer for Fatima pSoldier = FindSoldierByProfileID( 101, FALSE ); // Get pointer for meguel pSoldier2 = FindSoldierByProfileID( 57, FALSE ); // Give item! if ( !pSoldier || !pSoldier2 ) { return; } // Look for letter.... { INT8 bInvPos; // Look for item.... bInvPos = FindObj( pSoldier, LETTER ); AssertMsg( bInvPos != NO_SLOT, "Interface Dialogue.C: Gift item does not exist in NPC." ); SoldierGiveItem( pSoldier, pSoldier2, &(pSoldier->inv[ bInvPos ] ), bInvPos ); } break; case NPC_ACTION_FACE_CLOSEST_PLAYER: // Get pointer for player pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } pSoldier->ubQuoteRecord = ubQuoteNum; pSoldier->ubQuoteActionID = QUOTE_ACTION_ID_TURNTOWARDSPLAYER; // handle AI for this person every frame until a player merc is near pSoldier->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; break; case NPC_ACTION_OPEN_CLOSEST_DOOR: // Delete menu DeleteTalkingMenu( ); // Get pointer to NPC pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } // FInd, open Closest Door NPCOpenThing( pSoldier, TRUE ); break; case NPC_ACTION_LOWER_GUN: // Get pointer for player pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } if (pSoldier->inv[HANDPOS].exists() == true) { UINT16 usGun; INT8 bNewSlot, bOldSlot; usGun = pSoldier->inv[HANDPOS].usItem; pSoldier->ReLoadSoldierAnimationDueToHandItemChange( pSoldier->inv[HANDPOS].usItem, NOTHING ); AutoPlaceObject( pSoldier, &(pSoldier->inv[HANDPOS]), FALSE ); bNewSlot = FindObj( pSoldier, usGun ); if ( bNewSlot != NO_SLOT && gMercProfiles[ ubTargetNPC ].inv[ bNewSlot ] == NOTHING ) { // find where the gun is stored in the profile data and // move it to the new location bOldSlot = FindObjectInSoldierProfile( ubTargetNPC, usGun ); if ( bOldSlot != NO_SLOT ) { // CHRISL: Need to rearrange status as well gMercProfiles[ ubTargetNPC ].bInvStatus[ bNewSlot ] = gMercProfiles[ ubTargetNPC ].bInvStatus[ bOldSlot ]; gMercProfiles[ ubTargetNPC ].bInvStatus[ bOldSlot ] = 0; // rearrange profile... NB # of guns can only be 1 so this is easy gMercProfiles[ ubTargetNPC ].inv[ bOldSlot ] = NOTHING; gMercProfiles[ ubTargetNPC ].bInvNumber[ bOldSlot ] = 0; gMercProfiles[ ubTargetNPC ].inv[ bNewSlot ] = usGun; gMercProfiles[ ubTargetNPC ].bInvNumber[ bNewSlot ] = 1; } } } break; case NPC_ACTION_READY_GUN: // Get pointer for player pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier && pSoldier->inv[HANDPOS].exists() == true) { sGridNo = pSoldier->sGridNo + DirectionInc( pSoldier->ubDirection ); pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE, FALSE ); } break; case NPC_ACTION_START_RUNNING: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { pSoldier->flags.fUIMovementFast = TRUE; } break; case NPC_ACTION_STOP_RUNNING: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { pSoldier->flags.fUIMovementFast = FALSE; } break; case NPC_ACTION_BOOST_TOWN_LOYALTY: HandleLoyaltyChangeForNPCAction( ubTargetNPC ); break; // case NPC_ACTION_PENALIZE_TOWN_LOYALTY: // break; case NPC_ACTION_STOP_PLAYER_GIVING_FIRST_AID: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { pSoldier->ReceivingSoldierCancelServices( ); } break; case NPC_ACTION_FACE_NORTH: // handle this separately to keep the code clean... pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { SendSoldierSetDesiredDirectionEvent( pSoldier, NORTHWEST ); } break; case NPC_ACTION_FACE_NORTH_EAST: case NPC_ACTION_FACE_EAST: case NPC_ACTION_FACE_SOUTH_EAST: case NPC_ACTION_FACE_SOUTH: case NPC_ACTION_FACE_SOUTH_WEST: case NPC_ACTION_FACE_WEST: case NPC_ACTION_FACE_NORTH_WEST: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { // screen NORTHEAST corresponds to in-game NORTH SendSoldierSetDesiredDirectionEvent( pSoldier, (UINT16) (NORTH + (usActionCode - NPC_ACTION_FACE_NORTH_EAST)) ); } break; case NPC_ACTION_RECRUIT: // gonna work for free! gMercProfiles[ ubTargetNPC ].sTrueSalary = gMercProfiles[ ubTargetNPC ].sSalary; gMercProfiles[ ubTargetNPC ].sSalary = 0; // and fall through case NPC_ACTION_RECRUIT_WITH_SALARY: // Delete menu DeleteTalkingMenu( ); if ( PlayerTeamFull( ) ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_RECRUIT_TEAM_FULL ] ); } else { if (!RecruitRPC( ubTargetNPC )) { ScreenMsg( FONT_MCOLOR_RED, MSG_ERROR, L"Internal error in recruiting RPC, trying to recover as best it can but this might not be pretty..." ); return; } // OK, update UI with message that we have been recruited ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ HAS_BEEN_RECRUITED_STR ], gMercProfiles[ ubTargetNPC ].zNickname ); } break; case NPC_ACTION_BECOME_ENEMY: // CJC: disable because of new system? pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } if (pSoldier->ubCivilianGroup) { CivilianGroupMemberChangesSides( pSoldier ); } else { //MakeCivHostile(pSoldier); } if ( ( pSoldier->ubProfile != NO_PROFILE || pSoldier->IsAssassin() ) && pSoldier->stats.bLife >= OKLIFE ) { // trigger quote! //TriggerNPCWithIHateYouQuote( pSoldier->ubProfile ); AddToShouldBecomeHostileOrSayQuoteList( pSoldier->ubID ); } break; case NPC_ACTION_CLOSE_DIALOGUE_PANEL: DeleteTalkingMenu(); break; case NPC_ACTION_TRIGGER_FRIEND_WITH_HOSTILE_QUOTE: // CJC: disabled because of new system //TriggerFriendWithHostileQuote( ubTargetNPC ); DeleteTalkingMenu(); break; case NPC_ACTION_LEAVE_HIDEOUT: // Delete menu, give item to megual DeleteTalkingMenu( ); //if we are already leaving the sector, dont leave the sector again if( gubWaitingForAllMercsToExitCode != 0 ) return; // OK, we want to goto the basement level! // For one, loop through our current squad and move them over cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // look for all mercs on the same team, for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt ) { pSoldier = cnt; // Are we in this sector, On the current squad? if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bInSector ) { gfTacticalTraversal = TRUE; //DBrot: Grids SetGroupSectorValue( gModSettings.ubHideoutSurfaceX, gModSettings.ubHideoutSurfaceY, gModSettings.ubHideoutSurfaceZ, pSoldier->ubGroupID ); // Set insertion gridno if ( bNumDone < 12 ) { // Set next sectore pSoldier->sSectorX = gModSettings.ubHideoutSurfaceX; pSoldier->sSectorY = gModSettings.ubHideoutSurfaceY; pSoldier->bSectorZ = gModSettings.ubHideoutSurfaceZ; // Set gridno pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; //pSoldier->usStrategicInsertionData = sBasementExitGridNos[ bNumDone ]; pSoldier->usStrategicInsertionData = gModSettings.iBasementExit[ bNumDone ]; } bNumDone++; } } gFadeOutDoneCallback = DoneFadeOutActionLeaveBasement; FadeOutGameScreen( ); // turn off engaged in conv stuff gTacticalStatus.uiFlags &= ~ENGAGED_IN_CONV; // Decrement refrence count... giNPCReferenceCount = 0; break; case NPC_ACTION_TRAVERSE_MAP_EAST: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } pSoldier->ubQuoteActionID = QUOTE_ACTION_ID_TRAVERSE_EAST; break; case NPC_ACTION_TRAVERSE_MAP_SOUTH: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } pSoldier->ubQuoteActionID = QUOTE_ACTION_ID_TRAVERSE_SOUTH; break; case NPC_ACTION_TRAVERSE_MAP_WEST: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } pSoldier->ubQuoteActionID = QUOTE_ACTION_ID_TRAVERSE_WEST; break; case NPC_ACTION_TRAVERSE_MAP_NORTH: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } pSoldier->ubQuoteActionID = QUOTE_ACTION_ID_TRAVERSE_NORTH; break; case NPC_ACTION_REPORT_SHIPMENT_SIZE: // for now, hard-coded to small shipment... // medium is quote 14, large is 15 if (CheckFact( FACT_MEDIUM_SIZED_SHIPMENT_WAITING, 0 )) { TalkingMenuDialogue( 14 ); } else if (CheckFact( FACT_LARGE_SIZED_SHIPMENT_WAITING, 0 )) { TalkingMenuDialogue( 15 ); } else { TalkingMenuDialogue( 13 ); } if (CheckFact( FACT_PABLOS_BRIBED, 0 ) && Random( 100 ) < 75) { TalkingMenuDialogue( 16 ); if (Random( 100 ) < 75) { TalkingMenuDialogue( 21 ); } } break; case NPC_ACTION_RETURN_STOLEN_SHIPMENT_ITEMS: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, 480 + Random( 60 ), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_RETURN_STOLEN_SHIPMENT_ITEMS, 1 ); // also make Pablo neutral again and exit combat if we're in combat pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } if ( !pSoldier->aiData.bNeutral ) { DeleteTalkingMenu(); SetSoldierNeutral( pSoldier ); pSoldier->bBleeding = 0; // make sure he doesn't bleed now... RecalculateOppCntsDueToBecomingNeutral( pSoldier ); if ( gTacticalStatus.uiFlags & INCOMBAT ) { CheckForEndOfCombatMode( FALSE ); } } break; case NPC_ACTION_THREATENINGLY_RAISE_GUN: // Get pointer for NPC pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } bItemIn = FindAIUsableObjClass( pSoldier, IC_GUN ); if (bItemIn != NO_SLOT && bItemIn != HANDPOS) { SwapObjs( pSoldier, HANDPOS, bItemIn, TRUE ); sGridNo = pSoldier->sGridNo + DirectionInc( pSoldier->ubDirection ); pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE, FALSE ); } // fall through so that the person faces the nearest merc! case NPC_ACTION_TURN_TO_FACE_NEAREST_MERC: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { sGridNo = ClosestPC( pSoldier, NULL ); if (!TileIsOutOfBounds(sGridNo)) { // see if we are facing this person ConvertGridNoToCenterCellXY(pSoldier->sGridNo, &sX, &sY); ConvertGridNoToCenterCellXY(sGridNo, &sX2, &sY2); ubDesiredMercDir = atan8(sX, sY, sX2, sY2); // if not already facing in that direction, if (pSoldier->ubDirection != ubDesiredMercDir) { pSoldier->EVENT_SetSoldierDesiredDirection( ubDesiredMercDir ); } } } break; case NPC_ACTION_SEND_PACOS_INTO_HIDING: pSoldier = FindSoldierByProfileID( 114, FALSE ); sGridNo = 16028; //dnl!!! if (pSoldier) { if (NewOKDestination( pSoldier, sGridNo, TRUE, 0 ) ) { // go for it! NPCGotoGridNo( 114, sGridNo, ubQuoteNum ); } else { sAdjustedGridNo = FindAdjacentGridEx( pSoldier, sGridNo, NULL, NULL, FALSE, FALSE ); if (sAdjustedGridNo != -1) { NPCGotoGridNo( 114, sAdjustedGridNo, ubQuoteNum ); } } } break; case NPC_ACTION_HAVE_PACOS_FOLLOW: pSoldier = FindSoldierByProfileID( 114, FALSE ); sGridNo = 8537; //dnl!!! //kitty: changed gridno from 18193 to 8537, that's at entrance door to rebel basement, where Fatima and Dimitri dialogue happens if (pSoldier) { if (NewOKDestination( pSoldier, sGridNo, TRUE, 0 ) ) { // go for it! NPCGotoGridNo( 114, sGridNo, ubQuoteNum ); } else { sAdjustedGridNo = FindAdjacentGridEx( pSoldier, sGridNo, NULL, NULL, FALSE, FALSE ); if (sAdjustedGridNo != -1) { NPCGotoGridNo( 114, sAdjustedGridNo, ubQuoteNum ); } } } break; case NPC_ACTION_SET_DELAYED_PACKAGE_TIMER: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), FACT_SHIPMENT_DELAYED_24_HOURS, 1 ); break; case NPC_ACTION_SET_RANDOM_PACKAGE_DAMAGE_TIMER: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_SET_RANDOM_PACKAGE_DAMAGE_TIMER, 1 ); break; case NPC_ACTION_ENABLE_CAMBRIA_DOCTOR_BONUS: // add event in a iRandom = Random( 24 ); AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, ( GetWorldMinutesInDay() + ( ( 24 + iRandom ) * 60 ) ), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_ENABLE_CAMBRIA_DOCTOR_BONUS, 1 ); break; case NPC_ACTION_TRIGGER_END_OF_FOOD_QUEST: AddHistoryToPlayersLog( HISTORY_TALKED_TO_FATHER_WALKER, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_TRIGGER_END_OF_FOOD_QUEST, 1 ); // SANDRO - merc records - quest counter (food quest) GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); break; case NPC_ACTION_REMOVE_CONRAD: break; case NPC_ACTION_REDUCE_CONRAD_SALARY_CONDITIONS: gMercProfiles[ CONRAD ].sSalary = 3300; // and fall through case NPC_ACTION_ASK_ABOUT_ESCORTING_EPC: // Confirm if we want to start escorting or not.... case NPC_ACTION_ASK_ABOUT_PAYING_RPC: case NPC_ACTION_ASK_ABOUT_PAYING_RPC_WITH_DAILY_SALARY: // Ask whether the player will pay the RPC case NPC_ACTION_DARREN_REQUESTOR: // Darren asks if the player wants to fight case NPC_ACTION_FIGHT_AGAIN_REQUESTOR: // Darren asks if the player wants to fight again case NPC_ACTION_BUY_LEATHER_KEVLAR_VEST: // from Angel case NPC_ACTION_MEDICAL_REQUESTOR: // at hospital case NPC_ACTION_MEDICAL_REQUESTOR_2: // at hospital case NPC_ACTION_BUY_VEHICLE_REQUESTOR: // from Dave case NPC_ACTION_KROTT_REQUESTOR: case NPC_ACTION_WALDO_REPAIR_REQUESTOR: // Vince or Willis asks about payment? for medical attention if (ubTargetNPC != gpDestSoldier->ubProfile) { #ifdef JA2BETAVERSION ScreenMsg( FONT_MCOLOR_RED, MSG_ERROR, L"Inconsistency between HandleNPCDoAction and target profile IDs" ); #endif } else { DeleteTalkingMenu(); StartDialogueMessageBox( ubTargetNPC, usActionCode ); } break; case NPC_ACTION_REPORT_BALANCE: ScreenMsg( FONT_YELLOW, MSG_INTERFACE, TacticalStr[ BALANCE_OWED_STR ], gMercProfiles[ubTargetNPC].zNickname, -gMercProfiles[ubTargetNPC].iBalance ); break; case NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE: // set event to invoke Brenda's (#85) record 9 ten minutes from now DeleteTalkingMenu(); AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 10, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE ); break; case NPC_ACTION_SEX: // Delete menu //DeleteTalkingMenu( ); //gFadeOutDoneCallback = DoneFadeOutActionSex; //FadeOutGameScreen( ); SetPendingNewScreen( SEX_SCREEN ); break; case NPC_ACTION_KYLE_GETS_MONEY: // add a money item with $10000 to the tile in front of Kyle // and then have him pick it up { // this isn't mod friendly. Let's make a new Mod_Settings.ini value // INT32 sGridNo = 14952; //dnl!!! INT32 sGridNo = gModSettings.iKyleMoneyGridNo; INT32 iWorldItem; pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { CreateMoney(10000, &gTempObject ); AddItemToPoolAndGetIndex( sGridNo, &gTempObject, -1, pSoldier->pathing.bLevel, 0, 0, -1, &iWorldItem ); // shouldn't have any current action but make sure everything // is clear... and set pending action so the guy won't move // until the pickup is completed CancelAIAction(pSoldier,FORCE); pSoldier->aiData.bAction = AI_ACTION_PENDING_ACTION; pSoldier->ubQuoteRecord = NPC_ACTION_KYLE_GETS_MONEY; SoldierPickupItem( pSoldier, iWorldItem, sGridNo, ITEM_IGNORE_Z_LEVEL ); } } break; case NPC_ACTION_DRINK_DRINK_DRINK: gMercProfiles[ ubTargetNPC ].bNPCData++; break; case NPC_ACTION_MARTHA_DIES: pSoldier = FindSoldierByProfileID( MARTHA, FALSE ); if (pSoldier) { DeleteTalkingMenu(); pSoldier->EVENT_SoldierGotHit( 1, 100, 10, pSoldier->ubDirection, 320, NOBODY, FIRE_WEAPON_NO_SPECIAL, AIM_SHOT_TORSO, 0, NOWHERE ); } break; //case NPC_ACTION_DARREN_GIVEN_CASH: // Handled in NPC.c // break; case NPC_ACTION_START_BOXING_MATCH: if ( CheckOnBoxers() ) { DeleteTalkingMenu(); PlayJA2Sample( BOXING_BELL, RATE_11025, SoundVolume( MIDVOLUME, 11237 ), 5, SoundDir( 11237 ) ); ClearAllBoxerFlags(); SetBoxingState( BOXING_WAITING_FOR_PLAYER ); } break; case NPC_ACTION_ADD_JOEY_TO_WORLD: gMercProfiles[ JOEY ].sSectorX = gModSettings.ubJoeyPrimarySectorX; //4 gMercProfiles[ JOEY ].sSectorY = gModSettings.ubJoeyPrimarySectorY; //MAP_ROW_D gMercProfiles[ JOEY ].bSectorZ = gModSettings.ubJoeyPrimarySectorZ; //1 AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_ADD_JOEY_TO_WORLD, 3 ); break; case NPC_ACTION_MARK_KINGPIN_QUOTE_0_USED: // set Kingpin's quote 0 as used so he doesn't introduce himself gMercProfiles[86].ubLastDateSpokenTo = (UINT8) GetWorldDay(); break; case NPC_ACTION_TRIGGER_LAYLA_13_14_OR_15: if (CheckFact( FACT_CARLA_AVAILABLE, 0 )) { TriggerNPCRecord( 107, 13 ); } else if (CheckFact( FACT_CINDY_AVAILABLE, 0)) { TriggerNPCRecord( 107, 14 ); } else if (CheckFact( FACT_BAMBI_AVAILABLE, 0)) { TriggerNPCRecord( 107, 15 ); } break; case NPC_ACTION_OPEN_CARLAS_DOOR: if (usActionCode == NPC_ACTION_OPEN_CARLAS_DOOR ) { sGridNo = gModSettings.iCarlaDoorGridNo; //12290; //dnl!!! } // fall through case NPC_ACTION_OPEN_CINDYS_DOOR: if (usActionCode == NPC_ACTION_OPEN_CINDYS_DOOR ) { sGridNo = gModSettings.iCindyDoorGridNo; //13413; //dnl!!! } // fall through case NPC_ACTION_OPEN_BAMBIS_DOOR: if (usActionCode == NPC_ACTION_OPEN_BAMBIS_DOOR ) { sGridNo = gModSettings.iBambiDoorGridNo; //11173; //dnl!!! } // fall through case NPC_ACTION_OPEN_MARIAS_DOOR: if (usActionCode == NPC_ACTION_OPEN_MARIAS_DOOR ) { sGridNo = gModSettings.iMariaDoorGridNo; //10852; //dnl!!! } // JA3Gold: unlock the doors instead of opening them { DOOR* pDoor; pDoor = FindDoorInfoAtGridNo( sGridNo ); if (pDoor) { pDoor->fLocked = FALSE; } } /* // handle door opening here { STRUCTURE * pStructure; pStructure = FindStructure( sGridNo, STRUCTURE_ANYDOOR ); if (pStructure) { pStructure-> if (pStructure->fFlags & STRUCTURE_OPEN) { // it's already open - this MIGHT be an error but probably not // because we are basically just ensuring that the door is open } else { if (pStructure->fFlags & STRUCTURE_BASE_TILE) { HandleDoorChangeFromGridNo( NULL, sGridNo, FALSE ); } else { HandleDoorChangeFromGridNo( NULL, pStructure->sBaseGridNo, FALSE ); } } } } */ break; case NPC_ACTION_POSSIBLY_ADVERTISE_CINDY: if ( CheckFact( FACT_CINDY_AVAILABLE, 0 ) ) { TriggerNPCRecord( MADAME, 14 ); } // else fall through case NPC_ACTION_POSSIBLY_ADVERTISE_BAMBI: if ( CheckFact( FACT_BAMBI_AVAILABLE, 0 ) ) { TriggerNPCRecord( MADAME, 15 ); } break; case NPC_ACTION_LAYLA_GIVEN_WRONG_AMOUNT_OF_CASH: if ( CheckFact( FACT_NO_GIRLS_AVAILABLE, 0 ) ) { TriggerNPCRecord( MADAME, 27 ); } // else mention girls available... else if ( CheckFact( FACT_CARLA_AVAILABLE, 0 ) ) { // Mention Carla TriggerNPCRecord( MADAME, 28 ); break; } // else fall through case NPC_ACTION_LAYLAS_NEXT_LINE_AFTER_CARLA: if ( CheckFact( FACT_CINDY_AVAILABLE, 0 ) ) { // Mention Cindy TriggerNPCRecord( MADAME, 29 ); break; } case NPC_ACTION_LAYLAS_NEXT_LINE_AFTER_CINDY: // else fall through if ( CheckFact( FACT_BAMBI_AVAILABLE, 0 ) ) { // Mention Bambi TriggerNPCRecord( MADAME, 30 ); break; } case NPC_ACTION_LAYLAS_NEXT_LINE_AFTER_BAMBI: // else fall through if ( gubQuest[ QUEST_RESCUE_MARIA ] == QUESTINPROGRESS ) { // Mention Maria TriggerNPCRecord( MADAME, 31); break; } case NPC_ACTION_LAYLAS_NEXT_LINE_AFTER_MARIA: // else fall through if ( CheckFact( FACT_MULTIPLE_MERCS_CLOSE, MADAME ) ) { // if more than 1 merc nearby, say comment about 2 guys pergirl TriggerNPCRecord( MADAME, 32 ); } break; case NPC_ACTION_PROMPT_PLAYER_TO_LIE: // ubRecordThatTriggeredLiePrompt = ubQuoteNum; DeleteTalkingMenu(); StartDialogueMessageBox( ubTargetNPC, usActionCode ); break; case NPC_ACTION_REMOVE_JOE_QUEEN: // Find queen and joe and remove from sector... pSoldier = FindSoldierByProfileID( QUEEN, FALSE ); if ( pSoldier != NULL ) { TacticalRemoveSoldier( pSoldier->ubID ); } // Find queen and joe and remove from sector... pSoldier = FindSoldierByProfileID( JOE, FALSE ); if ( pSoldier != NULL ) { TacticalRemoveSoldier( pSoldier->ubID ); } break; case NPC_ACTION_REMOVE_ELLIOT_END_MEANWHILE: // Find queen and joe and remove from sector... pSoldier = FindSoldierByProfileID( ELLIOT, FALSE ); if ( pSoldier != NULL ) { TacticalRemoveSoldier( pSoldier->ubID ); } // End meanwhile.... // End meanwhile.... DeleteTalkingMenu(); EndMeanwhile( ); break; case NPC_ACTION_NO_SCI_FI_END_MEANWHILE: if (gGameOptions.ubGameStyle == STYLE_REALISTIC || !gGameExternalOptions.fEnableCrepitus) { // End meanwhile.... // End meanwhile.... DeleteTalkingMenu(); EndMeanwhile( ); } else { TriggerNPCRecord( QUEEN, 8 ); } /* if ( !( gGameOptions.ubGameStyle == STYLE_SCIFI && gGameExternalOptions.fEnableCrepitus) ) { // End meanwhile.... // End meanwhile.... DeleteTalkingMenu(); EndMeanwhile( ); } else { TriggerNPCRecord( QUEEN, 8 ); } */ break; case NPC_ACTION_TRIGGER_MARRY_DARYL_PROMPT: DeleteTalkingMenu(); StartDialogueMessageBox( ubTargetNPC, usActionCode ); break; case NPC_ACTION_HAVE_MARRIED_NPC_LEAVE_TEAM: // get the soldier pSoldier = FindSoldierByProfileID( gMercProfiles[ DARYL ].bNPCData, FALSE ); pSoldier2 = gpDestSoldier; if ( !pSoldier || !pSoldier2 ) { return; } //set the fact that the merc is being married ( used in the personnel screen ) gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_MARRIED_TO_HICKS; AddHistoryToPlayersLog( HISTORY_MERC_MARRIED_OFF, pSoldier->ubProfile, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); // if Flo is going off with Daryl, then set that fact true if( pSoldier->ubProfile == FLO ) { SetFactTrue( FACT_PC_MARRYING_DARYL_IS_FLO ); #ifdef JA2UB #else // anv: make Speck whine about it immediately if on team if( !IsMercDead(BIFF) && !IsSpeckComAvailable() ) { TacticalCharacterDialogue( FindSoldierByProfileID( SPECK_PLAYABLE , TRUE ), SPECK_PLAYABLE_QUOTE_FLO_MARRIED_A_COUSIN_BIFF_IS_ALIVE ); // don't bring this up again LaptopSaveInfo.fSpeckSaidFloMarriedCousinQuote = TRUE; MakeBiffAwayForCoupleOfDays(); } #endif } HandleMoraleEvent( pSoldier, MORALE_MERC_MARRIED, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); UpdateDarrelScriptToGoTo( pSoldier ); TriggerNPCRecord( DARREL, 10 ); //Since the married merc is leaving the team, add them to the departed list for the personnel screen AddCharacterToOtherList( pSoldier ); break; case NPC_ACTION_TRIGGER_ANGEL_17_OR_18: if (CheckFact( FACT_ANGEL_SOLD_VEST, ANGEL )) { TriggerNPCRecord( ANGEL, 18 ); } else { TriggerNPCRecord( ANGEL, 17 ); } break; case NPC_ACTION_TRIGGER_ANGEL_16_OR_19: if (CheckFact( FACT_PLAYER_IN_SAME_ROOM, ANGEL ) ) { TriggerNPCRecord( ANGEL, 16 ); } else { TriggerNPCRecord( ANGEL, 19 ); } break; case NPC_ACTION_TRIGGER_ANGEL_21_OR_22: if (CheckFact( FACT_PLAYER_IN_SAME_ROOM, ANGEL ) ) { TriggerNPCRecord( ANGEL, 22 ); } else { TriggerNPCRecord( ANGEL, 21 ); } break; case NPC_ACTION_TRIGGER_MARIA: if ( CheckFact( FACT_MARIA_ESCAPE_NOTICED, MARIA ) == FALSE ) { TriggerNPCRecord( MARIA, 8 ); } else { if ( CheckFact( FACT_PLAYER_IN_SAME_ROOM, MARIA ) ) { TriggerNPCRecord( MARIA, 9 ); } else { TriggerNPCRecord( MARIA, 10 ); } } break; case NPC_ACTION_ANGEL_LEAVES_DEED: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { bItemIn = FindObj( pSoldier, DEED ); if (bItemIn != NO_SLOT) { AddItemToPool( 12541, &(pSoldier->inv[bItemIn]), -1, 0, 0, 0 ); DeleteObj( &(pSoldier->inv[ bItemIn ]) ); RemoveObjectFromSoldierProfile( ubTargetNPC, DEED ); } } DeleteTalkingMenu(); NPCDoAction( ubTargetNPC, NPC_ACTION_UN_RECRUIT_EPC, 0 ); NPCDoAction( ubTargetNPC, NPC_ACTION_GRANT_EXPERIENCE_3, 0 ); TriggerNPCRecord( ANGEL, 24 ); break; case NPC_ACTION_SET_GIRLS_AVAILABLE: // Initially assume none available SetFactTrue( FACT_NO_GIRLS_AVAILABLE ); // Carla... available 66% of the time if ( Random( 3 ) ) { SetFactTrue( FACT_CARLA_AVAILABLE ); SetFactFalse( FACT_NO_GIRLS_AVAILABLE ); } else { SetFactFalse( FACT_CARLA_AVAILABLE ); } // Cindy... available 50% of time if ( Random( 2 ) ) { SetFactTrue( FACT_CINDY_AVAILABLE ); SetFactFalse( FACT_NO_GIRLS_AVAILABLE ); } else { SetFactFalse( FACT_CINDY_AVAILABLE ); } // Bambi... available 50% of time if ( Random( 2 ) ) { SetFactTrue( FACT_BAMBI_AVAILABLE ); SetFactFalse( FACT_NO_GIRLS_AVAILABLE ); } else { SetFactFalse( FACT_BAMBI_AVAILABLE ); } break; case NPC_ACTION_SET_DELAY_TILL_GIRLS_AVAILABLE: AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 1 + Random( 2 ), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_SET_DELAY_TILL_GIRLS_AVAILABLE ); break; case NPC_ACTION_SET_WAITED_FOR_GIRL_FALSE: SetFactFalse( FACT_PLAYER_WAITED_FOR_GIRL ); break; case NPC_ACTION_UN_RECRUIT_EPC: case NPC_ACTION_SET_EPC_TO_NPC: if ( ubTargetNPC == ANGEL ) { // hack to Mari! ubTargetNPC = MARIA; } UnRecruitEPC( ubTargetNPC ); HandleFactForNPCUnescorted( ubTargetNPC ); switch( ubTargetNPC ) { case MARY: UnRecruitEPC( JOHN ); break; case JOHN: UnRecruitEPC( MARY ); break; } break; case NPC_ACTION_REMOVE_DOREEN: // make Doreen disappear next time we do a sector traversal gMercProfiles[ DOREEN ].sSectorX = 0; gMercProfiles[ DOREEN ].sSectorY = 0; gMercProfiles[ DOREEN ].bSectorZ = 0; break; case NPC_ACTION_FREE_KIDS: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, 420, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_FREE_KIDS, 1 ); break; case NPC_ACTION_TRIGGER_FATHER_18_20_OR_15: if ( CheckFact( 132, FATHER ) == FALSE ) { TriggerNPCRecord( FATHER, 18 ); } else if ( CheckFact( 133, FATHER ) == FALSE ) { TriggerNPCRecord( FATHER, 20 ); } else if ( CheckFact( 134, FATHER ) == FALSE ) { TriggerNPCRecord( FATHER, 15 ); } else { TriggerNPCRecord( FATHER, 26 ); } break; case NPC_ACTION_ENTER_COMBAT: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier ) { if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP ) { if ( gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] == CIV_GROUP_NEUTRAL ) { CivilianGroupMemberChangesSides( pSoldier ); } } else { // make hostile MakeCivHostile(pSoldier); } DeleteTalkingMenu(); if ( ! ( gTacticalStatus.uiFlags & INCOMBAT ) ) { EnterCombatMode( pSoldier->bTeam ); } } break; case NPC_ACTION_DECIDE_ACTIVE_TERRORISTS: { // only (now) add all terrorist files to laptop UINT8 ubLoop; // one terrorist will always be Elgin // determine how many more terrorists - 2 to 4 more ubLoop = 0; while ( gubTerrorists[ ubLoop ] != 0 ) { AddFileAboutTerrorist( gubTerrorists[ ubLoop ] ); ubLoop++; } // Carmen has received 0 terrorist heads recently gMercProfiles[ 78 ].bNPCData2 = 0; } break; case NPC_ACTION_CHECK_LAST_TERRORIST_HEAD: // decrement head count gMercProfiles[ 78 ].bNPCData--; // increment number of heads on hand gMercProfiles[ 78 ].bNPCData2++; if (gWorldSectorX == gModSettings.ubCarmenGiveRewardSectorX && gWorldSectorY == gModSettings.ubCarmenGiveRewardSectorY && gbWorldSectorZ == gModSettings.ubCarmenGiveRewardSectorZ) //13, 3, 0 { TriggerNPCRecord( 78, 20 ); } else { TriggerNPCRecord( 78, 21 ); } // CJC Nov 28 2002 - fixed history record which didn't have location specified AddHistoryToPlayersLog( HISTORY_GAVE_CARMEN_HEAD, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); // SANDRO - end the quest here - the team will gain exp and records by now if (gMercProfiles[ CARMEN ].bNPCData <= 0) { SetFactTrue( FACT_ALL_TERRORISTS_KILLED ); EndQuest( QUEST_KILL_TERRORISTS, gWorldSectorX, gWorldSectorY ); IncrementTownLoyaltyEverywhere( LOYALTY_BONUS_TERRORISTS_DEALT_WITH );// end terrorist quest } break; case NPC_ACTION_CARMEN_LEAVES_FOR_GOOD: gMercProfiles[ ubTargetNPC ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_LEFT_COUNTRY; // fall through! case NPC_ACTION_CARMEN_LEAVES_FOR_C13: // set "don't add to sector" cause he'll only appear after an event... gMercProfiles[ ubTargetNPC ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR; SetCustomizableTimerCallbackAndDelay( 10000, CarmenLeavesSectorCallback, TRUE ); break; case NPC_ACTION_CARMEN_LEAVES_ON_NEXT_SECTOR_LOAD: // SANDRO - removed from here // if (gMercProfiles[ CARMEN ].bNPCData == 0) //{ // SetFactTrue( FACT_ALL_TERRORISTS_KILLED ); // // the next time we change sectors, quest 2 will be set to done // IncrementTownLoyaltyEverywhere( LOYALTY_BONUS_TERRORISTS_DEALT_WITH ); //} // anyhow Carmen has given the player money so reset his balance to 0. gMercProfiles[ CARMEN ].uiMoney = 0; break; case NPC_ACTION_END_COMBAT: // silversurfer: Bugfix for JaggZilla Bug #635 // We can't end combat just because this one guy is now not hostile anymore. What about the rest of the sector? if ( NumCapableEnemyInSector() == 0 ) ExitCombatMode(); break; case NPC_ACTION_BECOME_FRIENDLY_END_COMBAT: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier ) { DeleteTalkingMenu(); SetSoldierNeutral( pSoldier ); RecalculateOppCntsDueToBecomingNeutral( pSoldier ); if ( gTacticalStatus.bNumFoughtInBattle[ CIV_TEAM ] == 0 ) { // silversurfer: Bugfix for JaggZilla Bug #635 // Function CheckForEndOfBattle() will set this IF the sector is really free of enemies. //gTacticalStatus.fEnemyInSector = FALSE; CheckForEndOfBattle( FALSE ); } if ( !gTacticalStatus.fEnemyInSector ) { ExitCombatMode(); } CancelAIAction( pSoldier, FORCE ); // make stand up if not standing already if ( ubTargetNPC == SLAY && pSoldier->ubBodyType == CRIPPLECIV ) { HandleNPCDoAction( SLAY, NPC_ACTION_GET_OUT_OF_WHEELCHAIR, ubQuoteNum ); } else if (!PTR_STANDING) { pSoldier->aiData.bNextAction = AI_ACTION_CHANGE_STANCE; pSoldier->aiData.usNextActionData = ANIM_STAND; } } break; case NPC_ACTION_TERRORIST_REVEALS_SELF: // WAS swap names in profile // NOW overwrite name with true name in profile // copy new nickname into soldier structure { //INT16 zTemp[ NICKNAME_LENGTH ]; //wcsncpy( zTemp, gMercProfiles[ ubTargetNPC ].zNickname, NICKNAME_LENGTH ); wcsncpy( gMercProfiles[ ubTargetNPC ].zNickname, gMercProfiles[ ubTargetNPC ].zName, NICKNAME_LENGTH ); //wcsncpy( gMercProfiles[ ubTargetNPC ].zName, zTemp, NICKNAME_LENGTH ); pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier ) { wcsncpy( pSoldier->name, gMercProfiles[ ubTargetNPC ].zNickname, 10 ); } } break; case NPC_ACTION_END_MEANWHILE: // End meanwhile.... DeleteTalkingMenu(); EndMeanwhile( ); break; case NPC_ACTION_START_BLOODCAT_QUEST: StartQuest( QUEST_BLOODCATS, gWorldSectorX, gWorldSectorY ); SetFactTrue( FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR); break; case NPC_ACTION_START_MINE: ubMineIndex = GetHeadMinersMineIndex ( ubTargetNPC ); // record the fact that player has spoken with this head miner so he can now get production from that mine PlayerSpokeToHeadMiner( ubTargetNPC ); if ( IsMineShutDown( ubMineIndex ) ) { RestartMineProduction( ubMineIndex ); } break; case NPC_ACTION_STOP_MINE: ubMineIndex = GetHeadMinersMineIndex ( ubTargetNPC ); if ( !IsMineShutDown( ubMineIndex ) ) { ShutOffMineProduction( ubMineIndex ); } break; case NPC_ACTION_RESET_MINE_CAPTURED: ResetQueenRetookMine( ubTargetNPC ); break; case NPC_ACTION_SET_OSWALD_RECORD_13_USED: case NPC_ACTION_SET_CALVIN_RECORD_13_USED: case NPC_ACTION_SET_CARL_RECORD_13_USED: case NPC_ACTION_SET_FRED_RECORD_13_USED: case NPC_ACTION_SET_MATT_RECORD_13_USED: SetQuoteRecordAsUsed( ubTargetNPC, 13 ); break; case NPC_ACTION_TRIGGER_MATT: if ( CheckFact( FACT_DYNAMO_IN_J9, MATT ) ) { TriggerNPCRecord( MATT, 15 ); } else if ( CheckFact( FACT_DYNAMO_ALIVE, MATT ) ) { TriggerNPCRecord( MATT, 16 ); } break; case NPC_ACTION_MADLAB_GIVEN_GUN: SetFactFalse( FACT_MADLAB_EXPECTING_FIREARM ); if ( CheckFact( FACT_MADLAB_EXPECTING_VIDEO_CAMERA, 0 ) ) { TriggerNPCRecord( ubTargetNPC, 14 ); } else { TriggerNPCRecord( ubTargetNPC, 18 ); } break; case NPC_ACTION_MADLAB_GIVEN_CAMERA: SetFactFalse( FACT_MADLAB_EXPECTING_VIDEO_CAMERA ); if ( CheckFact( FACT_MADLAB_EXPECTING_FIREARM, 0 ) ) { TriggerNPCRecord( ubTargetNPC, 17 ); } else { TriggerNPCRecord( ubTargetNPC, 18 ); } break; case NPC_ACTION_MADLAB_ATTACHES_GOOD_CAMERA: SetFactFalse( FACT_MADLAB_HAS_GOOD_CAMERA ); pSoldier = FindSoldierByProfileID( MADLAB, FALSE ); pSoldier2 = FindSoldierByProfileID( ROBOT, FALSE ); // WANNE: If we get the 2nd (repaired) robot, first recruit, then give the robot the weapon from madlab if (gubFact[FACT_ROBOT_READY_SECOND_TIME] == TRUE) { RecruitEPC( ROBOT ); } // Give the robot the weapon, we gave madlab earlier if ( pSoldier && pSoldier2 ) { // Give weapon to robot INT8 bSlot; bSlot = FindObjClass( pSoldier, IC_GUN ); if ( bSlot != NO_SLOT ) { AutoPlaceObject( pSoldier2, &( pSoldier->inv[ bSlot ] ) , FALSE ); } } // WANNE: This is out first robot. Recruit it AFTER we gave him the weapon! if (gubFact[FACT_ROBOT_READY_SECOND_TIME] == FALSE) RecruitEPC( ROBOT ); break; case NPC_ACTION_READY_ROBOT: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, 420, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_READY_ROBOT, 1 ); break; case NPC_ACTION_HANDLE_END_OF_FIGHT: ExitBoxing(); DeleteTalkingMenu(); /* switch( gTacticalStatus.bBoxingState ) { case WON_ROUND: TriggerNPCRecord( DARREN, 23 ); break; case LOST_ROUND: TriggerNPCRecord( DARREN, 24 ); break; default: break; } */ break; case NPC_ACTION_DARREN_PAYS_PLAYER: // should change to split up cash pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier ) { INT32 sNearestPC; SoldierID ubID; INT8 bMoneySlot; INT8 bEmptySlot; sNearestPC = ClosestPC( pSoldier, NULL ); if (!TileIsOutOfBounds(sNearestPC)) { ubID = WhoIsThere2( sNearestPC, 0 ); if (ubID != NOBODY) { pSoldier2 = ubID; } } if (pSoldier2) { bMoneySlot = FindObjClass( pSoldier, IC_MONEY ); bEmptySlot = FindObj( pSoldier, NOTHING ); // have to separate out money from Darren's stash equal to the amount of the bet // times 2 (returning the player's money, after all!) if (bMoneySlot != NO_SLOT && bEmptySlot != NO_SLOT) { CreateMoney( gMercProfiles[ ubTargetNPC ].iBalance * 2, &(pSoldier->inv[ bEmptySlot ] ) ); pSoldier->inv[ bMoneySlot ][0]->data.money.uiMoneyAmount -= gMercProfiles[ ubTargetNPC ].iBalance * 2; if (bMoneySlot < bEmptySlot) { // move main stash to later in inventory! SwapObjs( pSoldier, bEmptySlot, bMoneySlot, TRUE ); SoldierGiveItem( pSoldier, pSoldier2, &(pSoldier->inv[ bMoneySlot ] ), bMoneySlot ); } else { SoldierGiveItem( pSoldier, pSoldier2, &(pSoldier->inv[ bEmptySlot ] ), bEmptySlot ); } } } } break; case NPC_ACTION_TRIGGER_SPIKE_OR_DARREN: pSoldier = FindSoldierByProfileID( KINGPIN, FALSE ); if (pSoldier) { //DBrot: More Rooms //UINT8 ubRoom; UINT16 usRoom; if ( InARoom( pSoldier->sGridNo, &usRoom ) && (usRoom == 1 || usRoom == 2 || usRoom == 3 ) ) { // Kingpin is in the club TriggerNPCRecord( DARREN, 31 ); break; } } // Kingpin not in club TriggerNPCRecord( SPIKE, 11 ); break; case NPC_ACTION_OPEN_CLOSEST_CABINET: // Delete menu DeleteTalkingMenu( ); // Get pointer to NPC pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( !pSoldier ) { return; } // FInd, open Closest non-door NPCOpenThing( pSoldier, FALSE ); break; case NPC_ACTION_GET_ITEMS_FROM_CLOSEST_CABINET: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { // shouldn't have any current action but make sure everything // is clear... and set pending action so the guy won't move // until the pickup is completed CancelAIAction(pSoldier,FORCE); pSoldier->aiData.bAction = AI_ACTION_PENDING_ACTION; // make sure the pickup starts dammit! pSoldier->flags.fInNonintAnim = FALSE; pSoldier->flags.fRTInNonintAnim = FALSE; if ( pSoldier->ubProfile == ARMAND ) { sGridNo = 6968; //dnl!!! } else { sGridNo = FindNearestOpenableNonDoor( pSoldier->sGridNo ); } SoldierPickupItem( pSoldier, ITEM_PICKUP_ACTION_ALL, sGridNo, ITEM_IGNORE_Z_LEVEL ); } break; case NPC_ACTION_SHOW_TIXA: SetTixaAsFound(); AddHistoryToPlayersLog( HISTORY_DISCOVERED_TIXA, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_SHOW_ORTA: SetOrtaAsFound(); AddHistoryToPlayersLog( HISTORY_DISCOVERED_ORTA, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_SLAP: // OK, LET'S FIND THE QUEEN AND MAKE HER DO SLAP ANIMATION pSoldier = FindSoldierByProfileID( QUEEN, FALSE ); if (pSoldier) { pSoldier->EVENT_InitNewSoldierAnim( QUEEN_SLAP, 0 , FALSE ); } break; case NPC_ACTION_PUNCH_PC_SLOT_0: case NPC_ACTION_PUNCH_PC_SLOT_1: case NPC_ACTION_PUNCH_PC_SLOT_2: DeleteTalkingMenu( ); // OK, LET'S FIND THE QUEEN AND MAKE HER DO SLAP ANIMATION pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { SoldierID ubTargetID; SOLDIERTYPE *pTarget; // Target a different merc.... if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_0 ) { //pTarget = MercPtrs[ 0 ]; sGridNo = gModSettings.iMeanwhileInterrogatePOWGridNo[ 0 ]; } else if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_1 ) { //pTarget = MercPtrs[ 1 ]; sGridNo = gModSettings.iMeanwhileInterrogatePOWGridNo[ 1 ]; } else //if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_2 ) { //pTarget = MercPtrs[ 2 ]; sGridNo = gModSettings.iMeanwhileInterrogatePOWGridNo[ 2 ]; } ubTargetID = WhoIsThere2( sGridNo, 0 ); if ( ubTargetID == NOBODY ) { pTarget = NULL; } else { pTarget = ubTargetID; } // Use a different approach.... if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_0 ) { pSoldier->aiData.uiPendingActionData4 = APPROACH_DONE_PUNCH_0; } else if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_1 ) { pSoldier->aiData.uiPendingActionData4 = APPROACH_DONE_PUNCH_1; } else if ( usActionCode == NPC_ACTION_PUNCH_PC_SLOT_2 ) { pSoldier->aiData.uiPendingActionData4 = APPROACH_DONE_PUNCH_2; } if ( pTarget && pTarget->bActive && pTarget->bInSector && pTarget->stats.bLife != 0 ) { pSoldier->aiData.bNextAction = AI_ACTION_KNIFE_MOVE; pSoldier->aiData.usNextActionData = pTarget->sGridNo; pSoldier->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; // UNless he's has a pending action, delete what he was doing! // Cancel anything he was doing if ( pSoldier->aiData.bAction != AI_ACTION_PENDING_ACTION ) { CancelAIAction( pSoldier, TRUE ); } //HandleItem( pSoldier, pTarget->sGridNo, 0, NOTHING, FALSE ); pSoldier->flags.uiStatusFlags |= SOLDIER_NPC_DOING_PUNCH; } else { TriggerNPCWithGivenApproach( pSoldier->ubProfile, (UINT8)pSoldier->aiData.uiPendingActionData4, FALSE ); } } break; case NPC_ACTION_SHOOT_ELLIOT: DeleteTalkingMenu( ); pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { SOLDIERTYPE *pTarget; pTarget = FindSoldierByProfileID( ELLIOT, FALSE ); if ( pTarget ) { // Set special flag.... pTarget->flags.uiStatusFlags |= SOLDIER_NPC_SHOOTING; pSoldier->flags.uiStatusFlags |= SOLDIER_NPC_SHOOTING; pSoldier->bAimShotLocation = AIM_SHOT_HEAD; // Add gun to inventory..... CreateItem( (UINT16) (DESERTEAGLE), 100, &( pSoldier->inv[ HANDPOS ] ) ); // Make shoot pSoldier->aiData.bNextAction = AI_ACTION_FIRE_GUN; pSoldier->aiData.usNextActionData = pTarget->sGridNo; pSoldier->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; // UNless he's has a pending action, delete what he was doing! // Cancel anything he was doing if ( pSoldier->aiData.bAction != AI_ACTION_PENDING_ACTION ) { CancelAIAction( pSoldier, TRUE ); } // change elliot portrait... gMercProfiles[ ELLIOT ].bNPCData = 17; } } break; //Emmons: is this line of code part of something missing //or no longer necessary? CJC //if ( pSoldier->flags.uiStatusFlags & SOLDIER_NPC_SHOOTING ) case NPC_ACTION_PUNCH_FIRST_LIVING_PC: // Punch first living pc.... // OK, LET'S FIND THE QUEEN AND MAKE HER DO SLAP ANIMATION pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { SoldierID ubTargetID; SOLDIERTYPE *pTarget; INT32 cnt; BOOLEAN fGoodTarget = FALSE; for ( cnt = 0; cnt < 3; cnt++ ) { ubTargetID = WhoIsThere2( gModSettings.iMeanwhileInterrogatePOWGridNo[ cnt ], 0 ); if ( ubTargetID == NOBODY ) { continue; } else { pTarget = ubTargetID; } pSoldier->aiData.uiPendingActionData4 = APPROACH_DONE_PUNCH_1; // If we are elliot, we can't do unconocious guys.... if ( pSoldier->ubProfile == ELLIOT ) { if ( pTarget->bActive && pTarget->bInSector && pTarget->stats.bLife >= OKLIFE ) { fGoodTarget = TRUE; } } else { if ( pTarget->bActive && pTarget->bInSector && pTarget->stats.bLife != 0 ) { fGoodTarget = TRUE; } } if ( fGoodTarget ) { pSoldier->aiData.bNextAction = AI_ACTION_KNIFE_MOVE; pSoldier->aiData.usNextActionData = pTarget->sGridNo; pSoldier->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; // UNless he's has a pending action, delete what he was doing! // Cancel anything he was doing if ( pSoldier->aiData.bAction != AI_ACTION_PENDING_ACTION ) { CancelAIAction( pSoldier, TRUE ); } pSoldier->flags.uiStatusFlags |= SOLDIER_NPC_DOING_PUNCH; break; } } if ( cnt == 3 ) { // If here, nobody was found... TriggerNPCWithGivenApproach( pSoldier->ubProfile, (UINT8)pSoldier->aiData.uiPendingActionData4, FALSE ); } } break; case NPC_ACTION_FRUSTRATED_SLAP: // OK, LET'S FIND THE QUEEN AND MAKE HER DO SLAP ANIMATION pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if (pSoldier) { pSoldier->EVENT_InitNewSoldierAnim( QUEEN_FRUSTRATED_SLAP, 0 , FALSE ); } break; case NPC_ACTION_START_TIMER_ON_KEITH_GOING_OUT_OF_BUSINESS: // start timer to place keith out of business AddStrategicEvent( EVENT_KEITH_GOING_OUT_OF_BUSINESS, GetWorldTotalMin() + ( 6 * 24 * 60 ), 0 ); break; case NPC_ACTION_KEITH_GOING_BACK_IN_BUSINESS: // keith is back in business SetFactFalse( FACT_KEITH_OUT_OF_BUSINESS ); break; case NPC_ACTION_TRIGGER_QUEEN_BY_CITIES_CONTROLLED: switch ( GetNumberOfWholeTownsUnderControlButExcludeCity( OMERTA ) ) { case 0: case 1: TriggerNPCRecord( QUEEN, 11 ); break; case 2: TriggerNPCRecord( QUEEN, 7 ); break; case 3: TriggerNPCRecord( QUEEN, 8 ); break; case 4: TriggerNPCRecord( QUEEN, 9 ); break; case 5: TriggerNPCRecord( QUEEN, 10 ); break; default: TriggerNPCRecord( QUEEN, 11 ); break; } break; case NPC_ACTION_SEND_SOLDIERS_TO_DRASSEN: case NPC_ACTION_SEND_SOLDIERS_TO_BATTLE_LOCATION: case NPC_ACTION_SEND_SOLDIERS_TO_OMERTA: case NPC_ACTION_ADD_MORE_ELITES: case NPC_ACTION_GIVE_KNOWLEDGE_OF_ALL_MERCS: case NPC_ACTION_SEND_SOLDIERS_TO_CHITZENA: case NPC_ACTION_SEND_SOLDIERS_TO_GRUMM: case NPC_ACTION_SEND_SOLDIERS_TO_CAMBRIA: case NPC_ACTION_SEND_SOLDIERS_TO_ALMA: case NPC_ACTION_SEND_SOLDIERS_TO_BALIME: case NPC_ACTION_GLOBAL_OFFENSIVE_1: case NPC_ACTION_GLOBAL_OFFENSIVE_2: case NPC_ACTION_DEPLOY_TRANSPORT_GROUP: break; case NPC_ACTION_TRIGGER_QUEEN_BY_SAM_SITES_CONTROLLED: switch ( GetNumberOfSAMSitesUnderPlayerControl() ) { case 0: case 1: TriggerNPCRecord( QUEEN, 7 ); break; case 2: TriggerNPCRecord( QUEEN, 8 ); break; case 3: TriggerNPCRecord( QUEEN, 9 ); break; default: break; } break; case NPC_ACTION_TRIGGER_ELLIOT_BY_BATTLE_RESULT: if ( gTacticalStatus.fLastBattleWon ) { TriggerNPCRecord( ELLIOT, 6 ); } else { TriggerNPCRecord( ELLIOT, 8 ); } break; case NPC_ACTION_TRIGGER_ELLIOT_BY_SAM_DISABLED: if ( IsThereAFunctionalSAMSiteInSector( gTacticalStatus.ubLastBattleSectorX, gTacticalStatus.ubLastBattleSectorY, 0 ) ) { TriggerNPCRecord( QUEEN, 6 ); } else { TriggerNPCRecord( ELLIOT, 2 ); } break; case NPC_ACTION_TRIGGER_VINCE_BY_LOYALTY: if( CheckFact( FACT_NPC_OWED_MONEY, ubTargetNPC ) && ( ubTargetNPC == VINCE ) ) { // check if we owe vince cash TriggerNPCRecord( ubTargetNPC, 21 ); } else if ( CheckFact( FACT_VINCE_EXPLAINED_HAS_TO_CHARGE, ubTargetNPC ) == FALSE) { TriggerNPCRecord( ubTargetNPC, 15 ); } else { if ( CheckFact( FACT_LOYALTY_LOW, ubTargetNPC ) ) { gbHospitalPriceModifier = HOSPITAL_NORMAL; TriggerNPCRecord( ubTargetNPC, 16 ); } else if ( CheckFact( FACT_LOYALTY_OKAY, ubTargetNPC ) ) { gbHospitalPriceModifier = HOSPITAL_BREAK; TriggerNPCRecord( ubTargetNPC, 17 ); } else { iRandom = PreRandom( 100 ); if( ubTargetNPC == VINCE ) { if ( (gbHospitalPriceModifier == HOSPITAL_RANDOM_FREEBIE || gbHospitalPriceModifier == HOSPITAL_FREEBIE) || (CheckFact( FACT_HOSPITAL_FREEBIE_DECISION_MADE, 0 ) == FALSE && iRandom < CHANCE_FOR_DOCTOR_TO_SAY_RANDOM_QUOTE ) ) { SetFactTrue( FACT_HOSPITAL_FREEBIE_DECISION_MADE ); if ( CheckFact( FACT_LOYALTY_HIGH, ubTargetNPC ) && CheckFact( FACT_24_HOURS_SINCE_DOCTOR_TALKED_TO, ubTargetNPC ) ) { // loyalty high... freebie gbHospitalPriceModifier = HOSPITAL_FREEBIE; TriggerNPCRecord( ubTargetNPC, 19 ); } else { // random vince quote gbHospitalPriceModifier = HOSPITAL_RANDOM_FREEBIE; TriggerNPCRecord( ubTargetNPC, 20 ); } } else // loyalty good { gbHospitalPriceModifier = HOSPITAL_COST; TriggerNPCRecord( ubTargetNPC, 18 ); } } else { // it's steve willis // in discount mode? if ( CheckFact( FACT_WILLIS_GIVES_DISCOUNT, ubTargetNPC ) ) { // yep inform player gbHospitalPriceModifier = HOSPITAL_COST; TriggerNPCRecord( ubTargetNPC, 21 ); } else if ( CheckFact( FACT_WILLIS_HEARD_ABOUT_JOEY_RESCUE, ubTargetNPC ) ) { // joey rescued.... note this will set FACT_WILLIS_GIVES_DISCOUNT so this will only ever be handled once gbHospitalPriceModifier = HOSPITAL_FREEBIE; TriggerNPCRecord( ubTargetNPC, 20 ); } else if ( CheckFact( FACT_LOYALTY_HIGH, ubTargetNPC ) && CheckFact( FACT_24_HOURS_SINCE_DOCTOR_TALKED_TO, ubTargetNPC ) && ( (gbHospitalPriceModifier == HOSPITAL_FREEBIE) || (CheckFact( FACT_HOSPITAL_FREEBIE_DECISION_MADE, 0 ) == FALSE && iRandom < CHANCE_FOR_DOCTOR_TO_SAY_RANDOM_QUOTE ) ) ) { // loyalty high... freebie gbHospitalPriceModifier = HOSPITAL_FREEBIE; TriggerNPCRecord( ubTargetNPC, 19 ); } else // loyalty good { gbHospitalPriceModifier = HOSPITAL_COST; TriggerNPCRecord( ubTargetNPC, 18 ); } } } } break; case NPC_ACTION_CHECK_DOCTORING_MONEY_GIVEN: break; case NPC_ACTION_DOCTOR_ESCORT_PATIENTS: // find anyone in sector who is wounded; set to hospital patient pSoldier2 = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier2 ) { //HOSPITAL_PATIENT_DISTANCE cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt ) { pSoldier = cnt; // Are we in this sector, On the current squad? if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 && (pSoldier->stats.bLife < pSoldier->stats.bLifeMax || NumberOfDamagedStats(pSoldier) > 0) && pSoldier->bAssignment != ASSIGNMENT_HOSPITAL && PythSpacesAway( pSoldier->sGridNo, pSoldier2->sGridNo ) < HOSPITAL_PATIENT_DISTANCE ) { SetSoldierAssignment( pSoldier, ASSIGNMENT_HOSPITAL, 0, 0, 0 ); TriggerNPCRecord( pSoldier->ubProfile, 2 ); pSoldier->bHospitalPriceModifier = gbHospitalPriceModifier; // make sure this person doesn't have an absolute dest any more pSoldier->sAbsoluteFinalDestination = NOWHERE; } } SetFactFalse( FACT_HOSPITAL_FREEBIE_DECISION_MADE ); gbHospitalPriceModifier = HOSPITAL_NORMAL; } break; case NPC_ACTION_START_DOCTORING: { // reset fact he is expecting money fromt the player SetFactFalse( FACT_VINCE_EXPECTING_MONEY ); // check fact if( CheckFact( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES, ubTargetNPC ) ) { TriggerNPCRecord( ubTargetNPC, 28 ); } else { TriggerNPCRecord( ubTargetNPC, 35 ); } } break; case NPC_ACTION_VINCE_UNRECRUITABLE: SetFactFalse( FACT_VINCE_RECRUITABLE ); break; case NPC_ACTION_ELLIOT_DECIDE_WHICH_QUOTE_FOR_PLAYER_ATTACK: if( DidFirstBattleTakePlaceInThisTown( DRASSEN ) ) { TriggerNPCRecord( ELLIOT, 2 ); } else if( DidFirstBattleTakePlaceInThisTown( CAMBRIA ) ) { TriggerNPCRecord( ELLIOT, 3 ); } else { TriggerNPCRecord( ELLIOT, 1 ); } break; case NPC_ACTION_QUEEN_DECIDE_WHICH_QUOTE_FOR_PLAYER_ATTACK: if( DidFirstBattleTakePlaceInThisTown( DRASSEN ) ) { TriggerNPCRecord( QUEEN, 8 ); } else { TriggerNPCRecord( QUEEN, 9 ); } break; case NPC_ACTION_KROTT_ALIVE_LOYALTY_BOOST: /* Delayed loyalty effects elimininated. Sep.12/98. ARM AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, 480 + Random( 60 ), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_KROTT_ALIVE_LOYALTY_BOOST, 1 ); */ if ( gMercProfiles[ SERGEANT ].bMercStatus != MERC_IS_DEAD ) { // give loyalty bonus to Alma IncrementTownLoyalty( ALMA, LOYALTY_BONUS_FOR_SERGEANT_KROTT ); } break; case NPC_ACTION_MAKE_NPC_FIRST_BARTENDER: gMercProfiles[ ubTargetNPC ].bNPCData = 1; break; case NPC_ACTION_MAKE_NPC_SECOND_BARTENDER: gMercProfiles[ ubTargetNPC ].bNPCData = 2; break; case NPC_ACTION_MAKE_NPC_THIRD_BARTENDER: gMercProfiles[ ubTargetNPC ].bNPCData = 3; break; case NPC_ACTION_MAKE_NPC_FOURTH_BARTENDER: gMercProfiles[ ubTargetNPC ].bNPCData = 4; break; case NPC_ACTION_END_DEMO: DeleteTalkingMenu(); // hack!! EndGameMessageBoxCallBack( MSG_BOX_RETURN_YES ); break; case NPC_ACTION_SEND_ENRICO_MIGUEL_EMAIL: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, 390 + Random( 60 ), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_SEND_ENRICO_MIGUEL_EMAIL, 1 ); break; case NPC_ACTION_PLAYER_SAYS_NICE_LATER: SetFactTrue( FACT_NEED_TO_SAY_SOMETHING ); gubNiceNPCProfile = gpDestSoldier->ubProfile; break; case NPC_ACTION_PLAYER_SAYS_NASTY_LATER: SetFactTrue( FACT_NEED_TO_SAY_SOMETHING ); gubNastyNPCProfile = gpDestSoldier->ubProfile; break; case NPC_ACTION_CHOOSE_DOCTOR: // find doctors available and trigger record 12 or 13 pSoldier = FindSoldierByProfileID( STEVE, FALSE ); // Steve Willis, 80 if (pSoldier) { if ( !pSoldier->bActive || !pSoldier->bInSector || !(pSoldier->bTeam == CIV_TEAM) || !(pSoldier->aiData.bNeutral) || (pSoldier->stats.bLife < OKLIFE) ) { pSoldier = NULL; } } pSoldier2 = FindSoldierByProfileID( VINCE, FALSE ); // Vince, 69 if (pSoldier2) { if ( !pSoldier2->bActive || !pSoldier2->bInSector || !(pSoldier2->bTeam == CIV_TEAM) || !(pSoldier2->aiData.bNeutral) || (pSoldier2->stats.bLife < OKLIFE) ) { pSoldier2 = NULL; } } if ( pSoldier == NULL && pSoldier2 == NULL ) { // uh oh break; } if( ( pSoldier ) && ( pSoldier2 ) ) { if( pSoldier->sGridNo == 10343 ) { pSoldier2 = NULL; } else if( pSoldier2->sGridNo == 10343 ) { pSoldier = NULL; } } if ( pSoldier && pSoldier2 ) { // both doctors available... turn one off randomly if ( Random( 2 ) ) { pSoldier = NULL; } else { pSoldier2 = NULL; } } // only one pointer left... if ( pSoldier ) { TriggerNPCRecord( ubTargetNPC, 12 ); } else { TriggerNPCRecord( ubTargetNPC, 13 ); } break; case NPC_ACTION_INVOKE_CONVERSATION_MODE: if ( !gfInTalkPanel ) { INT32 sNearestPC; SoldierID ubID; pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier ) { pSoldier2 = NULL; sNearestPC = ClosestPC( pSoldier, NULL ); if (!TileIsOutOfBounds(sNearestPC)) { ubID = WhoIsThere2( sNearestPC, 0 ); if (ubID != NOBODY) { pSoldier2 = ubID; } } if ( pSoldier2 ) { InitiateConversation( pSoldier, pSoldier2, NPC_INITIAL_QUOTE, 0 ); } } } break; case NPC_ACTION_KINGPIN_TRIGGER_25_OR_14: if ( CheckFact( FACT_KINGPIN_INTRODUCED_SELF, ubTargetNPC ) == TRUE) { TriggerNPCRecord( ubTargetNPC, 25 ); } else { TriggerNPCRecord( ubTargetNPC, 14 ); } break; case NPC_ACTION_INITIATE_SHOPKEEPER_INTERFACE: // check if this is a shopkeeper who has been shutdown if( HandleShopKeepHasBeenShutDown( gTalkPanel.ubCharNum ) == FALSE ) { DeleteTalkingMenu( ); EnterShopKeeperInterfaceScreen( gTalkPanel.ubCharNum ); } break; case NPC_ACTION_DRINK_WINE: gMercProfiles[ ubTargetNPC ].bNPCData += 2; break; case NPC_ACTION_DRINK_BOOZE: gMercProfiles[ ubTargetNPC ].bNPCData += 4; break; case NPC_ACTION_TRIGGER_ANGEL_22_OR_24: if ( CheckFact ( 120, ubTargetNPC ) ) // NB fact 120 is Angel left deed on counter { TriggerNPCRecord( ubTargetNPC, 22 ); } else { TriggerNPCRecord( ubTargetNPC, 24 ); } break; case NPC_ACTION_GRANT_EXPERIENCE_1: AwardExperienceBonusToActiveSquad( EXP_BONUS_MINIMUM ); break; case NPC_ACTION_GRANT_EXPERIENCE_2: AwardExperienceBonusToActiveSquad( EXP_BONUS_SMALL ); break; case NPC_ACTION_GRANT_EXPERIENCE_3: AwardExperienceBonusToActiveSquad( EXP_BONUS_AVERAGE ); break; case NPC_ACTION_GRANT_EXPERIENCE_4: AwardExperienceBonusToActiveSquad( EXP_BONUS_LARGE ); break; case NPC_ACTION_GRANT_EXPERIENCE_5: AwardExperienceBonusToActiveSquad( EXP_BONUS_MAXIMUM ); break; case NPC_ACTION_TRIGGER_YANNI: if ( CheckFact( FACT_CHALICE_STOLEN, 0 ) == TRUE ) { TriggerNPCRecord( YANNI, 8 ); } else { TriggerNPCRecord( YANNI, 7 ); } break; case NPC_ACTION_TRIGGER_MARY_OR_JOHN_RECORD_9: pSoldier = FindSoldierByProfileID ( MARY, FALSE ); if ( pSoldier && pSoldier->stats.bLife >= OKLIFE ) { TriggerNPCRecord( MARY, 9 ); } else { TriggerNPCRecord( JOHN, 9 ); } break; case NPC_ACTION_TRIGGER_MARY_OR_JOHN_RECORD_10: pSoldier = FindSoldierByProfileID ( MARY, FALSE ); if ( pSoldier && pSoldier->stats.bLife >= OKLIFE ) { TriggerNPCRecord( MARY, 10 ); } else { TriggerNPCRecord( JOHN, 10 ); } break; case NPC_ACTION_GET_OUT_OF_WHEELCHAIR: pSoldier = FindSoldierByProfileID ( ubTargetNPC, FALSE ); if ( pSoldier && pSoldier->ubBodyType == CRIPPLECIV ) { DeleteTalkingMenu(); pSoldier->EVENT_InitNewSoldierAnim( CRIPPLE_KICKOUT, 0, TRUE ); } break; case NPC_ACTION_GET_OUT_OF_WHEELCHAIR_AND_BECOME_HOSTILE: pSoldier = FindSoldierByProfileID ( ubTargetNPC, FALSE ); if ( pSoldier && pSoldier->ubBodyType == CRIPPLECIV ) { DeleteTalkingMenu(); pSoldier->EVENT_InitNewSoldierAnim( CRIPPLE_KICKOUT, 0, TRUE ); } TriggerFriendWithHostileQuote( ubTargetNPC ); break; case NPC_ACTION_ADD_JOHNS_GUN_SHIPMENT: AddJohnsGunShipment(); #ifdef JA2UB #else // anv: recruitable Kulba if( gGameExternalOptions.fEnableRecruitableJohnKulba == TRUE ) AddJohnAsMerc(); #endif // also close panel DeleteTalkingMenu(); break; case NPC_ACTION_SET_FACT_105_FALSE: SetFactFalse( FACT_FRANK_HAS_BEEN_BRIBED ); break; case NPC_ACTION_CANCEL_WAYPOINTS: pSoldier = FindSoldierByProfileID ( ubTargetNPC, FALSE ); if ( pSoldier ) { pSoldier->aiData.bOrders = ONGUARD; } break; case NPC_ACTION_MAKE_RAT_DISAPPEAR: // hack a flag to determine when RAT should leave gMercProfiles[ RAT ].bNPCData = 1; break; case NPC_ACTION_TRIGGER_MICKY_BY_SCI_FI: if ( gGameOptions.ubGameStyle == STYLE_SCIFI && gGameExternalOptions.fEnableCrepitus) { TriggerNPCRecord( MICKY, 7 ); } else { TriggerNPCRecord( MICKY, 8 ); } break; case NPC_ACTION_TRIGGER_KROTT_11_OR_12: if ( CheckFact( FACT_KROTT_GOT_ANSWER_NO, SERGEANT ) ) { TriggerNPCRecord( SERGEANT, 11 ); } else { TriggerNPCRecord( SERGEANT, 12 ); // SANDRO - give reward for rescuing Krott and getting the rocket rifle GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 5, CONRAD ); } break; case NPC_ACTION_CHANGE_MANNY_POSITION: gMercProfiles[ MANNY ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE; gMercProfiles[ MANNY ].ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; gMercProfiles[ MANNY ].usStrategicInsertionData = 19904; gMercProfiles[ MANNY ].fUseProfileInsertionInfo = TRUE; pSoldier = FindSoldierByProfileID( MANNY, FALSE ); if ( pSoldier ) { pSoldier->aiData.bOrders = STATIONARY; } // close his panel too DeleteTalkingMenu(); break; case NPC_ACTION_MAKE_BRENDA_STATIONARY: pSoldier = FindSoldierByProfileID( BRENDA, FALSE ); if ( pSoldier ) { gMercProfiles[ BRENDA ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE; gMercProfiles[ BRENDA ].ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; gMercProfiles[ BRENDA ].usStrategicInsertionData = pSoldier->sGridNo; gMercProfiles[ BRENDA ].fUseProfileInsertionInfo = TRUE; pSoldier->aiData.bOrders = STATIONARY; } break; case NPC_ACTION_MAKE_MIGUEL_STATIONARY: pSoldier = FindSoldierByProfileID( MIGUEL, FALSE ); if ( pSoldier ) { gMercProfiles[ MIGUEL ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE; gMercProfiles[ MIGUEL ].ubStrategicInsertionCode = INSERTION_CODE_GRIDNO; gMercProfiles[ MIGUEL ].usStrategicInsertionData = pSoldier->sGridNo; gMercProfiles[ MIGUEL ].fUseProfileInsertionInfo = TRUE; pSoldier->aiData.bOrders = STATIONARY; } break; case NPC_ACTION_TRIGGER_DARREN_OR_KINGPIN_IMPRESSED: if ( BoxerAvailable() ) { TriggerNPCRecord( DARREN, 25 ); } // else FALL THROUGH to check for Kingpin being impressed case NPC_ACTION_TRIGGER_KINGPIN_IMPRESSED: if ( gfLastBoxingMatchWonByPlayer && !BoxerAvailable() ) { TriggerNPCRecord( KINGPIN, 15 ); // WANNE: Disabled the quest reward points, because the whole team gets experience points too fast when doing some boxing // SANDRO - merc records - quest counter (Kingpin impressed) //GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); } break; case NPC_ACTION_ADD_RAT: // add Rat gMercProfiles[ RAT ].sSectorX = gModSettings.ubAddRatSectorX; //9 gMercProfiles[ RAT ].sSectorY = gModSettings.ubAddRatSectorY; //7 gMercProfiles[ RAT ].bSectorZ = gModSettings.ubAddRatSectorZ; //0 break; case NPC_ACTION_ENDGAME_STATE_1: // What is the status of fact for creatures? if ( gubQuest[ 15 ] == QUESTINPROGRESS ) { // This is not the end, 'cause momma creature is still alive TriggerNPCRecordImmediately( 136, 8 ); #ifdef JA2UB //no Ub #else EndQueenDeathEndgame( ); #endif } else { // Continue with endgame cimematic.. DeleteTalkingMenu( ); #ifdef JA2UB //no Ub #else EndQueenDeathEndgameBeginEndCimenatic( ); #endif } break; case NPC_ACTION_ENDGAME_STATE_2: // Just end queen killed dequence....... DeleteTalkingMenu( ); #ifdef JA2UB // no UB #else EndQueenDeathEndgame( ); #endif break; case NPC_ACTION_MAKE_ESTONI_A_FUEL_SITE: // Jake's script also sets the fact, but we need to be sure it happens before updating availability SetFactTrue( FACT_ESTONI_REFUELLING_POSSIBLE ); UpdateRefuelSiteAvailability(); break; case NPC_ACTION_24_HOURS_SINCE_JOEY_RESCUED: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), FACT_24_HOURS_SINCE_JOEY_RESCUED, 1 ); break; case NPC_ACTION_24_HOURS_SINCE_DOCTORS_TALKED_TO: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), FACT_24_HOURS_SINCE_DOCTOR_TALKED_TO, 1 ); break; case NPC_ACTION_REMOVE_MERC_FOR_MARRIAGE: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier ) { pSoldier = ChangeSoldierTeam( pSoldier, CIV_TEAM ); } Assert(pSoldier); // remove profile from map gMercProfiles[ pSoldier->ubProfile ].sSectorX = 0; gMercProfiles[ pSoldier->ubProfile ].sSectorY = 0; pSoldier->ubProfile = NO_PROFILE; // set to 0 civ group pSoldier->ubCivilianGroup = 0; break; case NPC_ACTION_TIMER_FOR_VEHICLE: AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_TIMER_FOR_VEHICLE, 1 ); break; case NPC_ACTION_RESET_SHIPMENT_ARRIVAL_STUFF: break; case NPC_ACTION_TRIGGER_JOE_32_OR_33: if ( gbWorldSectorZ > 0 ) { TriggerNPCRecord( JOE, 32 ); } else { TriggerNPCRecord( JOE, 33 ); } break; case NPC_ACTION_REMOVE_NPC: pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); if ( pSoldier ) { EndAIGuysTurn( pSoldier ); RemoveManAsTarget( pSoldier ); TacticalRemoveSoldier( pSoldier->ubID ); gMercProfiles[ ubTargetNPC ].sSectorX = 0; gMercProfiles[ ubTargetNPC ].sSectorY = 0; CheckForEndOfBattle( TRUE ); } break; case NPC_ACTION_HISTORY_GOT_ROCKET_RIFLES: AddHistoryToPlayersLog( HISTORY_GOT_ROCKET_RIFLES, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_DEIDRANNA_DEAD_BODIES: AddHistoryToPlayersLog( HISTORY_DEIDRANNA_DEAD_BODIES, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_BOXING_MATCHES: AddHistoryToPlayersLog( HISTORY_BOXING_MATCHES, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_SOMETHING_IN_MINES: AddHistoryToPlayersLog( HISTORY_SOMETHING_IN_MINES, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_DEVIN: AddHistoryToPlayersLog( HISTORY_DEVIN, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_MIKE: AddHistoryToPlayersLog( HISTORY_MIKE, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_TONY: AddHistoryToPlayersLog( HISTORY_TONY, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_KROTT: AddHistoryToPlayersLog( HISTORY_KROTT, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_KYLE: AddHistoryToPlayersLog( HISTORY_KYLE, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_MADLAB: AddHistoryToPlayersLog( HISTORY_MADLAB, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_GABBY: AddHistoryToPlayersLog( HISTORY_GABBY, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_KEITH_OUT_OF_BUSINESS: AddHistoryToPlayersLog( HISTORY_KEITH_OUT_OF_BUSINESS, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_HOWARD_CYANIDE: AddHistoryToPlayersLog( HISTORY_HOWARD_CYANIDE, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_KEITH: AddHistoryToPlayersLog( HISTORY_KEITH, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_HOWARD: AddHistoryToPlayersLog( HISTORY_HOWARD, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_PERKO: AddHistoryToPlayersLog( HISTORY_PERKO, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_SAM: AddHistoryToPlayersLog( HISTORY_SAM, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_FRANZ: AddHistoryToPlayersLog( HISTORY_FRANZ, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_ARNOLD: AddHistoryToPlayersLog( HISTORY_ARNOLD, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_FREDO: AddHistoryToPlayersLog( HISTORY_FREDO, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_RICHGUY_BALIME: AddHistoryToPlayersLog( HISTORY_RICHGUY_BALIME, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_JAKE: AddHistoryToPlayersLog( HISTORY_JAKE, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_BUM_KEYCARD: AddHistoryToPlayersLog( HISTORY_BUM_KEYCARD, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_WALTER: AddHistoryToPlayersLog( HISTORY_WALTER, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_DAVE: AddHistoryToPlayersLog( HISTORY_DAVE, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_PABLO: AddHistoryToPlayersLog( HISTORY_PABLO, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_HISTORY_KINGPIN_MONEY: AddHistoryToPlayersLog( HISTORY_KINGPIN_MONEY, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_SEND_TROOPS_TO_SAM: break; case NPC_ACTION_PUT_PACOS_IN_BASEMENT: gMercProfiles[ PACOS ].sSectorX = 10; gMercProfiles[ PACOS ].sSectorY = MAP_ROW_A; gMercProfiles[ PACOS ].bSectorZ = 1; //kitty: fixed - first level underground is 1, not 0 break; case NPC_ACTION_HISTORY_ASSASSIN: AddHistoryToPlayersLog( HISTORY_ASSASSIN, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); break; case NPC_ACTION_TRIGGER_HANS_BY_ROOM: { if ( gpSrcSoldier ) { //DBrot: More Rooms //UINT8 ubRoom; UINT16 usRoom; if ( InARoom( gpSrcSoldier->sGridNo, &usRoom ) && (usRoom == gModSettings.usPornShopRoomHans) ) { TriggerNPCRecord( HANS, 18 ); } else { TriggerNPCRecord( HANS, 14 ); } } } break; case NPC_ACTION_TRIGGER_MADLAB_31: if ( PlayerTeamFull( ) ) { DeleteTalkingMenu( ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_RECRUIT_TEAM_FULL ] ); } else { TriggerNPCRecord( MADLAB, 31 ); } break; case NPC_ACTION_TRIGGER_MADLAB_32: if ( PlayerTeamFull( ) ) { DeleteTalkingMenu( ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_RECRUIT_TEAM_FULL ] ); } else { TriggerNPCRecord( MADLAB, 32 ); } break; case NPC_ACTION_TRIGGER_BREWSTER_BY_WARDEN_PROXIMITY: pSoldier = FindSoldierByProfileID( BREWSTER, FALSE ); if ( pSoldier ) { sGridNo = GetGridNoOfCorpseGivenProfileID( WARDEN ); if (!TileIsOutOfBounds(sGridNo) && PythSpacesAway( pSoldier->sGridNo, sGridNo ) <= 10 ) { TriggerNPCRecord( BREWSTER, 16 ); } else { TriggerNPCRecord( BREWSTER, 17 ); } } break; case NPC_ACTION_FILL_UP_CAR: pSoldier = FindSoldierByProfileID( PROF_HUMMER, TRUE ); if ( !pSoldier ) { // ice cream truck? pSoldier = FindSoldierByProfileID( PROF_ICECREAM, TRUE ); } else if ( pSoldier->sBreathRed == 10000 ) { pSoldier2 = FindSoldierByProfileID( PROF_ICECREAM, TRUE ); if ( pSoldier2 ) { // try refueling this vehicle instead pSoldier = pSoldier2; } } if ( pSoldier ) { pSoldier->sBreathRed = 10000; pSoldier->bBreath = 100; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 50 ] ); } break; case NPC_ACTION_WALTER_GIVEN_MONEY_INITIALLY: if ( gMercProfiles[ WALTER ].iBalance >= WALTER_BRIBE_AMOUNT ) { TriggerNPCRecord( WALTER, 16 ); } else { TriggerNPCRecord( WALTER, 14 ); } break; case NPC_ACTION_WALTER_GIVEN_MONEY: if ( gMercProfiles[ WALTER ].iBalance >= WALTER_BRIBE_AMOUNT ) { TriggerNPCRecord( WALTER, 16 ); } else { TriggerNPCRecord( WALTER, 15 ); } break; #ifdef JA2UB //JA25 UB case NPC_ACTION_TRIGGER_JERRY_CONVERSATION_WITH_PGC_1: PerformJerryMiloAction301(); break; case NPC_ACTION_TRIGGER_JERRY_CONVERSATION_WITH_PGC_2: PerformJerryMiloAction302(); break; case NPC_ACTION_BIGGENS_DETONATES_BOMBS: HaveBiggensDetonatingExplosivesByTheMine(); break; case NPC_ACTION_LEAVING_NPC_TALK_MENU: HandleSpecificQuoteWhenLeavingNpcTalkMenu(); break; case NPC_ACTION_RAUL_BLOWS_HIMSELF_UP: HandleRaulBlowingHimselfUp(); break; case NPC_ACTION_TEX_FLUSHES_TOILET: HandleTexFlushingToilet(); break; case NPC_ACTION_MARK_TEX_AS_ALREADY_INTRODUCED_HIMSELF: HandleTexMakingHimselfAlreadyBeIntroduced(); break; case NPC_ACTION_MAKE_TEX_CAMOED: HandleTexBecomingCamoed(); break; case NPC_ACTION_HAVE_DEALER_OPEN_BUY_SELL_SCREEN: HaveNpcOpenUpDealerScreen( ubTargetNPC ); break; #endif case NPC_ACTION_RECRUIT_PROFILE_TO_EPC: //if ( !CheckNPCIsEPC(ubTargetNPC) ) //{ RecruitEPC( ubTargetNPC ); //} break; case NPC_ACTION_UNRECRUIT_EPC: //if ( CheckNPCIsEPC(ubTargetNPC) ) // { UnRecruitEPC( ubTargetNPC ); // } break; case NPC_ACTION_WALDO_START_REPAIRS: // it's called after giving him money StartHelicopterRepair( FALSE, TRUE ); break; default: ScreenMsg( FONT_MCOLOR_RED, MSG_TESTVERSION, L"No code support for NPC action %d", usActionCode ); break; } //Lua // LuaHandleNPCDoAction( ubTargetNPC, usActionCode, ubQuoteNum , 0); } } UINT32 CalcPatientMedicalCost( SOLDIERTYPE * pSoldier ) { UINT32 uiCost; if ( !pSoldier ) { return( 0 ); } if ( pSoldier->bHospitalPriceModifier == HOSPITAL_FREEBIE || pSoldier->bHospitalPriceModifier == HOSPITAL_RANDOM_FREEBIE ) { return( 0 ); } uiCost = 10 * ( pSoldier->stats.bLifeMax - pSoldier->stats.bLife ); for (UINT8 index = 0; index < NUM_DAMAGABLE_STATS; ++index) { // charge additional $150 for every damaged stat point uiCost += (150 * pSoldier->ubCriticalStatDamage[index]); } if ( pSoldier->stats.bLife < OKLIFE ) { // charge additional $25 for every point below OKLIFE he is uiCost += ( 25 * ( OKLIFE - pSoldier->stats.bLife ) ); } // also charge $2 for each point of bleeding that must be stopped if ( pSoldier->bBleeding > 0 ) { uiCost += ( 2 * pSoldier->bBleeding ); } if ( pSoldier->bHospitalPriceModifier == HOSPITAL_BREAK ) { uiCost = (uiCost * 85) / 100; } else if ( pSoldier->bHospitalPriceModifier == HOSPITAL_COST ) { // 30% discount uiCost = (uiCost * 70) / 100; } else if ( pSoldier->bHospitalPriceModifier == HOSPITAL_UNSET ) { if ( gbHospitalPriceModifier == HOSPITAL_BREAK ) { // 15% discount uiCost = (uiCost * 85) / 100; } else if ( gbHospitalPriceModifier == HOSPITAL_COST ) { // 30% discount uiCost = (uiCost * 70) / 100; } } return( uiCost ); } UINT32 CalcMedicalCost( UINT8 ubId ) { UINT32 uiCostSoFar = 0; SOLDIERTYPE* pSoldier; // find the doctor's soldiertype to get his position SOLDIERTYPE* pNPC = FindSoldierByProfileID( ubId, FALSE ); if (!pNPC) { return( 0 ); } INT32 sGridNo = pNPC->sGridNo; for ( SoldierID cnt = gTacticalStatus.Team[gbPlayerNum].bFirstID; cnt <= gTacticalStatus.Team[gbPlayerNum].bLastID; ++cnt ) { pSoldier = cnt; if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 && pSoldier->bAssignment != ASSIGNMENT_HOSPITAL ) { if ( pSoldier->stats.bLife < pSoldier->stats.bLifeMax || NumberOfDamagedStats(pSoldier) > 0) { if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= HOSPITAL_PATIENT_DISTANCE) { uiCostSoFar += CalcPatientMedicalCost( pSoldier ); } } } } // round up to nearest 10 dollars uiCostSoFar = ( (uiCostSoFar + 9) / 10 ); uiCostSoFar *= 10; // always ask for at least $10 uiCostSoFar = __max( 10, uiCostSoFar ); return( uiCostSoFar ); } BOOLEAN PlayerTeamHasTwoSpotsLeft( ) { return ( CountNonVehiclesOnPlayerTeam() <= OUR_TEAM_SIZE_NO_VEHICLE - 2 ); } void StartDialogueMessageBox( UINT8 ubProfileID, UINT16 usMessageBoxType ) { INT32 iTemp; CHAR16 zTemp[256], zTemp2[256]; gusDialogueMessageBoxType = usMessageBoxType; switch( gusDialogueMessageBoxType ) { case NPC_ACTION_ASK_ABOUT_ESCORTING_EPC: if ( (ubProfileID == JOHN && gMercProfiles[ MARY ].bMercStatus != MERC_IS_DEAD) || (ubProfileID == MARY && gMercProfiles[ JOHN ].bMercStatus != MERC_IS_DEAD) ) { swprintf( zTemp, gzLateLocalizedString[59] ); } else { swprintf( zTemp, TacticalStr[ ESCORT_PROMPT ], gMercProfiles[ubProfileID].zNickname ); } DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_ASK_ABOUT_PAYING_RPC: case NPC_ACTION_ASK_ABOUT_PAYING_RPC_WITH_DAILY_SALARY: case NPC_ACTION_REDUCE_CONRAD_SALARY_CONDITIONS: swprintf( zTemp2, L"%s", FormatMoney(gMercProfiles[ubProfileID].sSalary).data()); swprintf( zTemp, TacticalStr[ HIRE_PROMPT ], gMercProfiles[ubProfileID].zNickname, zTemp2 ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_DARREN_REQUESTOR: case NPC_ACTION_FIGHT_AGAIN_REQUESTOR: DoMessageBox( MSG_BOX_BASIC_STYLE, TacticalStr[ BOXING_PROMPT ], GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_BUY_LEATHER_KEVLAR_VEST: swprintf( zTemp2, L"%s", FormatMoney(Item[LEATHER_JACKET_W_KEVLAR].usPrice).data()); swprintf( zTemp, TacticalStr[ BUY_VEST_PROMPT ], ItemNames[LEATHER_JACKET_W_KEVLAR], zTemp2 ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_PROMPT_PLAYER_TO_LIE: DoMessageBox( MSG_BOX_BASIC_STYLE, TacticalStr[ YESNOLIE_STR ], GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNOLIE, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_MEDICAL_REQUESTOR_2: swprintf( zTemp, TacticalStr[ FREE_MEDICAL_PROMPT ] ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_MEDICAL_REQUESTOR: iTemp = (INT32) CalcMedicalCost( ubProfileID ); if ( giHospitalRefund > iTemp ) { iTemp = 10; } else { iTemp -= giHospitalRefund; } swprintf( zTemp2, L"%s", FormatMoney(iTemp).data()); swprintf( zTemp, TacticalStr[ PAY_MONEY_PROMPT ], zTemp2 ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_BUY_VEHICLE_REQUESTOR: swprintf( zTemp2, L"%s", FormatMoney(10000).data()); swprintf( zTemp, TacticalStr[ PAY_MONEY_PROMPT ], zTemp2 ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_TRIGGER_MARRY_DARYL_PROMPT: swprintf( zTemp, TacticalStr[ MARRY_DARYL_PROMPT ], gMercProfiles[ubProfileID].zNickname ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; case NPC_ACTION_KROTT_REQUESTOR: swprintf( zTemp, TacticalStr[ SPARE_KROTT_PROMPT ], gMercProfiles[ubProfileID].zNickname ); DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; // anv: Waldo The Mechanic case NPC_ACTION_WALDO_REPAIR_REQUESTOR: swprintf( zTemp, TacticalStr[ STR_HELI_RR_REPAIR_PROMPT ], gMercProfiles[ubProfileID].zNickname ); if( CheckFact(FACT_HELI_DAMAGED_CAN_START_REPAIR, 0) == TRUE ) { swprintf( zTemp, pHelicopterRepairRefuelStrings[ STR_HELI_RR_REPAIR_PROMPT ], gMercProfiles[ WALDO ].zNickname, CalculateHelicopterRepairCost( FALSE ), gHelicopterSettings.ubHelicopterBasicRepairTime); } else { swprintf( zTemp, pHelicopterRepairRefuelStrings[ STR_HELI_RR_REPAIR_PROMPT ], gMercProfiles[ WALDO ].zNickname, CalculateHelicopterRepairCost( TRUE ), gHelicopterSettings.ubHelicopterSeriousRepairTime ); } DoMessageBox( MSG_BOX_BASIC_STYLE, zTemp, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, DialogueMessageBoxCallBack, NULL ); break; default: break; } } void DialogueMessageBoxCallBack( UINT8 ubExitValue ) { UINT8 ubProfile; SOLDIERTYPE *pSoldier; ubProfile = gpDestSoldier->ubProfile; switch( gusDialogueMessageBoxType ) { case NPC_ACTION_ASK_ABOUT_ESCORTING_EPC: if ( ubExitValue == MSG_BOX_RETURN_YES ) { // Delete menu DeleteTalkingMenu( ); if ( PlayerTeamFull() ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_RECRUIT_TEAM_FULL ] ); } else { if ( ubProfile == JOHN ) { // WANNE: Bugfix: CTD when recruting John and Mary and there is only one place left in the team. // Mary might be alive, and if so we need to ensure two places pSoldier = FindSoldierByProfileID( MARY, FALSE ); if ( pSoldier && !PlayerTeamHasTwoSpotsLeft() ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_RECRUIT_TEAM_FULL ] ); break; } } RecruitEPC( ubProfile ); // Get soldier pointer pSoldier = FindSoldierByProfileID( ubProfile, FALSE ); if ( !pSoldier ) { return; } // OK, update UI with message that we have been recruited ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ NOW_BING_ESCORTED_STR ], gMercProfiles[ ubProfile ].zNickname, ( pSoldier->bAssignment + 1 ) ); // Change Squads.... SetCurrentSquad( pSoldier->bAssignment, FALSE ); HandleStuffForNPCEscorted( ubProfile ); } } break; case NPC_ACTION_ASK_ABOUT_PAYING_RPC: case NPC_ACTION_ASK_ABOUT_PAYING_RPC_WITH_DAILY_SALARY: #ifdef JA2UB if ( ubExitValue == MSG_BOX_RETURN_YES ) { //if the player cannot afford to hire the npc if( LaptopSaveInfo.iCurrentBalance < gMercProfiles[ubProfile].sSalary ) { //Set a flag indicating that you cannot afford the merc gfDisplayMsgBoxSayingCantAffordNPC = TRUE; } else { //First Deduct the money out of the players account AddTransactionToPlayersBook( PAYMENT_TO_NPC, ubProfile, GetWorldTotalMin(), -gMercProfiles[ubProfile].sSalary ); TriggerNPCRecord( ubProfile, 1 ); //if the person is BIGGENS if( ubProfile == BIGGENS_UB ) //BIGGENS { SetFactTrue( FACT_BIGGENS_IS_ON_TEAM ); } } } else { TriggerNPCRecord( ubProfile, 0 ); } #else if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, 1 ); } else { TriggerNPCRecord( ubProfile, 0 ); } #endif break; case NPC_ACTION_REDUCE_CONRAD_SALARY_CONDITIONS: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, 1 ); } else { TriggerNPCRecord( ubProfile, 2 ); } break; break; case NPC_ACTION_DARREN_REQUESTOR: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, 13 ); } else { TriggerNPCRecord( ubProfile, 12 ); } break; case NPC_ACTION_FIGHT_AGAIN_REQUESTOR: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, 30 ); } else { TriggerNPCRecord( ubProfile, 12 ); } break; case NPC_ACTION_BUY_LEATHER_KEVLAR_VEST: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, 27 ); } else { TriggerNPCRecord( ubProfile, 28 ); } break; case NPC_ACTION_PROMPT_PLAYER_TO_LIE: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( ubProfile, (UINT8)( ubRecordThatTriggeredLiePrompt + 1 ) ); } else if ( ubExitValue == MSG_BOX_RETURN_NO ) { TriggerNPCRecord( ubProfile, (UINT8)( ubRecordThatTriggeredLiePrompt + 2 ) ); } else { // He tried to lie..... // Find the best conscious merc with a chance.... SoldierID cnt; SOLDIERTYPE *pLier = NULL; SOLDIERTYPE *pSoldier; cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt ) { pSoldier = cnt; if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife >= OKLIFE && pSoldier->bBreath >= OKBREATH ) { if (!pLier || (EffectiveWisdom( pSoldier ) + EffectiveLeadership( pSoldier ) > EffectiveWisdom( pLier ) + EffectiveLeadership( pSoldier ) ) ) { pLier = pSoldier; } } } if ( pLier && SkillCheck( pLier, LIE_TO_QUEEN_CHECK, 0 ) >= 0 ) { // SUCCESS.. TriggerNPCRecord( ubProfile, (UINT8)( ubRecordThatTriggeredLiePrompt + 4 ) ); } else { // NAUGHY BOY TriggerNPCRecord( ubProfile, (UINT8)( ubRecordThatTriggeredLiePrompt + 3 ) ); } } break; case NPC_ACTION_MEDICAL_REQUESTOR: case NPC_ACTION_MEDICAL_REQUESTOR_2: if ( gusDialogueMessageBoxType == NPC_ACTION_MEDICAL_REQUESTOR ) { if ( ubExitValue == MSG_BOX_RETURN_YES ) { // give the guy the cash TriggerNPCRecord( ubProfile, 23 ); } else { // no cash, no help TriggerNPCRecord( ubProfile, 24 ); } } else { if ( ubExitValue == MSG_BOX_RETURN_YES ) { //HandleNPCDoAction( VINCE, NPC_ACTION_CHECK_DOCTORING_MONEY_GIVEN, 0 ); if ( CheckFact( FACT_WOUNDED_MERCS_NEARBY, ubProfile ) ) { TriggerNPCRecord( ubProfile, 26 ); } else if ( CheckFact( FACT_ONE_WOUNDED_MERC_NEARBY, ubProfile ) ) { TriggerNPCRecord( ubProfile, 25 ); } if ( ubProfile == VINCE ) giHospitalTempBalance = 0; else gMercProfiles[VINCE].iBalance = 0; } else { // just don't want the help if ( ubProfile == VINCE ) TriggerNPCRecord( ubProfile, 34 ); else TriggerNPCRecord( STEVE, 30 ); } } DeleteTalkingMenu(); break; case NPC_ACTION_BUY_VEHICLE_REQUESTOR: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( GERARD, 9 ); // Dave Gerard } else { TriggerNPCRecord( GERARD, 8 ); } break; case NPC_ACTION_KROTT_REQUESTOR: if ( ubExitValue == MSG_BOX_RETURN_YES ) { TriggerNPCRecord( SERGEANT, 7 ); } else { TriggerNPCRecord( SERGEANT, 6 ); } break; case NPC_ACTION_WALDO_REPAIR_REQUESTOR: if ( ubExitValue == MSG_BOX_RETURN_YES ) { StartHelicopterRepair( FALSE, FALSE ); } else { TriggerNPCRecord( WALDO, 17 ); } break; case NPC_ACTION_TRIGGER_MARRY_DARYL_PROMPT: gMercProfiles[ gpSrcSoldier->ubProfile ].ubMiscFlags2 |= PROFILE_MISC_FLAG2_ASKED_BY_HICKS; if ( ubExitValue == MSG_BOX_RETURN_YES ) { gMercProfiles[ DARYL ].bNPCData = (INT8) gpSrcSoldier->ubProfile; // create key for Daryl to give to player pSoldier = FindSoldierByProfileID( DARYL, FALSE ); if ( pSoldier ) { CreateKeyObject( &gTempObject, 1, 38 ); AutoPlaceObject( pSoldier, &gTempObject, FALSE ); } TriggerNPCRecord( DARYL, 11 ); } else { TriggerNPCRecord( DARYL, 12 ); } break; default: break; } } void DoneFadeOutActionBasement( ) { // OK, insertion data found, enter sector! //DBrot: Grids SetCurrentWorldSector( gModSettings.ubHideoutSectorX, gModSettings.ubHideoutSectorY, gModSettings.ubHideoutSectorZ ); // OK, once down here, adjust the above map with crate info.... gfTacticalTraversal = FALSE; gpTacticalTraversalGroup = NULL; gpTacticalTraversalChosenSoldier = NULL; // Remove crate RemoveStructFromUnLoadedMapTempFile( gModSettings.iHideoutEntryGrid, gModSettings.usCrateTileDef, gModSettings.ubHideoutSurfaceX, gModSettings.ubHideoutSurfaceY, gModSettings.ubHideoutSurfaceZ ); // Add crate AddStructToUnLoadedMapTempFile( gModSettings.iFinalCrateGrid, gModSettings.usCrateTileDef, gModSettings.ubHideoutSurfaceX, gModSettings.ubHideoutSurfaceY, gModSettings.ubHideoutSurfaceZ ); // Add trapdoor AddStructToUnLoadedMapTempFile( gModSettings.iHideoutEntryGrid, gModSettings.usTrapdoorTileDef, gModSettings.ubHideoutSurfaceX, gModSettings.ubHideoutSurfaceY, gModSettings.ubHideoutSurfaceZ ); gFadeInDoneCallback = DoneFadeInActionBasement; FadeInGameScreen( ); } void DoneFadeOutActionSex( ) { SetPendingNewScreen( SEX_SCREEN ); } void DoneFadeInActionBasement( ) { // Start conversation, etc SOLDIERTYPE *pSoldier, *pNPCSoldier; // Look for someone to talk to // look for all mercs on the same team, SoldierID cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; for ( ; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ++cnt ) { pSoldier = cnt; // Are we in this sector, On the current squad? if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bInSector && pSoldier->bAssignment == CurrentSquad( ) ) { break; } } // Get merc id for carlos! pNPCSoldier = FindSoldierByProfileID( 58, FALSE ); if ( !pNPCSoldier ) { return; } // Converse! //InitiateConversation( pNPCSoldier, pSoldier, 0, 1 ); TriggerNPCRecordImmediately( pNPCSoldier->ubProfile, 1 ); } void DoneFadeOutActionLeaveBasement( ) { // OK, insertion data found, enter sector! SetCurrentWorldSector( 10, 1, 0 ); gfTacticalTraversal = FALSE; gpTacticalTraversalGroup = NULL; gpTacticalTraversalChosenSoldier = NULL; gFadeInDoneCallback = DoneFadeInActionLeaveBasement; FadeInGameScreen( ); } void DoneFadeInActionLeaveBasement( ) { // Start conversation, etc } BOOLEAN NPCOpenThing( SOLDIERTYPE *pSoldier, BOOLEAN fDoor ) { STRUCTURE *pStructure; INT32 sStructGridNo; INT32 sActionGridNo; UINT8 ubDirection; INT32 sGridNo; DOOR * pDoor; // Find closest door and get struct data for it! if ( fDoor ) { sStructGridNo = FindClosestDoor( pSoldier ); if (TileIsOutOfBounds(sStructGridNo)) { return( FALSE ); } pStructure = FindStructure( sStructGridNo, STRUCTURE_ANYDOOR ); } else { // for Armand, hard code to tile 6968 if ( pSoldier->ubProfile == ARMAND ) { sStructGridNo = 6968; //dnl!!! } else { sStructGridNo = FindNearestOpenableNonDoor( pSoldier->sGridNo ); } if (TileIsOutOfBounds(sStructGridNo)) { return( FALSE ); } pStructure = FindStructure( sStructGridNo, STRUCTURE_OPENABLE ); } if ( pStructure == NULL ) { return( FALSE ); } if ( pStructure->fFlags & STRUCTURE_OPEN ) { // it's already open! TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_DONE_OPEN_STRUCTURE, FALSE ); return( FALSE ); } // anything that an NPC opens this way should become unlocked! pDoor = FindDoorInfoAtGridNo( sStructGridNo ); if ( pDoor ) { pDoor->fLocked = FALSE; } sActionGridNo = FindAdjacentGridEx( pSoldier, sStructGridNo, &ubDirection, NULL, FALSE, TRUE ); if ( sActionGridNo == -1 ) { return( FALSE ); } // Set dest gridno sGridNo = sActionGridNo; StartInteractiveObject( sStructGridNo, pStructure->usStructureID, pSoldier, ubDirection ); // check if we are at this location if ( pSoldier->sGridNo == sGridNo ) { InteractWithInteractiveObject( pSoldier, pStructure, ubDirection ); } else { SendGetNewSoldierPathEvent( pSoldier, sGridNo, pSoldier->usUIMovementMode ); } pSoldier->aiData.bAction = AI_ACTION_PENDING_ACTION; return( TRUE ); } void TextRegionClickCallback( 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 ) { InternalShutupaYoFace( gTalkPanel.iFaceIndex, FALSE ); } else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) { fLButtonDown = FALSE; } } void CarmenLeavesSectorCallback( void ) { #ifdef LUA_INTERFACE_DIALOGUE LetLuaInterfaceDialogue(0,0); #else if (gWorldSectorX == 13 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0) { TriggerNPCRecord( 78, 34 ); } else if (gWorldSectorX == 9 && gWorldSectorY == MAP_ROW_G && gbWorldSectorZ == 0) { TriggerNPCRecord( 78, 35 ); } else if (gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0) { TriggerNPCRecord( 78, 36 ); } #endif } #ifdef JA2UB //JA25 UB void PerformJerryMiloAction301() { SoldierID ubMercsPresent[NUM_MERCS_WITH_NEW_QUOTES]; UINT8 usNumMercsPresent; SOLDIERTYPE *pSoldier=NULL; SoldierID ubId; //Get the number and array of the new soldiers usNumMercsPresent = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( ubMercsPresent, NULL ); //Have them all say their quote for( UINT8 cnt=0; cnt 0 ) { UINT8 ubProfileID = NO_PROFILE; UINT8 ubIdOfMercWhoSaidQuote; ubIdOfMercWhoSaidQuote = Random( usNumMercsPresent ); UINT8 ubId = ubMercsPresent[ ubIdOfMercWhoSaidQuote ]; SOLDIERTYPE* pSoldier = MercPtrs[ ubId ]; TacticalCharacterDialogue( pSoldier, QUOTE_LAME_REFUSAL ); if( usNumMercsPresent == 1 ) ubProfileID = MercPtrs[ ubId ]->ubProfile; else { BOOLEAN fDone=FALSE; while( !fDone ) { ubProfileID = Random( usNumMercsPresent ); if( ubProfileID != ubIdOfMercWhoSaidQuote ) { ubId = ubMercsPresent[ ubProfileID ]; fDone = TRUE; } } ubProfileID = MercPtrs[ ubId ]->ubProfile; } //Say the quote in 15 seconds DelayedMercQuote( ubProfileID, QUOTE_DEPARTING_COMMENT_CONTRACT_NOT_RENEWED_OR_48_OR_MORE, GetWorldTotalSeconds( ) + 15 ); } //handle the merc arrives quotes now HandleMercArrivesQuotesFromHeliCrashSequence(); //Set the fact that we should show the destination dialog gJa25SaveStruct.fShowMercDestinationDialogWhenHiringMerc = TRUE; //Close the dialogue panel DeleteTalkingMenu(); } void DelayedMercQuote( UINT16 usProfileID, UINT32 uiQuoteNum, UINT32 uiTimeTillQuoteSaid ) { UINT32 uiParam; uiParam = usProfileID + ( uiQuoteNum << 16 ); AddStrategicEventUsingSeconds( EVENT_SAY_DELAYED_MERC_QUOTE, uiTimeTillQuoteSaid, uiParam ); } void DelayedSayingOfMercQuote( UINT32 uiParam ) { SOLDIERTYPE *pSoldier=NULL; UINT16 usProfileID; UINT16 usQuoteNum; usProfileID = 0x0000FFFF & uiParam; usQuoteNum = uiParam >> 16; //if its a normal quote if( usQuoteNum < DQ__NORMAL_DELAYED_QUOTE ) { //Get the soldier that should say the quote pSoldier = FindSoldierByProfileID( (UINT8)usProfileID, FALSE ); if( pSoldier == NULL ) return; // // Do Quote specific code here // if( usQuoteNum == QUOTE_DEPARTING_COMMENT_CONTRACT_NOT_RENEWED_OR_48_OR_MORE ) { //if the soldier is saying the 'brr its cold' quote, and he has left the sector if( pSoldier->sSectorX != JA2_5_START_SECTOR_X || pSoldier->sSectorY != JA2_5_START_SECTOR_Y && pSoldier->bSectorZ != 0 ) { //dont say the quote return; } } //Say the quote TacticalCharacterDialogue( pSoldier, usQuoteNum ); } else { switch( usQuoteNum ) { case DQ__JERRY_BROKE_TRANSMITTER: //Display the popup saying Jerry broke the transmitter DisplayJerryBreakingLaptopTransmitterPopup(); break; case DQ__MORRIS_NOTE_NEW_MERC_DELAY: HandleCommanderMorrisNewMercWantsNoteDelayedSpeech(); break; case DQ__MORRIS_NOTE_DISPLAY_NOTE_1: case DQ__MORRIS_NOTE_DISPLAY_NOTE_2: { //Get the soldier that should say the quote pSoldier = FindSoldierByProfileID( (UINT8)usProfileID, FALSE ); if( pSoldier == NULL ) return; DisplayCommanderMorrisNote( pSoldier ); } break; case DQ__SHOW_RADIO_LOCATOR: BeginMultiPurposeLocator( usProfileID, 0, TRUE ); break; case DQ__NEW_MERC_SAY_NOTE_QUOTES: //Get the soldier that should say the quote pSoldier = FindSoldierByProfileID( (UINT8)usProfileID, FALSE ); if( pSoldier == NULL ) return; HandleNewMercSayingContentsOfMorrisNote( pSoldier ); break; case DQ__START_EVERYONE_TALKING_AT_END_OF_GAME: EndGameEveryoneSayTheirGoodByQuotes(); break; case DQ__FADE_OUT_TO_END_GAME_CINEMATIC: HandleFadingOutToEndGameCinematics(); break; } } } void HandleSpecificQuoteWhenLeavingNpcTalkMenu() { SetFactTrue( FACT_MERC_SAY_QUOTE_WHEN_TALK_MENU_CLOSES ); } void HaveQualifiedMercSayQuoteAboutNpcWhenLeavingTalkScreen( UINT8 ubNpcProfileID, UINT32 uiQuoteNum ) { UINT8 usNumMercsPresent; SoldierID SoldierIdArray[NUM_MERCS_WITH_NEW_QUOTES]; SoldierID ValidSoldierIdArray[NUM_MERCS_WITH_NEW_QUOTES] = {0}; UINT8 ubNumValidSoldiers=0; UINT8 ubCnt; SOLDIERTYPE *pSoldier=NULL; SOLDIERTYPE * pNPC; pNPC = FindSoldierByProfileID( ubNpcProfileID, FALSE ); if( pNPC == NULL ) { return; } //Get the number and array of the new soldiers usNumMercsPresent = GetNumSoldierIdAndProfileIdOfTheNewMercsOnPlayerTeam( SoldierIdArray, NULL ); //if the player doesnt have any qualified players on the team if( !usNumMercsPresent ) { return; } //loop through the mercs and see if there in range of the dealer for( ubCnt=0; ubCntsGridNo, pSoldier->sGridNo ) < 10 && !AM_AN_EPC( pSoldier ) && !( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !(AM_A_ROBOT( pSoldier )) && !pSoldier->flags.fMercAsleep && SoldierTo3DLocationLineOfSightTest( pSoldier, pNPC->sGridNo, 0, 0, (UINT8)MaxDistanceVisible(), TRUE ) ) { ValidSoldierIdArray[ ubNumValidSoldiers ] = pSoldier->ubID; ++ubNumValidSoldiers; } } //If there is a valid merc, pick a merc to say the quote if( ubNumValidSoldiers > 0 ) { UINT8 ubChosenMerc = (UINT8)Random( ubNumValidSoldiers ); TacticalCharacterDialogue( MercPtrs[ ValidSoldierIdArray[ ubChosenMerc ] ], (UINT16)uiQuoteNum ); } SetFactFalse( FACT_MERC_SAY_QUOTE_WHEN_TALK_MENU_CLOSES ); } void CheckForValidQuotesWhenLeavingDealer( UINT8 ubProfile ) { //if the user is going to the dealer if( gTalkPanel.bCurSelect != -1 && ubTalkMenuApproachIDs[ gTalkPanel.bCurSelect ] == APPROACH_BUYSELL ) { return; } //if their scripting event going on, leave if( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) { return; } if( CheckFact( FACT_MERC_SAY_QUOTE_WHEN_TALK_MENU_CLOSES, 0 ) ) { if ( ubProfile == BETTY_UB ) HaveQualifiedMercSayQuoteAboutNpcWhenLeavingTalkScreen( ubProfile, QUOTE_JOINING_CAUSE_BUDDY_1_ON_TEAM ); else if ( ubProfile == RAUL_UB ) { //if the Raul is about to blow himself up if( !IsJa25GeneralFlagSet( JA_GF__RAUL_BLOW_HIMSELF_UP ) ) { //we can say the quote HaveQualifiedMercSayQuoteAboutNpcWhenLeavingTalkScreen( ubProfile, QUOTE_JOINING_CAUSE_BUDDY_2_ON_TEAM ); } } else if ( ubProfile == RUDY_UB ) HaveQualifiedMercSayQuoteAboutNpcWhenLeavingTalkScreen( ubProfile, QUOTE_REFUSAL_RENEW_DUE_TO_MORALE ); } } // This function checks if we should replace the mine entrance graphic BOOLEAN IsMineEntranceInSectorI13AtThisGridNo( UINT32 sGridNo ) { // First check current sector...... I13 if( gWorldSectorX == gGameUBOptions.MineSectorX && gWorldSectorY == gGameUBOptions.MineSectorY && gbWorldSectorZ == gGameUBOptions.MineSectorZ ) { //if this is the right gridno if( sGridNo == gGameUBOptions.MineEntranceGridno ) { return( TRUE ); } } return( FALSE ); } void HaveBiggensDetonatingExplosivesByTheMine() { SOLDIERTYPE *pSoldier = NULL; SoldierID ubID = NOBODY; pSoldier = FindSoldierByProfileID( BIGGENS_UB , FALSE ); //BIGGENS if( pSoldier != NULL ) { ubID = pSoldier->ubID; } //Have Biggens Triger the bombs by the cave wall SetOffBombsByFrequency( ubID, FIRST_MAP_PLACED_FREQUENCY + 1 ); } void ReplaceMineEntranceGraphicWithCollapsedEntrance() { UINT16 usTileIndex; UINT32 usGridNo = gGameUBOptions.MineGridnoAddStructToHead; //12745; //Make sure wed ont blow things up twice //off if( gJa25SaveStruct.fBiggensUsedDetonator ) return; //Remeber that biggens detonated the explosives gJa25SaveStruct.fBiggensUsedDetonator = TRUE; // Turn on permenant changes.... ApplyMapChangesToMapTempFile( TRUE ); // Remove it! // Get index for it... GetTileIndexFromTypeSubIndex( FIRSTOSTRUCT, (INT8)( 1 ), &usTileIndex ); AddStructToHead( usGridNo, usTileIndex ); //remove the exit grid from the world RemoveExitGridFromWorld( gGameUBOptions.MineRemoveExitGridFromWorld1 ); RemoveExitGridFromWorld( gGameUBOptions.MineRemoveExitGridFromWorld2 ); AddRemoveExitGridToUnloadedMapTempFile( gGameUBOptions.MineRemoveExitGridFromWorld1 , gGameUBOptions.MineSectorX, gGameUBOptions.MineSectorY, gGameUBOptions.MineSectorZ ); //I13 AddRemoveExitGridToUnloadedMapTempFile( gGameUBOptions.MineRemoveExitGridFromWorld2 , gGameUBOptions.MineSectorX, gGameUBOptions.MineSectorY, gGameUBOptions.MineSectorZ ); //I13 gpWorldLevelData[ usGridNo ].uiFlags |= MAPELEMENT_REVEALED; // Re-render the world! gTacticalStatus.uiFlags |= NOHIDE_REDUNDENCY; // FOR THE NEXT RENDER LOOP, RE-EVALUATE REDUNDENT TILES InvalidateWorldRedundency( ); SetRenderFlags(RENDER_FLAG_FULL); // Redo movement costs.... RecompileLocalMovementCostsFromRadius( usGridNo, 5 ); // // Apply changes to the underground mine // //Remove the old tunnel pieces first //First half of entrance usGridNo = gGameUBOptions.MineSectorUndergroundGridno1; //13057; // Get index for it... GetTileIndexFromTypeSubIndex( FIRSTDECORATIONS, (INT8)( 1 ), &usTileIndex ); RemoveStructFromUnLoadedMapTempFile( usGridNo, usTileIndex,gGameUBOptions.MineSectorUndergroundX, gGameUBOptions.MineSectorUndergroundY, gGameUBOptions.MineSectorUndergroundZ ); // Get index for it... GetTileIndexFromTypeSubIndex( FIRSTDECORATIONS, (INT8)( 5 ), &usTileIndex ); //Apply changes AddStructToUnLoadedMapTempFile( usGridNo, usTileIndex, gGameUBOptions.MineSectorUndergroundX, gGameUBOptions.MineSectorUndergroundY, gGameUBOptions.MineSectorUndergroundZ ); // 2nd half of entrance usGridNo = gGameUBOptions.MineSectorUndergroundGridno2; //12897; // Get index for it... GetTileIndexFromTypeSubIndex( FIRSTDECORATIONS, (INT8)( 2 ), &usTileIndex ); RemoveStructFromUnLoadedMapTempFile(usGridNo, usTileIndex, gGameUBOptions.MineSectorUndergroundX, gGameUBOptions.MineSectorUndergroundY, gGameUBOptions.MineSectorUndergroundZ); // Get index for it... GetTileIndexFromTypeSubIndex( FIRSTDECORATIONS, (INT8)( 6 ), &usTileIndex ); //Apply changes AddStructToUnLoadedMapTempFile(usGridNo, usTileIndex, gGameUBOptions.MineSectorUndergroundX, gGameUBOptions.MineSectorUndergroundY, gGameUBOptions.MineSectorUndergroundZ); //Remove the exit grid AddRemoveExitGridToUnloadedMapTempFile(usGridNo, gGameUBOptions.MineSectorUndergroundX, gGameUBOptions.MineSectorUndergroundY, gGameUBOptions.MineSectorUndergroundZ); // Turn off permenant changes.... ApplyMapChangesToMapTempFile( FALSE ); } void HandleCannotAffordNpcMsgBox() { // CHAR16 zString[512]; if( !gfDisplayMsgBoxSayingCantAffordNPC ) { return; } //display a msg box saying cant afford merc // swprintf( zString, zNewTacticalMessages[ TACT_MSG__CANNOT_AFFORD_MERC ], gMercProfiles[ 61 ].zNickname ); //BIGGENS // DoMessageBox( MSG_BOX_BASIC_STYLE, zString, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_OK, CantAffordMercCallback, NULL ); gfDisplayMsgBoxSayingCantAffordNPC = FALSE; } void CantAffordMercCallback( UINT8 ubExitValue ) { //Make the RPC say a quote TriggerNPCRecord( BIGGENS_UB, 0 ); //BIGGENS } void HandleMercArrivesQuotesFromHeliCrashSequence() { UINT32 uiCnt; SOLDIERTYPE *pSoldier=NULL; uiCnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // look for all mercs on the same team, for ( pSoldier = MercPtrs[ uiCnt ]; uiCnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; uiCnt++,pSoldier++) { if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE && pSoldier->bInSector ) { HandleMercArrivesQuotes( pSoldier ); } } } void HandleRaulBlowingHimselfUp() { SOLDIERTYPE *pSoldier=NULL; UINT16 usItem=0; //Find Raul pSoldier = FindSoldierByProfileID( RAUL_UB, FALSE ); //if he exists if( pSoldier ) { //First lower his life, artificially pSoldier->stats.bLife = 5; //blow himself up with, hmmm, lets say TNT. :) usItem = HAND_GRENADE; INT16 sX, sY; ConvertGridNoToCenterCellXY(pSoldier->sGridNo, &sX, &sY); IgniteExplosion( pSoldier->ubID, sX, sY, 0, pSoldier->sGridNo, usItem, pSoldier->pathing.bLevel ); SetJa25GeneralFlag( JA_GF__RAUL_BLOW_HIMSELF_UP ); } } void HandleTexFlushingToilet() { PlayJA2SampleFromFile( "SOUNDS\\ToiletFlush.wav", RATE_11025, HIGHVOLUME, 1, MIDDLE ); } void HandleTexMakingHimselfAlreadyBeIntroduced() { gMercProfiles[ TEX_UB ].ubLastDateSpokenTo = GetWorldDay( ); } void HandleTexBecomingCamoed() { SOLDIERTYPE *pSoldier=NULL; //Find TEX pSoldier = FindSoldierByProfileID( TEX_UB, FALSE ); //if we found him if( pSoldier != NULL ) { //make him camoed pSoldier->bCamo = gGameExternalOptions.bCamoKitArea; // 100 pSoldier->CreateSoldierPalettes( ); } //Then set him to be camo'ed in the profile ( cause he is still an RPC and we are just about to hire him ) // SANDRO - old/new traits check (I am not sure if this is used at all) if ( gGameOptions.fNewTraitSystem ) { gMercProfiles[ TEX_UB ].bSkillTraits[0] = RANGER_NT; } else { gMercProfiles[ TEX_UB ].bSkillTraits[0] = CAMOUFLAGED_OT; } //Close down the talking menu... DeleteTalkingMenu( ); // InitTalkingMenu( pSoldier->ubProfile, pSoldier->sGridNo ); // Trigger Tex to say the quote, this will cause the radio locater to come up giving a pause to make it appear that he // put on camoflauge TriggerNPCRecord( TEX_UB, 15 ); } void DisplayJerryBreakingLaptopTransmitterPopup() { CHAR16 zString[512]; INT8 bID=-1; UINT32 uiStartLoc=0; #define LANGMESSAGEFILE "BinaryData\\TacticalMessages.EDT" #define EDT_SIZE 400 * 2 if( gJa25SaveStruct.fJerryBreakingLaptopOccuring ) { return; } //get a random ID for a mercs name bID = RandomSoldierIdForAnyMercInSector(); if( bID == -1 ) { //Assert( 0 ); return; } /* if ( FileExists(LANGMESSAGEFILE) ) { uiStartLoc = EDT_SIZE * 10; LoadEncryptedDataFromFile(LANGMESSAGEFILE, sText, uiStartLoc, EDT_SIZE); swprintf( zString, sText, Menptr[ bID ].name ); } else { //Create the string swprintf( zString, zNewTacticalMessages[ TCTL_MSG__JERRY_BREAKIN_LAPTOP_ANTENA ], Menptr[ bID ].name ); } */ #ifdef UBMODSHADYJOB //See file builddefines.h swprintf( zString, XMLTacticalMessages[0] ); //Shady Job #else swprintf( zString, zNewTacticalMessages[TCTL_MSG__JERRY_BREAKIN_LAPTOP_ANTENA], Menptr[ bID ].name ); //UB #endif //Display it ExecuteTacticalTextBox( 110, zString ); gJa25SaveStruct.fJerryBreakingLaptopOccuring = TRUE; } void HaveNpcOpenUpDealerScreen( UINT8 ubProfileID ) { DeleteTalkingMenu( ); //Enter the shopkeeper interface EnterShopKeeperInterfaceScreen( gTalkPanel.ubCharNum ); } #endif