Files
2025-09-29 00:52:08 +02:00

2019 lines
65 KiB
Scheme
Executable File

//- commands headers -//
USING "rage_builtins.sch"
USING "globals.sch"
//- script headers -//
USING "commands_script.sch"
USING "commands_stats.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 "organiser_public.sch"
USING "selector_public.sch"
USING "chase_hint_cam.sch"
USING "rc_helper_functions.sch"
USING "friends_public.sch"
//- private headers -//
USING "friendUtil_private.sch"
USING "battlebuddy_private.sch"
USING "locates_private.sch"
//#IF IS_DEBUG_BUILD
////- debug headers -//
// USING "script_debug.sch"
// USING "shared_debug.sch"
//#ENDIF
///private header for friend activity scripts
/// sam.hackett@rockstarnorth.com
///
//---------------------------------------------------------------------------------------------------
//-- FriendActivity - CONSTS
//---------------------------------------------------------------------------------------------------
CONST_FLOAT CONST_fIsPlayerAtDoorstep 30.0
CONST_FLOAT CONST_fIsBuddyAtDriveway 20.0//25 - NB: If doorstep and driveway are further apart than this, buddy will be blipped when on doorstep
CONST_FLOAT CONST_fPickupHornDist 12.5//10.0//15
CONST_FLOAT CONST_fPickupHornExtraDist 30.0
CONST_FLOAT CONST_fPickupCamDist 20.0
CONST_FLOAT CONST_fBuddyJoinDist 25.0
CONST_FLOAT CONST_fBuddyLostDist 200.0
CONST_FLOAT CONST_fFriendConverseRadius 75.0
CONST_FLOAT CONST_fLateFailInRealMinutes 4.0//12.0
CONST_FLOAT CONST_fLateDialogueInRealMintues 2.0//6.0
CONST_FLOAT CONST_fLateFailInRealMinutes_rural 8.0//12.0
CONST_FLOAT CONST_fLateDialogueInRealMintues_rural 3.5//6.0
CONST_INT CONST_iActivityDebugPrintLineTop 4
CONST_INT CONST_iActivityDebugPrintLine 10
//STRING ANIMDICT_WaitIdle = "friends@"
//STRING ANIMDICT_PhoneIdle = "friends@laf@ig_1@idle_a"
//STRING ANIMDICT_PhoneExit = "friends@laf@ig_5"
//
//STRING ANIM_WaitIdle = "pickupwait"
//STRING ANIM_PhoneIdle = "idle_c"
//STRING ANIM_PhoneExit = "hustlecuz" //"anotherhalf"
MODEL_NAMES MODEL_PhoneProp = P_AMB_PHONE_01
//---------------------------------------------------------------------------------------------------
//-- FriendActivity - DATATYPES
//---------------------------------------------------------------------------------------------------
ENUM enumActivityState
ACTIVITY_STATE_Init,
ACTIVITY_STATE_Pickup,
ACTIVITY_STATE_Journey,
ACTIVITY_STATE_Minigame,
ACTIVITY_STATE_Cinema,
ACTIVITY_STATE_Bar,
// ACTIVITY_STATE_SquadReboot, // BBUDDIES REMOVED
// ACTIVITY_STATE_SquadRoaming,
// ACTIVITY_STATE_SquadMission,
ACTIVITY_STATE_Trapped,
ACTIVITY_STATE_Dropoff,
ACTIVITY_STATE_DropoffEarly,
ACTIVITY_STATE_DropoffSquad
ENDENUM
ENUM enumActivityFailReason
FAF_PlayerDeathArrest = 0,
FAF_PlayerOnMission,
FAF_PlayerSwitch,
FAF_RetryAbort,
FAF_PlaybackAbort,
FAF_Multiplayer,
FAF_MemberFail,
#IF IS_DEBUG_BUILD
FAF_Debug,
#ENDIF
FAF_NoFail
ENDENUM
// Member datatypes ----------------------------------------
ENUM enumMemberCleanupStyle
MC_Delete = 0,
MC_DeletePedAndCar,
MC_Release,
MC_LeavePedIntact,
MC_AmbientFlee,
MC_AmbientRejected,
MC_AmbientWander
ENDENUM
// Friend datatypes ----------------------------------------
ENUM enumFriendState
FRIEND_NULL = 0,
FRIEND_PICKUP,
FRIEND_GROUP,
FRIEND_LOST,
FRIEND_TRAPPED,
FRIEND_PARACHUTE,
FRIEND_PLUMMET,
FRIEND_CANCEL,
FRIEND_FAIL_REJECTED,
FRIEND_FAIL_INJURED,
FRIEND_FAIL_LATE,
FRIEND_FAIL_LOST,
FRIEND_FAIL_FLEE,
FRIEND_FAIL_ATTACKED,
FRIEND_FAIL_WANDER
ENDENUM
STRUCT structFriend
enumFriendState eState
enumCharacterList eChar
enumFriendLocation ePickup
TEXT_LABEL tName
PED_INDEX hPed
VEHICLE_INDEX hCar
OBJECT_INDEX hPhone
BLIP_INDEX hPedBlip
BLIP_INDEX hLocBlip
structTimer mParkedTimer
structTimer mWaitTimer
structTimer mFailTimer
VECTOR vDoorstep
VECTOR vDriveway
INT iOffsetIndex
SCENARIO_BLOCKING_INDEX hScenarioBlock
structTimer mArrivalStoppedTimer
INT iArrivalDrivingMode
INT iParachuteUpdateTime
MODEL_NAMES ePedModel
MODEL_NAMES eCarModel
BOOL bDoneTrappedDialogue
INT iBlockRunningUntilTime
INT iCarHealth
INT iCarShotTime
BOOL bWereInVehicleTogether
INT iHealth
VECTOR vParachuteTarget
BOOL bSwitchOverride
BOOL bIsBeingCalledToCancel
BOOL bIsShowingPickupCam
BOOL bForceCreateAsArriving
BOOL bUseStoredVehicleModel
BOOL bWasPickedUp
BOOL bWasMetAmbiently
enumActivityFailReason eFailReason
ENDSTRUCT
// Soldier datatypes ----------------------------------------
ENUM enumSoldierState
SOLDIER_NULL = 0,
SOLDIER_CREATE_IN_CAR,
SOLDIER_CREATE_ON_FOOT,
SOLDIER_ARRIVE_IN_CAR,
SOLDIER_APPROACH,
SOLDIER_GROUP,
SOLDIER_COMBAT,
SOLDIER_FOLLOW,
SOLDIER_PARACHUTE,
SOLDIER_GETINWAIT,
SOLDIER_PASSENGER,
SOLDIER_PLAYER,
SOLDIER_OVERRIDDEN,
SOLDIER_ARREST,
SOLDIER_FAIL_INJURED,
SOLDIER_FAIL_LOST
ENDENUM
ENUM enumSoldierBlipType
SOLDIER_BLIP_OFF = 0,
SOLDIER_BLIP_SIGNATURE,
SOLDIER_BLIP_VEHICLE,
SOLDIER_BLIP_PED
ENDENUM
STRUCT structSoldier
enumCharacterList eChar
enumSoldierState eState
BOOL bInitState
PED_INDEX hPed
BLIP_INDEX hBlip
VEHICLE_INDEX hVehicle
VEHICLE_CREATE_TYPE_ENUM eCreateInVehicleType
structTimer mAvailableTimer
VEHICLE_NODE_ID hArrivalNode
VECTOR vArrivalPos
INT iArrivalStage
INT iArrivalStoppedTimer
INT iArrivalHornTimer
INT iShoutTimer
BOOL bWasInCombat
BOOL bRequestGreetingDialogue
enumSoldierBlipType eCurrentBlip
BOOL bIsInParkingRange
enumCharacterList eCharToDriveTo
INT iCombatDelay
INT iStealthDelay
BOOL bDefendingCargobobArea
INT iCreateAttempts
VEHICLE_INDEX hPlayerEnteringVehicle
ENDSTRUCT
// Audio ---------------------------------------------------
ENUM enumFriendAudioState
FAUDIO_IDLE = 0,
FAUDIO_QUEUEING,
FAUDIO_QUEUEING_LABEL,
FAUDIO_PLAYING
ENDENUM
STRUCT structFriendAudio
enumFriendAudioState eState
TEXT_LABEL tBlock
TEXT_LABEL tRoot
TEXT_LABEL tLabel
ENDSTRUCT
// Dialogue ------------------------------------------------
ENUM enumFriendDialogueState
FDIALOGUE_REJECTZONE = 0, // FDIALOGUE_PRIORITY_REJECTION
FDIALOGUE_REJECTWAIT,
FDIALOGUE_REJECTCANCEL,
FDIALOGUE_REJECTED,
FDIALOGUE_BLOCKED, // FDIALOGUE_PRIORITY_BLOCKED
FDIALOGUE_SQUAD,
FDIALOGUE_DRUNK, // FDIALOGUE_PRIORITY_DRUNK
FDIALOGUE_ROBBERY, // FDIALOGUE_PRIORITY_ROBBERY
FDIALOGUE_PICKUP, // FDIALOGUE_PRIORITY_JOURNEY
FDIALOGUE_AMBIENT,
FDIALOGUE_RESULT,
FDIALOGUE_DAMAGE,
FDIALOGUE_COPS, // FDIALOGUE_PRIORITY_COPS
FDIALOGUE_CHAT, // FDIALOGUE_PRIORITY_CHAT
FDIALOGUE_COMMENT, // FDIALOGUE_PRIORITY_COMMENT
FDIALOGUE_SUGGESTION,
FDIALOGUE_PICKUP_IDLE, // FDIALOGUE_PRIORITY_IDLE
FDIALOGUE_JOURNEY_IDLE,
FDIALOGUE_SQUAD_IDLE,
MAX_FRIEND_DIALOGUE_STATE,
FDIALOGUE_NONE
ENDENUM
ENUM enumFriendDialoguePriority
FDIALOGUE_PRIORITY_REJECTION = 0,
FDIALOGUE_PRIORITY_BLOCKED,
FDIALOGUE_PRIORITY_DRUNK,
FDIALOGUE_PRIORITY_ROBBERY,
FDIALOGUE_PRIORITY_JOURNEY,
FDIALOGUE_PRIORITY_COPS,
FDIALOGUE_PRIORITY_CHAT,
FDIALOGUE_PRIORITY_COMMENT,
FDIALOGUE_PRIORITY_IDLE
ENDENUM
STRUCT structFriendDialogue
enumFriendDialogueState eState
enumFriendDialoguePriority eStatePriority
INT iCounter
enumFriendDialogueState eDefaultState
structTimer mGeneralTimer
structTimer mChatTimer
structTimer mSuggestTimer
BOOL bHasDonePickupIdleChat
INT iJourneyChatCounter
TEXT_LABEL tChatResumeBlock
TEXT_LABEL tChatResumeRoot
TEXT_LABEL tChatResumeLabel
INT iChatStoredTime
enumCharacterList eChatChars[3]
enumCharacterList eConvChar
enumFriendActivityPhrase eConvPhrase
ENDSTRUCT
// Fail reasons / text message -----------------------------
ENUM enumFriendFailReason
FFR_Injured = 0,
FFR_Lost,
FFR_Late,
FFR_Flee,
FFR_Attacked,
MAX_FRIEND_FAIL_REASONS,
NO_FRIEND_FAIL_REASON
ENDENUM
CONST_INT MAX_QUEUED_FAILS 5
CONST_INT MAX_QUEUED_TEXTS 5
STRUCT structQueuedFailReason
enumCharacterList eChar
enumFriendFailReason eReason
CC_CodeID eTxtCID
ENDSTRUCT
STRUCT structQueuedTextMessage
enumCharacterList eChar
enumFriendTextMessage eMsg
CC_CodeID eTxtCID
structTimer mTimer
ENDSTRUCT
// Objective -----------------------------------------------
CONST_INT CONST_iMaxVisitedLocations 4
ENUM enumFriendActivityObj
NO_FRIEND_ACTIVITY_OBJ = 0,
APPROACH_OBJ_ContextButton,
OBJ_PICKUP,
OBJ_LOST_1,
OBJ_LOST_2,
OBJ_VISIT_ACTIVITIES
ENDENUM
// Activity datatypes --------------------------------------
CONST_INT MAX_HATE_GROUPS 13
ENUM enumSwapState
SWAP_STATE_Wait = 0,
SWAP_STATE_CamIn,
SWAP_STATE_CamOut
ENDENUM
STRUCT structHateGroup
REL_GROUP_HASH hRelGroup
RELATIONSHIP_TYPE eOriginalRelType
ENDSTRUCT
ENUM enumGroupSpacing
FSPACING_INVALID = 0,
FSPACING_NORMAL,
FSPACING_INTERIOR,
FSPACING_FIGHT
ENDENUM
STRUCT structFriendActivity
enumActivityState mState
enumActivityFailReason mFailReason
BOOL bInitState
// Members
structFriend mPlayer
structFriend mFriendA
structFriend mFriendB
structSoldier mSoldiers[MAX_BATTLE_BUDDIES]
enumCharacterList ePlayerChar
BOOL bUpdateAfterSwitch
enumFriendTextMessage eQueuedFailTextMsg
enumCharacterList eQueuedFailTextSender
enumCharacterList eQueuedFailTextReceiver
VEHICLE_INDEX hPlayerVehicle
structTimer mFailTimer
// General
INT iCandidateID
INT iStateProgress
enumFriendActivityObj curObjective
structPedsForConversation convPedsDefault
structPedsForConversation convPedsVoicemail
LOCATES_HEADER_DATA locateData
BOOL bIsZoneRejectionEnabled
SP_MISSIONS eRecentRejectionZone
BOOL bIsCinemaEnabled
BOOL bIsGolfEnabled
BOOL bRestoreLocationBlips
BOOL bRestoreStripClub
BOOL bResumeFriendsAfterSquad
enumGroupSpacing eGroupSpacing
INT iLastHaircutChangeTime
TIMEOFDAY iLastClothesChangeTime
INT iLastTattooChangeTime
BOOL bMovedCarForMinigame
BOOL bIsPlayerInInterior
enumActivityLocation eStoppingForBarLoc
BOOL bStoppingForDropoff
enumCharacterList eLogFailCharA
enumCharacterList eLogFailCharB
// Journey
structBits64 bitsAllowedActivities
INT iAllowedCount
structBits64 bitsSuggestedActivities
structBits64 bitsVisitedActivities
structBits64 bitsVisitedLocations
INT iVisitedCount
BOOL bTakeFriendHome
enumActivityLocation eNearestActivityLoc
enumActivityLocation eLoadingActivityLoc
enumFriendLocation eDropoffLoc
VECTOR vDropoff
BLIP_INDEX hDropoffBlip
VEHICLE_INDEX hDropoffCar
structFDropoff dropoffData
INT iDropoffDrunkTimer
// SCENARIO_BLOCKING_INDEX hDropoffScenarioBlock
BOOL bIsDropoffRouteDisplayed
BOOL bIsRural
// Queued fail reasons
structQueuedFailReason mFailQueue[MAX_QUEUED_FAILS]
INT iFailQueueCount
// Queued text messages
structQueuedTextMessage mTextMsgQueue[MAX_QUEUED_TEXTS]
INT iTextMsgQueueCount
// Dialogue
structFriendDialogue mDialogue
structFriendAudio mAudio
// Squad
structHateGroup hateGroups[MAX_HATE_GROUPS]
INT iPlayerGroupFollowerCount
enumSwapState eHotswapStage
SELECTOR_PED_STRUCT sSelectorPeds
SELECTOR_CAM_STRUCT sCamDetails
BOOL bIsAnySwitchAvailable
ENDSTRUCT
structFriendActivity gActivity
// *******************************************************************************************
// DEBUG OUTPUT
// *******************************************************************************************
#IF IS_DEBUG_BUILD
FUNC STRING GetLabel_enumActivityFailReason(enumActivityFailReason eFailReason)
SWITCH eFailReason
CASE FAF_PlayerDeathArrest RETURN "FAF_PlayerDeathArrest" BREAK
CASE FAF_PlayerOnMission RETURN "FAF_PlayerOnMission" BREAK
CASE FAF_PlayerSwitch RETURN "FAF_PlayerSwitch" BREAK
CASE FAF_RetryAbort RETURN "FAF_RetryAbort" BREAK
CASE FAF_PlaybackAbort RETURN "FAF_PlaybackAbort" BREAK
CASE FAF_Multiplayer RETURN "FAF_Multiplayer" BREAK
CASE FAF_MemberFail RETURN "FAF_MemberFail" BREAK
CASE FAF_NoFail RETURN "FAF_NoFail" BREAK
#IF IS_DEBUG_BUILD
CASE FAF_Debug RETURN "FAF_Debug" BREAK
#ENDIF
ENDSWITCH
CPRINTLN(DEBUG_FRIENDS, "GetLabel_enumActivityFailReason() - invalid eFailReason ", ENUM_TO_INT(eFailReason))
SCRIPT_ASSERT("GetLabel_enumActivityFailReason() - invalid eFailReason")
RETURN "<invalid eFailReason>"
ENDFUNC
FUNC STRING GetLabel_enumActivityState(enumActivityState eActivityState)
SWITCH eActivityState
CASE ACTIVITY_STATE_Init RETURN "ACTIVITY_STATE_Init" BREAK
CASE ACTIVITY_STATE_Pickup RETURN "ACTIVITY_STATE_Pickup" BREAK
CASE ACTIVITY_STATE_Journey RETURN "ACTIVITY_STATE_Journey" BREAK
CASE ACTIVITY_STATE_Minigame RETURN "ACTIVITY_STATE_Minigame" BREAK
CASE ACTIVITY_STATE_Cinema RETURN "ACTIVITY_STATE_Cinema" BREAK
CASE ACTIVITY_STATE_Bar RETURN "ACTIVITY_STATE_Bar" BREAK
// CASE ACTIVITY_STATE_SquadReboot RETURN "ACTIVITY_STATE_SquadReboot" BREAK // BBUDDIES REMOVED
// CASE ACTIVITY_STATE_SquadRoaming RETURN "ACTIVITY_STATE_SquadRoaming" BREAK
// CASE ACTIVITY_STATE_SquadMission RETURN "ACTIVITY_STATE_SquadMission" BREAK
CASE ACTIVITY_STATE_Trapped RETURN "ACTIVITY_STATE_Trapped" BREAK
CASE ACTIVITY_STATE_Dropoff RETURN "ACTIVITY_STATE_Dropoff" BREAK
CASE ACTIVITY_STATE_DropoffEarly RETURN "ACTIVITY_STATE_DropoffEarly" BREAK
CASE ACTIVITY_STATE_DropoffSquad RETURN "ACTIVITY_STATE_DropoffSquad" BREAK
ENDSWITCH
CPRINTLN(DEBUG_FRIENDS, "GetLabel_enumActivityState() - invalid eActivityState ", ENUM_TO_INT(eActivityState))
SCRIPT_ASSERT("GetLabel_enumActivityState() - invalid eActivityState")
RETURN "<invalid eActivityState>"
ENDFUNC
FUNC STRING GetLabel_enumFriendState(enumFriendState eFriendState)
SWITCH eFriendState
CASE FRIEND_NULL RETURN "FRIEND_NULL" BREAK
CASE FRIEND_PICKUP RETURN "FRIEND_PICKUP" BREAK
CASE FRIEND_GROUP RETURN "FRIEND_GROUP" BREAK
CASE FRIEND_LOST RETURN "FRIEND_LOST" BREAK
CASE FRIEND_TRAPPED RETURN "FRIEND_TRAPPED" BREAK
CASE FRIEND_PARACHUTE RETURN "FRIEND_PARACHUTE" BREAK
CASE FRIEND_PLUMMET RETURN "FRIEND_PLUMMET" BREAK
CASE FRIEND_CANCEL RETURN "FRIEND_CANCEL" BREAK
CASE FRIEND_FAIL_INJURED RETURN "FRIEND_FAIL_INJURED" BREAK
CASE FRIEND_FAIL_LATE RETURN "FRIEND_FAIL_LATE" BREAK
CASE FRIEND_FAIL_LOST RETURN "FRIEND_FAIL_LOST" BREAK
CASE FRIEND_FAIL_FLEE RETURN "FRIEND_FAIL_FLEE" BREAK
CASE FRIEND_FAIL_REJECTED RETURN "FRIEND_FAIL_REJECTED" BREAK
CASE FRIEND_FAIL_ATTACKED RETURN "FRIEND_FAIL_ATTACKED" BREAK
CASE FRIEND_FAIL_WANDER RETURN "FRIEND_FAIL_WANDER" BREAK
ENDSWITCH
SCRIPT_ASSERT("GetLabel_enumFriendState() invalid eFriendState")
TEXT_LABEL str = "FRIEND_"
str += ENUM_TO_INT(eFriendState)
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
FUNC STRING GetLabel_enumFriendFailReason(enumFriendFailReason eReason)
SWITCH eReason
CASE FFR_Injured RETURN "FFR_Injured" BREAK
CASE FFR_Lost RETURN "FFR_Lost" BREAK
CASE FFR_Late RETURN "FFR_Late" BREAK
CASE FFR_Flee RETURN "FFR_Flee" BREAK
CASE FFR_Attacked RETURN "FFR_Attacked" BREAK
CASE MAX_FRIEND_FAIL_REASONS RETURN "MAX_FRIEND_FAIL_REASONS" BREAK
CASE NO_FRIEND_FAIL_REASON RETURN "NO_FRIEND_FAIL_REASON" BREAK
ENDSWITCH
TEXT_LABEL str = "FFR_"
str += ENUM_TO_INT(eReason)
CPRINTLN(DEBUG_FRIENDS, "GetLabel_enumFriendFailReason() invalid eReason ", str)
SCRIPT_ASSERT("GetLabel_enumFriendFailReason() invalid eReason")
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
FUNC STRING GetLabel_enumMemberCleanupStyle(enumMemberCleanupStyle eStyle)
SWITCH eStyle
CASE MC_Delete RETURN "MC_Delete" BREAK
CASE MC_DeletePedAndCar RETURN "MC_DeletePedAndCar" BREAK
CASE MC_Release RETURN "MC_Release" BREAK
CASE MC_LeavePedIntact RETURN "MC_LeavePedIntact" BREAK
CASE MC_AmbientFlee RETURN "MC_AmbientFlee" BREAK
CASE MC_AmbientRejected RETURN "MC_AmbientRejected" BREAK
CASE MC_AmbientWander RETURN "MC_AmbientWander" BREAK
ENDSWITCH
TEXT_LABEL str = "MC_"
str += ENUM_TO_INT(eStyle)
CPRINTLN(DEBUG_FRIENDS, "GetLabel_enumMemberCleanupStyle() invalid eStyle ", str)
SCRIPT_ASSERT("GetLabel_enumMemberCleanupStyle() invalid eStyle")
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
FUNC STRING GetLabel_enumFriendDialogueState(enumFriendDialogueState eState)
SWITCH eState
CASE FDIALOGUE_REJECTZONE RETURN "FDIALOGUE_REJECTZONE" BREAK
CASE FDIALOGUE_REJECTWAIT RETURN "FDIALOGUE_REJECTWAIT" BREAK
CASE FDIALOGUE_REJECTCANCEL RETURN "FDIALOGUE_REJECTCANCEL" BREAK
CASE FDIALOGUE_REJECTED RETURN "FDIALOGUE_REJECTED" BREAK
CASE FDIALOGUE_BLOCKED RETURN "FDIALOGUE_BLOCKED" BREAK
CASE FDIALOGUE_SQUAD RETURN "FDIALOGUE_SQUAD" BREAK
CASE FDIALOGUE_DRUNK RETURN "FDIALOGUE_DRUNK" BREAK
CASE FDIALOGUE_ROBBERY RETURN "FDIALOGUE_ROBBERY" BREAK
CASE FDIALOGUE_PICKUP RETURN "FDIALOGUE_PICKUP" BREAK
CASE FDIALOGUE_AMBIENT RETURN "FDIALOGUE_AMBIENT" BREAK
CASE FDIALOGUE_RESULT RETURN "FDIALOGUE_RESULT" BREAK
CASE FDIALOGUE_DAMAGE RETURN "FDIALOGUE_DAMAGE" BREAK
CASE FDIALOGUE_COPS RETURN "FDIALOGUE_COPS" BREAK
CASE FDIALOGUE_CHAT RETURN "FDIALOGUE_CHAT" BREAK
CASE FDIALOGUE_COMMENT RETURN "FDIALOGUE_COMMENT" BREAK
CASE FDIALOGUE_SUGGESTION RETURN "FDIALOGUE_SUGGESTION" BREAK
CASE FDIALOGUE_PICKUP_IDLE RETURN "FDIALOGUE_PICKUP_IDLE" BREAK
CASE FDIALOGUE_JOURNEY_IDLE RETURN "FDIALOGUE_JOURNEY_IDLE" BREAK
CASE FDIALOGUE_SQUAD_IDLE RETURN "FDIALOGUE_SQUAD_IDLE" BREAK
CASE MAX_FRIEND_DIALOGUE_STATE RETURN "MAX_FRIEND_DIALOGUE_STATE" BREAK
CASE FDIALOGUE_NONE RETURN "FDIALOGUE_NONE" BREAK
ENDSWITCH
SCRIPT_ASSERT("GetLabel_enumFriendDialogueState() invalid eState")
TEXT_LABEL str = "FDIALOGUE_"
str += ENUM_TO_INT(eState)
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
FUNC STRING GetLabel_enumFriendDialoguePriority(enumFriendDialoguePriority ePriority)
SWITCH ePriority
CASE FDIALOGUE_PRIORITY_REJECTION RETURN "FDIALOGUE_PRIORITY_REJECTION" BREAK
CASE FDIALOGUE_PRIORITY_BLOCKED RETURN "FDIALOGUE_PRIORITY_BLOCKED" BREAK
CASE FDIALOGUE_PRIORITY_DRUNK RETURN "FDIALOGUE_PRIORITY_DRUNK" BREAK
CASE FDIALOGUE_PRIORITY_ROBBERY RETURN "FDIALOGUE_PRIORITY_ROBBERY" BREAK
CASE FDIALOGUE_PRIORITY_JOURNEY RETURN "FDIALOGUE_PRIORITY_JOURNEY" BREAK
CASE FDIALOGUE_PRIORITY_COPS RETURN "FDIALOGUE_PRIORITY_COPS" BREAK
CASE FDIALOGUE_PRIORITY_CHAT RETURN "FDIALOGUE_PRIORITY_CHAT" BREAK
CASE FDIALOGUE_PRIORITY_COMMENT RETURN "FDIALOGUE_PRIORITY_COMMENT" BREAK
CASE FDIALOGUE_PRIORITY_IDLE RETURN "FDIALOGUE_PRIORITY_IDLE" BREAK
ENDSWITCH
SCRIPT_ASSERT("GetLabel_enumFriendDialoguePriority() invalid eState")
TEXT_LABEL str = "FD_"
str += ENUM_TO_INT(ePriority)
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
FUNC STRING GetLabel_enumFriendAudioState(enumFriendAudioState eState)
SWITCH eState
CASE FAUDIO_IDLE RETURN "FAUDIO_IDLE" BREAK
CASE FAUDIO_QUEUEING RETURN "FAUDIO_QUEUEING" BREAK
CASE FAUDIO_QUEUEING_LABEL RETURN "FAUDIO_QUEUEING_LABEL" BREAK
CASE FAUDIO_PLAYING RETURN "FAUDIO_PLAYING" BREAK
ENDSWITCH
SCRIPT_ASSERT("GetLabel_enumFriendAudioState() invalid eState")
TEXT_LABEL str = "FAUDIO_"
str += ENUM_TO_INT(eState)
RETURN GET_FIRST_N_CHARACTERS_OF_LITERAL_STRING(str, GET_LENGTH_OF_LITERAL_STRING(str))
ENDFUNC
#ENDIF
//---------------------------------------------------------------------------------------------------
//-- System Utils
//---------------------------------------------------------------------------------------------------
PROC Private_SetActivityState(enumActivityState eNewState)
IF gActivity.mState <> eNewState
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tNewState = GetLabel_enumActivityState(eNewState)
TEXT_LABEL_63 tOldState = GetLabel_enumActivityState(gActivity.mState)
CPRINTLN(DEBUG_FRIENDS, "Private_SetActivityState(", tNewState, ") - [Changing from ", tOldState, "]")
#ENDIF
gActivity.mState = eNewState
gActivity.bInitState = TRUE
gActivity.iStateProgress = 0
ENDIF
ENDPROC
PROC Private_SetActivityFailReason(enumActivityFailReason eFailReason)
CPRINTLN(DEBUG_FRIENDS, "Private_SetActivityFailReason(", GetLabel_enumActivityFailReason(eFailReason), ")")
gActivity.mFailReason = eFailReason
ENDPROC
PROC Private_ClearActivityFailReason()
gActivity.mFailReason = FAF_NoFail
ENDPROC
FUNC PED_INDEX Private_GetGlobalPed(enumCharacterList eChar)
IF IS_PLAYER_PED_PLAYABLE(eChar)
SELECTOR_SLOTS_ENUM eSelectorSlot = GET_SELECTOR_SLOT_FROM_PLAYER_PED_ENUM(eChar)
RETURN g_sPlayerPedRequest.sSelectorPeds.pedID[eSelectorSlot]
ELSE
enumFriend eFriend = GET_FRIEND_FROM_CHAR(eChar)
IF eFriend <> NO_FRIEND
INT iIndex = ENUM_TO_INT(eFriend) - NUM_OF_PLAYABLE_PEDS
IF iIndex < NUM_OF_NPC_FRIENDS
RETURN g_pGlobalFriends[iIndex]
ENDIF
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_GetGlobalPed() - Can't get friend handle for char ", GetLabel_enumCharacterList(eChar))
SCRIPT_ASSERT("Private_GetGlobalPed() - Can't get friend handle for char")
ENDIF
ENDIF
RETURN NULL
ENDFUNC
FUNC enumCharacterList Private_GetCharFromPed(PED_INDEX hPed)
enumCharacterList eChar = GET_PLAYER_PED_ENUM(hPed)
IF eChar = NO_CHARACTER
eChar = GET_NPC_PED_ENUM(hPed)
ENDIF
RETURN eChar
ENDFUNC
FUNC BOOL Private_IsVehicleOwnedByPed(VEHICLE_INDEX hVehicle, PED_INDEX hPed)
IF DOES_ENTITY_EXIST(hVehicle)
IF NOT HAS_VEHICLE_BEEN_MODDED(hVehicle)
MODEL_NAMES eVehModel = GET_ENTITY_MODEL(hVehicle)
enumCharacterList eChar = Private_GetCharFromPed(hPed)
BOOL bIsPlayableChar = IS_PLAYER_PED_PLAYABLE(eChar)
IF eChar < GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE()
PED_VEH_DATA_STRUCT vehData
// Check primary car model (check license plate unless it's a bike)
IF bIsPlayableChar
GET_PLAYER_VEH_DATA(eChar, vehData, VEHICLE_TYPE_CAR)
ELSE
GET_NPC_VEH_DATA(eChar, vehData, VEHICLE_TYPE_CAR)
ENDIF
IF vehData.model = eVehModel
IF IS_THIS_MODEL_A_BIKE(vehData.model)
OR IS_THIS_MODEL_A_BICYCLE(vehData.model)
OR ARE_STRINGS_EQUAL( GET_VEHICLE_NUMBER_PLATE_TEXT(hVehicle), vehData.tlNumberPlate )
RETURN TRUE
ENDIF
ENDIF
// Check bike model (check license plate unless it's a bike)
IF bIsPlayableChar
GET_PLAYER_VEH_DATA(eChar, vehData, VEHICLE_TYPE_BIKE)
ELSE
GET_NPC_VEH_DATA(eChar, vehData, VEHICLE_TYPE_BIKE)
ENDIF
IF vehData.model = eVehModel
IF IS_THIS_MODEL_A_BIKE(vehData.model)
OR IS_THIS_MODEL_A_BICYCLE(vehData.model)
OR ARE_STRINGS_EQUAL( GET_VEHICLE_NUMBER_PLATE_TEXT(hVehicle), vehData.tlNumberPlate )
RETURN TRUE
ENDIF
ENDIF
// Check secondary car model (check license plate unless it's a bike)
IF bIsPlayableChar
GET_PLAYER_VEH_DATA(eChar, vehData, VEHICLE_TYPE_SECONDARY_CAR)
ELSE
GET_NPC_VEH_DATA(eChar, vehData, VEHICLE_TYPE_SECONDARY_CAR)
ENDIF
IF vehData.model = eVehModel
IF IS_THIS_MODEL_A_BIKE(vehData.model)
OR IS_THIS_MODEL_A_BICYCLE(vehData.model)
OR ARE_STRINGS_EQUAL( GET_VEHICLE_NUMBER_PLATE_TEXT(hVehicle), vehData.tlNumberPlate )
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC enumActivityType Private_GetActivityLocType(enumActivityLocation eLoc)
IF eLoc < MAX_ACTIVITY_LOCATIONS
RETURN g_ActivityLocations[eLoc].type
ENDIF
RETURN NO_ACTIVITY_TYPE
ENDFUNC
FUNC BOOL Private_SetCurrentlyOnFriendMission(INT& iCandidateID)
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)
m_enumMissionCandidateReturnValue allowLaunch = Request_Mission_Launch(iCandidateID, MCTID_MEET_CHARACTER, MISSION_TYPE_FRIEND_ACTIVITY)
REQUEST_ADDITIONAL_TEXT("FRIENDS", OBJECT_TEXT_SLOT)
#IF IS_DEBUG_BUILD
IF (allowLaunch = MCRET_DENIED)
CPRINTLN(DEBUG_FRIENDS, "Friend_Activity_Request_Permission_To_Run: [", GET_THIS_SCRIPT_NAME(), "] ", "DENIED - so another mission must have launched so this Friend Activity should terminate")
ENDIF
IF (allowLaunch = MCRET_PROCESSING)
CPRINTLN(DEBUG_FRIENDS, "Friend_Activity_Request_Permission_To_Run: [", GET_THIS_SCRIPT_NAME(), "] ", "PROCESSING - so this Friend Activity should keep trying")
ENDIF
IF (allowLaunch = MCRET_ACCEPTED)
CPRINTLN(DEBUG_FRIENDS, "Friend_Activity_Request_Permission_To_Run: [", GET_THIS_SCRIPT_NAME(), "] ",
"ACCEPTED - Friend Activity must run because it now has control of the IS_CURRENTLY_ON_MISSION_TO_TYPE() flag")
ENDIF
#ENDIF
IF (allowLaunch <> MCRET_ACCEPTED)
// DENIED or still PROCESSING.
RETURN FALSE
ENDIF
// This mission has permission to launch
CPRINTLN(DEBUG_FRIENDS, "FRIEND ACTIVITY CANDIDATE ID (start): ", iCandidateID)
IF NOT GET_MISSION_FLAG()
SET_MISSION_FLAG(TRUE)
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
PROC Private_CancelCommsBetweenFriends(enumCharacterList eCharA, enumCharacterList eCharB)
IF eCharA != NO_CHARACTER
AND eCharB != NO_CHARACTER
IF eCharA = CHAR_MICHAEL
OR eCharA = CHAR_FRANKLIN
OR eCharA = CHAR_TREVOR
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_MICHAEL, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_FRANKLIN, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_TREVOR, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_LAMAR, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_JIMMY, eCharA, eCharB)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_AMANDA, eCharA, eCharB)
ENDIF
IF eCharB = CHAR_MICHAEL
OR eCharB = CHAR_FRANKLIN
OR eCharB = CHAR_TREVOR
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_MICHAEL, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_FRANKLIN, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_TREVOR, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_LAMAR, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_JIMMY, eCharB, eCharA)
CANCEL_COMMUNICATION_BETWEEN_CHARS(TEXT_FRIEND_GRIEF_AMANDA, eCharB, eCharA)
ENDIF
ENDIF
ENDPROC
//-------------------------------------------------------------------------------------------------------------------------------------------
// QUEUED TEXT MESSAGES
//-------------------------------------------------------------------------------------------------------------------------------------------
FUNC INT Private_QueueTextMessage(enumCharacterList eChar, enumFriendTextMessage eMsg, FLOAT fDelayInSeconds = 10.0, CC_CodeID eTxtCID = CID_BLANK)
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(eChar)
TEXT_LABEL_63 tMsg = GetLabel_enumFriendTextMessage(eMsg)
TEXT_LABEL_63 tCID = Get_Debug_String_For_Communication_Code_ID(eTxtCID)
CPRINTLN(DEBUG_FRIENDS, "Private_QueueTextMessage(", tChar, ", ", tMsg, ", ", fDelayInSeconds, ", ", tCID, ")")
#ENDIF
IF eChar >= NO_CHARACTER
SCRIPT_ASSERT("Private_QueueTextMessage() - Invalid eChar")
ELIF eMsg >= MAX_FRIEND_TEXT_MESSAGES
SCRIPT_ASSERT("Private_QueueTextMessage() - Invalid eMsg")
ELSE
// Find empty slot...
INT hSlot
REPEAT MAX_QUEUED_TEXTS hSlot
IF gActivity.mTextMsgQueue[hSlot].eMsg = NO_FRIEND_TEXT_MESSAGE
// Add text message to list
gActivity.mTextMsgQueue[hSlot].eChar = eChar
gActivity.mTextMsgQueue[hSlot].eMsg = eMsg
gActivity.mTextMsgQueue[hSlot].eTxtCID = eTxtCID
RESTART_TIMER_AT(gActivity.mTextMsgQueue[hSlot].mTimer, -fDelayInSeconds)
gActivity.iTextMsgQueueCount++
RETURN hSlot
ENDIF
ENDREPEAT
SCRIPT_ASSERT("Private_QueueTextMessage() - No slots free")
ENDIF
RETURN -1
ENDFUNC
PROC Private_InitTextMessageQueue()
gActivity.iTextMsgQueueCount = 0
INT i
REPEAT MAX_QUEUED_TEXTS i
gActivity.mTextMsgQueue[i].eMsg = NO_FRIEND_TEXT_MESSAGE
ENDREPEAT
ENDPROC
PROC Private_ProcessTextMessageQueue()
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
// If any texts are ready to be sent, send now and remove from queue
INT hSlot
REPEAT MAX_QUEUED_TEXTS hSlot
IF gActivity.mTextMsgQueue[hSlot].eMsg <> NO_FRIEND_TEXT_MESSAGE
AND gActivity.mTextMsgQueue[hSlot].eChar <> ePlayerChar
IF NOT IS_TIMER_STARTED(gActivity.mTextMsgQueue[hSlot].mTimer)
OR TIMER_DO_WHEN_READY(gActivity.mTextMsgQueue[hSlot].mTimer, 0.0)
IF NOT DOES_ENTITY_EXIST(Private_GetGlobalPed(gActivity.mTextMsgQueue[hSlot].eChar))
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(gActivity.mTextMsgQueue[hSlot].eChar)
TEXT_LABEL_63 tMsg = GetLabel_enumFriendTextMessage(gActivity.mTextMsgQueue[hSlot].eMsg)
TEXT_LABEL_63 tCID = Get_Debug_String_For_Communication_Code_ID(gActivity.mTextMsgQueue[hSlot].eTxtCID)
CPRINTLN(DEBUG_FRIENDS, "Private_ProcessTextMessageQueue() - ", tChar, " = ", tMsg, " (eTxtCID = ", tCID, ")")
#ENDIF
CC_CommID eCommID = TEXT_FRIEND
IF gActivity.mTextMsgQueue[hSlot].eMsg = FTM_FRIEND_HOSPITAL
eCommID = GET_COMM_ID_FOR_FRIEND_FAIL(GET_FRIEND_FROM_CHAR(gActivity.mTextMsgQueue[hSlot].eChar))
ENDIF
IF eCommID != COMM_NONE
REGISTERED_FRIEND_TEXT_MESSAGE_TO_PLAYER(ePlayerChar,
gActivity.mTextMsgQueue[hSlot].eChar,
gActivity.mTextMsgQueue[hSlot].eMsg, TRUE,
gActivity.mTextMsgQueue[hSlot].eTxtCID,
eCommID)
ENDIF
gActivity.mTextMsgQueue[hSlot].eMsg = NO_FRIEND_TEXT_MESSAGE
gActivity.iTextMsgQueueCount--
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
PROC Private_FlushTextMessageQueue()
// If any texts are still waiting to be sent, transfer to off-mission comms queue
INT hSlot
REPEAT MAX_QUEUED_TEXTS hSlot
IF gActivity.mTextMsgQueue[hSlot].eMsg <> NO_FRIEND_TEXT_MESSAGE
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(gActivity.mTextMsgQueue[hSlot].eChar)
TEXT_LABEL_63 tMsg = GetLabel_enumFriendTextMessage(gActivity.mTextMsgQueue[hSlot].eMsg)
TEXT_LABEL_63 tCID = Get_Debug_String_For_Communication_Code_ID(gActivity.mTextMsgQueue[hSlot].eTxtCID)
CPRINTLN(DEBUG_FRIENDS, "Private_FlushTextMessageQueue() - ", tChar, " = ", tMsg, " (eTxtCID = ", tCID, ")")
#ENDIF
CC_CommID eCommID = TEXT_FRIEND
IF gActivity.mTextMsgQueue[hSlot].eMsg = FTM_FRIEND_HOSPITAL
eCommID = GET_COMM_ID_FOR_FRIEND_FAIL(GET_FRIEND_FROM_CHAR(gActivity.mTextMsgQueue[hSlot].eChar))
ENDIF
IF eCommID != COMM_NONE
REGISTERED_FRIEND_TEXT_MESSAGE_TO_PLAYER(GET_CURRENT_PLAYER_PED_ENUM(),
gActivity.mTextMsgQueue[hSlot].eChar,
gActivity.mTextMsgQueue[hSlot].eMsg, FALSE,
gActivity.mTextMsgQueue[hSlot].eTxtCID,
eCommID)
ENDIF
gActivity.mTextMsgQueue[hSlot].eMsg = NO_FRIEND_TEXT_MESSAGE
gActivity.iTextMsgQueueCount--
ENDIF
ENDREPEAT
ENDPROC
//-------------------------------------------------------------------------------------------------------------------------------------------
// QUEUED FAIL REASONS
//-------------------------------------------------------------------------------------------------------------------------------------------
PROC Private_QueueFailReason(enumCharacterList eChar, enumFriendFailReason eReason, CC_CodeID eTxtCID = CID_BLANK)
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(eChar)
TEXT_LABEL_63 tReason = GetLabel_enumFriendFailReason(eReason)
TEXT_LABEL_63 tCID = Get_Debug_String_For_Communication_Code_ID(eTxtCID)
CPRINTLN(DEBUG_FRIENDS, "Private_QueueFailReason(", tChar, ", ", tReason, ", ", tCID, ")")
#ENDIF
// Add to end of queue...
IF gActivity.iFailQueueCount < MAX_QUEUED_FAILS
gActivity.mFailQueue[gActivity.iFailQueueCount].eChar = eChar
gActivity.mFailQueue[gActivity.iFailQueueCount].eReason = eReason
gActivity.mFailQueue[gActivity.iFailQueueCount].eTxtCID = eTxtCID
gActivity.iFailQueueCount++
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_QueueFailReason() - Out of queued fail slots")
SCRIPT_ASSERT("Private_QueueFailReason() - Out of queued fail slots")
ENDIF
ENDPROC
PROC Private_InitFailReasonQueue()
gActivity.iFailQueueCount = 0
ENDPROC
PROC Private_ProcessFailReasonQueue()
// Try to print first queued fail reason in list
IF gActivity.iFailQueueCount > 0
// Can display now?
IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(gActivity.mFailQueue[0].eChar)
TEXT_LABEL_63 tReason = GetLabel_enumFriendFailReason(gActivity.mFailQueue[0].eReason)
TEXT_LABEL_63 tCID = Get_Debug_String_For_Communication_Code_ID(gActivity.mFailQueue[0].eTxtCID)
CPRINTLN(DEBUG_FRIENDS, "Private_ProcessFailReasonQueue() ", tChar, " = ", tReason, " (CID: ", tCID, ")")
#ENDIF
// Get friend name + print fail reason
enumCharacterList eChar = gActivity.mFailQueue[0].eChar
enumFriend eFriend = GET_FRIEND_FROM_CHAR(gActivity.mFailQueue[0].eChar)
IF eFriend < MAX_FRIENDS
TEXT_LABEL tName = GLOBAL_CHARACTER_SHEET_GET_LABEL(eChar) //g_SavedGlobals.sFriendsData.g_FriendData[eFriend].charSheet.label - had bug where label was incorrect, inits in wrong order? Just use charsheet
// Print reason
SWITCH gActivity.mFailQueue[0].eReason
CASE FFR_Injured
IF eFriend <> FR_AMANDA
PRINT_HELP_WITH_STRING("FR_X_INJ_1m", tName)
ELSE
PRINT_HELP_WITH_STRING("FR_X_INJ_1f", tName)
ENDIF
IF gActivity.mFailQueue[0].eTxtCID <> CID_BLANK
Private_QueueTextMessage(gActivity.mFailQueue[0].eChar, FTM_FRIEND_HOSPITAL, DEFAULT, gActivity.mFailQueue[0].eTxtCID)
ENDIF
BREAK
CASE FFR_Flee
IF eFriend <> FR_AMANDA
PRINT_HELP_WITH_STRING("FR_X_FLEE_1m", tName)
ELSE
PRINT_HELP_WITH_STRING("FR_X_FLEE_1f", tName)
ENDIF
BREAK
CASE FFR_Attacked
IF eFriend <> FR_AMANDA
PRINT_HELP_WITH_STRING("FR_X_ATAC_1m", tName)
ELSE
PRINT_HELP_WITH_STRING("FR_X_ATAC_1f", tName)
ENDIF
BREAK
CASE FFR_Lost
IF eFriend <> FR_AMANDA
PRINT_HELP_WITH_STRING("FR_X_LOST_1m", tName)
ELSE
PRINT_HELP_WITH_STRING("FR_X_LOST_1f", tName)
ENDIF
Private_QueueTextMessage(gActivity.mFailQueue[0].eChar, FTM_FRIEND_LOST, DEFAULT, gActivity.mFailQueue[0].eTxtCID)
BREAK
CASE FFR_Late
PRINT_HELP_WITH_STRING("FR_X_LATE", tName)
Private_QueueTextMessage(gActivity.mFailQueue[0].eChar, FTM_FRIEND_STOOD_UP, DEFAULT, gActivity.mFailQueue[0].eTxtCID)
BREAK
ENDSWITCH
ELSE
SCRIPT_ASSERT("Private_PrintFailReason() - eChar is not one of the friend characters")
ENDIF
// Pop first queued fail
gActivity.iFailQueueCount--
INT i
REPEAT gActivity.iFailQueueCount i
gActivity.mFailQueue[i] = gActivity.mFailQueue[i+1]
ENDREPEAT
ENDIF
ENDIF
ENDPROC
//-------------------------------------------------------------------------------------------------------------------------------------------
// RESOURCES
//-------------------------------------------------------------------------------------------------------------------------------------------
FUNC BOOL Private_RequestFriendText()
IF NOT HAS_THIS_ADDITIONAL_TEXT_LOADED("FRIENDS", OBJECT_TEXT_SLOT)
CPRINTLN(DEBUG_FRIENDS, "REQUEST_ADDITIONAL_TEXT(\"FRIENDS\", OBJECT_TEXT_SLOT)")
REQUEST_ADDITIONAL_TEXT("FRIENDS", OBJECT_TEXT_SLOT)
RETURN FALSE
ELSE
RETURN TRUE
ENDIF
ENDFUNC
FUNC BOOL Private_LoadFriendPickupResources()
// Request resources
BOOL bTextLoaded = TRUE
BOOL bModelsLoaded = TRUE
IF NOT HAS_THIS_ADDITIONAL_TEXT_LOADED("FRIENDS", OBJECT_TEXT_SLOT)
CPRINTLN(DEBUG_FRIENDS, "REQUEST_ADDITIONAL_TEXT(\"FRIENDS\", OBJECT_TEXT_SLOT)")
REQUEST_ADDITIONAL_TEXT("FRIENDS", OBJECT_TEXT_SLOT)
bTextLoaded = FALSE
ENDIF
REQUEST_MODEL(MODEL_PhoneProp)
IF NOT HAS_MODEL_LOADED(MODEL_PhoneProp)
bModelsLoaded = FALSE
ENDIF
IF bTextLoaded AND bModelsLoaded
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_ReleaseFriendPickupResources()
SET_MODEL_AS_NO_LONGER_NEEDED(MODEL_PhoneProp)
ENDPROC
FUNC BOOL Private_CanSuggestActivity(enumActivityLocation eLoc)
IF gActivity.eNearestActivityLoc < MAX_ACTIVITY_LOCATIONS
AND gActivity.eNearestActivityLoc <> ALOC_tennis_michaelHouse
INT iTypeIndex = ENUM_TO_INT(g_ActivityLocations[eLoc].type)
IF IS_EXTENDED_BIT_SET(gActivity.bitsAllowedActivities, iTypeIndex)
AND NOT IS_EXTENDED_BIT_SET(gActivity.bitsSuggestedActivities, iTypeIndex)
IF Util_IsPedInsideRange(PLAYER_PED_ID(), ActivityLoc_GetCoord(eLoc), 175.0)//175.0)//120.0)//60.0)//45.0)
AND Util_IsPedOutsideRange(PLAYER_PED_ID(), ActivityLoc_GetCoord(eLoc), 75.0)//100.0)//120.0)//60.0)//45.0)
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_CanJimmySuggestBar(enumCharacterList ePlayerChar, enumCharacterList eFriendCharA, enumActivityLocation& eBestBarLoc)
IF eFriendCharA = CHAR_JIMMY
IF ( ePlayerChar = CHAR_MICHAEL AND NOT IS_BIT_SET(g_SavedGlobals.sFriendsData.g_iAmbChatBitfield, ENUM_TO_INT(FRCHATBIT_MJ_DRINKING)) )
OR ( ePlayerChar = CHAR_TREVOR AND NOT IS_BIT_SET(g_SavedGlobals.sFriendsData.g_iAmbChatBitfield, ENUM_TO_INT(FRCHATBIT_TJ_DRINKING)) )
IF NOT IS_EXTENDED_BIT_SET(gActivity.bitsSuggestedActivities, ENUM_TO_INT(ATYPE_bar))
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
enumActivityLocation eNearestBar = NO_ACTIVITY_LOCATION
FLOAT fNearestDist2 = 100000.0*100000.0
enumActivityLocation eLocLoop
REPEAT MAX_ACTIVITY_LOCATIONS eLocLoop
IF g_ActivityLocations[eLocLoop].type = ATYPE_bar
FLOAT fDist2 = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_STATIC_BLIP_POSITION(g_ActivityLocations[eLocLoop].sprite))
IF fNearestDist2 > fDist2
fNearestDist2 = fDist2
eNearestBar = eLocLoop
ENDIF
ENDIF
ENDREPEAT
IF eNearestBar <> NO_ACTIVITY_LOCATION
AND fNearestDist2 < 400.0*400.0
eBestBarLoc = eNearestBar
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
eBestBarLoc = NO_ACTIVITY_LOCATION
RETURN FALSE
ENDFUNC
PROC Private_SetActivitySuggested(enumCharacterList ePlayerChar, enumCharacterList eFriendCharA, enumActivityLocation eLoc)
SET_EXTENDED_BIT(gActivity.bitsSuggestedActivities, ENUM_TO_INT(g_ActivityLocations[eLoc].type))
IF eFriendCharA = CHAR_JIMMY
IF eLoc < MAX_ACTIVITY_LOCATIONS
AND g_ActivityLocations[eLoc].type = ATYPE_bar
IF ePlayerChar = CHAR_MICHAEL
SET_BIT(g_SavedGlobals.sFriendsData.g_iAmbChatBitfield, ENUM_TO_INT(FRCHATBIT_MJ_DRINKING))
ELIF ePlayerChar = CHAR_TREVOR
SET_BIT(g_SavedGlobals.sFriendsData.g_iAmbChatBitfield, ENUM_TO_INT(FRCHATBIT_TJ_DRINKING))
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC INT Private_GetFriendChatConditions()
INT iConditionsBitset = 0
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionAlways))
// Check if only one friend on activity
IF gActivity.mFriendB.eState = FRIEND_NULL
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionSingleFriend))
ENDIF
#if not USE_CLF_DLC
#if not USE_NRM_DLC
// Check if Michael has split from wife
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_AMANDA_HAVE_SPLIT)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionPostBreak))
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FINALE_A)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionPostBreakTrevorAlive))
ENDIF
ELSE
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionPreBreak))
ENDIF
// Check if exile has ended
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_TREVOR_EXILE_FINISHED)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionPostExile))
ELSE
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionPreExile))
ENDIF
// Check how far through Franklin's story we are
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_RESPAWNED_AFTER_FINALE)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEnd))
ELIF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FRANKLIN_MOVED_TO_HILLS_APARTMENT)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionMid))
ELSE
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEarly))
ENDIF
// End state...
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_RESPAWNED_AFTER_FINALE)
// Check if everyone is alive after credits
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_KILLED)
AND NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_TREVOR_KILLED)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEndAllAlive))
ENDIF
// Check if Michael is dead/alive after credits
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_KILLED)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEndMDead))
ELSE
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEndMAlive))
ENDIF
// Check if Trevor is dead/alive after credits
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_TREVOR_KILLED)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEndTDead))
ELSE
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEndTAlive))
ENDIF
ENDIF
// Check if before Trevor arrives
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FAMILY_4)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionBeforeTrevor))
ENDIF
// Check if before Trevor discovers Michael's betrayal
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_MICHAEL_1)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionBeforeBetrayal))
ENDIF
// Check if Trevor has discovered Michael's betrayal (+ haven't made up)
IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_TREVOR_HAVE_FALLEN_OUT)
AND NOT IS_BIT_SET(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionEnd))//AllAlive))
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionMichaelBetrayal))
ENDIF
// Check for Franklin/Lamar special cases
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_FRANKLIN_0) AND NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_LAMAR)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionFL0))
ENDIF
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_LAMAR) AND NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_FRANKLIN_2)
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionFL1))
ENDIF
#endif
#endif
// Check if player is in Los Santos
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF PRIVATE_IS_POINT_IN_CITY( GET_ENTITY_COORDS(PLAYER_PED_ID()) )
SET_BIT(iConditionsBitset, ENUM_TO_INT(FCHAT_ConditionInLosSantos))
ENDIF
ENDIF
RETURN iConditionsBitset
ENDFUNC
//---------------------------------------------------------------------------------------------------
//-- Objective Utils
//---------------------------------------------------------------------------------------------------
PROC Private_ClearPrint(STRING pTextLabel)
IF IS_THIS_PRINT_BEING_DISPLAYED(pTextLabel)
CLEAR_PRINTS()
ENDIF
ENDPROC
PROC Private_ClearPrintWithString(STRING pTextLabel, STRING pLiteralString)
IF IS_THIS_PRINT_BEING_DISPLAYED(pTextLabel, SCRIPT_PRINT_ONE_SUBSTRING, pLiteralString)
CLEAR_PRINTS()
ENDIF
ENDPROC
PROC Private_ClearHelpWithString(STRING pTextLabel, STRING pLiteralString)
IF IS_THIS_HELP_MESSAGE_WITH_STRING_BEING_DISPLAYED(pTextLabel, pLiteralString)
CLEAR_HELP()
ENDIF
ENDPROC
FUNC BOOL Private_GetAdjustedDropoffPos(enumFriendLocation eFriendLoc, VECTOR& vAdjustedDropoff)
structFDropoffScene scene
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF eFriendLoc <> NO_FRIEND_LOCATION
IF Private_FLOC_GetDropoffScene(eFriendLoc, scene)
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
vAdjustedDropoff = scene.vCarPos
ELSE
vAdjustedDropoff = scene.vPlayerPos
ENDIF
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//PROC PRIVATE_SetLocationBlipAttributes(BLIP_INDEX blipID, STATIC_BLIP_NAME_ENUM sprite)
// SET_BLIP_SPRITE(blipID, g_GameBlips[sprite].eSprite[0])
// SET_BLIP_COLOUR(blipID, BLIP_COLOUR_YELLOW)
// SET_BLIP_AS_SHORT_RANGE(blipID, TRUE)
//
// #IF IS_DEBUG_BUILD
// SET_BLIP_NAME_FROM_TEXT_FILE(blipID, DEBUG_GET_STRING_NAME_OF_STATIC_BLIP(ENUM_TO_INT(g_GameBlips[sprite].eSprite[0])))
// #ENDIF
//ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Member Utils
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_IsPlayerThirdParty()
enumCharacterList eCurrentPlayer = GET_CURRENT_PLAYER_PED_ENUM()
IF eCurrentPlayer <> gActivity.mPlayer.eChar
AND eCurrentPlayer <> gActivity.mFriendA.eChar
AND eCurrentPlayer <> gActivity.mFriendB.eChar
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_IsPlayerSwitching()
IF IS_PLAYER_PED_SWITCH_IN_PROGRESS()//(g_sPlayerPedRequest.eState = PR_STATE_PROCESSING)//
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_IsSwitchCamDescending()
IF IS_PLAYER_SWITCH_IN_PROGRESS()
IF GET_PLAYER_SWITCH_TYPE() <> SWITCH_TYPE_SHORT
AND GET_PLAYER_SWITCH_STATE() = SWITCH_STATE_JUMPCUT_DESCENT
AND GET_PLAYER_SWITCH_JUMP_CUT_INDEX() > 0
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL IS_PLAYER_IN_STRIPCLUB()
IF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = GET_INTERIOR_AT_COORDS(<<117.5826, -1284.4652, 27.2731>>)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_ResetFriendGroupTimers(structFriend& friend, enumFriendContactType eContactType, BOOL bIgnoreMyPickupState = FALSE)
// Reset last contact timers between friends that have been picked up
IF friend.bWasPickedUp OR bIgnoreMyPickupState
// IF /*gActivity.mPlayer.bWasPickedUp AND*/ gActivity.mPlayer.eChar <> friend.eChar
IF gActivity.mPlayer.eChar <> NO_CHARACTER AND gActivity.mPlayer.eChar <> friend.eChar
RESET_FRIEND_LAST_CONTACT_TIMER(gActivity.mPlayer.eChar, friend.eChar, eContactType)
ENDIF
IF gActivity.mFriendA.bWasPickedUp AND gActivity.mFriendA.eChar <> friend.eChar
RESET_FRIEND_LAST_CONTACT_TIMER(gActivity.mFriendA.eChar, friend.eChar, eContactType)
ENDIF
IF gActivity.mFriendB.bWasPickedUp AND gActivity.mFriendB.eChar <> friend.eChar
RESET_FRIEND_LAST_CONTACT_TIMER(gActivity.mFriendB.eChar, friend.eChar, eContactType)
ENDIF
ENDIF
ENDPROC
FUNC enumCharacterList Private_SetFriendsForcedSeats()
// PCF_PreventUsingLowerPrioritySeats - Try using this to fix motorbike bug
// Clear all from using front seat
IF IS_PED_UNINJURED(gActivity.mPlayer.hPed)
SET_PED_CONFIG_FLAG(gActivity.mPlayer.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, FALSE)
ENDIF
IF IS_PED_UNINJURED(gActivity.mFriendA.hPed)
SET_PED_CONFIG_FLAG(gActivity.mFriendA.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, FALSE)
ENDIF
IF IS_PED_UNINJURED(gActivity.mFriendB.hPed)
SET_PED_CONFIG_FLAG(gActivity.mFriendB.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, FALSE)
ENDIF
// If just one friend is picked up, force them to use front
IF IS_PED_UNINJURED(gActivity.mFriendA.hPed) AND gActivity.mFriendA.bWasPickedUp
IF NOT gActivity.mFriendB.bWasPickedUp
CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendsForcedSeats() - Forcing ", GetLabel_enumCharacterList(gActivity.mFriendA.eChar), " to use front seat")
SET_PED_CONFIG_FLAG(gActivity.mFriendA.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, TRUE)
RETURN gActivity.mFriendA.eChar
ENDIF
ENDIF
IF IS_PED_UNINJURED(gActivity.mFriendB.hPed) AND gActivity.mFriendB.bWasPickedUp
IF NOT gActivity.mFriendA.bWasPickedUp
CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendsForcedSeats() - Forcing ", GetLabel_enumCharacterList(gActivity.mFriendB.eChar), " to use front seat")
SET_PED_CONFIG_FLAG(gActivity.mFriendB.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, TRUE)
RETURN gActivity.mFriendA.eChar
ENDIF
ENDIF
// Else, don't force anyone to use front seat
CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendsForcedSeats() - Forcing NO ONE to use front seat")
RETURN NO_CHARACTER
ENDFUNC
PROC Private_RespotVehicle(VEHICLE_INDEX hVehicle, structFRespotData& respot, BOOL bForceExpand = FALSE)
IF IS_ENTITY_DEAD(hVehicle)
DELETE_VEHICLE(hVehicle)
ELSE
MODEL_NAMES eModel = GET_ENTITY_MODEL(hVehicle)
VECTOR vBoxMin, vBoxMax
GET_MODEL_DIMENSIONS(eModel, vBoxMin, vBoxMax)
CPRINTLN(DEBUG_FRIENDS, "Private_RespotVehicle() - pos = << ", respot.vCarPos.x, ", ", respot.vCarPos.y, ", ", respot.vCarPos.z, " >>, rot = ", respot.fCarRot)
// CPRINTLN(DEBUG_FRIENDS, "Private_RespotVehicle() - min = << ", vBoxMin.x, ", ", vBoxMin.y, ", ", vBoxMin.z, " >>, max = << ", vBoxMax.x, ", ", vBoxMax.y, ", ", vBoxMax.z, " >>")
// If model is large, expand parking spot
VECTOR vOffset = <<0.0, 0.0, 0.0>>
BOOL bExpand = FALSE
vBoxMax.x -= 1.02
vBoxMin.x += 1.02
vBoxMax.y -= 2.57
vBoxMin.y += 2.61
IF IS_BITMASK_SET(respot.expandDir, RESPOT_EXPAND_X_LEFT) AND (bForceExpand OR vBoxMax.x > 0)
vOffset.x -= vBoxMax.x
bExpand = TRUE
ELIF IS_BITMASK_SET(respot.expandDir, RESPOT_EXPAND_X_RIGHT) AND (bForceExpand OR vBoxMin.x < 0)
vOffset.x -= vBoxMin.x
bExpand = TRUE
ENDIF
IF IS_BITMASK_SET(respot.expandDir, RESPOT_EXPAND_Y_FORWARD) AND (bForceExpand OR vBoxMin.y < 0)
vOffset.y -= vBoxMin.y
bExpand = TRUE
ELIF IS_BITMASK_SET(respot.expandDir, RESPOT_EXPAND_Y_BACK) AND (bForceExpand OR vBoxMax.y > 0)
vOffset.y -= vBoxMax.y
bExpand = TRUE
ENDIF
IF bExpand
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tModel = GET_MODEL_NAME_FOR_DEBUG(eModel)
CPRINTLN(DEBUG_FRIENDS, "Private_RespotVehicleForActivity() - Adjusting for large vehicle [", tModel, "] offset = << ", vOffset.x, ", ", vOffset.y, ", ", vOffset.z, " >>")
#ENDIF
respot.vCarPos = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(respot.vCarPos, respot.fCarRot, vOffset)
ENDIF
SET_ENTITY_COORDS(hVehicle, respot.vCarPos+<<0,0,1>>, FALSE)
SET_ENTITY_HEADING(hVehicle, respot.fCarRot)
SET_VEHICLE_ON_GROUND_PROPERLY(hVehicle)
SET_VEHICLE_DOORS_SHUT(hVehicle)
ENDIF
ENDPROC
FUNC BOOL Private_RespotVehicleForActivity(VEHICLE_INDEX hVehicle, enumActivityLocation eLoc, BOOL bMustOwnVehicle = FALSE, BOOL bMustBeOffscreen = FALSE, BOOL bForceExpand = FALSE)
structFRespotData respot
IF Private_ALOC_GetRespotData(eLoc, respot)
IF DOES_ENTITY_EXIST(hVehicle)
IF bMustOwnVehicle = FALSE OR DOES_ENTITY_BELONG_TO_THIS_SCRIPT(hVehicle, FALSE)
// Special case: If in the SWIFT helicopter, place away from the telegraph poles
IF eLoc = ALOC_darts_hickBar
AND GET_ENTITY_MODEL(hVehicle) = SWIFT
respot.vCarPos = <<2015.5687, 3060.9106, 46.0499>>
respot.fCarRot = 62.5587
respot.expandDir = RESPOT_EXPAND_NONE
ENDIF
IF bMustBeOffscreen = FALSE
OR (NOT IS_ENTITY_ON_SCREEN(hVehicle) AND NOT IS_SPHERE_VISIBLE(respot.vCarPos, 5.0)) // Check if offscreen
OR (NOT IS_ENTITY_DEAD(hVehicle) AND NOT IS_ENTITY_VISIBLE(hVehicle)) // Check if render flag is false
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tLoc = GetLabel_enumActivityLocation(eLoc)
CPRINTLN(DEBUG_FRIENDS, "Private_RespotVehicleForActivity(", tLoc, ") - Placing car at <<", respot.vCarPos.x, ", ", respot.vCarPos.y, ", ", respot.vCarPos.z, ">> rot = ", respot.fCarRot)
#ENDIF
Private_RespotVehicle(hVehicle, respot, bForceExpand)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_UpdateFriendGroupSpacing()
enumGroupSpacing eDesiredSpacing = FSPACING_NORMAL
IF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) <> NULL
eDesiredSpacing = FSPACING_INTERIOR
ELIF gActivity.mFriendA.eChar = CHAR_JIMMY OR gActivity.mFriendA.eChar = CHAR_AMANDA
IF COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(PLAYER_PED_ID(), GET_ENTITY_COORDS(PLAYER_PED_ID()), 50.0) > 0
eDesiredSpacing = FSPACING_FIGHT
ENDIF
ENDIF
IF gActivity.eGroupSpacing != eDesiredSpacing
IF DOES_GROUP_EXIST(PLAYER_GROUP_ID())
gActivity.eGroupSpacing = eDesiredSpacing
IF eDesiredSpacing = FSPACING_NORMAL
CPRINTLN(DEBUG_FRIENDS, "RESET_GROUP_FORMATION_DEFAULT_SPACING(PLAYER_GROUP_ID()) - [FSPACING_NORMAL]")
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
RESET_GROUP_FORMATION_DEFAULT_SPACING(PLAYER_GROUP_ID())
ELIF eDesiredSpacing = FSPACING_INTERIOR
CPRINTLN(DEBUG_FRIENDS, "SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 1.5) - [FSPACING_INTERIOR]")
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 1.5)
ELIF eDesiredSpacing = FSPACING_FIGHT
CPRINTLN(DEBUG_FRIENDS, "SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 5.0) - [FSPACING_FIGHT]")
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_SURROUND_FACING_INWARDS)
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 6.5)
ELSE
gActivity.eGroupSpacing = FSPACING_INVALID
ENDIF
ELSE
gActivity.eGroupSpacing = FSPACING_INVALID
ENDIF
ENDIF
ENDPROC
#IF IS_DEBUG_BUILD
PROC DEBUG_DisplayGlobalFriendIDs(INT iRow)
TEXT_LABEL_63 tName
enumCharacterList eChar
iRow += CONST_iActivityDebugPrintLine
tName = "FRIEND_A_PED_ID(): "
IF DOES_ENTITY_EXIST(FRIEND_A_PED_ID())
eChar = GET_PLAYER_PED_ENUM(FRIEND_A_PED_ID())
IF eChar = NO_CHARACTER
eChar = GET_NPC_PED_ENUM(FRIEND_A_PED_ID())
ENDIF
tName += GetLabel_enumFriend(GET_FRIEND_FROM_CHAR(eChar))
IF NOT IS_PED_INJURED(FRIEND_A_PED_ID())
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_BLUE)
ELSE
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_RED)
ENDIF
ELSE
tName += "NULL"
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_RED)
ENDIF
iRow++
tName = "FRIEND_B_PED_ID(): "
IF DOES_ENTITY_EXIST(FRIEND_B_PED_ID())
eChar = GET_PLAYER_PED_ENUM(FRIEND_B_PED_ID())
IF eChar = NO_CHARACTER
eChar = GET_NPC_PED_ENUM(FRIEND_B_PED_ID())
ENDIF
tName += GetLabel_enumFriend(GET_FRIEND_FROM_CHAR(eChar))
IF NOT IS_PED_INJURED(FRIEND_B_PED_ID())
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_BLUE)
ELSE
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_RED)
ENDIF
ELSE
tName += "NULL"
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_RED)
ENDIF
ENDPROC
#ENDIF
//---------------------------------------------------------------------------------------------------
//-- Audio Utils
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_CanPlayAudio(structFriendAudio& audio)
IF audio.eState = FAUDIO_IDLE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_PlayAudio(structFriendAudio& audio, TEXT_LABEL& tBlock, TEXT_LABEL& tRoot)
IF audio.eState = FAUDIO_IDLE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
audio.eState = FAUDIO_QUEUEING
audio.tBlock = tBlock
audio.tRoot = tRoot
ENDIF
ENDIF
ENDPROC
PROC Private_PlayAudioFromLabel(structFriendAudio& audio, TEXT_LABEL& tBlock, TEXT_LABEL& tRoot, TEXT_LABEL& tLabel)
IF audio.eState = FAUDIO_IDLE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
audio.eState = FAUDIO_QUEUEING_LABEL
audio.tBlock = tBlock
audio.tRoot = tRoot
audio.tLabel = tLabel
ENDIF
ENDIF
ENDPROC
PROC Private_UpdateAudio(structFriendAudio& audio)
SWITCH audio.eState
CASE FAUDIO_QUEUEING
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF CREATE_CONVERSATION(gActivity.convPedsDefault, audio.tBlock, audio.tRoot, CONV_PRIORITY_AMBIENT_MEDIUM, DISPLAY_SUBTITLES)
CPRINTLN(DEBUG_FRIENDS, "Private_UpdateAudio() DIALOGUE [", audio.tBlock, "] ", audio.tRoot)
audio.eState = FAUDIO_PLAYING
ENDIF
ENDIF
BREAK
CASE FAUDIO_QUEUEING_LABEL
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF CREATE_CONVERSATION_FROM_SPECIFIC_LINE(gActivity.convPedsDefault, audio.tBlock, audio.tRoot, audio.tLabel, CONV_PRIORITY_AMBIENT_MEDIUM, DISPLAY_SUBTITLES)
CPRINTLN(DEBUG_FRIENDS, "Private_UpdateAudio() DIALOGUE [", audio.tBlock, "] ", audio.tRoot, " - from label ", audio.tLabel)
audio.eState = FAUDIO_PLAYING
ENDIF
ENDIF
BREAK
CASE FAUDIO_PLAYING
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
audio.eState = FAUDIO_IDLE
ENDIF
BREAK
ENDSWITCH
ENDPROC
PROC Private_StopAudio(structFriendAudio& audio, BOOL bFinishCurrentLine = FALSE)
STOP_SCRIPTED_CONVERSATION(bFinishCurrentLine)
audio.eState = FAUDIO_IDLE
ENDPROC
FUNC BOOL Private_GetAudioCurrentConversationLabel(structFriendAudio& audio, TEXT_LABEL& tBlock, TEXT_LABEL& tRoot, TEXT_LABEL& tLabel)
IF audio.eState = FAUDIO_PLAYING
IF IS_SCRIPTED_CONVERSATION_ONGOING()
tBlock = audio.tBlock
tRoot = audio.tRoot
tLabel = GET_STANDARD_CONVERSATION_LABEL_FOR_FUTURE_RESUMPTION()
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_IsLocalAudioPlaying(structFriendAudio& audio)
IF audio.eState = FAUDIO_PLAYING
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_StopLocalAudio(structFriendAudio& audio, BOOL bFinishCurrentLine = FALSE)
IF audio.eState = FAUDIO_PLAYING
STOP_SCRIPTED_CONVERSATION(bFinishCurrentLine)
ENDIF
audio.eState = FAUDIO_IDLE
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Dialogue Utils
//---------------------------------------------------------------------------------------------------
FUNC BOOL Private_SetDialogueState(structFriendDialogue& dialogue, enumFriendDialogueState eState, enumCharacterList eConvChar = NO_CHARACTER, enumFriendActivityPhrase eConvPhrase = NO_FRIEND_ACTIVITY_PHRASE)
// Get states priority
enumFriendDialoguePriority ePriority = FDIALOGUE_PRIORITY_IDLE
IF eState = FDIALOGUE_REJECTZONE ePriority = FDIALOGUE_PRIORITY_REJECTION
ELIF eState = FDIALOGUE_REJECTWAIT ePriority = FDIALOGUE_PRIORITY_REJECTION
ELIF eState = FDIALOGUE_REJECTCANCEL ePriority = FDIALOGUE_PRIORITY_REJECTION
ELIF eState = FDIALOGUE_REJECTED ePriority = FDIALOGUE_PRIORITY_REJECTION
ELIF eState = FDIALOGUE_BLOCKED ePriority = FDIALOGUE_PRIORITY_BLOCKED
ELIF eState = FDIALOGUE_SQUAD ePriority = FDIALOGUE_PRIORITY_BLOCKED
ELIF eState = FDIALOGUE_DRUNK ePriority = FDIALOGUE_PRIORITY_DRUNK
ELIF eState = FDIALOGUE_ROBBERY ePriority = FDIALOGUE_PRIORITY_ROBBERY
ELIF eState = FDIALOGUE_PICKUP ePriority = FDIALOGUE_PRIORITY_JOURNEY
ELIF eState = FDIALOGUE_AMBIENT ePriority = FDIALOGUE_PRIORITY_JOURNEY
ELIF eState = FDIALOGUE_RESULT ePriority = FDIALOGUE_PRIORITY_JOURNEY
ELIF eState = FDIALOGUE_DAMAGE ePriority = FDIALOGUE_PRIORITY_JOURNEY
ELIF eState = FDIALOGUE_COPS ePriority = FDIALOGUE_PRIORITY_COPS
ELIF eState = FDIALOGUE_CHAT ePriority = FDIALOGUE_PRIORITY_CHAT
ELIF eState = FDIALOGUE_COMMENT ePriority = FDIALOGUE_PRIORITY_COMMENT
ELIF eState = FDIALOGUE_SUGGESTION ePriority = FDIALOGUE_PRIORITY_COMMENT
ELIF eState = FDIALOGUE_PICKUP_IDLE ePriority = FDIALOGUE_PRIORITY_IDLE
ELIF eState = FDIALOGUE_JOURNEY_IDLE ePriority = FDIALOGUE_PRIORITY_IDLE
ELIF eState = FDIALOGUE_SQUAD_IDLE ePriority = FDIALOGUE_PRIORITY_IDLE
ENDIF
BOOL bIsBlocked = (ePriority > dialogue.eStatePriority)
#IF IS_DEBUG_BUILD
TEXT_LABEL_31 tState = GetLabel_enumFriendDialogueState(eState)
TEXT_LABEL_31 tPriority = GetLabel_enumFriendDialoguePriority(ePriority)
TEXT_LABEL_31 tChar = GetLabel_enumCharacterList(eConvChar)
TEXT_LABEL_31 tPhrase = GetLabel_enumFriendActivityPhrase(eConvPhrase)
TEXT_LABEL_63 tBlocked = ""
IF bIsBlocked
tBlocked = " failed, blocked by "
tBlocked += GetLabel_enumFriendDialogueState(dialogue.eState)
ENDIF
CPRINTLN(DEBUG_FRIENDS, "Private_SetDialogueState(", tState, ", ", tChar, ", ", tPhrase, ") - [", tPriority, tBlocked, "]")
#ENDIF
IF bIsBlocked = FALSE
dialogue.eState = eState
dialogue.eStatePriority = ePriority
dialogue.eConvChar = eConvChar
dialogue.eConvPhrase = eConvPhrase
dialogue.iCounter = 0
RESTART_TIMER_NOW(dialogue.mGeneralTimer)
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDFUNC
FUNC enumFriendDialogueState Private_GetDialogueState(structFriendDialogue& dialogue)
RETURN dialogue.eState
ENDFUNC
FUNC BOOL Private_IsDialogueDoingPickup(structFriendDialogue& dialogue)
IF dialogue.eState = FDIALOGUE_PICKUP
OR dialogue.eState = FDIALOGUE_AMBIENT
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL Private_IsDialogueDoingReject(structFriendDialogue& dialogue)
IF dialogue.eState = FDIALOGUE_REJECTZONE
OR dialogue.eState = FDIALOGUE_REJECTWAIT
OR dialogue.eState = FDIALOGUE_REJECTCANCEL
OR dialogue.eState = FDIALOGUE_REJECTED
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
PROC Private_EndDialogueState(structFriendDialogue& dialogue)
CPRINTLN(DEBUG_FRIENDS, "Private_EndDialogueState(", GetLabel_enumFriendDialogueState(dialogue.eState), ")")
dialogue.eState = FDIALOGUE_NONE
dialogue.eStatePriority = FDIALOGUE_PRIORITY_IDLE
dialogue.eConvChar = NO_CHARACTER
dialogue.eConvPhrase = NO_FRIEND_ACTIVITY_PHRASE
dialogue.iCounter = 0
ENDPROC
PROC Private_SetDialogueIdleState(structFriendDialogue& dialogue, enumFriendDialogueState eDefaultState)
CPRINTLN(DEBUG_FRIENDS, "Private_SetDialogueIdleState(", GetLabel_enumFriendDialogueState(eDefaultState), ")")
dialogue.eDefaultState = eDefaultState
ENDPROC
PROC Private_SetDialogueChatChars(structFriendDialogue& dialogue, enumCharacterList eChar0, enumCharacterList eChar1, enumCharacterList eChar2)
#IF IS_DEBUG_BUILD
TEXT_LABEL tChar0 = GetLabel_enumCharacterList(eChar0)
TEXT_LABEL tChar1 = GetLabel_enumCharacterList(eChar1)
TEXT_LABEL tChar2 = GetLabel_enumCharacterList(eChar2)
CPRINTLN(DEBUG_FRIENDS, "Private_SetDialogueChatChars(", tChar0, ", ", tChar1, ", ", tChar2, ")")
#ENDIF
dialogue.eChatChars[0] = eChar0
dialogue.eChatChars[1] = eChar1
dialogue.eChatChars[2] = eChar2
ENDPROC
PROC Private_UpdateChatResumption(structFriendDialogue& dialogue, structFriendAudio& audio)
IF Private_GetAudioCurrentConversationLabel(audio, dialogue.tChatResumeBlock, dialogue.tChatResumeRoot, dialogue.tChatResumeLabel)
dialogue.iChatStoredTime = GET_GAME_TIMER()
ELSE
dialogue.tChatResumeBlock = ""
dialogue.tChatResumeRoot = ""
dialogue.tChatResumeLabel = ""
ENDIF
ENDPROC
PROC Private_ClearChatResumption(structFriendDialogue& dialogue)
dialogue.tChatResumeBlock = ""
dialogue.tChatResumeRoot = ""
dialogue.tChatResumeLabel = ""
ENDPROC
FUNC BOOL Private_IsChatResumptionAvailable(structFriendDialogue& dialogue, INT iTimeout = -1)
IF iTimeout < 0
OR GET_GAME_TIMER() - dialogue.iChatStoredTime < iTimeout
IF NOT IS_STRING_NULL_OR_EMPTY(dialogue.tChatResumeBlock) AND NOT ARE_STRINGS_EQUAL(dialogue.tChatResumeBlock, "NULL")
AND NOT IS_STRING_NULL_OR_EMPTY(dialogue.tChatResumeRoot) AND NOT ARE_STRINGS_EQUAL(dialogue.tChatResumeRoot, "NULL")
AND NOT IS_STRING_NULL_OR_EMPTY(dialogue.tChatResumeLabel) AND NOT ARE_STRINGS_EQUAL(dialogue.tChatResumeLabel, "NULL")
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC