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