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

956 lines
32 KiB
Scheme
Executable File

//- commands headers -//
USING "commands_replay.sch"
//- script headers -//
//- public headers -//
//- private headers -//
USING "friendActivity_dialogue_private.sch"
#IF IS_DEBUG_BUILD
//- debug headers -//
#ENDIF
//---------------------------------------------------------------------------------------------------
//-- Sort friends
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_SortMembers(BOOL bSortFriendMembers)
enumCharacterList currentPlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
BOOL bResortedMembers = FALSE
// If player has swapped with friend A
IF gActivity.mFriendA.eState <> FRIEND_NULL AND gActivity.mFriendA.eChar = currentPlayerChar
structFriend tempMember = gActivity.mPlayer
// Swap player and friend members
gActivity.mPlayer = gActivity.mFriendA
gActivity.mFriendA = tempMember
bResortedMembers = TRUE
ENDIF
// If player has swapped with friend B
IF gActivity.mFriendB.eState <> FRIEND_NULL AND gActivity.mFriendB.eChar = currentPlayerChar
structFriend tempMember = gActivity.mPlayer
// Swap player and friend members
gActivity.mPlayer = gActivity.mFriendB
gActivity.mFriendB = tempMember
bResortedMembers = TRUE
ENDIF
// If friend A has cancelled, but friend B still exists
IF bSortFriendMembers
IF gActivity.mFriendA.eState = FRIEND_NULL AND gActivity.mFriendB.eState <> FRIEND_NULL
structFriend tempMember = gActivity.mFriendA
// Swap player and friend members
gActivity.mFriendA = gActivity.mFriendB
gActivity.mFriendB = tempMember
bResortedMembers = TRUE
ENDIF
ENDIF
// PRIVATE_SET_FRIEND_A_PED_ID(gActivity.mFriendA.hPed)
// PRIVATE_SET_FRIEND_B_PED_ID(gActivity.mFriendB.hPed)
Private_SetFriendsForcedSeats()
IF bResortedMembers
#IF IS_DEBUG_BUILD
TEXT_LABEL tPlayer = GetLabel_enumCharacterList(gActivity.mPlayer.eChar)
TEXT_LABEL tFriendA = GetLabel_enumCharacterList(gActivity.mFriendA.eChar)
TEXT_LABEL tFriendB = GetLabel_enumCharacterList(gActivity.mFriendB.eChar)
CPRINTLN(DEBUG_FRIENDS, "Pickup_SortFriends():- ", tPlayer, " / ", tFriendA, " / ", tFriendB)
#ENDIF
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
//---------------------------------------------------------------------------------------------------
//-- Rejection
//---------------------------------------------------------------------------------------------------
PROC Private_DeleteMembersForGriefing()
Private_CleanupFriend(gActivity.mPlayer, MC_Delete)
Private_CleanupFriend(gActivity.mFriendA, MC_Delete)
Private_CleanupFriend(gActivity.mFriendB, MC_Delete)
ENDPROC
FUNC BOOL Private_CanRejectCharForMission(enumCharacterList eChar, INT iAllowedChars)
RETURN NOT IS_BIT_SET(iAllowedChars, ENUM_TO_INT(GET_FRIEND_FROM_CHAR(eChar)))
ENDFUNC
FUNC BOOL Private_CanZoneRejectAnyConversableMembers()
// Is player in a rejection zone for a mission he can trigger?
IF (g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_REJECT AND IS_BITMASK_SET(g_sMissionStaticData[g_eFriendMissionZoneID].triggerCharBitset, GET_PLAYER_PED_BIT(GET_CURRENT_PLAYER_PED_ENUM())))
// Can any friends in group be rejected for this mission?
IF (Private_CanFriendConverse(gActivity.mFriendA) AND Private_CanRejectCharForMission(gActivity.mFriendA.eChar, g_iFriendMissionZoneAcceptBitset))
OR (Private_CanFriendConverse(gActivity.mFriendB) AND Private_CanRejectCharForMission(gActivity.mFriendB.eChar, g_iFriendMissionZoneAcceptBitset))
RETURN TRUE
ENDIF
// Can any soldiers in group be rejected for this mission?
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
enumCharacterList eChar
REPEAT MAX_BATTLE_BUDDIES eChar
IF eChar <> ePlayerChar
IF (Private_CanSoldierConverse(gActivity.mSoldiers[eChar]) AND Private_CanRejectCharForMission(eChar, g_iFriendMissionZoneAcceptBitset))
RETURN TRUE
ENDIF
ENDIF
ENDREPEAT
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_CanTimeRejectAnyConversableMembers()
IF g_eFriendMissionZoneState = FRIEND_MISSION_ZONE_OFF
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) = 0
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
enumCharacterList eChar
REPEAT MAX_BATTLE_BUDDIES eChar
IF eChar <> ePlayerChar
IF Private_CanSoldierConverse(gActivity.mSoldiers[eChar]) AND Private_CanRejectSoldierForTime(gActivity.mSoldiers[eChar])
RETURN TRUE
ENDIF
ENDIF
ENDREPEAT
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_RejectMembersForMission(BOOL bAllowSubtitles, enumFriendActivityPhrase ePhrase = FAP_REJECTION_OK, BOOL bIsPrep = FALSE)
IF bAllowSubtitles
CPRINTLN(DEBUG_FRIENDS, "Private_RejectMembersForMission(bAllowSubtitles = TRUE)")
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_RejectMembersForMission(bAllowSubtitles = FALSE)")
ENDIF
CPRINTLN(DEBUG_FRIENDS, "Current mission = ", GetLabel_SP_MISSIONS(g_eFriendMissionZoneID))
// Reject friends if they cannot join current mission, or if they are not in group
IF bIsPrep
IF Private_IsFriendValid(gActivity.mFriendA) AND NOT Private_CanFriendLeave(gActivity.mFriendA)
Private_SetFriendTrapped(gActivity.mFriendA)
ELSE
Private_SetFriendRejected(gActivity.mFriendA, bAllowSubtitles, ePhrase)
ENDIF
ELSE
IF Private_CanRejectCharForMission(gActivity.mFriendA.eChar, g_iFriendMissionZoneAcceptBitset)
OR NOT Private_CanFriendConverse(gActivity.mFriendA)
Private_SetFriendRejected(gActivity.mFriendA, bAllowSubtitles, ePhrase)
ENDIF
ENDIF
IF bIsPrep
IF Private_IsFriendValid(gActivity.mFriendB) AND NOT Private_CanFriendLeave(gActivity.mFriendB)
Private_SetFriendTrapped(gActivity.mFriendB)
ELSE
Private_SetFriendRejected(gActivity.mFriendB, bAllowSubtitles, ePhrase)
ENDIF
ELSE
IF Private_CanRejectCharForMission(gActivity.mFriendB.eChar, g_iFriendMissionZoneAcceptBitset)
OR NOT Private_CanFriendConverse(gActivity.mFriendB)
Private_SetFriendRejected(gActivity.mFriendB, bAllowSubtitles, ePhrase)
ENDIF
ENDIF
// Same for soldiers, except if they are on the way to a prep mission, don't reject them for not being in the group yet
// enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM() // BBUDDIES REMOVED
// enumCharacterList eChar
// REPEAT MAX_BATTLE_BUDDIES eChar
// IF eChar <> ePlayerChar
// IF Private_CanRejectCharForMission(eChar, g_iFriendMissionZoneAcceptBitset)
// Private_SetSoldierRejected(gActivity.mSoldiers[eChar], g_eFriendMissionZoneID, bAllowSubtitles, ePhrase)
//
// ELIF NOT Private_CanSoldierConverse(gActivity.mSoldiers[eChar]) AND NOT IS_BIT_SET(g_sMissionStaticData[g_eFriendMissionZoneID].settingsBitset, MF_INDEX_IS_PREP)
// Private_SetSoldierRejected(gActivity.mSoldiers[eChar], g_eFriendMissionZoneID, bAllowSubtitles, ePhrase)
// ENDIF
// ENDIF
// ENDREPEAT
ENDPROC
PROC Private_RejectAllSoldiers(BOOL bAllowSubtitles, enumFriendActivityPhrase ePhrase)
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tPhrase = GetLabel_enumFriendActivityPhrase(ePhrase)
CPRINTLN(DEBUG_FRIENDS, "Private_RejectAllSoldiers(", tPhrase, ")")
#ENDIF
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
enumCharacterList eChar
REPEAT MAX_BATTLE_BUDDIES eChar
IF eChar <> ePlayerChar
Private_SetSoldierRejected(gActivity.mSoldiers[eChar], g_BattleBuddyMission, bAllowSubtitles, ePhrase)
ENDIF
ENDREPEAT
ENDPROC
PROC Private_SetZoneRejection(BOOL bEnable)
IF gActivity.bIsZoneRejectionEnabled <> bEnable
// Enable/disable zone rejection
gActivity.bIsZoneRejectionEnabled = bEnable
// If disabling, stop current dialogue if running
IF bEnable = TRUE
CPRINTLN(DEBUG_FRIENDS, "Private_EnableZoneRejection(TRUE)")
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_EnableZoneRejection(FALSE)")
IF gActivity.mDialogue.eState = FDIALOGUE_REJECTZONE
OR gActivity.mDialogue.eState = FDIALOGUE_REJECTWAIT
CPRINTLN(DEBUG_FRIENDS, "Private_EnableZoneRejection(FALSE) - Ending rejection zone dialogue")
Private_EndDialogueState(gActivity.mDialogue)
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_EnableZoneRejection(FALSE) - No rejection zone dialogue playing")
ENDIF
gActivity.eRecentRejectionZone = SP_MISSION_NONE
ENDIF
ENDIF
ENDPROC
PROC Private_UpdateRejection()
// Reject for zone
IF gActivity.bIsZoneRejectionEnabled
AND g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_LAUNCHING
AND g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_LAUNCHED
IF Private_CanZoneRejectAnyConversableMembers()
// Start dialogue
IF gActivity.mDialogue.eState <> FDIALOGUE_REJECTZONE
AND gActivity.mDialogue.eState <> FDIALOGUE_REJECTWAIT
AND gActivity.eRecentRejectionZone <> g_eFriendMissionZoneID
Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_REJECTZONE)
gActivity.eRecentRejectionZone = g_eFriendMissionZoneID
ENDIF
// Reject members if possible
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IS_MESSAGE_BEING_DISPLAYED()
IF gActivity.mDialogue.eState <> FDIALOGUE_REJECTZONE
Private_RejectMembersForMission(TRUE)
ENDIF
ENDIF
ENDIF
ELSE
// Abort dialogue
IF gActivity.mDialogue.eState = FDIALOGUE_REJECTWAIT
IF g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_REJECT
Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_REJECTCANCEL)
ENDIF
ENDIF
ENDIF
ENDIF
// Reject trapped friends
IF gActivity.mFriendA.eState = FRIEND_TRAPPED
IF Private_CanFriendLeave(gActivity.mFriendA) AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_PLAYER_PED_PLAYABLE(gActivity.mFriendA.eChar)
Private_SetFriendRejected(gActivity.mFriendA, /*g_BattleBuddyMission*/ TRUE, FAP_REJECTION_OK)
ELSE
Private_SetFriendRejected(gActivity.mFriendA, /*g_BattleBuddyMission*/ TRUE, FAP_REJECTION_CRAZY)
ENDIF
ENDIF
ENDIF
IF gActivity.mFriendB.eState = FRIEND_TRAPPED
IF Private_CanFriendLeave(gActivity.mFriendB) AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_PLAYER_PED_PLAYABLE(gActivity.mFriendB.eChar)
Private_SetFriendRejected(gActivity.mFriendB, /*g_BattleBuddyMission*/ TRUE, FAP_REJECTION_OK)
ELSE
Private_SetFriendRejected(gActivity.mFriendB, /*g_BattleBuddyMission*/ TRUE, FAP_REJECTION_CRAZY)
ENDIF
ENDIF
ENDIF
// Reject for squad timeout
IF Private_CanTimeRejectAnyConversableMembers()
IF Private_CanPlayAudio(gActivity.mAudio) AND (NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR ABSF(GET_ENTITY_SPEED(PLAYER_PED_ID())) < 0.5)
Private_RejectAllSoldiers(TRUE, FAP_REJECTION_TIMEOUT)
ENDIF
ENDIF
// Reject for BB flag
IF Private_CheckBehaviourFlag(BBF_RejectAllBattleBuddies)
Private_RejectAllSoldiers(TRUE, NO_FRIEND_ACTIVITY_PHRASE)
ENDIF
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Add requests
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_ProcessAddFriends(BOOL bOnlyAllowIfMetAmbiently = FALSE)
IF NOT Private_IsPlayerSwitching()
// Get pending connection
enumFriendConnection ePendingConnection
IF GET_PENDING_CONNECTIONS(ePendingConnection) > 0
// Get friend char from pending connection
enumCharacterList eFriendChar
IF GET_PENDING_CONNECTION_CHAR(ePendingConnection, eFriendChar)
//-- If met friend ambiently, remove any friends waiting to be picked up --
BOOL bMetAmbiently = FALSE
IF GET_CONNECTION_MODE(ePendingConnection) = FC_MODE_Ambient
bMetAmbiently = TRUE
ENDIF
IF bMetAmbiently
BOOL bWereMembersRemoved = FALSE
IF gActivity.mFriendA.eState = FRIEND_PICKUP
CPRINTLN(DEBUG_FRIENDS, "Private_HandleAddFriendRequests() - Met friend - Removing pickup ", GetLabel_enumCharacterList(gActivity.mFriendA.eChar))
Private_CleanupFriend(gActivity.mFriendA, MC_Release)
bWereMembersRemoved = TRUE
ENDIF
IF gActivity.mFriendB.eState = FRIEND_PICKUP
CPRINTLN(DEBUG_FRIENDS, "Private_HandleAddFriendRequests() - Met friend - Removing pickup ", GetLabel_enumCharacterList(gActivity.mFriendB.eChar))
Private_CleanupFriend(gActivity.mFriendB, MC_Release)
bWereMembersRemoved = TRUE
ENDIF
IF bWereMembersRemoved
Private_SortMembers(TRUE)
// TODO: Help message
ENDIF
ELIF bOnlyAllowIfMetAmbiently
// Can only meet ambiently at this stage -> so abort and reset connection
SET_CONNECTION_STATE(ePendingConnection, FC_STATE_ContactWait)
RETURN FALSE
ENDIF
//-- Add friend --
IF gActivity.mFriendA.eState = FRIEND_NULL
enumFriendLocation ePickupLocation = FriendLoc_GetBestPickupLoc(gActivity.mPlayer.eChar, eFriendChar, TRUE, gActivity.mFriendB.ePickup)
IF ACTIVATE_CONNECTION(ePendingConnection, FC_MODE_Friend)
IF Private_AddFriend(gActivity.mFriendA, eFriendChar, ePickupLocation, 0, bMetAmbiently)
// Cancel old queued text messages
Private_CancelCommsBetweenFriends(gActivity.mFriendA.eChar, gActivity.mPlayer.eChar)
Private_CancelCommsBetweenFriends(gActivity.mFriendA.eChar, gActivity.mFriendB.eChar)
RETURN TRUE
ENDIF
ENDIF
ELIF gActivity.mFriendB.eState = FRIEND_NULL
enumFriendLocation ePickupLocation = FriendLoc_GetBestPickupLoc(gActivity.mPlayer.eChar, eFriendChar, TRUE, gActivity.mFriendA.ePickup)
IF ACTIVATE_CONNECTION(ePendingConnection, FC_MODE_Friend)
IF Private_AddFriend(gActivity.mFriendB, eFriendChar, ePickupLocation, 1, bMetAmbiently)
// Cancel old queued text messages
Private_CancelCommsBetweenFriends(gActivity.mFriendB.eChar, gActivity.mPlayer.eChar)
Private_CancelCommsBetweenFriends(gActivity.mFriendB.eChar, gActivity.mFriendA.eChar)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ELSE
SCRIPT_ASSERT("Private_HandleAddFriendRequests() - Cannot get valid character for friend to be added - perhaps current player is not properly involved in the pending connection")
ENDIF
// Failed to create pending connection, reset it
SET_CONNECTION_STATE(ePendingConnection, FC_STATE_ContactWait)
RETURN FALSE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_ProcessAddSoldiers()
IF NOT Private_IsPlayerSwitching()
// Get pending connection
enumFriendConnection ePendingConnection
IF GET_PENDING_CONNECTIONS(ePendingConnection) > 0
// Get friend char from pending connection
enumCharacterList eFriendChar = NO_CHARACTER
IF GET_PENDING_CONNECTION_CHAR(ePendingConnection, eFriendChar)
AND IS_PLAYER_PED_PLAYABLE(eFriendChar)
//-- Add squad member --
IF gActivity.mSoldiers[eFriendChar].eState = SOLDIER_NULL
enumFriendConnectionMode eInitMode = GET_CONNECTION_MODE(ePendingConnection)
IF ACTIVATE_CONNECTION(ePendingConnection, FC_MODE_Squad)
IF Private_AddSoldier(gActivity.mSoldiers[eFriendChar], eInitMode)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ELSE
SCRIPT_ASSERT("Private_HandleSquadAddRequests() - Cannot get valid character for squad member to be added - perhaps current player is not properly involved in the pending connection")
ENDIF
// Failed to create pending connection, reset it
SET_CONNECTION_STATE(ePendingConnection, FC_STATE_ContactWait)
RETURN FALSE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//---------------------------------------------------------------------------------------------------
//-- Process members
//---------------------------------------------------------------------------------------------------
PROC Private_ProcessMembers()
// Process soldiers
INT iSlot
REPEAT MAX_BATTLE_BUDDIES iSlot
Private_UpdateSoldier(gActivity.mSoldiers[iSlot])
ENDREPEAT
// Process friends
Private_UpdateFriend(gActivity.mPlayer)
Private_UpdateFriend(gActivity.mFriendA)
Private_UpdateFriend(gActivity.mFriendB)
HANDLE_BUDDY_HEAD_TRACK_WHILE_ENTERING_VEHICLE()
// Clear damage
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(PLAYER_PED_ID())
CLEAR_ENTITY_LAST_WEAPON_DAMAGE(PLAYER_PED_ID())
ENDIF
IF NOT IS_PED_INJURED(gActivity.mFriendA.hPed)
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(gActivity.mFriendA.hPed)
CLEAR_ENTITY_LAST_WEAPON_DAMAGE(gActivity.mFriendA.hPed)
ENDIF
IF NOT IS_PED_INJURED(gActivity.mFriendB.hPed)
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(gActivity.mFriendB.hPed)
CLEAR_ENTITY_LAST_WEAPON_DAMAGE(gActivity.mFriendB.hPed)
ENDIF
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Remove requests
//---------------------------------------------------------------------------------------------------
PROC Private_LogFriendFail(structFriend& friend, enumCharacterList& eFailChar)
IF friend.eState <> FRIEND_CANCEL
eFailChar = friend.eChar
ENDIF
ENDPROC
PROC Private_ProcessRemoveMembers()
// Process rejection for zones and time
Private_UpdateRejection()
BOOL bWereMembersRemoved = FALSE
// Remove friends
IF NOT Private_IsPlayerSwitching()
// Remove friend A if requested
IF gActivity.mFriendA.eState >= FRIEND_CANCEL
CPRINTLN(DEBUG_FRIENDS, "Private_ProcessRemoveMembers() - Removing friend A: ", GetLabel_enumCharacterList(gActivity.mFriendA.eChar))
Private_LogFriendFail(gActivity.mFriendA, gActivity.eLogFailCharA)
Private_RemoveFailedFriend(gActivity.mFriendA)
bWereMembersRemoved = TRUE
ENDIF
// Remove friend B if requested
IF gActivity.mFriendB.eState >= FRIEND_CANCEL
CPRINTLN(DEBUG_FRIENDS, "Private_ProcessRemoveMembers() - Removing friend B: ", GetLabel_enumCharacterList(gActivity.mFriendB.eChar))
Private_LogFriendFail(gActivity.mFriendB, gActivity.eLogFailCharB)
Private_RemoveFailedFriend(gActivity.mFriendB)
bWereMembersRemoved = TRUE
ENDIF
// Ensure friend A is never blank
IF bWereMembersRemoved
Private_SortMembers(TRUE)
ENDIF
ENDIF
// Remove soldiers
// enumCharacterList eChar
// REPEAT MAX_BATTLE_BUDDIES eChar
//
// IF gActivity.mSoldiers[eChar].eState >= SOLDIER_FAIL_INJURED
// CPRINTLN(DEBUG_FRIENDS, "Private_ProcessRemoveMembers() - Removing soldier: ", GetLabel_enumCharacterList(eChar))
//
// Private_HandleSoldierFail(gActivity.mSoldiers[eChar], eCleanupStyle)
// Private_CleanupSoldier(gActivity.mSoldiers[eChar], eCleanupStyle)
// ENDIF
//
// ENDREPEAT
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Help
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_DisplayQueuedHelp(STRING sLabel)
// IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP)
// AND NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_FRIEND_SQUAD)
//
// SWITCH GET_FLOW_HELP_MESSAGE_STATUS(sLabel)
// CASE FHS_EXPIRED
// CPRINTLN(DEBUG_FRIENDS, "Private_DisplayQueuedHelp() - \"", sLabel, "\" trying to queue")
// ADD_HELP_TO_FLOW_QUEUE(sLabel, FHP_HIGH, 0, DEFAULT_HELP_TEXT_TIME)
// BREAK
//
//// CASE FHS_QUEUED
//// CPRINTLN(DEBUG_FRIENDS, "Private_DisplayQueuedHelp() - \"", sLabel, "\" is queued")
//// BREAK
//
// CASE FHS_DISPLAYED
// CPRINTLN(DEBUG_FRIENDS, "Private_DisplayQueuedHelp() - \"", sLabel, "\" was displayed by queue")
// RETURN TRUE
// BREAK
// ENDSWITCH
//
// ELSE
IF NOT IS_HELP_MESSAGE_ON_SCREEN()
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayQueuedHelp() - \"", sLabel, "\" was displayed without queueing (as on mission)")
PRINT_HELP(sLabel)
RETURN TRUE
ENDIF
// ENDIF
RETURN FALSE
ENDFUNC
PROC Private_ProcessHelp()
// Help text: battle buddy arriving
IF g_savedGlobals.sFriendsData.g_bHelpDoneBBuddyArrival = FALSE
IF gActivity.mSoldiers[CHAR_MICHAEL].eState = SOLDIER_ARRIVE_IN_CAR
OR gActivity.mSoldiers[CHAR_MICHAEL].eState = SOLDIER_FOLLOW
IF Private_DisplayQueuedHelp("FR_H_BUDM_A")
g_savedGlobals.sFriendsData.g_bHelpDoneBBuddyArrival = TRUE
EXIT
ENDIF
ELIF gActivity.mSoldiers[CHAR_FRANKLIN].eState = SOLDIER_ARRIVE_IN_CAR
OR gActivity.mSoldiers[CHAR_FRANKLIN].eState = SOLDIER_FOLLOW
IF Private_DisplayQueuedHelp("FR_H_BUDF_A")
g_savedGlobals.sFriendsData.g_bHelpDoneBBuddyArrival = TRUE
EXIT
ENDIF
ELIF gActivity.mSoldiers[CHAR_TREVOR].eState = SOLDIER_ARRIVE_IN_CAR
OR gActivity.mSoldiers[CHAR_TREVOR].eState = SOLDIER_FOLLOW
IF Private_DisplayQueuedHelp("FR_H_BUDT_A")
g_savedGlobals.sFriendsData.g_bHelpDoneBBuddyArrival = TRUE
EXIT
ENDIF
ENDIF
ENDIF
// Help text: player can switch to battle buddy
IF g_savedGlobals.sFriendsData.g_bHelpDoneBBuddySwitch = FALSE
IF gActivity.bIsAnySwitchAvailable
IF Private_DisplayQueuedHelp("FR_H_BUD_SW")
g_savedGlobals.sFriendsData.g_bHelpDoneBBuddySwitch = TRUE
EXIT
ENDIF
ENDIF
ELIF IS_HELP_MESSAGE_BEING_DISPLAYED()
IF IS_PLAYER_SWITCH_IN_PROGRESS()
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("FR_H_BUD_SW")
CLEAR_HELP()
ENDIF
ENDIF
ENDIF
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Global handles
//---------------------------------------------------------------------------------------------------
PROC Private_UpdateGlobalFriendHandles()
// Keep global ped IDs in sync
IF FRIEND_A_PED_ID() <> gActivity.mFriendA.hPed
CPRINTLN(DEBUG_FRIENDS, "Update FRIEND_A_PED_ID to ", GetLabel_enumCharacterList(gActivity.mFriendA.eChar), ", hPed = ", NATIVE_TO_INT(gActivity.mFriendA.hPed))
PRIVATE_SET_FRIEND_A_PED_ID(gActivity.mFriendA.hPed)
ENDIF
IF FRIEND_B_PED_ID() <> gActivity.mFriendB.hPed
CPRINTLN(DEBUG_FRIENDS, "Update FRIEND_B_PED_ID to ", GetLabel_enumCharacterList(gActivity.mFriendB.eChar), ", hPed = ", NATIVE_TO_INT(gActivity.mFriendB.hPed))
PRIVATE_SET_FRIEND_B_PED_ID(gActivity.mFriendB.hPed)
ENDIF
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Transfer
//---------------------------------------------------------------------------------------------------
/// This is called when player has friends and either (a) squad mission starts, or (b) player calls squad buddy
PROC Private_TransferMembersToSquad()
// CPRINTLN(DEBUG_FRIENDS, "\n")
// CPRINTLN(DEBUG_FRIENDS, "Private_TransferMembersToSquad() - ** TRANSFER STARTED **")
//
// enumFriendConnection eConnection
// enumCharacterList ePlayerChar = gActivity.mPlayer.eChar
// enumCharacterList eFriendAChar = gActivity.mFriendA.eChar
// enumCharacterList eFriendBChar = gActivity.mFriendB.eChar
//
// gActivity.eLogFailCharA = NO_CHARACTER
// gActivity.eLogFailCharB = NO_CHARACTER
//
//
// //-- Squad mission must be set to transfer members
// IF g_BattleBuddyMission = SP_MISSION_NONE
// SCRIPT_ASSERT("Private_TransferMembersToSquad() - Squad mission is not set")
// ENDIF
//
//
// //-- Setup dialogue states for squad mode
// Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_SQUAD)
// Private_SetDialogueIdleState(gActivity.mDialogue, FDIALOGUE_SQUAD_IDLE)
//
//
// //-- Transfer connections
//
// // Backup connections, as Init ones will get cleared by cleanups
// enumFriendConnectionState backupStates[MAX_FRIEND_CONNECTIONS]
// enumFriendConnectionMode backupModes[MAX_FRIEND_CONNECTIONS]
// REPEAT MAX_FRIEND_CONNECTIONS eConnection
// backupStates[eConnection] = GET_CONNECTION_STATE(eConnection)
// backupModes[eConnection] = GET_CONNECTION_MODE(eConnection)
// ENDREPEAT
//
// // Transfer player
// Private_CleanupFriend(gActivity.mPlayer, MC_LeavePedIntact)
// Private_AddSoldier(gActivity.mSoldiers[ePlayerChar])
// Private_SetSoldierGlobalFlag(gActivity.mSoldiers[ePlayerChar], g_bitfieldBattleBuddyAvailable)
//
// // Transfer friend A
// IF NOT Private_IsFriendValid(gActivity.mFriendA)
// OR NOT Private_CanFriendConverse(gActivity.mFriendA)
//
// Private_SetFriendRejected(gActivity.mFriendA, g_BattleBuddyMission, FALSE, NO_FRIEND_ACTIVITY_PHRASE)
// Private_CleanupFriend(gActivity.mFriendA, MC_Release)
//
// ELIF NOT IS_BIT_SET(g_BattleBuddyAllowedChars, ENUM_TO_INT(GET_FRIEND_FROM_CHAR(gActivity.mFriendA.eChar)))
//
// IF NOT Private_CanFriendLeave(gActivity.mFriendA)
// Private_SetFriendTrapped(gActivity.mFriendA)
// ELSE
// Private_SetFriendRejected(gActivity.mFriendA, g_BattleBuddyMission, FALSE, FAP_REJECTION_OK)
// Private_CleanupFriend(gActivity.mFriendA, MC_Release)
// ENDIF
//
// ELSE
// // Convert to soldier
// Private_CleanupFriend(gActivity.mFriendA, MC_LeavePedIntact)
//
// IF GET_CONNECTION(ePlayerChar, eFriendAChar, eConnection)
// IF ACTIVATE_CONNECTION(eConnection, FC_MODE_Squad)
// Private_AddSoldier(gActivity.mSoldiers[eFriendAChar])
// Private_SetSoldierGlobalFlag(gActivity.mSoldiers[eFriendAChar], g_bitfieldBattleBuddyAvailable)
// ENDIF
// ENDIF
// ENDIF
//
// // Transfer friend B
// IF NOT Private_IsFriendValid(gActivity.mFriendB)
// OR NOT Private_CanFriendConverse(gActivity.mFriendB)
//
// Private_SetFriendRejected(gActivity.mFriendB, g_BattleBuddyMission, FALSE, NO_FRIEND_ACTIVITY_PHRASE)
// Private_CleanupFriend(gActivity.mFriendB, MC_Release)
//
// ELIF NOT IS_BIT_SET(g_BattleBuddyAllowedChars, ENUM_TO_INT(GET_FRIEND_FROM_CHAR(gActivity.mFriendB.eChar)))
//
// IF NOT Private_CanFriendLeave(gActivity.mFriendB)
// Private_SetFriendTrapped(gActivity.mFriendB)
// ELSE
// Private_SetFriendRejected(gActivity.mFriendB, g_BattleBuddyMission, FALSE, FAP_REJECTION_OK)
// Private_CleanupFriend(gActivity.mFriendB, MC_Release)
// ENDIF
//
// ELSE
// // Convert to soldier
// Private_CleanupFriend(gActivity.mFriendB, MC_LeavePedIntact)
//
// IF GET_CONNECTION(ePlayerChar, eFriendBChar, eConnection)
// IF ACTIVATE_CONNECTION(eConnection, FC_MODE_Squad)
// Private_AddSoldier(gActivity.mSoldiers[eFriendBChar])
// Private_SetSoldierGlobalFlag(gActivity.mSoldiers[eFriendBChar], g_bitfieldBattleBuddyAvailable)
// ENDIF
// ENDIF
// ENDIF
//
// // Restore any init connections
// REPEAT MAX_FRIEND_CONNECTIONS eConnection
// IF backupStates[eConnection] = FC_STATE_Init
// SET_CONNECTION_STATE(eConnection, backupStates[eConnection])
// SET_CONNECTION_MODE(eConnection, backupModes[eConnection])
// ENDIF
// ENDREPEAT
//
// OVERWRITE_BATTLEBUDDY_SNAPSHOT()
// CPRINTLN(DEBUG_FRIENDS, "Snapshot: g_bitfieldBattleBuddyAvailable = ", g_bitfieldBattleBuddyAvailable)
//
// IF g_eFriendMissionZoneState <> FRIEND_MISSION_ZONE_OFF
// IF g_eFriendMissionZoneID = SP_MISSION_FBI_4_PREP_4
// OR g_eFriendMissionZoneID = SP_MISSION_FBI_4_PREP_5
// CPRINTLN(DEBUG_FRIENDS, "Friend activity will resume when player passes squad mission...")
// gActivity.bResumeFriendsAfterSquad = TRUE
// ENDIF
// ENDIF
//
// CPRINTLN(DEBUG_FRIENDS, "Private_TransferMembersToSquad() - ** TRANSFER DONE **\n")
ENDPROC
FUNC BOOL Private_TransferMembersToFriends()
// CPRINTLN(DEBUG_FRIENDS, "\n")
// CPRINTLN(DEBUG_FRIENDS, "Private_TransferMembersToFriends() - ** TRANSFER STARTED **")
//
// // Clear any friends that are remaining from before the squad mode
// IF Private_IsFriendValid(gActivity.mFriendA)
// Private_SetFriendRejected(gActivity.mFriendA, g_BattleBuddyMission, FALSE, NO_FRIEND_ACTIVITY_PHRASE)
// ENDIF
// IF Private_IsFriendValid(gActivity.mFriendB)
// Private_SetFriendRejected(gActivity.mFriendB, g_BattleBuddyMission, FALSE, NO_FRIEND_ACTIVITY_PHRASE)
// ENDIF
//
// Private_CleanupFriend(gActivity.mPlayer)
// Private_CleanupFriend(gActivity.mFriendA)
// Private_CleanupFriend(gActivity.mFriendB)
//
// //g_bitfieldBattleBuddyAvailable = 0 // Does this need doing?
//
// DEACTIVATE_ALL_CONNECTIONS()
//
// enumFriendConnection eConnection
// enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
//
// // Transfer soldiers to friends
// BOOL bAddedFriendA = FALSE
//
// IF NOT IS_PED_INJURED(gActivity.mSoldiers[ePlayerChar].hPed)
//
// // Transfer player
// Private_CleanupSoldier(gActivity.mSoldiers[ePlayerChar], MC_LeavePedIntact)
// Private_AddFriend(gActivity.mPlayer, ePlayerChar, NO_FRIEND_LOCATION, 0, FALSE)
//
// // Transfer other buddies
// enumCharacterList eChar
// REPEAT MAX_BATTLE_BUDDIES eChar
// IF eChar <> ePlayerChar
// IF NOT IS_PED_INJURED(gActivity.mSoldiers[eChar].hPed)
// IF (gActivity.mSoldiers[eChar].eState = SOLDIER_GROUP
// OR gActivity.mSoldiers[eChar].eState = SOLDIER_APPROACH
// OR gActivity.mSoldiers[eChar].eState = SOLDIER_OVERRIDDEN)
// AND Private_IsSoldierGlobalFlagSet(gActivity.mSoldiers[eChar], g_bitfieldBattleBuddyAvailable)
//
// Private_CleanupSoldier(gActivity.mSoldiers[eChar], MC_LeavePedIntact)
//
// IF GET_CONNECTION(ePlayerChar, eChar, eConnection)
// IF ACTIVATE_CONNECTION(eConnection, FC_MODE_Friend)
// IF bAddedFriendA = FALSE
// Private_AddFriend(gActivity.mFriendA, eChar, NO_FRIEND_LOCATION, 0, TRUE)
// bAddedFriendA = TRUE
// ELSE
// Private_AddFriend(gActivity.mFriendB, eChar, NO_FRIEND_LOCATION, 0, TRUE)
// ENDIF
// ENDIF
// ENDIF
//
// ELSE
// Private_CleanupSoldier(gActivity.mSoldiers[eChar], MC_Release)
// ENDIF
// ENDIF
// ENDIF
// ENDREPEAT
//
// ENDIF
//
// CPRINTLN(DEBUG_FRIENDS, "Private_TransferMembersToFriends() - ** TRANSFER DONE **\n")
//
RETURN ARE_ANY_FRIEND_CONNECTIONS_PENDING_OR_ACTIVE()
ENDFUNC
//---------------------------------------------------------------------------------------------------
//-- Friend fails
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_AreFriendsFailed()
// If all members have failed, fail mission
IF gActivity.mFriendA.eState = FRIEND_NULL AND gActivity.mFriendB.eState = FRIEND_NULL
IF Private_GetDialogueState(gActivity.mDialogue) <> FDIALOGUE_REJECTED
IF gActivity.iFailQueueCount = 0
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_AreAnyMembersValid()
// Are any friends are valid...
IF (gActivity.mFriendA.eState <> FRIEND_NULL AND gActivity.mFriendA.eState < FRIEND_CANCEL)
OR (gActivity.mFriendB.eState <> FRIEND_NULL AND gActivity.mFriendB.eState < FRIEND_CANCEL)
RETURN TRUE
ENDIF
// Are any soldiers valid...
enumCharacterList eLoopChar
REPEAT MAX_BATTLE_BUDDIES eLoopChar
IF gActivity.mSoldiers[eLoopChar].eState <> SOLDIER_NULL
AND gActivity.mSoldiers[eLoopChar].eState <> SOLDIER_PLAYER
AND gActivity.mSoldiers[eLoopChar].eState < SOLDIER_FAIL_INJURED
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL Private_AreAllMembersRemoved()
// If any friends are valid, don't fail
IF gActivity.mFriendA.eState <> FRIEND_NULL
OR gActivity.mFriendB.eState <> FRIEND_NULL
RETURN FALSE
ENDIF
// If any soldiers are valid don't fail
enumCharacterList eLoopChar
REPEAT MAX_BATTLE_BUDDIES eLoopChar
IF gActivity.mSoldiers[eLoopChar].eState <> SOLDIER_NULL
AND gActivity.mSoldiers[eLoopChar].eState <> SOLDIER_PLAYER
RETURN FALSE
ENDIF
ENDREPEAT
// If doing rejection dialogue, or need to print fail reason don't fail
IF Private_GetDialogueState(gActivity.mDialogue) = FDIALOGUE_REJECTED
OR gActivity.iFailQueueCount > 0
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
PROC Private_ProcessSystem(BOOL bProcessHelp = FALSE)
Private_ProcessDialogue(gActivity.mDialogue, gActivity.mAudio)
Private_UpdateGlobalFriendHandles()
Private_ProcessFailReasonQueue()
Private_ProcessTextMessageQueue()
IF bProcessHelp
Private_ProcessHelp()
ENDIF
ENDPROC