// _________________________________________________________________________________________ // _________________________________________________________________________________________ // ___ ___ // ___ Author: Alwyn Roberts Date: 21/09/2010 ___ // _________________________________________________________________________________________ // ___ ___ // ___ (A1) - Friends_controller file for use – Friends_controller.sc ___ // ___ ___ // _________________________________________________________________________________________ //Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. USING "rage_builtins.sch" USING "globals.sch" USING "model_enums.sch" //- commands headers -// USING "commands_streaming.sch" //- script headers -// //- public headers -// USING "dialogue_public.sch" USING "cellphone_public.sch" USING "player_ped_public.sch" USING "timer_public.sch" USING "minigames_helpers.sch" USING "comms_control_public.sch" USING "selector_public.sch" //- private headers -// USING "friendController_private.sch" #IF IS_DEBUG_BUILD //- debug headers -// USING "script_debug.sch" USING "shared_debug.sch" #ENDIF // ******************************************************************************************* // CONSTANTS // ******************************************************************************************* // ******************************************************************************************* // ENUMERATIONS // ******************************************************************************************* // ******************************************************************************************* // VARIABLES // ******************************************************************************************* //- Flags(INT and BOOL) -// BOOL bFriends_controller_in_progress = TRUE BOOL bDefault_player_char_has_been_initialized = FALSE enumFriendConnection eMaintainedFriendCon enumFriend eMaintainFriendTimer //enumCharacterList ePhoneLoopChar // BBUDDIES REMOVED structAmbGroup ambGroup structPedsForConversation friendActivityCallConversation #IF IS_DEBUG_BUILD WIDGET_GROUP_ID hWidget BOOL bDummyRagButton PROC CreateDebugWidget() hWidget = START_WIDGET_GROUP("Friends Controller") ADD_WIDGET_BOOL("Dummy entry", bDummyRagButton) STOP_WIDGET_GROUP() ENDPROC PROC CleanupDebugWidget() IF DOES_WIDGET_GROUP_EXIST(hWidget) DELETE_WIDGET_GROUP(hWidget) ENDIF ENDPROC #ENDIF // ******************************************************************************************* // GENERAL FUNCTIONS AND PROCEDURES // ******************************************************************************************* //PURPOSE: Called on completion of the mission to release memory used for models etc PROC Friends_Controller_Cleanup() CPRINTLN(DEBUG_FRIENDS, "Friends_Controller_Cleanup() - Shutting down friend controller") #IF IS_DEBUG_BUILD CleanupDebugWidget() #ENDIF // Remove squad contacts // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_MICHAEL)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION") // BBUDDIES REMOVED // REMOVE_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_FRANKLIN)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION") // REMOVE_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_TREVOR)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION") // REMOVE_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // g_bitfieldBattleBuddyPhoneContact = 0 // Reset any initiating connections enumFriendConnection eConnection REPEAT MAX_FRIEND_CONNECTIONS eConnection IF g_FriendConnectState[eConnection].state = FC_STATE_PhoneAccept OR g_FriendConnectState[eConnection].state = FC_STATE_PhoneDecline OR g_FriendConnectState[eConnection].state = FC_STATE_Init SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) ENDIF ENDREPEAT // Cleanup ambient friends Private_CleanupAmbGroup(ambGroup) // Cleanup queued ambient friends enumCharacterList eCharLoop REPEAT NUM_OF_PLAYABLE_PEDS eCharLoop IF NOT IS_PED_INJURED(g_pDismissPeds[eCharLoop]) CPRINTLN(DEBUG_FRIENDS, "Friends_Controller_Cleanup() - already queued ambient friend to global delete queue as part of friends_controller shutdown (", GetLabel_enumCharacterList(eCharLoop), ")") Private_AddPedToDeleteQueue(g_pDismissPeds[eCharLoop]) g_pDismissPeds[eCharLoop] = NULL ENDIF ENDREPEAT // Shut down is successful CPRINTLN(DEBUG_FRIENDS, "/\\/\\ ...friends_controller.sc has shutdown (not running)") SET_GAME_PAUSED(FALSE) TERMINATE_THIS_THREAD() ENDPROC //PURPOSE: Initializes all the variables used within the scope of the script PROC Initialise_Friends_Controller_Variables() //- vectors -// //- floats -// //- ints -// //-- structs : FRIENDS_STRUCT --// PRIVATE_InitialiseFriendLocations(TRUE) PRIVATE_InitialiseActivityLocations() Private_InitAmbGroup(ambGroup) #IF IS_DEBUG_BUILD CreateDebugWidget() #ENDIF ENDPROC // ******************************************************************************************* // SETUP FUNCTIONS AND PROCEDURES // ******************************************************************************************* //PURPOSE: Load all the required models etc, and init peds, vehicles etc PROC Setup_Friends_controller() //- request models - peds -// //- request models - vehicles -// //- request models - objects -// //- request models - weapons -// //- request anims and ptfx --// //- request vehicle recordings -// //- request interior models -// //- wait for assets to load -// //- create any script vehicles -// //- create any script peds -// //- create the peds for hot-swap -// //- set the players initial coords and heading -// //- create any script objects -// //- create any sequence tasks -// //- setup any scripted coverpoints -// //- add any initial taxi locations -// //- load scene(if required) -// //- load additional text and mission text link-// //- setup audio malarky for player -// ENDPROC #IF IS_DEBUG_BUILD //// ******************************************************************************************* //// DEBUGGING FUNCTIONS AND PROCEDURES //// ******************************************************************************************* PROC DEBUG_DisplayMissionZoneInfo() IF g_flowUnsaved.bShowMissionFlowDebugScreen IF (g_iDebugSelectedFriendConnDisplay > 0) INT iTopLine = 32 HUD_COLOURS textColour = HUD_COLOUR_YELLOW // Draw background box DrawFriendBox((0.77+1.0)/2.0, 0.85, (1.0-0.77), 0.1, 0, 0, 0, 175) // Print current mission zone + accepted chars SWITCH g_eFriendMissionZoneState CASE FRIEND_MISSION_ZONE_LAUNCHING FALLTHRU CASE FRIEND_MISSION_ZONE_LAUNCHED textColour = HUD_COLOUR_YELLOW BREAK CASE FRIEND_MISSION_ZONE_REJECT textColour = HUD_COLOUR_RED BREAK CASE FRIEND_MISSION_ZONE_CALL CASE FRIEND_MISSION_ZONE_ON textColour = HUD_COLOUR_WHITE BREAK CASE FRIEND_MISSION_ZONE_OFF FALLTHRU DEFAULT textColour = HUD_COLOUR_BLUEDARK BREAK ENDSWITCH // Print mission zone state + accept chars TEXT_LABEL_63 tZoneMission = "CurrentZone: " tZoneMission += GetLabel_SP_MISSIONS(g_eFriendMissionZoneID) tZoneMission += " [" tZoneMission += GetLabel_FriendBits(g_iFriendMissionZoneAcceptBitset) tZoneMission += "]" DrawFriendLiteralString(tZoneMission, iTopLine, textColour) iTopLine++ // Print mission ID TEXT_LABEL_63 tZoneState = "CurrentZone: " tZoneState += GetLabel_enumFriendMissionZoneState(g_eFriendMissionZoneState) DrawFriendLiteralString(tZoneState, iTopLine, textColour) iTopLine++ // Print mission ID IF g_BattleBuddyMission <> SP_MISSION_NONE textColour = HUD_COLOUR_GREYLIGHT ELSE textColour = HUD_COLOUR_BLUEDARK ENDIF TEXT_LABEL_63 tBuddyMission = "BBuddyMission: " tBuddyMission += GetLabel_SP_MISSIONS(g_BattleBuddyMission) tBuddyMission += " [" tBuddyMission += GetLabel_FriendBits(g_BattleBuddyAllowedChars) tBuddyMission += "]" DrawFriendLiteralString(tBuddyMission, iTopLine, textColour) iTopLine++ ENDIF ENDIF ENDPROC #ENDIF // ******************************************************************************************* // MISSION SPECIFIC FUNCTIONS AND PROCEDURES // ******************************************************************************************* FUNC BOOL Private_StartFriendCall(enumCharacterList friendCharID, BOOL& bWasOutgoingCallSuccessful, BOOL& bWasCallAnswephone, BOOL& bWillFriendComeToPlayer) // Setup the conversation participants enumCharacterList playerCharID = g_eDefaultPlayerChar enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) ADD_FRIEND_CHAR_FOR_DIALOGUE(friendActivityCallConversation, playerCharID, PLAYER_PED_ID()) ADD_FRIEND_CHAR_FOR_DIALOGUE(friendActivityCallConversation, friendCharID, NULL) TEXT_LABEL tBlock, tRootA, tRootB, tRootC, tRootC_spec, tRootD BOOL ShouldPhoneBeForcedOnScreen = FALSE //TRUE // Answerphone IF NOT PRIVATE_FriendAcceptsCall(playerID, friendID) IF IS_PLAYER_PED_PLAYABLE(friendCharID) OR PRIVATE_Friend_DoAnswerPhone(friendActivityCallConversation, friendCharID) CPRINTLN(DEBUG_FRIENDS, "DEBUG_PrintFriendCallInfo(player called friend ANSWERPHONE)") bWasOutgoingCallSuccessful = FALSE bWasCallAnswephone = TRUE RETURN TRUE ENDIF // Accepts ELIF PRIVATE_FriendAcceptsPlayer(playerID, friendID) enumFriendPhonePhrase eGreetPhraseA, eGreetPhraseB PRIVATE_Friend_GetPhoneConv_Greet(playerID, eGreetPhraseA, eGreetPhraseB) enumFriendPhonePhrase eAcceptPhraseA, eAcceptPhraseB PRIVATE_Friend_GetPhoneConv_Accept(playerID, friendID, eAcceptPhraseA, eAcceptPhraseB, TRUE) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eGreetPhraseA, tBlock, tRootA) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eGreetPhraseB, tBlock, tRootB) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eAcceptPhraseA, tBlock, tRootC) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eAcceptPhraseB, tBlock, tRootD) tRootC_spec = tRootC IF eAcceptPhraseA = FPP_OUTGOING_YES1_FIRSTTIME tRootC_spec += "_1" ENDIF IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_4_LINES(friendActivityCallConversation, GET_CHAR_FROM_FRIEND(friendID), tBlock, tRootA, tRootA, // Greeting 1 tRootB, tRootB, // Greeting 2 tRootC, tRootC_spec, // Friend accepts tRootD, tRootD, // Player says bye CONV_PRIORITY_FLOW_ONLY_USE_AMBIENT_SLOT, ShouldPhoneBeForcedOnScreen) #IF IS_DEBUG_BUILD DEBUG_PrintFriendCallInfo("player called friend ACCEPT", tRootA, tRootB, tRootC, tRootD) #ENDIF // Check if friend will come to player IF eAcceptPhraseA = FPP_OUTGOING_YES1_COMETOYOU bWillFriendComeToPlayer = TRUE ELSE bWillFriendComeToPlayer = FALSE ENDIF bWasOutgoingCallSuccessful = TRUE bWasCallAnswephone = FALSE RETURN TRUE ENDIF // Declines - special case: because Lamar is laying low during the day after Michael/Trevor killed in finale ELIF NOT PRIVATE_FriendAcceptsPlayer_laylow(friendID) INT iRandomConv = GET_RANDOM_INT_IN_RANGE(0, 3) IF iRandomConv = 0 Private_GetFriendPhonePhrase(playerCharID, friendCharID, FPP_LAYLOW1, tBlock, tRootA) ELIF iRandomConv = 1 Private_GetFriendPhonePhrase(playerCharID, friendCharID, FPP_LAYLOW2, tBlock, tRootA) ELSE Private_GetFriendPhonePhrase(playerCharID, friendCharID, FPP_LAYLOW3, tBlock, tRootA) ENDIF IF PLAYER_CALL_CHAR_CELLPHONE(friendActivityCallConversation, GET_CHAR_FROM_FRIEND(friendID), tBlock, tRootA, CONV_PRIORITY_FLOW_ONLY_USE_AMBIENT_SLOT, ShouldPhoneBeForcedOnScreen) #IF IS_DEBUG_BUILD DEBUG_PrintFriendCallInfo("player called friend DECLINE (LAYLOW)", tRootA, tRootA, tRootA, tRootA) #ENDIF bWasOutgoingCallSuccessful = FALSE bWasCallAnswephone = FALSE RETURN TRUE ENDIF // Declines - general ELSE enumFriendPhonePhrase eGreetPhraseA, eGreetPhraseB PRIVATE_Friend_GetPhoneConv_Greet(playerID, eGreetPhraseA, eGreetPhraseB) enumFriendPhonePhrase eDeclinePhraseA, eDeclinePhraseB PRIVATE_Friend_GetPhoneConv_Reject(playerID, friendID, eDeclinePhraseA, eDeclinePhraseB) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eGreetPhraseA, tBlock, tRootA) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eGreetPhraseB, tBlock, tRootB) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eDeclinePhraseA, tBlock, tRootC) Private_GetFriendPhonePhrase(playerCharID, friendCharID, eDeclinePhraseB, tBlock, tRootD) IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_4_LINES(friendActivityCallConversation, GET_CHAR_FROM_FRIEND(friendID), tBlock, tRootA, tRootA, // Greeting 1 tRootB, tRootB, // Greeting 2 tRootC, tRootC, // Friend declines tRootD, tRootD, // Player says bye CONV_PRIORITY_FLOW_ONLY_USE_AMBIENT_SLOT, ShouldPhoneBeForcedOnScreen) #IF IS_DEBUG_BUILD DEBUG_PrintFriendCallInfo("player called friend DECLINE", tRootA, tRootB, tRootC, tRootD) #ENDIF bWasOutgoingCallSuccessful = FALSE bWasCallAnswephone = FALSE RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC //FUNC BOOL Private_StartSquadCall(enumCharacterList friendCharID, BOOL& bWasOutgoingCallSuccessful) // BBUDDIES REMOVED // // enumCharacterList playerCharID = g_eDefaultPlayerChar // // enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) // enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) // // // Setup the conversation participants // ADD_FRIEND_CHAR_FOR_DIALOGUE(friendActivityCallConversation, playerCharID, PLAYER_PED_ID()) // ADD_FRIEND_CHAR_FOR_DIALOGUE(friendActivityCallConversation, friendCharID, NULL) // // BOOL ShouldPhoneBeForcedOnScreen = FALSE //TRUE // // // Answerphone // IF NOT PRIVATE_SquadAcceptsCall(playerID, friendID) // // IF PRIVATE_Friend_DoAnswerPhone(friendActivityCallConversation, friendCharID) // // CPRINTLN(DEBUG_FRIENDS, "DEBUG_PrintFriendCallInfo(player called squad ANSWERPHONE)") // bWasOutgoingCallSuccessful = FALSE // RETURN TRUE // // ENDIF // // // Successful call // ELSE // // enumFriendPhonePhrase eBackupPhrase // PRIVATE_Friend_GetPhoneConv_Backup(eBackupPhrase) // // TEXT_LABEL tBlock // TEXT_LABEL tBackupRoot // Private_GetFriendPhonePhrase(playerCharID, friendCharID, eBackupPhrase, tBlock, tBackupRoot) // // IF PLAYER_CALL_CHAR_CELLPHONE(friendActivityCallConversation, // friendCharID, // tBlock, // tBackupRoot, // CONV_PRIORITY_FLOW_ONLY_USE_AMBIENT_SLOT, ShouldPhoneBeForcedOnScreen) // // #IF IS_DEBUG_BUILD // TEXT_LABEL tEmpty = "" // DEBUG_PrintFriendCallInfo("player called squad ACCEPT", tBackupRoot, tEmpty, tEmpty, tEmpty) // #ENDIF // bWasOutgoingCallSuccessful = TRUE // RETURN TRUE // // ENDIF // // ENDIF // // RETURN FALSE //ENDFUNC // PURPOSE: Maintains the Drunk Request at the specified Drunk Request array position. // Involves: error checks; requesting, loading, running 'drunk' script; setting/clearing details. // // INPUT PARAMS: paramArrayIndex Index into drunk requests array PROC UpdateFriendConnection(enumFriendConnection eConnection, enumFriend eFriendID) // enumCharacterList ePlayerChar = g_eDefaultPlayerChar enumCharacterList eFriendChar = GET_CHAR_FROM_FRIEND(eFriendID) BOOL bWasCallSuccessful BOOL bWasCallAnswerphone BOOL bWasCallComeToYou enumFriendConnectionState eState = g_FriendConnectState[eConnection].state // SWITCH g_FriendConnectState[eConnection].state // ----------------------------------------------------------------------------------------------------- CONTACTWAIT // Wait for friend activity to be arranged // NB: In this state, FriendActivity.sc/BattleBuddy.sc can directly set the connection's state to Active - (if two other friend connections are active, and share the friends in this connection) IF eState = FC_STATE_ContactWait IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_SWITCH) // Monitor squad calls // IF IS_CALLING_CONTACT_FOR_SECONDARY_FUNCTION(eFriendChar) // BBUDDIES REMOVED // IF CAN_CHARS_ARRANGE_BATTLE_BUDDY(ePlayerChar, eFriendChar) // IF Private_StartSquadCall(eFriendChar, bWasCallSuccessful) // IF bWasCallSuccessful // SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, FALSE) // SET_CONNECTION_FLAG(eConnection, FC_FLAG_IsCallAnswerphone, FALSE) // SET_CONNECTION_STATE(eConnection, FC_STATE_PhoneAccept) // // SET_CONNECTION_MODE(eConnection, FC_MODE_Squad) // SET_SQUAD_MISSION_TO_CURRENT_ZONE() // ELSE // SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, FALSE) // SET_CONNECTION_FLAG(eConnection, FC_FLAG_IsCallAnswerphone, TRUE) // SET_CONNECTION_STATE(eConnection, FC_STATE_PhoneDecline) // ENDIF // EXIT // ENDIF // ENDIF // ENDIF // Monitor friend calls IF IS_CALLING_FRIEND_FOR_ACTIVITY(eFriendChar) IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) IF Private_StartFriendCall(eFriendChar, bWasCallSuccessful, bWasCallAnswerphone, bWasCallComeToYou) IF bWasCallSuccessful IF bWasCallComeToYou SET_CONNECTION_MODE(eConnection, FC_MODE_Adhoc) ELSE SET_CONNECTION_MODE(eConnection, FC_MODE_Friend) ENDIF SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, FALSE) SET_CONNECTION_FLAG(eConnection, FC_FLAG_IsCallAnswerphone, FALSE) SET_CONNECTION_STATE(eConnection, FC_STATE_PhoneAccept) ELSE g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].wanted = eFriendID SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, FALSE) SET_CONNECTION_FLAG(eConnection, FC_FLAG_IsCallAnswerphone, bWasCallAnswerphone) SET_CONNECTION_STATE(eConnection, FC_STATE_PhoneDecline) ENDIF EXIT ENDIF ENDIF ENDIF ENDIF // BREAK // ----------------------------------------------------------------------------------------------------- FC_STATE_PhoneAccept ELIF eState = FC_STATE_PhoneAccept // Set bit if phone is answered IF NOT IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_HasCallConnected) IF IS_CELLPHONE_CONVERSATION_PLAYING() SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, TRUE) ENDIF ENDIF TEXT_LABEL tFriendScriptName = "FriendActivity" REQUEST_SCRIPT(tFriendScriptName) // When call ends, set to init state (if not answered return to ContactWait state) IF HAS_CELLPHONE_CALL_FINISHED() OR WAS_LAST_CELLPHONE_CALL_INTERRUPTED() IF IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_HasCallConnected) RESET_FRIEND_LAST_CONTACT_TIMER(g_eDefaultPlayerChar, eFriendChar, FRIEND_CONTACT_PHONE) g_SavedGlobals.sFriendsData.g_bHelpDoneCanCancel = TRUE // IF GET_CONNECTION_MODE(eConnection) = FC_MODE_Squad // BBUDDIES REMOVED // INC_BBUDDY_CALL_STAT(g_eDefaultPlayerChar, eFriendChar) // ENDIF SET_CONNECTION_STATE(eConnection, FC_STATE_Init) ELSE SET_SCRIPT_AS_NO_LONGER_NEEDED(tFriendScriptName) SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) ENDIF ENDIF // BREAK // ----------------------------------------------------------------------------------------------------- FC_STATE_PhoneDecline // Wait for unsuccessful call to finish ELIF eState = FC_STATE_PhoneDecline IF IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_IsCallAnswerphone) AND IS_PLAYER_PED_PLAYABLE(eFriendChar) IF NOT IS_CALLING_FRIEND_FOR_ACTIVITY(eFriendChar) IF g_savedGlobals.sFriendsData.g_bHasPlayerBeenTurnedDown = FALSE g_savedGlobals.sFriendsData.g_bHasPlayerBeenTurnedDown = TRUE ENDIF SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) ENDIF ELSE // Set bit if phone is answered IF NOT IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_HasCallConnected) IF IS_CELLPHONE_CONVERSATION_PLAYING() SET_CONNECTION_FLAG(eConnection, FC_FLAG_HasCallConnected, TRUE) ENDIF ENDIF // When call ends, return to ContactWait state IF HAS_CELLPHONE_CALL_FINISHED() OR WAS_LAST_CELLPHONE_CALL_INTERRUPTED() // If call was answered by friend -> reset the timer IF IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_HasCallConnected) IF NOT IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_IsCallAnswerphone) RESET_FRIEND_LAST_CONTACT_TIMER(g_eDefaultPlayerChar, eFriendChar, FRIEND_CONTACT_PHONE) ENDIF // If player has been turned down before -> decrease like stat IF g_savedGlobals.sFriendsData.g_bHasPlayerBeenTurnedDown = FALSE g_savedGlobals.sFriendsData.g_bHasPlayerBeenTurnedDown = TRUE ELIF NOT IS_CONNECTION_FLAG_SET(eConnection, FC_FLAG_IsCallAnswerphone) UPDATE_FRIEND_LIKE(g_eDefaultPlayerChar, eFriendChar, FriendLike_DECLINED_CALL) ENDIF ENDIF //g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].thread = 0 SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) ENDIF ENDIF // BREAK // ----------------------------------------------------------------------------------------------------- FC_STATE_Init // Wait for friend activity script to launch // NB: In this state, FriendActivity.sc can directly set the connection's state to Friend/ContactWait ELIF eState = FC_STATE_Init TEXT_LABEL tFriendScriptName = "FriendActivity" IF NOT IS_THREAD_ACTIVE(INT_TO_NATIVE(THREADID, g_SavedGlobals.sFriendsData.g_FriendScriptThread)) IF NOT HAS_SCRIPT_LOADED(tFriendScriptName) CPRINTLN(DEBUG_FRIENDS, "FC_STATE_Init - Requesting script \"", tFriendScriptName, "\"") REQUEST_SCRIPT(tFriendScriptName) ELSE CPRINTLN(DEBUG_FRIENDS, "FC_STATE_Init - STARTING SCRIPT **\"", tFriendScriptName, "\"**") THREADID friendThread friendThread = START_NEW_SCRIPT_WITH_ARGS(tFriendScriptName, eConnection, SIZE_OF(eConnection), FRIEND_STACK_SIZE) g_SavedGlobals.sFriendsData.g_FriendScriptThread = NATIVE_TO_INT(friendThread) SET_SCRIPT_AS_NO_LONGER_NEEDED(tFriendScriptName) ENDIF ENDIF // BREAK // ----------------------------------------------------------------------------------------------------- FC_STATE_Active // Wait for friend activity script to finish // NB: In this state, FriendActivity.sc can directly set the connection's state to ContactWait ELIF eState = FC_STATE_Active IF NOT IS_THREAD_ACTIVE(INT_TO_NATIVE(THREADID, g_SavedGlobals.sFriendsData.g_FriendScriptThread)) g_SavedGlobals.sFriendsData.g_FriendScriptThread = 0 SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) ENDIF // BREAK // ----------------------------------------------------------------------------------------------------- ELIF eState = FC_STATE_Invalid // DEFAULT // Empty ENDIF // ENDSWITCH ENDPROC // ******************************************************************************************* // MAIN SCRIPT // ******************************************************************************************* #IF IS_DEBUG_BUILD PED_INDEX hSelectorMirror[NUM_OF_PLAYABLE_PEDS] PROC DEBUG_WatchSelector() INT iGameTimer = GET_FRAME_COUNT() enumCharacterList eChar REPEAT NUM_OF_PLAYABLE_PEDS eChar SELECTOR_SLOTS_ENUM eSlot = GET_SELECTOR_SLOT_FROM_PLAYER_PED_ENUM(eChar) IF hSelectorMirror[eSlot] <> g_sPlayerPedRequest.sSelectorPeds.pedID[eSlot] TEXT_LABEL tChar = GetLabel_enumCharacterList(eChar) TEXT_LABEL tMirror IF NOT IS_PED_INJURED(hSelectorMirror[eSlot]) tMirror = "a" ELIF DOES_ENTITY_EXIST(hSelectorMirror[eSlot]) tMirror = "e" ELSE tMirror = "x" ENDIF TEXT_LABEL tSelect IF NOT IS_PED_INJURED(g_sPlayerPedRequest.sSelectorPeds.pedID[eSlot]) tSelect = "a" ELIF DOES_ENTITY_EXIST(g_sPlayerPedRequest.sSelectorPeds.pedID[eSlot]) tSelect = "e" ELSE tSelect = "x" ENDIF tMirror += NATIVE_TO_INT(hSelectorMirror[eSlot]) tSelect += NATIVE_TO_INT(g_sPlayerPedRequest.sSelectorPeds.pedID[eSlot]) PRINTSTRING(":WatchSelector ") PRINTINT(iGameTimer) PRINTSTRING(": ") PRINTSTRING(tChar) PRINTSTRING(" SELECTOR SLOT CHANGE: ") PRINTSTRING(tMirror) PRINTSTRING(" to ") PRINTSTRING(tSelect) PRINTNL() hSelectorMirror[eSlot] = g_sPlayerPedRequest.sSelectorPeds.pedID[eSlot] ENDIF ENDREPEAT ENDPROC #ENDIF SCRIPT // 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_MAGDEMO)) Friends_Controller_Cleanup() ENDIF CPRINTLN(DEBUG_FRIENDS, "/\\/\\ Starting friends_controller.sc (running)") Initialise_Friends_Controller_Variables() Setup_Friends_controller() WAIT(0) // Ensure all valid connections get upgraded if coming from a save game enumFriendConnection eConnection REPEAT MAX_FRIEND_CONNECTIONS eConnection IF g_FriendConnectState[eConnection].state = FC_STATE_Invalid IF IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(FC_FLAG_HasInitiated)) SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) g_iNumberOfActiveFriends++ ENDIF ENDIF ENDREPEAT enumFriend eNonPlayerFriend eMaintainedFriendCon = FC_MICHAEL_FRANKLIN // ePhoneLoopChar = CHAR_MICHAEL // BBUDDIES REMOVED WHILE bFriends_controller_in_progress WAIT(0) // Maintain value for players current ped enum (instead of calling the accessor over and over again!) g_eDefaultPlayerChar = GET_CURRENT_PLAYER_PED_ENUM() IF g_eDefaultPlayerChar = NO_CHARACTER IF bDefault_player_char_has_been_initialized #IF IS_DEBUG_BUILD IF (g_iDebugSelectedFriendConnDisplay > 0) CPRINTLN(DEBUG_FRIENDS, "Dont maintain player requests - default player char = ", GET_PLAYER_PED_STRING(g_eDefaultPlayerChar), " [frame: ", GET_FRAME_COUNT(), "]") ENDIF #ENDIF ENDIF ELSE // Update friend connections bDefault_player_char_has_been_initialized = TRUE IF g_flowUnsaved.bFlowControllerBusy #IF IS_DEBUG_BUILD DrawFriendLiteralString("g_bFlowControllerBusy!", 1, HUD_COLOUR_RED) #ENDIF ELIF IS_PLAYER_PLAYING(PLAYER_ID()) // Process friend connections (staggered, one per frame) IF GET_OTHER_FRIEND_FROM_CONNECTION(eMaintainedFriendCon, eNonPlayerFriend) UpdateFriendConnection(eMaintainedFriendCon, eNonPlayerFriend) ENDIF eMaintainedFriendCon = INT_TO_ENUM(enumFriendConnection, (ENUM_TO_INT(eMaintainedFriendCon) + 1) % ENUM_TO_INT(MAX_FRIEND_CONNECTIONS)) IF NOT g_savedGlobals.sFriendsData.g_bHelpDoneCanPhoneDecline IF g_savedGlobals.sFriendsData.g_bHasPlayerBeenTurnedDown SWITCH GET_FLOW_HELP_MESSAGE_STATUS("AM_H_NOFRND") CASE FHS_EXPIRED ADD_HELP_TO_FLOW_QUEUE("AM_H_NOFRND", FHP_HIGH, 0, 1000, DEFAULT_GOD_TEXT_TIME) BREAK CASE FHS_DISPLAYED g_savedGlobals.sFriendsData.g_bHelpDoneCanPhoneDecline = TRUE BREAK ENDSWITCH ENDIF ENDIF // Update squad phone contacts // IF g_eDefaultPlayerChar <> ePhoneLoopChar // BBUDDIES REMOVED // SWITCH ePhoneLoopChar // CASE CHAR_MICHAEL // IF CAN_CHARS_ARRANGE_BATTLE_BUDDY(g_eDefaultPlayerChar, CHAR_MICHAEL) // IF NOT IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_MICHAEL)) // OR NOT IS_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE() // SET_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE("CELL_223") // SET_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_MICHAEL)) // ENDIF // ELSE // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_MICHAEL)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION") // CLEAR_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_MICHAEL)) // REMOVE_MICHAEL_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // ENDIF // BREAK // // CASE CHAR_FRANKLIN // IF CAN_CHARS_ARRANGE_BATTLE_BUDDY(g_eDefaultPlayerChar, CHAR_FRANKLIN) // IF NOT IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_FRANKLIN)) // OR NOT IS_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE() // SET_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE("CELL_223") // SET_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_FRANKLIN)) // ENDIF // ELSE // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_FRANKLIN)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION") // CLEAR_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_FRANKLIN)) // REMOVE_FRANKLIN_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // ENDIF // BREAK // // CASE CHAR_TREVOR // IF CAN_CHARS_ARRANGE_BATTLE_BUDDY(g_eDefaultPlayerChar, CHAR_TREVOR) // IF NOT IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_TREVOR)) // OR NOT IS_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE() // SET_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION_AVAILABLE("CELL_223") // SET_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_TREVOR)) // ENDIF // ELSE // IF IS_BIT_SET(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_TREVOR)) // CPRINTLN(DEBUG_FRIENDS, "UpdateFriendSquadContacts() - REMOVE_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION") // CLEAR_BIT(g_bitfieldBattleBuddyPhoneContact, ENUM_TO_INT(CHAR_TREVOR)) // REMOVE_TREVOR_SECONDARY_CONTACT_LIST_FUNCTION() // ENDIF // ENDIF // BREAK // ENDSWITCH // ENDIF // // ePhoneLoopChar = INT_TO_ENUM(enumCharacterList, (ENUM_TO_INT(ePhoneLoopChar) + 1) % ENUM_TO_INT(NUM_OF_PLAYABLE_PEDS)) // If mission has been set as launching, monitor it's progress until it ends IF g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_LAUNCHING //IF MISSION_FLOW_GET_RUNNING_MISSION() = g_eFriendMissionZoneID IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_FRIENDS) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP) SET_FRIEND_MISSION_ZONE(g_eFriendMissionZoneID, FRIEND_MISSION_ZONE_LAUNCHED, g_iFriendMissionZoneAcceptBitset) ENDIF ELIF g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_LAUNCHED // IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP) // BBUDDIES REMOVED // // // If mission has failed and a replay has been accepted, don't class this as on-mission (otherwise pause fail timers) // IF NOT (IS_REPLAY_BEING_PROCESSED() OR g_replay.replayStageID = RS_REJECTED) // // PAUSE_SOLDIER_FAIL_TIMERS() // // ENDIF // // ELIF NOT IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE() OR MISSION_FLOW_GET_RUNNING_MISSION() <> g_eFriendMissionZoneID // // // Reset timers that were paused for existing during a non-replay-processing prep mission // CANCEL_PAUSED_SOLDIER_FAIL_TIMERS() // CLEAR_FRIEND_MISSION_ZONE(g_eFriendMissionZoneID) // // ENDIF IF NOT IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE() // BBUDDIES REPLACED CLEAR_FRIEND_MISSION_ZONE(g_eFriendMissionZoneID) ENDIF ENDIF // If player switches to failed soldier, clear the fail // IF IS_TIMER_STARTED(g_savedGlobals.sFriendsData.g_SoldierFailTimers[g_eDefaultPlayerChar]) // BBUDDIES REMOVED // CANCEL_TIMER(g_savedGlobals.sFriendsData.g_SoldierFailTimers[g_eDefaultPlayerChar]) // ENDIF // If player switches to failed friend, clear the fail // BBUDDIES REPLACED // enumFriend ePlayerID = GET_FRIEND_FROM_CHAR(g_eDefaultPlayerChar) // IF ePlayerID < MAX_FRIENDS // CANCEL_TIMER(g_savedGlobals.sFriendsData.g_FriendFailTimers[ePlayerID]) // ENDIF // Unpause fail timer, if associated text message has been recieved // enumFriend eFriendLoop // REPEAT MAX_FRIENDS eFriendLoop // IF g_savedGlobals.sFriendsData.g_FriendFailMessages[eFriendLoop] <> COMM_NONE // IF IS_COMMUNICATION_REGISTERED(g_savedGlobals.sFriendsData.g_FriendFailMessages[eFriendLoop]) // CC_CommunicationStatus eStatus = GET_COMMUNICATION_STATUS(g_savedGlobals.sFriendsData.g_FriendFailMessages[eFriendLoop]) // IF eStatus = CS_INACTIVE // OR eStatus = CS_ERROR // UNPAUSE_FRIEND_FAIL_TIMER(eFriendLoop) // ENDIF // ENDIF // ENDIF // ENDREPEAT // Process one friend fail timer each frame IF GET_FRAME_COUNT() % 10 = 0 IF NOT IS_THREAD_ACTIVE(INT_TO_NATIVE(THREADID, g_SavedGlobals.sFriendsData.g_FriendScriptThread)) IF IS_TIMER_PAUSED(g_savedGlobals.sFriendsData.g_FriendFailTimers[eMaintainFriendTimer]) IF g_savedGlobals.sFriendsData.g_FriendFailMessages[eMaintainFriendTimer] = COMM_NONE OR NOT IS_TEXT_MESSAGE_REGISTERED(g_savedGlobals.sFriendsData.g_FriendFailMessages[eMaintainFriendTimer]) OR GET_TEXT_MESSAGE_STATUS(g_savedGlobals.sFriendsData.g_FriendFailMessages[eMaintainFriendTimer]) = CS_ERROR UNPAUSE_FRIEND_FAIL_TIMER(eMaintainFriendTimer) ENDIF ENDIF eMaintainFriendTimer = INT_TO_ENUM(enumFriend, (ENUM_TO_INT(eMaintainFriendTimer) + 1) % ENUM_TO_INT(MAX_FRIENDS)) ENDIF ENDIF ENDIF // Debug checks #IF IS_DEBUG_BUILD // DEBUG_WatchSelector() DEBUG_DisplayMissionZoneInfo() #ENDIF // Update ambient friends Private_UpdateAmbGroup(ambGroup, friendActivityCallConversation) ENDIF // VEHICLE_INDEX hVeh = ambGroup.mFriends[CHAR_MICHAEL].hVehicle //g_vPlayerVeh[CHAR_MICHAEL] // TEXT_LABEL_63 tVeh = "None" // IF DOES_ENTITY_EXIST(hVeh) // tVeh = GET_MODEL_NAME_FOR_DEBUG(GET_ENTITY_MODEL(hVeh)) // IF IS_VEHICLE_DRIVEABLE(hVeh) // tVeh += " driveable" // ENDIF // ENDIF // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.1, "STRING", tVeh) // // hVeh = ambGroup.mFriends[CHAR_FRANKLIN].hVehicle //g_vPlayerVeh[CHAR_MICHAEL] // tVeh = "None" // IF DOES_ENTITY_EXIST(hVeh) // tVeh = GET_MODEL_NAME_FOR_DEBUG(GET_ENTITY_MODEL(hVeh)) // IF IS_VEHICLE_DRIVEABLE(hVeh) // tVeh += " driveable" // ENDIF // ENDIF // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", tVeh) // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_MICHAEL_BH) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.1, "STRING", "SAVEHOUSE_MICHAEL_BH") // ENDIF // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_MICHAEL_CS) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "SAVEHOUSE_MICHAEL_CS") // ENDIF // // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_SC) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.3, "STRING", "SAVEHOUSE_FRANKLIN_SC") // ENDIF // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_FRANKLIN_VH) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.4, "STRING", "SAVEHOUSE_FRANKLIN_VH") // ENDIF // // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_TREVOR_CS) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.5, "STRING", "SAVEHOUSE_TREVOR_CS") // ENDIF // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_TREVOR_VB) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.6, "STRING", "SAVEHOUSE_TREVOR_VB") // ENDIF // IF Is_Savehouse_Respawn_Available(SAVEHOUSE_TREVOR_SC) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.7, "STRING", "SAVEHOUSE_TREVOR_SC") // ENDIF // IF Private_IsPlayerAtOwnSafehouse() // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.1, "STRING", "AtSafehouse") // ELSE // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.1, "STRING", "NOT AtSafehouse") // ENDIF // Shutdown if on disallowed mission type... IF NOT Should_Friends_Controller_Be_Running() #IF IS_DEBUG_BUILD AND NOT g_bDebug_KeepFriendsControllerRunning #ENDIF CPRINTLN(DEBUG_FRIENDS, "...friends_controller.sc has been forced to cleanup...") bFriends_controller_in_progress = FALSE ENDIF ENDWHILE Friends_Controller_Cleanup() ENDSCRIPT