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

1527 lines
51 KiB
Scheme
Executable File

//- commands headers -//
//- script headers -//
//- public headers -//
USING "player_ped_public.sch"
//- private headers -//
USING "friendActivity_memberFriend_private.sch"
USING "friendActivity_memberSoldier_private.sch"
#IF IS_DEBUG_BUILD
//- debug headers -//
#ENDIF
CONST_FLOAT CONST_fChatDelayMin 2.0//6.0
CONST_FLOAT CONST_fChatDelayMax 3.0//9.0
CONST_FLOAT CONST_fSuggestionDelaySecs 20.0
//-------------------------------------------------------------------------------------------------------------------------------------------
// FRIEND DIALOGUE UTILS
//-------------------------------------------------------------------------------------------------------------------------------------------
FUNC enumFriendActivityPhrase Private_GetPickupDialogueFromFriend(structFriend& player, structFriend& friend, BOOL& bIsLate)
CPRINTLN(DEBUG_FRIENDS, "Private_GetPickupDialogueFromFriend(), buddyWaitTimer/RealTimeMins = ", GET_TIMER_IN_SECONDS_SAFE(friend.mWaitTimer)/60.0)
bIsLate = FALSE
IF friend.bWasMetAmbiently
SCRIPT_ASSERT("Private_GetPickupDialogueFromFriend() - Friend was met ambiently, shouldn't be handled by normal pickup state")
RETURN NO_FRIEND_ACTIVITY_PHRASE
ENDIF
// Onfoot + friend just left own car -> Tell player can use my car
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_TIMER_STARTED(friend.mParkedTimer) AND NOT TIMER_DO_WHEN_READY(friend.mParkedTimer, 8.0)
RETURN FAP_PICKUP_YOUDRIVE
ENDIF
// Player car full -> Tell player need bigger car
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT DOES_VEHICLE_HAVE_FREE_SEAT( GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) )
RETURN FAP_PICKUP_FULLCAR
ENDIF
ENDIF
// Late -> Tell player off
IF (gActivity.bIsRural = FALSE AND TIMER_DO_WHEN_READY(friend.mWaitTimer, CONST_fLateDialogueInRealMintues*60.0))
OR (gActivity.bIsRural = TRUE AND TIMER_DO_WHEN_READY(friend.mWaitTimer, CONST_fLateDialogueInRealMintues_rural*60.0))
bIsLate = TRUE
RETURN FAP_PICKUP_LATE
ENDIF
// On foot -> Tell player car is needed
VEHICLE_INDEX hRecentPlayerVehicle = GET_PLAYERS_LAST_VEHICLE()
IF NOT IS_VEHICLE_DRIVEABLE(hRecentPlayerVehicle)
RETURN FAP_PICKUP_NOCAR
ENDIF
IF NOT IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), hRecentPlayerVehicle, <<15.0, 15.0, 15.0>>)
AND NOT IS_ENTITY_AT_ENTITY(friend.hPed, hRecentPlayerVehicle, <<15.0, 15.0, 15.0>>)
RETURN FAP_PICKUP_NOCAR
ENDIF
// Stupid car -> Comment on stupidity
IF IS_PED_IN_ANY_HELI(PLAYER_PED_ID())
OR IS_PED_IN_ANY_BOAT(PLAYER_PED_ID())
OR IS_PED_IN_ANY_TAXI(PLAYER_PED_ID())
OR IS_PED_IN_ANY_PLANE(PLAYER_PED_ID())
OR IS_PED_IN_ANY_POLICE_VEHICLE(PLAYER_PED_ID())
OR IS_VEHICLE_MODEL_ON_BLACKLIST(GET_ENTITY_MODEL(hRecentPlayerVehicle))
OR GET_ENTITY_HEALTH(hRecentPlayerVehicle) < 500
// Block this line if it's Michael picking up Jimmy and not in a car (the dialogue line uses the word "car" so not appropriate)
IF player.eChar != CHAR_MICHAEL
AND friend.eChar != CHAR_JIMMY
AND NOT IS_PED_IN_ANY_HELI(PLAYER_PED_ID())
AND NOT IS_PED_IN_ANY_BOAT(PLAYER_PED_ID())
AND NOT IS_PED_IN_ANY_PLANE(PLAYER_PED_ID())
RETURN FAP_PICKUP_ODDCAR
ENDIF
ENDIF
// Otherwise -> Normal hello
RETURN FAP_PICKUP_OK
ENDFUNC
FUNC enumFriendActivityPhrase Private_GetPickupDialogue(enumCharacterList eChar, BOOL& bIsLate)
IF eChar = gActivity.mFriendA.eChar
RETURN Private_GetPickupDialogueFromFriend(gActivity.mPlayer, gActivity.mFriendA, bIsLate)
ELIF eChar = gActivity.mFriendB.eChar
RETURN Private_GetPickupDialogueFromFriend(gActivity.mPlayer, gActivity.mFriendB, bIsLate)
ENDIF
RETURN NO_FRIEND_ACTIVITY_PHRASE
ENDFUNC
FUNC enumFriendActivityPhrase Private_GetGreetDialogue(enumCharacterList eChar)
INT iLikeStat = GET_FRIEND_LIKE(GET_CURRENT_PLAYER_PED_ENUM(), eChar)
IF gActivity.mFriendA.eChar = eChar
AND DOES_ENTITY_EXIST(gActivity.mFriendA.hCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), gActivity.mFriendA.hCar) AND Private_IsVehicleOwnedByPed(gActivity.mFriendA.hCar, gActivity.mFriendA.hPed)
RETURN FAP_GREET_YOUDRIVE
ELIF gActivity.mFriendB.eChar = eChar
AND DOES_ENTITY_EXIST(gActivity.mFriendB.hCar) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), gActivity.mFriendB.hCar) AND Private_IsVehicleOwnedByPed(gActivity.mFriendA.hCar, gActivity.mFriendA.hPed)
RETURN FAP_GREET_YOUDRIVE
ELIF gActivity.mFriendA.eState = FRIEND_GROUP
AND gActivity.mFriendB.eState = FRIEND_GROUP
RETURN FAP_GREET_PLURAL
ELIF iLikeStat < 20
RETURN FAP_GREET_VIRATE
ELIF iLikeStat < 40
RETURN FAP_GREET_IRATE
ENDIF
RETURN FAP_GREET_OK
ENDFUNC
FUNC enumFriendActivityPhrase Private_GetHomeDialogue()
IF gActivity.iVisitedCount = 1
RETURN FAP_SATISFIED
ELIF gActivity.bTakeFriendHome
RETURN FAP_DONE
ENDIF
RETURN NO_FRIEND_ACTIVITY_PHRASE
ENDFUNC
FUNC enumFriendActivityPhrase Private_GetRejectZoneDialogue()
IF NOT IS_PED_INJURED(PLAYER_PED_ID()) AND IS_PED_DRUNK(PLAYER_PED_ID())
CPRINTLN(DEBUG_FRIENDS, "Private_GetRejectZoneDialogue() - Using drunk version [FAP_MISSIONZONE_DRUNK]")
RETURN FAP_MISSIONZONE_DRUNK
ENDIF
RETURN FAP_MISSIONZONE_STORY
ENDFUNC
FUNC enumFriendActivityPhrase Private_GetRejectCancelDialogue()
IF NOT IS_PED_INJURED(PLAYER_PED_ID()) AND IS_PED_DRUNK(PLAYER_PED_ID())
CPRINTLN(DEBUG_FRIENDS, "Private_GetRejectCancelDialogue() - Using drunk version [FAP_MISSIONZONE_CANCEL_DRUNK]")
RETURN FAP_MISSIONZONE_CANCEL_DRUNK
ENDIF
RETURN FAP_MISSIONZONE_CANCEL
ENDFUNC
//FUNC BOOL Private_IsFriendOkForConversation(structFriend& friend, VEHICLE_INDEX hMustBeInThisCar = NULL, BOOL bCanBeInCombat = FALSE)
//
// IF IS_PED_UNINJURED(PLAYER_PED_ID())
// IF friend.state = FRIEND_GROUP
//
// IF bCanBeInCombat OR NOT IS_PED_IN_COMBAT(friend.hPed)
//
// IF DOES_ENTITY_EXIST(hMustBeInThisCar)
// IF NOT IS_PED_IN_VEHICLE(friend.hPed, hMustBeInThisCar)
// RETURN FALSE
// ENDIF
// ELSE
// IF NOT IS_ENTITY_AT_COORD(friend.hPed, vPlayerPos, <<25.0,25.0,25.0>>)
// RETURN FALSE
// ENDIF
// ENDIF
//
// ENDIF
// ENDIF
// ENDIF
//
// RETURN TRUE
//ENDFUNC
FUNC enumCharacterList Private_GetConversationChar(BOOL bMustBeOutside = FALSE)
enumCharacterList groupChars[5]
INT iCharCount = 0
IF Private_CanFriendConverse(gActivity.mFriendA)
IF bMustBeOutside = FALSE OR Private_IsFriendOutside(gActivity.mFriendA)
groupChars[iCharCount] = gActivity.mFriendA.eChar
iCharCount++
ENDIF
ENDIF
IF Private_CanFriendConverse(gActivity.mFriendB)
IF bMustBeOutside = FALSE OR Private_IsFriendOutside(gActivity.mFriendB)
groupChars[iCharCount] = gActivity.mFriendB.eChar
iCharCount++
ENDIF
ENDIF
INT i
REPEAT MAX_BATTLE_BUDDIES i
IF Private_CanSoldierConverse(gActivity.mSoldiers[i])
IF bMustBeOutside = FALSE OR Private_IsSoldierOutside(gActivity.mSoldiers[i])
groupChars[iCharCount] = gActivity.mSoldiers[i].eChar
iCharCount++
ENDIF
ENDIF
ENDREPEAT
IF iCharCount > 0
RETURN groupChars[GET_RANDOM_INT_IN_RANGE(0, iCharCount)]
ENDIF
RETURN NO_CHARACTER
ENDFUNC
//FUNC BOOL Private_IsGroupTogether(BOOL bAllInCar = FALSE)
//
// VEHICLE_INDEX hPlayerVehicle
// IF bAllInCar
// hPlayerVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
// IF NOT DOES_ENTITY_EXIST(hPlayerVehicle)
// RETURN FALSE
// ENDIF
// ENDIF
//
// IF gActivity.mFriendA.bWasPickedUp
// IF gActivity.mFriendA.state <> FRIEND_GROUP
// OR IS_PED_INJURED(gActivity.mFriendA.hPed)
// OR (bAllInCar AND NOT IS_PED_IN_VEHICLE(gActivity.mFriendA.hPed, hPlayerVehicle))
// RETURN FALSE
// ENDIF
// ENDIF
//
// IF gActivity.mFriendB.bWasPickedUp
// IF gActivity.mFriendB.state <> FRIEND_GROUP
// OR IS_PED_INJURED(gActivity.mFriendB.hPed)
// OR (bAllInCar AND NOT IS_PED_IN_VEHICLE(gActivity.mFriendB.hPed, hPlayerVehicle))
// RETURN FALSE
// ENDIF
// ENDIF
//
// RETURN TRUE
//ENDFUNC
FUNC BOOL Private_CanStartFriendChat(BOOL bBlockedByGodText = FALSE)
// Check all the conditions that could stop a chat happening
IF IS_PED_INJURED(PLAYER_PED_ID())
RETURN FALSE
ELIF bBlockedByGodText AND IS_MESSAGE_BEING_DISPLAYED()
RETURN FALSE
ELIF IS_PLAYER_IN_ANY_SHOP()
RETURN FALSE
ELIF gActivity.mFriendA.bWasPickedUp = FALSE AND gActivity.mFriendB.bWasPickedUp = FALSE
RETURN FALSE
ELSE
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
VEHICLE_INDEX hPlayerVehicle = NULL
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
hPlayerVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
ENDIF
IF gActivity.mFriendA.bWasPickedUp
IF gActivity.mFriendA.eState <> FRIEND_GROUP
OR IS_PED_IN_COMBAT(gActivity.mFriendA.hPed)
RETURN FALSE
ELSE
IF DOES_ENTITY_EXIST(hPlayerVehicle)
IF NOT IS_PED_IN_VEHICLE(gActivity.mFriendA.hPed, hPlayerVehicle)
RETURN FALSE
ENDIF
ELSE
IF NOT IS_ENTITY_AT_COORD(gActivity.mFriendA.hPed, vPlayerPos, <<25.0,25.0,25.0>>)
RETURN FALSE
ENDIF
ENDIF
ENDIF
ENDIF
IF gActivity.mFriendB.bWasPickedUp
IF gActivity.mFriendB.eState <> FRIEND_GROUP
OR IS_PED_IN_COMBAT(gActivity.mFriendB.hPed)
RETURN FALSE
ELSE
IF DOES_ENTITY_EXIST(hPlayerVehicle)
IF NOT IS_PED_IN_VEHICLE(gActivity.mFriendB.hPed, hPlayerVehicle)
RETURN FALSE
ENDIF
ELSE
IF NOT IS_ENTITY_AT_COORD(gActivity.mFriendB.hPed, vPlayerPos, <<25.0,25.0,25.0>>)
RETURN FALSE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL Private_CanStartFriendComment(BOOL bBlockedByGodText = FALSE)
// Check all the conditions that could stop a comment happening
IF IS_PED_INJURED(PLAYER_PED_ID())
RETURN FALSE
ELIF bBlockedByGodText AND IS_MESSAGE_BEING_DISPLAYED()
RETURN FALSE
ELIF IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()
RETURN FALSE
ELSE
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
IF gActivity.mFriendA.bWasPickedUp
IF gActivity.mFriendA.eState <> FRIEND_GROUP
OR NOT IS_ENTITY_AT_COORD(gActivity.mFriendA.hPed, vPlayerPos, <<25.0, 25.0, 25.0>>)
OR IS_PED_IN_COMBAT(gActivity.mFriendA.hPed)
RETURN FALSE
ENDIF
ENDIF
IF gActivity.mFriendB.bWasPickedUp
IF gActivity.mFriendB.eState <> FRIEND_GROUP
OR NOT IS_ENTITY_AT_COORD(gActivity.mFriendB.hPed, vPlayerPos, <<25.0, 25.0, 25.0>>)
OR IS_PED_IN_COMBAT(gActivity.mFriendB.hPed)
RETURN FALSE
ENDIF
ENDIF
ENDIF
RETURN TRUE
ENDFUNC
FUNC BOOL Private_CanFriendContinueChat(enumCharacterList eChar)
IF eChar = GET_CURRENT_PLAYER_PED_ENUM()
RETURN TRUE
ELSE
IF gActivity.mFriendA.eChar = eChar
IF gActivity.mFriendA.eState = FRIEND_GROUP
RETURN TRUE
ENDIF
ENDIF
IF gActivity.mFriendB.eChar = eChar
IF gActivity.mFriendB.eState = FRIEND_GROUP
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC FLOAT Private_GetChatDelay(structFriendDialogue& dialogue)
FLOAT fMinDelay = CONST_fChatDelayMin + (TO_FLOAT(dialogue.iJourneyChatCounter) * 1.5)
FLOAT fMaxDelay = CONST_fChatDelayMax + (TO_FLOAT(dialogue.iJourneyChatCounter) * 1.5)
RETURN GET_RANDOM_FLOAT_IN_RANGE(fMaxDelay*-60.0, fMinDelay*-60.0)
ENDFUNC
FUNC BOOL Private_PlayAmbientComment(enumCharacterList eChar, STRING sComment)
PED_INDEX hPed = NULL
IF eChar = gActivity.mFriendA.eChar
hPed = gActivity.mFriendA.hPed
ELIF eChar = gActivity.mFriendB.eChar
hPed = gActivity.mFriendB.hPed
ELIF IS_PLAYER_PED_PLAYABLE(eChar)
hPed = gActivity.mSoldiers[eChar].hPed
ENDIF
IF NOT IS_PED_INJURED(hPed)
#IF IS_DEBUG_BUILD
TEXT_LABEL tChar = GetLabel_enumCharacterList(eChar)
CPRINTLN(DEBUG_FRIENDS, "Private_PlayAmbientComment(", sComment, ") - from ", tChar)
#ENDIF
PLAY_PED_AMBIENT_SPEECH(hPed, sComment, SPEECH_PARAMS_FORCE_FRONTEND)
RETURN TRUE
ENDIF
SCRIPT_ASSERT("Private_PlayAmbientComment() - passed in eChar is not alive")
RETURN FALSE
ENDFUNC
//-------------------------------------------------------------------------------------------------------------------------------------------
// FRIEND DIALOGUE STATE MACHINE
//-------------------------------------------------------------------------------------------------------------------------------------------
PROC Private_ProcessDialogue(structFriendDialogue& dialogue, structFriendAudio& audio)
TEXT_LABEL tBlock, tRoot
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
SWITCH dialogue.eState
//------------------------------------------------------------------------------------------------- FDIALOGUE_NONE
CASE FDIALOGUE_NONE
IF dialogue.eDefaultState <> FDIALOGUE_NONE
Private_SetDialogueState(dialogue, dialogue.eDefaultState)
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_REJECTZONE
CASE FDIALOGUE_REJECTZONE
IF dialogue.iCounter = 0
IF NOT Private_CanPlayAudio(audio)
Private_StopAudio(audio)
ELSE
dialogue.eConvChar = Private_GetConversationChar()
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, Private_GetRejectZoneDialogue(), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
Private_SetDialogueState(dialogue, FDIALOGUE_REJECTWAIT)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_REJECTWAIT
CASE FDIALOGUE_REJECTWAIT
// Wait
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_REJECTCANCEL
CASE FDIALOGUE_REJECTCANCEL
IF dialogue.iCounter = 0
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 20.0)
dialogue.iCounter++
ELIF Private_CanPlayAudio(audio)
dialogue.eConvChar = Private_GetConversationChar()
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, Private_GetRejectCancelDialogue(), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_REJECTED
CASE FDIALOGUE_REJECTED
IF dialogue.eConvChar = NO_CHARACTER
Private_EnddialogueState(dialogue)
ELIF dialogue.iCounter = 0
IF Private_CanPlayAudio(audio)
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, dialogue.eConvPhrase, tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_BLOCKED
CASE FDIALOGUE_BLOCKED
IF IS_PED_INJURED(PLAYER_PED_ID()) OR NOT IS_PLAYER_IN_ANY_SHOP()
Private_EndDialogueState(dialogue)
ELSE
Private_StopLocalAudio(audio, TRUE)
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_SQUAD
CASE FDIALOGUE_SQUAD
IF dialogue.iCounter = 0
IF NOT Private_CanPlayAudio(audio)
Private_StopAudio(audio, TRUE)
ENDIF
Private_EndDialogueState(dialogue)
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_DRUNK
CASE FDIALOGUE_DRUNK
IF dialogue.iCounter = 0
Private_StopAudio(audio)
IF TIMER_DO_WHEN_READY(dialogue.mChatTimer, -100.0)
RESTART_TIMER_AT(dialogue.mChatTimer, -100.0)
ENDIF
dialogue.iCounter++
ELIF dialogue.iCounter = 1
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 60.0)
dialogue.iCounter++
ELIF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 3.0)
IF Private_CanStartFriendChat(TRUE)
IF Private_CanPlayAudio(audio)
IF ePlayerChar = CHAR_TREVOR AND gActivity.mFriendA.eChar = CHAR_LAMAR // Special case: Trevor/Lamar have no drunk dialogue, so use some of the Lamar monolgues from drunk Trevor/Lamar/Franklin banks
AND Private_GetFriendChat(CHAR_TREVOR, CHAR_LAMAR, CHAR_FRANKLIN, FCHAT_TypeDrunk, Private_GetFriendChatConditions(), tBlock, tRoot, TRUE)
Private_PlayAudio(audio, tBlock, tRoot)
dialogue.iCounter++
ELIF Private_GetFriendChat(ePlayerChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar, FCHAT_TypeDrunk, Private_GetFriendChatConditions(), tBlock, tRoot, TRUE)
Private_PlayAudio(audio, tBlock, tRoot)
dialogue.iCounter++
ELSE
dialogue.eConvChar = Private_GetConversationChar()
IF dialogue.eConvChar = NO_CHARACTER
OR NOT Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, FAP_VERY_DRUNK, tBlock, tRoot)
dialogue.iCounter++
ELSE
Private_PlayAudio(audio, tBlock, tRoot)
dialogue.iCounter++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELIF dialogue.iCounter = 2
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_ROBBERY
CASE FDIALOGUE_ROBBERY
IF NOT IS_BIT_SET(g_bitfieldFriendFlags, ENUM_TO_INT(FRIENDFLAG_IS_ROBBERY_UNDERWAY))
IF (IS_PED_INJURED(PLAYER_PED_ID()) OR NOT IS_PLAYER_IN_ANY_SHOP())
// Private_ClearChatResumption(dialogue)
Private_EndDialogueState(dialogue)
ENDIF
ELSE
Private_StopLocalAudio(audio, TRUE)
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 0.0)
IF NOT Private_IsLocalAudioPlaying(audio)
PED_INDEX hPed
hPed = NULL
IF GET_RANDOM_BOOL()
IF Private_CanFriendConverse(gActivity.mFriendA)
hPed = gActivity.mFriendA.hPed
ENDIF
ELSE
IF Private_CanFriendConverse(gActivity.mFriendB)
hPed = gActivity.mFriendB.hPed
ENDIF
ENDIF
IF NOT IS_PED_INJURED(hPed) AND NOT IS_ANY_SPEECH_PLAYING(hPed)
PLAY_PED_AMBIENT_SPEECH(hPed, "ROBBERY_FRIEND_WITNESS", SPEECH_PARAMS_FORCE)
IF IS_ANY_SPEECH_PLAYING(hPed)
RESTART_TIMER_AT(dialogue.mGeneralTimer, -5.0) //GET_RANDOM_FLOAT_IN_RANGE(-5.0, -3.0))
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_PICKUP
CASE FDIALOGUE_PICKUP
// Abort if don't have pickup char
IF dialogue.eConvChar = NO_CHARACTER
Private_EndDialogueState(dialogue)
// Stop audio / Play pickup phrase
ELIF dialogue.iCounter = 0
IF NOT Private_CanPlayAudio(audio)
Private_StopAudio(audio)
ELSE
BOOL bIsLate
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, Private_GetPickupDialogue(dialogue.eConvChar, bIsLate), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
IF bIsLate
UPDATE_FRIEND_LIKE(ePlayerChar, dialogue.eConvChar, FriendLike_PLAYER_LATE_ARRIVAL)
ENDIF
RESTART_TIMER_NOW(dialogue.mGeneralTimer)
dialogue.iCounter++
ENDIF
// Wait for phrase end
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
dialogue.iCounter++
ENDIF
// Wait for player to get in a car (or timeout at 20s)
ELIF dialogue.iCounter = 2
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 20.0)
OR IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
dialogue.iCounter++
ENDIF
// Play greet phrase (or timeout at 30s)
ELIF dialogue.iCounter = 3
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 30.0)
OR NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
dialogue.iCounter++
ELIF IS_PED_IN_VEHICLE(Private_GetGlobalPed(dialogue.eConvChar), GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
IF Private_CanPlayAudio(audio)
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, Private_GetGreetDialogue(dialogue.eConvChar), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ENDIF
// Wait for phrase to end
ELIF dialogue.iCounter = 4
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_AMBIENT
CASE FDIALOGUE_AMBIENT
Private_EndDialogueState(dialogue)
// // Abort if don't have pickup char
// IF dialogue.eConvChar = NO_CHARACTER
// Private_EndDialogueState(dialogue)
//
// // Stop audio / Play pickup phrase
// ELIF dialogue.iCounter = 0
// IF NOT Private_CanPlayAudio(audio)
// Private_StopAudio(audio, TRUE)
// ELSE
// IF Private_IsFriendValid(gActivity.mFriendA) AND Private_IsFriendValid(gActivity.mFriendB)
// IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, FAP_GREET_PLURAL, tBlock, tRoot)
// Private_PlayAudio(audio, tBlock, tRoot)
// ENDIF
//
// ELIF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
// IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, FAP_AMBIENT_OFFER_YES2, tBlock, tRoot)
// Private_PlayAudio(audio, tBlock, tRoot)
// ENDIF
// ENDIF
// dialogue.iCounter++
// ENDIF
//
// // Wait for phrase end
// ELIF dialogue.iCounter = 1
// IF Private_CanPlayAudio(audio)
// Private_EndDialogueState(dialogue)
// ENDIF
// ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_RESULT
CASE FDIALOGUE_RESULT
// Stop audio
IF dialogue.iCounter = 0
IF Private_GetActivityLocType(g_ePreviousActivityLoc) <> ATYPE_cinema
Private_StopAudio(audio)
dialogue.iCounter++
ELSE
dialogue.iCounter = 2
ENDIF
// Say result comment
ELIF dialogue.iCounter = 1
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 30.0)
dialogue.iCounter++
ELIF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 0.5)
IF Private_CanPlayAudio(audio)
IF g_ePreviousActivityLoc < MAX_ACTIVITY_LOCATIONS
AND g_ActivityLocations[g_ePreviousActivityLoc].type = ATYPE_tennis
AND gActivity.mPlayer.eChar = CHAR_MICHAEL
AND gActivity.mFriendA.eChar = CHAR_AMANDA
IF NOT IS_PED_INJURED(gActivity.mFriendA.hPed)
IF g_ePreviousActivityResult = AR_playerWon
PLAY_PED_AMBIENT_SPEECH(gActivity.mFriendA.hPed, "FAC_LEAVE_TENNIS_WON", SPEECH_PARAMS_FORCE)
ELIF g_ePreviousActivityResult = AR_buddyA_won
PLAY_PED_AMBIENT_SPEECH(gActivity.mFriendA.hPed, "FAC_LEAVE_TENNIS_LOST", SPEECH_PARAMS_FORCE)
ELIF g_ePreviousActivityResult = AR_playerQuit
PLAY_PED_AMBIENT_SPEECH(gActivity.mFriendA.hPed, "FAC_LEAVE_TENNIS_QUIT", SPEECH_PARAMS_FORCE)
ENDIF
ENDIF
dialogue.iCounter++
ELIF g_ePreviousActivityLoc = ALOC_stripclub_southCentral
dialogue.eConvChar = Private_GetConversationChar(TRUE)
IF dialogue.eConvChar <> NO_CHARACTER
IF Private_GetFriendActivityResult(ePlayerChar, dialogue.eConvChar, g_ePreviousActivityLoc, g_ePreviousActivityResult, Is_Ped_Drunk(PLAYER_PED_ID()), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ELSE
dialogue.eConvChar = Private_GetConversationChar()
IF Private_GetFriendActivityResult(ePlayerChar, dialogue.eConvChar, g_ePreviousActivityLoc, g_ePreviousActivityResult, Is_Ped_Drunk(PLAYER_PED_ID()), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ENDIF
ENDIF
// Wait for it to end
ELIF dialogue.iCounter = 2
IF g_ePreviousActivityLoc < MAX_ACTIVITY_LOCATIONS
AND g_ActivityLocations[g_ePreviousActivityLoc].type = ATYPE_tennis
AND gActivity.mPlayer.eChar = CHAR_MICHAEL
AND gActivity.mFriendA.eChar = CHAR_AMANDA
IF IS_PED_INJURED(gActivity.mFriendA.hPed) OR NOT IS_ANY_SPEECH_PLAYING(gActivity.mFriendA.hPed)
RESTART_TIMER_NOW(dialogue.mGeneralTimer)
dialogue.iCounter++
ENDIF
ELSE
IF Private_CanPlayAudio(audio)
RESTART_TIMER_NOW(dialogue.mGeneralTimer)
dialogue.iCounter++
ENDIF
ENDIF
// Say can go home/want to go home
ELIF dialogue.iCounter = 3
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 1.5)
IF Private_CanStartFriendComment(TRUE)
IF Private_CanPlayAudio(audio)
dialogue.eConvChar = Private_GetConversationChar()
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, Private_GetHomeDialogue(), tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ENDIF
ENDIF
// End state
ELIF dialogue.iCounter = 4
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_DAMAGE
CASE FDIALOGUE_DAMAGE
IF dialogue.eConvChar = NO_CHARACTER
Private_EndDialogueState(dialogue)
ELIF dialogue.iCounter = 0
Private_StopLocalAudio(audio, FALSE)
PED_INDEX hPed
hPed = Private_GetGlobalPed(dialogue.eConvChar)
IF IS_PED_INJURED(hPed) OR NOT IS_PED_RAGDOLL(hPed)
IF Private_CanPlayAudio(audio)
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, dialogue.eConvPhrase, tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ENDIF
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_COPS
CASE FDIALOGUE_COPS
IF IS_PED_INJURED(PLAYER_PED_ID()) OR NOT IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
Private_EndDialogueState(dialogue)
ELSE
Private_StopLocalAudio(audio, TRUE)
IF dialogue.iCounter = 0
IF NOT Private_IsLocalAudioPlaying(audio)
PED_INDEX hPed
hPed = NULL
IF GET_RANDOM_BOOL()
IF Private_CanFriendConverse(gActivity.mFriendA)
hPed = gActivity.mFriendA.hPed
ENDIF
ELSE
IF Private_CanFriendConverse(gActivity.mFriendB)
hPed = gActivity.mFriendB.hPed
ENDIF
ENDIF
IF NOT IS_PED_INJURED(hPed) AND NOT IS_ANY_SPEECH_PLAYING(hPed)
PLAY_PED_AMBIENT_SPEECH(hPed, "GET_WANTED_LEVEL", SPEECH_PARAMS_FORCE)
IF IS_ANY_SPEECH_PLAYING(hPed)
dialogue.iCounter++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_CHAT
CASE FDIALOGUE_CHAT
IF Private_CanPlayAudio(audio)
RESTART_TIMER_NOW(dialogue.mSuggestTimer)
Private_ClearChatResumption(dialogue)
Private_EndDialogueState(dialogue)
ELIF (dialogue.eChatChars[0] <> NO_CHARACTER AND NOT Private_CanFriendContinueChat(dialogue.eChatChars[0]))
OR (dialogue.eChatChars[1] <> NO_CHARACTER AND NOT Private_CanFriendContinueChat(dialogue.eChatChars[1]))
OR (dialogue.eChatChars[2] <> NO_CHARACTER AND NOT Private_CanFriendContinueChat(dialogue.eChatChars[2]))
Private_StopAudio(audio)
RESTART_TIMER_NOW(dialogue.mSuggestTimer)
Private_EndDialogueState(dialogue)
ELSE
// Store what line of converation we're on in case it gets interrupted
Private_UpdateChatResumption(dialogue, audio)
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_COMMENT
CASE FDIALOGUE_COMMENT
IF dialogue.eConvChar = NO_CHARACTER
Private_EndDialogueState(dialogue)
ELIF dialogue.iCounter = 0
Private_StopLocalAudio(audio, TRUE)
IF Private_CanPlayAudio(audio)
IF Private_GetFriendActivityPhrase(ePlayerChar, dialogue.eConvChar, dialogue.eConvPhrase, tBlock, tRoot)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
dialogue.iCounter++
ENDIF
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_SUGGESTION
CASE FDIALOGUE_SUGGESTION
IF Private_CanPlayAudio(audio)
Private_EndDialogueState(dialogue)
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_PICKUP_IDLE
CASE FDIALOGUE_PICKUP_IDLE
IF dialogue.iCounter = 0
IF dialogue.bHasDonePickupIdleChat = FALSE
IF Private_CanStartFriendChat()
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 5.0)
IF Private_CanPlayAudio(audio)
dialogue.eConvChar = Private_GetConversationChar()
IF Private_GetFriendChat(ePlayerChar, dialogue.eConvChar, NO_CHARACTER, FCHAT_TypeMini, Private_GetFriendChatConditions(), tBlock, tRoot, TRUE)
Private_PlayAudio(audio, tBlock, tRoot)
dialogue.bHasDonePickupIdleChat = TRUE
dialogue.iCounter++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// Wait for end, then restart state
ELIF dialogue.iCounter = 1
IF Private_CanPlayAudio(audio)
dialogue.iCounter = 0
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_JOURNEY_IDLE
CASE FDIALOGUE_JOURNEY_IDLE
// Start chat/comment
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND NOT Is_Ped_Drunk(PLAYER_PED_ID())
IF Private_CanPlayAudio(audio)
// Resume chat
IF Private_IsChatResumptionAvailable(dialogue, 120000)
IF NOT TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 15.0)
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 1.5)
AND Private_CanStartFriendChat()
IF Private_SetDialogueState(dialogue, FDIALOGUE_CHAT)
Private_PlayAudioFromLabel(audio, dialogue.tChatResumeBlock, dialogue.tChatResumeRoot, dialogue.tChatResumeLabel)
Private_SetDialogueChatChars(dialogue, dialogue.eChatChars[0], dialogue.eChatChars[1], dialogue.eChatChars[2])
RESTART_TIMER_AT(dialogue.mChatTimer, Private_GetChatDelay(dialogue))
Private_ClearChatResumption(dialogue)
ENDIF
ENDIF
ELSE
Private_ClearChatResumption(dialogue)
ENDIF
ELSE
// Main chat
IF dialogue.iJourneyChatCounter = 0
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 5.0)
AND TIMER_DO_WHEN_READY(dialogue.mChatTimer, 0.0)
IF Private_CanStartFriendChat()
IF Private_GetFriendChat(ePlayerChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar, FCHAT_TypeFull, Private_GetFriendChatConditions(), tBlock, tRoot, TRUE)
AND Private_SetDialogueState(dialogue, FDIALOGUE_CHAT)
Private_PlayAudio(audio, tBlock, tRoot)
Private_SetDialogueChatChars(dialogue, ePlayerChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar)
RESTART_TIMER_AT(dialogue.mChatTimer, Private_GetChatDelay(dialogue))
dialogue.iJourneyChatCounter++
ENDIF
ENDIF
ENDIF
// Mini chat
ELIF dialogue.iJourneyChatCounter < 3
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 5.0)
AND TIMER_DO_WHEN_READY(dialogue.mChatTimer, 0.0)
IF Private_CanStartFriendChat()
IF Private_GetFriendChat(ePlayerChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar, FCHAT_TypeMini, Private_GetFriendChatConditions(), tBlock, tRoot, TRUE)
AND Private_SetDialogueState(dialogue, FDIALOGUE_CHAT)
Private_PlayAudio(audio, tBlock, tRoot)
Private_SetDialogueChatChars(dialogue, ePlayerChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar)
RESTART_TIMER_AT(dialogue.mChatTimer, Private_GetChatDelay(dialogue))
dialogue.iJourneyChatCounter++
ENDIF
ENDIF
ENDIF
ENDIF
// Comments/suggestions...
IF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 3.0)
IF Private_CanStartFriendComment(TRUE)
enumCharacterList eCommentChar
// Changed tattoo
IF GET_TIME_PLAYER_PED_LAST_GOT_TATTOO(ePlayerChar) <> gActivity.iLastTattooChangeTime
eCommentChar = Private_GetConversationChar(TRUE)
IF eCommentChar <> NO_CHARACTER
Private_SetDialogueState(dialogue, FDIALOGUE_COMMENT, eCommentChar, FAP_COMMENT_TATTOO)
ENDIF
// Changed haircut
ELIF GET_TIME_PLAYER_PED_LAST_CHANGED_HAIRDO(ePlayerChar) <> gActivity.iLastHaircutChangeTime
eCommentChar = Private_GetConversationChar(TRUE)
IF eCommentChar <> NO_CHARACTER
Private_SetDialogueState(dialogue, FDIALOGUE_COMMENT, eCommentChar, FAP_COMMENT_HAIRCUT)
ENDIF
// Changed clothes
ELIF GET_TIME_PLAYER_PED_LAST_CHANGED_CLOTHES(ePlayerChar) <> gActivity.iLastClothesChangeTime
eCommentChar = Private_GetConversationChar(TRUE)
IF eCommentChar <> NO_CHARACTER
Private_SetDialogueState(dialogue, FDIALOGUE_COMMENT, eCommentChar, FAP_COMMENT_CLOTHES)
ENDIF
// Suggestion
ELIF TIMER_DO_WHEN_READY(dialogue.mGeneralTimer, 10.0)
IF dialogue.iJourneyChatCounter > 0
IF NOT IS_TIMER_STARTED(dialogue.mSuggestTimer) OR TIMER_DO_WHEN_READY(dialogue.mSuggestTimer, CONST_fSuggestionDelaySecs)
enumActivityLocation eSuggestLoc
eSuggestLoc = gActivity.eNearestActivityLoc
IF Private_CanSuggestActivity(eSuggestLoc)
OR Private_CanJimmySuggestBar(gActivity.mPlayer.eChar, gActivity.mFriendA.eChar, eSuggestLoc)
eCommentChar = Private_GetConversationChar()
// Check distance to activity
IF eCommentChar <> NO_CHARACTER
AND eSuggestLoc < MAX_ACTIVITY_LOCATIONS
IF Private_GetFriendActivitySuggestion(ePlayerChar, eCommentChar, eSuggestLoc, tBlock, tRoot)
AND Private_SetDialogueState(dialogue, FDIALOGUE_SUGGESTION)
Private_SetActivitySuggested(gActivity.mPlayer.eChar, gActivity.mFriendA.eChar, eSuggestLoc)
Private_PlayAudio(audio, tBlock, tRoot)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
//------------------------------------------------------------------------------------------------- FDIALOGUE_SQUAD_IDLE
CASE FDIALOGUE_SQUAD_IDLE
// Empty
BREAK
//-------------------------------------------------------------------------------------------------
DEFAULT
SCRIPT_ASSERT("Invalid friend dialogue state")
BREAK
ENDSWITCH
//-- Check for events...
// Cops
IF dialogue.eState != FDIALOGUE_COPS
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
Private_SetDialogueState(dialogue, FDIALOGUE_COPS)
ENDIF
ENDIF
ENDIF
// Robbery
IF dialogue.eState != FDIALOGUE_ROBBERY
IF IS_BIT_SET(g_bitfieldFriendFlags, ENUM_TO_INT(FRIENDFLAG_IS_ROBBERY_UNDERWAY))
Private_SetDialogueState(dialogue, FDIALOGUE_ROBBERY)
ENDIF
ENDIF
// Blocked
IF dialogue.eState != FDIALOGUE_BLOCKED
IF NOT IS_PED_INJURED(PLAYER_PED_ID()) AND IS_PLAYER_IN_ANY_SHOP()
Private_SetDialogueState(dialogue, FDIALOGUE_BLOCKED)
ENDIF
ENDIF
//-- Clear any clothes comments unless in a state where it would make sense to comment on them...
IF dialogue.eState != FDIALOGUE_PICKUP_IDLE
AND dialogue.eState != FDIALOGUE_JOURNEY_IDLE
AND dialogue.eState != FDIALOGUE_PICKUP
AND dialogue.eState != FDIALOGUE_AMBIENT
AND dialogue.eState != FDIALOGUE_RESULT
AND dialogue.eState != FDIALOGUE_BLOCKED
AND dialogue.eState != FDIALOGUE_NONE
gActivity.iLastClothesChangeTime = GET_TIME_PLAYER_PED_LAST_CHANGED_CLOTHES(ePlayerChar)
gActivity.iLastHaircutChangeTime = GET_TIME_PLAYER_PED_LAST_CHANGED_HAIRDO(ePlayerChar)
gActivity.iLastTattooChangeTime = GET_TIME_PLAYER_PED_LAST_GOT_TATTOO(ePlayerChar)
ENDIF
//-- Update audio...
Private_UpdateAudio(audio)
ENDPROC
//---------------------------------------------------------------------------------------------------
//-- Display Objectives
//---------------------------------------------------------------------------------------------------
PROC Private_ClearObjective()
IF gActivity.curObjective <> NO_FRIEND_ACTIVITY_OBJ
CPRINTLN(DEBUG_FRIENDS, "Private_ClearObjective()")
// Clear objective text
Private_ClearFriendObjectives(gActivity.mPlayer)
Private_ClearFriendObjectives(gActivity.mFriendA)
Private_ClearFriendObjectives(gActivity.mFriendB)
// Remove dropoff blip
IF DOES_BLIP_EXIST(gActivity.hDropoffBlip)
REMOVE_BLIP(gActivity.hDropoffBlip)
ENDIF
// Remove help from queue
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("FR_H_ACTIV1")
CLEAR_HELP()
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("FR_H_ACTIV2")
CLEAR_HELP()
ENDIF
// CLEAR_HELP() // Took this out as it was clearing fail reasons. Specific help strings should get cleared about by ClearFriendObjectives(), can't see how this would be needed on top of that
// Remove activity blips
IF gActivity.bRestoreLocationBlips
enumActivityLocation eLoc
STATIC_BLIP_NAME_ENUM activitySprite
REPEAT MAX_ACTIVITY_LOCATIONS eLoc
activitySprite = g_ActivityLocations[eLoc].sprite
IF IS_STATIC_BLIP_CURRENTLY_VISIBLE(activitySprite)
SET_STATIC_BLIP_ACTIVE_STATE(activitySprite, FALSE)
ENDIF
ENDREPEAT
RESET_EXTENDED_BITS(gActivity.bitsAllowedActivities)
gActivity.iAllowedCount = 0
ENDIF
gActivity.curObjective = NO_FRIEND_ACTIVITY_OBJ
ENDIF
ENDPROC
PROC Private_DisplayObjective_Pickup()
// If objective has changed
IF gActivity.curObjective <> OBJ_PICKUP
Private_ClearObjective()
gActivity.curObjective = OBJ_PICKUP
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Pickup()")
ENDIF
// Show friend A pickup blibs
IF gActivity.mFriendA.eState = FRIEND_PICKUP
IF NOT DOES_BLIP_EXIST(gActivity.mFriendA.hLocBlip)
Private_CreateFriendLocBlip(gActivity.mFriendA)
ENDIF
// IF NOT DOES_BLIP_EXIST(gActivity.mFriendA.hPedBlip)
// IF Private_IsFriendArriving(gActivity.mFriendA)
// Private_CreateFriendPedBlip(gActivity.mFriendA)
// ENDIF
// ENDIF
ELSE
Private_RemoveFriendLocBlip(gActivity.mFriendA)
// Private_RemoveFriendPedBlip(gActivity.mFriendA)
ENDIF
// Show friend B pickup blibs
IF gActivity.mFriendB.eState = FRIEND_PICKUP
IF NOT DOES_BLIP_EXIST(gActivity.mFriendB.hLocBlip)
Private_CreateFriendLocBlip(gActivity.mFriendB)
ENDIF
// IF NOT DOES_BLIP_EXIST(gActivity.mFriendB.hPedBlip)
// IF Private_IsFriendArriving(gActivity.mFriendB)
// Private_CreateFriendPedBlip(gActivity.mFriendB)
// ENDIF
// ENDIF
ELSE
Private_RemoveFriendLocBlip(gActivity.mFriendB)
// Private_RemoveFriendPedBlip(gActivity.mFriendB)
ENDIF
// Print objective - Meet at blip
IF g_SavedGlobals.sFriendsData.g_bHelpDonePickupDest = FALSE
g_SavedGlobals.sFriendsData.g_bHelpDonePickupDest = TRUE
CLEAR_HELP()
IF gActivity.mFriendA.eChar <> CHAR_AMANDA
PRINT_HELP_WITH_STRING("FR_H_PKUP", gActivity.mFriendA.tName)
ELSE
PRINT_HELP_WITH_STRING("FR_H_PKUPf", gActivity.mFriendA.tName)
ENDIF
IF DOES_BLIP_EXIST(gActivity.mFriendA.hLocBlip)
SET_BLIP_FLASHES(gActivity.mFriendA.hLocBlip, TRUE)
SET_BLIP_FLASH_TIMER(gActivity.mFriendA.hLocBlip, 10000)
ENDIF
// Print objective - wait at blip
ELIF g_SavedGlobals.sFriendsData.g_bHelpDonePickupWait = FALSE
IF DOES_BLIP_EXIST(gActivity.mFriendA.hPedBlip)
IF gActivity.mFriendA.eChar <> CHAR_AMANDA
PRINT_HELP_WITH_STRING("FR_H_WAIT", gActivity.mFriendA.tName)
ELSE
PRINT_HELP_WITH_STRING("FR_H_WAITf", gActivity.mFriendA.tName)
ENDIF
g_SavedGlobals.sFriendsData.g_bHelpDonePickupWait = TRUE
ELIF DOES_BLIP_EXIST(gActivity.mFriendB.hPedBlip)
IF gActivity.mFriendB.eChar <> CHAR_AMANDA
PRINT_HELP_WITH_STRING("FR_H_WAIT", gActivity.mFriendB.tName)
ELSE
PRINT_HELP_WITH_STRING("FR_H_WAITf", gActivity.mFriendB.tName)
ENDIF
g_SavedGlobals.sFriendsData.g_bHelpDonePickupWait = TRUE
ENDIF
ENDIF
// Display ped blips
Private_UpdateFriendPedBlip(gActivity.mFriendA, Private_IsFriendArriving(gActivity.mFriendA))
Private_UpdateFriendPedBlip(gActivity.mFriendB, Private_IsFriendArriving(gActivity.mFriendB))
ENDPROC
PROC Private_DisplayObjective_Lost()
// Calculate correct obj variant
enumFriendActivityObj eLostObjType
IF gActivity.curObjective = OBJ_LOST_2
// (If already been told to return to both friends, don't need to reiterate after picking one of them back up)
eLostObjType = OBJ_LOST_2
ELIF (gActivity.mFriendA.eState = FRIEND_LOST OR gActivity.mFriendA.eState = FRIEND_FAIL_LOST OR gActivity.mFriendA.eState = FRIEND_PLUMMET)
AND (gActivity.mFriendB.eState = FRIEND_LOST OR gActivity.mFriendB.eState = FRIEND_FAIL_LOST OR gActivity.mFriendB.eState = FRIEND_PLUMMET)
eLostObjType = OBJ_LOST_2
ELSE
eLostObjType = OBJ_LOST_1
ENDIF
// If objective has changed
IF gActivity.curObjective <> eLostObjType
Private_ClearObjective()
// Display lost ped blips and return objective
IF eLostObjType = OBJ_LOST_1
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Lost(OBJ_LOST_2)")
IF gActivity.mFriendA.eState = FRIEND_LOST
OR gActivity.mFriendA.eState = FRIEND_FAIL_LOST
OR gActivity.mFriendA.eState = FRIEND_PLUMMET
PRINT_STRING_IN_STRING_NOW("FR_GETBACK", gActivity.mFriendA.tName, DEFAULT_GOD_TEXT_TIME, 0) // Return to ~b~~a~.
// Private_CreateFriendPedBlip(gActivity.mFriendA)
ELIF gActivity.mFriendB.eState = FRIEND_LOST
OR gActivity.mFriendB.eState = FRIEND_FAIL_LOST
OR gActivity.mFriendB.eState = FRIEND_PLUMMET
PRINT_STRING_IN_STRING_NOW("FR_GETBACK", gActivity.mFriendB.tName, DEFAULT_GOD_TEXT_TIME, 0) // Return to ~b~~a~.
// Private_CreateFriendPedBlip(gActivity.mFriendB)
ENDIF
ELSE
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Lost(OBJ_LOST_1)")
PRINT_NOW("FR_GETBACK2", DEFAULT_GOD_TEXT_TIME, 0) // Return to your ~b~friends.
// Private_CreateFriendPedBlip(gActivity.mFriendA)
// Private_CreateFriendPedBlip(gActivity.mFriendB)
ENDIF
gActivity.curObjective = eLostObjType
ENDIF
// Display ped blips
Private_UpdateFriendPedBlip(gActivity.mFriendA)
Private_UpdateFriendPedBlip(gActivity.mFriendB)
ENDPROC
PROC Private_DisplayObjective_Activities(BOOL bRecalcActivityBlips = FALSE)
enumActivityLocation eLoc
STATIC_BLIP_NAME_ENUM activitySprite
//-- Update objective if changed
BOOL bVerbose = FALSE // This is now actually set to true in every place that sets bRecalcActivityBlips to TRUE, but is retained incase it's too verbose.
IF gActivity.curObjective <> OBJ_VISIT_ACTIVITIES
Private_ClearObjective()
// Set objective status
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Activities() - Setting new objective...")
gActivity.curObjective = OBJ_VISIT_ACTIVITIES
// Add dropoff blip (if can go there)
IF gActivity.iVisitedCount > 0
VECTOR vAdjustedDropoff = gActivity.vDropoff
Private_GetAdjustedDropoffPos(gActivity.eDropoffLoc, vAdjustedDropoff)
gActivity.hDropoffBlip = CREATE_BLIP_FOR_COORD(vAdjustedDropoff, FALSE)
gActivity.bIsDropoffRouteDisplayed = FALSE
IF DOES_BLIP_EXIST(gActivity.hDropoffBlip)
SET_BLIP_NAME_FROM_TEXT_FILE(gActivity.hDropoffBlip, "FR_DROPBLIP")
ENDIF
ENDIF
bRecalcActivityBlips = TRUE
bVerbose = TRUE
ELIF bRecalcActivityBlips
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Activities() - Blip recalc requested by FriendActivity script state...")
bVerbose = TRUE
ENDIF
// Display help
IF g_SavedGlobals.sFriendsData.g_bHelpDoneActivityBlips = FALSE
IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
g_SavedGlobals.sFriendsData.g_bHelpDoneActivityBlips = TRUE
PRINT_HELP("FR_H_ACTIV1") // There are many activities you can visit with a friend. These are represented by radar markers like ~BLIP_CINEMA~, ~BLIP_COMEDY_CLUB~ and ~BLIP_MUSIC_VENUE~.
ENDIF
ELIF g_SavedGlobals.sFriendsData.g_bHelpDoneOpenMap = FALSE
IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
g_SavedGlobals.sFriendsData.g_bHelpDoneOpenMap = TRUE
PRINT_HELP("FR_H_ACTIV2") // The nearest activity suggested by a friend is always visible on the radar.
ENDIF
ELIF g_SavedGlobals.sFriendsData.g_bHelpDoneDropoff = FALSE
IF gActivity.iVisitedCount > 0
g_SavedGlobals.sFriendsData.g_bHelpDoneDropoff = TRUE
IF gActivity.mFriendB.eState = FRIEND_NULL
IF gActivity.mFriendA.eChar <> CHAR_AMANDA
PRINT_HELP_WITH_STRING("FR_H_DROPOFF0", gActivity.mFriendA.tName) // You can drop off ~a~, or take him to more activities.
ELSE
PRINT_HELP_WITH_STRING("FR_H_DROPOFF1", gActivity.mFriendA.tName) // You can drop off ~a~, or take her to more activities.
ENDIF
ELSE
PRINT_HELP("FR_H_DROPOFF2") // You can drop off your friends, or take them to more activities.
ENDIF
ENDIF
ENDIF
// Only display GPS route if everybody is in the same car
IF DOES_BLIP_EXIST(gActivity.hDropoffBlip)
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF gActivity.bIsDropoffRouteDisplayed = FALSE
VEHICLE_INDEX hPlayerVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF (IS_PED_INJURED(gActivity.mFriendA.hPed) OR IS_PED_IN_VEHICLE(gActivity.mFriendA.hPed, hPlayerVehicle))
AND (IS_PED_INJURED(gActivity.mFriendB.hPed) OR IS_PED_IN_VEHICLE(gActivity.mFriendB.hPed, hPlayerVehicle))
SET_BLIP_ROUTE(gActivity.hDropoffBlip, TRUE)
gActivity.bIsDropoffRouteDisplayed = TRUE
ENDIF
ENDIF
ELSE
IF gActivity.bIsDropoffRouteDisplayed = TRUE
SET_BLIP_ROUTE(gActivity.hDropoffBlip, FALSE)
gActivity.bIsDropoffRouteDisplayed = FALSE
ENDIF
ENDIF
ENDIF
// Check if cinema or golf has become available
BOOL bIsCinemaOpen = IS_CINEMA_OPEN_NOW()
BOOL bIsGolfOpen = IS_GOLF_OPEN_NOW()
IF NOT bRecalcActivityBlips
IF NOT gActivity.bTakeFriendHome
IF NOT IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
// NOTE - This used to check Private_IsLocationAvailable() against each corresponding blip in the blip manager. I've taken it out, as the blip manager doesn't run every frame, so data is unreliable
IF gActivity.bIsCinemaEnabled != bIsCinemaOpen
OR gActivity.bIsGolfEnabled != bIsGolfOpen
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Activities() - An activity opened/closed mid-objective due to clock time...")
bRecalcActivityBlips = TRUE
bVerbose = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
// Update activity blips
IF bRecalcActivityBlips
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Activities() - Updating activity blips")
RESET_EXTENDED_BITS(gActivity.bitsAllowedActivities)
gActivity.iAllowedCount = 0
REPEAT MAX_ACTIVITY_LOCATIONS eLoc
activitySprite = g_ActivityLocations[eLoc].sprite
IF NOT gActivity.bTakeFriendHome
AND Private_IsLocationAvailable(eLoc, gActivity.mPlayer.eChar, gActivity.mFriendA.eChar, gActivity.mFriendB.eChar, gActivity.bitsVisitedActivities, gActivity.bitsVisitedLocations, gActivity.eDropoffLoc, bIsCinemaOpen, bIsGolfOpen, bVerbose)
// Switch on location blip
SET_STATIC_BLIP_ACTIVE_STATE(activitySprite, TRUE)
SET_STATIC_BLIP_HIDDEN_IN_MISSION(activitySprite, FALSE)
SET_STATIC_BLIP_COLOUR(activitySprite, BLIP_COLOUR_YELLOW)
// Set bit in allowed activities list
IF NOT IS_EXTENDED_BIT_SET(gActivity.bitsAllowedActivities, ENUM_TO_INT(g_ActivityLocations[eLoc].type))
SET_EXTENDED_BIT(gActivity.bitsAllowedActivities, ENUM_TO_INT(g_ActivityLocations[eLoc].type))
gActivity.iAllowedCount++
ENDIF
//ELIF IS_STATIC_BLIP_CURRENTLY_VISIBLE(activitySprite) // Removed this check, as the values in the blip manager are often out of date and unreliable - SamH 13/08/14
ELSE
// Switch off location blip
SET_STATIC_BLIP_ACTIVE_STATE(activitySprite, FALSE)
ENDIF
ENDREPEAT
gActivity.bIsCinemaEnabled = bIsCinemaOpen
gActivity.bIsGolfEnabled = bIsGolfOpen
ENDIF
//-- Constantly promote the nearest blip to long range
enumActivityLocation bestLoc = gActivity.eNearestActivityLoc
FLOAT fBestDist2 = 99999.0*99999.0
// Determine nearest blip
REPEAT MAX_ACTIVITY_LOCATIONS eLoc
activitySprite = g_ActivityLocations[eLoc].sprite
IF IS_BIT_SET(g_GameBlips[activitySprite].iSetting, STATIC_BLIP_SETTING_ACTIVE)
FLOAT fDist2 = VDIST2(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_STATIC_BLIP_POSITION(g_ActivityLocations[eLoc].sprite))
IF fBestDist2 > fDist2
bestLoc = eLoc
fBestDist2 = fDist2
ENDIF
ENDIF
ENDREPEAT
// Set nearesr blip to long range, the rest to short
IF gActivity.eNearestActivityLoc <> bestLoc
gActivity.eNearestActivityLoc = bestLoc
CPRINTLN(DEBUG_FRIENDS, "Private_DisplayObjective_Activities() - Change nearest blip to '", GetLabel_enumActivityLocation(bestLoc), "'")
ENDIF
REPEAT MAX_ACTIVITY_LOCATIONS eLoc
activitySprite = g_ActivityLocations[eLoc].sprite
IF IS_BIT_SET(g_GameBlips[activitySprite].iSetting, STATIC_BLIP_SETTING_ACTIVE)
IF eLoc = gActivity.eNearestActivityLoc
IF NOT IS_BIT_SET(g_GameBlips[activitySprite].iSetting, STATIC_BLIP_SETTING_RADAR_LONG)
SET_STATIC_BLIP_APPEAR_EDGE_RADAR(activitySprite, TRUE, FALSE)
ENDIF
ELSE
IF IS_BIT_SET(g_GameBlips[activitySprite].iSetting, STATIC_BLIP_SETTING_RADAR_LONG)
SET_STATIC_BLIP_APPEAR_EDGE_RADAR(activitySprite, FALSE, FALSE)
ENDIF
ENDIF
ENDIF
ENDREPEAT
// Display ped blips
Private_UpdateFriendPedBlip(gActivity.mFriendA)
Private_UpdateFriendPedBlip(gActivity.mFriendB)
ENDPROC