USING "rage_builtins.sch" USING "globals.sch" USING "timer_public.sch" USING "friends_private.sch" #IF IS_DEBUG_BUILD USING "script_debug.sch" USING "shared_debug.sch" USING "flow_debug_GAME.sch" #ENDIF ///public interface for friends scripts /// sam.hackett@rockstarleeds.com /// // ******************************************************************************************* // ENUMS // ******************************************************************************************* ENUM enumFriendLikeType FriendLike_DECLINED_CALL = 0, FriendLike_BUDDY_INJURED, FriendLike_BUDDY_LOST, FriendLike_PLAYER_LATE_ARRIVAL, FriendLike_PLAYER_NO_ARRIVAL, FriendLike_PLAYER_CANCELLED, FriendLike_DID_SUGGESTED_ACTIVITY, FriendLike_DID_UNSUGGESTED_ACTIVITY, // FriendLike_PASSED_ACTIVITY, MAX_FRIEND_LIKE_EVENTS ENDENUM // ******************************************************************************************* // CONSTANTS // ******************************************************************************************* CONST_INT CONST_iLikeStatInitial 50 CONST_INT CONST_iLikeStatMin 0 CONST_INT CONST_iLikeStatMax 100 // ******************************************************************************************* // FRIEND PED ACCESSORS // ******************************************************************************************* FUNC PED_INDEX FRIEND_A_PED_ID() RETURN g_pActivityFriendA ENDFUNC FUNC PED_INDEX FRIEND_B_PED_ID() RETURN g_pActivityFriendB ENDFUNC // ******************************************************************************************* // FRIEND LIKE STAT // ******************************************************************************************* #IF IS_DEBUG_BUILD FUNC STRING GetLabel_enumFriendLikeType(enumFriendLikeType event) SWITCH event CASE FriendLike_DECLINED_CALL RETURN "FriendLike_DECLINED_CALL" CASE FriendLike_PLAYER_CANCELLED RETURN "FriendLike_PLAYER_CANCELLED" CASE FriendLike_PLAYER_LATE_ARRIVAL RETURN "FriendLike_PLAYER_LATE_ARRIVAL" CASE FriendLike_PLAYER_NO_ARRIVAL RETURN "FriendLike_PLAYER_NO_ARRIVAL" CASE FriendLike_BUDDY_INJURED RETURN "FriendLike_BUDDY_INJURED" CASE FriendLike_BUDDY_LOST RETURN "FriendLike_BUDDY_LOST" CASE FriendLike_DID_SUGGESTED_ACTIVITY RETURN "FriendLike_DID_SUGGESTED_ACTIVITY" CASE FriendLike_DID_UNSUGGESTED_ACTIVITY RETURN "FriendLike_DID_UNSUGGESTED_ACTIVITY" // CASE FriendLike_PASSED_ACTIVITY RETURN "FriendLike_PASSED_ACTIVITY" DEFAULT SCRIPT_ASSERT("invalid enumFriendLikeType in GetLabel_enumFriendLikeType()") BREAK ENDSWITCH RETURN "" ENDFUNC #ENDIF FUNC INT GET_FRIEND_LIKE(enumCharacterList playerCharID, enumCharacterList friendCharID) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) RETURN g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes ENDFUNC PROC SET_FRIEND_LIKE(enumCharacterList playerCharID, enumCharacterList friendCharID, INT iNewLikes) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes = iNewLikes IF g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes < CONST_iLikeStatMin g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes = CONST_iLikeStatMin ENDIF IF g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes > CONST_iLikeStatMax g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].likes = CONST_iLikeStatMax ENDIF ENDPROC PROC ADD_TO_FRIEND_LIKE(enumCharacterList playerCharID, enumCharacterList friendCharID, INT iLikesToAdd) SET_FRIEND_LIKE(playerCharID, friendCharID, GET_FRIEND_LIKE(playerCharID, friendCharID) + iLikesToAdd) ENDPROC PROC UPDATE_FRIEND_LIKE(enumCharacterList player, enumCharacterList friend, enumFriendLikeType event) CPRINTLN(DEBUG_FRIENDS, "UPDATE_FRIEND_LIKE(", GetLabel_enumFriendLikeType(event), ")") SWITCH event CASE FriendLike_DECLINED_CALL ADD_TO_FRIEND_LIKE(player, friend, -1) BREAK CASE FriendLike_PLAYER_CANCELLED ADD_TO_FRIEND_LIKE(player, friend, -1) BREAK CASE FriendLike_PLAYER_LATE_ARRIVAL ADD_TO_FRIEND_LIKE(player, friend, -2) BREAK CASE FriendLike_PLAYER_NO_ARRIVAL ADD_TO_FRIEND_LIKE(player, friend, -5) BREAK CASE FriendLike_BUDDY_INJURED ADD_TO_FRIEND_LIKE(player, friend, -5) BREAK CASE FriendLike_BUDDY_LOST ADD_TO_FRIEND_LIKE(player, friend, -5) BREAK CASE FriendLike_DID_SUGGESTED_ACTIVITY ADD_TO_FRIEND_LIKE(player, friend, 5) BREAK CASE FriendLike_DID_UNSUGGESTED_ACTIVITY ADD_TO_FRIEND_LIKE(player, friend, 3) BREAK // CASE FriendLike_PASSED_ACTIVITY ADD_TO_FRIEND_LIKE(player, friend, 2) BREAK DEFAULT SCRIPT_ASSERT("invalid enumFriendLikeType in UPDATE_FRIEND_LIKE()") BREAK ENDSWITCH ENDPROC // ******************************************************************************************* // LAST CONTACT CONTACT TIMER // ******************************************************************************************* /// PURPOSE: /// Pause the time since last contact (usually because face/phone contact between the friends has just started) /// PARAMS: /// playerCharID - Friend A /// friendCharID - Friend B /// contactType - Is the current contact phone or face-to-face? PROC PAUSE_FRIEND_LAST_CONTACT_TIMER(enumCharacterList playerCharID, enumCharacterList friendCharID) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) #IF IS_DEBUG_BUILD TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(friendConnID) CPRINTLN(DEBUG_FRIENDS, "PAUSE_FRIEND_LAST_CONTACT_TIMER(", tConn, ")") #ENDIF IF friendConnID <> NO_FRIEND_CONNECTION PAUSE_TIMER(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer) ENDIF ENDPROC /// PURPOSE: /// Reset the time since last contact, and set the recent contact type (usually because face/phone contact between the friends has just ended) /// PARAMS: /// playerCharID - Friend A /// friendCharID - Friend B /// contactType - Is the current ongoing contact phone or face-to-face? PROC RESET_FRIEND_LAST_CONTACT_TIMER(enumCharacterList playerCharID, enumCharacterList friendCharID, enumFriendContactType contactType) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) #IF IS_DEBUG_BUILD TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(friendConnID) IF contactType = FRIEND_CONTACT_PHONE CPRINTLN(DEBUG_FRIENDS, "RESET_FRIEND_LAST_CONTACT_TIMER(", tConn, ", FRIEND_CONTACT_PHONE)") ELIF contactType = FRIEND_CONTACT_FACE CPRINTLN(DEBUG_FRIENDS, "RESET_FRIEND_LAST_CONTACT_TIMER(", tConn, ", FRIEND_CONTACT_FACE)") ELIF contactType = FRIEND_CONTACT_DISMISSED CPRINTLN(DEBUG_FRIENDS, "RESET_FRIEND_LAST_CONTACT_TIMER(", tConn, ", FRIEND_CONTACT_DISMISSED)") ELSE CPRINTLN(DEBUG_FRIENDS, "RESET_FRIEND_LAST_CONTACT_TIMER(", tConn, ", FRIEND_CONTACT_unknown)") ENDIF #ENDIF IF friendConnID <> NO_FRIEND_CONNECTION RESTART_TIMER_NOW(g_savedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer) DEBUG_PRINTCALLSTACK() g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactType = contactType ENDIF ENDPROC /// PURPOSE: /// Reset the time since last contact, and set the recent contact type (usually because face/phone contact between the friends has just ended) /// PARAMS: /// playerCharID - Friend A /// friendCharID - Friend B /// contactType - Is the current ongoing contact phone or face-to-face? FUNC BOOL IS_FRIEND_LAST_CONTACT_TIMER_PAUSED(enumCharacterList playerCharID, enumCharacterList friendCharID) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) IF friendConnID <> NO_FRIEND_CONNECTION RETURN IS_TIMER_PAUSED(g_savedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer) ENDIF RETURN FALSE ENDFUNC // ******************************************************************************************* // SOLDIER FAIL TIMER // ******************************************************************************************* FUNC CC_CommID GET_COMM_ID_FOR_FRIEND_FAIL(enumFriend eFriend) IF eFriend = FR_MICHAEL RETURN TEXT_FRIEND_GRIEF_MICHAEL ELIF eFriend = FR_FRANKLIN RETURN TEXT_FRIEND_GRIEF_FRANKLIN ELIF eFriend = FR_TREVOR RETURN TEXT_FRIEND_GRIEF_TREVOR ELIF eFriend = FR_LAMAR RETURN TEXT_FRIEND_GRIEF_LAMAR ELIF eFriend = FR_JIMMY RETURN TEXT_FRIEND_GRIEF_JIMMY ELIF eFriend = FR_AMANDA RETURN TEXT_FRIEND_GRIEF_AMANDA ENDIF RETURN COMM_NONE ENDFUNC /// PURPOSE: /// Reset time since battle buddy failed, will not be able to call them again for 5 mins (timer pauses while on prep missions, and resets on pass/fail) /// PARAMS: /// eFriendChar - The playable char to reset the timer for PROC START_FRIEND_FAIL_TIMER(enumFriend eFriend, CC_CommID eMessage = COMM_NONE) CPRINTLN(DEBUG_FRIENDS, "START_FRIEND_FAIL_TIMER(", GetLabel_enumFriend(eFriend), ")") IF eFriend < MAX_FRIENDS // Restart timer RESTART_TIMER_NOW(g_savedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) // If a message has been sent, store ID and pause timer g_savedGlobals.sFriendsData.g_FriendFailMessages[eFriend] = eMessage IF eMessage <> COMM_NONE PAUSE_TIMER(g_savedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) ENDIF ELSE SCRIPT_ASSERT("START_FRIEND_FAIL_TIMER() - Invalid eFriendChar ID") ENDIF ENDPROC /// PURPOSE: /// Reset time since battle buddy failed, will not be able to call them again for 5 mins (timer pauses while on prep missions, and resets on pass/fail) /// PARAMS: /// eFriendChar - The playable char to reset the timer for PROC UNPAUSE_FRIEND_FAIL_TIMER(enumFriend eFriend) CPRINTLN(DEBUG_FRIENDS, "UNPAUSE_FRIEND_FAIL_TIMER(", GetLabel_enumFriend(eFriend), ")") IF eFriend < MAX_FRIENDS // Clear text message ID and unpause timer g_savedGlobals.sFriendsData.g_FriendFailMessages[eFriend] = COMM_NONE IF IS_TIMER_STARTED(g_savedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) AND IS_TIMER_PAUSED(g_savedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) UNPAUSE_TIMER(g_savedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) ENDIF ELSE SCRIPT_ASSERT("UNPAUSE_FRIEND_FAIL_TIMER() - Invalid eFriendChar ID") ENDIF ENDPROC /// PURPOSE: /// Has friend failed in the last 3 minutes (blocks friend calls) - pauses timer if waiting on text to be sent FUNC BOOL HAS_FRIEND_FAILED(enumFriend eFriend) IF eFriend < MAX_FRIENDS IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) IF GET_TIMER_IN_SECONDS(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) < 3.0*60.0 RETURN TRUE ELSE CANCEL_TIMER(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend]) RETURN FALSE ENDIF ENDIF ELSE CPRINTLN(DEBUG_FRIENDS, "HAS_FRIEND_FAILED(", GetLabel_enumFriend(eFriend), ") - Invalid eFriend ID") SCRIPT_ASSERT("HAS_FRIEND_FAILED() - Invalid eFriend ID") ENDIF RETURN FALSE ENDFUNC ///// PURPOSE: ///// Pauses all running friend fail timers (gets called when prep misison starts) //PROC PAUSE_SOLDIER_FAIL_TIMERS() // enumCharacterList eLoopChar // REPEAT NUM_OF_PLAYABLE_PEDS eLoopChar // IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // AND NOT IS_TIMER_PAUSED(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // CPRINTLN(DEBUG_FRIENDS, "PAUSE_SOLDIER_FAIL_TIMERS(", GetLabel_enumCharacterList(eLoopChar), ") - paused") // PAUSE_TIMER(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // ENDIF // ENDREPEAT //ENDPROC // ///// PURPOSE: ///// Stops all paused friend fail timers (gets called when any misison ends) //PROC CANCEL_PAUSED_SOLDIER_FAIL_TIMERS() // enumCharacterList eLoopChar // REPEAT NUM_OF_PLAYABLE_PEDS eLoopChar // IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // AND IS_TIMER_PAUSED(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // CPRINTLN(DEBUG_FRIENDS, "CANCEL_PAUSED_SOLDIER_FAIL_TIMERS(", GetLabel_enumCharacterList(eLoopChar), ") - cancelled") // CANCEL_TIMER(g_SavedGlobals.sFriendsData.g_SoldierFailTimers[eLoopChar]) // ENDIF // ENDREPEAT //ENDPROC // ******************************************************************************************* // FRIEND BLOCKING ACCESSORS // ******************************************************************************************* FUNC BOOL SET_FRIEND_BLOCK_FLAG(enumCharacterList playerCharID, enumCharacterList friendCharID, enumFriendBlockFlag blockFlag, SP_MISSIONS missionID = SP_MISSION_NONE) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) BOOL bHasUpdated = FALSE IF blockFlag <> FRIEND_BLOCK_FLAG_MISSION AND missionID <> SP_MISSION_NONE SCRIPT_ASSERT("SET_FRIEND_BLOCK_FLAG() - Mission ID was passed in params, but block type is not FRIEND_BLOCK_FLAG_MISSION") RETURN FALSE ENDIF IF blockFlag = FRIEND_BLOCK_FLAG_MISSION AND missionID = SP_MISSION_MAX SCRIPT_ASSERT("SET_FRIEND_BLOCK_FLAG() - Type is FRIEND_BLOCK_FLAG_MISSION, but mission ID is SP_MISSION_MAX") RETURN FALSE ENDIF IF blockFlag = FRIEND_BLOCK_FLAG_MISSION AND missionID = SP_MISSION_NONE SCRIPT_ASSERT("SET_FRIEND_BLOCK_FLAG() - Type is FRIEND_BLOCK_FLAG_MISSION, but mission ID is SP_MISSION_NONE") RETURN FALSE ENDIF IF friendConnID <> NO_FRIEND_CONNECTION // Debug print #IF IS_DEBUG_BUILD INT iOldBits = g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits #ENDIF // Set the flag (+ mission ref) IF NOT IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(blockFlag)) SET_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(blockFlag)) bHasUpdated = TRUE ENDIF IF blockFlag = FRIEND_BLOCK_FLAG_MISSION g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockMissionID = missionID ENDIF // Debug print the changes #IF IS_DEBUG_BUILD TEXT_LABEL_63 strFlag = GetLabel_enumFriendBlockFlag(blockFlag) TEXT_LABEL_63 strConn = GetLabel_enumFriendConnection(friendConnID) TEXT_LABEL_63 strOldBits = GetLabel_FriendBlockBits(iOldBits) TEXT_LABEL_63 strNewBits = GetLabel_FriendBlockBits(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits) IF blockFlag = FRIEND_BLOCK_FLAG_MISSION TEXT_LABEL_63 strMission = GET_SP_MISSION_DISPLAY_STRING_FROM_ID(missionID) CPRINTLN(DEBUG_FRIENDS, "SET_FRIEND_BLOCK_FLAG(", strFlag, ", ", strMission, ") - ", strConn, " ", strOldBits, " -> ", strNewBits) ELSE CPRINTLN(DEBUG_FRIENDS, "SET_FRIEND_BLOCK_FLAG(", strFlag, ") - ", strConn, " ", strOldBits, " -> ", strNewBits) ENDIF #ENDIF //PAUSE_friend_lastCellphone(playerCharID, friendCharID) //don't block just because he's busy //PAUSE_friend_lastFaceToFace(playerCharID, friendCharID) ENDIF RETURN bHasUpdated ENDFUNC FUNC BOOL CLEAR_FRIEND_BLOCK_FLAG(enumCharacterList playerCharID, enumCharacterList friendCharID, enumFriendBlockFlag blockFlag) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) BOOL bHasUpdated = FALSE IF friendConnID <> NO_FRIEND_CONNECTION // Debug print #IF IS_DEBUG_BUILD INT iOldBits = g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits #ENDIF // Clear the flag (+ mission ref) IF IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(blockFlag)) CLEAR_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(blockFlag)) bHasUpdated = TRUE ENDIF IF NOT IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(FRIEND_BLOCK_FLAG_MISSION)) g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockMissionID = SP_MISSION_NONE ENDIF // Debug print #IF IS_DEBUG_BUILD TEXT_LABEL_63 strFlag = GetLabel_enumFriendBlockFlag(blockFlag) TEXT_LABEL_63 strConn = GetLabel_enumFriendConnection(friendConnID) TEXT_LABEL_63 strOldBits = GetLabel_FriendBlockBits(iOldBits) TEXT_LABEL_63 strNewBits = GetLabel_FriendBlockBits(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits) IF blockFlag = FRIEND_BLOCK_FLAG_MISSION AND g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockMissionID <> SP_MISSION_NONE TEXT_LABEL_63 strMission = GET_SP_MISSION_DISPLAY_STRING_FROM_ID(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockMissionID) CPRINTLN(DEBUG_FRIENDS, "CLEAR_FRIEND_BLOCK_FLAG(", strFlag, ", ", strMission, ") - ", strConn, " ", strOldBits, " -> ", strNewBits) ELSE CPRINTLN(DEBUG_FRIENDS, "CLEAR_FRIEND_BLOCK_FLAG(", strFlag, ") - ", strConn, " ", strOldBits, " -> ", strNewBits) ENDIF #ENDIF ENDIF RETURN bHasUpdated ENDFUNC FUNC BOOL IS_FRIEND_BLOCK_FLAG_SET(enumCharacterList playerCharID, enumCharacterList friendCharID, enumFriendBlockFlag blockFlag) enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID) enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID) enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID) IF friendConnID = NO_FRIEND_CONNECTION #IF IS_DEBUG_BUILD TEXT_LABEL tPlayer = GetLabel_enumCharacterList(playerCharID) TEXT_LABEL tFriend = GetLabel_enumCharacterList(friendCharID) CPRINTLN(DEBUG_FRIENDS, "IS_FRIEND_BLOCK_FLAG_SET(", tPlayer, ", ", tFriend, ") - Can't find friend connection.") #ENDIF SCRIPT_ASSERT("IS_FRIEND_BLOCK_FLAG_SET() - Invalid friend connection") RETURN FALSE ENDIF RETURN IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].blockBits, ENUM_TO_INT(blockFlag)) ENDFUNC // ******************************************************************************************* // FRIEND BLOCKING/FLOW MAINTENANCE // ******************************************************************************************* FUNC BOOL ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION(SP_MISSIONS eMissionID, enumFriendConnection eConn) IF eMissionID = SP_MISSION_NONE OR eMissionID = SP_MISSION_MAX SCRIPT_ASSERT("ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION: SP_MISSION_NONE and SP_MISSION_MAX are invalid IDs to pass.") RETURN FALSE ENDIF INT friendBits = g_sMissionStaticData[eMissionID].friendCharBitset enumCharacterList friendCharA, friendCharB GET_FRIEND_CHARS_FROM_CONNECTION(eConn, friendCharA, friendCharB) IF DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, friendCharA) AND DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, friendCharB) #IF IS_DEBUG_BUILD IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_FRANKLIN)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [FRANKLIN] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_MICHAEL)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [MICHAEL] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_TREVOR)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [TREVOR] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_LAMAR)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [LAMAR] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_JIMMY)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [JIMMY] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF IF (DOES_CHARACTER_BITSET_CONTAIN_FRIEND_CHARACTER(friendBits, CHAR_AMANDA)) CPRINTLN(DEBUG_FRIENDS, "ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION() friendBits: ", friendBits, " [AMANDA] //", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID)) ENDIF #ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC PROC SET_ALL_FRIEND_BLOCKS_FOR_MISSION(SP_MISSIONS eMissionID) enumFriendConnection eConn enumCharacterList friendCharA enumCharacterList friendCharB #IF IS_DEBUG_BUILD BOOL bWasFriendRegisteredForMission = FALSE TEXT_LABEL_63 tMission = GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID) TEXT_LABEL_63 tInvolved = GetLabel_InvolvedFriends(eMissionID) TEXT_LABEL_63 tIsPrep = "" IF IS_BIT_SET(g_sMissionStaticData[eMissionID].settingsBitset, MF_INDEX_IS_PREP) tIsPrep = " (is prep)" ENDIF CPRINTLN(DEBUG_FRIENDS, "SET_ALL_FRIEND_BLOCKS_FOR_MISSION(", tMission, ") - Involved friend bits = ", tInvolved, tIsPrep) #ENDIF // IF eMissionID = SP_MISSION_FINALE_C1 // CPRINTLN(DEBUG_FRIENDS, "SET_ALL_FRIEND_BLOCKS_FOR_MISSION(", tMission, ") callstack >>>>>>>>>>") // DEBUG_PRINTCALLSTACK() // ENDIF // Don't set mission blocks for prep // IF NOT IS_BIT_SET(g_sMissionStaticData[eMissionID].settingsBitset, MF_INDEX_IS_PREP) // BBUDDIES REMOVED // For each connection... REPEAT MAX_FRIEND_CONNECTIONS eConn // If both friends are involved in mission, block connection IF ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION(eMissionID, eConn) IF GET_FRIEND_CHARS_FROM_CONNECTION(eConn, friendCharA, friendCharB) IF GET_CONNECTION_STATE(eConn) <> FC_STATE_Invalid SET_FRIEND_BLOCK_FLAG(friendCharA, friendCharB, FRIEND_BLOCK_FLAG_MISSION, eMissionID) ENDIF ENDIF #IF IS_DEBUG_BUILD bWasFriendRegisteredForMission = TRUE #ENDIF ENDIF ENDREPEAT // ENDIF #IF IS_DEBUG_BUILD IF bWasFriendRegisteredForMission = FALSE CPRINTLN(DEBUG_FRIENDS, "SET_ALL_FRIEND_BLOCKS_FOR_MISSION(", GET_SP_MISSION_DISPLAY_STRING_FROM_ID(eMissionID), ") - None") ENDIF #ENDIF ENDPROC // NOTE: CLEAR_ALL_FRIEND_BLOCKS_FOR_MISSION() is defined in friend_flow_public.sch FUNC BOOL MISSION_CANNOT_BE_REGISTERED_BECAUSE_OF_ACTIVE_FRIEND(SP_MISSIONS paramMissionID) INT iConnectionsBlocked = 0 // Don't block prep missions // IF NOT IS_BIT_SET(g_sMissionStaticData[paramMissionID].settingsBitset, MF_INDEX_IS_PREP) // For each connection... enumFriendConnection eConn REPEAT MAX_FRIEND_CONNECTIONS eConn // Is this connection active or initiating enumFriendConnectionState state = GET_CONNECTION_STATE(eConn) enumFriendConnectionMode mode = GET_CONNECTION_MODE(eConn) IF (state = FC_STATE_Init OR state = FC_STATE_Active) AND (mode = FC_MODE_Friend OR mode = FC_MODE_Adhoc OR mode = FC_MODE_Ambient) // Activity is ongoing for this friend IF ARE_BOTH_FRIENDS_INVOLVED_IN_MISSION(paramMissionID, eConn) CPRINTLN(DEBUG_FRIENDS, "Mission_Blocked_Because_Of_Friend(", GetLabel_enumFriendConnection(eConn), ")") iConnectionsBlocked++ ELSE CPRINTLN(DEBUG_FRIENDS, "No_Mission_Blocked_Because_Of_Friend(", GetLabel_enumFriendConnection(eConn), ")") ENDIF ELSE // No activity currently ongoing for this friend ENDIF ENDREPEAT // ENDIF RETURN (iConnectionsBlocked <> 0) ENDFUNC // ******************************************************************************************* // ADD FRIEND // ******************************************************************************************* PROC ADD_CHAR_AS_CHAR_FRIEND(enumCharacterList paramCharacterContact, enumCharacterList paramCharacterPhoneOwner, BOOL bSkipContactDelay = FALSE) #IF IS_DEBUG_BUILD TEXT_LABEL_63 tFriendChar = GetLabel_enumCharacterList(paramCharacterContact) TEXT_LABEL_63 tPlayerChar = GetLabel_enumCharacterList(paramCharacterPhoneOwner) #ENDIF enumFriendConnection eConnection IF GET_CONNECTION(paramCharacterPhoneOwner, paramCharacterContact, eConnection) CPRINTLN(DEBUG_FRIENDS, "ADD_CHAR_AS_CHAR_FRIEND(", tFriendChar, ", ", tPlayerChar, ")") // UPDATE_FRIEND_CONVERSATION_STAGE(paramCharacterPhoneOwner, paramCharacterContact, FGS_stageEarly) RESET_FRIEND_LAST_CONTACT_TIMER(paramCharacterPhoneOwner, paramCharacterContact, FRIEND_CONTACT_FACE) SET_FRIEND_LIKE(paramCharacterPhoneOwner, paramCharacterContact, CONST_iLikeStatInitial) IF bSkipContactDelay Private_ALTER_FRIEND_LAST_CONTACT_TIME(paramCharacterContact, paramCharacterPhoneOwner, 5.0 * 60.0) ENDIF SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait) SET_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(FC_FLAG_HasInitiated)) g_iNumberOfActiveFriends++ ELSE CPRINTLN(DEBUG_FRIENDS, "ADD_CHAR_AS_CHAR_FRIEND(", tFriendChar, ", ", tPlayerChar, ") - UNSUCCESSFUL") ENDIF ENDPROC PROC Add_Char_As_DefaultPlayer_Friend(enumCharacterList friendCharID) #IF IS_DEBUG_BUILD SWITCH g_eDefaultPlayerChar CASE CHAR_MICHAEL ADD_CONTACT_TO_PHONEBOOK(friendCharID, MICHAEL_BOOK) BREAK CASE CHAR_TREVOR ADD_CONTACT_TO_PHONEBOOK(friendCharID, TREVOR_BOOK) BREAK CASE CHAR_FRANKLIN ADD_CONTACT_TO_PHONEBOOK(friendCharID, FRANKLIN_BOOK) BREAK DEFAULT SCRIPT_ASSERT("invalid g_eDefaultPlayerChar in Add_Char_As_DefaultPlayer_Friend???") EXIT BREAK ENDSWITCH SWITCH friendCharID CASE CHAR_MICHAEL ADD_CONTACT_TO_PHONEBOOK(g_eDefaultPlayerChar, MICHAEL_BOOK) BREAK CASE CHAR_TREVOR ADD_CONTACT_TO_PHONEBOOK(g_eDefaultPlayerChar, TREVOR_BOOK) BREAK CASE CHAR_FRANKLIN ADD_CONTACT_TO_PHONEBOOK(g_eDefaultPlayerChar, FRANKLIN_BOOK) BREAK CASE CHAR_LAMAR // BREAK CASE CHAR_JIMMY // BREAK CASE CHAR_AMANDA // BREAK DEFAULT SCRIPT_ASSERT("invalid friendCharID in Add_Char_As_DefaultPlayer_Friend???") EXIT BREAK ENDSWITCH MAKE_CONTACT_ENTRY_PRIORITY(friendCharID) #ENDIF Add_Char_As_Char_Friend(g_eDefaultPlayerChar, friendCharID) ENDPROC // ******************************************************************************************* // RELATIONSHIP QUERY // ******************************************************************************************* FUNC BOOL ARE_CHARS_FRIENDS(enumCharacterList eCharA, enumCharacterList eCharB) enumCharacterList eMaxCharacter = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() IF eCharA >= eMaxCharacter OR eCharB >= eMaxCharacter OR eCharA = eCharB RETURN FALSE ENDIF enumFriend eFriendA = GET_FRIEND_FROM_CHAR(eCharA) enumFriend eFriendB = GET_FRIEND_FROM_CHAR(eCharB) // If both chars are valid friend chars, see if they have a friend connection IF eFriendA <> NO_FRIEND AND eFriendB <> NO_FRIEND enumFriendConnection eConnection = GET_CONNECTION_FROM_FRIENDS(eFriendA, eFriendB) // If they have a valid friend connection, reset the friend-last-contact timer IF eConnection <> NO_FRIEND_CONNECTION IF GET_CONNECTION_STATE(eConnection) <> FC_STATE_Invalid RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_CHARS_ARRANGE_BATTLE_BUDDY(enumCharacterList ePlayerChar, enumCharacterList eFriendChar) RETURN FALSE // BBUDDIES REMOVED enumCharacterList eMaxCharacter = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() IF ePlayerChar >= eMaxCharacter OR eFriendChar >= eMaxCharacter OR ePlayerChar = eFriendChar RETURN FALSE ENDIF // If char is allowed on mission IF g_eFriendMissionZoneID <> SP_MISSION_NONE AND IS_BIT_SET(g_sMissionStaticData[g_eFriendMissionZoneID].settingsBitset, MF_INDEX_IS_PREP) AND IS_BIT_SET(g_iFriendMissionZoneAcceptBitset, ENUM_TO_INT(eFriendChar)) // If mission is stored as launched, make sure it is (friend controller might have been switched off and not updated it) IF g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_LAUNCHED OR MISSION_FLOW_GET_RUNNING_MISSION() = g_eFriendMissionZoneID // Don't allow if mission has dynamically disabled battle buddies IF NOT IS_BATTLEBUDDY_BEHAVIOUR_REQUESTED(BBF_RejectAllBattleBuddies) // Get desired connection, is it in ContactWait state? enumFriendConnection eDesiredConnection IF GET_CONNECTION(ePlayerChar, eFriendChar, eDesiredConnection) AND GET_CONNECTION_STATE(eDesiredConnection) = FC_STATE_ContactWait RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_MISSION_ARRANGE_MULTIPLE_BATTLE_BUDDIES(SP_MISSIONS eMission) #if USE_CLF_DLC eMission = eMission RETURN FALSE // BBUDDIES REMOVED #ENDIF #if USE_NRM_DLC eMission = eMission RETURN FALSE // BBUDDIES REMOVED #ENDIF #if not USE_SP_DLC RETURN FALSE // BBUDDIES REMOVED IF eMission = SP_HEIST_RURAL_PREP_1 OR eMission = SP_HEIST_AGENCY_PREP_1 OR eMission = SP_HEIST_FINALE_PREP_B OR eMission = SP_MISSION_FBI_4_PREP_2 RETURN FALSE ENDIF RETURN TRUE #ENDIF ENDFUNC FUNC BOOL HAVE_CHARS_ARRANGED_FRIEND_ACTIVITYCLF(enumCharacterList eCharA, enumCharacterList eCharB) IF eCharA >= MAX_CLF_CHARACTERS OR eCharB >= MAX_CLF_CHARACTERS OR eCharA = eCharB RETURN FALSE ENDIF IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) enumFriend eFriendA = GET_FRIEND_FROM_CHARCLF(eCharA) enumFriend eFriendB = GET_FRIEND_FROM_CHARCLF(eCharB) // If both chars are valid friend chars, see if they have a friend connection IF eFriendA <> NO_FRIEND AND eFriendB <> NO_FRIEND enumFriendConnection eConnection = GET_CONNECTION_FROM_FRIENDS(eFriendA, eFriendB) // If they have a valid friend connection, reset the friend-last-contact timer IF eConnection <> NO_FRIEND_CONNECTION enumFriendConnectionState state = GET_CONNECTION_STATE(eConnection) IF state = FC_STATE_Init OR state = FC_STATE_Active RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAVE_CHARS_ARRANGED_FRIEND_ACTIVITYNRM(enumCharacterList eCharA, enumCharacterList eCharB) IF eCharA >= MAX_NRM_CHARACTERS OR eCharB >= MAX_NRM_CHARACTERS OR eCharA = eCharB RETURN FALSE ENDIF IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) enumFriend eFriendA = GET_FRIEND_FROM_CHARNRM(eCharA) enumFriend eFriendB = GET_FRIEND_FROM_CHARNRM(eCharB) // If both chars are valid friend chars, see if they have a friend connection IF eFriendA <> NO_FRIEND AND eFriendB <> NO_FRIEND enumFriendConnection eConnection = GET_CONNECTION_FROM_FRIENDS(eFriendA, eFriendB) // If they have a valid friend connection, reset the friend-last-contact timer IF eConnection <> NO_FRIEND_CONNECTION enumFriendConnectionState state = GET_CONNECTION_STATE(eConnection) IF state = FC_STATE_Init OR state = FC_STATE_Active RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL HAVE_CHARS_ARRANGED_FRIEND_ACTIVITY(enumCharacterList eCharA, enumCharacterList eCharB) #IF USE_CLF_DLC IF g_bLoadedClifford RETURN HAVE_CHARS_ARRANGED_FRIEND_ACTIVITYCLF(eCharA,eCharB) ENDIF #ENDIF #IF USE_NRM_DLC IF g_bLoadedNorman RETURN HAVE_CHARS_ARRANGED_FRIEND_ACTIVITYNRM(eCharA,eCharB) ENDIF #ENDIF enumCharacterList eMaxCharacter = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() IF eCharA >= eMaxCharacter OR eCharB >= eMaxCharacter OR eCharA = eCharB RETURN FALSE ENDIF IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) enumFriend eFriendA = GET_FRIEND_FROM_CHAR(eCharA) enumFriend eFriendB = GET_FRIEND_FROM_CHAR(eCharB) // If both chars are valid friend chars, see if they have a friend connection IF eFriendA <> NO_FRIEND AND eFriendB <> NO_FRIEND enumFriendConnection eConnection = GET_CONNECTION_FROM_FRIENDS(eFriendA, eFriendB) // If they have a valid friend connection, reset the friend-last-contact timer IF eConnection <> NO_FRIEND_CONNECTION enumFriendConnectionState state = GET_CONNECTION_STATE(eConnection) IF state = FC_STATE_Init OR state = FC_STATE_Active RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_CHARS_ARRANGE_FRIEND_ACTIVITY(enumCharacterList ePlayerChar, enumCharacterList eFriendChar) enumCharacterList eMaxCharacter = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() IF ePlayerChar >= eMaxCharacter OR eFriendChar >= eMaxCharacter OR ePlayerChar = eFriendChar RETURN FALSE ENDIF #IF NOT USE_CLF_DLC #IF NOT USE_NRM_DLC //B* 1929691: Disable friend activity if before Fame or Shame but after Jewel Heist IF (ePlayerChar = CHAR_FRANKLIN AND eFriendChar = CHAR_MICHAEL) OR (ePlayerChar = CHAR_MICHAEL AND eFriendChar = CHAR_FRANKLIN) IF GET_MISSION_COMPLETE_STATE(SP_HEIST_JEWELRY_2) AND (NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FAMILY_4)) CPRINTLN(debug_friends, "Franklin can't call Michael to arrange Friend Activity, Fame or shame not completed") RETURN FALSE ENDIF ENDIF #ENDIF #ENDIF // IF NOT CAN_CHARS_ARRANGE_BATTLE_BUDDY(ePlayerChar, eFriendChar) // BBUDDIES REMOVED IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) // Get desired connection, is it in ContactWait state? enumFriendConnection eDesiredConnection IF GET_CONNECTION(ePlayerChar, eFriendChar, eDesiredConnection) AND GET_CONNECTION_STATE(eDesiredConnection) = FC_STATE_ContactWait RETURN TRUE ENDIF ENDIF // ENDIF RETURN FALSE ENDFUNC FUNC BOOL CAN_CHARS_CANCEL_FRIEND_ACTIVITY(enumCharacterList eCharA, enumCharacterList eCharB) enumCharacterList eMaxCharacter = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() IF eCharA >= eMaxCharacter OR eCharB >= eMaxCharacter OR eCharA = eCharB RETURN FALSE ENDIF // Can't cancel if already picked up the friend IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY) AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY_WITH_MG) IF HAVE_CHARS_ARRANGED_FRIEND_ACTIVITY(eCharA, eCharB) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC // *******************************************************************************************