2872 lines
98 KiB
Scheme
Executable File
2872 lines
98 KiB
Scheme
Executable File
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
//
|
|
// MISSION NAME : friendActivity_memberSoldier_private.sch
|
|
// AUTHOR : Sam Hackett
|
|
// DESCRIPTION : State machine for individual battle buddies
|
|
//
|
|
// *****************************************************************************************
|
|
// *****************************************************************************************
|
|
|
|
//- commands headers -//
|
|
|
|
//- script headers -//
|
|
|
|
//- public headers -//
|
|
USING "ambient_common.sch"
|
|
|
|
//- private headers -//
|
|
USING "friendActivity_private.sch"
|
|
USING "battlebuddy_private.sch"
|
|
USING "RC_Helper_Functions.sch"
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
//- debug headers -//
|
|
#ENDIF
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
// CONSTANTS
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
CONST_FLOAT CONST_fSoldierExtraMaxHealth 400.0
|
|
CONST_FLOAT CONST_fSoldierStandardMaxHealth 200.0
|
|
CONST_FLOAT CONST_fSoldierRejectTime 300.0//60.0//120.0//60.0*2.0
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
// DEBUG
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
FUNC STRING GetLabel_enumSoldierState(enumSoldierState eState)
|
|
SWITCH eState
|
|
CASE SOLDIER_NULL RETURN "SOLDIER_NULL" BREAK
|
|
|
|
CASE SOLDIER_CREATE_IN_CAR RETURN "SOLDIER_CREATE_IN_CAR" BREAK
|
|
CASE SOLDIER_CREATE_ON_FOOT RETURN "SOLDIER_CREATE_ON_FOOT" BREAK
|
|
CASE SOLDIER_ARRIVE_IN_CAR RETURN "SOLDIER_ARRIVE_IN_CAR" BREAK
|
|
|
|
CASE SOLDIER_APPROACH RETURN "SOLDIER_APPROACH" BREAK
|
|
CASE SOLDIER_FOLLOW RETURN "SOLDIER_FOLLOW" BREAK
|
|
CASE SOLDIER_GROUP RETURN "SOLDIER_GROUP" BREAK
|
|
CASE SOLDIER_COMBAT RETURN "SOLDIER_COMBAT" BREAK
|
|
CASE SOLDIER_PARACHUTE RETURN "SOLDIER_PARACHUTE" BREAK
|
|
CASE SOLDIER_PASSENGER RETURN "SOLDIER_PASSENGER" BREAK
|
|
CASE SOLDIER_PLAYER RETURN "SOLDIER_PLAYER" BREAK
|
|
CASE SOLDIER_OVERRIDDEN RETURN "SOLDIER_OVERRIDDEN" BREAK
|
|
CASE SOLDIER_ARREST RETURN "SOLDIER_ARREST" BREAK
|
|
|
|
CASE SOLDIER_FAIL_INJURED RETURN "SOLDIER_FAIL_INJURED" BREAK
|
|
CASE SOLDIER_FAIL_LOST RETURN "SOLDIER_FAIL_LOST" BREAK
|
|
ENDSWITCH
|
|
|
|
SCRIPT_ASSERT("GetLabel_enumSoldierState() - Unknown state")
|
|
RETURN "<unknown state>"
|
|
ENDFUNC
|
|
|
|
PROC DEBUG_DisplaySquadMemberInfo(structSoldier& soldier)
|
|
IF IS_PLAYER_PED_PLAYABLE(soldier.eChar)
|
|
|
|
// Get line to print on
|
|
INT iRow = 4 + ENUM_TO_INT(soldier.eChar)//CONST_iActivityDebugPrintLineTop + ENUM_TO_INT(soldier.eChar)
|
|
|
|
// Build string
|
|
TEXT_LABEL_63 tName = GetLabel_enumFriend(GET_FRIEND_FROM_CHAR(soldier.eChar))
|
|
tName += ": "
|
|
tName += GetLabel_enumSoldierState(soldier.eState)
|
|
IF soldier.bInitState
|
|
tName += "*"
|
|
ENDIF
|
|
|
|
tName += " ["
|
|
IF DOES_ENTITY_EXIST(GET_BATTLEBUDDY_PED(soldier.eChar))
|
|
tName += "e"
|
|
ENDIF
|
|
IF IS_BIT_SET(g_bitfieldBattleBuddyOverridden, ENUM_TO_INT(soldier.eChar))
|
|
tName += "O"
|
|
ENDIF
|
|
IF IS_BIT_SET(g_bitfieldBattleBuddyAvailable, ENUM_TO_INT(soldier.eChar))
|
|
tName += "A"
|
|
// IF IS_TIMER_STARTED(soldier.mAvailableTimer)
|
|
// tName += FLOOR(GET_TIMER_IN_SECONDS(soldier.mAvailableTimer)) / 60
|
|
// ENDIF
|
|
ENDIF
|
|
IF HAS_FRIEND_FAILED(soldier.eChar)
|
|
tName += "F"
|
|
ENDIF
|
|
tName += "]"
|
|
|
|
IF NOT IS_PED_INJURED(soldier.hPed)
|
|
tName += " "
|
|
tName += (GET_ENTITY_HEALTH(soldier.hPed) * 100) / GET_ENTITY_MAX_HEALTH(soldier.hPed)
|
|
tName += "%"
|
|
ENDIF
|
|
|
|
|
|
DrawFriendLiteralString(tName, iRow, HUD_COLOUR_BLUELIGHT)
|
|
|
|
ENDIF
|
|
ENDPROC
|
|
#ENDIF
|
|
|
|
|
|
FUNC BOOL Private_CheckBehaviourFlag(enumBattleBuddyBehaviourFlag eFlag)
|
|
RETURN IS_BIT_SET(g_bitfieldBattleBuddyBehaviour, ENUM_TO_INT(eFlag))
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
// CREATION/DELETION/SETSTATE
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
PROC Private_InitSoldier(structSoldier& soldier, enumCharacterList eChar)
|
|
|
|
soldier.eChar = eChar
|
|
soldier.eState = SOLDIER_NULL
|
|
soldier.bInitState = FALSE
|
|
|
|
soldier.hPed = NULL
|
|
soldier.hBlip = NULL
|
|
soldier.hVehicle = NULL
|
|
soldier.eCreateInVehicleType = VEHICLE_TYPE_CAR
|
|
|
|
CANCEL_TIMER(soldier.mAvailableTimer)
|
|
|
|
soldier.hArrivalNode = NULL
|
|
soldier.iArrivalStage = 0
|
|
soldier.iArrivalStoppedTimer = 0
|
|
soldier.iArrivalHornTimer = 0
|
|
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
soldier.eCurrentBlip = SOLDIER_BLIP_OFF
|
|
|
|
soldier.bWasInCombat = FALSE
|
|
soldier.iShoutTimer = 0
|
|
|
|
soldier.bIsInParkingRange = FALSE
|
|
soldier.eCharToDriveTo = NO_CHARACTER
|
|
soldier.iCombatDelay = 0
|
|
soldier.iStealthDelay = 0
|
|
soldier.bDefendingCargobobArea = FALSE
|
|
|
|
ENDPROC
|
|
|
|
|
|
FUNC BOOL Private_IsSoldierGlobalFlagSet(structSoldier& soldier, INT iGlobalBitfield)
|
|
RETURN IS_BIT_SET(iGlobalBitfield, ENUM_TO_INT(soldier.eChar))
|
|
ENDFUNC
|
|
|
|
PROC Private_SetSoldierGlobalFlag(structSoldier& soldier, INT& iGlobalBitfield)
|
|
SET_BIT(iGlobalBitfield, ENUM_TO_INT(soldier.eChar))
|
|
ENDPROC
|
|
|
|
PROC Private_ClearSoldierGlobalFlag(structSoldier& soldier, INT& iGlobalBitfield)
|
|
CLEAR_BIT(iGlobalBitfield, ENUM_TO_INT(soldier.eChar))
|
|
ENDPROC
|
|
|
|
|
|
PROC Private_SetSoldierAvailable(structSoldier& soldier)
|
|
|
|
INT iIndex = ENUM_TO_INT(soldier.eChar)
|
|
IF NOT IS_BIT_SET(g_bitfieldBattleBuddyAvailable, iIndex)
|
|
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_SetSoldierAvailable(", GetLabel_enumCharacterList(soldier.eChar), ")")
|
|
SET_BIT(g_bitfieldBattleBuddyAvailable, iIndex)
|
|
RESTART_TIMER_NOW(soldier.mAvailableTimer)
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC Private_ClearSoldierAvailable(structSoldier& soldier)
|
|
|
|
INT iIndex = ENUM_TO_INT(soldier.eChar)
|
|
IF IS_BIT_SET(g_bitfieldBattleBuddyAvailable, iIndex)
|
|
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_ClearSoldierAvailable(", GetLabel_enumCharacterList(soldier.eChar), ")")
|
|
CLEAR_BIT(g_bitfieldBattleBuddyAvailable, iIndex)
|
|
|
|
// Reset timers with other available soldiers
|
|
enumCharacterList eLoopChar
|
|
REPEAT MAX_BATTLE_BUDDIES eLoopChar
|
|
IF soldier.eChar <> eLoopChar
|
|
AND Private_IsSoldierGlobalFlagSet(gActivity.mSoldiers[eLoopChar], g_bitfieldBattleBuddyAvailable)
|
|
RESET_FRIEND_LAST_CONTACT_TIMER(soldier.eChar, eLoopChar, FRIEND_CONTACT_FACE)
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
FUNC BOOL Private_SyncSoldierPed(structSoldier& soldier)
|
|
|
|
// Get the selector ped
|
|
soldier.hPed = g_sPlayerPedRequest.sSelectorPeds.pedID[GET_SELECTOR_SLOT_FROM_PLAYER_PED_ENUM(soldier.eChar)]
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
SET_ENTITY_AS_MISSION_ENTITY(soldier.hPed, TRUE, TRUE)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
PROC Private_SwitchOnRoadsAroundMilitaryBase(BOOL bEnable)
|
|
|
|
VECTOR vPos1[TOTAL_SUB_AREAS], vPos2[TOTAL_SUB_AREAS]
|
|
FLOAT fWidth[TOTAL_SUB_AREAS]
|
|
INT iUpperZ = 0
|
|
|
|
vPos1[0] = <<-1600.287598,2806.558838,16.444683>> // Lower ramp, z is fine
|
|
vPos2[0] = <<-1665.018066,2881.735352,37.717834>>
|
|
fWidth[0] = 51.250000
|
|
vPos1[1] = <<-1776.896606,2879.143555,30>>
|
|
vPos2[1] = <<-2344.001953,3201.897705,250 + iUpperZ>>
|
|
fWidth[1] = 260.000000
|
|
vPos1[2] = <<-2112.905029,2869.362549,30>>
|
|
vPos2[2] = <<-2794.882568,3266.906250,250 + iUpperZ>>
|
|
fWidth[2] = 88.500000
|
|
vPos1[3] = <<-2028.532593,3305.804932,30>>
|
|
vPos2[3] = <<-1715.586060,3126.489258,250 + iUpperZ>>
|
|
fWidth[3] = 234.500000
|
|
vPos1[4] = <<-2376.502441,3144.741455,30>>
|
|
vPos2[4] = <<-2736.747803,3344.206299,250 + iUpperZ>>
|
|
fWidth[4] = 123.000000
|
|
vPos1[5] = <<-2049.336914,3264.578613,30>>
|
|
vPos2[5] = <<-2162.414307,3328.668457,250 + iUpperZ>>
|
|
fWidth[5] = 139.750000
|
|
vPos1[6] = <<-2317.464600,3377.807617,30>>
|
|
vPos2[6] = <<-2419.537354,3208.734131,250 + iUpperZ>>
|
|
fWidth[6] = 133.250000
|
|
vPos1[7] = <<-2207.642334,3389.073486,30>>
|
|
vPos2[7] = <<-2208.911377,3269.166748,250 + iUpperZ>>
|
|
fWidth[7] = 160.250000
|
|
vPos1[8] = <<-2545.383301,3270.769531,30>>
|
|
vPos2[8] = <<-2362.583984,3377.416016,250 + iUpperZ>>
|
|
fWidth[8] = 97.500000
|
|
vPos1[9] = <<-2500.651123,2908.789795,30>>
|
|
vPos2[9] = <<-2440.603271,3010.204834,250 + iUpperZ>>
|
|
fWidth[9] = 144.750000
|
|
vPos1[10] = <<-2139.515625,2787.671631,30>>
|
|
vPos2[10] = <<-1984.539063,2877.048340,250 + iUpperZ>>
|
|
fWidth[10] = 69.250000
|
|
vPos1[11] = <<-1823.778687,2795.451660,30>>
|
|
vPos2[11] = <<-2015.374390,2842.778320,250 + iUpperZ>>
|
|
fWidth[11] = 68.000000
|
|
vPos1[12] = <<-1752.250122,2806.126953,30>>
|
|
vPos2[12] = <<-1760.667969,3169.826172,250 + iUpperZ>>
|
|
fWidth[12] = 111.500000
|
|
vPos1[13] = <<-1676.144531,2843.249512,30>>
|
|
vPos2[13] = <<-1734.778687,3170.531250,250 + iUpperZ>>
|
|
fWidth[13] = 89.750000
|
|
vPos1[14] = <<-1963.187134,3375.750488,30>>
|
|
vPos2[14] = <<-2039.847290,3310.039551,250 + iUpperZ>>
|
|
fWidth[14] = 41.500000
|
|
|
|
IF bEnable
|
|
// Set wider area on
|
|
SET_ROADS_IN_ANGLED_AREA(<<-1218.494141, 2596.197998, 69.801003>>, <<-3017.008789, 3552.707275, 0.363300>>, 825.0, FALSE, TRUE)
|
|
|
|
// Set military base off
|
|
INT i
|
|
REPEAT TOTAL_SUB_AREAS i
|
|
SET_ROADS_IN_ANGLED_AREA(vPos1[i], vPos2[i], fWidth[i], FALSE, FALSE)
|
|
ENDREPEAT
|
|
ELSE
|
|
// Revert military base
|
|
INT iBackwards = TOTAL_SUB_AREAS
|
|
INT i
|
|
REPEAT TOTAL_SUB_AREAS i
|
|
iBackwards--
|
|
SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(vPos1[iBackwards], vPos2[iBackwards], fWidth[iBackwards])
|
|
ENDREPEAT
|
|
|
|
// Revert wider area
|
|
SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(<<-1218.494141, 2596.197998, 69.801003>>, <<-3017.008789, 3552.707275, 0.363300>>, 825.0)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC VEHICLE_NODE_ID Private_GetUnusedRoadNode(VECTOR vSourcePos, VECTOR& vPos, NODE_FLAGS flags)
|
|
|
|
//-- Get nearest node
|
|
INT n = 1
|
|
VEHICLE_NODE_ID hNode = GET_NTH_CLOSEST_VEHICLE_NODE_ID(vSourcePos, n, flags)
|
|
|
|
WHILE IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
|
|
// If already used for arrival, get next closest
|
|
enumCharacterList eChar
|
|
REPEAT MAX_BATTLE_BUDDIES eChar
|
|
IF hNode <> NULL AND gActivity.mSoldiers[eChar].hArrivalNode = hNode
|
|
hNode = NULL
|
|
n++
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
IF hNode = NULL
|
|
hNode = GET_NTH_CLOSEST_VEHICLE_NODE_ID(vSourcePos, n, flags)
|
|
ELSE
|
|
GET_VEHICLE_NODE_POSITION(hNode, vPos)
|
|
RETURN hNode
|
|
ENDIF
|
|
|
|
ENDWHILE
|
|
|
|
RETURN NULL
|
|
|
|
ENDFUNC
|
|
|
|
FUNC VEHICLE_NODE_ID Private_GetNearestDestNode(VECTOR vPlayerPos, VECTOR& vNodePos)
|
|
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Player pos = << ", vPlayerPos.x, ", ", vPlayerPos.y, ", ", vPlayerPos.z, " >>")
|
|
|
|
// BOOL bNeedNonMilitaryNode = FALSE
|
|
// VEHICLE_NODE_ID hNode
|
|
//
|
|
// //-- Try nearest on-node
|
|
// hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES)
|
|
//
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hNode) AND GET_DISTANCE_BETWEEN_COORDS(vPlayerPos, vNodePos) < 50.0
|
|
// IF IS_COORD_IN_SPECIFIED_AREA(vNodePos, AC_MILITARY_BASE) AND NOT IS_COORD_IN_SPECIFIED_AREA(vPlayerPos, AC_MILITARY_BASE)
|
|
// bNeedNonMilitaryNode = TRUE
|
|
// ELSE
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest switched-on-node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
// RETURN hNode
|
|
// ENDIF
|
|
// ENDIF
|
|
//
|
|
// // Get nearest any-node
|
|
// IF bNeedNonMilitaryNode = FALSE
|
|
// hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES|NF_INCLUDE_SWITCHED_OFF_NODES)
|
|
//
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
// IF IS_COORD_IN_SPECIFIED_AREA(vNodePos, AC_MILITARY_BASE) AND NOT IS_COORD_IN_SPECIFIED_AREA(vPlayerPos, AC_MILITARY_BASE)
|
|
// bNeedNonMilitaryNode = TRUE
|
|
// ELSE
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest any-state-node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
// RETURN hNode
|
|
// ENDIF
|
|
// ENDIF
|
|
// ENDIF
|
|
//
|
|
// // Get nearest non-military node
|
|
// IF bNeedNonMilitaryNode
|
|
// Private_SwitchOnRoadsAroundMilitaryBase(TRUE)
|
|
// hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES)
|
|
// Private_SwitchOnRoadsAroundMilitaryBase(FALSE)
|
|
//
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest non-military node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
// RETURN hNode
|
|
// ENDIF
|
|
// ENDIF
|
|
//
|
|
// // Couldn't find node, use player pos
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - couldn't get road node, using player pos")
|
|
// vNodePos = vPlayerPos
|
|
// RETURN NULL
|
|
|
|
VEHICLE_NODE_ID hNode
|
|
|
|
//-- Try nearest on-node
|
|
BOOL bForceSwitchedOnNode = Private_CheckBehaviourFlag(BBF_ArriveOnSwitchOnNodesOnly)
|
|
hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES)
|
|
|
|
IF IS_VEHICLE_NODE_ID_VALID(hNode) AND (GET_DISTANCE_BETWEEN_COORDS(vPlayerPos, vNodePos) < 50.0 OR bForceSwitchedOnNode)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest switched-on-node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
RETURN hNode
|
|
ENDIF
|
|
|
|
// Get nearest any-node
|
|
IF bForceSwitchedOnNode = FALSE
|
|
hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES|NF_INCLUDE_SWITCHED_OFF_NODES)
|
|
|
|
IF IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest any-state-node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
RETURN hNode
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Couldn't find node, use player pos
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - couldn't get road node, using player pos")
|
|
vNodePos = vPlayerPos
|
|
RETURN NULL
|
|
|
|
ENDFUNC
|
|
|
|
//FUNC VEHICLE_NODE_ID Private_GetNearestDestNode(VECTOR vPlayerPos, VECTOR& vParkPos)
|
|
//
|
|
// // Get nearest node
|
|
// VECTOR vNodePos
|
|
// VEHICLE_NODE_ID hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES|NF_INCLUDE_SWITCHED_OFF_NODES)
|
|
//
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
//
|
|
// // If in military base but player isn't, Force non-military node
|
|
// IF IS_COORD_IN_SPECIFIED_AREA(vNodePos, AC_MILITARY_BASE) AND NOT IS_COORD_IN_SPECIFIED_AREA(vPlayerPos, AC_MILITARY_BASE)
|
|
// Private_SwitchOnRoadsAroundMilitaryBase(TRUE)
|
|
// hNode = Private_GetUnusedRoadNode(vPlayerPos, vNodePos, NF_IGNORE_SLIPLANES)
|
|
// Private_SwitchOnRoadsAroundMilitaryBase(FALSE)
|
|
//
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hNode)
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest non-military node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
// vParkPos = Private_GetRoadside(vPlayerPos, vNodePos)
|
|
// RETURN hNode
|
|
// ENDIF
|
|
//
|
|
// // Otherwise, Try and get switched on node
|
|
// ELSE
|
|
// VECTOR vOnNodePos
|
|
// VEHICLE_NODE_ID hOnNode = Private_GetUnusedRoadNode(vPlayerPos, vOnNodePos, NF_IGNORE_SLIPLANES)
|
|
//
|
|
// // If on-node usable?
|
|
// IF IS_VEHICLE_NODE_ID_VALID(hOnNode) AND GET_DISTANCE_BETWEEN_COORDS(vPlayerPos, vOnNodePos) < 50.0
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest switched-on-node = << ", vOnNodePos.x, ", ", vOnNodePos.y, ", ", vOnNodePos.z, " >>")
|
|
// vParkPos = Private_GetRoadside(vPlayerPos, vOnNodePos)
|
|
// RETURN hNode
|
|
//
|
|
// // Otherwise, use original closest node
|
|
// ELSE
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - Using nearest any-state-node = << ", vNodePos.x, ", ", vNodePos.y, ", ", vNodePos.z, " >>")
|
|
// vParkPos = Private_GetRoadside(vPlayerPos, vNodePos)
|
|
// RETURN hNode
|
|
// ENDIF
|
|
// ENDIF
|
|
//
|
|
// ENDIF
|
|
//
|
|
// CPRINTLN(DEBUG_FRIENDS, "Private_GetNearestDestNode() - couldn't get road node, using player pos")
|
|
// vParkPos = vPlayerPos
|
|
// RETURN NULL
|
|
//
|
|
//ENDFUNC
|
|
|
|
FUNC VECTOR Private_GetNodeParkingPos(VECTOR vPlayerPos, VECTOR vNodePos)
|
|
|
|
BOOL bGotSideA, bGotSideB
|
|
VECTOR vSideA, vSideB
|
|
bGotSideA = GET_POSITION_BY_SIDE_OF_ROAD(vNodePos, 0, vSideA)
|
|
bGotSideB = GET_POSITION_BY_SIDE_OF_ROAD(vNodePos, 1, vSideB)
|
|
|
|
IF bGotSideA
|
|
vSideA += NORMALISE_VECTOR(vNodePos - vSideA) * 3.5
|
|
ENDIF
|
|
IF bGotSideB
|
|
vSideB += NORMALISE_VECTOR(vNodePos - vSideB) * 3.5
|
|
ENDIF
|
|
|
|
IF bGotSideA AND bGotSideB
|
|
IF VDIST2(vPlayerPos, vSideA) < VDIST2(vPlayerPos, vSideB)
|
|
RETURN vSideA
|
|
ELSE
|
|
RETURN vSideB
|
|
ENDIF
|
|
|
|
ELIF bGotSideA
|
|
RETURN vSideA
|
|
|
|
ELIF bGotSideB
|
|
RETURN vSideB
|
|
|
|
ELSE
|
|
RETURN vNodePos
|
|
ENDIF
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CreateSoldierInVehicle(structSoldier& soldier)
|
|
|
|
// Load required models
|
|
PED_VEH_DATA_STRUCT sVehData
|
|
GET_PLAYER_VEH_DATA(soldier.eChar, sVehData, soldier.eCreateInVehicleType)
|
|
|
|
MODEL_NAMES pedModel = GET_PLAYER_PED_MODEL(soldier.eChar)
|
|
MODEL_NAMES vehModel = sVehData.model
|
|
|
|
IF vehModel = DUMMY_MODEL_FOR_SCRIPT
|
|
vehModel = ASEA
|
|
ENDIF
|
|
|
|
REQUEST_MODEL(pedModel)
|
|
REQUEST_MODEL(vehModel)
|
|
|
|
IF HAS_MODEL_LOADED(vehModel)
|
|
AND HAS_MODEL_LOADED(pedModel)
|
|
|
|
// Find car spawn pos
|
|
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
BOOL bSpawnOnSwitchedOffNodes = Private_CheckBehaviourFlag(BBF_SpawnOnSwitchedOffNodes)
|
|
|
|
IF bSpawnOnSwitchedOffNodes
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Attempting to spawn soldier in vehicle, allow switched off nodes")
|
|
ELSE
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Attempting to spawn soldier in vehicle, disallow switched off nodes")
|
|
ENDIF
|
|
|
|
VECTOR vResultPos
|
|
VECTOR vDummyLinkDir
|
|
IF GENERATE_VEHICLE_CREATION_POS_FROM_PATHS(vPlayerPos, vResultPos, vDummyLinkDir, 0, 180, CONST_fBattleBuddyMinCreateDist, bSpawnOnSwitchedOffNodes, TRUE, TRUE)
|
|
|
|
// Result should be in/out of military base if player is
|
|
IF Private_CheckBehaviourFlag(BBF_SpawnCheckMilitaryBase)
|
|
// If it is on wrong side, search again from the arrival-dest node pos
|
|
BOOL bIsPlayerInBase = IS_COORD_IN_SPECIFIED_AREA(vPlayerPos, AC_MILITARY_BASE)
|
|
|
|
IF bIsPlayerInBase <> IS_COORD_IN_SPECIFIED_AREA(vResultPos, AC_MILITARY_BASE)
|
|
IF NOT GENERATE_VEHICLE_CREATION_POS_FROM_PATHS(soldier.vArrivalPos, vResultPos, vDummyLinkDir, 0, 180, CONST_fBattleBuddyMinCreateDist, bSpawnOnSwitchedOffNodes, TRUE, TRUE)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting emergency position, couldn't find one")
|
|
RETURN FALSE
|
|
ELIF VDIST2(vPlayerPos, vResultPos) < CONST_fBattleBuddyMinCreateDist*CONST_fBattleBuddyMinCreateDist
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting emergency position, too close to player")
|
|
RETURN FALSE
|
|
ELIF bIsPlayerInBase <> IS_COORD_IN_SPECIFIED_AREA(vResultPos, AC_MILITARY_BASE)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting emergency position, doesn't match player's in-military-base status either")
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Result shouldn't be at sea end of docks
|
|
IF Private_CheckBehaviourFlag(BBF_SpawnCheckDocks)
|
|
IF soldier.iCreateAttempts < 60
|
|
IF Private_IsPointInArea2D(vResultPos, <</*1074.0*//*981.58*/890.0, -3365.0, 0.0>>, <<1312.0, -2888.0, 0.0>>)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting position, too close to sea end of docks")
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Result should be occluded
|
|
IF soldier.iCreateAttempts < 30
|
|
IF NOT WOULD_ENTITY_BE_OCCLUDED(vehModel, vResultPos)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting position, wouldn't be occluded")
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Result should not intersect with another car
|
|
CLEAR_AREA_OF_VEHICLES(vResultPos, 10.0)
|
|
VECTOR vAreaMin = vResultPos - <<3,3,3>>
|
|
VECTOR vAreaMax = vResultPos + <<3,3,3>>
|
|
IF IS_AREA_OCCUPIED(vAreaMin, vAreaMax, FALSE, TRUE, FALSE, FALSE, FALSE)
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Rejecting position, another car is in the area")
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
|
|
// Accept position
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - Accepting position <<",vResultPos.x,", ",vResultPos.y,", ",vResultPos.z, ">> on ", soldier.iCreateAttempts, " attempts")
|
|
|
|
// Get the node heading
|
|
VECTOR vSpawnPos
|
|
FLOAT fSpawnHeading
|
|
INT iDummyLanes
|
|
GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(vResultPos, 1, vSpawnPos, fSpawnHeading, iDummyLanes)
|
|
vSpawnPos = vResultPos
|
|
|
|
// Create car and ped
|
|
IF NOT DOES_ENTITY_EXIST(soldier.hVehicle)
|
|
IF CREATE_PLAYER_VEHICLE(soldier.hVehicle, soldier.eChar, vSpawnPos, fSpawnHeading, TRUE, soldier.eCreateInVehicleType)
|
|
IF DOT_PRODUCT_XY(GET_ENTITY_FORWARD_VECTOR(soldier.hVehicle), vSpawnPos-vPlayerPos) > 0.0
|
|
SET_ENTITY_HEADING(soldier.hVehicle, fSpawnHeading+180.0)
|
|
ENDIF
|
|
SET_VEHICLE_HAS_STRONG_AXLES(soldier.hVehicle, TRUE)
|
|
// SET_ENTITY_SHOULD_FREEZE_WAITING_ON_COLLISION(soldier.hVehicle, TRUE) // Can't use this, doesn't work if player's in an interior and driving under a freeway counts as an interior in some places.
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(soldier.hVehicle, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
IF DOES_ENTITY_EXIST(soldier.hVehicle)
|
|
IF CREATE_PLAYER_PED_INSIDE_VEHICLE(soldier.hPed, soldier.eChar, soldier.hVehicle, VS_DRIVER, TRUE)
|
|
IF NOT HAS_PED_GOT_WEAPON(soldier.hPed, WEAPONTYPE_PISTOL)
|
|
GIVE_WEAPON_TO_PED(soldier.hPed, WEAPONTYPE_PISTOL, GET_WEAPON_CLIP_SIZE(WEAPONTYPE_PISTOL)*GET_RANDOM_INT_IN_RANGE(6, 10))
|
|
STORE_PLAYER_PED_WEAPONS(soldier.hPed)
|
|
ENDIF
|
|
soldier.bRequestGreetingDialogue = TRUE
|
|
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ELSE
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_CreateSoldierInVehicle(", GetLabel_enumCharacterList(soldier.eChar), ") - GENERATE_VEHICLE_CREATION_POS_FROM_PATHS returned false")
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CreateSoldierOnFoot(structSoldier& soldier)
|
|
|
|
// Load required models
|
|
MODEL_NAMES pedModel = GET_PLAYER_PED_MODEL(soldier.eChar)
|
|
|
|
REQUEST_MODEL(pedModel)
|
|
IF HAS_MODEL_LOADED(pedModel)
|
|
|
|
// Find ped spawn pos
|
|
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
VECTOR vSafePos
|
|
|
|
IF GET_SAFE_COORD_FOR_PED(vPlayerPos, FALSE, vSafePos)
|
|
|
|
IF VDIST(vPlayerPos, vSafePos) < CONST_fBattleBuddyMaxOnFootCreateDist
|
|
|
|
// Create car and ped
|
|
IF CREATE_PLAYER_PED_ON_FOOT(soldier.hPed, soldier.eChar, vSafePos, 0)
|
|
IF NOT HAS_PED_GOT_WEAPON(soldier.hPed, WEAPONTYPE_PISTOL)
|
|
GIVE_WEAPON_TO_PED(soldier.hPed, WEAPONTYPE_PISTOL, GET_WEAPON_CLIP_SIZE(WEAPONTYPE_PISTOL)*GET_RANDOM_INT_IN_RANGE(6, 10))
|
|
STORE_PLAYER_PED_WEAPONS(soldier.hPed)
|
|
ENDIF
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
soldier.hVehicle = NULL
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
PROC Private_SetSoldierState(structSoldier& soldier, enumSoldierState eState)
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(soldier.eChar)
|
|
TEXT_LABEL_63 tState = GetLabel_enumSoldierState(eState)
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Private_SetSoldierState(", tChar, ", ", tState, ")")
|
|
#ENDIF
|
|
|
|
soldier.eState = eState
|
|
soldier.bInitState = TRUE
|
|
|
|
ENDPROC
|
|
|
|
|
|
PROC Private_SetSoldierInitialWeapons(structSoldier& soldier)
|
|
|
|
WEAPON_TYPE eBestWeapon = GET_BEST_PED_WEAPON(soldier.hPed)
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
TEXT_LABEL tChar = GetLabel_enumCharacterList(soldier.eChar)
|
|
TEXT_LABEL tWeapon = GET_WEAPON_NAME(eBestWeapon)
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Setting ", tChar, " to best weapon: ", tWeapon)
|
|
#ENDIF
|
|
|
|
SET_PED_INFINITE_AMMO(soldier.hPed, TRUE)
|
|
SET_CURRENT_PED_WEAPON(soldier.hPed, eBestWeapon, TRUE)
|
|
|
|
ENDPROC
|
|
|
|
|
|
PROC Private_SetSoldierAttribs(structSoldier& soldier)
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
SET_GROUP_SEPARATION_RANGE(PLAYER_GROUP_ID(), CONST_fBattleBuddyLostDist)
|
|
// SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LINE_ABREAST) //FORMATION_LOOSE)
|
|
|
|
IF Private_CheckBehaviourFlag(BBF_CombatGroupSpacing)
|
|
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_SURROUND_FACING_INWARDS)
|
|
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 4.0) // NOTE: This is set when group state starts too
|
|
|
|
ELIF Private_CheckBehaviourFlag(BBF_CloseGroupSpacing)
|
|
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
|
|
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 2.0)
|
|
|
|
ELSE
|
|
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
|
|
// SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 3.0)
|
|
ENDIF
|
|
|
|
SET_PED_RELATIONSHIP_GROUP_HASH(soldier.hPed, RELGROUPHASH_PLAYER)
|
|
|
|
SET_PED_PATH_CAN_USE_CLIMBOVERS(soldier.hPed, TRUE)
|
|
SET_PED_PATH_CAN_USE_LADDERS(soldier.hPed, TRUE)
|
|
SET_PED_PATH_CAN_DROP_FROM_HEIGHT(soldier.hPed, TRUE)
|
|
SET_PED_PATH_MAY_ENTER_WATER(soldier.hPed, TRUE)
|
|
SET_PED_PATH_PREFER_TO_AVOID_WATER(soldier.hPed, TRUE)
|
|
|
|
SET_PED_DIES_INSTANTLY_IN_WATER(soldier.hPed, FALSE)
|
|
SET_PED_DIES_IN_WATER(soldier.hPed, FALSE)
|
|
|
|
IF Private_CheckBehaviourFlag(BBF_CombatDefensive)
|
|
SET_PED_COMBAT_MOVEMENT(soldier.hPed, CM_DEFENSIVE)
|
|
ELSE
|
|
SET_PED_COMBAT_MOVEMENT(soldier.hPed, CM_WILLADVANCE)
|
|
ENDIF
|
|
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_AGGRESSIVE, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_ALWAYS_FIGHT, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_REQUIRES_LOS_TO_SHOOT, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_CAN_SHOOT_WITHOUT_LOS, FALSE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_CAN_FIGHT_ARMED_PEDS_WHEN_NOT_ARMED, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_CAN_USE_DYNAMIC_STRAFE_DECISIONS, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_DO_DRIVEBYS, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_USE_COVER, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_USE_VEHICLE, TRUE)
|
|
SET_PED_COMBAT_ATTRIBUTES(soldier.hPed, CA_LEAVE_VEHICLES, FALSE)
|
|
|
|
SET_PED_COMBAT_ABILITY(soldier.hPed, CAL_PROFESSIONAL)
|
|
SET_PED_FLEE_ATTRIBUTES(soldier.hPed, FA_NEVER_FLEE, TRUE)
|
|
SET_PED_SUFFERS_CRITICAL_HITS(soldier.hPed, FALSE)
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(soldier.hPed, KNOCKOFFVEHICLE_NEVER)
|
|
SET_PED_CONFIG_FLAG(soldier.hPed, PCF_DontActivateRagdollFromBulletImpact, TRUE)
|
|
|
|
// SET_PED_CONFIG_FLAG(soldier.hPed, PCF_OnlyAttackLawIfPlayerIsWanted, TRUE)
|
|
SET_PED_CONFIG_FLAG(soldier.hPed, PCF_LawWillOnlyAttackIfPlayerIsWanted, TRUE)
|
|
|
|
SET_PED_CONFIG_FLAG(soldier.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, Private_CheckBehaviourFlag(BBF_ForceFrontPassengerSeat))
|
|
// SET_PED_CONFIG_FLAG(soldier.hPed, PCF_AICanDrivePlayerAsRearPassenger, TRUE)
|
|
SET_PED_GROUP_MEMBER_PASSENGER_INDEX(soldier.hPed, VS_FRONT_RIGHT)
|
|
|
|
STOP_PED_SPEAKING(soldier.hPed, TRUE)
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(soldier.hPed, TRUE)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC Private_ClearSoldierAttribs(structSoldier& soldier)
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
// Set in attributes functions
|
|
// TODO: Might need to reset other attribs
|
|
SET_ENTITY_LOAD_COLLISION_FLAG(soldier.hPed, FALSE)
|
|
STOP_PED_SPEAKING(soldier.hPed, FALSE)
|
|
|
|
SET_PED_COMBAT_MOVEMENT(soldier.hPed, CM_WILLADVANCE)
|
|
|
|
SET_PED_SUFFERS_CRITICAL_HITS(soldier.hPed, TRUE)
|
|
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(soldier.hPed, KNOCKOFFVEHICLE_DEFAULT)
|
|
SET_PED_CONFIG_FLAG(soldier.hPed, PCF_DontActivateRagdollFromBulletImpact, FALSE)
|
|
|
|
// SET_PED_CONFIG_FLAG(soldier.hPed, PCF_AICanDrivePlayerAsRearPassenger, FALSE)
|
|
SET_PED_CONFIG_FLAG(soldier.hPed, PCF_ForcedToUseSpecificGroupSeatIndex, FALSE)
|
|
|
|
// Not set in attributes function, but can be set elsewhere
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, FALSE)
|
|
SET_PED_INFINITE_AMMO(soldier.hPed, FALSE)
|
|
IF GET_PED_STEALTH_MOVEMENT(soldier.hPed)
|
|
SET_PED_STEALTH_MOVEMENT(soldier.hPed, FALSE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC Private_SetSoldierExtraHealth(structSoldier& soldier)
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
IF GET_ENTITY_MAX_HEALTH(soldier.hPed) < FLOOR(CONST_fSoldierExtraMaxHealth)
|
|
|
|
FLOAT fNewHealth = TO_FLOAT(GET_ENTITY_HEALTH(soldier.hPed)) * (CONST_fSoldierExtraMaxHealth / CONST_fSoldierStandardMaxHealth)
|
|
|
|
SET_ENTITY_MAX_HEALTH(soldier.hPed, FLOOR(CONST_fSoldierExtraMaxHealth))
|
|
SET_ENTITY_HEALTH(soldier.hPed, FLOOR(fNewHealth))
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC Private_ClearSoldierExtraHealth(structSoldier& soldier)
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
IF GET_ENTITY_MAX_HEALTH(soldier.hPed) > FLOOR(CONST_fSoldierStandardMaxHealth)
|
|
|
|
FLOAT fNewHealth = TO_FLOAT(GET_ENTITY_HEALTH(soldier.hPed)) * (CONST_fSoldierStandardMaxHealth / CONST_fSoldierExtraMaxHealth)
|
|
|
|
SET_ENTITY_MAX_HEALTH(soldier.hPed, FLOOR(CONST_fSoldierStandardMaxHealth))
|
|
SET_ENTITY_HEALTH(soldier.hPed, FLOOR(fNewHealth))
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC Private_CleanupSoldier(structSoldier& soldier, enumMemberCleanupStyle eStyle = MC_Release)
|
|
|
|
IF soldier.eState <> SOLDIER_NULL
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
IF eStyle = MC_Delete
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Private_CleanupSoldier(", GetLabel_enumCharacterList(soldier.eChar), ", MC_Delete)")
|
|
ELIF eStyle = MC_Release
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Private_CleanupSoldier(", GetLabel_enumCharacterList(soldier.eChar), ", MC_Release)")
|
|
ELIF eStyle = MC_LeavePedIntact
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Private_CleanupSoldier(", GetLabel_enumCharacterList(soldier.eChar), ", MC_LeavePedIntact)")
|
|
ELSE
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Private_CleanupSoldier(", GetLabel_enumCharacterList(soldier.eChar), ", <unknown cleanup style>)")
|
|
ENDIF
|
|
#ENDIF
|
|
|
|
// Remove blips
|
|
SAFE_REMOVE_BLIP(soldier.hBlip)
|
|
|
|
// Clear extra health
|
|
Private_ClearSoldierExtraHealth(soldier)
|
|
|
|
IF DOES_ENTITY_EXIST(soldier.hPed)
|
|
|
|
// Take ped back if overridden
|
|
IF soldier.eState = SOLDIER_OVERRIDDEN AND eStyle <> MC_LeavePedIntact
|
|
IF NOT IS_ENTITY_DEAD(soldier.hPed) // (Really shouldn't have to check this)
|
|
IF NOT DOES_ENTITY_BELONG_TO_THIS_SCRIPT(soldier.hPed)
|
|
SET_ENTITY_AS_MISSION_ENTITY(soldier.hPed, TRUE, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Reset attributes
|
|
Private_ClearSoldierAttribs(soldier)
|
|
|
|
// Cleanup ped
|
|
IF soldier.hPed <> PLAYER_PED_ID()
|
|
#IF IS_DEBUG_BUILD
|
|
IF soldier.hPed <> GET_BATTLEBUDDY_PED(soldier.eChar)
|
|
SCRIPT_ASSERT("Private_CleanupSoldier() - Ped out of sync with global selector")
|
|
ENDIF
|
|
#ENDIF
|
|
|
|
IF IS_PED_IN_GROUP(soldier.hPed)
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
|
|
IF eStyle = MC_Delete
|
|
DELETE_PED(soldier.hPed)
|
|
|
|
ELIF eStyle = MC_Release
|
|
SET_PED_AS_NO_LONGER_NEEDED(soldier.hPed)
|
|
|
|
ELSE
|
|
// For transfer, do nothing
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
// Add communication delay
|
|
// IF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyAvailable)
|
|
// ADD_COMMUNICATION_DELAY_FOR_CHARACTER(soldier.eChar)
|
|
// ENDIF
|
|
|
|
// // Unblock family scenes
|
|
// Private_EnableFamilyScenes(friend.eChar, TRUE) // TODO: Add these in
|
|
//
|
|
// // Unblock scenarios
|
|
// Private_ClearFriendScenarioBlocking(friend)
|
|
|
|
// Reset flags
|
|
Private_ClearSoldierAvailable(soldier)
|
|
Private_ClearSoldierGlobalFlag(soldier, g_bitfieldBattleBuddyOverridden)
|
|
|
|
// Deactive char connections
|
|
DEACTIVATE_CHAR_CONNECTIONS(soldier.eChar)
|
|
|
|
// Reset structure
|
|
Private_InitSoldier(soldier, soldier.eChar)
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
// UTILS
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
FUNC BOOL Private_IsSoldierOutsidePoliceGate(structSoldier& soldier)
|
|
VECTOR vGate = <<400.6273, -1610.1445, 28.2928>>
|
|
|
|
IF NOT IS_PED_INJURED(soldier.hPed)
|
|
IF IS_ENTITY_AT_COORD(soldier.hPed, vGate, <<7.0, 7.0, 7.0>>)
|
|
VECTOR vToSoldier = GET_ENTITY_COORDS(soldier.hPed) - vGate
|
|
VECTOR vGateNormal = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(<<0,0,0>>, 324.8394, <<0,1,0>>)
|
|
IF DOT_PRODUCT_XY(vToSoldier, vGateNormal) > 0.0
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_IsSoldierOutOfRange(structSoldier& soldier)
|
|
|
|
// Can only go out of range once been available
|
|
IF IS_BIT_SET(g_bitfieldBattleBuddyAvailable, ENUM_TO_INT(soldier.eChar))
|
|
|
|
// If parachuting, don't test Z difference
|
|
IF (soldier.eState = SOLDIER_PARACHUTE) OR (GET_PED_PARACHUTE_STATE(PLAYER_PED_ID()) <> PPS_INVALID)
|
|
|
|
RETURN Util_IsPedOutsideRangePed(PLAYER_PED_ID(), soldier.hPed, CONST_fBattleBuddyAvailableFailDist)
|
|
|
|
ELSE
|
|
|
|
RETURN GET_DISTANCE_BETWEEN_ENTITIES(soldier.hPed, PLAYER_PED_ID()) > CONST_fBattleBuddyAvailableFailDist
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_IsPlayerArrested()
|
|
IF IS_PLAYER_BEING_ARRESTED(PLAYER_ID())
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_LoadSoldierArrestAnims()
|
|
|
|
REQUEST_ANIM_DICT("random@arrests")
|
|
RETURN HAS_ANIM_DICT_LOADED("random@arrests")
|
|
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_ShouldSoldierFollow(structSoldier& soldier)
|
|
|
|
// Is player in car that ped can't fit in?
|
|
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
AND NOT IS_PED_IN_VEHICLE(soldier.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
AND NOT DOES_VEHICLE_HAVE_FREE_SEAT(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
// If player+soldier each in own cars, don't get out
|
|
IF Private_CheckBehaviourFlag(BBF_DriveInConvoy)
|
|
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
|
|
AND IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
IF NOT IS_PED_IN_VEHICLE(soldier.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// // Is ped being driven by a mission entity
|
|
// IF IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed)
|
|
// PED_INDEX hDriver = GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
//
|
|
// IF IS_PED_UNINJURED(hDriver)
|
|
// AND hDriver <> PLAYER_PED_ID()
|
|
// AND hDriver <> soldier.hPed
|
|
// AND DOES_ENTITY_BELONG_TO_THIS_SCRIPT(soldier.hPed)
|
|
// RETURN TRUE
|
|
// ENDIF
|
|
// ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_CanSoldierJoinGroup(structSoldier& soldier, BOOL bAlreadyInGroup = FALSE)
|
|
|
|
FLOAT fDist = 25.0
|
|
IF bAlreadyInGroup
|
|
fDist = 100.0
|
|
IF NOT IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), soldier.hPed, <<fDist, fDist, 3.0>>, FALSE)//IS_BUDDY_GOOD_TO_JOIN_PLAYERS_GROUP(gActivity.locateData, soldier.hPed, fDist)//
|
|
IF NOT Private_ShouldSoldierFollow(soldier)
|
|
IF NOT IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
SET_PED_AS_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
ENDIF
|
|
|
|
IF IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF IS_PED_IN_GROUP(soldier.hPed)
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_AreAnyHatedPedsNearby(structSoldier& soldier, FLOAT fRadius = 100.0)
|
|
|
|
// Is soldier near to any peds that are in combat with player
|
|
// IF (COUNT_PEDS_IN_COMBAT_WITH_TARGET(PLAYER_PED_ID()) > 0)
|
|
// OR (COUNT_PEDS_IN_COMBAT_WITH_TARGET(soldier.hPed) > 0)
|
|
|
|
PED_INDEX nearbyPeds[25]
|
|
INT iNearCount = GET_PED_NEARBY_PEDS(soldier.hPed, nearbyPeds)
|
|
|
|
INT i
|
|
REPEAT iNearCount i
|
|
IF IS_PED_UNINJURED(nearbyPeds[i])
|
|
REL_GROUP_HASH hPedRelGroup = GET_PED_RELATIONSHIP_GROUP_HASH(nearbyPeds[i])
|
|
IF hPedRelGroup <> RELGROUPHASH_NO_RELATIONSHIP
|
|
|
|
IF GET_RELATIONSHIP_BETWEEN_GROUPS(RELGROUPHASH_PLAYER, hPedRelGroup) = ACQUAINTANCE_TYPE_PED_HATE
|
|
|
|
IF IS_ENTITY_AT_ENTITY(nearbyPeds[i], soldier.hPed, <<fRadius, fRadius, fRadius>>)
|
|
// IF CAN_PED_SEE_HATED_PED(soldier.hPed, nearbyPeds[i])
|
|
|
|
RETURN TRUE
|
|
|
|
// ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
// ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CanSoldierEnterCombat(structSoldier& soldier)
|
|
|
|
IF IS_PED_ON_FOOT(PLAYER_PED_ID())
|
|
IF Private_CheckBehaviourFlag(BBF_CombatDefendCargobobArea)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Is player onfoot + nearby, and are hated peds are near?
|
|
IF (IS_PED_ON_FOOT(PLAYER_PED_ID()) OR (Private_CheckBehaviourFlag(BBF_DriveInConvoy) AND (soldier.eState = SOLDIER_FOLLOW OR soldier.eState = SOLDIER_COMBAT)))
|
|
|
|
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), soldier.hPed, <<100.0, 100.0, 50.0>>)
|
|
// OR Private_CheckBehaviourFlag(BBF_CombatIgnorePlayerDist)
|
|
IF Private_AreAnyHatedPedsNearby(soldier, 100.0)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Couldn't join group
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_CanSoldierEnterParachute(structSoldier& soldier)
|
|
|
|
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(soldier.hPed)
|
|
IF NOT IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
IF GET_ENTITY_HEIGHT_ABOVE_GROUND(soldier.hPed) > 50.0
|
|
|
|
IF HAS_PED_GOT_WEAPON(soldier.hPed, GADGETTYPE_PARACHUTE)
|
|
RETURN TRUE
|
|
ELSE
|
|
CPRINTLN(DEBUG_FRIENDS, "Player parachuting and falling high in air, but ", GetLabel_enumCharacterList(soldier.eChar), " doesn't have parachute")
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CanSoldierExitParachute(structSoldier& soldier)
|
|
|
|
IF NOT IS_ENTITY_IN_AIR(soldier.hPed)
|
|
IF GET_PED_PARACHUTE_STATE(soldier.hPed) <> PPS_LANDING
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
|
|
FUNC BOOL Private_ShouldSoldierBePassenger(structSoldier& soldier)
|
|
IF IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(soldier.hPed)
|
|
IF IS_VEHICLE_DRIVEABLE(hVehicle)
|
|
PED_INDEX hDriverPed = GET_PED_IN_VEHICLE_SEAT(hVehicle, VS_DRIVER)
|
|
|
|
IF IS_PED_UNINJURED(hDriverPed)
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
|
|
// Is another battle buddy (not player) driving the car I'm in?
|
|
enumCharacterList eChar
|
|
REPEAT MAX_BATTLE_BUDDIES eChar
|
|
IF eChar <> ePlayerChar
|
|
AND eChar <> soldier.eChar
|
|
IF gActivity.mSoldiers[eChar].hPed = hDriverPed
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_RegisterSoldierForSwapping(structSoldier& soldier, SELECTOR_PED_STRUCT& selector)
|
|
|
|
SELECTOR_SLOTS_ENUM eSlot = GET_SELECTOR_SLOT_FROM_PLAYER_PED_ENUM(soldier.eChar)
|
|
|
|
// If valid + within 300m fail range, allow switch
|
|
IF soldier.eState <> SOLDIER_NULL
|
|
AND NOT IS_PED_INJURED(soldier.hPed)
|
|
AND NOT IS_PED_INJURED(PLAYER_PED_ID())
|
|
AND NOT (soldier.hPed = PLAYER_PED_ID())
|
|
AND NOT Private_IsSoldierOutOfRange(soldier)
|
|
AND Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyAvailable)
|
|
|
|
// Allow switch
|
|
selector.pedID[eSlot] = soldier.hPed
|
|
|
|
IF selector.bBlockSelectorPed[eSlot] = TRUE
|
|
SET_SELECTOR_PED_BLOCKED(selector, eSlot, FALSE)
|
|
ENDIF
|
|
RETURN TRUE
|
|
|
|
ELSE
|
|
|
|
// Block switch
|
|
selector.pedID[eSlot] = NULL
|
|
|
|
IF selector.bBlockSelectorPed[eSlot] = FALSE
|
|
SET_SELECTOR_PED_BLOCKED(selector, eSlot, TRUE)
|
|
ENDIF
|
|
RETURN FALSE
|
|
|
|
ENDIF
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_HasSoldierBeenAvailable(structSoldier& soldier, BOOL bMustBeAlive)
|
|
IF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyAvailable)
|
|
IF bMustBeAlive = FALSE OR IS_PED_UNINJURED(soldier.hPed)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_IsSoldierValid(structSoldier& soldier)
|
|
IF soldier.eState <> SOLDIER_NULL AND soldier.eState < SOLDIER_FAIL_INJURED
|
|
RETURN TRUE
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_IsSoldierOutside(structSoldier& soldier)
|
|
IF NOT IS_PED_INJURED(soldier.hPed)
|
|
IF GET_INTERIOR_FROM_ENTITY(soldier.hPed) = NULL
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CanSoldierConverse(structSoldier& soldier)
|
|
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND IS_PED_UNINJURED(soldier.hPed)
|
|
IF soldier.eChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
IF soldier.eState = SOLDIER_APPROACH
|
|
OR soldier.eState = SOLDIER_GROUP
|
|
OR soldier.eState = SOLDIER_COMBAT
|
|
OR soldier.eState = SOLDIER_OVERRIDDEN
|
|
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), soldier.hPed, <<CONST_fFriendConverseRadius, CONST_fFriendConverseRadius, CONST_fFriendConverseRadius>>)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_CanRejectSoldierForTime(structSoldier& soldier)
|
|
|
|
IF TIMER_DO_WHEN_READY(soldier.mAvailableTimer, CONST_fSoldierRejectTime)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_SetSoldierRejected(structSoldier& soldier, SP_MISSIONS eMission, BOOL bAllowSubtitles, enumFriendActivityPhrase ePhrase = FAP_REJECTION_OK)
|
|
|
|
IF soldier.eState <> SOLDIER_NULL AND soldier.eState < SOLDIER_FAIL_INJURED
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
TEXT_LABEL_63 tChar = GetLabel_enumCharacterList(soldier.eChar)
|
|
TEXT_LABEL_63 tMission = GetLabel_SP_MISSIONS(eMission)
|
|
TEXT_LABEL_63 tSubtitles = "bAllowSubtitles"
|
|
TEXT_LABEL_63 tPhrase = GetLabel_enumFriendActivityPhrase(ePhrase)
|
|
|
|
IF bAllowSubtitles tSubtitles += "=TRUE"
|
|
ELSE tSubtitles += "=FALSE"
|
|
ENDIF
|
|
|
|
CPRINTLN(DEBUG_FRIENDS, "Private_SetSoldierRejected(", tChar, ", ", tMission, ", ", tSubtitles, ", ", tPhrase, ")")
|
|
#ENDIF
|
|
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
AND soldier.eChar <> ePlayerChar
|
|
|
|
// Play audio comment
|
|
IF Private_CanSoldierConverse(soldier)
|
|
IF (ePhrase <> NO_FRIEND_ACTIVITY_PHRASE)
|
|
|
|
TEXT_LABEL tRoot
|
|
|
|
IF bAllowSubtitles = FALSE
|
|
IF PRIVATE_FriendDialogue_GetRawAudio(soldier.eChar, ePhrase, tRoot)
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(soldier.hPed, tRoot, PRIVATE_Get_SpeakerLabel_From_Char(soldier.eChar), SPEECH_PARAMS_FORCE_FRONTEND)
|
|
ENDIF
|
|
ELSE
|
|
IF Private_GetDialogueState(gActivity.mDialogue) <> FDIALOGUE_REJECTED
|
|
Private_SetDialogueState(gActivity.mDialogue, FDIALOGUE_REJECTED, soldier.eChar, ePhrase)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Get mission position
|
|
BOOL bHasDestPos = FALSE
|
|
VECTOR vRejectionDest
|
|
|
|
IF eMission <> SP_MISSION_NONE
|
|
STATIC_BLIP_NAME_ENUM eMissionBlip
|
|
VECTOR vMissionPos
|
|
|
|
eMissionBlip = g_sMissionStaticData[eMission].blip
|
|
IF IS_STATIC_BLIP_MULTIMODE(eMissionBlip)
|
|
vMissionPos = GET_STATIC_BLIP_POSITION(eMissionBlip, GET_CURRENT_PLAYER_PED_INT())
|
|
ELSE
|
|
vMissionPos = GET_STATIC_BLIP_POSITION(eMissionBlip)
|
|
ENDIF
|
|
|
|
// Get rejection dest
|
|
FLOAT fHeadingDummy
|
|
INT iLanesDummy
|
|
|
|
vRejectionDest = vMissionPos + (NORMALISE_VECTOR(GET_ENTITY_COORDS(soldier.hPed) - vMissionPos) * 50.0)
|
|
IF GET_SAFE_VEHICLE_NODE(vRejectionDest, vRejectionDest, fHeadingDummy, iLanesDummy, 1, FALSE)
|
|
bHasDestPos = TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Remove from group
|
|
IF IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
|
|
// Don't allow ambient launch
|
|
DECOR_SET_BOOL(soldier.hPed, "BlockFriendGrab", TRUE)
|
|
SET_PED_KEEP_TASK(soldier.hPed, TRUE)
|
|
|
|
// Walk away from the mission
|
|
SEQUENCE_INDEX seq
|
|
OPEN_SEQUENCE_TASK(seq)
|
|
IF IS_PED_IN_ANY_VEHICLE(soldier.hPed, TRUE)
|
|
TASK_LEAVE_ANY_VEHICLE(null)
|
|
ENDIF
|
|
TASK_LOOK_AT_ENTITY(null, PLAYER_PED_ID(), 2000, SLF_WHILE_NOT_IN_FOV|SLF_USE_TORSO)
|
|
TASK_PAUSE(null, GET_RANDOM_INT_IN_RANGE(800, 1200))
|
|
IF bHasDestPos
|
|
TASK_FOLLOW_NAV_MESH_TO_COORD(null, vRejectionDest, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED|ENAV_NO_STOPPING)
|
|
ENDIF
|
|
TASK_WANDER_STANDARD(null)
|
|
CLOSE_SEQUENCE_TASK(seq)
|
|
TASK_PERFORM_SEQUENCE(soldier.hPed, seq)
|
|
CLEAR_SEQUENCE_TASK(seq)
|
|
|
|
Private_CleanupSoldier(soldier, MC_Release)
|
|
RETURN TRUE
|
|
|
|
ELSE
|
|
Private_CleanupSoldier(soldier, MC_Release)
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
//PROC Private_SetSoldierLeaving(structSoldier& soldier)
|
|
//
|
|
// enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
//
|
|
// IF soldier.eState <> SOLDIER_NULL
|
|
// AND soldier.eState < SOLDIER_FAIL_INJURED
|
|
//
|
|
// IF IS_PED_UNINJURED(soldier.hPed)
|
|
// AND soldier.eChar <> ePlayerChar
|
|
//
|
|
// BOOL bCanCleanup = FALSE
|
|
//
|
|
// //-- Try to do preliminary stuff, so clean up can take place
|
|
//
|
|
// // On foot, or slow moving vehicle?
|
|
// IF NOT IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
// OR GET_ENTITY_SPEED(GET_VEHICLE_PED_IS_IN(soldier.hPed)) < 5.0//10.0
|
|
//
|
|
// // Say "We kicked ass" and leave
|
|
// TEXT_LABEL tBlock, tRoot
|
|
//
|
|
// IF NOT IS_MESSAGE_BEING_DISPLAYED()
|
|
// AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
|
|
// AND Private_GetFriendActivityPhrase(GET_FRIEND_FROM_CHAR(ePlayerChar), GET_FRIEND_FROM_CHAR(soldier.eChar), FAP_SQUAD_PASSED, tBlock, tRoot)
|
|
//
|
|
// ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, soldier.eChar, soldier.hPed)
|
|
// ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, ePlayerChar, PLAYER_PED_ID())
|
|
//
|
|
// IF CREATE_CONVERSATION(gActivity.convPedsDefault, tBlock, tRoot, CONV_PRIORITY_AMBIENT_HIGH)
|
|
// bCanCleanup = TRUE
|
|
// ENDIF
|
|
//
|
|
// ELIF PRIVATE_FriendDialogue_GetRawAudio(soldier.eChar, FAP_SQUAD_PASSED, tRoot)
|
|
// PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(soldier.hPed, tRoot, PRIVATE_Get_SpeakerLabel_From_Char(soldier.eChar), SPEECH_PARAMS_FORCE_FRONTEND)
|
|
// bCanCleanup = TRUE
|
|
// ENDIF
|
|
// ENDIF
|
|
//
|
|
// //-- If ready, leave and clean up
|
|
// IF bCanCleanUp
|
|
// // Remove from group
|
|
// IF IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
// REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
// ENDIF
|
|
//
|
|
// // Don't allow ambient launch
|
|
// DECOR_SET_BOOL(soldier.hPed, "BlockFriendGrab", TRUE)
|
|
// SET_PED_KEEP_TASK(soldier.hPed, TRUE)
|
|
//// STORE_PLAYER_PED_INFO(soldier.hPed)
|
|
//
|
|
// // Walk away from the mission
|
|
// SEQUENCE_INDEX seq
|
|
// OPEN_SEQUENCE_TASK(seq)
|
|
// IF IS_PED_IN_ANY_VEHICLE(soldier.hPed, TRUE)
|
|
// TASK_LEAVE_ANY_VEHICLE(null)
|
|
// ENDIF
|
|
// TASK_LOOK_AT_ENTITY(null, PLAYER_PED_ID(), 2000, SLF_WHILE_NOT_IN_FOV|SLF_USE_TORSO)
|
|
// TASK_PAUSE(null, GET_RANDOM_INT_IN_RANGE(800, 1200))
|
|
// TASK_WANDER_STANDARD(null)
|
|
// CLOSE_SEQUENCE_TASK(seq)
|
|
// TASK_PERFORM_SEQUENCE(soldier.hPed, seq)
|
|
// CLEAR_SEQUENCE_TASK(seq)
|
|
//
|
|
// // Cleanup soldier
|
|
// Private_CleanupSoldier(soldier, MC_LeavePedIntact)
|
|
// ENDIF
|
|
//
|
|
// ELSE
|
|
// Private_CleanupSoldier(soldier, MC_LeavePedIntact)
|
|
// ENDIF
|
|
//
|
|
// ENDIF
|
|
//
|
|
//ENDPROC
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// TASKS
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
PROC Private_UpdateSoldierBlip(structSoldier& soldier)
|
|
|
|
//-- Decide if blip is needed
|
|
BOOL bEnableBlip = FALSE
|
|
|
|
// Blip shouldn't ever be allowed in these states
|
|
IF soldier.eState >= SOLDIER_FAIL_INJURED
|
|
OR soldier.eState = SOLDIER_CREATE_IN_CAR
|
|
OR soldier.eState = SOLDIER_CREATE_ON_FOOT
|
|
OR IS_PED_INJURED(soldier.hPed)
|
|
OR soldier.hPed = PLAYER_PED_ID()
|
|
|
|
bEnableBlip = FALSE
|
|
|
|
// Blip should always be on when arriving
|
|
ELIF soldier.eState = SOLDIER_ARRIVE_IN_CAR
|
|
|
|
bEnableBlip = TRUE
|
|
|
|
// Blip should always be on when following in car
|
|
ELIF soldier.eState = SOLDIER_FOLLOW AND IS_PED_IN_ANY_VEHICLE(soldier.hPed) // When follow state not true anymore, ped told to get out, but task doesn't take effect until frame later, so get a one frame non signature blip
|
|
|
|
bEnableBlip = TRUE
|
|
|
|
// Blip should always be on when parachuting
|
|
ELIF soldier.eState = SOLDIER_PARACHUTE
|
|
|
|
bEnableBlip = TRUE
|
|
|
|
// Blip is currently off, switch it on if player > 100m away
|
|
ELIF soldier.eCurrentBlip = SOLDIER_BLIP_OFF
|
|
|
|
bEnableBlip = FALSE
|
|
IF Util_IsPedOutsideRangePed(soldier.hPed, PLAYER_PED_ID(), 100.0)
|
|
bEnableBlip = TRUE
|
|
ENDIF
|
|
|
|
// Blip is currently on, switch it off if player < 25m away and (onfoot/in same car as player)
|
|
ELSE
|
|
|
|
bEnableBlip = TRUE
|
|
IF Util_IsPedInsideRangePed(soldier.hPed, PLAYER_PED_ID(), 25.0)
|
|
AND ( NOT IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed) OR ( IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), GET_VEHICLE_PED_IS_IN(soldier.hPed)) ) )
|
|
bEnableBlip = FALSE
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
//-- Determine appropriate blip type
|
|
enumSoldierBlipType eRequestBlip = SOLDIER_BLIP_OFF
|
|
|
|
IF bEnableBlip
|
|
IF NOT Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyAvailable)
|
|
eRequestBlip = SOLDIER_BLIP_SIGNATURE
|
|
|
|
ELIF soldier.eState = SOLDIER_ARRIVE_IN_CAR
|
|
eRequestBlip = SOLDIER_BLIP_SIGNATURE
|
|
|
|
ELIF soldier.eState = SOLDIER_FOLLOW AND IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
eRequestBlip = SOLDIER_BLIP_SIGNATURE
|
|
|
|
ELIF IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
eRequestBlip = SOLDIER_BLIP_VEHICLE
|
|
|
|
ELSE
|
|
eRequestBlip = SOLDIER_BLIP_PED
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//-- Update to requested type
|
|
IF soldier.eCurrentBlip <> eRequestBlip
|
|
|
|
SAFE_REMOVE_BLIP(soldier.hBlip)
|
|
soldier.eCurrentBlip = SOLDIER_BLIP_OFF
|
|
|
|
SWITCH eRequestBlip
|
|
CASE SOLDIER_BLIP_SIGNATURE
|
|
soldier.hBlip = CREATE_PED_BLIP(soldier.hPed, TRUE, TRUE)
|
|
IF DOES_BLIP_EXIST(soldier.hBlip)
|
|
IF soldier.eChar = CHAR_MICHAEL
|
|
SET_BLIP_SPRITE(soldier.hBlip, RADAR_TRACE_MICHAEL_FAMILY)
|
|
ELIF soldier.eChar = CHAR_FRANKLIN
|
|
SET_BLIP_SPRITE(soldier.hBlip, RADAR_TRACE_FRANKLIN_FAMILY)
|
|
ELIF soldier.eChar = CHAR_TREVOR
|
|
SET_BLIP_SPRITE(soldier.hBlip, RADAR_TRACE_TREVOR_FAMILY)
|
|
ENDIF
|
|
SET_BLIP_COLOUR(soldier.hBlip, BLIP_COLOUR_BLUE)
|
|
ENDIF
|
|
soldier.eCurrentBlip = SOLDIER_BLIP_SIGNATURE
|
|
BREAK
|
|
|
|
CASE SOLDIER_BLIP_VEHICLE
|
|
soldier.hBlip = CREATE_VEHICLE_BLIP(GET_VEHICLE_PED_IS_IN(soldier.hPed), TRUE)
|
|
soldier.eCurrentBlip = SOLDIER_BLIP_VEHICLE
|
|
BREAK
|
|
|
|
CASE SOLDIER_BLIP_PED
|
|
soldier.hBlip = CREATE_PED_BLIP(soldier.hPed, TRUE, TRUE)
|
|
soldier.eCurrentBlip = SOLDIER_BLIP_PED
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
FUNC BOOL Private_CanSoldierExitArrival(structSoldier& soldier)
|
|
|
|
IF NOT IS_VEHICLE_DRIVEABLE(soldier.hVehicle)
|
|
OR NOT IS_PED_IN_VEHICLE(soldier.hPed, soldier.hVehicle)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
|
|
ENDFUNC
|
|
|
|
PROC Private_UpdateSoldierArriveInCarTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
// Store the nearest road node, to use as dest
|
|
// soldier.hArrivalNode = Private_GetNearestRoadside(GET_ENTITY_COORDS(PLAYER_PED_ID()), soldier.vArrivalPos)
|
|
soldier.iArrivalStage = 0
|
|
soldier.iArrivalStoppedTimer = GET_GAME_TIMER() + 1000
|
|
soldier.iArrivalHornTimer = 0
|
|
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
//-- Parameters
|
|
|
|
FLOAT fPlayerDist = GET_DISTANCE_BETWEEN_ENTITIES(soldier.hPed, PLAYER_PED_ID())
|
|
FLOAT fDestDist = GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(soldier.hPed, soldier.vArrivalPos)
|
|
|
|
INT iBasicMode = ENUM_TO_INT(DF_ChangeLanesAroundObstructions)|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_SteerAroundStationaryCars)|ENUM_TO_INT(DF_SwerveAroundAllCars)|ENUM_TO_INT(DF_SteerAroundPeds)
|
|
INT iParkAvoidMode = iBasicMode|ENUM_TO_INT(DF_SteerAroundStationaryCars)
|
|
INT iParkStopMode = iBasicMode|ENUM_TO_INT(DF_SteerAroundStationaryCars)|ENUM_TO_INT(DF_StopForCars)
|
|
|
|
FLOAT fDriveSpeed = CONST_fBattleBuddyArrivalSpeed
|
|
IF IS_BATTLEBUDDY_BEHAVIOUR_REQUESTED(BBF_DriveHighSpeed)
|
|
fDriveSpeed = CONST_fBattleBuddyArrivalSpeedFast
|
|
ENDIF
|
|
|
|
//-- Behaviour
|
|
|
|
BOOL bIsCarStopped = FALSE
|
|
|
|
IF GET_ENTITY_SPEED(soldier.hPed) > 1.0
|
|
soldier.iArrivalStoppedTimer = GET_GAME_TIMER() + 2000//1000
|
|
|
|
ELIF soldier.iArrivalStoppedTimer < GET_GAME_TIMER()
|
|
bIsCarStopped = TRUE
|
|
ENDIF
|
|
|
|
// Near player and stopped / very near player...
|
|
IF NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
OR fPlayerDist < 12.0
|
|
OR (fPlayerDist < 20.0 AND fDestDist < 10.0 AND bIsCarStopped)
|
|
|
|
// Stop get out of vehicle
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) OR soldier.iArrivalStage <> 0
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
soldier.iArrivalStage = 0
|
|
ENDIF
|
|
|
|
// At dest...
|
|
ELIF fDestDist < 2.0
|
|
|
|
// Stop vehicle
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.iArrivalStage <> 1
|
|
TASK_VEHICLE_MISSION_COORS_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), soldier.vArrivalPos, MISSION_STOP, 0.0, INT_TO_ENUM(DRIVINGMODE, iParkAvoidMode), 2.0, 20.0/*15.0*/, TRUE)
|
|
soldier.iArrivalStage = 1
|
|
ENDIF
|
|
|
|
// Very close to dest...
|
|
ELIF fDestDist < 7.0
|
|
|
|
// Drive slowly (+ stop for cars)
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.iArrivalStage <> 2
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_COORS_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), soldier.vArrivalPos, MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iParkStopMode), 2.0, 20.0/*15.0*/, TRUE)
|
|
soldier.iArrivalStage = 2
|
|
ENDIF
|
|
|
|
// Close to dest or player...
|
|
ELIF fPlayerDist < 30.0 OR fDestDist < 40.0
|
|
|
|
// Drive slowly (+ avoid cars)
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.iArrivalStage <> 3
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_COORS_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), soldier.vArrivalPos, MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iParkAvoidMode), 2.0, 20.0/*15.0*/, TRUE)
|
|
soldier.iArrivalStage = 3
|
|
ENDIF
|
|
|
|
// Not close to dest/player...
|
|
ELSE
|
|
|
|
// Drive full speed
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.iArrivalStage <> 4
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_COORS_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), soldier.vArrivalPos, MISSION_GOTO, fDriveSpeed, INT_TO_ENUM(DRIVINGMODE, iDriveAvoidMode), 10.0, 15.0, TRUE)
|
|
soldier.iArrivalStage = 4
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
// Update greeting horn
|
|
IF soldier.iArrivalHornTimer >= 0
|
|
IF soldier.iArrivalHornTimer = 0
|
|
IF (IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed) AND NOT IS_PED_ON_ANY_BIKE(soldier.hPed))
|
|
AND (fDestDist < 2.0 AND bIsCarStopped AND fPlayerDist > 20.0)
|
|
SET_HORN_PERMANENTLY_ON_TIME(GET_VEHICLE_PED_IS_IN(soldier.hPed), 50)
|
|
soldier.iArrivalHornTimer = GET_GAME_TIMER() + 500
|
|
ENDIF
|
|
|
|
ELSE
|
|
IF NOT IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed) OR IS_PED_ON_ANY_BIKE(soldier.hPed)
|
|
soldier.iArrivalHornTimer = -1
|
|
|
|
ELIF soldier.iArrivalHornTimer < GET_GAME_TIMER()
|
|
SET_HORN_PERMANENTLY_ON_TIME(GET_VEHICLE_PED_IS_IN(soldier.hPed), 500)
|
|
soldier.iArrivalHornTimer = -1
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Display
|
|
#IF IS_DEBUG_BUILD
|
|
IF g_flowUnsaved.bShowMissionFlowDebugScreen
|
|
IF (g_iDebugSelectedFriendConnDisplay > 0)
|
|
|
|
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
|
|
|
|
INT r = 0
|
|
INT g = 0
|
|
INT b = 0
|
|
IF soldier.eChar = CHAR_MICHAEL
|
|
r = 255
|
|
g = 128
|
|
ENDIF
|
|
IF soldier.eChar = CHAR_FRANKLIN
|
|
g = 255
|
|
b = 128
|
|
ENDIF
|
|
IF soldier.eChar = CHAR_TREVOR
|
|
b = 255
|
|
r = 128
|
|
ENDIF
|
|
DRAW_DEBUG_SPHERE(soldier.vArrivalPos, 0.1, r, g, b, 255)
|
|
DRAW_DEBUG_LINE(soldier.vArrivalPos-<<0,0,5>>, soldier.vArrivalPos+<<0,0,5>>, r, g, b, 255)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
#ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
PROC Private_UpdateSoldierApproachTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState OR soldier.eCharToDriveTo <> GET_CURRENT_PLAYER_PED_ENUM()
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
soldier.eCharToDriveTo = GET_CURRENT_PLAYER_PED_ENUM()
|
|
soldier.bIsInParkingRange = FALSE
|
|
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
// Parameters
|
|
FLOAT fPlayerDist = GET_DISTANCE_BETWEEN_ENTITIES(soldier.hPed, PLAYER_PED_ID())
|
|
INT iDrivingMode = ENUM_TO_INT(DF_ChangeLanesAroundObstructions)|ENUM_TO_INT(DF_DriveIntoOncomingTraffic)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_StopForPeds)|ENUM_TO_INT(DF_SwerveAroundAllCars)|ENUM_TO_INT(DF_SteerAroundStationaryCars)|ENUM_TO_INT(DF_SteerAroundPeds)//|ENUM_TO_INT(DF_UseSwitchedOffNodes)
|
|
INT iParkingMode = ENUM_TO_INT(DF_ChangeLanesAroundObstructions)|ENUM_TO_INT(DF_DriveIntoOncomingTraffic)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_StopForPeds)|ENUM_TO_INT(DF_StopForCars)//|ENUM_TO_INT(DF_UseSwitchedOffNodes)
|
|
|
|
FLOAT fDriveSpeed = 25.0
|
|
IF IS_BATTLEBUDDY_BEHAVIOUR_REQUESTED(BBF_DriveHighSpeed)
|
|
fDriveSpeed = 40.0
|
|
ENDIF
|
|
|
|
// Behaviour
|
|
IF NOT IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
|
|
// Not in vehicle -> Run to player
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_GO_TO_ENTITY)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_GO_TO_ENTITY(soldier.hPed, PLAYER_PED_ID(), DEFAULT_TIME_NEVER_WARP, 5.0)
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
// Vehicle undrivable -> Get out
|
|
IF NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
ENDIF
|
|
|
|
// Not within parking range -> Drive to player
|
|
ELIF fPlayerDist > 30.0
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.bIsInParkingRange = TRUE
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_PED_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), PLAYER_PED_ID(), MISSION_GOTO, fDriveSpeed, INT_TO_ENUM(DRIVINGMODE, iDrivingMode), 10.0, 15.0, TRUE)
|
|
ENDIF
|
|
soldier.bIsInParkingRange = FALSE
|
|
|
|
// Within parking range + car is moving -> Slow down
|
|
ELIF fPlayerDist > 12.0 AND GET_ENTITY_SPEED(soldier.hPed) > 1.0
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.bIsInParkingRange = FALSE
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_PED_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), PLAYER_PED_ID(), MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iParkingMode), 10.0, 15.0, TRUE)
|
|
ENDIF
|
|
soldier.bIsInParkingRange = TRUE
|
|
|
|
// Within parking range + car is stopped -> Get out
|
|
ELIF fPlayerDist > 12.0
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) OR soldier.bIsInParkingRange = FALSE
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
ENDIF
|
|
soldier.bIsInParkingRange = TRUE
|
|
|
|
// Very close -> Get out
|
|
ELSE
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) OR soldier.bIsInParkingRange = FALSE
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
ENDIF
|
|
soldier.bIsInParkingRange = TRUE
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
// // Within parking range
|
|
// IF fPlayerDist < 30.0
|
|
//
|
|
// // Very close or stopped -> Get out of car
|
|
// IF (fPlayerDist < 12.0) OR (GET_ENTITY_SPEED(soldier.hPed) < 1.0)
|
|
// IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE) OR soldier.bIsInParkingRange = FALSE
|
|
// CLEAR_PED_TASKS(soldier.hPed)
|
|
// TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
// ENDIF
|
|
// soldier.bIsInParkingRange = TRUE
|
|
//
|
|
// // Otherwise -> Drive+stop near player
|
|
// ELSE
|
|
// IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.bIsInParkingRange = FALSE
|
|
// CLEAR_PED_TASKS(soldier.hPed)
|
|
// TASK_VEHICLE_MISSION_PED_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), PLAYER_PED_ID(), MISSION_GOTO, 10.0, INT_TO_ENUM(DRIVINGMODE, iParkingMode), 10.0, 15.0, TRUE)
|
|
// ENDIF
|
|
// soldier.bIsInParkingRange = TRUE
|
|
// ENDIF
|
|
//
|
|
// // Out of parking range -> Drive to player
|
|
// ELSE
|
|
// IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION) OR soldier.bIsInParkingRange = TRUE
|
|
// CLEAR_PED_TASKS(soldier.hPed)
|
|
// TASK_VEHICLE_MISSION_PED_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), PLAYER_PED_ID(), MISSION_GOTO, fDriveSpeed, INT_TO_ENUM(DRIVINGMODE, iDrivingMode), 10.0, 15.0, TRUE)
|
|
// ENDIF
|
|
// soldier.bIsInParkingRange = FALSE
|
|
// ENDIF
|
|
//
|
|
// ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
FUNC BOOL Private_UpdateSoldierVehicle(structSoldier& soldier)
|
|
|
|
// If have no target, try to get one nearby
|
|
IF NOT IS_VEHICLE_DRIVEABLE(soldier.hVehicle)
|
|
|
|
// Get nearby vehicles
|
|
CONST_INT CONST_iMaxNearbyVehicles 10
|
|
VEHICLE_INDEX nearbyVehicles[CONST_iMaxNearbyVehicles]
|
|
INT iNearCount = GET_PED_NEARBY_VEHICLES(soldier.hPed, nearbyVehicles)
|
|
|
|
// Remove any unusable vehicles from list
|
|
INT i
|
|
REPEAT iNearCount i
|
|
IF NOT IS_VEHICLE_DRIVEABLE(nearbyVehicles[i])
|
|
nearbyVehicles[i] = NULL
|
|
ELSE
|
|
IF DOES_ENTITY_EXIST(GET_PED_IN_VEHICLE_SEAT(nearbyVehicles[i], VS_DRIVER))
|
|
nearbyVehicles[i] = NULL
|
|
ELSE
|
|
VECTOR vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
|
|
VECTOR vSoldierPos = GET_ENTITY_COORDS(soldier.hPed)
|
|
VECTOR vCarPos = GET_ENTITY_COORDS(nearbyVehicles[i])
|
|
|
|
IF VDIST2(vSoldierPos, vCarPos) > 70.0*70.0
|
|
OR VDIST2(vPlayerPos, vCarPos) > (CONST_fBattleBuddyAvailableFailDist-30.0)*(CONST_fBattleBuddyAvailableFailDist-30.0)
|
|
nearbyVehicles[i] = NULL
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
// Return first non-blacklisted vehicle if available
|
|
REPEAT iNearCount i
|
|
IF nearbyVehicles[i] <> NULL
|
|
IF NOT IS_VEHICLE_MODEL_ON_BLACKLIST(GET_ENTITY_MODEL(nearbyVehicles[i]))
|
|
soldier.hVehicle = nearbyVehicles[i]
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
// Return first available vehicle if any
|
|
REPEAT iNearCount i
|
|
IF nearbyVehicles[i] <> NULL
|
|
soldier.hVehicle = nearbyVehicles[i]
|
|
RETURN TRUE
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
// Couldn't find usable vehicle
|
|
RETURN FALSE
|
|
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
|
|
ENDFUNC
|
|
|
|
PROC Private_UpdateSoldierFollowTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
soldier.eCharToDriveTo = GET_CURRENT_PLAYER_PED_ENUM()
|
|
soldier.bIsInParkingRange = FALSE
|
|
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
// Parameters
|
|
FLOAT fPlayerDist = GET_DISTANCE_BETWEEN_ENTITIES(soldier.hPed, PLAYER_PED_ID())
|
|
INT iDrivingMode = ENUM_TO_INT(DF_ChangeLanesAroundObstructions)|ENUM_TO_INT(DF_DriveIntoOncomingTraffic)|ENUM_TO_INT(DF_GoOffRoadWhenAvoiding)|ENUM_TO_INT(DF_SteerAroundObjects)|ENUM_TO_INT(DF_StopForPeds)|ENUM_TO_INT(DF_SwerveAroundAllCars)|ENUM_TO_INT(DF_SteerAroundStationaryCars)|ENUM_TO_INT(DF_SteerAroundPeds)//|ENUM_TO_INT(DF_UseSwitchedOffNodes)
|
|
|
|
FLOAT fDriveSpeed = 25.0
|
|
IF IS_BATTLEBUDDY_BEHAVIOUR_REQUESTED(BBF_DriveHighSpeed) AND fPlayerDist > 50.0
|
|
fDriveSpeed = 40.0
|
|
ENDIF
|
|
|
|
// If close by mark as available (and beep horn)
|
|
// IF NOT Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyAvailable)
|
|
// IF fPlayerDist < 50.0
|
|
// // Set as available
|
|
// Private_SetSoldierGlobalFlag(soldier, g_bitfieldBattleBuddyAvailable)
|
|
//
|
|
// // Beep horn
|
|
// IF IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed)
|
|
// AND GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_PED_IS_IN(soldier.hPed), VS_DRIVER) = soldier.hPed
|
|
// START_VEHICLE_HORN(GET_VEHICLE_PED_IS_IN(soldier.hPed), 1000)
|
|
// ENDIF
|
|
// ENDIF
|
|
// ENDIF
|
|
|
|
// Behaviour
|
|
|
|
//-- Not in vehicle
|
|
IF NOT IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
|
|
// Try to find vehicle and get in
|
|
IF Private_UpdateSoldierVehicle(soldier)
|
|
|
|
IF NOT IS_PED_IN_VEHICLE(soldier.hPed, soldier.hVehicle)
|
|
IF GET_DISTANCE_BETWEEN_ENTITIES(soldier.hPed, soldier.hVehicle) > 30.0
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_GO_TO_ENTITY)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_GO_TO_ENTITY(soldier.hPed, soldier.hVehicle, DEFAULT_TIME_NEVER_WARP)
|
|
ENDIF
|
|
ELSE
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_ENTER_VEHICLE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_ENTER_VEHICLE(soldier.hPed, soldier.hVehicle, DEFAULT_TIME_NEVER_WARP)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Can't find vehicle, follow player
|
|
ELSE
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_GO_TO_ENTITY)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_GO_TO_ENTITY(soldier.hPed, PLAYER_PED_ID(), DEFAULT_TIME_NEVER_WARP, 5.0)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//-- In vehicle
|
|
ELSE
|
|
|
|
// Exit if vehicle undrivable
|
|
IF NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
ENDIF
|
|
ELSE
|
|
// Follow player around
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_MISSION)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_VEHICLE_MISSION_PED_TARGET(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), PLAYER_PED_ID(), MISSION_FOLLOW, fDriveSpeed, INT_TO_ENUM(DRIVINGMODE, iDrivingMode), 2.0, 20.0, TRUE)
|
|
ENDIF
|
|
|
|
SET_DRIVE_TASK_MAX_CRUISE_SPEED(soldier.hPed, fDriveSpeed)
|
|
SET_DRIVE_TASK_CRUISE_SPEED(soldier.hPed, fDriveSpeed)
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
|
|
PROC Private_UpdateSoldierGroupTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, FALSE)
|
|
REGISTER_HATED_TARGETS_AROUND_PED(soldier.hPed, 100.0)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
IF Private_CheckBehaviourFlag(BBF_CombatGroupSpacing)
|
|
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_SURROUND_FACING_INWARDS)
|
|
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 4.0) // NOTE: This is set in attributes too
|
|
ELSE
|
|
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
|
|
// SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 3.0)
|
|
ENDIF
|
|
|
|
soldier.iStealthDelay = 0
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
// Makr sure in group
|
|
IF NOT IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
SET_PED_AS_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
ENDIF
|
|
|
|
// Process
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
AND NOT Private_IsPlayerSwitching()
|
|
|
|
// Say "let's do this!" on first arrival
|
|
IF soldier.bRequestGreetingDialogue
|
|
IF (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_PED_IN_VEHICLE(soldier.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())))
|
|
OR (IS_PED_ON_FOOT(PLAYER_PED_ID()) AND IS_PED_ON_FOOT(soldier.hPed))
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
TEXT_LABEL tBlock, tRoot
|
|
|
|
IF NOT IS_MESSAGE_BEING_DISPLAYED()
|
|
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
|
|
AND Private_GetFriendActivityPhrase(ePlayerChar, soldier.eChar, FAP_SQUAD_START, tBlock, tRoot)
|
|
|
|
ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, soldier.eChar, soldier.hPed)
|
|
ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, ePlayerChar, PLAYER_PED_ID())
|
|
|
|
IF CREATE_CONVERSATION(gActivity.convPedsDefault, tBlock, tRoot, CONV_PRIORITY_AMBIENT_HIGH)
|
|
TASK_LOOK_AT_ENTITY(soldier.hPed, PLAYER_PED_ID(), 3500)
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
ENDIF
|
|
|
|
ELIF PRIVATE_FriendDialogue_GetRawAudio(soldier.eChar, FAP_SQUAD_START, tRoot)
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(soldier.hPed, tRoot, PRIVATE_Get_SpeakerLabel_From_Char(soldier.eChar), SPEECH_PARAMS_FORCE_FRONTEND)
|
|
TASK_LOOK_AT_ENTITY(soldier.hPed, PLAYER_PED_ID(), 3500)
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// If in undrivable car, exit
|
|
IF IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
AND NOT IS_VEHICLE_DRIVEABLE(GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed)
|
|
ENDIF
|
|
|
|
// If driver and in combat, drive randomly
|
|
ELIF NOT IS_BATTLEBUDDY_BEHAVIOUR_REQUESTED(BBF_DontFleeCopsWhenDriver)
|
|
AND IS_PED_SITTING_IN_ANY_VEHICLE(soldier.hPed)
|
|
AND IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), GET_VEHICLE_PED_IS_IN(soldier.hPed))
|
|
AND GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_PED_IS_IN(soldier.hPed), VS_DRIVER) = soldier.hPed
|
|
AND GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 1
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_DRIVE_WANDER)
|
|
TASK_VEHICLE_DRIVE_WANDER(soldier.hPed, GET_VEHICLE_PED_IS_IN(soldier.hPed), 60.0, DRIVINGMODE_AVOIDCARS_RECKLESS)
|
|
ENDIF
|
|
|
|
// Otherwise, clear tasks
|
|
ELSE
|
|
IF IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_VEHICLE_DRIVE_WANDER)
|
|
OR IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// If current weapon is empty, equip best weapon
|
|
IF soldier.hPed <> PLAYER_PED_ID()
|
|
WEAPON_TYPE eCurrentWeapon
|
|
GET_CURRENT_PED_WEAPON(soldier.hPed, eCurrentWeapon)
|
|
|
|
IF eCurrentWeapon = WEAPONTYPE_UNARMED
|
|
OR GET_AMMO_IN_PED_WEAPON(soldier.hPed, eCurrentWeapon) = 0
|
|
|
|
WEAPON_TYPE eBestWeapon = GET_BEST_PED_WEAPON(soldier.hPed)
|
|
IF eBestWeapon <> WEAPONTYPE_UNARMED
|
|
#IF IS_DEBUG_BUILD
|
|
TEXT_LABEL tChar = GetLabel_enumCharacterList(soldier.eChar)
|
|
TEXT_LABEL tWeapon = GET_WEAPON_NAME(eBestWeapon)
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Setting ", tChar, " to best weapon: ", tWeapon)
|
|
#ENDIF
|
|
SET_CURRENT_PED_WEAPON(soldier.hPed, eBestWeapon, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Crouch when player crouches
|
|
IF GET_PED_STEALTH_MOVEMENT(PLAYER_PED_ID())
|
|
IF NOT GET_PED_STEALTH_MOVEMENT(soldier.hPed)
|
|
IF soldier.iStealthDelay = 0
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(200, 1200)
|
|
ELIF soldier.iStealthDelay < GET_GAME_TIMER()
|
|
SET_PED_STEALTH_MOVEMENT(soldier.hPed, TRUE)
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
IF GET_PED_STEALTH_MOVEMENT(soldier.hPed)
|
|
IF soldier.iStealthDelay = 0
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(200, 1200)
|
|
ELIF soldier.iStealthDelay < GET_GAME_TIMER()
|
|
SET_PED_STEALTH_MOVEMENT(soldier.hPed, FALSE)
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC Private_UpdateSoldierCombatTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
IF IS_PED_IN_GROUP(soldier.hPed)
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
IF Private_CheckBehaviourFlag(BBF_CombatDefendCargobobArea)
|
|
SET_PED_SPHERE_DEFENSIVE_AREA(soldier.hPed, << -2145.4856, 3018.2944, 31.8100 >>, 10.0)
|
|
soldier.bDefendingCargobobArea = TRUE
|
|
ELSE
|
|
// IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
// SET_PED_DEFENSIVE_SPHERE_ATTACHED_TO_PED(soldier.hPed, PLAYER_PED_ID(), <<0, 0, 0>>, 150.0)
|
|
// ELSE
|
|
REMOVE_PED_DEFENSIVE_AREA(soldier.hPed)
|
|
// ENDIF
|
|
soldier.bDefendingCargobobArea = FALSE
|
|
ENDIF
|
|
|
|
soldier.iCombatDelay = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(0, 1000)
|
|
soldier.iStealthDelay = 0
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
// Reset state if defensive area changes
|
|
IF Private_CheckBehaviourFlag(BBF_CombatDefendCargobobArea) <> soldier.bDefendingCargobobArea
|
|
soldier.bInitState = TRUE
|
|
ENDIF
|
|
|
|
// Process
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID())
|
|
AND NOT Private_IsPlayerSwitching()
|
|
|
|
// Say "let's do this!" on first arrival
|
|
IF soldier.bRequestGreetingDialogue
|
|
IF (IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND IS_PED_IN_VEHICLE(soldier.hPed, GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())))
|
|
OR (IS_PED_ON_FOOT(PLAYER_PED_ID()) AND IS_PED_ON_FOOT(soldier.hPed))
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
TEXT_LABEL tBlock, tRoot
|
|
|
|
IF NOT IS_MESSAGE_BEING_DISPLAYED()
|
|
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
|
|
AND Private_GetFriendActivityPhrase(ePlayerChar, soldier.eChar, FAP_SQUAD_START, tBlock, tRoot)
|
|
|
|
ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, soldier.eChar, soldier.hPed)
|
|
ADD_FRIEND_CHAR_FOR_DIALOGUE(gActivity.convPedsDefault, ePlayerChar, PLAYER_PED_ID())
|
|
|
|
IF CREATE_CONVERSATION(gActivity.convPedsDefault, tBlock, tRoot, CONV_PRIORITY_AMBIENT_HIGH)
|
|
TASK_LOOK_AT_ENTITY(soldier.hPed, PLAYER_PED_ID(), 3500)
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
ENDIF
|
|
|
|
ELIF PRIVATE_FriendDialogue_GetRawAudio(soldier.eChar, FAP_SQUAD_START, tRoot)
|
|
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(soldier.hPed, tRoot, PRIVATE_Get_SpeakerLabel_From_Char(soldier.eChar), SPEECH_PARAMS_FORCE_FRONTEND)
|
|
TASK_LOOK_AT_ENTITY(soldier.hPed, PLAYER_PED_ID(), 3500)
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Set tasks
|
|
IF IS_PED_IN_ANY_VEHICLE(soldier.hPed)
|
|
VEHICLE_INDEX hVehicle = GET_VEHICLE_PED_IS_IN(soldier.hPed)
|
|
IF GET_ENTITY_SPEED(hVehicle) > 3.0
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
BRING_VEHICLE_TO_HALT(hVehicle, 0.5, 10)
|
|
ELSE
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_LEAVE_ANY_VEHICLE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_LEAVE_ANY_VEHICLE(soldier.hPed, 0, ECF_DONT_CLOSE_DOOR|ECF_RESUME_IF_INTERRUPTED)
|
|
ENDIF
|
|
ENDIF
|
|
ELSE
|
|
IF soldier.iCombatDelay < GET_GAME_TIMER()
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_COMBAT_HATED_TARGETS_AROUND_PED)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_COMBAT_HATED_TARGETS_AROUND_PED(soldier.hPed, 60.0)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// If current weapon is empty, equip best weapon
|
|
IF soldier.hPed <> PLAYER_PED_ID()
|
|
WEAPON_TYPE eCurrentWeapon
|
|
GET_CURRENT_PED_WEAPON(soldier.hPed, eCurrentWeapon)
|
|
|
|
IF eCurrentWeapon = WEAPONTYPE_UNARMED
|
|
OR GET_AMMO_IN_PED_WEAPON(soldier.hPed, eCurrentWeapon) = 0
|
|
|
|
WEAPON_TYPE eBestWeapon = GET_BEST_PED_WEAPON(soldier.hPed)
|
|
IF eBestWeapon <> WEAPONTYPE_UNARMED
|
|
#IF IS_DEBUG_BUILD
|
|
TEXT_LABEL tChar = GetLabel_enumCharacterList(soldier.eChar)
|
|
TEXT_LABEL tWeapon = GET_WEAPON_NAME(eBestWeapon)
|
|
CPRINTLN(DEBUG_FRIENDS, "BATTLEBUDDY - Setting ", tChar, " to best weapon: ", tWeapon)
|
|
#ENDIF
|
|
SET_CURRENT_PED_WEAPON(soldier.hPed, eBestWeapon, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Crouch when player crouches
|
|
IF GET_PED_STEALTH_MOVEMENT(PLAYER_PED_ID())
|
|
IF NOT GET_PED_STEALTH_MOVEMENT(soldier.hPed)
|
|
IF soldier.iStealthDelay = 0
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(200, 1200)
|
|
ELIF soldier.iStealthDelay < GET_GAME_TIMER()
|
|
SET_PED_STEALTH_MOVEMENT(soldier.hPed, TRUE)
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
IF GET_PED_STEALTH_MOVEMENT(soldier.hPed)
|
|
IF soldier.iStealthDelay = 0
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(200, 1200)
|
|
ELIF soldier.iStealthDelay < GET_GAME_TIMER()
|
|
SET_PED_STEALTH_MOVEMENT(soldier.hPed, FALSE)
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ELSE
|
|
soldier.iStealthDelay = 0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC Private_UpdateSoldierParachuteTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
IF NOT IsPedPerformingTask(soldier.hPed, SCRIPT_TASK_PARACHUTE_TO_TARGET)
|
|
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
TASK_PARACHUTE_TO_TARGET(soldier.hPed, GET_ENTITY_COORDS(PLAYER_PED_ID()))
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + 1000
|
|
|
|
ELIF soldier.iStealthDelay < GET_GAME_TIMER()
|
|
|
|
SET_PARACHUTE_TASK_TARGET(soldier.hPed, GET_ENTITY_COORDS(PLAYER_PED_ID()))
|
|
soldier.iStealthDelay = GET_GAME_TIMER() + 1000
|
|
|
|
ENDIF
|
|
|
|
IF GET_PED_PARACHUTE_STATE(soldier.hPed) = PPS_SKYDIVING
|
|
FORCE_PED_TO_OPEN_PARACHUTE(soldier.hPed)
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
PROC Private_UpdateSoldierPassengerTasks(structSoldier& soldier)
|
|
|
|
// Reset if required
|
|
IF soldier.bInitState
|
|
Private_SetSoldierAttribs(soldier)
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
IF IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
|
|
ENDPROC
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// STATE MACHINE
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
FUNC BOOL Private_AddSoldier(structSoldier& soldier, enumFriendConnectionMode eInitMode = FC_MODE_Squad)
|
|
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
|
|
IF g_BattleBuddyMission = SP_MISSION_NONE
|
|
SCRIPT_ASSERT("Private_AddSoldier() - Squad mission is not set")
|
|
ENDIF
|
|
|
|
// Is player
|
|
IF soldier.eChar = ePlayerChar
|
|
soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
// Creating a group char for replay - Create on foot by player
|
|
ELIF eInitMode = FC_MODE_ReplayGroup
|
|
soldier.iCreateAttempts = 0
|
|
Private_SetSoldierState(soldier, SOLDIER_CREATE_ON_FOOT)
|
|
|
|
// Doesn't exist, create ped
|
|
ELIF NOT Private_SyncSoldierPed(soldier)
|
|
soldier.iCreateAttempts = 0
|
|
|
|
// Choose vehicle type
|
|
IF soldier.eChar = CHAR_FRANKLIN
|
|
IF GET_RANDOM_INT_IN_RANGE(0, 100) < 25
|
|
soldier.eCreateInVehicleType = VEHICLE_TYPE_BIKE
|
|
ELSE
|
|
soldier.eCreateInVehicleType = VEHICLE_TYPE_CAR
|
|
ENDIF
|
|
ENDIF
|
|
|
|
Private_SetSoldierState(soldier, SOLDIER_CREATE_IN_CAR)
|
|
|
|
// Already exists, get ped
|
|
ELIF NOT IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierInitialWeapons(soldier)
|
|
Private_SetSoldierExtraHealth(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
// Already exists but dead, set failed
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
|
|
ENDFUNC
|
|
|
|
FUNC BOOL Private_HasSoldierShotAnyPed(structSoldier& soldier)
|
|
|
|
PED_INDEX nearbyPeds[10]
|
|
INT i, iNearCount = GET_PED_NEARBY_PEDS(soldier.hPed, nearbyPeds)
|
|
REPEAT iNearCount i
|
|
IF DOES_ENTITY_EXIST(nearbyPeds[i])
|
|
// IF IS_PED_INJURED(nearbyPeds[i]) //OR IS_PED_WRITHING(nearbyPeds[i])
|
|
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(nearbyPeds[i], soldier.hPed)
|
|
AND NOT HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(nearbyPeds[i], WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYMELEE)
|
|
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(nearbyPeds[i])
|
|
RETURN TRUE
|
|
ENDIF
|
|
// ENDIF
|
|
ENDIF
|
|
ENDREPEAT
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
PROC Private_UpdateSoldier(structSoldier& soldier)
|
|
|
|
IF IS_PED_UNINJURED(PLAYER_PED_ID()) AND soldier.eState <> SOLDIER_NULL
|
|
|
|
enumCharacterList ePlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
|
|
// Set available for switch/override if within 100m
|
|
IF IS_PLAYER_PED_PLAYABLE(soldier.eChar) AND NOT IS_BIT_SET(g_bitfieldBattleBuddyAvailable, ENUM_TO_INT(soldier.eChar))
|
|
IF IS_PED_UNINJURED(soldier.hPed)
|
|
IF IS_ENTITY_AT_ENTITY(soldier.hPed, PLAYER_PED_ID(), <<100.0, 100.0, 100.0>>)
|
|
OR PLAYER_PED_ID() = soldier.hPed
|
|
Private_SetSoldierAvailable(soldier)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Load anims
|
|
Private_LoadSoldierArrestAnims()
|
|
|
|
// Shout during combat
|
|
IF ePlayerChar <> soldier.eChar
|
|
IF NOT IS_PED_INJURED(soldier.hPed)
|
|
IF IS_ANY_SPEECH_PLAYING(soldier.hPed)
|
|
soldier.iShoutTimer = GET_GAME_TIMER() + 7000
|
|
|
|
ELIF IS_PED_IN_COMBAT(soldier.hPed)
|
|
IF Private_HasSoldierShotAnyPed(soldier)
|
|
CPRINTLN(DEBUG_FRIENDS, "PLAY_PED_AMBIENT_SPEECH_NATIVE(", GetLabel_enumCharacterList(soldier.eChar), ", \"SHOOT\") - Damaged ped ", GET_FRAME_COUNT())
|
|
PLAY_PED_AMBIENT_SPEECH_NATIVE(soldier.hPed, "SHOOT", AUDIO_SPEECH_GET_PARAM_STRING_FROM_ENUM(SPEECH_PARAMS_SHOUTED))
|
|
soldier.bWasInCombat = TRUE
|
|
|
|
// ELIF soldier.iShoutTimer < GET_GAME_TIMER()
|
|
// CPRINTLN(DEBUG_FRIENDS, "PLAY_PED_AMBIENT_SPEECH_NATIVE(", GetLabel_enumCharacterList(soldier.eChar), ", \"SHOOT\") - Idle ", GET_FRAME_COUNT())
|
|
// PLAY_PED_AMBIENT_SPEECH_NATIVE(soldier.hPed, "SHOOT", AUDIO_SPEECH_GET_PARAM_STRING_FROM_ENUM(SPEECH_PARAMS_SHOUTED))
|
|
ENDIF
|
|
|
|
ELIF soldier.bWasInCombat
|
|
CPRINTLN(DEBUG_FRIENDS, "PLAY_PED_AMBIENT_SPEECH_NATIVE(", GetLabel_enumCharacterList(soldier.eChar), ", \"SHOOT\") - Idle ", GET_FRAME_COUNT())
|
|
PLAY_PED_AMBIENT_SPEECH_NATIVE(soldier.hPed, "KILLED_ALL", AUDIO_SPEECH_GET_PARAM_STRING_FROM_ENUM(SPEECH_PARAMS_SHOUTED))
|
|
soldier.bWasInCombat = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Process state
|
|
SWITCH soldier.eState
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_CREATE_IN_CAR // TODO: Switching
|
|
CASE SOLDIER_CREATE_IN_CAR
|
|
|
|
IF soldier.bInitState
|
|
soldier.hArrivalNode = Private_GetNearestDestNode(GET_ENTITY_COORDS(PLAYER_PED_ID()), soldier.vArrivalPos)
|
|
IF IS_VEHICLE_NODE_ID_VALID(soldier.hArrivalNode)
|
|
soldier.vArrivalPos = Private_GetNodeParkingPos(GET_ENTITY_COORDS(PLAYER_PED_ID()), soldier.vArrivalPos)
|
|
ENDIF
|
|
soldier.bInitState = FALSE
|
|
ENDIF
|
|
|
|
IF Private_CreateSoldierInVehicle(soldier)
|
|
|
|
Private_SetSoldierInitialWeapons(soldier)
|
|
Private_SetSoldierExtraHealth(soldier)
|
|
|
|
IF NOT Private_CheckBehaviourFlag(BBF_DriveInConvoy)
|
|
Private_SetSoldierState(soldier, SOLDIER_ARRIVE_IN_CAR)
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
ENDIF
|
|
|
|
ELSE
|
|
soldier.iCreateAttempts++
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_CREATE_ON_FOOT // TODO: Switching
|
|
CASE SOLDIER_CREATE_ON_FOOT
|
|
|
|
IF Private_CreateSoldierOnFoot(soldier)
|
|
|
|
Private_SetSoldierInitialWeapons(soldier)
|
|
Private_SetSoldierExtraHealth(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ELIF soldier.iCreateAttempts < 30*5
|
|
soldier.iCreateAttempts++
|
|
|
|
ELSE
|
|
Private_CleanupSoldier(soldier, MC_Release)
|
|
DEACTIVATE_CHAR_CONNECTIONS(soldier.eChar)
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
DEBUG_PRINT_ALL_CONNECTIONS()
|
|
#ENDIF
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_ARRIVE_IN_CAR
|
|
CASE SOLDIER_ARRIVE_IN_CAR
|
|
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_CanSoldierExitArrival(soldier)
|
|
|
|
IF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
Private_UpdateSoldierArriveInCarTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_APPROACH
|
|
CASE SOLDIER_APPROACH
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
|
|
Private_UpdateSoldierApproachTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_FOLLOW
|
|
CASE SOLDIER_FOLLOW
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF NOT Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ELSE
|
|
|
|
Private_UpdateSoldierFollowTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_GROUP
|
|
CASE SOLDIER_GROUP
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF NOT Private_CanSoldierJoinGroup(soldier, TRUE)
|
|
|
|
IF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
// Private_SetSoldierAvailable(soldier)
|
|
Private_UpdateSoldierGroupTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_COMBAT
|
|
CASE SOLDIER_COMBAT
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF NOT Private_CanSoldierEnterCombat(soldier)
|
|
|
|
IF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
// Private_SetSoldierAvailable(soldier)
|
|
Private_UpdateSoldierCombatTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_PARACHUTE
|
|
CASE SOLDIER_PARACHUTE
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierExitParachute(soldier)
|
|
|
|
IF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
// Private_SetSoldierAvailable(soldier)
|
|
Private_UpdateSoldierParachuteTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_PASSENGER
|
|
CASE SOLDIER_PASSENGER
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed = PLAYER_PED_ID()
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELIF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF NOT Private_ShouldSoldierBePassenger(soldier)
|
|
|
|
IF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
Private_UpdateSoldierPassengerTasks(soldier)
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_PLAYER
|
|
CASE SOLDIER_PLAYER
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
Private_SetSoldierState(soldier, SOLDIER_OVERRIDDEN)
|
|
|
|
ELIF soldier.hPed <> PLAYER_PED_ID()
|
|
|
|
SET_ENTITY_AS_MISSION_ENTITY(soldier.hPed, TRUE, TRUE)
|
|
SET_PED_INFINITE_AMMO(soldier.hPed, FALSE)
|
|
|
|
IF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
// Private_SetSoldierAvailable(soldier)
|
|
soldier.bInitState = FALSE
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_OVERRIDDEN
|
|
CASE SOLDIER_OVERRIDDEN
|
|
IF IS_PED_INJURED(soldier.hPed)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_INJURED)
|
|
|
|
ELIF NOT Private_IsSoldierGlobalFlagSet(soldier, g_bitfieldBattleBuddyOverridden)
|
|
|
|
IF soldier.eChar = ePlayerChar
|
|
Private_SetSoldierState(soldier, SOLDIER_PLAYER)
|
|
|
|
ELSE
|
|
SET_ENTITY_AS_MISSION_ENTITY(soldier.hPed, TRUE, TRUE)
|
|
|
|
IF Private_IsSoldierOutOfRange(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FAIL_LOST)
|
|
|
|
ELIF Private_IsPlayerArrested()
|
|
Private_SetSoldierState(soldier, SOLDIER_ARREST)
|
|
|
|
ELIF Private_ShouldSoldierBePassenger(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PASSENGER)
|
|
|
|
ELIF Private_CanSoldierEnterParachute(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_PARACHUTE)
|
|
|
|
ELIF Private_CanSoldierEnterCombat(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_COMBAT)
|
|
|
|
ELIF Private_CanSoldierJoinGroup(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_GROUP)
|
|
|
|
ELIF Private_ShouldSoldierFollow(soldier)
|
|
Private_SetSoldierState(soldier, SOLDIER_FOLLOW)
|
|
|
|
ELSE
|
|
Private_SetSoldierState(soldier, SOLDIER_APPROACH)
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
soldier.bRequestGreetingDialogue = FALSE
|
|
soldier.bInitState = FALSE
|
|
|
|
ENDIF
|
|
BREAK
|
|
|
|
//------------------------------------------------------------------------------------------------- SOLDIER_ARREST
|
|
CASE SOLDIER_ARREST
|
|
|
|
// Set as not available
|
|
CLEAR_BIT(g_bitfieldBattleBuddyAvailable, ENUM_TO_INT(soldier.eChar))
|
|
CLEAR_BIT(g_bitfieldBattleBuddyOverridden, ENUM_TO_INT(soldier.eChar))
|
|
|
|
// Play animation
|
|
IF soldier.bInitState
|
|
IF soldier.hPed <> PLAYER_PED_ID()
|
|
IF NOT IS_PED_INJURED(soldier.hPed)
|
|
|
|
IF IS_PED_ON_FOOT(soldier.hPed)
|
|
AND NOT IS_ENTITY_IN_AIR(soldier.hPed)
|
|
AND NOT IS_PED_RAGDOLL(soldier.hPed)
|
|
|
|
IF Private_LoadSoldierArrestAnims()
|
|
|
|
IF IS_PED_GROUP_MEMBER(soldier.hPed, PLAYER_GROUP_ID())
|
|
REMOVE_PED_FROM_GROUP(soldier.hPed)
|
|
ENDIF
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(soldier.hPed, TRUE)
|
|
// SET_PED_CONFIG_FLAG(soldier.hPed, PCF_PedIgnoresAnimInterruptEvents, TRUE)
|
|
SET_ENTITY_PROOFS(soldier.hPed, TRUE, TRUE, TRUE, TRUE, TRUE)
|
|
SET_PED_KEEP_TASK(soldier.hPed, TRUE)
|
|
CLEAR_PED_TASKS(soldier.hPed)
|
|
|
|
//PCF_TreatAsPlayerDuringTargeting
|
|
|
|
SEQUENCE_INDEX seq
|
|
OPEN_SEQUENCE_TASK(seq)
|
|
TASK_PLAY_ANIM(null, "random@arrests", "idle_2_hands_up", SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_NOT_INTERRUPTABLE)
|
|
TASK_PLAY_ANIM(null, "random@arrests", "kneeling_arrest_idle", SLOW_BLEND_IN, SLOW_BLEND_OUT, -1, AF_LOOPING|AF_NOT_INTERRUPTABLE)
|
|
CLOSE_SEQUENCE_TASK(seq)
|
|
TASK_PERFORM_SEQUENCE(soldier.hPed, seq)
|
|
CLEAR_SEQUENCE_TASK(seq)
|
|
|
|
soldier.bInitState = FALSE
|
|
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
BREAK
|
|
|
|
ENDSWITCH
|
|
|
|
ENDIF
|
|
|
|
Private_UpdateSoldierBlip(soldier)
|
|
|
|
ENDPROC
|
|
|
|
PROC Private_HandleSoldierFail(structSoldier& soldier, enumMemberCleanupStyle& eCleanup)
|
|
eCleanup = MC_Release
|
|
|
|
SWITCH soldier.eState
|
|
CASE SOLDIER_FAIL_INJURED
|
|
Private_QueueFailReason(soldier.eChar, FFR_Injured)
|
|
eCleanup = MC_Release
|
|
BREAK
|
|
|
|
CASE SOLDIER_FAIL_LOST
|
|
Private_QueueFailReason(soldier.eChar, FFR_Lost)
|
|
eCleanup = MC_Delete
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
// START_SOLDIER_FAIL_TIMER(soldier.eChar)
|
|
|
|
ENDPROC
|