//- 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 "" 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 "" 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