Files
gtav-src/script/dev_ng/singleplayer/include/public/friend_flow_public.sch
T
2025-09-29 00:52:08 +02:00

500 lines
21 KiB
XML
Executable File

USING "timer_public.sch"
USING "friends_core.sch"
CONST_INT CONST_iIncomingPeriodInit_Hours 12
// -----------------------------------------------------------------------------------------
// Public Friend Controller Launch Check
// -----------------------------------------------------------------------------------------
/// PURPOSE:
///
/// RETURNS:
///
FUNC BOOL Should_Friends_Controller_Be_Running()
IF NOT IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE()
RETURN TRUE
ENDIF
IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_ACTIVITY_WITH_MG)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_EVENT)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_SWITCH)
OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_GRIEFING)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
// *******************************************************************************************
// MAINTAIN FLOW-BLOCKED CONNECTIONS
// *******************************************************************************************
PROC CLEAR_ALL_FRIEND_BLOCKS_FOR_MISSION(SP_MISSIONS paramMissionID)
#IF IS_DEBUG_BUILD
BOOL bClearedAnyBlocks = FALSE
#ENDIF
// IF paramMissionID = SP_MISSION_FINALE_C1
// TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(paramMissionID)
// CPRINTLN(DEBUG_FRIENDS, "CLEAR_ALL_FRIEND_BLOCKS_FOR_MISSION(", tMission, ") callstack >>>>>>>>>>")
// DEBUG_PRINTCALLSTACK()
// ENDIF
// Unblock accordingly - ** this must match code in CLEAR_FRIEND_BLOCK_FLAG() **
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockMissionID = paramMissionID
IF IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockBits, ENUM_TO_INT(FRIEND_BLOCK_FLAG_MISSION))
// Remove the mission block type
#IF IS_DEBUG_BUILD
INT iOldBits = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockBits
#ENDIF
CLEAR_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockBits, ENUM_TO_INT(FRIEND_BLOCK_FLAG_MISSION))
g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockMissionID = SP_MISSION_NONE
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(paramMissionID)
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConn)
TEXT_LABEL_63 tOldBits = GetLabel_FriendBlockBits(iOldBits)
TEXT_LABEL_63 tNewBits = GetLabel_FriendBlockBits(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].blockBits)
CPRINTLN(DEBUG_FRIENDS, "CLEAR_ALL_FRIEND_BLOCKS_FOR_MISSION(", tMission, ") - ", tConn, " ", tOldBits, " -> ", tNewBits)
bClearedAnyBlocks = TRUE
#ENDIF
// Set most recent contact
RESTART_TIMER_NOW(g_savedGlobals.sFriendsData.g_FriendConnectData[eConn].lastContactTimer)
g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].lastContactType = FRIEND_CONTACT_FACE
// UNPAUSE_timer(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].lastCellphone_timer) // These two were commented out already
// UNPAUSE_timer(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].lastFaceToFace_timer)
// RESTART_TIMER_NOW(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConn].lastFaceToFace_timer) // TODO: Should this be done?
ENDIF
ENDIF
ENDREPEAT
#IF IS_DEBUG_BUILD
IF bClearedAnyBlocks = FALSE
TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(paramMissionID)
CPRINTLN(DEBUG_FRIENDS, "CLEAR_ALL_FRIEND_BLOCKS_FOR_MISSION(", tMission, ") - None")
ENDIF
#ENDIF
ENDPROC
// *******************************************************************************************
// FRIEND REJECTION INTERFACE
// *******************************************************************************************
/// PURPOSE: The trigger scene uses this function to clear when the player is near a mission trigger.
PROC CLEAR_FRIEND_MISSION_ZONE(SP_MISSIONS eMission)
// Preliminaries
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(eMission)
CPRINTLN(DEBUG_FRIENDS, "CLEAR_FRIEND_MISSION_ZONE(", tMission, ") - called by ", GET_THIS_SCRIPT_NAME())
#ENDIF
IF eMission >= SP_MISSION_MAX
SCRIPT_ASSERT("CLEAR_FRIEND_MISSION_ZONE() - SP_MISSION_MAX and SP_MISSION_NONE are not valid mission IDs")
EXIT
ENDIF
// If no mission passed in, don't need to attempt to clear
IF g_eFriendMissionZoneID <> SP_MISSION_NONE
IF g_eFriendMissionZoneID <> eMission
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tNewMission = GetLabel_SP_MISSIONS(eMission)
TEXT_LABEL_63 tOldMission = GetLabel_SP_MISSIONS(g_eFriendMissionZoneID)
CPRINTLN(DEBUG_FRIENDS, "CLEAR_FRIEND_MISSION_ZONE() - Mission zone is already set by \"", tOldMission, "\", cannot clear \"", tNewMission, "\"")
//SCRIPT_ASSERT("CLEAR_FRIEND_MISSION_ZONE() - Mission zone is already set by another mission, cannot clear")
#ENDIF
EXIT
ENDIF
// Clear the current mission zone
g_eFriendMissionZoneID = SP_MISSION_NONE
g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_OFF
g_iFriendMissionZoneAcceptBitset = 0
ENDIF
ENDPROC
/// PURPOSE: The trigger scene uses this function to set when the player is NEAR A MISSION TRIGGER,
/// and tells it which friends can come along on the mission
///
/// Friends that cannot come along will be rejected by the friend activity when the player
/// is ON FOOT IN THIS ZONE
PROC SET_FRIEND_MISSION_ZONE(SP_MISSIONS eMission, enumFriendMissionZoneState eState, INT iAllowedFriendBits)
// [Check if current zone has expired, but friends controller has not resumed and updated it yet -> If so, clear the zone before setting]
IF g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_LAUNCHED
IF NOT IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE()
CLEAR_FRIEND_MISSION_ZONE(g_eFriendMissionZoneID)
ENDIF
ENDIF
// Preliminaries
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(eMission)
TEXT_LABEL_63 tState = GetLabel_enumFriendMissionZoneState(eState)
TEXT_LABEL_63 tBitfield = GetLabel_FriendBits(iAllowedFriendBits)
CPRINTLN(DEBUG_FRIENDS, "SET_FRIEND_MISSION_ZONE(", tMission, ", ", tState, ", ", tBitfield, ") - called by ", GET_THIS_SCRIPT_NAME())
#ENDIF
IF eMission >= SP_MISSION_MAX
SCRIPT_ASSERT("SET_FRIEND_MISSION_ZONE() - SP_MISSION_MAX and SP_MISSION_NONE are not valid mission IDs")
EXIT
ENDIF
IF eState = FRIEND_MISSION_ZONE_OFF
SCRIPT_ASSERT("SET_FRIEND_MISSION_ZONE() - Cannot pass FRIEND_MISSION_ZONE_OFF as state, use CLEAR_FRIEND_MISSION_ZONE() to clear")
EXIT
ENDIF
IF iAllowedFriendBits <> (iAllowedFriendBits & (BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR|BIT_LAMAR|BIT_JIMMY|BIT_AMANDA))
SCRIPT_ASSERT("SET_FRIEND_MISSION_ZONE() - iAllowedFriendBits is invalid.")
EXIT
ENDIF
IF g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_OFF
IF g_eFriendMissionZoneID <> eMission
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tNewMission = GetLabel_SP_MISSIONS(eMission)
TEXT_LABEL_63 tOldMission = GetLabel_SP_MISSIONS(g_eFriendMissionZoneID)
CPRINTLN(DEBUG_FRIENDS, "SET_FRIEND_MISSION_ZONE() - Mission zone is already set by \"", tOldMission, "\", cannot set \"", tNewMission, "\"")
//SCRIPT_ASSERT("SET_FRIEND_MISSION_ZONE() - Another friend mission zone is already set, cannot set again until cleared")
#ENDIF
EXIT
ENDIF
IF g_iFriendMissionZoneAcceptBitset <> iAllowedFriendBits
CPRINTLN(DEBUG_FRIENDS,"SET_FRIEND_MISSION_ZONE() - Updating active friend mission zone state, but passing different char bits")
ENDIF
ENDIF
// Set the current mission zone
g_eFriendMissionZoneID = eMission
g_eFriendMissionZoneState = eState
g_iFriendMissionZoneAcceptBitset = iAllowedFriendBits
ENDPROC
// *******************************************************************************************
// INITIALISE FRIENDS
// *******************************************************************************************
PROC InitialiseThisFriendSheet(structFriendData &thisFriendSheet, enumCharacterList thisFriendCharID)//, enumFriendLocation eDefaultPickupLoc)
GLOBAL_CHARACTER_SHEET_GET(thisFriendSheet.charSheet, thisFriendCharID)
ENDPROC
PROC InitialiseFriendGroup(structFriendGroupData &group, enumFriendGroup eGroupID)
//-- Init chat data banks Full Mini Drunk Condition
Private_InitFriendChatData(group.chatData)
SWITCH eGroupID
CASE FG_MICHAEL_FRANKLIN_TREVOR
Private_SetFriendChatBankData(group.chatData.banks[0], 0, 0, 0, 2, 2, 0, FCHAT_ConditionEnd) // End of game
Private_SetFriendChatBankData(group.chatData.banks[1], 0, 0, 0, 8, 8, 2, FCHAT_ConditionAlways) // General
BREAK
CASE FG_FRANKLIN_TREVOR_LAMAR
Private_SetFriendChatBankData(group.chatData.banks[0], 0, 0, 0, 6, 6, 5, FCHAT_ConditionAlways)
BREAK
ENDSWITCH
ENDPROC
PROC InitialiseThisFriendGroup(enumFriend eFriendA, enumFriend eFriendB, enumFriend eFriendC)
enumFriendGroup eGroup = GET_GROUP_FROM_FRIENDS(eFriendA, eFriendB, eFriendC)
IF eGroup < MAX_FRIEND_GROUPS
InitialiseFriendGroup(g_SavedGlobals.sFriendsData.g_FriendGroupData[eGroup], eGroup)
ELSE
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tFriendA = GetLabel_enumFriend(eFriendA)
TEXT_LABEL_63 tFriendB = GetLabel_enumFriend(eFriendB)
TEXT_LABEL_63 tFriendC = GetLabel_enumFriend(eFriendC)
CPRINTLN(DEBUG_FRIENDS, "InitialiseFriendGroup() - Invalid friend trio (", tFriendA, "/", tFriendB, "/", tFriendC, ")")
SCRIPT_ASSERT("InitialiseFriendGroup() - Invalid friend trio")
#ENDIF
ENDIF
ENDPROC
PROC InitialiseThisFriendConnection(structFriendConnection& connState, structFriendConnectData &connection, enumFriendConnection eConnectionID, enumFriend eFriendA, enumFriend eFriendB)
//-- Init vars
connection.friendA = eFriendA
connection.friendB = eFriendB
connState.state = FC_STATE_Invalid
connState.mode = FC_MODE_Friend
connection.blockBits = 0
connection.blockMissionID = SP_MISSION_NONE
connection.commID = COMM_NONE
CANCEL_TIMER(connection.lastContactTimer)
connection.lastContactType = FRIEND_CONTACT_FACE
// connection.playerTurnedDown = 0
connection.wanted = NO_FRIEND
connection.likes = -1
connection.flags = 0
//-- Init chat data banks Full Mini Drunk Condition
Private_InitFriendChatData(connection.chatData)
SWITCH eConnectionID
CASE FC_FRANKLIN_JIMMY
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 1, 0, 0, FCHAT_ConditionPostBreak)
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 10, 6, 10, FCHAT_ConditionAlways)
BREAK
CASE FC_FRANKLIN_LAMAR
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 1, 0, 0, FCHAT_ConditionFL0) // Between Franklin0-Lamar1 missions
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 1, 0, 0, FCHAT_ConditionFL1) // Between Lamar1-Franklin2 missions
Private_SetFriendChatBankData(connection.chatData.banks[2], 0, 0, 0, 4, 8, 0, FCHAT_ConditionEarly) // Start of game
Private_SetFriendChatBankData(connection.chatData.banks[3], 0, 0, 0, 4, 8, 0, FCHAT_ConditionMid) // Franklin moved to Vinewood
Private_SetFriendChatBankData(connection.chatData.banks[4], 0, 0, 0, 9, 0, 0, FCHAT_ConditionEnd) // Completed game
Private_SetFriendChatBankData(connection.chatData.banks[5], 0, 0, 0, 0, 0, 8, FCHAT_ConditionAlways) // General drunk bank
Private_InitFriendChatData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat)
Private_SetFriendChatBankData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat.banks[0], 0, 0, 0, 0, 4, 0, FCHAT_ConditionEndAllAlive) // Michael+Trevor are alive
Private_SetFriendChatBankData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat.banks[1], 0, 0, 0, 0, 5, 0, FCHAT_ConditionEndMDead) // Michael is dead
Private_SetFriendChatBankData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat.banks[2], 0, 0, 0, 0, 4, 0, FCHAT_ConditionEndTDead) // Trevor is dead
Private_SetFriendChatBankData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat.banks[3], 0, 0, 0, 0, 6, 0, FCHAT_ConditionEndMAlive) // Michael is alive
Private_SetFriendChatBankData(g_SavedGlobals.sFriendsData.g_FranklinLamarEndChat.banks[4], 0, 0, 0, 0, 3, 0, FCHAT_ConditionEndTAlive) // Trevor is alive
BREAK
CASE FC_FRANKLIN_TREVOR
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 2, 2, 0, FCHAT_ConditionMichaelBetrayal) // Michael/Trevor fallen out
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 2, 1, 1, FCHAT_ConditionEndAllAlive) // End of game, everyone alive
Private_SetFriendChatBankData(connection.chatData.banks[2], 0, 0, 0, 8, 8, 4, FCHAT_ConditionAlways) // General
BREAK
CASE FC_MICHAEL_AMANDA
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 8, 8, 4, FCHAT_ConditionPreBreak)
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 8, 8, 3, FCHAT_ConditionPostBreak)
Private_SetFriendChatBankData(connection.chatData.banks[2], 0, 0, 0, 0, 0, 1, FCHAT_ConditionPostBreakTrevorAlive)
BREAK
CASE FC_MICHAEL_FRANKLIN
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 2, 2, 0, FCHAT_ConditionBeforeTrevor) // Before Trevor arrives
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 2, 2, 0, FCHAT_ConditionMichaelBetrayal) // After Michael/Trevor fall out
Private_SetFriendChatBankData(connection.chatData.banks[2], 0, 0, 0, 2, 2, 0, FCHAT_ConditionEnd) // End of game
Private_SetFriendChatBankData(connection.chatData.banks[3], 0, 0, 0, 8, 8, 4, FCHAT_ConditionAlways) // General
BREAK
CASE FC_MICHAEL_JIMMY
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 6, 6, 0, FCHAT_ConditionPreExile)
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 8, 8, 0, FCHAT_ConditionPostExile)
BREAK
CASE FC_TREVOR_MICHAEL
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 2, 0, 0, FCHAT_ConditionBeforeBetrayal) // Michael/Trevor haven't fallen out yet
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 2, 1, 1, FCHAT_ConditionEndAllAlive) // End of game, everyone alive
Private_SetFriendChatBankData(connection.chatData.banks[2], 0, 0, 0, 1, 0, 0, FCHAT_ConditionInLosSantos) // General (and in Los Santos - applies to one conversation that mentions being in city directly)
Private_SetFriendChatBankData(connection.chatData.banks[3], 0, 0, 0, 5, 8, 4, FCHAT_ConditionAlways) // General
BREAK
CASE FC_TREVOR_JIMMY
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 1, 0, 0, FCHAT_ConditionPostBreak)
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 10, 6, 0, FCHAT_ConditionAlways)
BREAK
CASE FC_TREVOR_LAMAR
Private_SetFriendChatBankData(connection.chatData.banks[0], 0, 0, 0, 6, 6, 0, FCHAT_ConditionAlways) // 1:1
Private_SetFriendChatBankData(connection.chatData.banks[1], 0, 0, 0, 6, 6, 0, FCHAT_ConditionAlways) // 2:1 or 1:1
BREAK
ENDSWITCH
ENDPROC
PROC InitialiseThisFriendConnect(enumFriend eFriendA, enumFriend eFriendB)
enumFriendConnection eConnection = GET_CONNECTION_FROM_FRIENDS(eFriendA, eFriendB)
IF eConnection < MAX_FRIEND_CONNECTIONS
InitialiseThisFriendConnection(g_FriendConnectState[eConnection], g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection], eConnection, eFriendA, eFriendB)
ELSE
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tFriendA = GetLabel_enumFriend(eFriendA)
TEXT_LABEL_63 tFriendB = GetLabel_enumFriend(eFriendB)
CPRINTLN(DEBUG_FRIENDS, "InitialiseThisFriendConnect() - Invalid friend pairing (", tFriendA, "/", tFriendB, ")")
SCRIPT_ASSERT("InitialiseThisFriendConnect() - Invalid friend pairing")
#ENDIF
ENDIF
ENDPROC
PROC Initialise_FriendSheet_Global_Variables_On_Startup()
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_MICHAEL], CHAR_MICHAEL)//, FL_Michael_RH) // Makes no sense now to have permenant default pickup locs
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_FRANKLIN], CHAR_FRANKLIN)//, FL_Franklin_SC) // ... as exile and savehouse unlocking change what is available
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_TREVOR], CHAR_TREVOR)//, FL_Trevor_CS)
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_LAMAR], CHAR_LAMAR)//, FL_Lamar_SC)
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_JIMMY], CHAR_JIMMY)//, FL_Lamar_SC)
InitialiseThisFriendSheet(g_SavedGlobals.sFriendsData.g_FriendData[FR_AMANDA], CHAR_AMANDA)//, FL_Lamar_SC)
InitialiseThisFriendConnect(FR_MICHAEL, FR_FRANKLIN)
InitialiseThisFriendConnect(FR_FRANKLIN, FR_TREVOR)
InitialiseThisFriendConnect(FR_TREVOR, FR_MICHAEL)
InitialiseThisFriendConnect(FR_FRANKLIN, FR_LAMAR)
InitialiseThisFriendConnect(FR_TREVOR, FR_LAMAR)
InitialiseThisFriendConnect(FR_MICHAEL, FR_JIMMY)
InitialiseThisFriendConnect(FR_FRANKLIN, FR_JIMMY)
InitialiseThisFriendConnect(FR_TREVOR, FR_JIMMY)
InitialiseThisFriendConnect(FR_MICHAEL, FR_AMANDA)
InitialiseThisFriendGroup(FR_MICHAEL, FR_FRANKLIN, FR_TREVOR)
InitialiseThisFriendGroup(FR_FRANKLIN, FR_TREVOR, FR_LAMAR)
g_SavedGlobals.sFriendsData.g_FriendScriptThread = 0
g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_OFF
g_eFriendMissionZoneID = SP_MISSION_NONE
g_iFriendMissionZoneAcceptBitset = 0
g_bitfieldFriendFlags = 0
g_bitfieldBattleBuddyPhoneContact = 0
g_bitfieldBattleBuddyAvailable = 0
g_bitfieldBattleBuddyOverridden = 0
g_bitfieldBattleBuddyBehaviour = 0
g_BattleBuddyMission = SP_MISSION_NONE
g_BattleBuddyAllowedChars = 0
g_eRecentFriendChar = NO_CHARACTER
ENDPROC
// *******************************************************************************************
// FRIENDS TIMERS
// *******************************************************************************************
PROC ADVANCE_FRIEND_TIMERS(FLOAT fGameHours)
CPRINTLN(DEBUG_FRIENDS, "ADVANCE_FRIEND_TIMERS(", GET_STRING_FROM_FLOAT(fGameHours), " game hours)")
// Adjust contact timers
enumFriendConnection eConnection
REPEAT MAX_FRIEND_CONNECTIONS eConnection
IF IS_TIMER_STARTED(g_savedGlobals.sFriendsData.g_FriendConnectData[eConnection].lastContactTimer)
ADJUST_TIMER(g_savedGlobals.sFriendsData.g_FriendConnectData[eConnection].lastContactTimer, fGameHours*60.0)
ENDIF
ENDREPEAT
// Adjust fail timers
enumFriend eFriend
REPEAT MAX_FRIENDS eFriend
IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend])
ADJUST_TIMER(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend], fGameHours*60.0)
ENDIF
ENDREPEAT
SKIP_RADIO_FORWARD()
ENDPROC
PROC PRIVATE_CorrectTimerForSave(structTimer& timer)
timer.StartTime -= (TO_FLOAT(g_savedGlobals.sCommsControlData.iCommsGameTime) / 1000.0)
timer.StartTime += (TO_FLOAT(GET_GAME_TIMER()) / 1000.0)
// timer.PauseTime -= (TO_FLOAT(g_savedGlobals.sCommsControlData.iCommsGameTime) / 1000.0)
// timer.PauseTime += (TO_FLOAT(GET_GAME_TIMER()) / 1000.0)
ENDPROC
PROC PRIVATE_update_friend_timers_from_save()
// Adjust contact timers
enumFriendConnection eConnection
REPEAT MAX_FRIEND_CONNECTIONS eConnection
IF IS_TIMER_STARTED(g_savedGlobals.sFriendsData.g_FriendConnectData[eConnection].lastContactTimer)
PRIVATE_CorrectTimerForSave(g_savedGlobals.sFriendsData.g_FriendConnectData[eConnection].lastContactTimer)
ENDIF
ENDREPEAT
// Adjust fail timers
enumFriend eFriend
REPEAT MAX_FRIENDS eFriend
IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend])
PRIVATE_CorrectTimerForSave(g_SavedGlobals.sFriendsData.g_FriendFailTimers[eFriend])
ENDIF
ENDREPEAT
ENDPROC
// *******************************************************************************************
// HAS ARRANGED ACTIVITY WITH ANYONE
// *******************************************************************************************
FUNC BOOL HAS_CHAR_ARRANGED_FRIEND_ACTIVITY_WITH_ANYONE(enumCharacterList eChar)
IF eChar >= GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE()
RETURN FALSE
ENDIF
enumFriend eFriend = GET_FRIEND_FROM_CHAR(eChar)
IF eFriend <> NO_FRIEND
enumFriendConnection eConnection
REPEAT MAX_FRIEND_CONNECTIONS eConnection
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].friendA = eFriend
OR g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].friendB = eFriend
enumFriendConnectionState eState = g_FriendConnectState[eConnection].state
IF eState = FC_STATE_Init
OR eState = FC_STATE_Active
RETURN TRUE
ENDIF
ENDIF
ENDREPEAT
ENDIF
RETURN FALSE
ENDFUNC