2868 lines
100 KiB
Scheme
Executable File
2868 lines
100 KiB
Scheme
Executable File
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
//
|
|
// 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 = <<fHalfSize, fHalfSize, fHalfSize>>
|
|
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, ") <NO_FRIEND_LOCATION>")
|
|
#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, <<fMaxDist, fMaxDist, fMaxDist>>)
|
|
// 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, <<fMaxDist, fMaxDist, fMaxDist>>)
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_IsFriendCarUsableForArrival(", GetLabel_enumCharacterList(friend.eChar), ") - NOT IS_ENTITY_AT_ENTITY(friend.hPed, friend.hCar, <<fMaxDist, fMaxDist, fMaxDist>>)")
|
|
// 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, <<CONST_fFriendConverseRadius, CONST_fFriendConverseRadius, CONST_fFriendConverseRadius>>)
|
|
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
|
|
|