Files
gtav-src/script/dev_ng/singleplayer/scripts/commscontrol/comms_controller.sc
T
2025-09-29 00:52:08 +02:00

1915 lines
89 KiB
Python
Executable File

//
// Communication Controller Main Script
//
//
// AUTHOR: Ben Rollinson
// DATE: 12/10/10
// DESCRIPTION: A system used to control off-mission communications
// between characters in the game.
//
// -Handles phone communications from characters to the player.
// -Controls the frequency of communications with the player.
// -Controls the frequency of communications from each character.
// -Prioritises all incoming communications to the player.
// -Intercepts calls from the player to characters.
//
//
USING "rage_builtins.sch"
USING "globals.sch"
USING "code_control_public.sch"
USING "comms_control_private.sch"
USING "comms_control_data_GTA5.sch"
USING "code_control_data_GTA5.sch"
USING "cellphone_public.sch"
USING "vehicle_gen_public.sch"
USING "ply_to_ply_calls.sch"
//
// System Variables
//
BOOL bCommunicationMade // Has a communication been activated this frame?
BOOL bFirstCallOngoingHelpQueued
BOOL bDoCallBranch = FALSE
BOOL bWaitForForceAwayFlagToClear = FALSE
INT iTimeCallInitialisationStarted = -1
INT iDialBlimpState // Controls blimp delivery (preorder bonus unlocked after landing on the blimp)
BOOL bCBActive = FALSE
INT iCBState = -1 // Controls the state of the CB radio controller
INT iCBCheckTimer // Stores the last time we checked the CB radio controller
INT iCBIdentWaitTimer // Stores the last time we played an Ident type of CB conversation
INT iCBMonConvWaitTimer // Stores the last time we played a Monologue or Conversation type of CB conversation
INT iSoundID = -1 // Used to stop the background loop noise for the CB radio
ENUM CommsControllerState
CCS_LOOKING_FOR_COMM,
CCS_INITIALISING_COMM,
CCS_COMM_IN_PROGRESS
ENDENUM
#IF IS_DEBUG_BUILD
WIDGET_GROUP_ID widgetID
BOOL bDoMonologue
BOOL bDoOneLine
BOOL bDoConv
BOOL bFireTestEmails = FALSE
INT iForceDebugConv = -1
#ENDIF
CommsControllerState eState = CCS_LOOKING_FOR_COMM
structPedsForConversation convoStruct
//
// System Cleanup
//
// PURPOSE: Ensures that the script gets a chance to cleanup under specific circumstances (ie: moving from SP to MP)
PROC Script_Cleanup()
CPRINTLN(DEBUG_COMMUNICATIONS, "Comms controller cleaning up.")
g_iCallInProgress = -1
CC_CallData sBlankCallData
INT index
REPEAT g_savedGlobals.sCommsControlData.iNoMissedCalls index
CPRINTLN(DEBUG_COMMUNICATIONS, "SCRIPT CLEANUP: Removing call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.eID), " from the missed call queue.")
//Clear the missed caller status of the missed call contact.
CLEAR_MISSED_CALLER_STATUS_FOR_CONTACT(g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.eNPCCharacter)
//Move all array positions up one place and overwrite the call we want to remove.
INT index2
FOR index2 = index TO (g_savedGlobals.sCommsControlData.iNoMissedCalls-2)
g_savedGlobals.sCommsControlData.sMissedCalls[index2] = g_savedGlobals.sCommsControlData.sMissedCalls[index2+1]
ENDFOR
//Set the old last missed call in the queue to be blank data to be safe.
g_savedGlobals.sCommsControlData.sMissedCalls[g_savedGlobals.sCommsControlData.iNoMissedCalls-1] = sBlankCallData
//Reduce the counter tracking the number of missed calls in the queue.
g_savedGlobals.sCommsControlData.iNoMissedCalls--
ENDREPEAT
//Currently nothing to clean up.
TERMINATE_THIS_THREAD()
ENDPROC
//
// System Subfunctions
//
PROC Pause_Timers()
INT index
INT iFrameTime = CEIL(GET_FRAME_TIME()*1000)
//Extend global timer
g_iGlobalWaitTime += iFrameTime
//Extend queued call timers.
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedCalls index
g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iQueueTime += iFrameTime
ENDREPEAT
//Extend queued text message timers.
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedTexts index
g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.iQueueTime += iFrameTime
ENDREPEAT
//Extend queued email timers.
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedEmails index
g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.iQueueTime += iFrameTime
ENDREPEAT
//Extend queued chat call timers.
REPEAT g_savedGlobals.sCommsControlData.iNoChatCalls index
g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.iQueueTime += iFrameTime
ENDREPEAT
//Extend character timers.
INT iMaxCharacter = ENUM_TO_INT(GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE())
REPEAT iMaxCharacter index
g_iCharWaitTime[index] += iFrameTime
ENDREPEAT
ENDPROC
PROC Execute_Special_Code_For_Communication(CC_CommData &sCommData)
CPRINTLN(DEBUG_COMMUNICATIONS, "Checking for CodeID to run for communication ", GET_COMM_ID_DEBUG_STRING(sCommData.eID), "...")
//Double check we don't have an invalid CID set.
IF sCommData.eExecuteOnCompleteID = CID_MAX
SCRIPT_ASSERT("Execute_Special_Code_For_Communication: A communication had a CodeID of CID_MAX set. This is an invalid CodeID and should be guarded against!")
EXIT
ENDIF
//Add contact to character phonebooks if requested.
IF IS_BIT_SET(sCommData.iSettings, COMM_BIT_ADD_CONTACT)
INT iPlayerIndex
REPEAT 3 iPlayerIndex
IF IS_BIT_SET(sCommData.iPlayerCharBitset, iPlayerIndex)
CPRINTLN(DEBUG_COMMUNICATIONS, "Adding contact ", GET_CHARSHEET_DISPLAY_STRING_FROM_CHARSHEET(sCommData.eNPCCharacter),
" to ", GET_CHARSHEET_DISPLAY_STRING_FROM_CHARSHEET(INT_TO_ENUM(enumCharacterList, iPlayerIndex)),
"'s phonebook as communication ", GET_COMM_ID_DEBUG_STRING(sCommData.eID), " sends.")
ADD_CONTACT_TO_PHONEBOOK(sCommData.eNPCCharacter, INT_TO_ENUM(enumPhoneBookPresence, iPlayerIndex), FALSE)
ENDIF
ENDREPEAT
ENDIF
//Check if the CID has been set to something of meaning.
IF sCommData.eExecuteOnCompleteID <> CID_BLANK
//Tell code controller to execute CID without a delay.
CPRINTLN(DEBUG_COMMUNICATIONS, "Running ", Get_Debug_String_For_Communication_Code_ID(sCommData.eExecuteOnCompleteID), " with no delay.")
Execute_Code_ID(sCommData.eExecuteOnCompleteID)
EXIT
ENDIF
CPRINTLN(DEBUG_COMMUNICATIONS, "No CodeID found.")
ENDPROC
PROC Process_Cleanup_Of_Sent_Text(INT &gameTime, CC_TextMessageData &sentText)
//Execute any special code assigned to this text.
Execute_Special_Code_For_Communication(sentText.sCommData)
//Register this as the last completed text message.
g_savedGlobals.sCommsControlData.eLastCompletedText = sentText.sCommData.eID
//Update the system's global wait time.
g_iGlobalWaitTime = gameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
//Update the sending character's wait time.
g_iCharWaitTime[sentText.sCommData.eNPCCharacter] = gameTime + CC_CHARACTER_DELAY_BETWEEN_COMMS
//Remove text from sent text queue.
PRIVATE_Remove_Text_From_Sent_Queue(sentText.sCommData.eID)
ENDPROC
PROC Process_Cleanup_Of_Sent_Email(INT &gameTime, CC_EmailData &sentEmail)
//Execute any special code assigned to this text.
Execute_Special_Code_For_Communication(sentEmail.sCommData)
//Register this as the last completed text message.
g_savedGlobals.sCommsControlData.eLastCompletedEmail = sentEmail.sCommData.eID
//Update the system's global wait time.
g_iGlobalWaitTime = gameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
//Update the sending character's wait time.
IF sentEmail.sCommData.eNPCCharacter != CHAR_BLANK_ENTRY
g_iCharWaitTime[sentEmail.sCommData.eNPCCharacter] = gameTime + CC_CHARACTER_DELAY_BETWEEN_COMMS
ENDIF
ENDPROC
PROC Check_For_Queued_Phonecall_To_Player_To_Run(INT &gameTime)
// Ensure we are a playable character
IF NOT IS_PLAYER_PED_PLAYABLE(GET_CURRENT_PLAYER_PED_ENUM())
EXIT
ENDIF
INT index = 0
WHILE (index < g_savedGlobals.sCommsControlData.iNoQueuedCalls) AND NOT bCommunicationMade
Run_Call_Timer_Safeguard(g_savedGlobals.sCommsControlData.sQueuedCalls[index])
//Is this call going to a playable character?
IF NOT IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iSettings, COMM_BIT_FROM_CHAR_IS_PLAYER)
//Check if the priority of this call is high enough to override character and global timers.
BOOL bPriorityTimerOverride = FALSE
IF ENUM_TO_INT(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.ePriority) >= ENUM_TO_INT(CPR_VERY_HIGH)
bPriorityTimerOverride = TRUE
ENDIF
//Is the global wait timer at 0?
IF gameTime >= g_iGlobalWaitTime
OR bPriorityTimerOverride
OR IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iSettings, COMM_BIT_INGORE_GLOBAL_DELAY)
//Is this queued phonecall the correct priority?
IF g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.ePriority = g_savedGlobals.sCommsControlData.eCharacterPriorityLevel[GET_CURRENT_PLAYER_PED_ENUM()]
OR NOT IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iPlayerCharBitset, GET_CURRENT_PLAYER_PED_INT())
//Are the characters involved in this call waiting for timers?
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eNPCCharacter]
OR bPriorityTimerOverride
//Is this queued call ready to be triggered?
IF gameTime >= g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iQueueTime
//Attempt to make the call.
IF PRIVATE_Attempt_Make_Queued_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[index], bDoCallBranch)
//Register a call in progress.
g_iCallInProgress = index
iTimeCallInitialisationStarted = -1
eState = CCS_INITIALISING_COMM
g_savedGlobals.sCommsControlData.bLastCallHadResponse = FALSE
bCommunicationMade = TRUE
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = TRUE
ENDIF
ELSE
//Call failed to start. Reschedule the call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eID), " failed to start. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
index++
ENDWHILE
ENDPROC
PROC Check_For_Queued_Phonecall_From_Player_To_Run(INT &gameTime)
// Ensure we are a playable character
IF NOT IS_PLAYER_PED_PLAYABLE(GET_CURRENT_PLAYER_PED_ENUM())
EXIT
ENDIF
INT index = 0
WHILE (index < g_savedGlobals.sCommsControlData.iNoQueuedCalls) AND NOT bCommunicationMade
Run_Call_Timer_Safeguard(g_savedGlobals.sCommsControlData.sQueuedCalls[index])
//Is this call coming from a playable character?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iSettings, COMM_BIT_FROM_CHAR_IS_PLAYER)
//Check if the priority of this call is high enough to override character and global timers.
BOOL bPriorityTimerOverride = FALSE
IF ENUM_TO_INT(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.ePriority) >= ENUM_TO_INT(CPR_VERY_HIGH)
bPriorityTimerOverride = TRUE
ENDIF
//Is the global wait timer at 0?
IF gameTime >= g_iGlobalWaitTime
OR IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iSettings, COMM_BIT_INGORE_GLOBAL_DELAY)
OR bPriorityTimerOverride
//Is this queued phonecall the correct priority?
IF g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.ePriority = g_savedGlobals.sCommsControlData.eCharacterPriorityLevel[GET_CURRENT_PLAYER_PED_ENUM()]
OR NOT IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iPlayerCharBitset, GET_CURRENT_PLAYER_PED_INT())
//Is this queued call ready to be triggered?
IF gameTime >= g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iQueueTime
//Attempt to make the call.
IF PRIVATE_Attempt_Make_Queued_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[index], bDoCallBranch)
//Register a call in progress.
g_iCallInProgress = index
iTimeCallInitialisationStarted = -1
eState = CCS_INITIALISING_COMM
g_savedGlobals.sCommsControlData.bLastCallHadResponse = FALSE
bCommunicationMade = TRUE
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = TRUE
ENDIF
ELSE
//Call failed to start. Reschedule the call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eID), " failed to start. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
index++
ENDWHILE
ENDPROC
PROC Check_For_Queued_Text_Message_To_Run(INT &gameTime)
// Ensure we are a playable character
IF NOT IS_PLAYER_PED_PLAYABLE(GET_CURRENT_PLAYER_PED_ENUM())
EXIT
ENDIF
INT index = 0
WHILE (index < g_savedGlobals.sCommsControlData.iNoQueuedTexts) AND NOT bCommunicationMade
Run_Text_Timer_Safeguard(g_savedGlobals.sCommsControlData.sQueuedTexts[index])
//Check if the priority of this text is high enough to override character and global timers.
BOOL bPriorityTimerOverride = FALSE
IF ENUM_TO_INT(g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.ePriority) >= ENUM_TO_INT(CPR_VERY_HIGH)
bPriorityTimerOverride = TRUE
ENDIF
//Is the global wait timer at 0?
IF gameTime >= g_iGlobalWaitTime
OR IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.iSettings, COMM_BIT_INGORE_GLOBAL_DELAY)
OR bPriorityTimerOverride
//Are the characters involved in this text waiting for timers?
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.eNPCCharacter]
OR bPriorityTimerOverride
//Is this queued text ready to be triggered?
IF gameTime >= g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.iQueueTime
//Attempt to send the text.
IF PRIVATE_Attempt_Send_Queued_Text_Message(g_savedGlobals.sCommsControlData.sQueuedTexts[index])
//Add a copy of the text message that we've just sent to the sent text queue.
PRIVATE_Add_Text_To_Sent_Text_Queue(g_savedGlobals.sCommsControlData.sQueuedTexts[index])
//Tell the communication controller that we're waiting for a response.
g_savedGlobals.sCommsControlData.bLastTextHadResponse = FALSE
//Remove text entry from queue.
PRIVATE_Remove_Text_From_Queue(index)
bCommunicationMade = TRUE
ELSE
//Text message failed. Reschedule the text message.
CPRINTLN(DEBUG_COMMUNICATIONS, "Text ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.eID), " failed to send. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
index++
ENDWHILE
ENDPROC
PROC Check_For_Quick_Calls_To_Run(INT &gameTime)
INT index
//Check if there are any quick calls to run.
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedCalls index
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.iSettings, COMM_BIT_CALL_IS_QUICK)
IF IS_CALLING_CONTACT(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eNPCCharacter)
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eNPCCharacter]
//Attempt to make the quick call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Attempting to make outgoing quick call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eID), ".")
IF PRIVATE_Attempt_Make_Outgoing_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[index], bDoCallBranch)
//Register a call in progress.
g_iCallInProgress = index
iTimeCallInitialisationStarted = -1
eState = CCS_INITIALISING_COMM
g_savedGlobals.sCommsControlData.bLastCallHadResponse = FALSE
bCommunicationMade = TRUE
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = TRUE
ENDIF
ELSE
//Call failed to start. Reschedule the call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Quick call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eID), " failed to start. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData)
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC Check_For_Missed_Calls_To_Run(INT &gameTime)
INT index
//Check if there are any missed calls queued to run.
REPEAT g_savedGlobals.sCommsControlData.iNoMissedCalls index
IF IS_CALLING_CONTACT(g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.eNPCCharacter)
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.eNPCCharacter]
//Try and get the missed call queue index.
INT iQueueIndex = PRIVATE_Get_Missed_Call_Queue_Index(g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.eID)
//Call not in the queue. Add it.
IF iQueueIndex = -1
iQueueIndex = g_savedGlobals.sCommsControlData.iNoQueuedCalls
g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex] = g_savedGlobals.sCommsControlData.sMissedCalls[index]
g_savedGlobals.sCommsControlData.iNoQueuedCalls++
//Update character queue priority levels in case this new call is the new highest priority communication.
INT iPlayerIndex
REPEAT 3 iPlayerIndex
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sMissedCalls[index].sCommData.iPlayerCharBitset, iPlayerIndex)
PRIVATE_Update_Playable_Character_Priority_Level(INT_TO_ENUM(enumCharacterList, iPlayerIndex))
ENDIF
ENDREPEAT
ENDIF
//Attempt to make the missed call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Attempting to make outgoing missed call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData.eID), ".")
IF PRIVATE_Attempt_Make_Outgoing_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex], bDoCallBranch)
//Register a call in progress.
g_iCallInProgress = index
iTimeCallInitialisationStarted = -1
eState = CCS_INITIALISING_COMM
g_savedGlobals.sCommsControlData.bLastCallHadResponse = FALSE
bCommunicationMade = TRUE
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = TRUE
ENDIF
ELSE
//Call failed to start. Reschedule the call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Missed call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData.eID), " failed to start. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData)
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC Check_For_Chat_Calls_To_Run(INT &gameTime)
INT index
//Check if there are any chat calls to run.
REPEAT g_savedGlobals.sCommsControlData.iNoChatCalls index
enumCharacterList ePlayer = GET_CURRENT_PLAYER_PED_ENUM()
IF IS_PLAYER_PED_PLAYABLE(ePlayer)
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.iPlayerCharBitset, ENUM_TO_INT(ePlayer))
IF IS_CALLING_CONTACT(g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.eNPCCharacter)
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.eNPCCharacter]
//Chat call should be able to run. Check if we have it in the main queue yet.
BOOL bAlreadyQueued = FALSE
INT iQueueIndex = 0
WHILE (iQueueIndex < g_savedGlobals.sCommsControlData.iNoQueuedCalls) AND NOT bAlreadyQueued
IF g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData.eID = g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.eID
CPRINTLN(DEBUG_COMMUNICATIONS, "Chat call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.eID), " already in main queue.")
bAlreadyQueued = TRUE
ENDIF
iQueueIndex++
ENDWHILE
//Add the chat call to the main communication queue.
IF NOT bAlreadyQueued
CPRINTLN(DEBUG_COMMUNICATIONS, "Player is calling contact for chat call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sChatCalls[index].sCommData.eID), ". Adding to main call queue.")
iQueueIndex = g_savedGlobals.sCommsControlData.iNoQueuedCalls
IF iQueueIndex < CC_MAX_QUEUED_CALLS
g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex] = g_savedGlobals.sCommsControlData.sChatCalls[index]
g_savedGlobals.sCommsControlData.iNoQueuedCalls++
//Update character queue priority levels in case this new call is the new highest priority communication.
INT iPlayerIndex
REPEAT 3 iPlayerIndex
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData.iPlayerCharBitset, iPlayerIndex)
PRIVATE_Update_Playable_Character_Priority_Level(INT_TO_ENUM(enumCharacterList, iPlayerIndex))
ENDIF
ENDREPEAT
ELSE
SCRIPT_ASSERT("Check_For_Chat_Calls_To_Run: Tried to add a chat call to the main queue, but it was full. Bug BenR.")
EXIT
ENDIF
ENDIF
//Attempt to make the chat call.
CPRINTLN(DEBUG_COMMUNICATIONS, "Attempting to make outgoing chat call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex].sCommData.eID), ".")
IF PRIVATE_Attempt_Make_Outgoing_Chat_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[iQueueIndex])
//Register a call in progress.
g_iCallInProgress = iQueueIndex
iTimeCallInitialisationStarted = -1
eState = CCS_INITIALISING_COMM
g_savedGlobals.sCommsControlData.bLastCallHadResponse = FALSE
bCommunicationMade = TRUE
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = TRUE
ENDIF
ELSE
//Call failed to start. Remove chat call from the main queue.
CPRINTLN(DEBUG_COMMUNICATIONS, "Chat call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sChatCalls[iQueueIndex].sCommData.eID), " failed to start.")
PRIVATE_Remove_Call_From_Queue(iQueueIndex)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC Check_For_Queued_Email_To_Run(INT &gameTime)
// Ensure we are a playable character
IF NOT IS_PLAYER_PED_PLAYABLE(GET_CURRENT_PLAYER_PED_ENUM())
EXIT
ENDIF
INT index = 0
WHILE (index < g_savedGlobals.sCommsControlData.iNoQueuedEmails) AND NOT bCommunicationMade
Run_Email_Timer_Safeguard(g_savedGlobals.sCommsControlData.sQueuedEmails[index])
//Check if the priority of this text is high enough to override character and global timers.
BOOL bPriorityTimerOverride = FALSE
IF ENUM_TO_INT(g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.ePriority) >= ENUM_TO_INT(CPR_VERY_HIGH)
bPriorityTimerOverride = TRUE
ENDIF
//Is the global wait timer at 0?
IF gameTime >= g_iGlobalWaitTime
OR IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.iSettings, COMM_BIT_INGORE_GLOBAL_DELAY)
OR bPriorityTimerOverride
//Are the characters involved in this call waiting for timers?
IF gameTime >= g_iCharWaitTime[g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.eNPCCharacter]
OR bPriorityTimerOverride
//Is this queued text ready to be triggered?
IF gameTime >= g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.iQueueTime
//Attempt to send the text.
IF PRIVATE_Attempt_Send_Queued_Email(g_savedGlobals.sCommsControlData.sQueuedEmails[index])
//Remove text entry from queue.
iTimeCallInitialisationStarted = -1
Process_Cleanup_Of_Sent_Email(gameTime, g_savedGlobals.sCommsControlData.sQueuedEmails[index])
PRIVATE_Remove_Email_From_Queue(index)
bCommunicationMade = TRUE
ELSE
//Email failed. Reschedule the email.
CPRINTLN(DEBUG_COMMUNICATIONS, "Email ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.eID), " failed to send. Rescheduling.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData)
ENDIF
ENDIF
ENDIF
ENDIF
index++
ENDWHILE
ENDPROC
/// PURPOSE:
/// Activate the closest blimp vehicle gen to the player
FUNC BOOL Activate_Closest_Blimp_Location()
IF IS_PED_INJURED(PLAYER_PED_ID())
RETURN FALSE
ENDIF
INT i
FLOAT fShortestDist = 99999.99
INT iClosestGen = -1
VECTOR vGenCoords[2]
VECTOR vPlayerCoords = GET_ENTITY_COORDS(PLAYER_PED_ID())
vGenCoords[0] = << 1133.21, 120.20, 80.9 >>
vGenCoords[1] = << -806.31, -2679.65, 13.9 >>
REPEAT 2 i
IF GET_DISTANCE_BETWEEN_COORDS(vPlayerCoords, vGenCoords[i]) < fShortestDist
fShortestDist = GET_DISTANCE_BETWEEN_COORDS(vPlayerCoords, vGenCoords[i])
iClosestGen = i
ENDIF
ENDREPEAT
CLEANUP_VEHICLE_GEN_VEHICLE(VEHGEN_BLIMP_CASINO)
CLEANUP_VEHICLE_GEN_VEHICLE(VEHGEN_BLIMP_DOCKS)
// B*1558610 - Swap gen if the player is within 250m of the blimp spawn position
IF IS_SPHERE_VISIBLE(vGenCoords[iClosestGen], 300) OR fShortestDist < 300
// Swap to Docks from Casino...
IF iClosestGen = 0
iClosestGen = 1
// ...or vice versa
ELSE
iClosestGen = 0
ENDIF
ENDIF
// Casino
IF iClosestGen = 0
SET_VEHICLE_GEN_AVAILABLE(VEHGEN_BLIMP_CASINO, TRUE)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_BLIMP_CASINO)
RETURN TRUE
// Docks
ELIF iClosestGen = 1
SET_VEHICLE_GEN_AVAILABLE(VEHGEN_BLIMP_DOCKS, TRUE)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_BLIMP_DOCKS)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Is_Blimp_Nearby()
VEHICLE_INDEX vehArray[15]
INT numberOfVehicles = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(),vehArray)
INT i
FOR i = 0 TO (numberOfVehicles - 1)
IF GET_ENTITY_MODEL(vehArray[i]) = BLIMP
IF NOT IS_ENTITY_DEAD(vehArray[i]) AND IS_VEHICLE_DRIVEABLE(vehArray[i])
RETURN TRUE
ENDIF
ENDIF
ENDFOR
RETURN FALSE
ENDFUNC
FUNC BOOL Is_Player_In_Blimp()
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(),TRUE)
IF GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE)) = BLIMP
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC Check_For_Ability_Calls_To_Run(INT &gameTime)
STRING sRootLabel[5]
// Dial a Blimp!
SWITCH iDialBlimpState
// Wait for player to call
CASE 0
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_CALLING_CONTACT(CHAR_BLIMP)
// Has preorder content
IF IS_PREORDER_GAME()
OR IS_COLLECTORS_EDITION_GAME()
OR IS_SPECIAL_EDITION_GAME()
OR IS_JAPANESE_SPECIAL_EDITION_GAME()
OR IS_LAST_GEN_PLAYER()
// Don't connect if a blimp already exists in the world
IF NOT DOES_ENTITY_EXIST(GET_VEHICLE_GEN_VEHICLE_INDEX(VEHGEN_BLIMP_CASINO))
AND NOT DOES_ENTITY_EXIST(GET_VEHICLE_GEN_VEHICLE_INDEX(VEHGEN_BLIMP_DOCKS))
//If the blip is called in a mission trigger we get an assert B*1868387
AND g_iOffMissionCutsceneRequestAllowed = NULL_OFFMISSION_CUTSCENE_REQUEST
AND NOT Is_Player_In_Blimp()
AND NOT Is_Blimp_Nearby()
// Michael
IF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_MICHAEL
ADD_PED_FOR_DIALOGUE(convoStruct, 0, PLAYER_PED_ID(), "MICHAEL")
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, "DBLIMPOperator")
sRootLabel[0] = "DAB_HELLO"
sRootLabel[1] = "DAB_MICHAEL"
sRootLabel[2] = "DAB_SEND"
sRootLabel[3] = "DAB_THANK_M"
sRootLabel[4] = "DAB_BYE"
// Franklin
ELIF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_FRANKLIN
ADD_PED_FOR_DIALOGUE(convoStruct, 1, PLAYER_PED_ID(), "FRANKLIN")
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, "DBLIMPOperator")
sRootLabel[0] = "DAB_HELLO"
sRootLabel[1] = "DAB_FRANKLIN"
sRootLabel[2] = "DAB_SEND"
sRootLabel[3] = "DAB_THANK_F"
sRootLabel[4] = "DAB_BYE"
// Trevor
ELIF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_TREVOR
ADD_PED_FOR_DIALOGUE(convoStruct, 2, PLAYER_PED_ID(), "TREVOR")
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, "DBLIMPOperator")
sRootLabel[0] = "DAB_HELLO"
sRootLabel[1] = "DAB_TREVOR"
sRootLabel[2] = "DAB_SEND"
sRootLabel[3] = "DAB_THANK_T"
sRootLabel[4] = "DAB_BYE"
ENDIF
// Attempt phonecall
CPRINTLN(DEBUG_COMMUNICATIONS, "Check_For_Ability_Calls_To_Run - Blimp - Initiating Call")
IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_N_LINES(5, convoStruct, CHAR_BLIMP, "BLIMPAU", sRootLabel, sRootLabel, CONV_PRIORITY_CELLPHONE)
CPRINTLN(DEBUG_COMMUNICATIONS, "Check_For_Ability_Calls_To_Run - blimp - Call in progess")
iDialBlimpState++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
// Wait for player to finish call
CASE 1
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF NOT IS_CALLING_CONTACT(CHAR_BLIMP) AND NOT IS_PHONE_ONSCREEN(TRUE)
g_iGlobalWaitTime = gameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
IF NOT IS_CELLPHONE_CONVERSATION_PLAYING()
CPRINTLN(DEBUG_COMMUNICATIONS, "Check_For_Ability_Calls_To_Run - Blimp - Call Completed")
/*
CPRINTLN(DEBUG_COMMUNICATIONS, "Waiting 15 Seconds for delivery")
iDialBlimpState++
*/
// Bypass delay for now
iDialBlimpState = 3
ENDIF
ELSE
//If the blip is called in a mission trigger we get an assert B*1868387
IF g_iOffMissionCutsceneRequestAllowed != NULL_OFFMISSION_CUTSCENE_REQUEST
CPRINTLN(DEBUG_COMMUNICATIONS, "Check_For_Ability_Calls_To_Run - a cutscene is being requested while ringing for a blimp")
HANG_UP_AND_PUT_AWAY_PHONE()
ENDIF
ENDIF
ENDIF
BREAK
// Wait some time for delivery
CASE 2
IF (GET_GAME_TIMER() > g_iGlobalWaitTime)
CPRINTLN(DEBUG_COMMUNICATIONS, "Check_For_Ability_Calls_To_Run - Blimp - Delay before Delivery Complete")
iDialBlimpState++
ENDIF
BREAK
// Activate suitable vehicle gen
CASE 3
// Get the nearest blimp location to the player
Activate_Closest_Blimp_Location()
iDialBlimpState = 0
BREAK
ENDSWITCH
ENDPROC
PROC Check_For_Any_Outgoing_Calls_To_Run(INT &gameTime)
IF IS_CALLING_ANY_CONTACT()
IF eState = CCS_LOOKING_FOR_COMM
Check_For_Quick_Calls_To_Run(gameTime)
ENDIF
IF eState = CCS_LOOKING_FOR_COMM
Check_For_Missed_Calls_To_Run(gameTime)
ENDIF
IF eState = CCS_LOOKING_FOR_COMM
Check_For_Chat_Calls_To_Run(gameTime)
ENDIF
ENDIF
// Keep this out the calling contact loop as we need
// to run some script when the call ends.
Check_For_Ability_Calls_To_Run(gameTime)
ENDPROC
PROC Update_Call_In_Progress_Responses()
//Does the call in progress have a question that needs responding to?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_HAS_QUESTION)
//Check if we need to display help text for making a decision on the phone.
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_FIRST_CALL_DECISION)
IF IS_CELLPHONE_CALL_WITH_REPLIES_WAITING_ON_USER_INPUT()
SWITCH g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID
CASE QCALL_ME_AMANDA
CASE QCALL_ME_JIMMY
CASE QCALL_ME_TRACEY
PRINT_HELP("AM_H_FDEC")
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_DECISION)
BREAK
ENDSWITCH
ENDIF
ENDIF
//Yes. Check for responses from the player.
IF NOT g_savedGlobals.sCommsControlData.bLastCallHadResponse
IF (CHECK_RESPONSE_TO_CELLPHONE_PROMPT() <> RESPONSE_STORE_EMPTY)
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FDEC")
CLEAR_HELP(FALSE)
ENDIF
IF (CHECK_RESPONSE_TO_CELLPHONE_PROMPT() = RESPONDED_YES)
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " received a YES response.")
g_savedGlobals.sCommsControlData.bLastCallResponse = TRUE
g_savedGlobals.sCommsControlData.bLastCallHadResponse = TRUE
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " received a NO response.")
IF g_iCommsCandidateID != NO_CANDIDATE_ID
Mission_Over(g_iCommsCandidateID)
Set_Leave_Area_Flag_For_All_Blipped_Missions()
CPRINTLN(DEBUG_COMMUNICATIONS, "Mission triggering call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " was rejected so cleaned-up mission candidate.")
CONST_FLOAT fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT 300.0
enumFriendConnection friendConnID
REPEAT MAX_FRIEND_CONNECTIONS friendConnID
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactType = FRIEND_CONTACT_PHONE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_FRIENDS, "RESTART_TIMER_AT(", GetLabel_enumFriendConnection(friendConnID), ", ", fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT, ")")
#ENDIF
RESTART_TIMER_AT(g_savedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer, fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT)
ENDIF
ENDREPEAT
ENDIF
g_savedGlobals.sCommsControlData.bLastCallResponse = FALSE
g_savedGlobals.sCommsControlData.bLastCallHadResponse = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
//If we've flagged to load dynamic dialogue for a branched call, load the correct branch here.
PROC Update_Branched_Call_Dialogue()
IF bDoCallBranch
FLOW_CHECK_IDS eBranchCheck = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eSendCheck
IF eBranchCheck != FLOW_CHECK_NONE
CPRINTLN(DEBUG_COMMUNICATIONS, "Running check ", GET_DEBUG_STRING_FOR_FLOW_CHECK_ID(eBranchCheck), " for ongoing branched call.")
//Grab dialogue details based on the flow check outcome.
CC_CommID eBranch
IF DO_CUSTOM_FLOW_CHECK(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eSendCheck)
CPRINTLN(DEBUG_COMMUNICATIONS, "Branched call loading the TRUE branch.")
eBranch = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].eCommExtra
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Branched call loading the FALSE branch.")
eBranch = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].eCommExtra2
ENDIF
IF eBranch != COMM_NONE
CC_CallStringData sCallStrings
PRIVATE_Get_Call_String_Data(eBranch, sCallStrings)
SET_DYNAMIC_BRANCH_FOR_ONGOING_CALL(sCallStrings.tBlock, sCallStrings.tConversation)
CPRINTLN(DEBUG_COMMUNICATIONS, "Branched call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " adding dynamic conversation ending ", GET_COMM_ID_DEBUG_STRING(eBranch), " to the call.")
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Branch for call was blank. No dynamic dialogue being added.")
ENDIF
ELSE
SCRIPT_ASSERT("Update_Branched_Call_Dialogue: Branched call did not have a valid branch check defined.")
ENDIF
bDoCallBranch = FALSE
ENDIF
ENDPROC
PROC Update_Call_Help()
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_FIRST_CALL_RINGING)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_1)
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_2)
IF IS_PHONE_ONSCREEN(TRUE)
IF g_iCallInProgress != -1
IF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID = CALL_ARM2_UNLOCK
or g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID = CALL_CARDMG_ARM2_UNLOCK
SWITCH GET_FLOW_HELP_MESSAGE_STATUS("AM_H_FCAL1")
CASE FHS_EXPIRED
ADD_HELP_TO_FLOW_QUEUE("AM_H_FCAL1", FHP_HIGH, 0, 1000, DEFAULT_GOD_TEXT_TIME)
BREAK
CASE FHS_DISPLAYED
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_RINGING)
BREAK
ENDSWITCH
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_FIRST_CALL_ONGOING)
IF NOT bFirstCallOngoingHelpQueued
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_1)
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_2)
IF IS_PHONE_ONSCREEN(TRUE)
IF g_iCallInProgress != -1
IF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID = CALL_ARM2_UNLOCK
or g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID = CALL_CARDMG_ARM2_UNLOCK
IF IS_CELLPHONE_CONVERSATION_PLAYING()
IF IS_FLOW_HELP_MESSAGE_QUEUED("AM_H_FCAL1")
REMOVE_HELP_FROM_FLOW_QUEUE("AM_H_FCAL1")
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL1")
CLEAR_HELP(FALSE)
ENDIF
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_RINGING)
ADD_HELP_TO_FLOW_QUEUE("AM_H_FCAL2", FHP_HIGH, 0, 1000, DEFAULT_GOD_TEXT_TIME)
bFirstCallOngoingHelpQueued = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
IF GET_FLOW_HELP_MESSAGE_STATUS("AM_H_FCAL2") = FHS_EXPIRED
bFirstCallOngoingHelpQueued = FALSE
ELIF GET_FLOW_HELP_MESSAGE_STATUS("AM_H_FCAL2") = FHS_DISPLAYED
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_ONGOING)
ENDIF
IF NOT IS_CELLPHONE_CONVERSATION_PLAYING()
REMOVE_HELP_FROM_FLOW_QUEUE("AM_H_FCAL2")
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL2")
CLEAR_HELP(FALSE)
ENDIF
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_ONGOING)
ENDIF
ENDIF
IF g_savedGlobals.sCommsControlData.eLastCompletedCall = CALL_ARM2_UNLOCK
or g_savedGlobals.sCommsControlData.eLastCompletedCall = CALL_CARDMG_ARM2_UNLOCK
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_ONGOING)
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_FIRST_CALL_RINGING)
IF IS_FLOW_HELP_MESSAGE_QUEUED("AM_H_FCAL1")
REMOVE_HELP_FROM_FLOW_QUEUE("AM_H_FCAL1")
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL1")
CLEAR_HELP(FALSE)
ENDIF
IF IS_FLOW_HELP_MESSAGE_QUEUED("AM_H_FCAL2")
REMOVE_HELP_FROM_FLOW_QUEUE("AM_H_FCAL2")
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL2")
CLEAR_HELP(FALSE)
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL Update_Secure_Mission_Candidate_For_Mission_Triggering_Call()
SWITCH Request_Mission_Launch(g_iCommsCandidateID, MCTID_PHONECALL_TO_PLAYER, MISSION_TYPE_STORY)
CASE MCRET_ACCEPTED
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " secured a candidate ID for mission that will trigger from this call.")
RETURN TRUE
BREAK
CASE MCRET_DENIED
CPRINTLN(DEBUG_COMMUNICATIONS, "Backing out of call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " because it couldn't secure a candidate ID.")
HANG_UP_AND_PUT_AWAY_PHONE()
BREAK
ENDSWITCH
CDEBUG1LN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " waiting to secure a candidate ID.")
RETURN FALSE
ENDFUNC
PROC Process_Early_Cancellation_Of_Call(INT &gameTime, BOOL bForceReqeue = FALSE)
CPRINTLN(DEBUG_COMMUNICATIONS, "Processing early cancellation of call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), ".")
HANG_UP_AND_PUT_AWAY_PHONE()
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL1")
CLEAR_HELP(FALSE)
ENDIF
//Do we need to clean up a temporary contact?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REMOVE_TEMP_CONTACT)
enumPhoneBookPresence ePhonebook
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL ePhonebook = MICHAEL_BOOK BREAK
CASE CHAR_FRANKLIN ePhonebook = FRANKLIN_BOOK BREAK
CASE CHAR_TREVOR ePhonebook = TREVOR_BOOK BREAK
ENDSWITCH
REMOVE_CONTACT_FROM_INDIVIDUAL_PHONEBOOK(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter, ePhonebook)
CLEAR_BIT(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REMOVE_TEMP_CONTACT)
CPRINTLN(DEBUG_COMMUNICATIONS, "Removing temporary contact for call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " was cancelled.")
ENDIF
//If the call has a question handle cleaning up its responses and adding unique character delays.
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_HAS_QUESTION)
IF NOT g_savedGlobals.sCommsControlData.bLastCallHadResponse
CPRINTLN(DEBUG_COMMUNICATIONS, "Backed out of call with question. Forcing requeue flag on and adding to missed call queue.")
SET_BIT(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REQUEUE_ON_MISS)
PRIVATE_Add_Call_To_Missed_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress])
IF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter = CHAR_AMANDA
Execute_Code_ID(CID_SET_LONG_AMANDA_TIMER)
ELIF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter = CHAR_JIMMY
Execute_Code_ID(CID_SET_LONG_JIMMY_TIMER)
ELIF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter = CHAR_TRACEY
Execute_Code_ID(CID_SET_LONG_TRACEY_TIMER)
ENDIF
ENDIF
ENDIF
IF g_iCommsCandidateID != NO_CANDIDATE_ID
Set_Leave_Area_Flag_For_All_Blipped_Missions()
Mission_Over(g_iCommsCandidateID)
CPRINTLN(DEBUG_COMMUNICATIONS, "Backed out of mission triggering call so cleaned-up mission candidate.")
CONST_FLOAT fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT 300.0
enumFriendConnection friendConnID
REPEAT MAX_FRIEND_CONNECTIONS friendConnID
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactType = FRIEND_CONTACT_PHONE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_FRIENDS, "RESTART_TIMER_AT(", GetLabel_enumFriendConnection(friendConnID), ", ", fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT, ")")
#ENDIF
RESTART_TIMER_AT(g_savedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer, fCONST_FRIEND_TIME_RESET_FOR_MISSION_BACKOUT)
ENDIF
ENDREPEAT
ENDIF
//Requeue if missed.
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REQUEUE_ON_MISS)
OR bForceReqeue
CPRINTLN(DEBUG_COMMUNICATIONS, "Executing call missed response for call: Requeuing.")
PRIVATE_Set_New_Communication_Queue_Time(gameTime, g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData)
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_TRIGGERS_MISSION)
IF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iRequeueTime < 300000
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iRequeueTime += 60000
CPRINTLN(DEBUG_COMMUNICATIONS, "Added 1 min to next requeue time of mission trigger communication ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), ".")
ENDIF
ENDIF
//Check if we should add the call to the missed call queue.
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_IS_MISSED)
PRIVATE_Add_Call_To_Missed_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress])
ENDIF
//Text if missed.
ELIF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_TEXT_ON_MISS)
CPRINTLN(DEBUG_COMMUNICATIONS, "Executing call missed response for call: Sending text message [", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].eCommExtra), "].")
REGISTER_TEXT_MESSAGE_FROM_CHARACTER_TO_PLAYER( g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].eCommExtra,
CT_FLOW,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iPlayerCharBitset,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iRequeueTime,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iRequeueTime,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eRestrictedAreaID,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eExecuteOnCompleteID,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eSendCheck,
g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings)
//Flag this call as the last completed call.
g_savedGlobals.sCommsControlData.eLastCompletedCall = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID
//Clear the last call answered flag.
g_savedGlobals.sCommsControlData.bLastCallAnswered = FALSE
PRIVATE_Remove_Call_From_Missed_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
PRIVATE_Remove_Call_From_Chat_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
PRIVATE_Remove_Call_From_Queue(g_iCallInProgress)
//Remove from queue if missed.
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Executing call missed response for call: Removing from queue.")
//Flag this call as the last completed call.
g_savedGlobals.sCommsControlData.eLastCompletedCall = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID
//Clear the last call answered flag.
g_savedGlobals.sCommsControlData.bLastCallAnswered = FALSE
PRIVATE_Remove_Call_From_Missed_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
PRIVATE_Remove_Call_From_Chat_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
PRIVATE_Remove_Call_From_Queue(g_iCallInProgress)
ENDIF
//Clean up the PedsForConversation struct.
PRIVATE_Clean_Up_Peds_For_Conversation_Struct()
g_iCallInProgress = -1
ENDPROC
PROC Update_Mission_Triggering_Calls_Safeguards(INT paramGameTime)
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_TRIGGERS_MISSION)
VectorID eRestrictedArea = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eRestrictedAreaID
IF eRestrictedArea != VID_BLANK
//If the player gets 2/3 of the way into the restricted area before the call finishes, end it early.
IF IS_PED_AT_VECTOR_ID( PLAYER_PED_ID(), eRestrictedArea, g_sVectorIDData[eRestrictedArea].radius * 0.35)
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " was cancelled early as the player got too close the a mission triggering restricted area.")
Process_Early_Cancellation_Of_Call(paramGameTime)
HANG_UP_AND_PUT_AWAY_PHONE()
eState = CCS_LOOKING_FOR_COMM
g_iGlobalWaitTime = paramGameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
ENDIF
ENDIF
ENDIF
ENDPROC
PROC Process_Termination_Of_Last_Call(INT &gameTime)
IF g_iCallInProgress != -1
//Was the call hung up before a required response was made?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_HAS_QUESTION) AND NOT g_savedGlobals.sCommsControlData.bLastCallHadResponse
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " ended before a response was made.")
Process_Early_Cancellation_Of_Call(gameTime)
//The call succeeded.
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " sucessfully completed.")
//Set the last call answered flag.
g_savedGlobals.sCommsControlData.bLastCallAnswered = TRUE
// Reset friend last-contact timer
PRIVATE_Update_Friend_Timer_Resets_For_Call(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter, GET_CURRENT_PLAYER_PED_ENUM())
//Clean up the PedsForConversation struct.
PRIVATE_Clean_Up_Peds_For_Conversation_Struct()
//Execute any special code assigned to this call.
Execute_Special_Code_For_Communication(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData)
//Register this as the last completed call.
g_savedGlobals.sCommsControlData.eLastCompletedCall = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID
//Update the system's global wait time.
g_iGlobalWaitTime = gameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
//Update the sending character's wait time.
g_iCharWaitTime[g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter] = gameTime + CC_CHARACTER_DELAY_BETWEEN_COMMS
//Remove call from missed call queue (if it's in it).
PRIVATE_Remove_Call_From_Missed_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
//Remove call from chat call queue (if it's in it).
PRIVATE_Remove_Call_From_Chat_Call_Queue(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID)
//Remove call entry from queue.
PRIVATE_Remove_Call_From_Queue(g_iCallInProgress)
//Do we need to clean up a temporary contact?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REMOVE_TEMP_CONTACT)
enumPhoneBookPresence ePhonebook
SWITCH GET_CURRENT_PLAYER_PED_ENUM()
CASE CHAR_MICHAEL ePhonebook = MICHAEL_BOOK BREAK
CASE CHAR_FRANKLIN ePhonebook = FRANKLIN_BOOK BREAK
CASE CHAR_TREVOR ePhonebook = TREVOR_BOOK BREAK
ENDSWITCH
REMOVE_CONTACT_FROM_INDIVIDUAL_PHONEBOOK(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eNPCCharacter, ePhonebook)
CLEAR_BIT(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_CALL_REMOVE_TEMP_CONTACT)
CPRINTLN(DEBUG_COMMUNICATIONS, "Removing temporary contact for call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " from player phonebook as call has finished.")
ENDIF
//Special case. Clear help when hanging up the first flow phonecall.
IF HAS_ONE_TIME_HELP_DISPLAYED(FHM_FIRST_CALL_ONGOING)
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_2)
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("AM_H_FCAL2")
CLEAR_HELP(FALSE)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
PROC Update_Sent_Text_Responses(INT &gameTime, CC_TextMessageData &sentText)
TEXT_LABEL tTextMessageLabel
PRIVATE_Get_Text_Message_Message_Label(sentText.sCommData.eID, tTextMessageLabel)
//Check the status of the text message that was sent.
SWITCH GET_TEXT_MESSAGE_REPLY_STATUS(tTextMessageLabel)
CASE NO_REPLY_REQUIRED
CPRINTLN(DEBUG_COMMUNICATIONS, "A response is not required for sent text ", GET_COMM_ID_DEBUG_STRING(sentText.sCommData.eID), ".")
g_savedGlobals.sCommsControlData.bLastTextHadResponse = FALSE
Process_Cleanup_Of_Sent_Text(gameTime, sentText)
BREAK
CASE REPLIED_YES
CPRINTLN(DEBUG_COMMUNICATIONS, "YES response received for sent text ", GET_COMM_ID_DEBUG_STRING(sentText.sCommData.eID), ".")
g_savedGlobals.sCommsControlData.bLastTextHadResponse = TRUE
g_savedGlobals.sCommsControlData.bLastTextResponse = TRUE
Process_Cleanup_Of_Sent_Text(gameTime, sentText)
BREAK
CASE REPLIED_NO
CPRINTLN(DEBUG_COMMUNICATIONS, "NO response received for sent text ", GET_COMM_ID_DEBUG_STRING(sentText.sCommData.eID), ".")
g_savedGlobals.sCommsControlData.bLastTextHadResponse = TRUE
g_savedGlobals.sCommsControlData.bLastTextResponse = FALSE
BREAK
//NB. If REPLY_REQUIRED then the text is not cleaned up and we will run this check again next frame.
ENDSWITCH
ENDPROC
DEBUGONLY PROC Debug_Draw_All_Queued_Comms_Restricted_Areas()
IF g_iCallInProgress = -1
//No call in progress. Render restricted area for queued communications.
INT index
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedCalls index
VectorID eRestrictedArea = g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eRestrictedAreaID
IF eRestrictedArea != VID_BLANK
DEBUG_DRAW_VECTOR_ID_AREA(eRestrictedArea, GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[index].sCommData.eID))
ENDIF
ENDREPEAT
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedTexts index
VectorID eRestrictedArea = g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.eRestrictedAreaID
IF eRestrictedArea != VID_BLANK
DEBUG_DRAW_VECTOR_ID_AREA(eRestrictedArea, GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedTexts[index].sCommData.eID))
ENDIF
ENDREPEAT
REPEAT g_savedGlobals.sCommsControlData.iNoQueuedEmails index
VectorID eRestrictedArea = g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.eRestrictedAreaID
IF eRestrictedArea != VID_BLANK
DEBUG_DRAW_VECTOR_ID_AREA(eRestrictedArea, GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedEmails[index].sCommData.eID))
ENDIF
ENDREPEAT
ELSE
//Call in progress. If this call triggers a mission, render its cancel area.
VectorID eRestrictedArea = g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eRestrictedAreaID
IF eRestrictedArea != VID_BLANK
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_TRIGGERS_MISSION)
DEBUG_DRAW_VECTOR_ID_AREA(eRestrictedArea, "Call Cancel-Area", g_sVectorIDData[eRestrictedArea].radius*0.35)
ENDIF
ENDIF
ENDIF
ENDPROC
PROC GET_CHARACTER_INDEXES_FOR_CB_CONV_INDEX(INT iConvIndex, INT &iChar1, INT &iChar2)
SWITCH iConvIndex
CASE 1
iChar1 = 1
iChar2 = 8
BREAK
CASE 2
iChar1 = 5
iChar2 = 2
BREAK
CASE 3
iChar1 = 3
iChar2 = 10
BREAK
CASE 4
iChar1 = 4
iChar2 = 13
BREAK
CASE 5
iChar1 = 7
iChar2 = 6
BREAK
CASE 6
iChar1 = 12
iChar2 = 9
BREAK
CASE 7
iChar1 = 11
iChar2 = 44
BREAK
CASE 8
iChar1 = 34
iChar2 = 14
BREAK
CASE 9
iChar1 = 15
iChar2 = 28
BREAK
CASE 10
iChar1 = 43
iChar2 = 16
BREAK
CASE 11
iChar1 = 17
iChar2 = 18
BREAK
CASE 12
iChar1 = 19
iChar2 = 20
BREAK
CASE 13
iChar1 = 26
iChar2 = 21
BREAK
CASE 14
iChar1 = 22
iChar2 = 23
BREAK
CASE 15
iChar1 = 24
iChar2 = 25
BREAK
CASE 16
iChar1 = 27
iChar2 = 29
BREAK
CASE 17
iChar1 = 30
iChar2 = 31
BREAK
CASE 18
iChar1 = 33
iChar2 = 32
BREAK
CASE 19
iChar1 = 35
iChar2 = 36
BREAK
CASE 20
iChar1 = 38
iChar2 = 37
BREAK
CASE 21
iChar1 = 40
iChar2 = 39
BREAK
CASE 22
iChar1 = 41
iChar2 = 42
BREAK
DEFAULT
CPRINTLN(DEBUG_COMMUNICATIONS, "Tried to get speaker IDs for a CB conversation # that doesn't exist!")
iChar1 = 1
iChar2 = 2
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Checks whether the current weather is OK for this monologue to play (in case it references weather like Mon 5)
/// PARAMS:
/// iMonID - the ID we're checking
/// RETURNS:
/// TRUE if the monologue makes sense if said with the current weather (most do), false if not
FUNC BOOL IS_CURRENT_WEATHER_OK_FOR_MONOLOGUE(int iMonID)
SWITCH iMonID
CASE 5
IF IS_PREV_WEATHER_TYPE("SMOG")
OR IS_PREV_WEATHER_TYPE("OVERCAST")
OR IS_PREV_WEATHER_TYPE("RAIN")
OR IS_PREV_WEATHER_TYPE("THUNDER")
OR IS_PREV_WEATHER_TYPE("SNOW")
OR IS_NEXT_WEATHER_TYPE("SMOG")
OR IS_NEXT_WEATHER_TYPE("OVERCAST")
OR IS_NEXT_WEATHER_TYPE("RAIN")
OR IS_NEXT_WEATHER_TYPE("THUNDER")
OR IS_NEXT_WEATHER_TYPE("SNOW")
RETURN FALSE
ENDIF
BREAK
DEFAULT // If it ain't in this list, it can be used
RETURN TRUE
BREAK
ENDSWITCH
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Generates a random ID for a monologue (int between 1 and 43), checks to make sure it's okay to be played now, and regenerates it if not
/// RETURNS:
/// An int between 1 and 43
FUNC INT RETURN_APPROPRIATE_MONOLOGUE_ID()
TIMEOFDAY newTOD = GET_CURRENT_TIMEOFDAY()
INT iHour = GET_TIMEOFDAY_HOUR(newTOD)
BOOL bCanUseID = FALSE
INT iConvNum
WHILE bCanUseID = FALSE
iConvNum = GET_RANDOM_INT_IN_RANGE(1, 44)
SWITCH iConvNum
CASE 5
IF iHour > 19
// Too late in the day for this monologue to make sense
bCanUseID = FALSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Too late for Monologue ", iConvNum, " to play, regenerating another one")
ELIF iHour < 9
// Too early in the day for this monologue to make sense
bCanUseID = FALSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Too early for Monologue ", iConvNum, " to play, regenerating another one")
ELIF NOT IS_CURRENT_WEATHER_OK_FOR_MONOLOGUE(iConvNum)
bCanUseID = FALSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Current weather makes Monologue ", iConvNum, " not make sense, regenerating another one")
ELSE
bCanUseID = TRUE // Yay, we can use it
ENDIF
BREAK
DEFAULT // If it ain't in this list, it can be used
bCanUseID = TRUE
BREAK
ENDSWITCH
WAIT(0)
ENDWHILE
//Force debug conversation
#IF IS_DEBUG_BUILD
IF iForceDebugConv != -1
iConvNum = CLAMP_INT(iForceDebugConv,1,43)
iForceDebugConv = -1
ENDIF
#ENDIF
RETURN iConvNum
ENDFUNC
/// PURPOSE:
/// Try to do a monologue or conversation type CB convo
/// RETURNS:
/// TRUE if the conversation was successful
FUNC BOOL Do_CB_MonConvo()
TEXT_LABEL_15 tlConv
INT iConvNum
TEXT_LABEL_15 tlPedName
BOOL bDecision = GET_RANDOM_BOOL()
// If any of these RAG widget bools are true, override the random decision because one of us wants a specific conv type
#IF IS_DEBUG_BUILD
IF bDoMonologue
bDecision = TRUE
ELIF bDoConv
bDecision = FALSE
ENDIF
#ENDIF
IF bDecision // If true, do a monologue - if false, do a conversation
tlConv = "CB_MON"
iConvNum = RETURN_APPROPRIATE_MONOLOGUE_ID()
tlConv += iConvNum // Creates the label we want, e.g. "CB_MON23"
tlPedName = "CB_CHAR"
tlPedName += iConvNum // Reuse the conv number we just generated to get the correct ped ID (they must match in D*!)
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, tlPedName, FALSE, FALSE)
IF CREATE_CONVERSATION(convoStruct, "CBRADAU", tlConv, CONV_PRIORITY_AMBIENT_LOW, DO_NOT_DISPLAY_SUBTITLES)
#IF IS_DEBUG_BUILD
IF bDoMonologue
bDoMonologue = FALSE
ENDIF
#ENDIF
PLAY_SOUND_FRONTEND(-1, "Start_Squelch", "CB_RADIO_SFX")
PLAY_SOUND_FRONTEND(iSoundID, "Background_Loop", "CB_RADIO_SFX")
RETURN TRUE
ENDIF
ELSE
INT iChar1
INT iChar2
TEXT_LABEL_15 tlPedName2 // Need a second ped name for a conversation!
tlConv = "CB_CONVO"
iConvNum = GET_RANDOM_INT_IN_RANGE(1, 23)
//Force debug conversation
#IF IS_DEBUG_BUILD
IF iForceDebugConv != -1
iConvNum = CLAMP_INT(iForceDebugConv,1,22)
iForceDebugConv = -1
ENDIF
#ENDIF
tlConv += iConvNum // Creates the label we want, e.g. "CB_CONVO10"
GET_CHARACTER_INDEXES_FOR_CB_CONV_INDEX(iConvNum, iChar1, iChar2)
// Set up the two characters
tlPedName = "CB_CHAR"
tlPedName += iChar1
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, tlPedName, FALSE, FALSE)
tlPedName2 = "CB_CHAR"
tlPedName2 += iChar2
ADD_PED_FOR_DIALOGUE(convoStruct, 4, NULL, tlPedName2, FALSE, FALSE)
IF CREATE_CONVERSATION(convoStruct, "CBRADAU", tlConv, CONV_PRIORITY_AMBIENT_LOW, DO_NOT_DISPLAY_SUBTITLES)
#IF IS_DEBUG_BUILD
IF bDoConv
bDoConv = FALSE
ENDIF
#ENDIF
PLAY_SOUND_FRONTEND(-1, "Start_Squelch", "CB_RADIO_SFX")
PLAY_SOUND_FRONTEND(iSoundID, "Background_Loop", "CB_RADIO_SFX")
RETURN TRUE
ENDIF
ENDIF
// Something went wrong...
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Try to do an Ident type CB conversation
/// RETURNS:
/// TRUE if the conversation was successful
FUNC BOOL Do_CB_Ident()
TEXT_LABEL_15 tlConv = "CB_IDN"
INT iConvNum = GET_RANDOM_INT_IN_RANGE(1, 44)
#IF IS_DEBUG_BUILD
IF iForceDebugConv != -1
iConvNum = CLAMP_INT(iForceDebugConv,1,43)
iForceDebugConv = -1
ENDIF
#ENDIF
tlConv += iConvNum // Creates the label we want, e.g. "CB_IDN6"
TEXT_LABEL_15 tlPedName = "CB_CHAR"
tlPedName += iConvNum // Reuse the conv number we just generated to get the correct ped ID (they must match in D*!)
ADD_PED_FOR_DIALOGUE(convoStruct, 3, NULL, tlPedName, FALSE, FALSE)
IF CREATE_CONVERSATION(convoStruct, "CBRADAU", tlConv, CONV_PRIORITY_AMBIENT_LOW, DO_NOT_DISPLAY_SUBTITLES)
// Reset the RAG debug bool if it's set
#IF IS_DEBUG_BUILD
IF bDoOneLine
bDoOneLine = FALSE
ENDIF
#ENDIF
PLAY_SOUND_FRONTEND(-1, "Start_Squelch", "CB_RADIO_SFX")
PLAY_SOUND_FRONTEND(iSoundID, "Background_Loop", "CB_RADIO_SFX")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Handles CB radio conversations in vehicles.
/// The player must be Trevor, and the player must in a vehicle that supports a CB radio and be within range of a transmitter.
PROC Handle_CB_Radio_In_Vehicles()
IF bCBActive = TRUE // Check the ongoing convo status to handle the player leaving the vehicle
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
STOP_SOUND(iSoundID)
PLAY_SOUND_FRONTEND(-1, "End_Squelch", "CB_RADIO_SFX")
CPRINTLN(DEBUG_COMMUNICATIONS, "Stopped CB loop, played end squelch")
CPRINTLN(DEBUG_COMMUNICATIONS, "CB conversation finished, now inactive")
bCBActive = FALSE // If no conversation is ongoing, the CB conversation must have finished
ELSE
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE() // If the player exits the vehicle, kill the conversation early
STOP_SOUND(iSoundID)
PLAY_SOUND_FRONTEND(-1, "End_Squelch", "CB_RADIO_SFX")
CPRINTLN(DEBUG_COMMUNICATIONS, "Player exited vehicle during CB dialogue - loop stopped, end squelch played")
bCBActive = FALSE // If no conversation is ongoing, the CB conversation must have finished
ENDIF
ENDIF
ELSE
// Only check this every 10 seconds, except if we're trying to do a CB radio conversation
IF (GET_GAME_TIMER() - iCBCheckTimer) >= 10000
OR iCBState >= 1
IF GET_CURRENT_PLAYER_PED_ENUM() = CHAR_TREVOR
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF CAN_VEHICLE_RECEIVE_CB_RADIO(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), FALSE))
SWITCH iCBState
// Initialise
CASE -1
iCBIdentWaitTimer = GET_GAME_TIMER()
iCBMonConvWaitTimer = GET_GAME_TIMER()
iCBState++ // Done initialising
iSoundID = GET_SOUND_ID()
CPRINTLN(DEBUG_COMMUNICATIONS, "Initialised CB radio in Trevor's vehicle")
BREAK
// Check timers for either Ident or Monologue/Conversation time tiggers
CASE 0
IF (GET_GAME_TIMER() - iCBIdentWaitTimer) >= 120000 // 2 MINUTES
iCBState = 1 // Ident time
ENDIF
IF (GET_GAME_TIMER() - iCBMonConvWaitTimer) >= 300000 // 5 MINUTES
iCBState = 2 // Monologue/Conversation time
ENDIF
// Check for the RAG debug bools overriding the timer
#IF IS_DEBUG_BUILD
IF bDoOneLine
iCBState = 1
ELIF (bDoMonologue OR bDoConv)
iCBState = 2
ENDIF
#ENDIF
BREAK
// Do an Ident CB call
CASE 1
IF Do_CB_Ident()
bCBActive = TRUE // Set CB conversation as active
iCBIdentWaitTimer = GET_GAME_TIMER() // Reset the timer for Idents
iCBState = 0 // Back to waiting...
CPRINTLN(DEBUG_COMMUNICATIONS, "Started an ident CB radio conversation! ")
ENDIF
BREAK
// Do an Monologue/Conversation CB call
CASE 2
IF Do_CB_MonConvo()
bCBActive = TRUE // Set CB conversation as active
iCBMonConvWaitTimer = GET_GAME_TIMER() // Reset the timer for Idents
iCBState = 0 // Back to waiting...
CPRINTLN(DEBUG_COMMUNICATIONS, "Started a monologue/conversation CB radio conversation!")
ENDIF
BREAK
ENDSWITCH
ENDIF
ELSE
IF iCBState != -1
iCBState = -1 // Reset the state back to the initialise stage
ENDIF
ENDIF
ENDIF
ENDIF
iCBCheckTimer = GET_GAME_TIMER() // Reset the check timer now we've run this at least once
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handles updating calls to Cletus. Calls need to change based on what's gon on in hunting recently.
PROC MAINTAIN_HUNTING_PHONECALL_STATUS()
//Early out if no hunter call timer is set.
IF ENUM_TO_INT(g_SavedGlobals.sAmbient.todHuntedWeekExp) = 0
EXIT
ENDIF
//Early out if the hunting minigame hasn't been unlocked.
IF NOT GET_MISSION_FLOW_BITSET_BIT_STATE(FLOWBITSET_MINIGAME_ACTIVE, ENUM_TO_INT(MINIGAME_HUNTING))
EXIT
ENDIF
// If the conversations saying that the palyer has hunted in the last week are registered, and it's been more than a week
// swap them.
IF IS_COMMUNICATION_REGISTERED(CHAT_CLE1_1) OR IS_COMMUNICATION_REGISTERED(CHAT_CLE1_2)
IF IS_NOW_AFTER_TIMEOFDAY(g_SavedGlobals.sAmbient.todHuntedWeekExp)
// These calls have expired because the player hasn't hunted recently. Remove them, and register the conversations
// where the hunter comments on the fact that Trevor hasn't hunted recently.
CANCEL_COMMUNICATION(CHAT_CLE1_1)
CANCEL_COMMUNICATION(CHAT_CLE1_2)
// Register the "You haven't hunted in a while recently." conversations.
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE2_1, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE2_2, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
EXIT
ENDIF
ENDIF
// Cletus comments on the player's last awesome hunt is happening, remove it, and register something else.
IF (GET_LAST_COMPLETED_CALL() = CHAT_CLE3_1)
CANCEL_COMMUNICATION(CHAT_CLE3_1)
CANCEL_COMMUNICATION(CHAT_CLE1_1)
CANCEL_COMMUNICATION(CHAT_CLE1_2)
CANCEL_COMMUNICATION(CHAT_CLE2_1)
CANCEL_COMMUNICATION(CHAT_CLE2_2)
// Wipe that call...
g_savedGlobals.sCommsControlData.eLastCompletedCall = COMM_NONE
IF IS_NOW_AFTER_TIMEOFDAY(g_SavedGlobals.sAmbient.todHuntedWeekExp)
// Not hunted in a while, register that.
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE2_1, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE2_2, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
ELSE
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE1_1, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
REGISTER_CHAT_CALL_FROM_PLAYER_TO_CHARACTER(CHAT_CLE1_2, BIT_TREVOR, CHAR_HUNTER, 3, 7200000)
ENDIF
ENDIF
ENDPROC
//
// Controller Main Loop
//
SCRIPT
CPRINTLN(DEBUG_COMMUNICATIONS, "Starting communication controller.")
// This script needs to cleanup only when the game moves from SP to MP
IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_REPEAT_PLAY)
CPRINTLN(DEBUG_COMMUNICATIONS, "The communication controller has been forced to cleanup.")
Script_Cleanup()
ENDIF
#IF IS_DEBUG_BUILD
IF NOT DOES_WIDGET_GROUP_EXIST(widgetID)
widgetID = START_WIDGET_GROUP("Comms Controller")
ADD_WIDGET_STRING("CB Radio debug")
ADD_WIDGET_STRING("(Will only work if player is Trevor, is inside a CB-equipped vehicle, and within range of a transmitter!)")
ADD_WIDGET_STRING("(Only checked every 10 seconds - there may be a delay between ticking the box and the conv starting)")
ADD_WIDGET_BOOL("Do One Line CB Radio Conversation", bDoOneLine)
ADD_WIDGET_BOOL("Do Monologue CB Radio Conversation", bDoMonologue)
ADD_WIDGET_BOOL("Do Full Conv CB Radio Conversation", bDoConv)
ADD_WIDGET_BOOL("Fire test emails into queue...", bFireTestEmails)
ADD_WIDGET_INT_SLIDER("Force conversarion number, -1 for random",iForceDebugConv,-1,43,1)
STOP_WIDGET_GROUP()
ENDIF
#ENDIF
g_iGlobalWaitTime = GET_GAME_TIMER() + CC_GLOBAL_DELAY_BETWEEN_COMMS
INT iCommsCheckStage = 0 //Used to cycle through a different queue check each frame.
iCBCheckTimer = GET_GAME_TIMER() // Initialise the CB check timer
WHILE TRUE
#IF IS_DEBUG_BUILD
IF NOT g_flowUnsaved.bUpdatingGameflow
IF bFireTestEmails
//INIT_AND_FIRE_TEST_EMAIL_QUEUE() // Commented out in comms_control_public.sch
bFireTestEmails = FALSE
ENDIF
#ENDIF
INT iGameTime = GET_GAME_TIMER()
SWITCH (eState)
CASE CCS_LOOKING_FOR_COMM
//If we go on mission while idling looking for a call then clean up.
IF IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE()
and not IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_EXILE)
CPRINTLN(DEBUG_COMMUNICATIONS, "Cleaning up as we go on mission.")
Script_Cleanup()
ENDIF
//No call in progress. Look for a communication to process.
bCommunicationMade = FALSE
IF iTimeCallInitialisationStarted != -1
iTimeCallInitialisationStarted = -1
ENDIF
SWITCH(iCommsCheckStage)
CASE 0
Check_For_Queued_Phonecall_To_Player_To_Run(iGameTime)
BREAK
CASE 1
Check_For_Queued_Phonecall_From_Player_To_Run(iGameTime)
BREAK
CASE 2
Check_For_Queued_Text_Message_To_Run(iGameTime)
BREAK
CASE 3
Check_For_Any_Outgoing_Calls_To_Run(iGameTime)
BREAK
CASE 4
Check_For_Queued_Email_To_Run(iGameTime)
BREAK
ENDSWITCH
//Loop check stage counter.
iCommsCheckStage++
IF iCommsCheckStage > 4
iCommsCheckStage = 0
ENDIF
// Try and check the CB radio, if possible
IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_CHAR)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_EVENT)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_SPMC)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_FRIENDS)
AND NOT IS_MISSION_LEADIN_ACTIVE()
Handle_CB_Radio_In_Vehicles()
ENDIF
BREAK
CASE CCS_INITIALISING_COMM
//Has a mission launched before this call could go through?
IF g_iCommsCandidateID = NO_CANDIDATE_ID
IF NOT CAN_MISSION_TYPE_START_AGAINST_CURRENT_TYPE(MISSION_TYPE_STORY)
AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_EXILE)
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " cancelled as mission started before it initialised.")
Process_Early_Cancellation_Of_Call(iGameTime)
eState = CCS_LOOKING_FOR_COMM
ENDIF
ENDIF
//Has the phone been hung up before it could be answered?
IF eState = CCS_INITIALISING_COMM
IF bWaitForForceAwayFlagToClear
IF NOT HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
bWaitForForceAwayFlagToClear = FALSE
ENDIF
ELSE
IF CHECK_CELLPHONE_LAST_CALL_REJECTED()
OR WAS_LAST_CELLPHONE_CALL_INTERRUPTED()
OR HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
OR g_bScriptsSetSafeForCutscene
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " rejected or forced away for the following reason/s:")
IF CHECK_CELLPHONE_LAST_CALL_REJECTED()
CPRINTLN(DEBUG_COMMUNICATIONS, "CHECK_CELLPHONE_LAST_CALL_REJECTED = TRUE")
ENDIF
IF WAS_LAST_CELLPHONE_CALL_INTERRUPTED()
CPRINTLN(DEBUG_COMMUNICATIONS, "WAS_LAST_CELLPHONE_CALL_INTERRUPTED = TRUE")
ENDIF
IF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
CPRINTLN(DEBUG_COMMUNICATIONS, "HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY = TRUE")
ENDIF
IF g_bScriptsSetSafeForCutscene
CPRINTLN(DEBUG_COMMUNICATIONS, "g_bScriptsSetSafeForCutscene = TRUE")
ENDIF
#ENDIF
Process_Early_Cancellation_Of_Call(iGameTime)
eState = CCS_LOOKING_FOR_COMM
ENDIF
ENDIF
ENDIF
//Has this call been answered yet?
IF eState = CCS_INITIALISING_COMM
IF IS_PHONE_ONSCREEN(FALSE)
IF IS_CELLPHONE_CONVERSATION_PLAYING()
IF g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.ePriority = CPR_VERY_HIGH
DISABLE_HANGUP_FOR_THIS_CALL(FALSE)
ENDIF
//Does this call need to secure a candidate ID for a mission?
IF IS_BIT_SET(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.iSettings, COMM_BIT_TRIGGERS_MISSION)
IF Update_Secure_Mission_Candidate_For_Mission_Triggering_Call()
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " finished initialising.")
eState = CCS_COMM_IN_PROGRESS
ENDIF
ELSE
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " finished initialising.")
eState = CCS_COMM_IN_PROGRESS
ENDIF
ENDIF
ENDIF
ENDIF
//Check for call initialisation taking too long. Timeout and requeue as a failsafe.
IF eState = CCS_INITIALISING_COMM
IF iTimeCallInitialisationStarted = -1
CPRINTLN(DEBUG_COMMUNICATIONS, "Setting new initialisation timer for call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), ".")
iTimeCallInitialisationStarted = GET_GAME_TIMER()
ELIF (GET_GAME_TIMER() - iTimeCallInitialisationStarted) > 20000
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " failed to initialise in time. Killing call and requeuing.")
KILL_PHONE_CONVERSATION()
HANG_UP_AND_PUT_AWAY_PHONE(TRUE)
Process_Early_Cancellation_Of_Call(iGameTime, TRUE)
iTimeCallInitialisationStarted = -1
eState = CCS_LOOKING_FOR_COMM
ENDIF
ENDIF
BREAK
CASE CCS_COMM_IN_PROGRESS
IF HAS_CELLPHONE_CALL_FINISHED()
CPRINTLN(DEBUG_COMMUNICATIONS, "Call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[g_iCallInProgress].sCommData.eID), " has finished.")
Process_Termination_Of_Last_Call(iGameTime)
bDoCallBranch = FALSE
g_iGlobalWaitTime = iGameTime + CC_GLOBAL_DELAY_BETWEEN_COMMS
eState = CCS_LOOKING_FOR_COMM
g_iCallInProgress = -1
ELIF g_iCallInProgress != -1
Update_Branched_Call_Dialogue()
Update_Call_In_Progress_Responses()
Update_Mission_Triggering_Calls_Safeguards(iGameTime)
ENDIF
BREAK
ENDSWITCH
//Process all texts that are sitting in the sent text queue.
INT index
REPEAT g_savedGlobals.sCommsControlData.iNoSentTexts index
Update_Sent_Text_Responses(iGameTime, g_savedGlobals.sCommsControlData.sSentTexts[index])
ENDREPEAT
Update_Call_Help()
IF g_bPauseCommsQueues OR g_bPauseCommsQueuesThisFrame
Pause_Timers()
g_bPauseCommsQueuesThisFrame = FALSE
ENDIF
#IF IS_DEBUG_BUILD
ENDIF
IF g_bTriggerDebugOn
Debug_Draw_All_Queued_Comms_Restricted_Areas()
ENDIF
#ENDIF
MAINTAIN_HUNTING_PHONECALL_STATUS()
WAIT(0)
ENDWHILE
ENDSCRIPT