// ***************************************************************************************** // ***************************************************************************************** // // 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 "" 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, <>, <<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), ", )") 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, <>, 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, <>) // 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, <>) 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