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

933 lines
30 KiB
Scheme
Executable File

//- commands headers -//
USING "rage_builtins.sch"
USING "globals.sch"
//- script headers -//
USING "commands_script.sch"
//- public headers -//
USING "player_ped_public.sch"
USING "timer_public.sch"
USING "dialogue_public.sch"
USING "blip_control_public.sch"
USING "flow_public_core_override.sch"
USING "stats_enums.sch"
USING "organiser_public.sch"
USING "selector_public.sch"
USING "chase_hint_cam.sch"
USING "friends_core.sch"
//- private headers -//
#IF IS_DEBUG_BUILD
//- debug headers -//
USING "script_debug.sch"
USING "shared_debug.sch"
#ENDIF
///private header for friends scripts
/// sam.hackett@rockstarleeds.com
///
FUNC BOOL PRIVATE_IS_POINT_IN_CITY(VECTOR v)
IF v.y < 400.0
IF v.x < 1400.0
IF v.x > -1900.0
IF v.y > -3500.0
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
// *******************************************************************************************
// LAST CONTACT TIMER - private
// *******************************************************************************************
/// PURPOSE:
/// Gets the time since last contact between two friends (in seconds)
/// PARAMS:
/// playerCharID - FriendA
/// friendCharID - FriendB
/// RETURNS:
/// The time since last contact / in seconds
FUNC FLOAT Private_GET_FRIEND_LAST_CONTACT_TIME(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 < MAX_FRIEND_CONNECTIONS
IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer)
RETURN GET_TIMER_IN_SECONDS(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer)
ENDIF
ELSE
SCRIPT_ASSERT("Private_GET_FRIEND_LAST_CONTACT_TIME() - Invalid friendConnID")
ENDIF
RETURN 0.0
ENDFUNC
/// PURPOSE:
/// Gets the most recent type of contact between two friends
/// PARAMS:
/// playerCharID - FriendA
/// friendCharID - FriendB
/// RETURNS:
/// The type of contact / phone or face
FUNC enumFriendContactType Private_GET_FRIEND_LAST_CONTACT_TYPE(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 < MAX_FRIEND_CONNECTIONS
RETURN g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactType
ELSE
SCRIPT_ASSERT("Private_GET_FRIEND_LAST_CONTACT_TYPE() - Invalid friendConnID")
ENDIF
RETURN FRIEND_CONTACT_FACE
ENDFUNC
/// PURPOSE:
/// Adds the given time to the timer - for use by debug menus
/// PARAMS:
/// playerCharID - FriendA
/// friendCharID - FriendB
/// Delay_Time - The time to add
PROC Private_ALTER_FRIEND_LAST_CONTACT_TIME(enumCharacterList playerCharID, enumCharacterList friendCharID, FLOAT Delay_Time)
CPRINTLN(DEBUG_FRIENDS, "Private_ALTER_FRIEND_LAST_CONTACT_TIME(FR_", GetLabel_enumFriend(GLOBAL_CHARACTER_SHEET_GET_FRIEND(friendCharID)), ", ", Delay_Time, ")")
enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID)
enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID)
enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID)
IF friendConnID < MAX_FRIEND_CONNECTIONS
FLOAT Start_Time = 0.0
IF IS_TIMER_STARTED(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer)
Start_Time = GET_TIMER_IN_SECONDS(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer)
ENDIF
RESTART_timer_AT(g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactTimer, Start_Time + Delay_Time)
ELSE
SCRIPT_ASSERT("Private_ALTER_FRIEND_LAST_CONTACT_TIME() - Invalid friendConnID")
ENDIF
ENDPROC
/// PURPOSE:
/// Adds the given time to the timer - for use by debug menus
/// PARAMS:
/// playerCharID - FriendA
/// friendCharID - FriendB
/// Delay_Time - The time to add
PROC Private_ALTER_FRIEND_LAST_CONTACT_TYPE(enumCharacterList playerCharID, enumCharacterList friendCharID, enumFriendContactType type)
CPRINTLN(DEBUG_FRIENDS, "Private_ALTER_FRIEND_LAST_CONTACT_TYPE(FR_", GetLabel_enumFriend(GLOBAL_CHARACTER_SHEET_GET_FRIEND(friendCharID)), ", ", type, ")")
enumFriend playerID = GET_FRIEND_FROM_CHAR(playerCharID)
enumFriend friendID = GET_FRIEND_FROM_CHAR(friendCharID)
enumFriendConnection friendConnID = GET_CONNECTION_FROM_FRIENDS(playerID, friendID)
IF friendConnID < MAX_FRIEND_CONNECTIONS
g_SavedGlobals.sFriendsData.g_FriendConnectData[friendConnID].lastContactType = type
ELSE
SCRIPT_ASSERT("Private_ALTER_FRIEND_LAST_CONTACT_TYPE() - Invalid friendConnID")
ENDIF
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Friend ped setters
//---------------------------------------------------------------------------------------------------
PROC PRIVATE_SET_FRIEND_A_PED_ID(PED_INDEX activityFriendID)
g_pActivityFriendA = activityFriendID
ENDPROC
PROC PRIVATE_SET_FRIEND_B_PED_ID(PED_INDEX activityFriendID)
g_pActivityFriendB = activityFriendID
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Direct connection manipulation functions
//---------------------------------------------------------------------------------------------------
FUNC BOOL GET_CONNECTION(enumCharacterList ePlayerChar, enumCharacterList eFriendChar, enumFriendConnection& eConn)
// Are chars valid as friends?
enumFriend ePlayerID = GET_FRIEND_FROM_CHAR(ePlayerChar)
enumFriend eFriendID = GET_FRIEND_FROM_CHAR(eFriendChar)
IF ePlayerID <> NO_FRIEND AND eFriendID <> NO_FRIEND
// Check desired connection is ContactWait
eConn = GET_CONNECTION_FROM_FRIENDS(ePlayerID, eFriendID)
IF eConn <> NO_FRIEND_CONNECTION
RETURN TRUE
ENDIF
ENDIF
eConn = NO_FRIEND_CONNECTION
RETURN FALSE
ENDFUNC
FUNC enumFriendConnectionState GET_CONNECTION_STATE(enumFriendConnection eConn)
IF eConn < MAX_FRIEND_CONNECTIONS
RETURN g_FriendConnectState[eConn].state
ELSE
SCRIPT_ASSERT("GET_CONNECTION_STATE() - Invalid friend connection ID")
RETURN FC_STATE_Invalid
ENDIF
ENDFUNC
PROC SET_CONNECTION_STATE(enumFriendConnection eConn, enumFriendConnectionState state)
IF eConn < MAX_FRIEND_CONNECTIONS
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConn)
TEXT_LABEL_63 tState = GetLabel_enumFriendConnectionState(state)
CPRINTLN(DEBUG_FRIENDS, "SET_CONNECTION_STATE(", tConn, ", ", tState, ")")
#ENDIF
g_FriendConnectState[eConn].state = state
IF state = FC_STATE_ContactWait
g_FriendConnectState[eConn].mode = FC_MODE_Friend
#IF IS_DEBUG_BUILD
CDEBUG1LN(DEBUG_FRIENDS, "(Auto setting ", tConn, " init mode to FC_MODE_Friend)")
#ENDIF
ENDIF
ELSE
SCRIPT_ASSERT("SET_CONNECTION_STATE() - Invalid friend connection ID")
ENDIF
ENDPROC
FUNC enumFriendConnectionMode GET_CONNECTION_MODE(enumFriendConnection eConn)
IF eConn < MAX_FRIEND_CONNECTIONS
RETURN g_FriendConnectState[eConn].mode
ELSE
SCRIPT_ASSERT("GET_CONNECTION_MODE() - Invalid friend connection ID")
RETURN FC_MODE_Friend
ENDIF
ENDFUNC
PROC SET_CONNECTION_MODE(enumFriendConnection eConn, enumFriendConnectionMode eMode)
IF eConn < MAX_FRIEND_CONNECTIONS
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConn)
TEXT_LABEL_63 tMode = GetLabel_enumFriendConnectionMode(eMode)
CPRINTLN(DEBUG_FRIENDS, "SET_CONNECTION_MODE(", tConn, ", ", tMode, ")")
#ENDIF
g_FriendConnectState[eConn].mode = eMode
ELSE
SCRIPT_ASSERT("SET_CONNECTION_MODE() - Invalid friend connection ID")
ENDIF
ENDPROC
PROC SET_CONNECTION_FLAG(enumFriendConnection eConnection, enumFriendConnectionFlag eFlag, BOOL bEnable)
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConnection)
IF bEnable
CPRINTLN(DEBUG_FRIENDS, "SET_CONNECTION_FLAG(", tConn, ", flag=", ENUM_TO_INT(eFlag), ", bEnable=TRUE")
ELSE
CPRINTLN(DEBUG_FRIENDS, "SET_CONNECTION_FLAG(", tConn, ", flag=", ENUM_TO_INT(eFlag), ", bEnable=FALSE")
ENDIF
#ENDIF
IF eConnection < MAX_FRIEND_CONNECTIONS
IF bEnable
SET_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(eFlag))
ELSE
CLEAR_BIT(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(eFlag))
ENDIF
ELSE
SCRIPT_ASSERT("SET_CONNECTION_FLAG() - Invalid friend connection ID")
ENDIF
ENDPROC
FUNC BOOL IS_CONNECTION_FLAG_SET(enumFriendConnection eConnection, enumFriendConnectionFlag eFlag)
IF eConnection < MAX_FRIEND_CONNECTIONS
RETURN IS_BIT_SET(g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].flags, ENUM_TO_INT(eFlag))
ELSE
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConnection)
CPRINTLN(DEBUG_FRIENDS, "IS_CONNECTION_FLAG_SET(", tConn, ", flag=", ENUM_TO_INT(eFlag), ") - Invalid friend connection")
#ENDIF
SCRIPT_ASSERT("SET_CONNECTION_FLAG() - Invalid friend connection ID")
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL ARE_ANY_CONNECTIONS_PENDING_OR_PHONE()
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_FriendConnectState[eConn].state = FC_STATE_PhoneAccept
OR g_FriendConnectState[eConn].state = FC_STATE_PhoneDecline
OR g_FriendConnectState[eConn].state = FC_STATE_Init
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL ARE_ANY_FRIEND_CONNECTIONS_PENDING_OR_ACTIVE()
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_FriendConnectState[eConn].state = FC_STATE_Init
OR g_FriendConnectState[eConn].state = FC_STATE_Active
IF g_FriendConnectState[eConn].mode = FC_MODE_Friend
RETURN TRUE
ENDIF
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC BOOL ARE_ANY_SQUAD_CONNECTIONS_PENDING_OR_ACTIVE(BOOL bIncludePhone = FALSE, BOOL bIncludeReplay = FALSE)
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
enumFriendConnectionMode eMode = g_FriendConnectState[eConn].mode
IF eMode = FC_MODE_Squad OR (bIncludeReplay AND eMode = FC_MODE_ReplayGroup)
enumFriendConnectionState eState = g_FriendConnectState[eConn].state
IF eState = FC_STATE_Init
OR eState = FC_STATE_Active
RETURN TRUE
ENDIF
IF bIncludePhone
IF eState = FC_STATE_PhoneAccept
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
FUNC INT GET_PENDING_CONNECTIONS(enumFriendConnection& eFirstMatchingConnection)
INT iCount = 0
eFirstMatchingConnection = NO_FRIEND_CONNECTION
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_FriendConnectState[eConn].state = FC_STATE_Init
IF eFirstMatchingConnection = NO_FRIEND_CONNECTION
eFirstMatchingConnection = eConn
ENDIF
iCount++
ENDIF
ENDREPEAT
RETURN iCount
ENDFUNC
FUNC INT GET_ACTIVE_CONNECTIONS(enumFriendConnection& eFirstMatchingConnection)
INT iCount = 0
eFirstMatchingConnection = NO_FRIEND_CONNECTION
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_FriendConnectState[eConn].state = FC_STATE_Active
IF eFirstMatchingConnection = NO_FRIEND_CONNECTION
eFirstMatchingConnection = eConn
ENDIF
iCount++
ENDIF
ENDREPEAT
RETURN iCount
ENDFUNC
FUNC INT GET_PENDING_OR_ACTIVE_CONNECTIONS(enumFriendConnection& eFirstMatchingConnection)
INT iCount = 0
eFirstMatchingConnection = NO_FRIEND_CONNECTION
enumFriendConnection eConn
REPEAT MAX_FRIEND_CONNECTIONS eConn
IF g_FriendConnectState[eConn].state = FC_STATE_Init
OR g_FriendConnectState[eConn].state = FC_STATE_Active
IF eFirstMatchingConnection = NO_FRIEND_CONNECTION
eFirstMatchingConnection = eConn
ENDIF
iCount++
ENDIF
ENDREPEAT
RETURN iCount
ENDFUNC
FUNC BOOL GET_COMMON_CONNECTION(enumFriendConnection eConnA, enumFriendConnection eConnB, enumFriendConnection& eCommonConn)
enumFriend eFriend1 = NO_FRIEND
enumFriend eFriend2 = NO_FRIEND
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendA = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendA
eFriend1 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendB
eFriend2 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendB
ELIF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendB = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendB
eFriend1 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendA
eFriend2 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendA
ELIF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendA = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendB
eFriend1 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendB
eFriend2 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendA
ELIF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendB = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendA
eFriend1 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnA].friendA
eFriend2 = g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnB].friendB
ENDIF
IF IS_PLAYER_PED_PLAYABLE(GET_CHAR_FROM_FRIEND(eFriend1)) OR IS_PLAYER_PED_PLAYABLE(GET_CHAR_FROM_FRIEND(eFriend2))
eCommonConn = GET_CONNECTION_FROM_FRIENDS(eFriend1, eFriend2)
IF eCommonConn <> NO_FRIEND_CONNECTION
RETURN TRUE
ENDIF
ENDIF
eCommonConn = NO_FRIEND_CONNECTION
RETURN FALSE
ENDFUNC
FUNC BOOL DOES_CONNECTION_INVOLVE_CHAR(enumFriendConnection eConnection, enumCharacterList eChar)
enumFriend eFriend = GET_FRIEND_FROM_CHAR(eChar)
IF eFriend < MAX_FRIENDS
IF g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].friendA = eFriend
OR g_SavedGlobals.sFriendsData.g_FriendConnectData[eConnection].friendB = eFriend
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL GET_PENDING_CONNECTION_CHAR(enumFriendConnection eConnection, enumCharacterList& eFriendChar)
// Get friend char from pending connection
enumFriend eFriendID
IF GET_OTHER_FRIEND_FROM_CONNECTION(eConnection, eFriendID)
eFriendChar = GET_CHAR_FROM_FRIEND(eFriendID)
IF eFriendChar <> NO_CHARACTER
RETURN TRUE
ENDIF
ENDIF
eFriendChar = NO_CHARACTER
RETURN FALSE
ENDFUNC
// *******************************************************************************************
FUNC BOOL IS_FRIEND_ACTIVITY_SCRIPT_RUNNING()
RETURN IS_THREAD_ACTIVE(INT_TO_NATIVE(THREADID, g_SavedGlobals.sFriendsData.g_FriendScriptThread))
ENDFUNC
FUNC BOOL ACTIVATE_CONNECTION(enumFriendConnection eConnection, enumFriendConnectionMode eMode) // Should this do something to delay the creation, if the another friend is still pending?
enumFriendConnection eActiveConnection
enumFriendConnection eCommonConnection
INT iActiveFriends = GET_ACTIVE_CONNECTIONS(eActiveConnection)
IF iActiveFriends = 0
SET_CONNECTION_STATE(eConnection, FC_STATE_Active)
SET_CONNECTION_MODE(eConnection, eMode)
RETURN TRUE
ELIF iActiveFriends = 1
IF GET_COMMON_CONNECTION(eConnection, eActiveConnection, eCommonConnection)
AND GET_CONNECTION_STATE(eCommonConnection) <> FC_STATE_Invalid
SET_CONNECTION_STATE(eConnection, FC_STATE_Active)
SET_CONNECTION_STATE(eCommonConnection, FC_STATE_Active)
SET_CONNECTION_MODE(eConnection, eMode)
SET_CONNECTION_MODE(eCommonConnection, eMode)
RETURN TRUE
ENDIF
ENDIF
//ELIF iActiveFriends > 1
RETURN FALSE
ENDFUNC
FUNC BOOL DEACTIVATE_CHAR_CONNECTIONS(enumCharacterList eChar)
// Reset active connections involving given char
enumFriendConnection eConnection
enumCharacterList eConnCharA
enumCharacterList eConnCharB
BOOL bDeactivated = FALSE
REPEAT MAX_FRIEND_CONNECTIONS eConnection
GET_FRIEND_CHARS_FROM_CONNECTION(eConnection, eConnCharA, eConnCharB)
IF eConnCharA = eChar
OR eConnCharB = eChar
enumFriendConnectionState eState = GET_CONNECTION_STATE(eConnection)
IF eState = FC_STATE_Init
OR eState = FC_STATE_Active
SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait)
bDeactivated = TRUE
ENDIF
ENDIF
ENDREPEAT
RETURN bDeactivated
ENDFUNC
FUNC BOOL DEACTIVATE_ALL_CONNECTIONS()
BOOL bDeactivated = FALSE
// Reset any friend connections
enumFriendConnection eConnection
REPEAT MAX_FRIEND_CONNECTIONS eConnection
enumFriendConnectionState eState = GET_CONNECTION_STATE(eConnection)
IF eState = FC_STATE_Init
OR eState = FC_STATE_Active
SET_CONNECTION_STATE(eConnection, FC_STATE_ContactWait)
bDeactivated = TRUE
ENDIF
ENDREPEAT
RETURN bDeactivated
ENDFUNC
// *******************************************************************************************
#IF IS_DEBUG_BUILD
PROC DEBUG_PRINT_ALL_CONNECTIONS()
CPRINTLN(DEBUG_FRIENDS, "DEBUG_PRINT_ALL_CONNECTIONS()...")
// Reset any friend connections
enumFriendConnection eConnection
REPEAT MAX_FRIEND_CONNECTIONS eConnection
TEXT_LABEL_63 tConn = GetLabel_enumFriendConnection(eConnection)
TEXT_LABEL_63 tState = GetLabel_enumFriendConnectionState(GET_CONNECTION_STATE(eConnection))
TEXT_LABEL_63 tMode = GetLabel_enumFriendConnectionMode(GET_CONNECTION_MODE(eConnection))
CPRINTLN(DEBUG_FRIENDS, " ", tConn, " ", tState, " (", tMode, ")")
ENDREPEAT
ENDPROC
#ENDIF
// *******************************************************************************************
//PROC INC_FRIEND_CALL_STAT(enumCharacterList ePlayerChar, enumCharacterList eFriendChar)
//
// #IF IS_DEBUG_BUILD
// TEXT_LABEL_63 tPlayerChar = GetLabel_enumCharacterList(ePlayerChar)
// TEXT_LABEL_63 tFriendChar = GetLabel_enumCharacterList(eFriendChar)
// CPRINTLN(DEBUG_FRIENDS, "INC_FRIEND_CALL_STAT(", tPlayerChar, ", ", tFriendChar, ")")
// #ENDIF
//
// STATSENUM eStat
//
// IF ePlayerChar = CHAR_MICHAEL
// IF eFriendChar = CHAR_FRANKLIN eStat = TIMES_M_INIT_F_FRIEND
// ELIF eFriendChar = CHAR_TREVOR eStat = TIMES_M_INIT_T_FRIEND
// ELIF eFriendChar = CHAR_JIMMY eStat = TIMES_M_INIT_J_FRIEND
// ELIF eFriendChar = CHAR_AMANDA eStat = TIMES_M_INIT_A_FRIEND
// ELSE
// SCRIPT_ASSERT("INC_FRIEND_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELIF ePlayerChar = CHAR_FRANKLIN
// IF eFriendChar = CHAR_MICHAEL eStat = TIMES_F_INIT_M_FRIEND
// ELIF eFriendChar = CHAR_TREVOR eStat = TIMES_F_INIT_T_FRIEND
// ELIF eFriendChar = CHAR_LAMAR eStat = TIMES_F_INIT_L_FRIEND
// ELIF eFriendChar = CHAR_JIMMY eStat = TIMES_F_INIT_J_FRIEND
// ELSE
// SCRIPT_ASSERT("INC_FRIEND_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELIF ePlayerChar = CHAR_TREVOR
// IF eFriendChar = CHAR_MICHAEL eStat = TIMES_T_INIT_M_FRIEND
// ELIF eFriendChar = CHAR_FRANKLIN eStat = TIMES_T_INIT_F_FRIEND
// ELIF eFriendChar = CHAR_LAMAR eStat = TIMES_T_INIT_L_FRIEND
// ELIF eFriendChar = CHAR_JIMMY eStat = TIMES_T_INIT_J_FRIEND
// ELSE
// SCRIPT_ASSERT("INC_FRIEND_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELSE
// SCRIPT_ASSERT("INC_FRIEND_CALL_STAT() - ePlayerChar is not a valid player character")
// EXIT
// ENDIF
//
// STAT_INCREMENT(eStat, 1)
//
// #IF IS_DEBUG_BUILD
// INT iCount = 0
// STAT_GET_INT(eStat, iCount)
// CPRINTLN(DEBUG_FRIENDS, "INC_FRIEND_CALL_STAT() New value = ", iCount)
// #ENDIF
//
//ENDPROC
//PROC INC_BBUDDY_CALL_STAT(enumCharacterList ePlayerChar, enumCharacterList eFriendChar) // BBUDDIES REMOVED
//
// #IF IS_DEBUG_BUILD
// TEXT_LABEL_63 tPlayerChar = GetLabel_enumCharacterList(ePlayerChar)
// TEXT_LABEL_63 tFriendChar = GetLabel_enumCharacterList(eFriendChar)
// CPRINTLN(DEBUG_FRIENDS, "INC_BBUDDY_CALL_STAT(", tPlayerChar, ", ", tFriendChar, ")")
// #ENDIF
//
// STATSENUM eStat
//
// IF ePlayerChar = CHAR_MICHAEL
// IF eFriendChar = CHAR_FRANKLIN eStat = TIMES_M_INIT_F_BBUDDY
// ELIF eFriendChar = CHAR_TREVOR eStat = TIMES_M_INIT_T_BBUDDY
// ELSE
// SCRIPT_ASSERT("INC_BBUDDY_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELIF ePlayerChar = CHAR_FRANKLIN
// IF eFriendChar = CHAR_MICHAEL eStat = TIMES_F_INIT_M_BBUDDY
// ELIF eFriendChar = CHAR_TREVOR eStat = TIMES_F_INIT_T_BBUDDY
// ELSE
// SCRIPT_ASSERT("INC_BBUDDY_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELIF ePlayerChar = CHAR_TREVOR
// IF eFriendChar = CHAR_MICHAEL eStat = TIMES_T_INIT_M_BBUDDY
// ELIF eFriendChar = CHAR_FRANKLIN eStat = TIMES_T_INIT_F_BBUDDY
// ELSE
// SCRIPT_ASSERT("INC_BBUDDY_CALL_STAT() - eFriendChar has no connection with the given player char")
// EXIT
// ENDIF
//
// ELSE
// SCRIPT_ASSERT("INC_BBUDDY_CALL_STAT() - ePlayerChar is not a valid player character")
// EXIT
// ENDIF
//
// STAT_INCREMENT(eStat, 1)
//
// #IF IS_DEBUG_BUILD
// INT iCount = 0
// STAT_GET_INT(eStat, iCount)
// CPRINTLN(DEBUG_FRIENDS, "INC_BBUDDY_CALL_STAT() New value = ", iCount)
// #ENDIF
//
//ENDPROC
//------------------------------------------------------------------------------------------------------------------------------
// Delete queue
//------------------------------------------------------------------------------------------------------------------------------
PROC Private_AddPedToDeleteQueue(PED_INDEX hPed)
INT iQueueSpot = -1, iQueue
REPEAT COUNT_OF(g_ambientSelectorPedDeleteQueue) iQueue
IF (iQueueSpot < 0)
IF NOT DOES_ENTITY_EXIST(g_ambientSelectorPedDeleteQueue[iQueue])
iQueueSpot = iQueue
ENDIF
ENDIF
ENDREPEAT
IF (iQueueSpot < 0)
OR (iQueueSpot > COUNT_OF(g_ambientSelectorPedDeleteQueue))
SCRIPT_ASSERT("invalid iQueueSpot???")
iQueueSpot = 0
ENDIF
g_ambientSelectorPedDeleteQueue[iQueueSpot] = hPed
ENDPROC
FUNC BOOL Private_IsPedInDeleteQueue(PED_INDEX hPed)
INT iQueue
REPEAT COUNT_OF(g_ambientSelectorPedDeleteQueue) iQueue
IF g_ambientSelectorPedDeleteQueue[iQueue] = hPed
RETURN TRUE
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
PROC SET_PED_AS_AMBIENT_FRIEND(PED_INDEX hPed, enumCharacterList eChar, enumAmbGrabMode eMode) // TODO: What if ped is the player?
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND(", GetLabel_enumCharacterList(eChar), ")")
IF IS_PED_INJURED(hPed)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - ped is injured, set as no longer needed")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELIF NOT IS_PLAYER_PED_PLAYABLE(eChar)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - ped is NPC, set as no longer needed")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELIF g_bInMultiplayer
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - multiplayer is active, adding to global delete queue")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELIF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("friends_controller")) = 0
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - friends controller isn't running, adding to global delete queue")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELIF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - friends controller is running but prep mission is active, adding to global delete queue")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELIF (g_OnMissionState = MISSION_TYPE_FRIEND_ACTIVITY OR g_OnMissionState = MISSION_TYPE_FRIEND_ACTIVITY_WITH_MG)
AND g_eCurrentActivityLoc < MAX_ACTIVITY_LOCATIONS
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - friends controller is running but fr. activity has started, adding to global delete queue")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ELSE
IF NOT IS_PED_INJURED(g_pDismissPeds[eChar])
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - already a ped in list, set old ped as no longer needed")
SET_PED_AS_NO_LONGER_NEEDED(hPed)
// Private_AddPedToDeleteQueue(hPed)
ENDIF
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND() - successfully added ", GetLabel_enumCharacterList(eChar), " to ambfriend queue")
g_pDismissPeds[eChar] = hPed
g_pDismissMode[eChar] = eMode
ENDIF
ENDPROC
PROC SET_PED_AS_AMBIENT_FRIEND_WANDER(PED_INDEX hPed, enumCharacterList eChar)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND_WANDER(", GetLabel_enumCharacterList(eChar), ")")
// Set tasks
IF NOT IS_PED_INJURED(hPed)
IF IS_PED_GROUP_MEMBER(hPed, PLAYER_GROUP_ID())
REMOVE_PED_FROM_GROUP(hPed)
ENDIF
SET_PED_KEEP_TASK(hPed, TRUE)
SCRIPTTASKSTATUS eStatus = GET_SCRIPT_TASK_STATUS(hPed, SCRIPT_TASK_WANDER_STANDARD)
IF eStatus <> PERFORMING_TASK AND eStatus <> WAITING_TO_START_TASK
CLEAR_PED_TASKS(hPed)
TASK_WANDER_STANDARD(hPed)
ENDIF
ENDIF
// Release to system
SET_PED_AS_AMBIENT_FRIEND(hPed, eChar, AMBGRAB_TRANSFER_WANDER)
ENDPROC
PROC SET_PED_AS_AMBIENT_FRIEND_FLEE(PED_INDEX hPed, enumCharacterList eChar)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND_FLEE(", GetLabel_enumCharacterList(eChar), ")")
// Set tasks
IF NOT IS_PED_INJURED(hPed)
IF IS_PED_GROUP_MEMBER(hPed, PLAYER_GROUP_ID())
REMOVE_PED_FROM_GROUP(hPed)
ENDIF
SET_PED_KEEP_TASK(hPed, TRUE)
SCRIPTTASKSTATUS eStatus = GET_SCRIPT_TASK_STATUS(hPed, SCRIPT_TASK_SMART_FLEE_PED)
IF eStatus <> PERFORMING_TASK AND eStatus <> WAITING_TO_START_TASK
CLEAR_PED_TASKS(hPed)
TASK_SMART_FLEE_PED(hPed, PLAYER_PED_ID(), 5000.0, -1, TRUE, FALSE)
ENDIF
ENDIF
// Release to system
SET_PED_AS_AMBIENT_FRIEND(hPed, eChar, AMBGRAB_TRANSFER_FLEE)
ENDPROC
//PROC SET_PED_AS_AMBIENT_FRIEND_FLEE(PED_INDEX hPed, enumCharacterList eChar)
//
// CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND_FLEE(", GetLabel_enumCharacterList(eChar), ")")
//
// // Set tasks
// IF NOT IS_PED_INJURED(hPed)
// IF IS_PED_GROUP_MEMBER(hPed, PLAYER_GROUP_ID())
// REMOVE_PED_FROM_GROUP(hPed)
// ENDIF
// SET_PED_KEEP_TASK(hPed, TRUE)
//
// // Player
// IF IS_PLAYER_PED_PLAYABLE(eChar)
// SCRIPTTASKSTATUS eStatus = GET_SCRIPT_TASK_STATUS(hPed, SCRIPT_TASK_SMART_FLEE_PED)
// IF eStatus <> PERFORMING_TASK AND eStatus <> WAITING_TO_START_TASK
// CLEAR_PED_TASKS(hPed)
// TASK_SMART_FLEE_PED(hPed, PLAYER_PED_ID(), 5000.0, -1, TRUE, FALSE)
// ENDIF
//
// // NPC
// ELSE
// CLEAR_PED_TASKS(hPed)
//
// // Get out of car and run away
// SEQUENCE_INDEX seq
// OPEN_SEQUENCE_TASK(seq)
// IF IS_PED_IN_ANY_VEHICLE(hPed, TRUE)
// TASK_LEAVE_ANY_VEHICLE(null)
// ENDIF
// TASK_SMART_FLEE_PED(null, PLAYER_PED_ID(), 5000.0, -1, TRUE, FALSE)
// TASK_WANDER_STANDARD(null)
// CLOSE_SEQUENCE_TASK(seq)
// TASK_PERFORM_SEQUENCE(hPed, seq)
// CLEAR_SEQUENCE_TASK(seq)
// ENDIF
//
// ENDIF
//
// // Release to system
// SET_PED_AS_AMBIENT_FRIEND(hPed, eChar, AMBMODE_FLEE)
//
//ENDPROC
PROC SET_PED_AS_AMBIENT_FRIEND_REJECTED(PED_INDEX hPed, enumCharacterList eChar, SP_MISSIONS eMission)
CPRINTLN(DEBUG_FRIENDS, "SET_PED_AS_AMBIENT_FRIEND_REJECTED(", GetLabel_enumCharacterList(eChar), ")")
// Set tasks
IF NOT IS_PED_INJURED(hPed)
IF IS_PED_GROUP_MEMBER(hPed, PLAYER_GROUP_ID())
REMOVE_PED_FROM_GROUP(hPed)
ENDIF
SET_PED_KEEP_TASK(hPed, TRUE)
CLEAR_PED_TASKS(hPed)
// Get mission position
BOOL bHasDestPos = FALSE
VECTOR vRejectionDest
#if USE_CLF_DLC
IF eMission <> SP_MISSION_NONE
#ENDIF
#if USE_NRM_DLC
IF eMission <> SP_MISSION_NONE
#ENDIF
#if not USE_CLF_DLC
#if not USE_NRM_DLC
IF eMission = SP_MISSION_LESTER_1
vRejectionDest = <<1382.8588, -1706.0695, 62.8927>> // Hardcode the destination for leaving Lester's house
bHasDestPos = TRUE
ELIF eMission <> SP_MISSION_NONE
#ENDIF
#ENDIF
STATIC_BLIP_NAME_ENUM eMissionBlip
VECTOR vMissionPos
eMissionBlip = g_sMissionStaticData[eMission].blip
IF IS_STATIC_BLIP_MULTIMODE(eMissionBlip)
vMissionPos = GET_STATIC_BLIP_POSITION(eMissionBlip, GET_CURRENT_PLAYER_PED_INT())
ELSE
vMissionPos = GET_STATIC_BLIP_POSITION(eMissionBlip)
ENDIF
// Get rejection dest
FLOAT fHeadingDummy
INT iLanesDummy
vRejectionDest = vMissionPos + (NORMALISE_VECTOR(GET_ENTITY_COORDS(hPed) - vMissionPos) * 50.0)
IF GET_SAFE_VEHICLE_NODE(vRejectionDest, vRejectionDest, fHeadingDummy, iLanesDummy, 1, FALSE)
bHasDestPos = TRUE
ENDIF
ENDIF
// Walk away from the mission
SEQUENCE_INDEX seq
OPEN_SEQUENCE_TASK(seq)
IF IS_PED_IN_ANY_VEHICLE(hPed, TRUE)
TASK_LEAVE_ANY_VEHICLE(null)
ENDIF
TASK_LOOK_AT_ENTITY(null, PLAYER_PED_ID(), 2000, SLF_WHILE_NOT_IN_FOV|SLF_USE_TORSO)
TASK_PAUSE(null, GET_RANDOM_INT_IN_RANGE(800, 1200))
IF bHasDestPos
TASK_FOLLOW_NAV_MESH_TO_COORD(null, vRejectionDest, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED|ENAV_NO_STOPPING)
ENDIF
TASK_WANDER_STANDARD(null)
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(hPed, seq)
CLEAR_SEQUENCE_TASK(seq)
ENDIF
// Release to system
SET_PED_AS_AMBIENT_FRIEND(hPed, eChar, AMBGRAB_TRANSFER_REJECTED)
ENDPROC