// ***************************************************************************************** // ***************************************************************************************** // // MISSION NAME : friendActivity_memberFriend_private.sch // AUTHOR : Sam Hackett // DESCRIPTION : State machine for individual friend activity members // // ***************************************************************************************** // ***************************************************************************************** //- commands headers -// //- script headers -// USING "ambient_common.sch" //- public headers -// USING "shop_public.sch" //- private headers -// USING "friendActivity_private.sch" USING "player_scene_private.sch" #IF IS_DEBUG_BUILD //- debug headers -// #ENDIF //--------------------------------------------------------------------------------------------------- //-- Consts //--------------------------------------------------------------------------------------------------- CONST_FLOAT CONST_fFriendCreateDist 300.0 //150.0 CONST_FLOAT CONST_fFriendCreateTooCloseDist 225.0 //65.0 CONST_FLOAT CONST_fFriendRemoveDist 400.0 //250.0//300.0 CONST_FLOAT CONST_fFriendRemoveDistOnFoot 175.0 CONST_FLOAT CONST_fFriendCreateAdhocMin 200.0 CONST_FLOAT CONST_fFriendCreateAdhocMax 250.0 CONST_FLOAT CONST_fFriendArriveSpeed 18.0//20.0 CONST_FLOAT CONST_fDrivewayParkRange 20.0 CONST_FLOAT CONST_fDoorstepWaitRange 1.5 CONST_FLOAT CONST_fRunToPlayerRange 15.0 CONST_FLOAT CONST_fScenarioBlockingBoxSize 10.0 CONST_INT c_iPickupRunBlockDuration 10000 //--------------------------------------------------------------------------------------------------- //-- Enums //--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //-- Friend Debug //--------------------------------------------------------------------------------------------------- #IF IS_DEBUG_BUILD PROC DEBUG_DisplayFriendInfo(structFriend& friend, INT iSlot) TEXT_LABEL_63 tName = GetLabel_enumFriend(GET_FRIEND_FROM_CHAR(friend.eChar)) INT iRow = CONST_iActivityDebugPrintLineTop + iSlot IF friend.eState = FRIEND_PICKUP // Buddy name (+ mWaitTimer) tName += ": FRIEND_PICKUP: " tName += GET_STRING_FROM_MILISECONDS(ROUND(GET_TIMER_IN_SECONDS(friend.mWaitTimer) * 1000.0)) FLOAT fTimeLimit = CONST_fLateFailInRealMinutes HUD_COLOURS eTimeColour = HUD_COLOUR_BLUELIGHT IF gActivity.bIsRural fTimeLimit = CONST_fLateFailInRealMinutes_rural eTimeColour = HUD_COLOUR_GREENLIGHT ENDIF DrawFriendTimerBar(friend.mWaitTimer, fTimeLimit/60.0, iRow, eTimeColour) DrawFriendLiteralString(tName, iRow, eTimeColour) iRow++ // Display dist to friend TEXT_LABEL_63 tDist = "" tDist += " loc dist: " IF DOES_ENTITY_EXIST(friend.hPed) AND NOT IS_PED_INJURED(friend.hPed) DrawFriendLiteralStringFloat(tDist, VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), friend.vDoorstep), iRow, HUD_COLOUR_WHITE) ELSE DrawFriendLiteralStringFloat(tDist, VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), friend.vDoorstep), iRow, HUD_COLOUR_GREY) ENDIF ELIF friend.eState >= FRIEND_FAIL_INJURED // Buddy name (+ state + mFailTimer) tName += ": " tName += GetLabel_enumFriendState(friend.eState) tName += ": " IF IS_TIMER_STARTED(gActivity.mFailTimer) tName += GET_STRING_FROM_MILISECONDS(ROUND(GET_TIMER_IN_SECONDS(gActivity.mFailTimer) * 1000.0)) ELSE tName += GET_STRING_FROM_MILISECONDS(0) ENDIF DrawFriendLiteralString(tName, iRow, HUD_COLOUR_BLUELIGHT) ELIF friend.eState <> FRIEND_NULL // Buddy name (+ state) tName += ": " tName += GetLabel_enumFriendState(friend.eState) DrawFriendLiteralString(tName, iRow, HUD_COLOUR_BLUELIGHT) ENDIF ENDPROC #ENDIF //--------------------------------------------------------------------------------------------------- //-- Member init //--------------------------------------------------------------------------------------------------- PROC Private_InitFriend(structFriend& friend) friend.eState = FRIEND_NULL friend.eChar = NO_CHARACTER friend.ePickup = NO_FRIEND_LOCATION friend.tName = "" friend.hPed = null friend.hCar = null friend.hPhone = null friend.hPedBlip = null friend.hLocBlip = null RESTART_TIMER_NOW(friend.mWaitTimer) friend.vDoorstep = << 0.0, 0.0, 0.0 >> friend.vDriveway = << 0.0, 0.0, 0.0 >> friend.iOffsetIndex = 0 friend.hScenarioBlock = NULL CANCEL_TIMER(friend.mArrivalStoppedTimer) friend.iArrivalDrivingMode = 0 friend.ePedModel = DUMMY_MODEL_FOR_SCRIPT friend.eCarModel = DUMMY_MODEL_FOR_SCRIPT friend.bDoneTrappedDialogue = FALSE friend.iBlockRunningUntilTime = 0 friend.iCarHealth = 0 friend.iCarShotTime = 0 friend.bWereInVehicleTogether = FALSE friend.iHealth = 0 friend.bSwitchOverride = FALSE friend.bIsBeingCalledToCancel = FALSE friend.bIsShowingPickupCam = FALSE friend.bForceCreateAsArriving = FALSE friend.bUseStoredVehicleModel = FALSE friend.bWasPickedUp = FALSE friend.bWasMetAmbiently = FALSE friend.eFailReason = FAF_NoFail ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member general utils //--------------------------------------------------------------------------------------------------- FUNC VEHICLE_SEAT Private_GetMemberSeat(structFriend& friend) IF gActivity.mFriendA.eChar = friend.eChar RETURN VS_FRONT_RIGHT ELSE RETURN VS_BACK_RIGHT|VS_BACK_LEFT ENDIF ENDFUNC //--------------------------------------------------------------------------------------------------- //-- Member ped utils //--------------------------------------------------------------------------------------------------- PROC Private_SetFriendAttribs(structFriend& friend, structPedsForConversation& convStruct, BOOL bIsPlayer = FALSE) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL IF NOT IS_PED_INJURED(friend.hPed) IF bIsPlayer // Player controlled CLEAR_ENTITY_LAST_DAMAGE_ENTITY(friend.hPed) CLEAR_ENTITY_LAST_WEAPON_DAMAGE(friend.hPed) IF NOT IS_PED_REGISTERED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) REGISTER_PED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) // Don't know what this is all about (and should it be buddy ped instead of player?) ENDIF ADD_FRIEND_CHAR_FOR_DIALOGUE(convStruct, friend.eChar, friend.hPed) SET_PED_CONFIG_FLAG(friend.hPed, PCF_WillFlyThroughWindscreen, FALSE) ELSE // AI controlled CLEAR_ENTITY_LAST_DAMAGE_ENTITY(friend.hPed) CLEAR_ENTITY_LAST_WEAPON_DAMAGE(friend.hPed) friend.iHealth = GET_ENTITY_HEALTH(friend.hPed) IF NOT IS_PED_REGISTERED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) REGISTER_PED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) // Don't know what this is all about (and should it be buddy ped instead of player?) ENDIF ADD_FRIEND_CHAR_FOR_DIALOGUE(convStruct, friend.eChar, friend.hPed) SET_PED_CAN_BE_TARGETTED(friend.hPed, FALSE) SET_PED_RELATIONSHIP_GROUP_HASH(friend.hPed, RELGROUPHASH_PLAYER) // SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(friend.hPed, TRUE) SET_PED_HELMET(friend.hPed, TRUE) SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(friend.hPed, TRUE) SET_PED_PATH_CAN_USE_CLIMBOVERS(friend.hPed, TRUE) SET_PED_PATH_CAN_USE_LADDERS(friend.hPed, TRUE) SET_PED_PATH_CAN_DROP_FROM_HEIGHT(friend.hPed, TRUE) SET_PED_PATH_MAY_ENTER_WATER(friend.hPed, TRUE) SET_PED_PATH_PREFER_TO_AVOID_WATER(friend.hPed, TRUE) SET_PED_SUFFERS_CRITICAL_HITS(friend.hPed, FALSE) SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(friend.hPed, KNOCKOFFVEHICLE_HARD) SET_PED_CONFIG_FLAG(friend.hPed, PCF_DontActivateRagdollFromBulletImpact, TRUE) SET_PED_CONFIG_FLAG(friend.hPed, PCF_WillFlyThroughWindscreen, FALSE) // SET_PED_CONFIG_FLAG(friend.hPed, PCF_TeleportToLeaderVehicle, TRUE) SET_PED_STAY_IN_VEHICLE_WHEN_JACKED(friend.hPed, TRUE) SET_PED_CONFIG_FLAG(friend.hPed, PCF_OnlyAttackLawIfPlayerIsWanted, TRUE) SET_PED_CONFIG_FLAG(friend.hPed, PCF_LawWillOnlyAttackIfPlayerIsWanted, TRUE) SET_PED_DIES_INSTANTLY_IN_WATER(friend.hPed, FALSE) SET_PED_DIES_IN_WATER(friend.hPed, FALSE) IF IS_PED_USING_ACTION_MODE(friend.hPed) SET_PED_USING_ACTION_MODE(friend.hPed, FALSE) ENDIF // Fighting chars IF friend.eChar <> CHAR_JIMMY AND friend.eChar <> CHAR_AMANDA IF NOT friend.bWasPickedUp SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, TRUE) ELSE SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, FALSE) ENDIF SET_PED_CONFIG_FLAG(friend.hPed, PCF_RunFromFiresAndExplosions, FALSE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_ALWAYS_FIGHT, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_ALWAYS_FLEE, FALSE) // SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_NEVER_FLEE, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_REQUIRES_LOS_TO_SHOOT, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_CAN_SHOOT_WITHOUT_LOS, FALSE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_CAN_FIGHT_ARMED_PEDS_WHEN_NOT_ARMED, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_CAN_USE_DYNAMIC_STRAFE_DECISIONS, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_DO_DRIVEBYS, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_USE_COVER, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_USE_VEHICLE, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_LEAVE_VEHICLES, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_USE_VEHICLE, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_NEVER_FLEE, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_DISABLE_COWER, TRUE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_DISABLE_EXIT_VEHICLE, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_DISABLE_FLEE_FROM_INDIRECT_THREATS, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_FORCE_EXIT_VEHICLE, TRUE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_DISABLE_HESITATE_IN_VEHICLE, TRUE) SET_PED_COMBAT_ABILITY(friend.hPed, CAL_PROFESSIONAL) SET_PED_COMBAT_MOVEMENT(friend.hPed, CM_WILLADVANCE) // Fleeing chars ELSE SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, TRUE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_ALWAYS_FIGHT, FALSE) SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_USE_COVER, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_NEVER_FLEE, TRUE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_USE_COVER, FALSE) SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_CAN_SCREAM, TRUE) //// SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_ALWAYS_FIGHT, TRUE) // SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_ALWAYS_FLEE, TRUE) //// SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_JUST_SEEK_COVER, TRUE) // SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_USE_COVER, TRUE) //// SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_FLEE_WHILST_IN_VEHICLE, FALSE) //// //// SET_PED_COMBAT_ATTRIBUTES(friend.hPed, CA_USE_VEHICLE, TRUE) //// //// SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_NEVER_FLEE, FALSE) // SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_CAN_SCREAM, TRUE) // // SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_USE_COVER, TRUE) // SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_DISABLE_COWER, FALSE) //// SET_PED_FLEE_ATTRIBUTES(friend.hPEd, FA_COWER_INSTEAD_OF_FLEE, TRUE) // //// SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_PREFER_PAVEMENTS, TRUE) //// SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_RETURN_TO_ORIGNAL_POSITION_AFTER_FLEE, TRUE) //// SET_PED_FLEE_ATTRIBUTES(friend.hPed, FA_USE_COVER, TRUE) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC Private_ClearFriendAttribs(structFriend& friend) IF friend.eState <> FRIEND_NULL IF NOT IS_PED_INJURED(friend.hPed) SET_PED_SUFFERS_CRITICAL_HITS(friend.hPed, TRUE) SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(friend.hPed, KNOCKOFFVEHICLE_DEFAULT) SET_PED_CONFIG_FLAG(friend.hPed, PCF_WillFlyThroughWindscreen, TRUE) SET_PED_CONFIG_FLAG(friend.hPed, PCF_DontActivateRagdollFromBulletImpact, FALSE) IF DOES_GROUP_EXIST(PLAYER_GROUP_ID()) AND IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) SET_PED_CAN_TELEPORT_TO_GROUP_LEADER(friend.hPed, PLAYER_GROUP_ID(), FALSE) ENDIF SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(friend.hPed, FALSE) IF friend.eChar <> CHAR_MICHAEL IF IS_PED_REGISTERED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) UNREGISTER_PED_TO_ACTIVATE_AUTOMATIC_DOOR(AUTODOOR_MICHAEL_MANSION_GATE, friend.hPed) ENDIF ENDIF IF friend.hPed <> PLAYER_PED_ID() IF IS_PED_IN_GROUP(friend.hPed) REMOVE_PED_FROM_GROUP(friend.hPed) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC Private_SyncFriendPed(structFriend& friend) IF friend.eState <> FRIEND_NULL // Current player IF friend.eChar = GET_CURRENT_PLAYER_PED_ENUM() IF friend.hPed <> PLAYER_PED_ID() CPRINTLN(DEBUG_FRIENDS, "Private_SyncFriendPed(", GetLabel_enumCharacterList(friend.eChar), "):- Grabbed ped from current player") friend.hPed = PLAYER_PED_ID() Private_SetFriendAttribs(friend, gActivity.convPedsDefault, TRUE) ENDIF EXIT ELIF friend.eChar <> NO_CHARACTER // Playable selector ped IF IS_PLAYER_PED_PLAYABLE( friend.eChar ) SELECTOR_SLOTS_ENUM eSelectorSlot = GET_SELECTOR_SLOT_FROM_PLAYER_PED_ENUM(friend.eChar) PED_INDEX hSelectorPed = g_sPlayerPedRequest.sSelectorPeds.pedID[eSelectorSlot] IF NOT DOES_ENTITY_EXIST(friend.hPed) friend.hPed = hSelectorPed ELSE IF NOT DOES_ENTITY_EXIST(hSelectorPed) CPRINTLN(DEBUG_FRIENDS, "Private_SyncFriendPed(", GetLabel_enumCharacterList(friend.eChar), ") - Member has ped, but selector doesn't") SCRIPT_ASSERT("Private_SyncFriendPed() - Member has ped, but selector doesn't (playable)") DELETE_PED(friend.hPed) ENDIF ENDIF // NPC cached ped ELSE enumFriend eFriend = GET_FRIEND_FROM_CHAR(friend.eChar) INT iIndex = ENUM_TO_INT(eFriend) - NUM_OF_PLAYABLE_PEDS IF eFriend = NO_FRIEND SCRIPT_ASSERT("Private_SyncFriendPed() - Can't get friend handle for char") CPRINTLN(DEBUG_FRIENDS, "Private_SyncFriendPed(", GetLabel_enumCharacterList(friend.eChar), ") - Can't get friend handle for char") ELSE IF NOT DOES_ENTITY_EXIST(friend.hPed) friend.hPed = g_pGlobalFriends[iIndex] ELSE IF NOT DOES_ENTITY_EXIST(g_pGlobalFriends[iIndex]) CPRINTLN(DEBUG_FRIENDS, "Private_SyncFriendPed(", GetLabel_enumCharacterList(friend.eChar), ") - Member has ped, but selector doesn't") SCRIPT_ASSERT("Private_SyncFriendPed() - Member has ped, but selector doesn't (npc)") DELETE_PED(friend.hPed) ENDIF ENDIF ENDIF ENDIF // If got a ped and I don't own it, take control of it IF NOT IS_PED_INJURED(friend.hPed) IF NOT DOES_ENTITY_BELONG_TO_THIS_SCRIPT(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_SyncFriendPed(", GetLabel_enumCharacterList(friend.eChar), "):- Grabbed ped from selector") IF friend.bWasPickedUp SCRIPT_ASSERT("Private_SyncFriendPed() - Grabbed ped from selector, even though friend has already been picked up") ENDIF SET_ENTITY_AS_MISSION_ENTITY(friend.hPed, TRUE, TRUE) Private_SetFriendAttribs(friend, gActivity.convPedsDefault) ENDIF ENDIF ENDIF ENDIF ENDPROC //PROC Private_StorePedInfo(PED_INDEX hPed, enumCharacterList eChar) // STORE_PLAYER_PED_INFO(hPed) // // IF IS_PLAYER_PED_PLAYABLE(eChar) // STORE_VEH_DATA_FROM_PED(hPed, g_sPlayerLastVeh[eChar], g_vPlayerLastVehCoordOff[eChar], g_fPlayerLastVehHeadOff[eChar], g_ePlayerLastVehState[eChar]) // ENDIF //ENDPROC PROC Private_SetPedAmandaOutfit(PED_INDEX PedIndex) FAMILY_COMP_NAME_ENUM eFamilyOutfitName = FC_AMANDA_OUTFIT_leavingNoGlasses FAMILY_COMP_NAME_ENUM ePC_head, ePC_hair, ePC_torso, ePC_leg, ePC_feet, ePC_hand, ePC_special, ePC_special2, ePC_decl, ePC_berd, ePC_teeth, ePC_jbib FAMILY_PROP_BIT_ENUM ePC_prop IF GetOutfitForFamilyMember(eFamilyOutfitName, ePC_head, ePC_hair, ePC_torso, ePC_leg, ePC_feet, ePC_hand, ePC_special, ePC_special2, ePC_decl, ePC_berd, ePC_teeth, ePC_jbib, ePC_prop) // SetComponentForFamilyMember(PedIndex, ePC_head) SetComponentForFamilyMember(PedIndex, ePC_hair) SetComponentForFamilyMember(PedIndex, ePC_torso) SetComponentForFamilyMember(PedIndex, ePC_leg) SetComponentForFamilyMember(PedIndex, ePC_feet) SetComponentForFamilyMember(PedIndex, ePC_hand) SetComponentForFamilyMember(PedIndex, ePC_special) SetComponentForFamilyMember(PedIndex, ePC_special2) SetComponentForFamilyMember(PedIndex, ePC_decl) SetComponentForFamilyMember(PedIndex, ePC_berd) SetComponentForFamilyMember(PedIndex, ePC_teeth) SetComponentForFamilyMember(PedIndex, ePC_jbib) IF IS_BITMASK_ENUM_AS_ENUM_SET(ePC_prop, FAMILY_PROP_NULL) CLEAR_ALL_PED_PROPS(pedIndex) ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ePC_prop, FPB_AMANDA_GLASSES) CLEAR_ALL_PED_PROPS(pedIndex) SET_PED_PROP_INDEX(pedIndex, ANCHOR_EYES, 0) //amanda glasses ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ePC_prop, FPB_AMANDA_CUCUMBERS) CLEAR_ALL_PED_PROPS(pedIndex) SET_PED_PROP_INDEX(pedIndex, ANCHOR_EYES, 1) //amanda cucumbers ENDIF ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member loc utils //--------------------------------------------------------------------------------------------------- PROC Private_SetFriendSwitchOverride(structFriend& friend) IF friend.eState <> FRIEND_NULL #IF IS_DEBUG_BUILD TEXT_LABEL_63 tFriend = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_63 tLocation = GetLabel_enumFriendLocation(friend.ePickup) CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendSwitchOverride(", tFriend, ") At location ", tLocation) #ENDIF IF IS_PLAYER_PED_PLAYABLE(friend.eChar) IF friend.ePickup < MAX_FRIEND_LOCATIONS VECTOR vFacing = friend.vDriveway - friend.vDoorstep SET_PED_SWITCH_OVERRIDE(friend.eChar, friend.vDoorstep, GET_HEADING_FROM_VECTOR_2D(vFacing.x, vFacing.y)) friend.bSwitchOverride = TRUE ENDIF ENDIF ENDIF ENDPROC PROC Private_ClearFriendSwitchOverride(structFriend& friend) IF friend.eState <> FRIEND_NULL IF IS_PLAYER_PED_PLAYABLE(friend.eChar) IF friend.bSwitchOverride IF (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] = PR_SCENE_M_OVERRIDE) OR (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] = PR_SCENE_F_OVERRIDE) OR (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] = PR_SCENE_T_OVERRIDE) CLEAR_PED_SWITCH_OVERRIDE(friend.eChar) ELSE #IF IS_DEBUG_BUILD TEXT_LABEL_63 tFriend = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_63 tLocation = GetLabel_enumFriendLocation(friend.ePickup) TEXT_LABEL_63 tScene = Get_String_From_Ped_Request_Scene_Enum(g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar]) CPRINTLN(DEBUG_FRIENDS, "Private_ClearFriendSwitchOverride(", tFriend, ") Set for location ", tLocation, " but switch scene is not overriden (it's ", tScene, ")") #ENDIF ENDIF friend.bSwitchOverride = FALSE ENDIF ENDIF ENDIF ENDPROC PROC Private_SetFriendScenarioBlocking(structFriend& friend) IF friend.eState <> FRIEND_NULL IF friend.ePickup < MAX_FRIEND_LOCATIONS IF friend.hScenarioBlock = NULL FLOAT fHalfSize = CONST_fScenarioBlockingBoxSize/2.0 VECTOR vHalfSize = <> VECTOR vMin = FriendLoc_GetCoord(friend.ePickup) - vHalfSize VECTOR vMax = FriendLoc_GetCoord(friend.ePickup) + vHalfSize friend.hScenarioBlock = ADD_SCENARIO_BLOCKING_AREA(vMin, vMax) ELSE CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendScenarioBlocking(", GetLabel_enumCharacterList(friend.eChar), ") - Trying to set scenario blocking, when blocking has already been set") SCRIPT_ASSERT("Private_SetFriendScenarioBlocking() - Trying to set scenario blocking, when blocking has already been set") ENDIF ENDIF ENDIF ENDPROC PROC Private_ClearFriendScenarioBlocking(structFriend& friend) IF friend.eState <> FRIEND_NULL IF friend.ePickup < MAX_FRIEND_LOCATIONS IF friend.hScenarioBlock <> NULL REMOVE_SCENARIO_BLOCKING_AREA(friend.hScenarioBlock) friend.hScenarioBlock = NULL // ELSE // CPRINTLN(DEBUG_FRIENDS, "Private_ClearFriendScenarioBlocking(", GetLabel_enumCharacterList(friend.eChar), ") - Trying to clear scenario blocking, but not block is set") // SCRIPT_ASSERT("Private_ClearFriendScenarioBlocking() - Trying to clear scenario blocking, but not block is set") ENDIF ENDIF ENDIF ENDPROC PROC Private_SetFriendPickupLocOffset(structFriend& friend, INT iOffsetIndex) IF friend.ePickup < MAX_FRIEND_LOCATIONS // Get offset for this particular friend VECTOR vOffset IF iOffsetIndex = 0 vOffset = g_FriendLocations[friend.ePickup].vPedOffsetA ELIF iOffsetIndex = 1 vOffset = g_FriendLocations[friend.ePickup].vPedOffsetB ELSE SCRIPT_ASSERT("Private_SetMemberDestOffset() - iOffsetIndex must be 0 or 1") vOffset = g_FriendLocations[friend.ePickup].vPedOffsetB iOffsetIndex = 1 ENDIF // Setup shorthand vectors friend.vDriveway = g_FriendLocations[friend.ePickup].vPickupCoord friend.vDoorstep = g_FriendLocations[friend.ePickup].vPickupCoord + vOffset friend.iOffsetIndex = iOffsetIndex ENDIF ENDPROC PROC Private_UpdateFriendPickupLocToNearest(structFriend& friend) IF friend.eState = FRIEND_NULL SCRIPT_ASSERT("Private_UpdateFriendPickupLocToNearest() - passed friend is not valid") ENDIF // Store locations for each friend enumFriendLocation arrayLocations[3] arrayLocations[0] = gActivity.mPlayer.ePickup arrayLocations[1] = gActivity.mFriendA.ePickup arrayLocations[2] = gActivity.mFriendB.ePickup // Find closest location IF NOT IS_PED_INJURED(friend.hPed) VECTOR vFriend = GET_ENTITY_COORDS(friend.hPed) FLOAT fClosest = 999999.0*999999.0 INT iClosest = -1 // (Don't need to do this, as all three locations are now included in loop) // IF friend.ePickup <> NO_FRIEND_LOCATION // fClosest = VDIST2(vFriend, g_FriendLocations[friend.ePickup].vPickupCoord) // ENDIF INT i REPEAT COUNT_OF(arrayLocations) i IF arrayLocations[i] < MAX_FRIEND_LOCATIONS FLOAT fDist = VDIST2(vFriend, g_FriendLocations[arrayLocations[i]].vPickupCoord) IF fClosest > fDist fClosest = fDist iClosest = i ENDIF ENDIF ENDREPEAT // If have a better loc than members current one, set it as home destination IF iClosest <> -1 friend.ePickup = arrayLocations[iClosest] ENDIF ENDIF // Update for location IF friend.ePickup < MAX_FRIEND_LOCATIONS #IF IS_DEBUG_BUILD TEXT_LABEL_63 tFriend = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_63 tPickup = GetLabel_enumFriendLocation(friend.ePickup) CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriendPickupLocToNearest(", tFriend, "):- ", tPickup) #ENDIF Private_SetFriendPickupLocOffset(friend, 0) ELSE #IF IS_DEBUG_BUILD TEXT_LABEL_63 tFriend = GetLabel_enumCharacterList(friend.eChar) CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriendPickupLocToNearest(", tFriend, ") ") #ENDIF SCRIPT_ASSERT("Private_UpdateFriendPickupLocToNearest() - No location") ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member creation / deletion //--------------------------------------------------------------------------------------------------- FUNC BOOL Private_TryCreateFriend_AtDest(structFriend& friend, BOOL bIgnoreTooCloseCheck = FALSE) IF friend.ePickup <> NO_FRIEND_LOCATION IF friend.bForceCreateAsArriving = FALSE VECTOR vCreatePos = friend.vDoorstep VECTOR vLookAt = friend.vDriveway - friend.vDoorstep FLOAT fCreateRot = GET_HEADING_FROM_VECTOR_2D(vLookAt.x, vLookAt.y) FLOAT fTooCloseDist = CONST_fFriendCreateTooCloseDist IF Util_IsPedInsideRange(PLAYER_PED_ID(), vCreatePos, CONST_fFriendCreateDist) AND (Util_IsPedOutsideRange(PLAYER_PED_ID(), vCreatePos, fTooCloseDist) OR bIgnoreTooCloseCheck) // Create ped BOOL bSuccess IF IS_PLAYER_PED_PLAYABLE(friend.eChar) bSuccess = CREATE_PLAYER_PED_ON_FOOT(friend.hPed, friend.eChar, vCreatePos, fCreateRot, TRUE) ELSE bSuccess = CREATE_NPC_PED_ON_FOOT(friend.hPed, friend.eChar, vCreatePos, fCreateRot, TRUE) ENDIF // If it's Amanda, change from default outfit IF NOT IS_PED_INJURED(friend.hPed) AND friend.eChar = CHAR_AMANDA // SetOutfitForFamilyMember(friend.hPed, FC_AMANDA_OUTFIT_leavingGlasses) Private_SetPedAmandaOutfit(friend.hPed) // Fix for 1976287: Special variation of SetOutfitForFamilyMember() that doesn't set the head (because Amanda's main outdoors outift has her makeup running from crying) ENDIF IF bSuccess CPRINTLN(DEBUG_FRIENDS, "ActivityPickup: Created buddy (AtDest) ", GetLabel_enumCharacterList(friend.eChar)) Private_SetFriendAttribs(friend, gActivity.convPedsDefault) RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_TryCreateFriend_ArrivingAtDest(structFriend& friend) IF friend.ePickup <> NO_FRIEND_LOCATION // If player is waiting at doorstep IF Util_IsPedInsideRange(PLAYER_PED_ID(), friend.vDoorstep, CONST_fIsPlayerAtDoorstep) VECTOR vCreatePos = g_FriendLocations[friend.ePickup].vSpawnPos FLOAT fCreateRot = g_FriendLocations[friend.ePickup].fSpawnRot // If there is no set spawn point, try to generate one IF vCreatePos.x = 0.0 AND vCreatePos.y = 0.0 AND vCreatePos.z = 0.0 VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) VECTOR vResultPos VECTOR vResultDir IF GENERATE_VEHICLE_CREATION_POS_FROM_PATHS(vPlayerPos, vResultPos, vResultDir, 0, 180, CONST_fFriendCreateAdhocMin, FALSE, TRUE, FALSE) AND GET_DISTANCE_BETWEEN_COORDS(vPlayerPos, vResultPos) < CONST_fFriendCreateAdhocMax vResultDir = vPlayerPos - vResultPos vCreatePos = vResultPos fCreateRot = GET_HEADING_FROM_VECTOR_2D(vResultDir.x, vResultDir.y) ENDIF ENDIF // If managed to get spawn point, try to create... IF vCreatePos.x <> 0.0 OR vCreatePos.y <> 0.0 OR vCreatePos.z <> 0.0 // Set required models MODEL_NAMES pedModel MODEL_NAMES vehModel = ASEA BOOL bSuccess = FALSE PED_VEH_DATA_STRUCT sVehData IF friend.bUseStoredVehicleModel IF NOT IS_PLAYER_PED_PLAYABLE(friend.eChar) OR g_ePlayerLastVehState[friend.eChar] <> PTVS_2_playerInVehicle OR g_sPlayerLastVeh[friend.eChar].model = DUMMY_MODEL_FOR_SCRIPT OR IS_VEHICLE_MODEL_ON_BLACKLIST(g_sPlayerLastVeh[friend.eChar].model) friend.bUseStoredVehicleModel = FALSE ENDIF ENDIF IF friend.bUseStoredVehicleModel // Set required models (playable char in stored car) vehModel = g_sPlayerLastVeh[friend.eChar].model pedModel = GET_PLAYER_PED_MODEL(friend.eChar) ELIF IS_PLAYER_PED_PLAYABLE(friend.eChar) // Set required models (playable char) GET_PLAYER_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_CAR) vehModel = sVehData.model pedModel = GET_PLAYER_PED_MODEL(friend.eChar) ELIF friend.eChar = CHAR_JIMMY // Set required models (Jimmy rides a bike) GET_NPC_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_BIKE) vehModel = sVehData.model pedModel = GET_NPC_PED_MODEL(friend.eChar) ELSE // Set required models (npc char) GET_NPC_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_CAR) vehModel = sVehData.model pedModel = GET_NPC_PED_MODEL(friend.eChar) ENDIF IF vehModel = DUMMY_MODEL_FOR_SCRIPT vehModel = ASEA ENDIF // Load models + create REQUEST_MODEL(pedModel) REQUEST_MODEL(vehModel) IF HAS_MODEL_LOADED(vehModel) AND HAS_MODEL_LOADED(pedModel) IF IS_PLAYER_PED_PLAYABLE(friend.eChar) // Create vehicle and ped (playable) BOOL bCarSuccess = FALSE IF friend.bUseStoredVehicleModel bCarSuccess = CREATE_STORED_VEHICLE(friend.hCar, friend.eChar, vCreatePos, fCreateRot, TRUE, g_sPlayerLastVeh[friend.eChar]) ELSE bCarSuccess = CREATE_PLAYER_VEHICLE(friend.hCar, friend.eChar, vCreatePos, fCreateRot, TRUE, VEHICLE_TYPE_CAR) ENDIF IF bCarSuccess bSuccess = CREATE_PLAYER_PED_INSIDE_VEHICLE(friend.hPed, friend.eChar, friend.hCar, VS_DRIVER, TRUE) ENDIF ELSE // Create vehicle and ped (npc) IF CREATE_NPC_VEHICLE(friend.hCar, friend.eChar, vCreatePos, fCreateRot, TRUE, VEHICLE_TYPE_CAR) bSuccess = CREATE_NPC_PED_INSIDE_VEHICLE(friend.hPed, friend.eChar, friend.hCar, VS_DRIVER, TRUE) // If it's Amanda, change from default outfit IF NOT IS_PED_INJURED(friend.hPed) AND friend.eChar = CHAR_AMANDA SetOutfitForFamilyMember(friend.hPed, FC_AMANDA_OUTFIT_leavingNoGlasses) ENDIF ENDIF ENDIF ENDIF IF bSuccess IF friend.bUseStoredVehicleModel CPRINTLN(DEBUG_FRIENDS, "ActivityPickup: Created buddy (ArrivingAtDest) ", GetLabel_enumCharacterList(friend.eChar), " - using backed up vehicle model") ELSE CPRINTLN(DEBUG_FRIENDS, "ActivityPickup: Created buddy (ArrivingAtDest) ", GetLabel_enumCharacterList(friend.eChar), " - using standard vehicle model") ENDIF IF DOES_ENTITY_EXIST(friend.hCar) AND NOT IS_ENTITY_DEAD(friend.hCar) SET_ENTITY_COORDS(friend.hCar, vCreatePos) SET_ENTITY_HEADING(friend.hCar, fCreateRot) SET_VEHICLE_ON_GROUND_PROPERLY(friend.hCar) ENDIF Private_SetFriendAttribs(friend, gActivity.convPedsDefault) friend.bForceCreateAsArriving = FALSE RETURN TRUE ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_TryRemoveFriend(structFriend& friend, BOOL bForceDelete = FALSE, BOOL bAllowVehicleBackup = FALSE) BOOL bRemove = FALSE BOOL bFallen = FALSE FLOAT fGround IF bForceDelete OR Util_IsPedOutsideRangePed(PLAYER_PED_ID(), friend.hPed, CONST_fFriendRemoveDist) bRemove = TRUE ELIF (IS_PED_FALLING(friend.hPed) OR IS_PED_IN_PARACHUTE_FREE_FALL(friend.hPed)) AND (NOT HAS_COLLISION_LOADED_AROUND_ENTITY(friend.hPed) OR NOT GET_GROUND_Z_FOR_3D_COORD(GET_ENTITY_COORDS(friend.hPed), fGround) OR fGround < -200.0) CPRINTLN(DEBUG_FRIENDS, "Private_TryRemoveFriend(): fallen through world??...") bRemove = TRUE bFallen = TRUE ELSE IF IS_PED_ON_FOOT(friend.hPed) AND Util_IsPedInsideRange(PLAYER_PED_ID(), friend.vDoorstep, CONST_fIsPlayerAtDoorstep) AND Util_IsPedOutsideRangePed(PLAYER_PED_ID(), friend.hPed, CONST_fFriendRemoveDistOnFoot) bRemove = TRUE ENDIF ENDIF IF bRemove CPRINTLN(DEBUG_FRIENDS, "Private_TryRemoveFriend(): Removed buddy ", GetLabel_enumCharacterList(friend.eChar)) VEHICLE_INDEX hVehicle = null IF IS_PED_IN_ANY_VEHICLE(friend.hPed) hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) ENDIF IF IS_PLAYER_PED_PLAYABLE(friend.eChar) AND bFallen = FALSE SAFE_AMBIENT_STORE_PLAYER_PED_INFO(friend.hPed) // STORE_PLAYER_PED_INFO(friend.hPed) IF bAllowVehicleBackup CPRINTLN(DEBUG_FRIENDS, "Private_TryRemoveFriend() - Backup vehicle data for next creation") STORE_VEH_DATA_FROM_VEH(friend.hPed, hVehicle, g_sPlayerLastVeh[friend.eChar], g_vPlayerLastVehCoord[friend.eChar], g_fPlayerLastVehHead[friend.eChar], g_ePlayerLastVehState[friend.eChar], g_ePlayerLastVehGen[friend.eChar]) friend.bUseStoredVehicleModel = TRUE ENDIF ENDIF DELETE_PED(friend.hPed) friend.hPed = NULL // TODO: Delete phone? IF DOES_ENTITY_EXIST(hVehicle) AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(hVehicle) DELETE_VEHICLE(hVehicle) // ELIF DOES_ENTITY_EXIST(g_vPlayerVeh[friend.eChar]) // SET_VEHICLE_AS_NO_LONGER_NEEDED(g_vPlayerVeh[friend.eChar]) ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_GetFriendAnimDict(structFriend& friend, TEXT_LABEL_63& tAnimDict) IF friend.eChar = CHAR_MICHAEL tAnimDict = "friends@frm@ig_1" RETURN TRUE ELIF friend.eChar = CHAR_FRANKLIN tAnimDict = "friends@frf@ig_1" RETURN TRUE ELIF friend.eChar = CHAR_TREVOR tAnimDict = "friends@frt@ig_1" RETURN TRUE ELIF friend.eChar = CHAR_LAMAR tAnimDict = "friends@frl@ig_1" RETURN TRUE ELIF friend.eChar = CHAR_JIMMY tAnimDict = "friends@frj@ig_1" RETURN TRUE ELIF friend.eChar = CHAR_AMANDA tAnimDict = "friends@fra@ig_1" RETURN TRUE ENDIF SCRIPT_ASSERT("Private_GetFriendAnimDict() - passed friend is not a valid friend char") RETURN FALSE ENDFUNC FUNC BOOL Private_GetFriendAnim_Impatient(structFriend& friend, TEXT_LABEL_63& tAnim) INT iVariation IF friend.eChar = CHAR_MICHAEL iVariation = GET_RANDOM_INT_IN_RANGE(0, 3) IF iVariation = 0 tAnim = "impatient_idle_a" ELIF iVariation = 1 tAnim = "impatient_idle_b" ELSE tAnim = "impatient_idle_c" ENDIF RETURN TRUE ELIF friend.eChar = CHAR_FRANKLIN iVariation = GET_RANDOM_INT_IN_RANGE(0, 4) IF iVariation = 0 tAnim = "impatient_idle_a" ELIF iVariation = 1 tAnim = "impatient_idle_b" ELIF iVariation = 2 tAnim = "impatient_idle_c" ELSE tAnim = "impatient_idle_d" ENDIF RETURN TRUE ELIF friend.eChar = CHAR_TREVOR iVariation = GET_RANDOM_INT_IN_RANGE(0, 3) IF iVariation = 0 tAnim = "trevor_impatient_wait_1" ELIF iVariation = 1 tAnim = "trevor_impatient_wait_2" ELIF iVariation = 2 tAnim = "trevor_impatient_wait_3" ELSE tAnim = "trevor_impatient_wait_4" ENDIF RETURN TRUE ELIF friend.eChar = CHAR_LAMAR iVariation = GET_RANDOM_INT_IN_RANGE(0, 3) IF iVariation = 0 tAnim = "idle_a_lamar" ELIF iVariation = 1 tAnim = "idle_b_lamar" ELSE tAnim = "idle_c_lamar" ENDIF RETURN TRUE ELIF friend.eChar = CHAR_JIMMY iVariation = GET_RANDOM_INT_IN_RANGE(0, 4) IF iVariation = 0 tAnim = "idle_a" ELIF iVariation = 1 tAnim = "idle_b" ELIF iVariation = 2 tAnim = "idle_c" ELSE tAnim = "idle_d" ENDIF RETURN TRUE ELIF friend.eChar = CHAR_AMANDA iVariation = GET_RANDOM_INT_IN_RANGE(0, 2) IF iVariation = 0 tAnim = "impatient_idle_a" ELSE tAnim = "impatient_idle_b" ENDIF RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_LoadFriendPickupAnims(structFriend& friend) TEXT_LABEL_63 tAnimDict IF Private_GetFriendAnimDict(friend, tAnimDict) REQUEST_ANIM_DICT(tAnimDict) IF NOT HAS_ANIM_DICT_LOADED(tAnimDict) CPRINTLN(DEBUG_FRIENDS, "Private_LoadFriendPickupAnims(): ", tAnimDict) RETURN FALSE ENDIF ENDIF RETURN TRUE ENDFUNC PROC Private_ReleaseFriendPickupAnims(structFriend& friend) TEXT_LABEL_63 tAnimDict IF Private_GetFriendAnimDict(friend, tAnimDict) REMOVE_ANIM_DICT(tAnimDict) ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member behaviour tasks //--------------------------------------------------------------------------------------------------- //FUNC BOOL Private_IsFriendCarUsableForArrival(structFriend& friend, FLOAT fMaxDist) // // IF IS_VEHICLE_DRIVEABLE(friend.hCar) // AND GET_ENTITY_HEALTH(friend.hCar) > 600 // AND NOT IS_ENTITY_UPSIDEDOWN(friend.hCar) // AND IS_ENTITY_AT_ENTITY(friend.hPed, friend.hCar, <>) // AND ABSF(GET_ENTITY_SPEED(friend.hCar)) < 5.0 // //// VECTOR vFriendPos = GET_ENTITY_COORDS(friend.hPed) //// VECTOR vCarPos = GET_ENTITY_COORDS(friend.hCar) //// //// FLOAT fCarDist = VDIST(vFriendPos, vCarPos) //// FLOAT fLocDist = VDIST(vFriendPos, friend.vDoorstep) //// //// IF fCarDist < fLocDist - 50.0 // PED_INDEX hDriver = GET_PED_IN_VEHICLE_SEAT(friend.hCar, VS_DRIVER) // IF NOT DOES_ENTITY_EXIST(hDriver) // OR hDriver = friend.hPed // RETURN TRUE // ENDIF //// ENDIF // // ENDIF // // IF NOT IS_VEHICLE_DRIVEABLE(friend.hCar) // CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - NOT IS_VEHICLE_DRIVEABLE(friend.hCar)") // ENDIF // IF GET_ENTITY_HEALTH(friend.hCar) <= 600 // CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - GET_ENTITY_HEALTH(friend.hCar) <= 600") // ENDIF // IF IS_ENTITY_UPSIDEDOWN(friend.hCar) // CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - IS_ENTITY_UPSIDEDOWN(friend.hCar)") // ENDIF // IF NOT IS_ENTITY_AT_ENTITY(friend.hPed, friend.hCar, <>) // CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - NOT IS_ENTITY_AT_ENTITY(friend.hPed, friend.hCar, <>)") // ENDIF // IF ABSF(GET_ENTITY_SPEED(friend.hCar)) >= 5.0 // CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - ABSF(GET_ENTITY_SPEED(friend.hCar)) >= 5.0") // ENDIF // // RETURN FALSE // //ENDFUNC PROC Private_FriendTask_RunToCar( structFriend& friend ) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_ENTER_VEHICLE) CLEAR_PED_TASKS(friend.hPed) TASK_ENTER_VEHICLE(friend.hPed, friend.hCar, 30000, VS_DRIVER, PEDMOVE_RUN, ECF_RESUME_IF_INTERRUPTED|ECF_WARP_IF_DOOR_IS_BLOCKED|ECF_WARP_IF_SHUFFLE_LINK_IS_BLOCKED) ENDIF ENDPROC PROC Private_FriendTask_DriveAndPark(structFriend& friend) RESTART_TIMER_NOW(friend.mParkedTimer) VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) VECTOR vParkPos = g_FriendLocations[friend.ePickup].vParkPos FLOAT fDestDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(friend.hPed, vParkPos) INT iBasicMode = ENUM_TO_INT(DF_DriveIntoOncomingTraffic)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_StopForPeds)//|ENUM_TO_INT(DF_SteerAroundStationaryCars)//|ENUM_TO_INT(DF_UseSwitchedOffNodes) INT iDriveAvoidMode = iBasicMode|ENUM_TO_INT(DF_ChangeLanesAroundObstructions)|ENUM_TO_INT(DF_SteerAroundStationaryCars)|ENUM_TO_INT(DF_SwerveAroundAllCars)|ENUM_TO_INT(DF_SteerAroundPeds) INT iParkStopMode = iBasicMode|/*ENUM_TO_INT(DF_SteerAroundStationaryCars)|*/ENUM_TO_INT(DF_StopForCars) // IF GET_ENTITY_SPEED(friend.hPed) > 1.0 // friend.iArrivalStoppedTimer = GET_GAME_TIMER() // ENDIF FLOAT fStoppedTimer = 0.0 IF GET_ENTITY_SPEED(friend.hPed) <= 1.0 IF NOT IS_TIMER_STARTED(friend.mArrivalStoppedTimer) RESTART_TIMER_NOW(friend.mArrivalStoppedTimer) ELSE fStoppedTimer = GET_TIMER_IN_SECONDS(friend.mArrivalStoppedTimer) ENDIF ELSE CANCEL_TIMER(friend.mArrivalStoppedTimer) ENDIF // At dest / Near dest and stopped for blockage ... Get out IF fDestDist < 2.0 // OR (fDestDist < 15.0 AND (friend.iArrivalStoppedTimer+1000) < GET_GAME_TIMER()) // OR (fDestDist < 30.0 AND (friend.iArrivalStoppedTimer+3000) < GET_GAME_TIMER()) OR (fDestDist < 15.0 AND fStoppedTimer > 1.0) // OR (fDestDist < 30.0 AND fStoppedTimer > 3.0) OR (fDestDist < 20.0 AND fStoppedTimer > 6.0) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) CPRINTLN(DEBUG_FRIENDS, "Exit vehicle") CLEAR_PED_TASKS(friend.hPed) // B*1480465 - Friend will turn off headlights when exiting vehicle IF DOES_ENTITY_EXIST(hVehicle) SET_VEHICLE_ENGINE_ON(hVehicle, FALSE, TRUE) ENDIF TASK_LEAVE_ANY_VEHICLE(friend.hPed) // TASK_LEAVE_ANY_VEHICLE(friend.hPed, 0, ECF_RESUME_IF_INTERRUPTED|ECF_WARP_IF_DOOR_IS_BLOCKED) ENDIF // Very close to dest... Drive slow, stop for blockages // MAKE SURE ALL THIS WORKS WHEN SWITCHING TO PED AND AWAY AGAIN ELIF fDestDist < 10.0//12.0//7.0 IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR friend.iArrivalDrivingMode <> 0 CPRINTLN(DEBUG_FRIENDS, "Driving mode 0: Drive slow, stop for blockages") CLEAR_PED_TASKS(friend.hPed) TASK_VEHICLE_MISSION_COORS_TARGET(friend.hPed, hVehicle, vParkPos, MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iParkStopMode), 2.0, 10.0/*20.0*//*15.0*/, TRUE) friend.iArrivalDrivingMode = 0 ENDIF ELSE IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR friend.iArrivalDrivingMode <> 1 CPRINTLN(DEBUG_FRIENDS, "Driving mode 1: Drive slow, go around blockages") CLEAR_PED_TASKS(friend.hPed) TASK_VEHICLE_MISSION_COORS_TARGET(friend.hPed, hVehicle, vParkPos, MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iDriveAvoidMode), 2.0, 20.0/*15.0*/, TRUE) friend.iArrivalDrivingMode = 1 ENDIF IF fDestDist < 30.0 SET_DRIVE_TASK_CRUISE_SPEED(friend.hPed, 10.0) ELSE SET_DRIVE_TASK_CRUISE_SPEED(friend.hPed, CONST_fFriendArriveSpeed) ENDIF ENDIF // VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) // VECTOR vParkPos = g_FriendLocations[friend.ePickup].vParkPos // INT iDrivingMode = ENUM_TO_INT(DF_StopForPeds)|ENUM_TO_INT(DF_SteerAroundPeds)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_SteerAroundStationaryCars)|ENUM_TO_INT(DF_SwerveAroundAllCars)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding) // INT iParkingMode = ENUM_TO_INT(DF_StopForCars)|ENUM_TO_INT(DF_StopForPeds)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding)|ENUM_TO_INT(DF_DriveIntoOncomingTraffic) // // RESTART_TIMER_NOW(friend.mParkedTimer) // // //-- Drive -- // IF Util_IsPedOutsideRange(friend.hPed, vParkPos, 30.0) // // IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_VEHICLE_MISSION) // CLEAR_PED_TASKS(friend.hPed) // TASK_VEHICLE_MISSION_COORS_TARGET(friend.hPed, hVehicle, friend.vDriveway, MISSION_GOTO, CONST_fFriendArriveSpeed, INT_TO_ENUM(DRIVINGMODE, iDrivingMode), 1, 10, TRUE)//FALSE) // ENDIF // // //-- Park -- // ELSE // // IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_PERFORM_SEQUENCE) // IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) // CLEAR_PED_TASKS(friend.hPed) // SEQUENCE_INDEX seq // OPEN_SEQUENCE_TASK(seq) // TASK_VEHICLE_GOTO_NAVMESH(null, hVehicle, vParkPos, 6.0, INT_TO_ENUM(DRIVINGMODE, iParkingMode), 1) // TASK_LEAVE_ANY_VEHICLE(null, 0, ECF_RESUME_IF_INTERRUPTED|ECF_WARP_IF_DOOR_IS_BLOCKED) // CLOSE_SEQUENCE_TASK(seq) // TASK_PERFORM_SEQUENCE(friend.hPed, seq) // // friend.iParkTimer = GET_GAME_TIMER() + 10000 // ENDIF // ELSE // IF friend.iParkTimer < GET_GAME_TIMER() // TASK_LEAVE_ANY_VEHICLE(friend.hPed, 0, ECF_RESUME_IF_INTERRUPTED|ECF_WARP_IF_DOOR_IS_BLOCKED) // ENDIF // ENDIF // // ENDIF ENDPROC PROC Private_FriendTask_RunToPlayer( structFriend& friend ) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_GO_TO_ENTITY) IF NOT IS_PED_INJURED(gActivity.mPlayer.hPed) TASK_GO_TO_ENTITY(friend.hPed, gActivity.mPlayer.hPed, DEFAULT_TIME_NEVER_WARP, 5.0) ENDIF ENDIF ENDPROC PROC Private_FriendTask_RunToDoorstep( structFriend& friend ) //-- Run to doorstep -- IF Util_IsPedOutsideRange(friend.hPed, friend.vDoorstep, 1.5) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) TASK_FOLLOW_NAV_MESH_TO_COORD(friend.hPed, friend.vDoorstep, PEDMOVE_RUN, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_STOP_EXACTLY) ENDIF ELSE VECTOR vPedForward = GET_ENTITY_FORWARD_VECTOR(friend.hPed) VECTOR vTargetForward = NORMALISE_VECTOR(friend.vDriveway - friend.vDoorstep) FLOAT fAngle = 0.0 IF (vPedForward.x <> 0.0 OR vPedForward.y <> 0.0) AND (vTargetForward.x <> 0.0 OR vTargetForward.y <> 0.0) fAngle = GET_ANGLE_BETWEEN_2D_VECTORS(vPedForward.x, vPedForward.y, vTargetForward.x, vTargetForward.y) ENDIF //-- Turn to face loc -- IF (fAngle > 20 OR NOT Private_LoadFriendPickupAnims(friend)) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_TURN_PED_TO_FACE_COORD) AND NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_PLAY_ANIM) CPRINTLN(DEBUG_FRIENDS, "------------- Turn friend to player ------------- ", GetLabel_enumCharacterList(friend.eChar)) TASK_TURN_PED_TO_FACE_COORD(friend.hPed, friend.vDriveway, 6000) ENDIF //-- Play wait anim -- ELSE IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_PLAY_ANIM) TEXT_LABEL_63 tAnimDict, tAnim Private_GetFriendAnimDict(friend, tAnimDict) Private_GetFriendAnim_Impatient(friend, tAnim) CPRINTLN(DEBUG_FRIENDS, "------------- Starting friend anim ------------- ", GetLabel_enumCharacterList(friend.eChar)) IF friend.eChar = CHAR_AMANDA TASK_PLAY_ANIM(friend.hPed, tAnimDict, tAnim, WALK_BLEND_IN, WALK_BLEND_OUT, -1, AF_LOOPING) ELSE TASK_PLAY_ANIM(friend.hPed, tAnimDict, tAnim, WALK_BLEND_IN, WALK_BLEND_OUT, -1) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC Private_FriendArrivalTasks(structFriend& friend) IF NOT IS_PED_RAGDOLL(friend.hPed) AND NOT IS_PED_RUNNING_RAGDOLL_TASK(friend.hPed) IF IS_PED_IN_ANY_VEHICLE(friend.hPed) Private_FriendTask_DriveAndPark(friend) ELSE IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND Util_IsPedInsideRangePed(PLAYER_PED_ID(), friend.hPed, CONST_fRunToPlayerRange) Private_FriendTask_RunToPlayer(friend) // ELIF Util_IsPedOutsideRange(friend.hPed, friend.vDoorstep, 50.0) // ELIF Private_IsFriendCarUsableForArrival(friend, 100.0) // // Private_FriendTask_RunToCar(friend) ELSE Private_FriendTask_RunToDoorstep(friend) ENDIF ENDIF ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member objectives //--------------------------------------------------------------------------------------------------- PROC Private_ClearFriendObjectives(structFriend& friend) IF DOES_BLIP_EXIST(friend.hLocBlip) REMOVE_BLIP(friend.hLocBlip) ENDIF IF DOES_BLIP_EXIST(friend.hPedBlip) REMOVE_BLIP(friend.hPedBlip) ENDIF IF friend.bIsShowingPickupCam = TRUE IF IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT() ENDIF SET_CINEMATIC_BUTTON_ACTIVE(TRUE) friend.bIsShowingPickupCam = FALSE ENDIF Private_ClearHelpWithString("FR_HV_HORN", friend.tName) Private_ClearHelpWithString("FR_H_PKUP", friend.tName) Private_ClearHelpWithString("FR_H_WAIT", friend.tName) Private_ClearHelpWithString("FR_H_DROPOFF0", friend.tName) Private_ClearHelpWithString("FR_H_DROPOFF1", friend.tName) Private_ClearHelpWithString("FR_H_DROPOFF2", friend.tName) Private_ClearPrintWithString("FR_GETBACK", friend.tName) Private_ClearPrint("FR_GETBACK2") ENDPROC FUNC BLIP_INDEX Private_CreateFriendLocBlip(structFriend& friend) IF friend.eState = FRIEND_NULL SCRIPT_ASSERT("Private_CreateFriendLocBlip() - friend is null") ELIF friend.ePickup <> NO_FRIEND_LOCATION CPRINTLN(DEBUG_FRIENDS, "Private_CreateFriendLocBlip(", GetLabel_enumCharacterList(friend.eChar), ")") friend.hLocBlip = CREATE_BLIP_FOR_COORD(friend.vDriveway) IF DOES_BLIP_EXIST(friend.hLocBlip) SET_BLIP_AS_FRIENDLY(friend.hLocBlip, TRUE) SET_BLIP_SPRITE(friend.hLocBlip, RADAR_TRACE_FRIEND) SET_BLIP_NAME_FROM_TEXT_FILE(friend.hLocBlip, "FR_PKUPBLIP") ENDIF RETURN friend.hLocBlip ENDIF RETURN null ENDFUNC FUNC BLIP_INDEX Private_CreateFriendPedBlip(structFriend& friend) IF friend.eState = FRIEND_NULL SCRIPT_ASSERT("Private_CreateFriendPedBlip() - friend is null") ELSE CPRINTLN(DEBUG_FRIENDS, "Private_CreateFriendPedBlip(", GetLabel_enumCharacterList(friend.eChar), ")") IF NOT IS_PED_INJURED(friend.hPed) friend.hPedBlip = CREATE_BLIP_FOR_PED(friend.hPed) IF DOES_BLIP_EXIST(friend.hPedBlip) SET_BLIP_AS_FRIENDLY(friend.hPedBlip, TRUE) SET_BLIP_NAME_FROM_TEXT_FILE(friend.hPedBlip, friend.tName) ENDIF RETURN friend.hPedBlip ENDIF ENDIF RETURN null ENDFUNC PROC Private_RemoveFriendLocBlip(structFriend& friend) IF DOES_BLIP_EXIST(friend.hLocBlip) REMOVE_BLIP(friend.hLocBlip) ENDIF ENDPROC PROC Private_RemoveFriendPedBlip(structFriend& friend) IF DOES_BLIP_EXIST(friend.hPedBlip) REMOVE_BLIP(friend.hPedBlip) ENDIF ENDPROC PROC Private_UpdateFriendPedBlip(structFriend& friend, BOOL bForceOn = FALSE) BOOL bDisplay = FALSE IF friend.eState <> FRIEND_NULL IF NOT IS_PED_INJURED(friend.hPed) IF bForceOn = TRUE OR friend.eState = FRIEND_PARACHUTE OR friend.eState = FRIEND_PLUMMET OR friend.eState = FRIEND_LOST OR friend.eState = FRIEND_FAIL_LOST bDisplay = TRUE ELSE INTERIOR_INSTANCE_INDEX hStripClubInterior = GET_INTERIOR_AT_COORDS(<<121.9946, -1292.5457, 29.2792>>) IF hStripClubInterior <> NULL IF GET_INTERIOR_FROM_ENTITY(friend.hPed) = hStripClubInterior bDisplay = TRUE ENDIF ENDIF ENDIF ENDIF ENDIF IF bDisplay IF NOT DOES_BLIP_EXIST(friend.hPedBlip) AND (GET_BLIP_FROM_ENTITY(friend.hPed) = NULL) Private_CreateFriendPedBlip(friend) ENDIF ELSE IF DOES_BLIP_EXIST(friend.hPedBlip) Private_RemoveFriendPedBlip(friend) ENDIF ENDIF ENDPROC //--------------------------------------------------------------------------------------------------- //-- Member state utils //--------------------------------------------------------------------------------------------------- PROC Private_SetFriendState(structFriend& friend, enumFriendState eState) #IF IS_DEBUG_BUILD TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_63 tState = GetLabel_enumFriendState(eState) CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendState(", tChar, ", ", tState, ")") #ENDIF friend.eState = eState ENDPROC FUNC BOOL Private_IsFriendArriving(structFriend& friend) // Set objective IF friend.eState = FRIEND_PICKUP AND DOES_ENTITY_EXIST(friend.hPed) IF Util_IsPedOutsideRange(friend.hPed, friend.vDriveway, CONST_fIsBuddyAtDriveway) AND Util_IsPedInsideRange(PLAYER_PED_ID(), friend.vDoorstep, CONST_fIsPlayerAtDoorstep) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanPickupFriend(structFriend& friend) IF friend.eState = FRIEND_PICKUP IF IS_PLAYER_CONTROL_ON(PLAYER_ID()) // Friend must be on foot to trigger IF NOT IS_PED_IN_ANY_VEHICLE(friend.hPed) // Player on foot IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // Is friend near + on screen? IF Util_IsPedInsideRangePed(friend.hPed, PLAYER_PED_ID(), CONST_fPickupHornDist) IF IS_ENTITY_ON_SCREEN(friend.hPed) RETURN TRUE ENDIF ENDIF // Player in car ELSE // Is friend near? IF Util_IsPedInsideRangePed(friend.hPed, PLAYER_PED_ID(), CONST_fPickupHornDist) RETURN TRUE // Are friend and player at driveway? ELIF friend.ePickup <> NO_FRIEND_LOCATION IF Util_IsPedInsideRange(friend.hPed, friend.vDoorstep, CONST_fIsBuddyAtDriveway) IF Util_IsPedInsideRange(PLAYER_PED_ID(), friend.vDriveway, CONST_fPickupHornDist) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_IsPlayerTakingTaxi() IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF IS_VEHICLE_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), TAXI) IF GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) <> PLAYER_PED_ID() RETURN TRUE ENDIF ENDIF ENDIF // IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) // IF DOES_ENTITY_EXIST(hVehicle) // IF GET_ENTITY_MODEL(hVehicle) = TAXI // PED_INDEX hDriver = GET_PED_IN_VEHICLE_SEAT(hVehicle, VS_DRIVER) // IF DOES_ENTITY_EXIST(hDriver) AND hDriver <> PLAYER_PED_ID() // RETURN TRUE // ENDIF // ENDIF // ENDIF // ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_TryPickupFriend(structFriend& friend) TEXT_LABEL sUseCarHorn_help = "FR_HV_HORN" //Click ~INPUT_HORN~ to use the vehicle horn and attract ~a~'s attention. BOOL bCanPickup = Private_CanPickupFriend(friend) // Display help text / Update hint cam IF bCanPickup AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT Private_IsPlayerTakingTaxi() //AND NOT IS_PLAYER_PRESSING_HORN(PLAYER_ID()) // Try to start camera IF friend.bIsShowingPickupCam = FALSE IF NOT IS_CINEMATIC_CAM_RENDERING() IF IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT() ELSE SET_GAMEPLAY_ENTITY_HINT(friend.hPed, <<0,0,0>>, TRUE, -1, 3000, 3000, HINTTYPE_DEFAULT) SET_CINEMATIC_BUTTON_ACTIVE(FALSE) friend.bIsShowingPickupCam = TRUE ENDIF ENDIF ENDIF // Show hown help text IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED() IF 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_SUB(PLAYER_PED_ID()) AND NOT IS_PED_IN_ANY_TRAIN(PLAYER_PED_ID()) AND NOT IS_PED_IN_MODEL(PLAYER_PED_ID(), BMX) PRINT_HELP_FOREVER_WITH_STRING_NO_SOUND(sUseCarHorn_help, friend.tName) ENDIF ENDIF ELSE // Clear camera IF friend.bIsShowingPickupCam = TRUE IF IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT() ENDIF SET_CINEMATIC_BUTTON_ACTIVE(TRUE) friend.bIsShowingPickupCam = FALSE ENDIF // Clear hown help text IF IS_THIS_HELP_MESSAGE_WITH_STRING_BEING_DISPLAYED(sUseCarHorn_help, friend.tName) CLEAR_HELP() ENDIF ENDIF IF NOT IS_PED_RAGDOLL(friend.hPed) AND NOT IS_PED_RUNNING_RAGDOLL_TASK(friend.hPed) AND NOT Private_IsPlayerTakingTaxi() // Pickup if in zone and onfoot / stops car / not on doorstep IF bCanPickup IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // On foot - pickup automatically RETURN TRUE ELIF IS_PLAYER_PRESSING_HORN(PLAYER_ID()) // In car - pickup if pressing horn RETURN TRUE ELIF Util_IsPedOutsideRange(friend.hPed, friend.vDoorstep, 2.0) // In car - pickup automatically if friend is not on doorstep RETURN TRUE ENDIF ENDIF // Car-pickup, if in normal range, and both stopped IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) // In car - pickup automatically if very close and both stopped IF IS_CHAR_ALMOST_STOPPED(PLAYER_PED_ID()) IF IS_CHAR_ALMOST_STOPPED(friend.hPed) IF Util_IsPedInsideRangePed(friend.hPed, PLAYER_PED_ID(), CONST_fPickupHornDist) RETURN TRUE ENDIF ENDIF ENDIF ENDIF // Car-pickup, if in extended range, and beeping horn - Fix b*1987632 - Cars must be almost stopped when going into group state, otherwise friend won't be able to join group, and will be set to lost state. IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) IF IS_PLAYER_PRESSING_HORN(PLAYER_ID()) IF IS_CHAR_ALMOST_STOPPED(PLAYER_PED_ID()) IF IS_CHAR_ALMOST_STOPPED(friend.hPed) IF Util_IsPedInsideRangePed(friend.hPed, PLAYER_PED_ID(), CONST_fPickupHornExtraDist) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC PROC Private_ClearFriendPickupHelp(structFriend& friend, BOOL bForce = FALSE) IF friend.bIsShowingPickupCam OR bForce IF IS_GAMEPLAY_HINT_ACTIVE() STOP_GAMEPLAY_HINT() ENDIF SET_CINEMATIC_BUTTON_ACTIVE(TRUE) friend.bIsShowingPickupCam = FALSE ENDIF Private_ClearHelpWithString("FR_HV_HORN", friend.tName) ENDPROC PROC Private_SetFriendPickedUp(structFriend& friend) Private_SetFriendState(friend, FRIEND_GROUP) friend.bWasPickedUp = TRUE Private_ReleaseFriendPickupAnims(friend) IF gActivity.mPlayer.eChar <> friend.eChar PAUSE_TIMER(friend.mWaitTimer) // TODO: This needs looking at Private_SetFriendsForcedSeats() Private_ClearFriendSwitchOverride(friend) Private_ClearFriendPickupHelp(friend, TRUE) // SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(friend.hPed, FALSE) // CLEAR_ENTITY_LAST_DAMAGE_ENTITY(friend.hPed) // CLEAR_ENTITY_LAST_WEAPON_DAMAGE(friend.hPed) CLEAR_PED_TASKS(friend.hPed) // IF DOES_ENTITY_EXIST(friend.hCar) // friend.iCarHealth = GET_ENTITY_HEALTH(friend.hCar) // ENDIF friend.iBlockRunningUntilTime = GET_GAME_TIMER() + c_iPickupRunBlockDuration // Add to group SET_PED_AS_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) SET_PED_GROUP_MEMBER_PASSENGER_INDEX(friend.hPed, VS_FRONT_RIGHT) TASK_LOOK_AT_ENTITY(friend.hPed, PLAYER_PED_ID(), 7000)//, SLF_FAST_TURN_RATE) #if not USE_CLF_DLC #if not USE_NRM_DLC IF friend.eChar = CHAR_LAMAR IF gActivity.mPlayer.eChar = CHAR_FRANKLIN SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FRAN_DONE_ACTIVITY_WITH_LAMAR, TRUE) ENDIF IF gActivity.mPlayer.eChar = CHAR_TREVOR SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_FRAN_DONE_ACTIVITY_WITH_LAMAR, TRUE) ENDIF ENDIF #endif #endif IF friend.eChar = CHAR_JIMMY OR friend.eChar = CHAR_AMANDA SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, TRUE) ELSE SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, FALSE) ENDIF // Start pickup dialogue (if not already running for another member) IF NOT Private_IsDialogueDoingPickup(gActivity.mDialogue) IF friend.bWasMetAmbiently Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_AMBIENT, friend.eChar) ELSE Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_PICKUP, friend.eChar) ENDIF ENDIF ENDIF ENDPROC FUNC BOOL Private_IsFriendValid(structFriend& friend) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_IsFriendOutside(structFriend& friend) IF NOT IS_PED_INJURED(friend.hPed) IF GET_INTERIOR_FROM_ENTITY(friend.hPed) = NULL RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendConverse(structFriend& friend) IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_UNINJURED(friend.hPed) IF friend.eChar = GET_CURRENT_PLAYER_PED_ENUM() RETURN TRUE ENDIF IF friend.eState = FRIEND_GROUP OR friend.eState = FRIEND_TRAPPED IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), friend.hPed, <>) RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendLeave(structFriend& friend) IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hVehicle) IF NOT IS_VEHICLE_STOPPED(hVehicle) //ABSF(GET_ENTITY_SPEED(friend.hPed)) > 8.0//0.5 IF NOT IS_PED_INJURED(PLAYER_PED_ID()) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), hVehicle) RETURN FALSE ENDIF ENDIF ENDIF ENDIF RETURN TRUE ENDFUNC FUNC BOOL Private_IsPlayerOrFriendPersued(structFriend& friend, BOOL bCheckIfTarget = FALSE) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF bCheckIfTarget IF COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(PLAYER_PED_ID(), GET_ENTITY_COORDS(PLAYER_PED_ID()), 50.0) > 0 CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Peds in combat with player") RETURN TRUE ENDIF IF COUNT_PEDS_IN_COMBAT_WITH_TARGET_WITHIN_RADIUS(friend.hPed, GET_ENTITY_COORDS(friend.hPed), 50.0) > 0 CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Peds in combat with friend") RETURN TRUE ENDIF ENDIF IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON) AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Player attacked with weapons") RETURN TRUE ENDIF IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(friend.hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON) AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(friend.hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Friend attacked with weapons") RETURN TRUE ENDIF IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0) VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) VECTOR vMin = vPlayerPos - << 50.0,50.0,50.0 >> VECTOR vMax = vPlayerPos + << 50.0,50.0,50.0 >> IF IS_COP_PED_IN_AREA_3D(vMin, vMax) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Player persued by cops") RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_IsFriendAirbourne(structFriend& friend) IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hVehicle) IF GET_ENTITY_HEIGHT_ABOVE_GROUND(hVehicle) > 5.0 RETURN TRUE ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_ShouldFriendFlee(structFriend& friend) IF friend.eState <> FRIEND_NULL AND NOT IS_PED_INJURED(friend.hPed) IF NOT Private_IsFriendAirbourne(friend) IF IS_PED_FLEEING(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_ShouldFriendFlee(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Already fleeing") RETURN TRUE ELIF friend.eChar = CHAR_JIMMY OR friend.eChar = CHAR_AMANDA IF IS_BIT_SET(g_bitfieldFriendFlags, ENUM_TO_INT(FRIENDFLAG_IS_ROBBERY_UNDERWAY)) RETURN TRUE ENDIF IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON) AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Player attacked with weapons") RETURN TRUE ENDIF IF HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(friend.hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON) AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(friend.hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Friend attacked with weapons") RETURN TRUE ENDIF IF NOT IS_PED_IN_ANY_VEHICLE(friend.hPed) IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0) VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) VECTOR vMin = vPlayerPos - << 50.0,50.0,50.0 >> VECTOR vMax = vPlayerPos + << 50.0,50.0,50.0 >> IF IS_COP_PED_IN_AREA_3D(vMin, vMax) CPRINTLN(DEBUG_FRIENDS, "Private_IsPlayerOrFriendPersued(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Player persued by cops") RETURN TRUE ENDIF ENDIF ENDIF IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hCar = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hCar) IF IS_ENTITY_DEAD(hCar) OR IS_ENTITY_ON_FIRE(hCar) CPRINTLN(DEBUG_FRIENDS, "Private_ShouldFriendFlee(", GetLabel_enumCharacterList(friend.eChar), ") = TRUE - Vehicle dead/on fire") RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendEnterParachute(structFriend& friend) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) PED_PARACHUTE_STATE ePlayerState = GET_PED_PARACHUTE_STATE(PLAYER_PED_ID()) IF ePlayerState = PPS_DEPLOYING OR ePlayerState = PPS_PARACHUTING OR ePlayerState = PPS_LANDING IF IS_ENTITY_IN_AIR(friend.hPed) IF NOT IS_PED_IN_ANY_VEHICLE(friend.hPed) IF GET_ENTITY_HEIGHT_ABOVE_GROUND(friend.hPed) > 50.0 IF HAS_PED_GOT_WEAPON(friend.hPed, GADGETTYPE_PARACHUTE) // Make sure not too close to any other parachuters // PED_INDEX nearbyPeds[5] // INT iNearbyPedCount = GET_PED_NEARBY_PEDS(friend.hPed, nearbyPeds) // // INT iPedID // REPEAT iNearbyPedCount iPedID // IF NOT IS_PED_INJURED(nearbyPeds[iPedID]) // SWITCH GET_PED_PARACHUTE_STATE(nearbyPeds[iPedID]) // CASE PPS_DEPLOYING // CASE PPS_PARACHUTING // CASE PPS_LANDING // IF IS_ENTITY_AT_ENTITY(friend.hPed, nearbyPeds[iPedID], <<20.0, 20.0, 20.0>>) // RETURN FALSE // ENDIF // BREAK // ENDSWITCH // ENDIF // ENDREPEAT // // IF NOT IS_ENTITY_AT_ENTITY(friend.hPed, PLAYER_PED_ID(), <<25.0, 25.0, 25.0>>) // RETURN TRUE // ENDIF RETURN TRUE ELSE CPRINTLN(DEBUG_FRIENDS, "Player parachuting and falling high in air, but ", GetLabel_enumCharacterList(friend.eChar), " doesn't have parachute") ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendExitParachute(structFriend& friend) IF NOT IS_ENTITY_IN_AIR(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_CanFriendExitParachute() - Not in air") IF GET_PED_PARACHUTE_STATE(friend.hPed) = PPS_INVALID //<> PPS_LANDING RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendEnterPlummet(structFriend& friend) IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hVehicle) IF IS_PED_INJURED(PLAYER_PED_ID()) OR NOT IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), hVehicle) IF GET_ENTITY_HEIGHT_ABOVE_GROUND(hVehicle) > 50.0 IF NOT HAS_PED_GOT_WEAPON(friend.hPed, GADGETTYPE_PARACHUTE) RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC FUNC BOOL Private_CanFriendExitPlummet(structFriend& friend) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF NOT IS_PED_IN_ANY_VEHICLE(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_CanFriendExitPlummet(", GetLabel_enumCharacterList(friend.eChar), ") - Friend not in vehicle") RETURN TRUE ELSE VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hVehicle) IF NOT IS_ENTITY_IN_AIR(hVehicle) CPRINTLN(DEBUG_FRIENDS, "Private_CanFriendExitPlummet(", GetLabel_enumCharacterList(friend.eChar), ") - Vehicle not in air") RETURN TRUE ELSE IF GET_ENTITY_SPEED(hVehicle) < 5.0 AND GET_ENTITY_HEIGHT_ABOVE_GROUND(hVehicle) < 30.0 CPRINTLN(DEBUG_FRIENDS, "Private_CanFriendExitPlummet(", GetLabel_enumCharacterList(friend.eChar), ") - Vehicle stopped near ground") RETURN TRUE ENDIF ENDIF ENDIF ENDIF ENDIF RETURN FALSE ENDFUNC PROC Private_SetFriendTrapped(structFriend& friend) IF NOT IS_PED_INJURED(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendTrapped(", GetLabel_enumCharacterList(friend.eChar), ")") TASK_PAUSE(friend.hPed, -1) friend.bDoneTrappedDialogue = FALSE Private_SetFriendState(friend, FRIEND_TRAPPED) ENDIF ENDPROC PROC Private_SetFriendFleeing(structFriend& friend, BOOL bAllowDeathShockDialogue = FALSE) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL IF NOT IS_PED_INJURED(friend.hPed) IF bAllowDeathShockDialogue AND Private_CanFriendConverse(friend) IF Private_GetDialogueState(gActivity.mDialogue) <> FDIALOGUE_REJECTED Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_REJECTED, friend.eChar, FAP_DEATH) ENDIF ENDIF Private_SetFriendState(friend, FRIEND_FAIL_FLEE) ENDIF ENDIF ENDPROC PROC Private_SetFriendAttacked(structFriend& friend, BOOL bForceResetContactTime = FALSE) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL IF NOT IS_PED_INJURED(friend.hPed) Private_ResetFriendGroupTimers(friend, FRIEND_CONTACT_DISMISSED, bForceResetContactTime) Private_SetFriendState(friend, FRIEND_FAIL_ATTACKED) ENDIF ENDIF ENDPROC PROC Private_SetFriendWander(structFriend& friend, BOOL bForceResetContactTime = FALSE) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL IF NOT IS_PED_INJURED(friend.hPed) Private_ResetFriendGroupTimers(friend, FRIEND_CONTACT_DISMISSED, bForceResetContactTime) Private_SetFriendState(friend, FRIEND_FAIL_WANDER) ENDIF ENDIF ENDPROC PROC Private_SetFriendsFleeing(BOOL bDueToDeath) IF gActivity.mFriendA.eState = FRIEND_GROUP OR gActivity.mFriendA.eState = FRIEND_LOST Private_SetFriendFleeing(gActivity.mFriendA, bDueToDeath) ENDIF IF gActivity.mFriendB.eState = FRIEND_GROUP OR gActivity.mFriendB.eState = FRIEND_LOST Private_SetFriendFleeing(gActivity.mFriendB, bDueToDeath) ENDIF ENDPROC PROC Private_SetFriendsWander() IF gActivity.mFriendA.eState = FRIEND_GROUP OR gActivity.mFriendA.eState = FRIEND_LOST IF NOT IS_PED_INJURED(gActivity.mFriendA.hPed) Private_SetFriendState(gActivity.mFriendA, FRIEND_FAIL_WANDER) ENDIF ENDIF IF gActivity.mFriendB.eState = FRIEND_GROUP OR gActivity.mFriendB.eState = FRIEND_LOST IF NOT IS_PED_INJURED(gActivity.mFriendB.hPed) Private_SetFriendState(gActivity.mFriendB, FRIEND_FAIL_WANDER) ENDIF ENDIF ENDPROC FUNC BOOL Private_SetFriendRejected(structFriend& friend, BOOL bAllowSubtitles, enumFriendActivityPhrase ePhrase = FAP_REJECTION_OK) IF friend.eState <> FRIEND_NULL AND friend.eState < FRIEND_CANCEL #IF IS_DEBUG_BUILD TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_63 tSubtitles = "bAllowSubtitles" TEXT_LABEL_63 tPhrase = GetLabel_enumFriendActivityPhrase(ePhrase) IF bAllowSubtitles tSubtitles += "=TRUE" ELSE tSubtitles += "=FALSE" ENDIF CPRINTLN(DEBUG_FRIENDS, "Private_SetFriendRejected(", tChar, ", ", tSubtitles, ", ", tPhrase, ")") #ENDIF enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM() // Play audio comment IF IS_PED_UNINJURED(friend.hPed) AND friend.eChar <> ePlayerChar IF Private_CanFriendConverse(friend) IF (ePhrase <> NO_FRIEND_ACTIVITY_PHRASE) TEXT_LABEL tRoot IF bAllowSubtitles = FALSE IF PRIVATE_FriendDialogue_GetRawAudio(friend.eChar, ePhrase, tRoot) PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(friend.hPed, tRoot, PRIVATE_Get_SpeakerLabel_From_Char(friend.eChar), SPEECH_PARAMS_FORCE_FRONTEND) ENDIF ELSE IF Private_GetDialogueState(gActivity.mDialogue) <> FDIALOGUE_REJECTED Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_REJECTED, friend.eChar, ePhrase) ENDIF ENDIF ENDIF ENDIF ENDIF Private_SetFriendState(friend, FRIEND_FAIL_REJECTED) RETURN TRUE ENDIF RETURN FALSE ENDFUNC //--------------------------------------------------------------------------------------------------- //-- Member main //--------------------------------------------------------------------------------------------------- FUNC BOOL Private_AddFriend(structFriend& friend, enumCharacterList eChar, enumFriendLocation ePickupLocation, INT iOffsetIndex, BOOL bWasMetAmbiently = FALSE) CPRINTLN(DEBUG_FRIENDS, "Private_AddFriend(", GetLabel_enumCharacterList(eChar), ")") IF eChar = NO_CHARACTER SCRIPT_ASSERT("Private_AddFriend() - Character passed is null") ELSE enumFriend eFriend = GET_FRIEND_FROM_CHAR(eChar) IF eFriend >= MAX_FRIENDS SCRIPT_ASSERT("Private_AddFriend() - Character passed is not valid friend") ELSE Private_SetFriendState(friend, FRIEND_PICKUP) friend.eChar = eChar friend.ePickup = ePickupLocation friend.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 RESTART_TIMER_NOW(friend.mWaitTimer) // Set friend home location IF ePickupLocation < MAX_FRIEND_LOCATIONS Private_SetFriendPickupLocOffset(friend, iOffsetIndex) Private_SetFriendSwitchOverride(friend) // If picking up from a rural location, allow more time for pickup IF ePickupLocation = FLOC_michael_CS OR ePickupLocation = FLOC_trevor_CS OR ePickupLocation = FLOC_paletoMainSt_PA OR ePickupLocation = FLOC_minimartCarpark_SS gActivity.bIsRural = TRUE ENDIF ENDIF IF ePickupLocation = FLOC_adhoc friend.bForceCreateAsArriving = TRUE ENDIF Private_SyncFriendPed(friend) // Mark as ambient launched IF bWasMetAmbiently friend.bWasMetAmbiently = TRUE Private_SetFriendPickedUp(friend) Private_SetFriendPickedUp(gActivity.mPlayer) ELSE friend.bWasMetAmbiently = FALSE Private_SetFriendScenarioBlocking(friend) ENDIF // Setup models for friend ped and car PED_VEH_DATA_STRUCT sVehData IF IS_PLAYER_PED_PLAYABLE(friend.eChar) // Set required models (playable char) GET_PLAYER_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_CAR) friend.eCarModel = sVehData.model friend.ePedModel = GET_PLAYER_PED_MODEL(friend.eChar) ELIF friend.eChar = CHAR_JIMMY // Set required models (Jimmy rides a bike) GET_NPC_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_BIKE) friend.eCarModel = sVehData.model friend.ePedModel = GET_NPC_PED_MODEL(friend.eChar) ELSE // Set required models (npc char) GET_NPC_VEH_DATA(friend.eChar, sVehData, VEHICLE_TYPE_CAR) friend.eCarModel = sVehData.model friend.ePedModel = GET_NPC_PED_MODEL(friend.eChar) ENDIF IF friend.eCarModel = DUMMY_MODEL_FOR_SCRIPT friend.eCarModel = ASEA ENDIF // request models REQUEST_MODEL(friend.eCarModel) REQUEST_MODEL(friend.ePedModel) // Disable family scenes Private_EnableFamilyScenes(eChar, FALSE) RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC PROC Private_CleanupFriend(structFriend& friend, enumMemberCleanupStyle eCleanupStyle = MC_Release, BOOL bForceTimerDismissed = FALSE) IF friend.eState <> FRIEND_NULL #IF IS_DEBUG_BUILD TEXT_LABEL_31 tChar = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL_31 tStyle = GetLabel_enumMemberCleanupStyle(eCleanupStyle) CPRINTLN(DEBUG_FRIENDS, "Private_CleanupFriend(", tChar, ", ", tStyle, ")") #ENDIF // Clear friend available flag IF IS_PLAYER_PED_PLAYABLE(friend.eChar) CLEAR_BIT(g_bitfieldFriendFlags, ENUM_TO_INT(friend.eChar)) ENDIF // Clear switch override Private_ClearFriendSwitchOverride(friend) // Clear pickup help text and camera Private_ClearFriendPickupHelp(friend) // Probably not needed (keeping just to avoid breaking anything by taking it out) Private_ClearFriendObjectives(friend) // Remove blips IF DOES_BLIP_EXIST(friend.hPedBlip) REMOVE_BLIP(friend.hPedBlip) ENDIF IF DOES_BLIP_EXIST(friend.hLocBlip) REMOVE_BLIP(friend.hLocBlip) ENDIF // Cleanup phone IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF // Cleanup anims Private_ReleaseFriendPickupAnims(friend) // Cleanup attribs Private_ClearFriendAttribs(friend) // Cleanup model IF (friend.eCarModel <> DUMMY_MODEL_FOR_SCRIPT) SET_MODEL_AS_NO_LONGER_NEEDED(friend.eCarModel) ENDIF IF (friend.ePedModel <> DUMMY_MODEL_FOR_SCRIPT) SET_MODEL_AS_NO_LONGER_NEEDED(friend.ePedModel) ENDIF // Add communication delay IF friend.bWasPickedUp ADD_COMMUNICATION_DELAY_FOR_CHARACTER(friend.eChar) ENDIF // Reset contact timers IF IS_PLAYER_PED_PLAYABLE(friend.eChar) AND (eCleanupStyle = MC_AmbientFlee OR eCleanupStyle = MC_AmbientRejected OR eCleanupStyle = MC_AmbientWander OR bForceTimerDismissed) Private_ResetFriendGroupTimers(friend, FRIEND_CONTACT_DISMISSED) ELSE Private_ResetFriendGroupTimers(friend, FRIEND_CONTACT_FACE) ENDIF // Unblock family scenes Private_EnableFamilyScenes(friend.eChar, TRUE) // Unblock scenarios Private_ClearFriendScenarioBlocking(friend) // Deactive friend connections DEACTIVATE_CHAR_CONNECTIONS(friend.eChar) // Cleanup car (if requested) IF eCleanupStyle = MC_DeletePedAndCar IF DOES_ENTITY_EXIST(friend.hCar) AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(friend.hCar, FALSE) DELETE_VEHICLE(friend.hCar) ENDIF ENDIF // Cleanup ped IF DOES_ENTITY_EXIST(friend.hPed) AND friend.hPed <> PLAYER_PED_ID() // TODO: Store player ped info? IF eCleanupStyle = MC_Delete OR eCleanupStyle = MC_DeletePedAndCar DELETE_PED(friend.hPed) ELIF eCleanupStyle = MC_Release SET_PED_AS_NO_LONGER_NEEDED(friend.hPed) ELIF eCleanupStyle = MC_AmbientFlee SET_PED_AS_AMBIENT_FRIEND_FLEE(friend.hPed, friend.eChar) ELIF eCleanupStyle = MC_AmbientRejected SET_PED_AS_AMBIENT_FRIEND_REJECTED(friend.hPed, friend.eChar, g_eFriendMissionZoneID) ELIF eCleanupStyle = MC_AmbientWander SET_PED_AS_AMBIENT_FRIEND_WANDER(friend.hPed, friend.eChar) ELIF eCleanupStyle = MC_LeavePedIntact // ENDIF ENDIF // Reset vars Private_InitFriend(friend) ENDIF ENDPROC PROC Private_UpdateFriend(structFriend& friend) // Check that switch override hasn't been overwritten // #IF IS_DEBUG_BUILD // IF friend.bSwitchOverride // IF (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] <> PR_SCENE_M_OVERRIDE) // AND (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] <> PR_SCENE_F_OVERRIDE) // AND (g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] <> PR_SCENE_T_OVERRIDE) // TEXT_LABEL tChar = GetLabel_enumCharacterList(friend.eChar) // TEXT_LABEL_63 tScene = Get_String_From_Ped_Request_Scene_Enum(g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar]) // CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriend(", tChar, ") - Switch scene should be overridden but is \"", tScene, "\"") // SCRIPT_ASSERT("Private_UpdateFriend() - switch override is set, but g_ePlayerLastScene is incorrect") // ENDIF // ENDIF // #ENDIF // Exit if null or failed IF friend.eState = FRIEND_NULL OR friend.eState >= FRIEND_CANCEL EXIT ENDIF // Check car for damage BOOL bCarDamaged = FALSE IF DOES_ENTITY_EXIST(friend.hCar) IF NOT IS_ENTITY_DEAD(friend.hCar) INT iCarHealth = GET_ENTITY_HEALTH(friend.hCar) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), friend.hCar) IF iCarHealth < friend.iCarHealth - 50 bCarDamaged = TRUE ENDIF ENDIF friend.iCarHealth = iCarHealth CLEAR_ENTITY_LAST_DAMAGE_ENTITY(friend.hCar) CLEAR_ENTITY_LAST_WEAPON_DAMAGE(friend.hCar) ELSE IF friend.iCarHealth <> -1 bCarDamaged = TRUE ENDIF friend.iCarHealth = -1 ENDIF ENDIF // Clear friend available flag IF IS_PLAYER_PED_PLAYABLE(friend.eChar) CLEAR_BIT(g_bitfieldFriendFlags, ENUM_TO_INT(friend.eChar)) ENDIF // Exit if dead IF DOES_ENTITY_EXIST(friend.hPed) AND IS_PED_INJURED(friend.hPed) CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriend(", GetLabel_enumCharacterList(friend.eChar), ") - Ped is dead") IF friend.bWasPickedUp UPDATE_FRIEND_LIKE(gActivity.mPlayer.eChar, friend.eChar, FriendLike_BUDDY_INJURED) ENDIF IF IS_PLAYER_PED_PLAYABLE(friend.eChar) Private_ClearFriendSwitchOverride(friend) g_SavedGlobals.sPlayerSceneData.g_ePlayerLastScene[friend.eChar] = PR_SCENE_DEAD ENDIF // Make other friends run away (if in group) Private_SetFriendsFleeing(TRUE) Private_SetFriendState(friend, FRIEND_FAIL_INJURED) EXIT ENDIF // Exit if picked friend up, but their ped doesn't exist IF NOT DOES_ENTITY_EXIST(friend.hPed) IF friend.eState = FRIEND_GROUP OR friend.eState = FRIEND_LOST OR friend.eState = FRIEND_TRAPPED #IF IS_DEBUG_BUILD TEXT_LABEL tChar = GetLabel_enumCharacterList(friend.eChar) TEXT_LABEL tState = GetLabel_enumFriendState(friend.eState) CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriend(", tChar, ") state = ", tState, ", ped doesn't exist") SCRIPT_ASSERT("Private_UpdateFriend() state = FRIEND_GROUP/LOST/SHOP, ped doesn't exist") #ENDIF Private_SetFriendState(friend, FRIEND_CANCEL) EXIT ENDIF ENDIF // Check for ped damage IF DOES_ENTITY_EXIST(friend.hPed) AND friend.hPed <> PLAYER_PED_ID() // IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID()) // AND NOT IS_PED_ON_ANY_BIKE(PLAYER_PED_ID()) // AND NOT IS_PED_IN_VEHICLE(friend.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) // IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(friend.hPed, PLAYER_PED_ID(), TRUE) // Private_SetFriendAttacked(friend, TRUE) // ENDIF // ELSE // ENDIF BOOL bAreInVehicleTogether = FALSE IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) VEHICLE_INDEX hPlayerVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(hPlayerVehicle) AND IS_PED_IN_VEHICLE(friend.hPed, hPlayerVehicle) bAreInVehicleTogether = TRUE ENDIF ENDIF IF bAreInVehicleTogether = TRUE friend.bWereInVehicleTogether = TRUE ELSE IF NOT IS_PED_RAGDOLL(PLAYER_PED_ID()) AND NOT IS_PED_RAGDOLL(friend.hPed) AND NOT IS_PED_RUNNING_RAGDOLL_TASK(PLAYER_PED_ID()) AND NOT IS_PED_RUNNING_RAGDOLL_TASK(friend.hPed) friend.bWereInVehicleTogether = FALSE ENDIF ENDIF INT iNewHealth = GET_ENTITY_HEALTH(friend.hPed) // TEXT_LABEL_31 tText = "Hlth:" // tText += iNewHealth // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.1, "STRING", tText) IF friend.bWereInVehicleTogether = FALSE // DISPLAY_TEXT_WITH_LITERAL_STRING(0.1, 0.2, "STRING", "CanDamage") IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(friend.hPed, PLAYER_PED_ID(), TRUE) IF iNewHealth < friend.iHealth - 10 Private_SetFriendAttacked(friend, TRUE) ENDIF ENDIF ENDIF friend.iHealth = iNewHealth ENDIF // Exit if player is third party (delete ped too) IF friend.eState <> FRIEND_TRAPPED IF Private_IsPlayerThirdParty() IF friend.eChar <> GET_CURRENT_PLAYER_PED_ENUM() IF DOES_ENTITY_EXIST(friend.hPed) Private_TryRemoveFriend(friend, TRUE) ENDIF ENDIF EXIT ENDIF ENDIF // Reset wait timer if not at doorstep IF friend.eState = FRIEND_PICKUP IF friend.ePickup = NO_FRIEND_LOCATION OR (DOES_ENTITY_EXIST(friend.hPed) AND Util_IsPedOutsideRange(friend.hPed, friend.vDriveway, CONST_fIsBuddyAtDriveway)) RESTART_TIMER_NOW(friend.mWaitTimer) ENDIF ENDIF // Delay calls from buddy till after mission g_iCharWaitTime[friend.eChar] = GET_GAME_TIMER() + CC_GLOBAL_DELAY_BETWEEN_COMMS // Prevent player/friends attacking each other IF NOT IS_PED_INJURED(friend.hPed) SET_PED_RESET_FLAG(friend.hPed, PRF_DisablePlayerMeleeFriendlyAttacks, TRUE) ENDIF // Debug print if collision is loaded around the friend ped // IF DOES_ENTITY_EXIST(friend.hPed) AND friend.eChar <> GET_CURRENT_PLAYER_PED_ENUM() // TEXT_LABEL_31 tColl // IF friend.eChar = CHAR_MICHAEL tColl = "M-" // ELIF friend.eChar = CHAR_FRANKLIN tColl = "F-" // ELIF friend.eChar = CHAR_TREVOR tColl = "T-" // ENDIF // IF HAS_COLLISION_LOADED_AROUND_ENTITY(friend.hPed) // tColl += "COLL" // ELSE // tColl += "none" // ENDIF // DISPLAY_TEXT_WITH_LITERAL_STRING(0.7, 0.6, "STRING", tColl) //// SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION // // TEXT_LABEL_31 tHeight = "H " // VECTOR vPos = GET_ENTITY_COORDS(friend.hPed, FALSE) // tHeight += ROUND(vPos.z * 1000.0) // DISPLAY_TEXT_WITH_LITERAL_STRING(0.7, 0.7, "STRING", tHeight) // ENDIF //-- For non-player members, manage state... IF friend.eChar <> GET_CURRENT_PLAYER_PED_ENUM() // Pickup ---------------------------------------------------------------------------- IF friend.eState = FRIEND_PICKUP Private_LoadFriendPickupAnims(friend) //--- If not switching: Check state conditions --- IF NOT Private_IsPlayerSwitching() // Fail if late (and ped doesn't exist, and not on phone to cancel) IF (gActivity.bIsRural = FALSE AND TIMER_DO_WHEN_READY(friend.mWaitTimer, CONST_fLateFailInRealMinutes*60.0)) OR (gActivity.bIsRural = TRUE AND TIMER_DO_WHEN_READY(friend.mWaitTimer, CONST_fLateFailInRealMinutes_rural*60.0)) IF NOT DOES_ENTITY_EXIST(friend.hPed) IF NOT friend.bIsBeingCalledToCancel RESET_FRIEND_LAST_CONTACT_TIMER(gActivity.mPlayer.eChar, friend.eChar, FRIEND_CONTACT_PHONE) UPDATE_FRIEND_LIKE(gActivity.mPlayer.eChar, friend.eChar, FriendLike_PLAYER_NO_ARRIVAL) Private_SetFriendState(friend, FRIEND_FAIL_LATE) EXIT ENDIF ENDIF ENDIF // Cancel if calls back IF NOT friend.bIsBeingCalledToCancel IF IS_CALLING_FRIEND_FOR_ACTIVITY_CANCELLATION(friend.eChar) IF DOES_ENTITY_EXIST(friend.hPed) // Calling+ped -> Start answerphone conversation PRIVATE_Friend_DoAnswerPhone(gActivity.convPedsVoicemail, friend.eChar) ELIF PRIVATE_Friend_DoCancelConv(gActivity.convPedsDefault, gActivity.mPlayer.eChar, friend.eChar) // Calling+no ped -> Start cancel conversation friend.bIsBeingCalledToCancel = TRUE EXIT ENDIF ENDIF ELSE IF WAS_LAST_CELLPHONE_CALL_INTERRUPTED() // Call is aborted before answer -> Reset bool friend.bIsBeingCalledToCancel = FALSE EXIT ELIF IS_CELLPHONE_CONVERSATION_PLAYING() // Call connects -> Remove friend RESET_FRIEND_LAST_CONTACT_TIMER(gActivity.mPlayer.eChar, friend.eChar, FRIEND_CONTACT_PHONE) Private_SetFriendState(friend, FRIEND_CANCEL) EXIT ENDIF ENDIF // Pickup if able IF NOT Private_IsPlayerSwitching() IF NOT IS_PED_INJURED(friend.hPed) IF friend.bWasMetAmbiently OR Private_TryPickupFriend(friend) Private_SetFriendPickedUp(friend) Private_SetFriendPickedUp(gActivity.mPlayer) EXIT ELIF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), friend.hPed, <<25.0,25.0,25.0>>) IF (NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR (ABSF(GET_ENTITY_SPEED(PLAYER_PED_ID())) < 10.0)) IF (friend.eChar = CHAR_JIMMY OR friend.eChar = CHAR_AMANDA) IF Private_IsPlayerOrFriendPersued(friend, FALSE) Private_SetFriendFleeing(friend) EXIT ENDIF ELSE IF Private_IsPlayerOrFriendPersued(friend, TRUE) Private_SetFriendPickedUp(friend) Private_SetFriendPickedUp(gActivity.mPlayer) EXIT ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF // Display corona IF Util_IsPedOutsideRange(PLAYER_PED_ID(), friend.vDriveway, 10.0) IS_ENTITY_AT_COORD(PLAYER_PED_ID(), friend.vDriveway, g_vAnyMeansLocate, TRUE) ENDIF //--- If is switching: Freeze ped position --- ELSE IF NOT IS_PED_INJURED(friend.hPed) IF Private_IsSwitchCamDescending() IF IS_PED_IN_ANY_VEHICLE(friend.hPed) FREEZE_ENTITY_POSITION(GET_VEHICLE_PED_IS_IN(friend.hPed), TRUE) ELSE FREEZE_ENTITY_POSITION(friend.hPed, TRUE) ENDIF //CLEAR_PED_TASKS(friend.hPed) ELSE IF IS_PED_IN_ANY_VEHICLE(friend.hPed) FREEZE_ENTITY_POSITION(GET_VEHICLE_PED_IS_IN(friend.hPed), FALSE) ELSE FREEZE_ENTITY_POSITION(friend.hPed, FALSE) ENDIF ENDIF ENDIF CANCEL_TIMER(friend.mArrivalStoppedTimer) // friend.iArrivalDrivingMode = -1 friend.bIsBeingCalledToCancel = FALSE ENDIF //--- Process ped --- IF DOES_ENTITY_EXIST(friend.hPed) IF NOT Private_IsPlayerSwitching() Private_TryRemoveFriend(friend, FALSE, TRUE) ENDIF ELSE IF NOT Private_TryCreateFriend_AtDest(friend, Private_IsSwitchCamDescending()) Private_TryCreateFriend_ArrivingAtDest(friend) ENDIF ENDIF IF NOT IS_PED_INJURED(friend.hPed) Private_FriendArrivalTasks(friend) ENDIF // In group -------------------------------------------------------------------------- ELIF friend.eState = FRIEND_GROUP IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF // Check if buddy is in group... IF Private_ShouldFriendFlee(friend) Private_SetFriendFleeing(friend) ELIF NOT IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) Private_SetFriendState(friend, FRIEND_LOST) ELIF Private_CanFriendEnterPlummet(friend) Private_SetFriendState(friend, FRIEND_PLUMMET) ELIF Private_CanFriendEnterParachute(friend) Private_SetFriendState(friend, FRIEND_PARACHUTE) REMOVE_PED_FROM_GROUP(friend.hPed) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, TRUE) CLEAR_PED_TASKS(friend.hPed) ELSE // Set friend available flag IF IS_PLAYER_PED_PLAYABLE(friend.eChar) SET_BIT(g_bitfieldFriendFlags, ENUM_TO_INT(friend.eChar)) ENDIF // Set can teleport to player SET_PED_CAN_TELEPORT_TO_GROUP_LEADER(friend.hPed, PLAYER_GROUP_ID(), TRUE) // Get out of sinking car IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hCar = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hCar) AND IS_VEHICLE_IN_WATER(hCar) AND NOT IS_VEHICLE_DRIVEABLE(hCar) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) CLEAR_PED_TASKS(friend.hPed) TASK_LEAVE_ANY_VEHICLE(friend.hPed) ENDIF ENDIF ENDIF // Block running (after pickup) IF GET_GAME_TIMER() < friend.iBlockRunningUntilTime IF NOT Private_IsPlayerOrFriendPersued(friend, TRUE) //IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) AND IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), friend.hPed, <<20.0, 20.0, 20.0>>) SET_PED_MAX_MOVE_BLEND_RATIO(friend.hPed, PEDMOVE_WALK) ENDIF ENDIF ENDIF // Head tracking IF IS_ENTITY_AT_ENTITY(friend.hPed, PLAYER_PED_ID(), << 30.0, 30.0, 30.0 >>) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LOOK_AT_ENTITY) IF NOT IS_PED_IN_ANY_VEHICLE(friend.hPed) OR NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), GET_VEHICLE_PED_IS_IN(friend.hPed)) TASK_LOOK_AT_ENTITY(friend.hPed, PLAYER_PED_ID(), 3000) ENDIF ENDIF IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_LOOK_AT_ENTITY) IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR NOT IS_PED_IN_VEHICLE(friend.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), friend.hPed, 3000) ENDIF ENDIF ENDIF // Respond to vehicle damage with dialogue IF bCarDamaged IF IS_PLAYER_PED_PLAYABLE(friend.eChar) IF gActivity.mDialogue.eState != FDIALOGUE_DAMAGE Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_DAMAGE, friend.eChar, FAP_COMMENT_CARDAMAGE) friend.iCarShotTime = GET_GAME_TIMER() + 18000//12000 ENDIF ELSE CPRINTLN(DEBUG_FRIENDS, "Private_UpdateFriend() - Not playing car damage dialogue - only have lines for playable peds") ENDIF ENDIF ENDIF // Lost ------------------------------------------------------------------------------ ELIF friend.eState = FRIEND_LOST IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF IF NOT IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) IF NOT IS_PED_RAGDOLL(friend.hPed) IF IS_BUDDY_GOOD_TO_JOIN_PLAYERS_GROUP(gActivity.locateData, friend.hPed, CONST_fBuddyJoinDist) SET_PED_AS_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) ENDIF ENDIF ENDIF IF Private_ShouldFriendFlee(friend) Private_SetFriendFleeing(friend) ELIF Util_IsPedOutsideRangePed(friend.hPed, PLAYER_PED_ID(), CONST_fBuddyLostDist) Private_SetFriendState(friend, FRIEND_FAIL_LOST) ELIF Private_CanFriendEnterPlummet(friend) Private_SetFriendState(friend, FRIEND_PLUMMET) ELIF Private_CanFriendEnterParachute(friend) Private_SetFriendState(friend, FRIEND_PARACHUTE) REMOVE_PED_FROM_GROUP(friend.hPed) SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(friend.hPed, TRUE) CLEAR_PED_TASKS(friend.hPed) ELIF IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) OR IS_PED_IN_VEHICLE(friend.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) Private_SetFriendState(friend, FRIEND_GROUP) ELSE // Get out of sinking car IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hCar = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hCar) AND IS_VEHICLE_IN_WATER(hCar) AND NOT IS_VEHICLE_DRIVEABLE(hCar) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) CLEAR_PED_TASKS(friend.hPed) TASK_LEAVE_ANY_VEHICLE(friend.hPed) ENDIF ENDIF ENDIF ENDIF ENDIF // Trapped --------------------------------------------------------------------------- ELIF friend.eState = FRIEND_TRAPPED IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF // Get out of sinking car IF IS_PED_IN_ANY_VEHICLE(friend.hPed) VEHICLE_INDEX hCar = GET_VEHICLE_PED_IS_IN(friend.hPed) IF DOES_ENTITY_EXIST(hCar) AND IS_VEHICLE_IN_WATER(hCar) AND NOT IS_VEHICLE_DRIVEABLE(hCar) IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) CLEAR_PED_TASKS(friend.hPed) TASK_LEAVE_ANY_VEHICLE(friend.hPed) ENDIF ENDIF ENDIF // Complaining about being stuck in the car... IF friend.bDoneTrappedDialogue = FALSE TEXT_LABEL tBlock, tRoot IF Private_CanPlayAudio(gActivity.mAudio) AND Private_GetFriendActivityPhrase(GET_CURRENT_PLAYER_PED_ENUM(), friend.eChar, FAP_REJECTION_STUCK, tBlock, tRoot) IF CREATE_CONVERSATION(gActivity.convPedsDefault, tBlock, tRoot, CONV_PRIORITY_AMBIENT_HIGH, DO_NOT_DISPLAY_SUBTITLES) friend.bDoneTrappedDialogue = TRUE ENDIF ENDIF ENDIF // // Keep complaining about being stuck in the car... // IF Private_CanPlayAudio(gActivity.mAudio) // IF Private_CanFriendConverse(friend) // IF TIMER_DO_WHEN_READY(friend.mTrappedTimer, 0.0) // // PLAY_PED_AMBIENT_SPEECH(friend.hPed, "LET_ME_OUT", SPEECH_PARAMS_FORCE_FRONTEND) // RESTART_TIMER_AT(friend.mTrappedTimer, -15.0) // // ENDIF // ENDIF // ENDIF // Plummet ---------------------------------------------------------------------------- ELIF friend.eState = FRIEND_PLUMMET IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF IF Private_CanFriendExitPlummet(friend) CLEAR_PED_TASKS(friend.hPed) IF NOT IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) IF NOT IS_PED_RAGDOLL(friend.hPed) IF IS_BUDDY_GOOD_TO_JOIN_PLAYERS_GROUP(gActivity.locateData, friend.hPed, CONST_fBuddyJoinDist) SET_PED_AS_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) ENDIF ENDIF ENDIF IF IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) Private_SetFriendState(friend, FRIEND_GROUP) ELSE Private_SetFriendState(friend, FRIEND_LOST) ENDIF ELSE IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_PAUSE) CLEAR_PED_TASKS(friend.hPed) TASK_PAUSE(friend.hPed, -1) ENDIF ENDIF // Parachute ------------------------------------------------------------------------- ELIF friend.eState = FRIEND_PARACHUTE IF DOES_ENTITY_EXIST(friend.hPhone) IF IS_ENTITY_ATTACHED_TO_ANY_PED(friend.hPhone) DETACH_ENTITY(friend.hPhone) ENDIF DELETE_OBJECT(friend.hPhone) ENDIF IF Private_CanFriendExitParachute(friend) CLEAR_PED_TASKS(friend.hPed) CLEAR_PED_PARACHUTE_PACK_VARIATION(friend.hPed) IF NOT IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) IF NOT IS_PED_RAGDOLL(friend.hPed) IF IS_BUDDY_GOOD_TO_JOIN_PLAYERS_GROUP(gActivity.locateData, friend.hPed, CONST_fBuddyJoinDist) SET_PED_AS_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) ENDIF ENDIF ENDIF IF IS_PED_GROUP_MEMBER(friend.hPed, PLAYER_GROUP_ID()) Private_SetFriendState(friend, FRIEND_GROUP) ELSE Private_SetFriendState(friend, FRIEND_LOST) ENDIF ELSE IF NOT IsPedPerformingTask(friend.hPed, SCRIPT_TASK_PARACHUTE_TO_TARGET) friend.vParachuteTarget = GET_ENTITY_COORDS(PLAYER_PED_ID()) IF IS_ENTITY_AT_COORD(friend.hPed, friend.vParachuteTarget, <<20.0, 20.0, 20.0>>) friend.vParachuteTarget.z += 40.0 ENDIF CLEAR_PED_TASKS(friend.hPed) TASK_PARACHUTE_TO_TARGET(friend.hPed, friend.vParachuteTarget) friend.iParachuteUpdateTime = GET_GAME_TIMER() + 1000 ELIF friend.iParachuteUpdateTime < GET_GAME_TIMER() OR IS_ENTITY_AT_COORD(friend.hPed, friend.vParachuteTarget, <<20.0, 20.0, 20.0>>) friend.vParachuteTarget = GET_ENTITY_COORDS(PLAYER_PED_ID()) IF IS_ENTITY_AT_COORD(friend.hPed, friend.vParachuteTarget, <<20.0, 20.0, 20.0>>) friend.vParachuteTarget.z += 40.0 ENDIF SET_PARACHUTE_TASK_TARGET(friend.hPed, friend.vParachuteTarget) friend.iParachuteUpdateTime = GET_GAME_TIMER() + 1000 ENDIF IF GET_PED_PARACHUTE_STATE(friend.hPed) = PPS_SKYDIVING FORCE_PED_TO_OPEN_PARACHUTE(friend.hPed) ENDIF ENDIF ENDIF ENDIF ENDPROC PROC Private_RemoveFailedFriend(structFriend& friend) IF friend.eState = FRIEND_FAIL_INJURED enumFriend eFriend eFriend = GET_FRIEND_FROM_CHAR(friend.eChar) START_FRIEND_FAIL_TIMER(eFriend, GET_COMM_ID_FOR_FRIEND_FAIL(eFriend)) Private_QueueFailReason(friend.eChar, FFR_Injured, Private_GetHospitalChargeCID(friend.hPed)) Private_CleanupFriend(friend, MC_Release) ELIF friend.eState = FRIEND_FAIL_LATE Private_QueueFailReason(friend.eChar, FFR_Late) Private_CleanupFriend(friend, MC_Delete) ELIF friend.eState = FRIEND_FAIL_LOST Private_QueueFailReason(friend.eChar, FFR_Lost) Private_CleanupFriend(friend, MC_Delete) ELIF friend.eState = FRIEND_FAIL_REJECTED Private_CleanupFriend(friend, MC_AmbientRejected) ELIF friend.eState = FRIEND_FAIL_FLEE Private_QueueFailReason(friend.eChar, FFR_Flee) Private_CleanupFriend(friend, MC_AmbientFlee) ELIF friend.eState = FRIEND_FAIL_ATTACKED Private_QueueFailReason(friend.eChar, FFR_Attacked) Private_CleanupFriend(friend, MC_AmbientFlee) ELIF friend.eState = FRIEND_FAIL_WANDER Private_CleanupFriend(friend, MC_AmbientWander) ELIF friend.eState = FRIEND_CANCEL // Private_QueueFailReason(friend.eChar, FFR_Cancel) Private_CleanupFriend(friend, MC_AmbientWander) ELSE Private_CleanupFriend(friend, MC_AmbientWander) ENDIF ENDPROC