Files
gtav-src/script/dev_ng/singleplayer/scripts/Ambient/Misc/taxiLauncher.sc
T
2025-09-29 00:52:08 +02:00

3673 lines
200 KiB
Python
Executable File

//////////////////////////////////////////////////////////////////////////////////////////
// //
// MISSION NAME : taxiLauncher.sc //
// AUTHOR : Ahron Mason //
// DESCRIPTION : Handles player calling a cab or entering a cab, //
// Also launches TaxiService.sc which handles player in a cab //
// //
//////////////////////////////////////////////////////////////////////////////////////////
USING "rage_builtins.sch"
USING "globals.sch"
USING "area_checks.sch"
USING "cellphone_public.sch"
USING "context_control_public.sch"
USING "flow_help_public.sch"
USING "taxi_functions.sch"
USING "tv_control_public.sch"
USING "website_public.sch"
//-------------------------------------------------------------------------------------------------------------------------------------------------
// :ENUMS:
//-------------------------------------------------------------------------------------------------------------------------------------------------
/// PURPOSE: state of the launcher
ENUM TAXI_LAUNCHER_STATE
TL_STATE_IDLE,
TL_STATE_PLAYER_NOT_IN_TAXI,
TL_STATE_PLAYER_IN_TAXI
ENDENUM
/// PURPOSE: state for the phone launching
ENUM TAXI_LAUNCHER_PHONE_STATE
TL_PHONE_STATE_AWAITING_CALL,
TL_PHONE_STATE_WAIT_TO_RESET_CALL,
TL_PHONE_STATE_CALL_IN_PROGRESS
ENDENUM
/// PURPOSE: states for the dispatched taxi
ENUM TAXI_LAUNCHER_DISPATCHED_STATE
TL_DISPATCHED_STATE_IDLE,
TL_DISPATCHED_STATE_CREATE_TAXI,
TL_DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER,
TL_DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER
ENDENUM
/// PURPOSE: states for controlling player getting into taxis
ENUM TAXI_LAUNCHER_ENTER_TAXI_STATE
TL_ENTER_TAXI_STATE_IDLE,
TL_ENTER_TAXI_STATE_ENTERING,
TL_ENTER_TAXI_STATE_INSIDE,
TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT
ENDENUM
/// PURPOSE: states for controlling player getting into taxis
ENUM TAXI_LAUNCHER_HAIL_TAXI_STATE
TL_HAIL_TAXI_STATE_IDLE,
TL_HAIL_TAXI_STATE_DETECT_HAIL,
TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT,
TL_HAIL_TAXI_STATE_FAILED_ATTEMPT,
TL_HAIL_TAXI_STATE_TAXI_WAITING
ENDENUM
/// PURPOSE: data used by the taxi dispatched by the phone call
STRUCT DISPATCHED_TAXI_STRUCT
VEHICLE_INDEX vehicleIndex
PED_INDEX pedIndex
BOOL bHasActiveTask
BOOL bForcedPullOverAtCurrentPosition = FALSE
BOOL bFailedZCheck = FALSE
FLOAT fDistToTarget
FLOAT fDriveToHeading
FLOAT fTargetReached
INT iNodeSearchNumber
INT iTimer_TaxiDispatchDelay
INT iSpawnAttempts
VECTOR vDistToPlayer
VECTOR vDriveToCoords
VECTOR vPullOverCoords
VECTOR vPlayerCalledCoords
VECTOR vPathNodeRequestMin
VECTOR vPathNodeRequestMax
DRIVINGMODE taxiDrivingModeStandard
enumCharacterList eCharDispatchedFor
ENDSTRUCT
//-------------------------------------------------------------------------------------------------------------------------------------------------
// :CONSTANTS
//-------------------------------------------------------------------------------------------------------------------------------------------------
CONST_FLOAT TAXI_HAIL_DISTANCE 35.0
CONST_FLOAT TAXI_MOVING_GET_IN_SPEED 0.5
CONST_INT ENTER_CAR_AS_PASSENGER_TIME 275
CONST_INT STICK_DEAD_ZONE 28
CONST_INT TIME_DELAY_TAXI_DISPATCHED 10000
CONST_INT PROG_INITIALISE 0
CONST_INT PROG_ATTEMPT_HAIL 1
//-------------------------------------------------------------------------------------------------------------------------------------------------
// :VARIABLES
//-------------------------------------------------------------------------------------------------------------------------------------------------
TAXI_LAUNCHER_STATE eTaxiLauncherState = TL_STATE_IDLE
TAXI_LAUNCHER_PHONE_STATE eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
TAXI_LAUNCHER_DISPATCHED_STATE eDispatchedTaxiState = TL_DISPATCHED_STATE_IDLE
TAXI_LAUNCHER_ENTER_TAXI_STATE eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
TAXI_LAUNCHER_HAIL_TAXI_STATE eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
DISPATCHED_TAXI_STRUCT sDispatchedTaxi
BOOL bPlayAdditionalFuckYouDialogue
BOOL bHintTriggeredByTaxiLauncher
BOOL bHelpEnterTaxiDisplayed = FALSE
BOOL bUpdateHailTargetThisFrame = TRUE
BOOL bPhonecallReachedSuccessfulLine = FALSE
BOOL bBlockingPlayerAmbientIdles = FALSE
BLIP_INDEX blipWaitingTaxi
INT iHailPromptCounter
INT iTaxiHailIntention = NEW_CONTEXT_INTENTION
INT iTimer_DelayTaxiSearch
INT iTimer_HailAnimTriggered
INT iTimer_HailFailedDialogueDelay
MODEL_NAMES mnTaxiDriverModel = GET_TAXI_DRIVER_MODEL()
MODEL_NAMES mnTaxiModel = GET_TAXI_MODEL()
// Phonecall Vars
structPedsForConversation phonecallStruct
STRING playerVoice
STRING playerLine1
STRING playerLine3
THREADID tTaxiServiceThread
TEXT_LABEL_15 tlTaxiAnimDict = "TAXI_HAIL"
VECTOR vPlayerPos
VEHICLE_INDEX vehClosestTaxi
VEHICLE_INDEX vehHailTarget
VEHICLE_SEAT ePlayerChosenSeat
//-------------------------------------------------------------------------------------------------------------------------------------------------
// :DEBUG FUNCS / PROCS / WIDGETS
//-------------------------------------------------------------------------------------------------------------------------------------------------
#IF IS_DEBUG_BUILD
BLIP_INDEX bDebug_blip1
BLIP_INDEX bDebug_blip2
BLIP_INDEX bDebug_blip3
BOOL bDebug_AddBlips = FALSE
BOOL bDebug_CallCab = FALSE
BOOL bDebug_DisplayInfo = FALSE
BOOL bDebug_DisplayCleanupTTY = FALSE
BOOL bDebug_KillPlayerVehicle = FALSE
BOOL bDebug_VisualiseDispatchTaxi = FALSE
BOOL bDebug_OutputText = FALSE
BOOL bDebug_Point1 = TRUE
BOOL bDebug_ZeroPlayerCash = FALSE
BOOL bDebug_DrawGetPullOverResults = FALSE
BOOL bDebug_SetCanPlayerUseTaxiFalse = FALSE
BOOL bDebug_SetCanPlayerUseTaxiTrue = FALSE
BOOL bDebug_VisualiseIsPointInAngledAreaCheck = FALSE
VECTOR vDebug_PointInAngledTest
VECTOR vDebug_PointInAngledAreaCheck[2]
FLOAT fDebug_PointInAngledAreaWidth
BOOL bDebug_UseForceTaxiSpawnCoordsAndHeading = FALSE
VECTOR vDebug_ForcedTaxiSpawnCoords
FLOAT fDebug_ForcedTaxiSpawnHeading
//BOOL bDebugPerformGenerateTaxiSpawnPos = FALSE
//BOOL bDebugPerformGetTaxiDriveToPlayerTest = FALSE
//BOOL bDebug_TestIsPositionInSpecialArea = FALSE
//BOOL bDebugPerformGetTaxiPullInSpotTest = FALSE
FLOAT fDebug_DistBetween1n4[8]
//FLOAT fDebug_DriveToNodeHeading
INT iDebug_CurrentArea
VECTOR vDebug_AreaBound1[8]
VECTOR vDebug_AreaBound2[8]
VECTOR vDebug_DispatchTaxiSpawnPos
//VECTOR vDebug_TaxiPos
//VECTOR vDebug_DriveToNodePos
//VECTOR vDebug_TempPickupPos
WIDGET_GROUP_ID widgetGroup
/// PURPOSE:
/// Sets up the script's widget groups, which get created in RAG->SCRIPT
PROC DEBUG_SETUP_WIDGETS()
widgetGroup = START_WIDGET_GROUP("taxiLauncher")
ADD_WIDGET_BOOL("Output additional TTY info", bDebug_DisplayInfo)
ADD_WIDGET_BOOL("Output additional cleanup TTY info", bDebug_DisplayCleanupTTY)
ADD_WIDGET_BOOL("Zero Player Cash", bDebug_ZeroPlayerCash)
ADD_WIDGET_BOOL("Add/remove some blips", bDebug_AddBlips)
ADD_WIDGET_BOOL("Is player in a taxi", g_bPlayerIsInTaxi)
ADD_WIDGET_BOOL("Disable Hailing status", g_bTaxiHailingIsDisabled)
ADD_WIDGET_BOOL("bDebug_SetCanPlayerUseTaxiFalse", bDebug_SetCanPlayerUseTaxiFalse)
ADD_WIDGET_BOOL("bDebug_SetCanPlayerUseTaxiTrue", bDebug_SetCanPlayerUseTaxiTrue)
ADD_WIDGET_BOOL("Kill current car", bDebug_KillPlayerVehicle)
ADD_WIDGET_BOOL("Call a cab", bDebug_CallCab)
ADD_WIDGET_BOOL("Dispatched Taxi : visualise info : ", bDebug_VisualiseDispatchTaxi)
ADD_WIDGET_VECTOR_SLIDER("vDebug_ForcedTaxiSpawnCoords : ", vDebug_ForcedTaxiSpawnCoords, -10000.0, 10000.0, 0.0001)
ADD_WIDGET_FLOAT_SLIDER("fDebug_ForcedTaxiSpawnHeading : ", fDebug_ForcedTaxiSpawnHeading, -360.0, 360.0, 0.01)
ADD_WIDGET_BOOL("Use Forced dispatch taxi spawn coords and heading: ", bDebug_UseForceTaxiSpawnCoordsAndHeading)
ADD_WIDGET_BOOL("bDebug_VisualiseIsPointInAngledAreaCheck", bDebug_VisualiseIsPointInAngledAreaCheck)
ADD_WIDGET_VECTOR_SLIDER("vDebug_PointInAngledTest : ", vDebug_PointInAngledTest, -10000.0, 10000.0, 0.0001)
ADD_WIDGET_VECTOR_SLIDER("vDebug_PointInAngledAreaCheck[0] : ", vDebug_PointInAngledAreaCheck[0], -10000.0, 10000.0, 0.0001)
ADD_WIDGET_VECTOR_SLIDER("vDebug_PointInAngledAreaCheck[1] : ", vDebug_PointInAngledAreaCheck[1], -10000.0, 10000.0, 0.0001)
ADD_WIDGET_FLOAT_SLIDER("fDebug_PointInAngledAreaWidth : ", fDebug_PointInAngledAreaWidth, 0.0, 1000.0, 0.01)
/*ADD_WIDGET_BOOL("display taxi pull over results", bDebug_DrawGetPullOverResults)
ADD_WIDGET_BOOL("Debug perform GET_TAXI_PICK_UP_PLAYER_DESTINATION test uses : ", bDebugPerformGetTaxiDriveToPlayerTest)
ADD_WIDGET_BOOL("Debug perform GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER test : ", bDebugPerformGenerateTaxiSpawnPos)
ADD_WIDGET_BOOL("Debug perform ARE_COORDS_IN_SPECIAL_AREA test uses vDebug_TempPickupPos : ", bDebug_TestIsPositionInSpecialArea)
ADD_WIDGET_BOOL("Debug perform GET_TAXI_PULL_OVER_INFO / test uses : ", bDebugPerformGetTaxiPullInSpotTest)
ADD_WIDGET_VECTOR_SLIDER("vDebug_DriveToNodePos :", vDebug_DriveToNodePos, -10000.0, 10000.0, 0.0001)
ADD_WIDGET_VECTOR_SLIDER("vDebug_TempPickupPos :", vDebug_TempPickupPos, -10000.0, 10000.0, 0.0001)*/
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
/// updates the script's widgets, based off RAG input
PROC DEBUG_UPDATE_WIDGETS()
//MONITOR_CUSTOM_DROP_OFF_BLIP()
IF bDebug_ZeroPlayerCash
//BREAK_ON_NATIVE_COMMAND("PRINTNL", TRUE)
DEBIT_BANK_ACCOUNT(GET_CURRENT_PLAYER_PED_ENUM(), BAAC_TAXI, GET_TOTAL_CASH(GET_CURRENT_PLAYER_PED_ENUM()))
bDebug_ZeroPlayerCash = FALSE
ENDIF
IF bDebug_AddBlips
IF NOT DOES_BLIP_EXIST(bDebug_blip1)
bDebug_blip1 = ADD_BLIP_FOR_COORD(<< -820.1073, -356.7995, 36.5842 >>)
SET_TAXI_DROPOFF_LOCATION_FOR_BLIP(bDebug_blip1, << -158.2055, -854.6122, 28.8008 >>, 339.2080)
ENDIF
IF NOT DOES_BLIP_EXIST(bDebug_blip2)
bDebug_blip2 = ADD_BLIP_FOR_COORD(<< -1579.8685, -503.4034, 34.3710 >>)
SET_TAXI_DROPOFF_LOCATION_FOR_BLIP(bDebug_blip1, << -158.2055, -854.6122, 28.8008 >>, 339.2080)
ENDIF
IF NOT DOES_BLIP_EXIST(bDebug_blip3)
bDebug_blip3 = ADD_BLIP_FOR_COORD(<< -735.7357, -1185.1532, 9.6465 >>)
SET_TAXI_DROPOFF_LOCATION_FOR_BLIP(bDebug_blip1, << -158.2055, -854.6122, 28.8008 >>, 339.2080)
ENDIF
ELSE
IF DOES_BLIP_EXIST(bDebug_blip1)
REMOVE_BLIP(bDebug_blip1)
ENDIF
IF DOES_BLIP_EXIST(bDebug_blip2)
REMOVE_BLIP(bDebug_blip2)
ENDIF
IF DOES_BLIP_EXIST(bDebug_blip3)
REMOVE_BLIP(bDebug_blip3)
ENDIF
ENDIF
IF bDebug_SetCanPlayerUseTaxiFalse
DISABLE_TAXI_HAILING(TRUE)
bDebug_SetCanPlayerUseTaxiFalse = FALSE
ELIF bDebug_SetCanPlayerUseTaxiTrue
DISABLE_TAXI_HAILING(FALSE)
bDebug_SetCanPlayerUseTaxiTrue = FALSE
ENDIF
IF bDebug_KillPlayerVehicle
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
SET_VEHICLE_ENGINE_HEALTH(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), 0)
ENDIF
ENDIF
bDebug_KillPlayerVehicle = FALSE
ENDIF
IF bDebug_VisualiseIsPointInAngledAreaCheck
IF IS_POINT_IN_ANGLED_AREA(vDebug_PointInAngledTest, vDebug_PointInAngledAreaCheck[0], vDebug_PointInAngledAreaCheck[1], fDebug_PointInAngledAreaWidth, TRUE)
DRAW_DEBUG_SPHERE(vDebug_PointInAngledTest, 0.5, 10, 200, 50, 150)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " DEBUG: IS_POINT_IN_ANGLED_AREA vDebug_PointInAngledTest = ", vDebug_PointInAngledTest)
ENDIF
ENDIF
IF bDebug_VisualiseDispatchTaxi
IF DOES_ENTITY_EXIST(sDispatchedTaxi.vehicleIndex)
SET_DEBUG_ACTIVE(TRUE)
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
VECTOR vTempDrawPos
VECTOR vTempPos = GET_ENTITY_COORDS(sDispatchedTaxi.vehicleIndex, FALSE)
IF IS_VEHICLE_DRIVEABLE(g_WaitingTaxi)
vTempDrawPos = vTempPos
vTempDrawPos.Z += 14.0
DRAW_DEBUG_SPHERE(vTempDrawPos, 10.0, 0, 250, 100, 120)
ENDIF
DRAW_DEBUG_LINE(vDebug_DispatchTaxiSpawnPos, vTempPos, 255, 0, 0, 255) // red
DRAW_DEBUG_LINE(sDispatchedTaxi.vDriveToCoords, vTempPos, 255, 165, 0, 255) // orange
DRAW_DEBUG_LINE(sDispatchedTaxi.vPullOverCoords , vTempPos, 75, 255, 0, 255) // light green
ENDIF
ENDIF
/*
IF bDebugPerformGenerateTaxiSpawnPos
IF GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER(vTempReturnCoords, fTempReturnHeading)
STRING sTemp
OPEN_DEBUG_FILE()
SAVE_NEWLINE_TO_DEBUG_FILE()
sTemp = "DEBUG : bDebugPerformGenerateTaxiSpawnPos results : vReturnCoords = "
SAVE_STRING_TO_DEBUG_FILE(sTemp)
SAVE_VECTOR_TO_DEBUG_FILE(vTempReturnCoords)
sTemp = " : vReturnHeading = "
SAVE_STRING_TO_DEBUG_FILE(sTemp)
SAVE_FLOAT_TO_DEBUG_FILE(fTempReturnHeading)
SAVE_NEWLINE_TO_DEBUG_FILE()
CLOSE_DEBUG_FILE()
bDebugPerformGenerateTaxiSpawnPos = FALSE
ENDIF
ENDIF
IF bDebugPerformGetTaxiDriveToPlayerTest
iDesinationNodeSearchNumber = 0
IF GET_TAXI_PICK_UP_PLAYER_DESTINATION(vDebug_TempPickupPos, vDebug_DriveToNodePos, fDebug_DriveToNodeHeading, iDesinationNodeSearchNumber)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " bDebugPerformGetTaxiDriveToPlayerTest - return TRUE for vDebug_TempPickupPos : ", vDebug_TempPickupPos,
" vDebug_DriveToNodePos = ", vDebug_DriveToNodePos, " fDebug_DriveToNodeHeading = ", fDebug_DriveToNodeHeading)
ENDIF
SET_DEBUG_ACTIVE(TRUE)
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
DRAW_DEBUG_SPHERE(vDebug_TempPickupPos, 2.5, 250, 150, 0, 200)
DRAW_DEBUG_SPHERE(vTempReturnCoords, 5.0, 0, 150, 150, 200)
ENDIF
IF bDebugPerformGetTaxiPullInSpotTest
vDebug_TaxiPos = vPlayerPos
IF GET_TAXI_PULL_OVER_INFO(vDebug_TaxiPos, vDebug_DriveToNodePos, fDebug_DriveToNodeHeading, vTempReturnCoords, fTempReturnHeading)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " bDebugPerformGetTaxiPullInSpotTest - return TRUE for vDebug_TaxiPos : ", vDebug_TaxiPos,
" vDebug_DriveToNodePos = ", vDebug_DriveToNodePos, " fDebug_DriveToNodeHeading = ", fDebug_DriveToNodeHeading,
" vTempReturnCoords = ", vTempReturnCoords, " fTempReturnHeading = ", fTempReturnHeading)
ENDIF
//DRAW_DEBUG_SPHERE(vDebug_TaxiPos, 0.25, 50, 0, 250, 200)
ENDIF
IF bDebug_TestIsPositionInSpecialArea
IF ARE_COORDS_IN_SPECIAL_AREA(vDebug_TempPickupPos, vTempReturnCoords, fTempReturnHeading)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " bDebug_TestIsPositionInSpecialArea - return TRUE for vDebug_TempPickupPos : ", vDebug_TempPickupPos,
" vTempReturnCoords = ", vTempReturnCoords, " fTempReturnHeading = ", fTempReturnHeading)
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " bDebug_TestIsPositionInSpecialArea - return FALSE for vDebug_TempPickupPos : ", vDebug_TempPickupPos)
ENDIF
SET_DEBUG_ACTIVE(TRUE)
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
DRAW_DEBUG_SPHERE(vDebug_TempPickupPos, 2.5, 250, 150, 0, 200)
DRAW_DEBUG_SPHERE(vTempReturnCoords, 5.0, 0, 150, 150, 200)
ENDIF*/
ENDPROC
/// PURPOSE:
/// not sure - maybe custom area checks?
PROC DEBUG_SETUP_AREAS_WIDGETS()
vDebug_AreaBound1[0] = <<-1812.778320,-2764.928711,13.047204>>
vDebug_AreaBound2[0] = <<-800.595398,-3344.736816,16.444502>>
fDebug_DistBetween1n4[0] = 250.000000
SET_CURRENT_WIDGET_GROUP(widgetGroup)
CLEAR_CURRENT_WIDGET_GROUP(widgetGroup)
START_WIDGET_GROUP("Area Debug")
ADD_WIDGET_BOOL("Output areas to debug file", bDebug_OutputText)
ADD_WIDGET_INT_SLIDER("Which area", iDebug_CurrentArea, 0, 7, 1)
ADD_WIDGET_BOOL("Is this point 1", bDebug_Point1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[0].x", vDebug_AreaBound1[0].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[0].y", vDebug_AreaBound1[0].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[0].z", vDebug_AreaBound1[0].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[0].x", vDebug_AreaBound2[0].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[0].y", vDebug_AreaBound2[0].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[0].z", vDebug_AreaBound2[0].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[0]", fDebug_DistBetween1n4[0], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[1].x", vDebug_AreaBound1[1].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[1].y", vDebug_AreaBound1[1].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[1].z", vDebug_AreaBound1[1].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[1].x", vDebug_AreaBound2[1].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[1].y", vDebug_AreaBound2[1].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[1].z", vDebug_AreaBound2[1].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[1]", fDebug_DistBetween1n4[1], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[2].x", vDebug_AreaBound1[2].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[2].y", vDebug_AreaBound1[2].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[2].z", vDebug_AreaBound1[2].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[2].x", vDebug_AreaBound2[2].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[2].y", vDebug_AreaBound2[2].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[2].z", vDebug_AreaBound2[2].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[2]", fDebug_DistBetween1n4[2], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[3].x", vDebug_AreaBound1[3].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[3].y", vDebug_AreaBound1[3].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[3].z", vDebug_AreaBound1[3].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[3].x", vDebug_AreaBound2[3].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[3].y", vDebug_AreaBound2[3].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[3].z", vDebug_AreaBound2[3].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[3]", fDebug_DistBetween1n4[3], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[4].x", vDebug_AreaBound1[4].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[4].y", vDebug_AreaBound1[4].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[4].z", vDebug_AreaBound1[4].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[4].x", vDebug_AreaBound2[4].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[4].y", vDebug_AreaBound2[4].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[4].z", vDebug_AreaBound2[4].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[4]", fDebug_DistBetween1n4[4], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[5].x", vDebug_AreaBound1[5].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[5].y", vDebug_AreaBound1[5].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[5].z", vDebug_AreaBound1[5].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[5].x", vDebug_AreaBound2[5].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[5].y", vDebug_AreaBound2[5].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[5].z", vDebug_AreaBound2[5].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[5]", fDebug_DistBetween1n4[5], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[6].x", vDebug_AreaBound1[6].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[6].y", vDebug_AreaBound1[6].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[6].z", vDebug_AreaBound1[6].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[6].x", vDebug_AreaBound2[6].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[6].y", vDebug_AreaBound2[6].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[6].z", vDebug_AreaBound2[6].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[6]", fDebug_DistBetween1n4[6], 0, 1000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[7].x", vDebug_AreaBound1[7].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[7].y", vDebug_AreaBound1[7].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound1[7].z", vDebug_AreaBound1[7].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[7].x", vDebug_AreaBound2[7].x, -4000, 4000, 0.001)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[7].y", vDebug_AreaBound2[7].y, -4000, 4000, 0.1)
ADD_WIDGET_FLOAT_SLIDER("vDebug_AreaBound2[7].z", vDebug_AreaBound2[7].z, -10, 200, 0.1)
ADD_WIDGET_FLOAT_SLIDER("fDebug_DistBetween1n4[7]", fDebug_DistBetween1n4[7], 0, 1000, 0.1)
STOP_WIDGET_GROUP()
ENDPROC
/// PURPOSE:
/// not sure - maybe custom area checks?
PROC DEBUG_UPDATE_AREA_WIDGETS()
INT i
VECTOR vInput = <<0,0,0>>
REPEAT 8 i
IF VDIST(vDebug_AreaBound1[i], vDebug_AreaBound2[i]) > 0
DRAW_DEBUG_LINE(vDebug_AreaBound1[i], vDebug_AreaBound2[i])
ENDIF
ENDREPEAT
IF IS_COORD_IN_SPECIFIED_AREA(vInput, AC_PRISON)
ENDIF
IF bDebug_Point1
vDebug_AreaBound1[iDebug_CurrentArea] = GET_SCRIPT_MOUSE_POINTER_IN_WORLD_COORDS()
ELSE
vDebug_AreaBound2[iDebug_CurrentArea] = GET_SCRIPT_MOUSE_POINTER_IN_WORLD_COORDS()
ENDIF
IF bDebug_OutputText
i=0
OPEN_DEBUG_FILE()
REPEAT 8 i
SAVE_NEWLINE_TO_DEBUG_FILE()
SAVE_STRING_TO_DEBUG_FILE("BOOL vDebug_AreaBound1[")
SAVE_INT_TO_DEBUG_FILE(i)
SAVE_STRING_TO_DEBUG_FILE("] = ")
SAVE_VECTOR_TO_DEBUG_FILE(vDebug_AreaBound1[i])
SAVE_NEWLINE_TO_DEBUG_FILE()
SAVE_NEWLINE_TO_DEBUG_FILE()
SAVE_STRING_TO_DEBUG_FILE("BOOL vDebug_AreaBound2[")
SAVE_INT_TO_DEBUG_FILE(i)
SAVE_STRING_TO_DEBUG_FILE("] = ")
SAVE_VECTOR_TO_DEBUG_FILE(vDebug_AreaBound2[i])
SAVE_NEWLINE_TO_DEBUG_FILE()
SAVE_NEWLINE_TO_DEBUG_FILE()
SAVE_STRING_TO_DEBUG_FILE("FLOAT fDebug_DistBetween1n4[")
SAVE_INT_TO_DEBUG_FILE(i)
SAVE_STRING_TO_DEBUG_FILE("] = ")
SAVE_FLOAT_TO_DEBUG_FILE(fDebug_DistBetween1n4[i])
SAVE_NEWLINE_TO_DEBUG_FILE()
ENDREPEAT
CLOSE_DEBUG_FILE()
bDebug_OutputText = FALSE
ENDIF
ENDPROC
/// PURPOSE:
/// used to draw the taxi's pull over to pick up player info
/// PARAMS:
/// vParkCoords - place parking at
/// vOppositeSideCoords - position selected as side of the road
/// vNodeCoords - the node coords
PROC DEBUG_DRAW_TAXI_PULL_OVER_INFO(VECTOR vParkCoords, VECTOR vOppositeSideCoords, VECTOR vNodeCoords)
IF bDebug_DrawGetPullOverResults
INT iTempTime = GET_GAME_TIMER()
WHILE (GET_GAME_TIMER() - iTempTime) < 3000
SET_DEBUG_ACTIVE(TRUE)
SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE)
DRAW_DEBUG_SPHERE(vParkCoords, 2.5, 128, 255, 0, 150) // green
DRAW_DEBUG_SPHERE(vOppositeSideCoords, 2.5, 255, 0, 0, 150) // red
DRAW_DEBUG_SPHERE(vNodeCoords, 1.5, 178, 0, 255, 150) // purple
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : bDebug_DrawGetPullOverResults this frame green = park, purple = node, red = opposite side ")
WAIT(0)
ENDWHILE
ENDIF
ENDPROC
#ENDIF
/// PURPOSE:
/// Checks if the entity exists and is not dead.
/// PARAMS:
/// mEntity - the entity we are checking.
/// RETURNS:
/// True if the entity exists and is not dead.
FUNC BOOL IS_ENTITY_ALIVE(ENTITY_INDEX mEntity)
IF DOES_ENTITY_EXIST(mEntity)
IF NOT IS_ENTITY_DEAD(mEntity)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks that the ped exists, is alive and is not injured
/// PARAMS:
/// mPed - the ped we are checking
/// RETURNS:
/// True if the ped exists, is alive and is not injured. false otherwise.
FUNC BOOL IS_PED_UNINJURED(PED_INDEX mPed)
IF DOES_ENTITY_EXIST(mPed)
IF NOT IS_ENTITY_DEAD(mPed)
IF NOT IS_PED_INJURED(mPed)
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks that the vehicle exists, is alive, driveable and not on fire
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// RETURNS:
/// True if the vehicle exists, is alive, driveable and not on fire. false otherwise.
FUNC BOOL IS_VEHICLE_OK(VEHICLE_INDEX mVehicle)
IF IS_ENTITY_ALIVE(mVehicle)
IF IS_VEHICLE_DRIVEABLE(mVehicle)
IF NOT IS_ENTITY_ON_FIRE(mVehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// check if iTimeAmount has passed since iTimer was set
/// PARAMS:
/// iTimer - the timer
/// iTimeAmount - the amount of time to check has passed
/// RETURNS:
/// True is the specified amount of time has passed for the specified timer.
FUNC BOOL HAS_TIME_PASSED(INT iTimer, INT iTimeAmount)
RETURN (GET_GAME_TIMER() - iTimer) > iTimeAmount
ENDFUNC
/// PURPOSE:
/// blocks specific player controls relating to weapon equip swap, to be called during hail animations
/// Implemented for B*2074743 - block aiming during hail animation
PROC DISABLE_PLAYER_WEAPON_CONTROLS_FOR_HAIL_THIS_FRAME()
// B*2074743 - block aiming during hail animation
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_NEXT_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_PREV_WEAPON)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_UD)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_WEAPON_WHEEL_LR)
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, TRUE)
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISABLE_PLAYER_WEAPON_CONTROLS_FOR_HAIL_THIS_FRAME : ", GET_FRAME_COUNT())
ENDPROC
/// PURPOSE:
/// used to toggle the ped config flag PCF_AICanDrivePlayerAsRearPassenger of the taxi driver of the vehicleIndex
/// this is needed to allow the player to enter as passenger with input press. Input hold will jack the driver
/// PARAMS:
/// vehicleIndex - vehicle of driver to have flag updated
/// bSetActive - if flag is going to be set active or off
PROC SET_TAXI_DRIVER_ENTER_AS_PASSENGER_FLAG(VEHICLE_INDEX &vehicleIndex, BOOL bSetActive)
IF DOES_ENTITY_EXIST(vehicleIndex)
IF IS_VEHICLE_DRIVEABLE(vehicleIndex)
PED_INDEX pedIndex = GET_PED_IN_VEHICLE_SEAT(vehicleIndex)
IF DOES_ENTITY_EXIST(pedIndex)
IF IS_PED_MODEL(pedIndex, GET_TAXI_DRIVER_MODEL())
IF NOT IS_PED_INJURED(pedIndex)
// B*1536974 - Press to enter taxi as passenger hold to jack driver - opposite to how it worked on IV
// to get IV behaviour you have to ensur this flag is false then task the player in script to enter as rear passenger when input detected
SET_PED_CONFIG_FLAG(pedIndex, PCF_AICanDrivePlayerAsRearPassenger, bSetActive)
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SET_TAXI_DRIVER_ENTER_AS_PASSENGER_FLAG() - set : ", bSetActive) ENDIF #ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// get the vehicle seat player should be aiming for based on where they are and if the entry point is clear
/// RETURNS:
/// VEHICLE_SEAT to use in the TASK_ENTER_VEHICLE task along with direct entry
/// returns VS_ANY_PASSENGER if neither of the rear seats are ok to use
FUNC VEHICLE_SEAT GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT(VEHICLE_INDEX &vehIndexTaxi, VECTOR vTempPlayerPosition)
BOOL bUseLeftEntry = TRUE
VEHICLE_SEAT eTempSeat = VS_BACK_LEFT
PED_INDEX pedTempInSeat
IF (TAXI_GET_SIDE_COORDS_IS_TO_ENTITY(vehIndexTaxi, GET_ENTITY_COORDS(vehIndexTaxi, FALSE), vTempPlayerPosition) = 1)
bUseLeftEntry = FALSE
eTempSeat = VS_BACK_RIGHT
ENDIF
// attempt to enter the prefered side
IF IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), vehIndexTaxi, eTempSeat, TRUE, bUseLeftEntry)
IF IS_VEHICLE_SEAT_FREE(vehIndexTaxi, eTempSeat)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : closest side seat empty selected : seat = ", eTempSeat)
RETURN eTempSeat
ELSE
pedTempInSeat = GET_PED_IN_VEHICLE_SEAT(vehIndexTaxi, eTempSeat)
IF DOES_ENTITY_EXIST(pedTempInSeat)
IF NOT (pedTempInSeat = PLAYER_PED_ID())
// don't jake group members
IF NOT IS_PED_GROUP_MEMBER(pedTempInSeat, PLAYER_GROUP_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : closest side seat occupied selected : seat = ", eTempSeat)
RETURN eTempSeat
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : closest side seat rejected for group member in seat selected : seat = ", eTempSeat)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// back up attempt to enter from opposite side
IF bUseLeftEntry
bUseLeftEntry = FALSE
eTempSeat = VS_BACK_RIGHT
ELSE
bUseLeftEntry = TRUE
eTempSeat = VS_BACK_LEFT
ENDIF
IF IS_ENTRY_POINT_FOR_SEAT_CLEAR(PLAYER_PED_ID(), vehIndexTaxi, eTempSeat, TRUE, bUseLeftEntry)
IF IS_VEHICLE_SEAT_FREE(vehIndexTaxi, eTempSeat)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : far side seat empty selected : seat = ", eTempSeat)
RETURN eTempSeat
ELSE
pedTempInSeat = GET_PED_IN_VEHICLE_SEAT(vehIndexTaxi, eTempSeat)
IF DOES_ENTITY_EXIST(pedTempInSeat)
IF NOT (pedTempInSeat = PLAYER_PED_ID())
// don't jake group members
IF NOT IS_PED_GROUP_MEMBER(pedTempInSeat, PLAYER_GROUP_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : far side seat occupied selected : seat = ", eTempSeat)
RETURN eTempSeat
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_PLAYER_PREFERRED_REAR_PASSENGER_SEAT : far side seat rejected for group member in seat selected : seat = ", eTempSeat)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN VS_ANY_PASSENGER
ENDFUNC
/// PURPOSE:
/// create the waiting taxi blip for g_WaitingTaxi
PROC CREATE_WAITING_TAXI_BLIP()
IF DOES_BLIP_EXIST(blipWaitingTaxi)
SET_BLIP_ROUTE(blipWaitingTaxi, FALSE)
REMOVE_BLIP(blipWaitingTaxi)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : CREATE_WAITING_TAXI_BLIP() : blip already existed removed")
ENDIF
IF IS_VEHICLE_OK(g_WaitingTaxi)
IF NOT DOES_BLIP_EXIST(blipWaitingTaxi)
blipWaitingTaxi = ADD_BLIP_FOR_ENTITY(g_WaitingTaxi)
SET_BLIP_SPRITE(blipWaitingTaxi, RADAR_TRACE_TAXI)
SET_BLIP_NAME_FROM_TEXT_FILE(blipWaitingTaxi, "TXM_BLIP")
SET_BLIP_FLASHES(blipWaitingTaxi, TRUE)
SET_BLIP_FLASH_TIMER(blipWaitingTaxi, 10000)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : CREATE_WAITING_TAXI_BLIP() : blip added to g_WaitingTaxi")
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// returns the search flags used for getting closest taxi
/// RETURNS:
/// INT bit set value
FUNC INT GET_TAXI_SEARCH_FLAGS()
RETURN (VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES |
VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES |
VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_CONTAINING_GROUP_MEMBERS |
VEHICLE_SEARCH_FLAG_RETURN_VEHICLES_WITH_PEDS_ENTERING_OR_EXITING |
VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK)
ENDFUNC
/// PURPOSE:
/// Cleanup the process enter closest taxi
PROC CLEANUP_ENTER_CLOSEST_TAXI()
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_ENTERING
SET_PLAYER_CAN_DO_DRIVE_BY(PLAYER_ID(), TRUE)
CANCEL_GROUP_GETTING_INTO_CAB()
ELIF eEnterTaxiState = TL_ENTER_TAXI_STATE_INSIDE
IF HAS_SCRIPT_LOADED("taxiService")
SET_SCRIPT_AS_NO_LONGER_NEEDED("taxiService")
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : CLEANUP_ENTER_CLOSEST_TAXI eEnterTaxiState was TL_ENTER_TAXI_STATE_ENTERING - ET_SCRIPT_AS_NO_LONGER_NEEDED(taxiService)") ENDIF #ENDIF
ENDIF
SET_PLAYER_CAN_DO_DRIVE_BY(PLAYER_ID(), TRUE)
CANCEL_GROUP_GETTING_INTO_CAB()
ENDIF
CLEANUP_WAITING_TAXI() // handles release of g_WaitingTaxi and g_WaitingTaxiDriver
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_ENTER_CLOSEST_TAXI() : called CLEANUP_WAITING_TAXI()")
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TX_H02") // Hold ~INPUT_ENTER~ to enter the cab as a passenger.
CLEAR_HELP(TRUE)
ENDIF
iTimer_DelayTaxiSearch = 0 //reset
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : CLEANUP_ENTER_CLOSEST_TAXI() : eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE") ENDIF #ENDIF
ENDPROC
/// PURPOSE:
/// Cleanup the process hail taxi
PROC CLEANUP_HAIL_TAXI()
// stop scripted player anims
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
STOP_ENTITY_ANIM(PLAYER_PED_ID(), "HAIL_TAXI", tlTaxiAnimDict, REALLY_SLOW_BLEND_OUT)
ELIF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
STOP_ENTITY_ANIM(PLAYER_PED_ID(), "FP_HAIL_TAXI", tlTaxiAnimDict, REALLY_SLOW_BLEND_OUT)
ELIF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FUCK_U")
STOP_ENTITY_ANIM(PLAYER_PED_ID(), "FUCK_U", tlTaxiAnimDict, REALLY_SLOW_BLEND_OUT)
ELIF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FORGET_IT")
STOP_ENTITY_ANIM(PLAYER_PED_ID(), "FORGET_IT", tlTaxiAnimDict, REALLY_SLOW_BLEND_OUT)
ENDIF
// B*1515351 - SET_PED_CONFIG_FLAG needs alive check
IF iTaxiHailIntention != NEW_CONTEXT_INTENTION
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, FALSE)
ENDIF
// B*1991223 - RESET need to block ambient anims during hail anims
IF bBlockingPlayerAmbientIdles = TRUE
SET_PED_CAN_PLAY_AMBIENT_ANIMS(PLAYER_PED_ID(), TRUE)
bBlockingPlayerAmbientIdles = FALSE
ENDIF
ENDIF
REMOVE_ANIM_DICT(tlTaxiAnimDict)
IF iTaxiHailIntention != NEW_CONTEXT_INTENTION
RELEASE_CONTEXT_INTENTION(iTaxiHailIntention)
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TXM_H01") // Press ~INPUT_CONTEXT~ to hail a Taxi.
iHailPromptCounter++
IF iHailPromptCounter = 3
g_savedGlobals.sAmbient.bTaxiHailingHelpDisplayed = TRUE
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_HAIL_TAXI() : g_savedGlobals.sAmbient.bTaxiHailingHelpDisplayed = TRUE") ENDIF #ENDIF
ENDIF
CLEAR_HELP(TRUE)
ENDIF
IF DOES_BLIP_EXIST(blipWaitingTaxi)
SET_BLIP_ROUTE(blipWaitingTaxi, FALSE)
REMOVE_BLIP(blipWaitingTaxi)
ENDIF
IF bHintTriggeredByTaxiLauncher
IF IS_GAMEPLAY_HINT_ACTIVE()
STOP_GAMEPLAY_HINT()
ENDIF
ENDIF
// stop his aknowledge anims
IF DOES_ENTITY_EXIST(g_WaitingTaxiDriver)
IF NOT IS_PED_INJURED(g_WaitingTaxiDriver)
IF IS_ENTITY_PLAYING_ANIM(g_WaitingTaxiDriver, tlTaxiAnimDict, "Aknowledge_R")
STOP_ENTITY_ANIM(g_WaitingTaxiDriver, "Aknowledge_R", tlTaxiAnimDict, SLOW_BLEND_OUT)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_HAIL_TAXI() : stopped driver aknowledge anim Aknowledge_R")
ELIF IS_ENTITY_PLAYING_ANIM(g_WaitingTaxiDriver, tlTaxiAnimDict, "Aknowledge_L")
STOP_ENTITY_ANIM(g_WaitingTaxiDriver, "Aknowledge_L", tlTaxiAnimDict, SLOW_BLEND_OUT)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_HAIL_TAXI() : stopped driver aknowledge anim Aknowledge_L")
ENDIF
ENDIF
ENDIF
// don't stomp on the global handle g_WaitingTaxi (if player is entering a taxi)
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
CLEANUP_WAITING_TAXI() // handles release of g_WaitingTaxi and g_WaitingTaxiDriver
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_HAIL_TAXI() : called CLEANUP_WAITING_TAXI()")
ENDIF
vehHailTarget = NULL
bPlayAdditionalFuckYouDialogue = FALSE
bHintTriggeredByTaxiLauncher = FALSE
iTimer_HailAnimTriggered = 0
iTimer_HailFailedDialogueDelay = 0
g_iTaxiHailedTime = -1
eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : CLEANUP_HAIL_TAXI() : eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE") ENDIF #ENDIF
ENDPROC
/// PURPOSE:
/// clear all the dispatched taxi data struct
PROC CLEANUP_DISPATCHED_TAXI_DATA()
// set driver's behaviour and release
IF DOES_ENTITY_EXIST(sDispatchedTaxi.pedIndex)
IF DOES_ENTITY_BELONG_TO_THIS_SCRIPT(sDispatchedTaxi.pedIndex, FALSE)
// don't stomp on the global handle
IF sDispatchedTaxi.pedIndex != g_WaitingTaxiDriver
IF NOT IS_PED_INJURED(sDispatchedTaxi.pedIndex)
// RESET FLAG for cleanup B*1536974 - Press to enter taxi as passenger hold to jack driver - opposite to how it worked on IV
// to get IV behaviour you have to ensur this flag is false then task the player in script to enter as rear passenger when input detected
SET_PED_CONFIG_FLAG(sDispatchedTaxi.pedIndex, PCF_AICanDrivePlayerAsRearPassenger, FALSE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sDispatchedTaxi.pedIndex, FALSE)
IF NOT IS_PED_FLEEING(sDispatchedTaxi.pedIndex)
AND NOT IS_PED_IN_COMBAT(sDispatchedTaxi.pedIndex)
IF IS_PED_IN_ANY_VEHICLE(sDispatchedTaxi.pedIndex)
IF DOES_ENTITY_EXIST(sDispatchedTaxi.vehicleIndex)
IF IS_VEHICLE_DRIVEABLE(sDispatchedTaxi.vehicleIndex)
IF IS_PED_SITTING_IN_VEHICLE(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex)
SEQUENCE_INDEX seq
OPEN_SEQUENCE_TASK(seq)
// if any of the players buddies are in the taxi then wait for then to get out
IF NOT IS_VEHICLE_SEAT_FREE(sDispatchedTaxi.vehicleIndex, VS_BACK_LEFT)
OR NOT IS_VEHICLE_SEAT_FREE(sDispatchedTaxi.vehicleIndex, VS_BACK_RIGHT)
OR NOT IS_VEHICLE_SEAT_FREE(sDispatchedTaxi.vehicleIndex, VS_FRONT_RIGHT)
TASK_PAUSE(NULL, 2000)
ELSE
TASK_PAUSE(NULL, 500)
ENDIF
TASK_VEHICLE_DRIVE_WANDER(NULL, sDispatchedTaxi.vehicleIndex, 12.0, DRIVINGMODE_STOPFORCARS | DF_AvoidRestrictedAreas)
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(sDispatchedTaxi.pedIndex, seq)
CLEAR_SEQUENCE_TASK(seq)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA() : tasked sDispatchedTaxi.pedIndex to TASK_VEHICLE_DRIVE_WANDER")
ELSE
TASK_SMART_FLEE_PED(sDispatchedTaxi.pedIndex, PLAYER_PED_ID(), 500, -1)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA() : tasked sDispatchedTaxi.pedIndex driver to flee as not sat in sDispatchedTaxi.vehicleIndex")
ENDIF
ELSE
TASK_SMART_FLEE_PED(sDispatchedTaxi.pedIndex, PLAYER_PED_ID(), 500, -1)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA() : tasked sDispatchedTaxi.pedIndex driver to flee as sDispatchedTaxi.vehicleIndex was not driverable")
ENDIF
ENDIF
ELSE
// just walk off not fleeing but on foot
TASK_WANDER_STANDARD(sDispatchedTaxi.pedIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA() : tasked sDispatchedTaxi.pedIndex to TASK_WANDER_STANDARD on foot")
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA() : NOT tasked sDispatchedTaxi.pedIndex since IS_PED_FLEEING / combat returned TRUE")
ENDIF
ENDIF
// release assets
SET_MODEL_AS_NO_LONGER_NEEDED(GET_ENTITY_MODEL(sDispatchedTaxi.pedIndex))
SET_PED_AS_NO_LONGER_NEEDED(sDispatchedTaxi.pedIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA : set sDispatchedTaxi.pedIndex model and vehicle as no longer needed")
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA : sDispatchedTaxi.pedIndex = g_WaitingTaxiDriver so not released entity and model")
ENDIF
ENDIF
ENDIF
// release vehicle handle
IF DOES_ENTITY_EXIST(sDispatchedTaxi.vehicleIndex)
IF DOES_ENTITY_BELONG_TO_THIS_SCRIPT(sDispatchedTaxi.vehicleIndex, FALSE)
// don't stomp on the global handle
IF sDispatchedTaxi.vehicleIndex != g_WaitingTaxi
//SET_MODEL_AS_NO_LONGER_NEEDED(ENTITY_MODEL(sDispatchedTaxi.vehicleIndex))
SET_VEHICLE_AS_NO_LONGER_NEEDED(sDispatchedTaxi.vehicleIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA : set sDispatchedTaxi.vehicleIndex as no longer needed")
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " CLEANUP_DISPATCHED_TAXI_DATA : sDispatchedTaxi.vehicleIndex = g_WaitingTaxi so not released entity and model")
ENDIF
ENDIF
ENDIF
// release asset requests
IF eDispatchedTaxiState = TL_DISPATCHED_STATE_CREATE_TAXI
SET_MODEL_AS_NO_LONGER_NEEDED(mnTaxiModel)
SET_MODEL_AS_NO_LONGER_NEEDED(mnTaxiDriverModel)
ENDIF
// reset struct vars
sDispatchedTaxi.vehicleIndex = NULL
sDispatchedTaxi.pedIndex = NULL
sDispatchedTaxi.bHasActiveTask = FALSE
sDispatchedTaxi.bForcedPullOverAtCurrentPosition = FALSE
sDispatchedTaxi.fDistToTarget = 0
sDispatchedTaxi.fDriveToHeading = 0
sDispatchedTaxi.fTargetReached = 45.0
sDispatchedTaxi.iNodeSearchNumber = 0
sDispatchedTaxi.iSpawnAttempts = 0
sDispatchedTaxi.iTimer_TaxiDispatchDelay = 0
sDispatchedTaxi.vDistToPlayer = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.vDriveToCoords = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.vPullOverCoords = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.vPlayerCalledCoords = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.vPathNodeRequestMin = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.vPathNodeRequestMax = << 0.0, 0.0, 0.0 >>
sDispatchedTaxi.taxiDrivingModeStandard = DF_SteerAroundStationaryCars|DF_StopForPeds|DF_StopAtLights|DF_ChangeLanesAroundObstructions|DF_StopForCars|DF_ForceJoinInRoadDirection|DF_SteerAroundObjects|DF_UseSwitchedOffNodes|DF_AvoidRestrictedAreas
sDispatchedTaxi.eCharDispatchedFor = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE()
// reset state machine
eDispatchedTaxiState = TL_DISPATCHED_STATE_IDLE
ENDPROC
/// PURPOSE:
/// resets the taxi launcher and sets eTaxiLauncherState = TL_STATE_IDLE
/// PURPOSE:
/// reset everything in the script
/// PARAMS:
/// bResetLauncherState - if TRUE eTaxiLauncherState will get reset to TL_STATE_IDLE
PROC RESET_TAXI_LAUNCHER(BOOL bResetLauncherState = TRUE)
SET_VEHICLE_MODEL_IS_SUPPRESSED(TAXI, FALSE)
CLEANUP_DISPATCHED_TAXI_DATA()
CLEANUP_ENTER_CLOSEST_TAXI()
CLEANUP_HAIL_TAXI()
// expect there will be other variables i'll need to reset here as and when i find them
bUpdateHailTargetThisFrame = TRUE
bHintTriggeredByTaxiLauncher = FALSE
eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
eDispatchedTaxiState = TL_DISPATCHED_STATE_IDLE
eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
iTimer_DelayTaxiSearch = 0
IF bResetLauncherState
eTaxiLauncherState = TL_STATE_IDLE
ENDIF
ENDPROC
/// PURPOSE:
/// cleanup for the script
PROC TAXI_LAUNCHER_SCRIPT_CLEANUP()
CLEANUP_WAITING_TAXI() // handles release of g_WaitingTaxi and g_WaitingTaxiDriver
RESET_TAXI_LAUNCHER()
REMOVE_ANIM_DICT(tlTaxiAnimDict)
SET_VEHICLE_MODEL_IS_SUPPRESSED(TAXI, FALSE)
SET_MODEL_AS_NO_LONGER_NEEDED(mnTaxiModel)
SET_MODEL_AS_NO_LONGER_NEEDED(mnTaxiDriverModel)
IF bHintTriggeredByTaxiLauncher
IF IS_GAMEPLAY_HINT_ACTIVE()
STOP_GAMEPLAY_HINT()
ENDIF
ENDIF
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " TAXI_LAUNCHER_SCRIPT_CLEANUP() : done")
ENDPROC
/// PURPOSE:
/// queries if g_CustomDropOffBlip exists
PROC MONITOR_CUSTOM_DROP_OFF_BLIP()
IF g_fTaxiDropOffHeading <> 0
IF DOES_BLIP_EXIST(g_CustomDropOffBlip)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : MONITOR_CUSTOM_DROP_OFF_BLIP() g_CustomDropOffBlip exists")
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : MONITOR_CUSTOM_DROP_OFF_BLIP() set g_CustomDropOffBlip doesn't exists")
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// sets dialogue info for the current player ped
PROC IDENTIFY_PLAYER()
enumCharacterList eCurrentPlayerChar = GET_CURRENT_PLAYER_PED_ENUM()
IF eCurrentPlayerChar = CHAR_MICHAEL
playerVoice = "MICHAEL"
playerLine1 = "TX_1M"
playerLine3 = "TX_3M"
ELIF eCurrentPlayerChar = CHAR_FRANKLIN
playerVoice = "FRANKLIN"
playerLine1 = "TX_1F"
playerLine3 = "TX_3F"
ELIF eCurrentPlayerChar = CHAR_TREVOR
playerVoice = "TREVOR"
playerLine1 = "TX_1T"
playerLine3 = "TX_3T"
ENDIF
ENDPROC
/// PURPOSE:
/// checks for the player being allowed to enter a taxi as a passenger
/// RETURNS:
/// TRUE if player is allowed to enter as a passenger
FUNC BOOL IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER()
// check global flags for being allowed taxi rides
IF NOT IS_PLAYER_ALLOWED_TO_RIDE_IN_TAXIS()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER() - return FALSE - IS_PLAYER_ALLOWED_TO_RIDE_IN_TAXIS") ENDIF #ENDIF
RETURN FALSE
ENDIF
/* already gets tested in
// check player isn't injured
IF IS_PED_INJURED(PLAYER_PED_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER() - return FALSE - IS_PED_INJURED(PLAYER_PED_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF */
// check the player has control
IF NOT IS_PLAYER_PLAYING(PLAYER_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER() - return FALSE - IS_PLAYER_PLAYING(PLAYER_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF
// check for player being wanted
IF IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER() - return FALSE - IS_PLAYER_WANTED_LEVEL_GREATER(PLAYER_ID(), 0)") ENDIF #ENDIF
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// checks for the player being allowed to hail a taxi
/// RETURNS:
/// TRUE if player is allowed to hail a taxi
FUNC BOOL IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI()
// don't allow player to hail a whilst getting in one
IF eEnterTaxiState != TL_ENTER_TAXI_STATE_IDLE
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - eEnterTaxiState != TL_ENTER_TAXI_STATE_IDLE") ENDIF #ENDIF
RETURN FALSE
ENDIF
// don't allow hail if player has an ambient task
// apparently checks climbing, on ladders, current task is idle, combat, jumping, shooting
IF NOT IS_PLAYER_FREE_FOR_AMBIENT_TASK(PLAYER_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PLAYER_FREE_FOR_AMBIENT_TASK(PLAYER_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF
// aim a weapon
IF IS_PLAYER_FREE_AIMING(PLAYER_ID())
OR IS_PLAYER_TARGETTING_ANYTHING(PLAYER_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PLAYER_FREE_AIMING(PLAYER_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF
// in the air
IF IS_ENTITY_IN_AIR(PLAYER_PED_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_ENTITY_IN_AIR(PLAYER_PED_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF
// falling over (exclude drunk for some reason?)
IF NOT g_playerIsDrunk
AND IS_PED_RAGDOLL(PLAYER_PED_ID())
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PED_RAGDOLL(PLAYER_PED_ID())") ENDIF #ENDIF
RETURN FALSE
ENDIF
// already inside a vehicle
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)") ENDIF #ENDIF
RETURN FALSE
ENDIF
// don't allow hail whilst phone is on screen
IF IS_PHONE_ONSCREEN()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PHONE_ONSCREEN()") ENDIF #ENDIF
RETURN FALSE
ENDIF
// is internet on screen
IF IS_BROWSER_OPEN()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE -IS_BROWSER_OPEN()") ENDIF #ENDIF
RETURN FALSE
ENDIF
// if player is shopping
IF IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()") ENDIF #ENDIF
RETURN FALSE
ENDIF
// custom menu active
IF IS_CUSTOM_MENU_ON_SCREEN()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_CUSTOM_MENU_ON_SCREEN()") ENDIF #ENDIF
RETURN FALSE
ENDIF
// don't allow taxis during minigames
IF IS_MINIGAME_IN_PROGRESS()
#IF IS_DEBUG_BUILD IF bDebug_DisplayCleanupTTY CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI() - return FALSE - IS_MINIGAME_IN_PROGRESS()") ENDIF #ENDIF
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// checks for the player being allowed to call a taxi
/// RETURNS:
/// TRUE if player is allowed a taxi
FUNC BOOL IS_PLAYER_ALLOWED_TO_CALL_TAXI()
// check if a dispatched taxi is already on route to the player
IF eDispatchedTaxiState != TL_DISPATCHED_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - eDispatchedTaxiState check")
RETURN FALSE
ENDIF
// don't allow a taxi to be dispatched if player has a hailed taxi waiting
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
OR eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - eHailTaxiState check")
RETURN FALSE
ENDIF
// check if a enter taxi state is idle (player isn't currently getting in a taxi)
IF eEnterTaxiState != TL_ENTER_TAXI_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - eEnterTaxiState check")
RETURN FALSE
ENDIF
// check the player isn't currently in a taxi journey
IF IS_THREAD_ACTIVE(tTaxiServiceThread)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - IS_THREAD_ACTIVE(tTaxiServiceThread)")
RETURN FALSE
ENDIF
// check the player isn't already in a taxi
IF NOT IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER()
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER")
RETURN FALSE
ENDIF
// test for player being in the air (presumably to prevent calls during flights
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF IS_ENTITY_IN_AIR(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return FALSE - IS_ENTITY_IN_AIR whilst in VEHICLE")
RETURN FALSE
ENDIF
ENDIF
IS_PLAYER_IN_ANY_COMMUNICATION_RESTRICTED_AREAS()
// ideally perform GET_TAXI_PICK_UP_PLAYER_DESTINATION now and store the pickup position ready
// that way if it was unable to get a position the tdispatch service could decline the call
// check player is close to the road network
VECTOR vNode
FLOAT fDistMinFromNode = 50.0
// always search switched off nodes, but if we are in the city ensure they aren't dead ends (stop taxi using driveways).
NODE_FLAGS nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES
IF NOT IS_POSITION_IN_ZONE_SAFE_FOR_DEADEND_NODES(vPlayerPos)
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() : using node flags NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS")
ENDIF
IF NOT GET_CLOSEST_VEHICLE_NODE(vPlayerPos, vNode, nodeFlags, 100.0, 2.5)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() : return FALSE - failed to find closest valid node nearby :", vPlayerPos)
RETURN FALSE
ENDIF
IF NOT IS_ENTITY_AT_COORD(PLAYER_PED_ID(), vNode, <<fDistMinFromNode, fDistMinFromNode, 20.0>>)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() : return FALSE - player more than ", fDistMinFromNode, " away from closest valid node")
RETURN FALSE
ENDIF
/*VEHICLE_NODE_ID tempVehNodeID = GET_NTH_CLOSEST_VEHICLE_NODE_ID(vNode, 1, nodeFlags)
IF IS_VEHICLE_NODE_ID_VALID(tempVehNodeID)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() : return FALSE - no valid node nearby")
RETURN FALSE
ENDIF*/
// make sure he's not calling from an inaccessible area
IF IS_POSITION_IN_TAXI_RESTRICTED_AREA(vPlayerPos, TRUE)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() : return FALSE - IS_POSITION_IN_TAXI_RESTRICTED_AREA check")
RETURN FALSE
ENDIF
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : IS_PLAYER_ALLOWED_TO_CALL_TAXI() - return TRUE")
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// check if the taxi service is listed for the player to call
/// PARAMS:
/// ePlayer - the player to check, passing GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() will test all players and return TRUE if one of them have the taxi listed
/// RETURNS:
/// TRUE if specified char has taxi listed (if GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE() parameter return TRUE if any of them have listed)
FUNC BOOL IS_TAXI_SERVICE_LISTED_IN_PLAYERS_PHONEBOOK(enumCharacterList ePlayer = MAX_CHARACTERS)
IF ePlayer = CHAR_MICHAEL
OR ePlayer = CHAR_FRANKLIN
OR ePlayer = CHAR_TREVOR
IF (GLOBAL_CHARACTER_SHEET_GET_PHONEBOOK_STATE(CHAR_TAXI, ENUM_TO_INT(ePlayer))= LISTED)
RETURN TRUE
ENDIF
ELIF ePlayer = GLOBAL_CHARACTER_SHEET_GET_MAX_CHARACTERS_FOR_GAMEMODE()
IF (GLOBAL_CHARACTER_SHEET_GET_PHONEBOOK_STATE(CHAR_TAXI, ENUM_TO_INT(CHAR_MICHAEL)) = LISTED
OR GLOBAL_CHARACTER_SHEET_GET_PHONEBOOK_STATE(CHAR_TAXI, ENUM_TO_INT(CHAR_FRANKLIN)) = LISTED
OR GLOBAL_CHARACTER_SHEET_GET_PHONEBOOK_STATE(CHAR_TAXI, ENUM_TO_INT(CHAR_TREVOR)) = LISTED)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// updates fDropOffDistFromBlip used to check player leaving pulled up taxi
/// PARAMS:
/// vDestinationCoord - the place the taxi is supposed to reach
/// vPullOverCoord - the actual position the taxi pulled up
FUNC FLOAT GET_DIST_BETWEEN_VECTORS_NONE_Z(VECTOR vDestinationCoord, VECTOR vPullOverCoord)
VECTOR vDiff_Destination_To_ReturnNode
vDiff_Destination_To_ReturnNode = vDestinationCoord - vPullOverCoord
vDiff_Destination_To_ReturnNode.z = 0.0
RETURN VMAG(vDiff_Destination_To_ReturnNode)
ENDFUNC
/// PURPOSE:
/// generate a positin and heading which will lead the taxi along the path nodes to the player's position
/// shouldn't need to load the path nodes prior to the checks on this one, since the spawn dist should easliy be with in 400m loaded around player
/// PARAMS:
/// vSpawnPos - the positio to set value returned by reference
/// fSpawnHeading - the heading value to be returned by reference
/// iReturnedNodeNumber - return the node number of the last test, used to setup repeat checks
/// nodeFlags - default to NF_INCLUDE_SWITCHED_OFF_NODES
/// fMinSpawnRadius - min dist for spawn point from player
/// RETURNS:
/// TRUE if position and heading were successfully generated
FUNC BOOL GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER(VECTOR &vSpawnPos, FLOAT &fSpawnHeading, INT &iReturnedNodeNumber, NODE_FLAGS nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES, FLOAT fMinSpawnRadius = 25.0)
VECTOR vClosestNodeToPlayer, vGeneratedSpawnPos, vResultLinkDir
FLOAT fGeneratedHeading = 0.0
INT iNumLanes
BOOL bIncludeSwitchedOffNodes = TRUE
IF nodeFlags = NF_NONE
bIncludeSwitchedOffNodes = FALSE
ENDIF
BOOL bGeneratedPositionFound = FALSE
INT iLoopCounter = 0
FLOAT fZ_MeasureMulti = 100.0 // increased as per B*1183689
FLOAT fZ_Tolerance = 2.5 // B*1430520
VECTOR vPosHeadingTest, vOffset1, vOffset2
TAXI_SPECIAL_AREAS_ENUM eSpecialAreaCheck
/*#IF IS_DEBUG_BUILD
VECTOR vSpawnPosWithFavDirection
FLOAT fSpawnHeadingWithFavDirection
#ENDIF*/
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
VECTOR vPlayerCoords = GET_ENTITY_COORDS(PLAYER_PED_ID())
// first check we don't need to force a special spawn position and heading for the taxi if the player is in a special area
eSpecialAreaCheck = GET_TAXI_SPECIAL_AREA_AT_COORDS(vPlayerCoords)
IF eSpecialAreaCheck != TAXI_SPECIAL_AREAS_INVALID
IF GET_TAXI_SPAWN_INFO_FOR_TAXI_SPECIAL_AREA(vPlayerCoords, eSpecialAreaCheck, vSpawnPos, fSpawnHeading)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER special area setup eSpecialAreaCheck = ", eSpecialAreaCheck,
" : vSpawnPos = ", vSpawnPos, " : fSpawnHeading = ", fSpawnHeading, " - return TRUE")
RETURN TRUE
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - GET_TAXI_SPAWN_INFO_FOR_TAXI_SPECIAL_AREA - return FALSE")
ENDIF
ELSE
// first get the closest node to the player's position (using high zMulti) to work from (this should stop spawn issues where different z height nodes are around)
// without it causes bug 1183689 - player is closest to road node above than on the road he's stood on
// so GENERATE_VEHICLE_CREATION_POS_FROM_PATHS returns pos on the roof
IF GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(vPlayerCoords, iReturnedNodeNumber, vClosestNodeToPlayer, fGeneratedHeading, iNumLanes, nodeFlags, fZ_MeasureMulti, fZ_Tolerance)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - gen closest node to player result : vPlayer = ", vPlayerCoords,
" : result vClosestNodeToPlayer = ", vClosestNodeToPlayer, " : node in = ", iReturnedNodeNumber, " : out heading = ", fGeneratedHeading, " : inumlanes = ", iNumLanes)
// 5 chances to get a valid node otherwise bail out
WHILE (NOT bGeneratedPositionFound AND (iLoopCounter < 5))
IF GENERATE_VEHICLE_CREATION_POS_FROM_PATHS(vClosestNodeToPlayer, vGeneratedSpawnPos, vResultLinkDir, 0, 180, fMinSpawnRadius, bIncludeSwitchedOffNodes, TRUE, FALSE)
fGeneratedHeading = TAXI_GET_HEADING_FROM_COORDS(<< 0.0, 0.0, 0.0 >>, vResultLinkDir) // not working reliably so verting back to old setup for now -
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - gen veh creation pos : search pos (vClosestNodeToPlayer) = ", vClosestNodeToPlayer, " : result pos (vGeneratedSpawnPos) = ", vGeneratedSpawnPos,
" : result link direction = ", vResultLinkDir, " fGeneratedHeading = ", fGeneratedHeading)
// check the generated spawn point isn't within a special area
// if so the function will update the spawn pos to use a suitable position
//eSpecialAreaCheck = GET_TAXI_SPECIAL_AREA_AT_COORDS(vPlayerCoords)
//IF ARE_COORDS_IN_SPECIAL_AREA(vGeneratedSpawnPos, vGeneratedSpawnPos, fGeneratedHeading)
// CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " generate creation pos was inside a special area - updated vGeneratedSpawnPos = ", vGeneratedSpawnPos, " updated fGeneratedHeading = ", fGeneratedHeading)
//ENDIF
// check the generated position is safe
IF IS_SPAWN_POSITION_SAFE_FOR_TAXI(vPlayerCoords, vGeneratedSpawnPos)
bGeneratedPositionFound = TRUE
vPosHeadingTest = GET_OFFSET_FROM_COORD_AND_HEADING_IN_WORLD_COORDS(vGeneratedSpawnPos, fGeneratedHeading, <<0.0, 1.0, 0.0>>)
// Vehicle Vector
vOffset1 = vPosHeadingTest - vGeneratedSpawnPos
// Vector to Player
vOffset2 = vClosestNodeToPlayer - vGeneratedSpawnPos
IF (GET_ANGLE_BETWEEN_2D_VECTORS(vOffset1.x, vOffset1.y, vOffset2.x, vOffset2.y) > 60.0)
fGeneratedHeading += 180
fGeneratedHeading = WRAP(fGeneratedHeading, 0, 360)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - revised fGeneratedHeading = ", fGeneratedHeading)
ENDIF
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - update fGeneratedHeading = ", fGeneratedHeading, " vResultLinkDir.Z = ", vResultLinkDir.Z,
" : heading from 2d vector = ", GET_HEADING_FROM_VECTOR_2D(vResultLinkDir.X, vResultLinkDir.Y), " : result link direction = ", vResultLinkDir, " ")
// check the generated spawn point isn't within a special area
//IF ARE_COORDS_IN_SPECIAL_AREA(vGeneratedSpawnPos, vGeneratedSpawnPos, fGeneratedHeading)
// CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - ARE_COORDS_IN_SPECIAL_AREA return TRUE so values updated : vGeneratedSpawnPos = ", vGeneratedSpawnPos, " : fGeneratedHeading = ", fGeneratedHeading)
//ENDIF
/*#IF IS_DEBUG_BUILD
IF GET_NTH_CLOSEST_VEHICLE_NODE_FAVOUR_DIRECTION(vGeneratedSpawnPos, vClosestNodeToPlayer, 0, vSpawnPosWithFavDirection, fSpawnHeadingWithFavDirection, nodeFlags, 1)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - node fav direction would give : ",
" fSpawnHeadingWithFavDirection = ", fSpawnHeadingWithFavDirection, " vSpawnPosWithFavDirection = ", vSpawnPosWithFavDirection)
ENDIF
#ENDIF*/
vSpawnPos = vGeneratedSpawnPos
fSpawnHeading = fGeneratedHeading
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - vSpawnPos = ", vSpawnPos, " : fSpawnHeading = ", fSpawnHeading, " - return TRUE")
RETURN TRUE
ELSE
iLoopCounter++
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER : IS_SPAWN_POSITION_SAFE_FOR_TAXI return FALSE vGeneratedSpawnPos :", vGeneratedSpawnPos, " iLoopCounter = ", iLoopCounter)
ENDIF
ELSE
iLoopCounter++
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - * GENERATE_VEHICLE_CREATION_POS_FROM_PATHS - returned FALSE bIncludeSwitchedOffNodes = ", bIncludeSwitchedOffNodes, " iLoopCounter = ", iLoopCounter)
ENDIF
ENDWHILE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - return FALSE : failed to generate spawn pos from node pos = ", vClosestNodeToPlayer, " iNodeNumber = ", iReturnedNodeNumber)
iReturnedNodeNumber++ // increment for retry next frame
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING to player - return FALSE : iNodeNumber = ", iReturnedNodeNumber)
iReturnedNodeNumber++ // increment for retry next frame
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER - player injured - return FALSE")
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// get a valid node position for the taxi to drive to - handles requesting the path nodes at the position to find a valid node
/// PARAMS:
/// vDestinationCoord - location we want to reach
/// vReturnNodeCoord - the returned coords for the VEHICLE_NODE_ID
/// fReturnHeading - the returned node heading
/// iReturnedNodeNumber - return the node number of the last test, used to setup repeat checks
/// iExtraLoadPathDist - dist around vDestinationCoord to load the path nodes in for the search
/// RETURNS:
/// TRUE if a valid VEHICLE_NODE_ID was found
FUNC BOOL GET_TAXI_PICK_UP_PLAYER_DESTINATION(VECTOR vDestinationCoord, VECTOR &vReturnNodeCoord, FLOAT &fReturnHeading, INT &iReturnedNodeNumber, INT iExtraLoadPathDist = 250)
FLOAT zMeasureMult = 3
FLOAT fZ_Tolerance = 2.5 // B*1430520
FLOAT fTempZDiff
ENTITY_INDEX entityPointObsuredCheck = NULL
INT iNoOfLanes
VEHICLE_NODE_ID tempVehNodeID
INT iMaxNodeLoopChecksPerFrame = iReturnedNodeNumber + 2 // limit checks per frame
INT iMaxNodeLoopChecksInTotal = 50 // don't search past this amount
BOOL bFoundSuitableNode = FALSE
// always search switched off nodes, but if we are in the city ensure they aren't dead ends (stop taxi using driveways).
NODE_FLAGS nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES
IF NOT IS_POSITION_IN_ZONE_SAFE_FOR_DEADEND_NODES(vDestinationCoord)
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : using node flags NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS")
ENDIF
REQUEST_PATH_NODES_IN_AREA_FOR_TAXI_THIS_FRAME(vDestinationCoord, vDestinationCoord, sDispatchedTaxi.vPathNodeRequestMin, sDispatchedTaxi.vPathNodeRequestMax, iExtraLoadPathDist)
IF ARE_REQUEST_PATH_NODES_LOADED_FOR_TAXI(sDispatchedTaxi.vPathNodeRequestMin, sDispatchedTaxi.vPathNodeRequestMax)
IF NOT ARE_COORDS_IN_SPECIAL_AREA(vDestinationCoord, vReturnNodeCoord, fReturnHeading)
// get closest point that is on a road.
// 3 chances to get a valid node otherwise bail out this frame
WHILE (NOT bFoundSuitableNode AND (iReturnedNodeNumber < iMaxNodeLoopChecksPerFrame))
IF vDestinationCoord.z = 1
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : zMeasureMult = 0 ")
zMeasureMult = 0
ENDIF
IF GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(vDestinationCoord, iReturnedNodeNumber, vReturnNodeCoord, fReturnHeading, iNoOfLanes, nodeFlags, zMeasureMult, fZ_Tolerance)
// get the VEHICLE_NODE_ID for returned node positin
tempVehNodeID = GET_NTH_CLOSEST_VEHICLE_NODE_ID(vReturnNodeCoord, 1, nodeFlags)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : vDestinationCoord = ", vDestinationCoord, " iReturnedNodeNumber = ", iReturnedNodeNumber,
" vReturnNodeCoord = ", vReturnNodeCoord, " iNoOfLanes = ", iNoOfLanes)
IF IS_VEHICLE_NODE_ID_VALID(tempVehNodeID)
// Bug fix B*1245895 - check was returning FALSE for coords with same/similar Z value
fTempZDiff = vDestinationCoord.z - vReturnNodeCoord.z
IF fTempZDiff < 0.0
fTempZDiff *= -1.0
ENDIF
IF IS_COORD_ON_SAME_LEVEL_AS_COORD(vDestinationCoord, vReturnNodeCoord)
OR (fTempZDiff < 0.5) // Bug fix B*1245895 - check was returning FALSE for coords with same/similar Z value
IF IS_VEHICLE_DRIVEABLE(sDispatchedTaxi.vehicleIndex)
entityPointObsuredCheck = sDispatchedTaxi.vehicleIndex
ENDIF
//check the position isn't obsured
IF NOT IS_POINT_OBSCURED_BY_A_MISSION_ENTITY(vReturnNodeCoord, <<3,3,3>>, entityPointObsuredCheck)
#IF IS_DEBUG_BUILD
// Spoke with JMart the taxi pathfinding doesn't actually care about GPS being allowed so don't fail the search for GPS not be allowed
IF NOT GET_VEHICLE_NODE_IS_GPS_ALLOWED(tempVehNodeID)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : node GPS not allowed")
ENDIF
// Since we are now using switched off nodes in the searrch don't fail the search for the selected node being switched off
IF NOT GET_VEHICLE_NODE_IS_SWITCHED_OFF(tempVehNodeID)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : node is switched off")
ENDIF
#ENDIF
bFoundSuitableNode = TRUE
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : IS_POINT_OBSCURED_BY_A_MISSION_ENTITY() return TRUE, bFoundSuitableNode = FALSE")
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : IS_COORD_ON_SAME_LEVEL_AS_COORD return FALSE")
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : IS_VEHICLE_NODE_ID_VALID return FALSE")
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING return FALSE")
ENDIF
iReturnedNodeNumber++
// fail safe, don't test past iMaxNodeLoopChecksInTotal
IF (iReturnedNodeNumber >= iMaxNodeLoopChecksInTotal) // don't search past this amount)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : iReturnedNodeNumber = ", iReturnedNodeNumber, " reached max check amount, bFoundSuitableNode = TRUE, FC = ", GET_FRAME_COUNT())
bFoundSuitableNode = TRUE
ENDIF
// debug print to show reached frame loop limit
#IF IS_DEBUG_BUILD
IF (iReturnedNodeNumber > iMaxNodeLoopChecksPerFrame)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : iReturnedNodeNumber = ", iReturnedNodeNumber, " reached max loop check amount this frame FC = ", GET_FRAME_COUNT())
ENDIF
#ENDIF
ENDWHILE
ELSE
// destination in special area
bFoundSuitableNode = TRUE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : ARE_COORDS_IN_SPECIAL_AREA returned TRUE, vDestinationCoord = ", vDestinationCoord, " vReturnNodeCoord = ", vReturnNodeCoord,
" fReturnHeading = ", fReturnHeading)
ENDIF
IF bFoundSuitableNode
sDispatchedTaxi.fDistToTarget = GET_DIST_BETWEEN_VECTORS_NONE_Z(vDestinationCoord, vReturnNodeCoord)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : returning TRUE for vReturnNodeCoord = ", vReturnNodeCoord,
" fReturnHeading = ", fReturnHeading, " sDispatchedTaxi.fDistToTarget = ", sDispatchedTaxi.fDistToTarget)
RETURN TRUE
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PICK_UP_PLAYER_DESTINATION() : returning FALSE")
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// handles taxi driving to the player / or pickup position and detecting when he's close enough to pull over
/// RETURNS:
/// TRUE if he's reached the pickup player location
FUNC BOOL HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER()
VECTOR vTaxiPos
IF NOT sDispatchedTaxi.bHasActiveTask
IF GET_TAXI_PICK_UP_PLAYER_DESTINATION(sDispatchedTaxi.vPlayerCalledCoords, sDispatchedTaxi.vDriveToCoords, sDispatchedTaxi.fDriveToHeading, sDispatchedTaxi.iNodeSearchNumber)
TASK_VEHICLE_DRIVE_TO_COORD(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vDriveToCoords, 12.0, DRIVINGSTYLE_NORMAL, GET_ENTITY_MODEL(sDispatchedTaxi.vehicleIndex), sDispatchedTaxi.taxiDrivingModeStandard, (sDispatchedTaxi.fTargetReached - 20), 20)
//TASK_VEHICLE_MISSION_COORS_TARGET(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vDriveToCoords, MISSION_GOTO, 12.0, taxiDrivingModeStandard, (sDispatchedTaxi.fTargetReached - 20), 20, FALSE)
// B*1329777 - JMart request Can we just use the regular Goto and not Longrange when tasking the taxi to go to the player's position
//TASK_VEHICLE_DRIVE_TO_COORD_LONGRANGE(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vDriveToCoords, 12.0, taxiDrivingModeStandard, sDispatchedTaxi.fTargetReached)
sDispatchedTaxi.bHasActiveTask = TRUE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER() : vehicle task drive coord, sDispatchedTaxi.vDriveToCoords = ", sDispatchedTaxi.vDriveToCoords, " sDispatchedTaxi.fDriveToHeading = ", sDispatchedTaxi.fDriveToHeading)
ENDIF
ELSE
vTaxiPos = GET_ENTITY_COORDS(sDispatchedTaxi.vehicleIndex)
// check to see when the taxi gets with in range
IF TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, sDispatchedTaxi.vDriveToCoords, sDispatchedTaxi.fTargetReached)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER() return TRUE - reached sDispatchedTaxi.vDriveToCoords : ", sDispatchedTaxi.vDriveToCoords)
RETURN TRUE
ELIF TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, vPlayerPos, 5.0)
sDispatchedTaxi.vDriveToCoords = vPlayerPos
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER() return TRUE - reached vPlayerPos : ", vPlayerPos, " so updated sDispatchedTaxi.vDriveToCoords to match")
RETURN TRUE
ELSE
// reapply the drive to task if it failed for some reason
IF NOT TAXI_IS_PED_PERFORMING_TASK(sDispatchedTaxi.pedIndex, SCRIPT_TASK_VEHICLE_DRIVE_TO_COORD)
// B*1329777 - JMart request Can we just use the regular Goto and not Longrange when tasking the taxi to go to the player's position?
//IF NOT TAXI_IS_PED_PERFORMING_TASK(sDispatchedTaxi.pedIndex, SCRIPT_TASK_VEHICLE_DRIVE_TO_COORD_LONGRANGE)
sDispatchedTaxi.bHasActiveTask = FALSE // commented out for now since performing task return false when it shouldn't see B*
sDispatchedTaxi.iNodeSearchNumber = 0 // reset ready for retest
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER() : vehicle task drive coord, failed so set to reapply")
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Tests Z distance between 2 vectors
/// PARAMS:
/// vector1 - pull over position
/// vector2 - road node
/// RETURNS:
/// TRUE if Z difference is greater than 0.45 meters, otherwise FALSE
FUNC BOOL TEST_VECTOR_Z_DIFFERENCE(VECTOR vector1, VECTOR vector2)
IF(vector1.z - vector2.z > 0.45) OR (vector1.z - vector2.z < -0.45)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Z checks taxi pull over position, Finds a valid position for the taxi to stop at, that passes the Z check.
/// PARAMS:
/// vReturnPullOverPosition - the taxi needing to pull over position
/// vNodePosition - closest road node
/// RETURNS:
/// TRUE if Z check failed and another postion had to be found. FALSE, if Z check passed
FUNC BOOL DO_PARK_Z_CHECK(VECTOR &vReturnPullOverPosition, VECTOR vNodePosition)
FLOAT zCoord
IF NOT GET_GROUND_Z_FOR_3D_COORD(<<vReturnPullOverPosition.x,vReturnPullOverPosition.y,1000>>,zCoord)
vReturnPullOverPosition = vNodePosition
RETURN FALSE
ENDIF
VECTOR tempVec = << vReturnPullOverPosition.x, vReturnPullOverPosition.y, zCoord >>
IF TEST_VECTOR_Z_DIFFERENCE(tempVec,vNodePosition)
VECTOR vDirection = (vNodePosition-tempVec)/5.0
INT i
FOR i = 1 TO 5
tempVec = tempVec + vDirection
IF NOT TEST_VECTOR_Z_DIFFERENCE(tempVec,vNodePosition)
vReturnPullOverPosition = tempVec
RETURN TRUE
ENDIF
ENDFOR
vReturnPullOverPosition = vNodePosition
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// get a valid position and heading for the taxi to pull over based from passed in node coords
/// PARAMS:
/// vTaxiCoords - the taxi needing to pull over position
/// vDestinationNodeCoords - the destination node's position
/// fDestinationNodeHeading - the destination node's heading
/// vRetunPullOverPosition - the position the taxi should park
/// fReturnPullOverHeading - the desired heading the taxi should use to park
/// RETURNS:
/// TRUE if a valid positon was found
FUNC BOOL GET_TAXI_PULL_OVER_INFO(VECTOR vTaxiCoords, VECTOR vDestinationNodeCoords, FLOAT fDestinationNodeHeading, VECTOR &vReturnPullOverPosition, FLOAT &fReturnPullOverHeading)
VECTOR vNodePosition
VECTOR vRoadSideForwards
VECTOR vRoadSideBackwards
VEHICLE_NODE_ID tempVehNodeID
// always search switched off nodes, but if we are in the city ensure they aren't dead ends (stop taxi using driveways).
NODE_FLAGS nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES
IF NOT IS_POSITION_IN_ZONE_SAFE_FOR_DEADEND_NODES(vDestinationNodeCoords)
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : using node flags NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS")
ENDIF
// get the VEHICLE_NODE_ID for node position
tempVehNodeID = GET_NTH_CLOSEST_VEHICLE_NODE_ID(vDestinationNodeCoords, 1, nodeFlags)
// check there is a valid vehicle node at the destination
IF IS_VEHICLE_NODE_ID_VALID(tempVehNodeID)
GET_VEHICLE_NODE_POSITION(tempVehNodeID, vNodePosition)
#IF IS_DEBUG_BUILD
IF NOT ARE_VECTORS_ALMOST_EQUAL(vNodePosition, vDestinationNodeCoords, 0.5)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : passed in node coords didn't match the cloest node position :
vDestinationNodeCoords = ", vDestinationNodeCoords, " vNodePosition = ", vNodePosition)
ENDIF
#ENDIF
// try to find a position on both sides of the road
IF GET_POSITION_BY_SIDE_OF_ROAD(vNodePosition, 0, vRoadSideForwards) // iDirection - should be a direction (0=forwards, 1=back, -1=doesn't matter)
AND GET_POSITION_BY_SIDE_OF_ROAD(vNodePosition, 1, vRoadSideBackwards) // iDirection - should be a direction (0=forwards, 1=back, -1=doesn't matter)
VECTOR v1, v2, v3
v1 = vRoadSideForwards - vNodePosition
v2 = << -v1.y, v1.x, 0.0 >>
v3 = vTaxiCoords - vDestinationNodeCoords
FLOAT fDotProduct = DOT_PRODUCT(v2, v3)
IF fDotProduct < 0.0
vReturnPullOverPosition = vRoadSideForwards
fReturnPullOverHeading = fDestinationNodeHeading
//z check - B* 1869986
IF DO_PARK_Z_CHECK(vReturnPullOverPosition,vNodePosition)
sDispatchedTaxi.bFailedZCheck = TRUE
ENDIF
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : return TRUE cloest side found (forwards)",
" vReturnPullOverPosition : ", vReturnPullOverPosition, " fReturnPullOverHeading = ", fReturnPullOverHeading)
#IF IS_DEBUG_BUILD DEBUG_DRAW_TAXI_PULL_OVER_INFO(vReturnPullOverPosition, vRoadSideBackwards, vNodePosition) #ENDIF
ELSE
vReturnPullOverPosition = vRoadSideBackwards
fReturnPullOverHeading += 180
fReturnPullOverHeading = WRAP(fReturnPullOverHeading, 0, 360)
//z check - B* 1869986
IF DO_PARK_Z_CHECK(vReturnPullOverPosition,vNodePosition)
sDispatchedTaxi.bFailedZCheck = TRUE
ENDIF
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : return TRUE cloest side found (backwards)",
" vReturnPullOverPosition : ", vReturnPullOverPosition, " fReturnPullOverHeading = ", fReturnPullOverHeading)
#IF IS_DEBUG_BUILD DEBUG_DRAW_TAXI_PULL_OVER_INFO(vReturnPullOverPosition, vRoadSideForwards, vNodePosition) #ENDIF
ENDIF
RETURN TRUE
// try to find any valid position at the side of the road
ELIF GET_POSITION_BY_SIDE_OF_ROAD(vNodePosition, -1, vRoadSideForwards) // iDirection - should be a direction (0=forwards, 1=back, -1=doesn't matter)
vReturnPullOverPosition = vRoadSideForwards
fReturnPullOverHeading = fDestinationNodeHeading
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : return TRUE just the one position found vReturnPullOverPosition : ", vReturnPullOverPosition)
RETURN TRUE
// unable to find a valid position at the side of the road
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : return FALSE unable to find a valid position by the side of the road vDestinationNodeCoords : ", vDestinationNodeCoords)
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : GET_TAXI_PULL_OVER_INFO() : return FALSE IS_VEHICLE_NODE_ID_VALID vDestinationNodeCoords : ", vDestinationNodeCoords)
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// handles the taxi pulling over to pickup the player
/// RETURNS:
/// TRUE if taxi has pulled over successfully
FUNC BOOL HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER()
VECTOR vTaxiPos
vTaxiPos = GET_ENTITY_COORDS(sDispatchedTaxi.vehicleIndex, FALSE)
IF NOT sDispatchedTaxi.bHasActiveTask
// if player has got close to taxi before it's reached it's pull up position allow the task to be reapplied using current position
IF NOT sDispatchedTaxi.bForcedPullOverAtCurrentPosition
IF GET_TAXI_PULL_OVER_INFO(vTaxiPos, sDispatchedTaxi.vDriveToCoords, sDispatchedTaxi.fDriveToHeading, sDispatchedTaxi.vPullOverCoords, sDispatchedTaxi.fDriveToHeading)
IF NOT IS_ENTITY_DEAD(sDispatchedTaxi.pedIndex)
SET_DRIVER_ABILITY(sDispatchedTaxi.pedIndex, 0.5)
//z check - B* 1869986
IF sDispatchedTaxi.bFailedZCheck
TASK_VEHICLE_DRIVE_TO_COORD(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vPullOverCoords, 10, DRIVINGSTYLE_NORMAL, GET_ENTITY_MODEL(sDispatchedTaxi.vehicleIndex), sDispatchedTaxi.taxiDrivingModeStandard, 5, GET_DISTANCE_BETWEEN_COORDS(vTaxiPos,sDispatchedTaxi.vPullOverCoords))
sDispatchedTaxi.bFailedZCheck = FALSE
ELSE
// info: apparently TASK_VEHICLE_PARK should work from as far 50m away also as the path nodes are loaded. Needs to kick in earlier than later.
// can take up to 10 metres to stop, so best to pass in a position offset from the actual spot you want to stop
//TASK_VEHICLE_PARK(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vPullOverCoords, sDispatchedTaxi.fDriveToHeading, PARK_TYPE_PULL_OVER, 90, TRUE)
TASK_VEHICLE_PARK(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vPullOverCoords, sDispatchedTaxi.fDriveToHeading, PARK_TYPE_PULL_OVER, 90, TRUE)
ENDIF
ENDIF
sDispatchedTaxi.bHasActiveTask = TRUE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() applied park task ",
" sDispatchedTaxi.vPullOverCoords : ", sDispatchedTaxi.vPullOverCoords, " sDispatchedTaxi.fDriveToHeading = ", sDispatchedTaxi.fDriveToHeading)
ENDIF
ELSE
SET_DRIVER_ABILITY(sDispatchedTaxi.pedIndex, 0.5)
sDispatchedTaxi.vPullOverCoords = vTaxiPos
TASK_VEHICLE_TEMP_ACTION(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, TEMPACT_HANDBRAKESTRAIGHT, 15000)
sDispatchedTaxi.bHasActiveTask = TRUE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() applied TEMPACT_HANDBRAKESTRAIGHT task ",
" sDispatchedTaxi.vPullOverCoords : ", sDispatchedTaxi.vPullOverCoords)
// info: apparently TASK_VEHICLE_PARK should work from as far 50m away also as the path nodes are loaded. Needs to kick in earlier than later.
// can take up to 10 metres to stop, so best to pass in a position offset from the actual spot you want to stop
//TASK_VEHICLE_PARK(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.vPullOverCoords, sDispatchedTaxi.fDriveToHeading, PARK_TYPE_PULL_OVER, 90, TRUE)
//bTaxiDriverHasActiveTask = TRUE
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() applied park task ",
// " sDispatchedTaxi.vPullOverCoords : ", sDispatchedTaxi.vPullOverCoords, " sDispatchedTaxi.fDriveToHeading = ", sDispatchedTaxi.fDriveToHeading)
ENDIF
ELSE
IF NOT TAXI_IS_PED_PERFORMING_TASK(sDispatchedTaxi.pedIndex, SCRIPT_TASK_VEHICLE_PARK)
IF IS_VEHICLE_STOPPED(sDispatchedTaxi.vehicleIndex)
//AND TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, sDispatchedTaxi.vPullOverCoords, 15.0) // seems they can pull over far away
TASK_VEHICLE_TEMP_ACTION(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, TEMPACT_WAIT, 1000000)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() : driver tasked TEMPACT_WAIT")
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() : return TRUE - stopped at : ", vTaxiPos)
RETURN TRUE
ENDIF
ELSE
// if the player get close and the vehicle is already stopped just left him get in
IF TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, vPlayerPos, 5.0)
IF IS_VEHICLE_STOPPED(sDispatchedTaxi.vehicleIndex)
OR IS_VEHICLE_STOPPED_AT_TRAFFIC_LIGHTS(sDispatchedTaxi.vehicleIndex)
TASK_VEHICLE_TEMP_ACTION(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex, TEMPACT_WAIT, 1000000)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() : driver tasked TEMPACT_WAIT")
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() : return TRUE - stopped early for player prox : ", vTaxiPos)
RETURN TRUE
ENDIF
ENDIF
IF NOT sDispatchedTaxi.bForcedPullOverAtCurrentPosition
// allow player to flag it earlier if he gets close to it before it's had a chance finish it's pull over task
IF NOT TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, sDispatchedTaxi.vPullOverCoords, 10.0)
IF TAXI_IS_COORD_IN_RANGE_OF_COORD(vTaxiPos, vPlayerPos, 5.0)
sDispatchedTaxi.vDriveToCoords = vPlayerPos
sDispatchedTaxi.bForcedPullOverAtCurrentPosition = TRUE
sDispatchedTaxi.bHasActiveTask = FALSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER() : player got close before pulled over so reapplied")
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Creates a taxi ready to drive to the player - for when they have rang for a taxi
PROC DISPATCHED_STATE_CREATE_TAXI()
IF IS_PLAYER_PLAYING(PLAYER_ID()) // might not be needed now?
// B*1339179 - Taxi came a bit too quickly - always have a minimum time of 10 seconds then it arriving. Les Bug
IF HAS_TIME_PASSED(sDispatchedTaxi.iTimer_TaxiDispatchDelay, TIME_DELAY_TAXI_DISPATCHED)
REQUEST_MODEL(mnTaxiModel)
REQUEST_MODEL(mnTaxiDriverModel)
IF HAS_MODEL_LOADED(mnTaxiModel)
IF HAS_MODEL_LOADED(mnTaxiDriverModel)
VECTOR vSpawnPos
FLOAT fHeading
NODE_FLAGS nodeFlags
// Info from J Mart - switched off nodes should be ok in most case, but if we are in the city ensure they aren't dead ends (stop taxi using driveways).
IF IS_POSITION_IN_ZONE_SAFE_FOR_DEADEND_NODES(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE))
// COUNTRYSIDE / OK FOR DEADEND NODES -
// try to make taxi spawn on major road networks first to fix issues where they spawn in blocked off areas/deadends
IF sDispatchedTaxi.iSpawnAttempts < 2
nodeFlags = NF_NONE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : countryside : using node flags NF_NONE : iSpawnAttempts = ", sDispatchedTaxi.iSpawnAttempts)
// then attempt spawn not using deadends
ELIF sDispatchedTaxi.iSpawnAttempts < 5
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : countryside : using node flags NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS : iSpawnAttempts = ", sDispatchedTaxi.iSpawnAttempts)
ELSE
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : countryside : using node flags NF_INCLUDE_SWITCHED_OFF_NODES : iSpawnAttempts = ", sDispatchedTaxi.iSpawnAttempts)
ENDIF
ELSE
// CITY / NOT OK FOR DEADEND NODES -
// try to make taxi spawn on major road networks first to fix issues where they spawn in blocked off areas/deadends
IF sDispatchedTaxi.iSpawnAttempts < 5
nodeFlags = NF_NONE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : using node flags NF_NONE : iSpawnAttempts = ", sDispatchedTaxi.iSpawnAttempts)
ELSE
nodeFlags = NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : area NOT safe for DeadEnds : using node flags NF_INCLUDE_SWITCHED_OFF_NODES | NF_IGNORE_SWITCHED_OFF_DEADENDS : iSpawnAttempts = ", sDispatchedTaxi.iSpawnAttempts)
ENDIF
ENDIF
IF GENERATE_TAXI_SPAWN_POS_AND_HEADING_TO_PLAYER(vSpawnPos, fHeading, sDispatchedTaxi.iNodeSearchNumber, nodeFlags, DEFAULT)
#IF IS_DEBUG_BUILD
vDebug_DispatchTaxiSpawnPos = vSpawnPos
IF bDebug_UseForceTaxiSpawnCoordsAndHeading
vSpawnPos = vDebug_ForcedTaxiSpawnCoords
fHeading = fDebug_ForcedTaxiSpawnHeading
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI() : DEBUG! forcing spawn coords & heading")
ENDIF
#ENDIF
CLEAR_AREA(vSpawnPos, 5.0, TRUE)
IF CREATE_TAXI_AND_DRIVER(sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.pedIndex, vSpawnPos, fHeading)
sDispatchedTaxi.fDistToTarget = GET_DIST_BETWEEN_VECTORS_NONE_Z(GET_ENTITY_COORDS(sDispatchedTaxi.vehicleIndex), GET_ENTITY_COORDS(PLAYER_PED_ID()))
sDispatchedTaxi.bHasActiveTask = FALSE // reset ready for next task
sDispatchedTaxi.iNodeSearchNumber = 0 // reset ready for destination node search
eDispatchedTaxiState = TL_DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : eDispatchedTaxiState = TL_DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER : fc = ", GET_FRAME_COUNT())
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " DISPATCHED_STATE_CREATE_TAXI - CREATE_TAXI - return FALSE")
ENDIF
ELSE
// fail safe for create taxi not being able to generate suitable creation node
IF sDispatchedTaxi.iNodeSearchNumber >= 5 // limit to 5 so taxi is still trying to generate a path close to the player
sDispatchedTaxi.iSpawnAttempts++
// 10 retry attempts since it might just be the player's camera angle blocking a successful spawn
IF sDispatchedTaxi.iSpawnAttempts > 10
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI - Bail Out : failed to generate taxi creation position! : fc = ", GET_FRAME_COUNT())
CLEANUP_DISPATCHED_TAXI_DATA()
ELSE
sDispatchedTaxi.iNodeSearchNumber = 0 // reset ready for retry
sDispatchedTaxi.iTimer_TaxiDispatchDelay = (GET_GAME_TIMER() - (TIME_DELAY_TAXI_DISPATCHED - 1000)) // retry go through in a seconds time
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_CREATE_TAXI - setup Retry : failed to generate taxi creation position! : fc = ", GET_FRAME_COUNT())
ENDIF
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " DISPATCHED_STATE_CREATE_TAXI - HAS_MODEL_LOADED(mnTaxiDriverModel) - return FALSE")
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " DISPATCHED_STATE_CREATE_TAXI - HAS_MODEL_LOADED(mnTaxiModel) - return FALSE")
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " DISPATCHED_STATE_CREATE_TAXI - IS_PLAYER_PLAYING() - return FALSE")
ENDIF
ENDPROC
/// PURPOSE:
/// handles the created taxi driving over to the player
PROC DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER()
IF HAS_DISPATCHED_TAXI_ARRIVED_TO_PICKUP_PLAYER()
sDispatchedTaxi.bHasActiveTask = FALSE // reset ready for next task
eDispatchedTaxiState = TL_DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : eDispatchedTaxiState = TL_DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER : fc = ", GET_FRAME_COUNT())
ENDIF
ENDPROC
/// PURPOSE:
/// Handles the created taxi finding a pull over spot to park up near the player upon arrival
PROC DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER()
IF HAS_DISPATCHED_TAXI_PULLED_OVER_TO_PICKUP_PLAYER()
// only set this up as waiting if player isn't getting into a taxi and there isn't one waiting
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
AND eHailTaxiState != TL_HAIL_TAXI_STATE_TAXI_WAITING
// clear ready for next updated state
CLEANUP_HAIL_TAXI()
//update handles
IF STORE_CAR_AS_TAXI_WAITING_FOR_PLAYER(sDispatchedTaxi.vehicleIndex, sDispatchedTaxi.pedIndex)
g_iTaxiHailedTime = 0
IF IS_VEHICLE_OK(g_WaitingTaxi)
START_VEHICLE_HORN(g_WaitingTaxi, 2500, GET_HASH_KEY("NORMAL"))
ENDIF
IF DOES_ENTITY_EXIST(g_WaitingTaxiDriver)
IF NOT IS_PED_INJURED(g_WaitingTaxiDriver)
TASK_LOOK_AT_ENTITY(g_WaitingTaxiDriver, PLAYER_PED_ID(), 3000)
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), g_WaitingTaxiDriver, 3000)
ENDIF
ENDIF
CREATE_WAITING_TAXI_BLIP()
// set the taxi hailing taxi to taxi waiting
eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
CLEANUP_DISPATCHED_TAXI_DATA()
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER() : marked taxi as waiting : fc = ", GET_FRAME_COUNT())
ELSE
CLEANUP_DISPATCHED_TAXI_DATA()
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER() : failed attempt to mark taxi as waiting : fc = ", GET_FRAME_COUNT())
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// check if the taxi already have a fare on board
/// NOTE: doesn't safety check entity
/// RETURNS:
/// TRUE if found ped in rear seat who isn't in player group
FUNC BOOL DOES_TAXI_ALREADY_HAVE_A_FARE(VEHICLE_INDEX &vehicleIndex)
PED_INDEX pedIndex
IF NOT IS_VEHICLE_SEAT_FREE(vehicleIndex, VS_BACK_LEFT)
pedIndex = GET_PED_IN_VEHICLE_SEAT (vehicleIndex, VS_BACK_LEFT)
IF NOT (pedIndex = PLAYER_PED_ID())
// don't worry if it's got player group member in
IF NOT IS_PED_GROUP_MEMBER(pedIndex, PLAYER_GROUP_ID())
// not sure why this is here! but there you go
IF IS_TAXI_LIGHT_ON(vehicleIndex)
SET_TAXI_LIGHTS(vehicleIndex, FALSE)
ENDIF
RETURN TRUE
ENDIF
ENDIF
ENDIF
IF NOT IS_VEHICLE_SEAT_FREE(vehicleIndex, VS_BACK_RIGHT)
pedIndex = GET_PED_IN_VEHICLE_SEAT (vehicleIndex, VS_BACK_RIGHT)
IF NOT (pedIndex = PLAYER_PED_ID())
// don't worry if it's got player group member in
IF NOT IS_PED_GROUP_MEMBER(pedIndex, PLAYER_GROUP_ID())
// not sure why this is here! but there you go
IF IS_TAXI_LIGHT_ON(vehicleIndex)
SET_TAXI_LIGHTS(vehicleIndex, FALSE)
ENDIF
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Player comment for hailed taxi not stopping
/// FUNC needs improving
PROC PLAY_FUCK_YOU_DIALOGUE()
BOOL bFlag
// shout 'fuck you'
IF (bPlayAdditionalFuckYouDialogue)
IF HAS_TIME_PASSED(iTimer_HailFailedDialogueDelay, 1000)
IF (GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_PLAY_ANIM) = FINISHED_TASK)
IF (GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK)
IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FUCK_U")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FORGET_IT")
IF NOT (g_playerIsDrunk)
// has player been shut up for mission?
bFlag = IS_AMBIENT_SPEECH_DISABLED(PLAYER_PED_ID())
//bFlag = TRUE
IF NOT (bFlag)
STOP_PED_SPEAKING(PLAYER_PED_ID(), TRUE)
ENDIF
PLAY_PED_AMBIENT_SPEECH(PLAYER_PED_ID(), "TAXI_DRIVES_PAST")
IF NOT (bFlag)
STOP_PED_SPEAKING(PLAYER_PED_ID(), FALSE)
ENDIF
ENDIF
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, FALSE)
// B*1991223 - RESET need to block ambient anims during hail anims
IF bBlockingPlayerAmbientIdles = TRUE
SET_PED_CAN_PLAY_AMBIENT_ANIMS(PLAYER_PED_ID(), TRUE)
bBlockingPlayerAmbientIdles = FALSE
ENDIF
bPlayAdditionalFuckYouDialogue = FALSE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// check if the player is moving the analogue sticks
/// RETURNS:
/// TRUE if movement detected
FUNC BOOL IS_PLAYER_MOVING()
// get stick vec
INT LSx, LSy, RSx, RSy
GET_CONTROL_VALUE_OF_ANALOGUE_STICKS(LSx, LSy, RSx, RSy)
IF (LSx > 64)
OR (LSx < -64)
OR (LSy > 64)
OR (LSy < -64)
RETURN(TRUE)
ENDIF
RETURN(FALSE)
ENDFUNC
/// PURPOSE:
/// stops the gameplay hint cam if it was applied by the launcher
PROC CLEAR_HINT_CAM_IF_PLAYER_IS_MOVING()
IF IS_GAMEPLAY_HINT_ACTIVE()
IF bHintTriggeredByTaxiLauncher
IF IS_PLAYER_MOVING()
STOP_GAMEPLAY_HINT()
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// check if the vehicle is going below TAXI_MOVING_GET_IN_SPEED
/// PARAMS:
/// vehicleIndex - vehicle to check
/// RETURNS:
/// TRUE if speed is less than TAXI_MOVING_GET_IN_SPEED
FUNC BOOL IS_CAR_ALMOST_STOPPED(VEHICLE_INDEX vehicleIndex)
IF IS_VEHICLE_DRIVEABLE(vehicleIndex)
IF (GET_ENTITY_SPEED(vehicleIndex) < TAXI_MOVING_GET_IN_SPEED)
RETURN(TRUE)
ENDIF
ELSE
RETURN(TRUE)
ENDIF
RETURN(FALSE)
ENDFUNC
/// PURPOSE:
/// check if the vehicle's roll is ok
/// PARAMS:
/// vehicleIndex -
/// RETURNS:
/// TRUE if roll is ok
FUNC BOOL IS_CAR_ROLL_ACCEPTABLE(VEHICLE_INDEX vehicleIndex)
IF IS_VEHICLE_DRIVEABLE(vehicleIndex)
//IF (GET_ENTITY_ROLL(vehicleIndex) < 45.0)
//AND (GET_ENTITY_ROLL(vehicleIndex) > -45.0)
IF IS_ENTITY_UPRIGHT(vehicleIndex)
RETURN(TRUE)
ENDIF
ENDIF
RETURN(FALSE)
ENDFUNC
PROC STOP_PLAYER_RAGDOLLING()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF NOT (IS_PED_RAGDOLL(PLAYER_PED_ID()))
EXIT
ENDIF
SET_PED_CAN_RAGDOLL (PLAYER_PED_ID(), TRUE )
//CREATE_NM_MESSAGE(NM_START_STOP , NM_BALANCE_MSG)
//SEND_NM_MESSAGE(PLAYER_PED_ID())
SET_PED_TO_ANIMATED(PLAYER_PED_ID(), FALSE)
ENDIF
ENDPROC
FUNC BOOL HAS_PLAYER_CANCELLED_GETTING_IN_TAXI()
VECTOR vec
IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_ENTER)
RETURN(FALSE)
ENDIF
// get camera heading in world
FLOAT fCamHeading
VECTOR vGameCamVec
vec = GET_GAMEPLAY_CAM_ROT()
fCamHeading = vec.z
vGameCamVec = <<0.0, 1.0, 0.0>>
ROTATE_VECTOR(vGameCamVec, <<0.0, 0.0, fCamHeading>>)
// get stick vec
INT LSx, LSy, RSx, RSy
VECTOR vStickVec
GET_CONTROL_VALUE_OF_ANALOGUE_STICKS(LSx, LSy, RSx, RSy)
vec.x = LSx / 128.0
vec.y = LSy / -128.0
vec.z = 0.0
// check the stick is moving
IF (VMAG(vec) < 0.5)
RETURN(FALSE)
ENDIF
vStickVec = <<0.0, 1.0, 0.0>>
ROTATE_VECTOR(vStickVec, <<0.0, 0.0, fCamHeading>>)
ROTATE_VECTOR(vStickVec, <<0.0, 0.0, GET_HEADING_FROM_VECTOR_2D(vec.x, vec.y)>>)
// get player heading vec
VECTOR vPlayerVec
FLOAT fPlayerHeading
IF IS_PLAYER_PLAYING(PLAYER_ID())
fPlayerHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
vPlayerVec = <<0.0, 1.0, 0.0>>
ROTATE_VECTOR(vPlayerVec, <<0.0, 0.0, fPlayerHeading>>)
ENDIF
// // draw player and stick vec
// VECTOR pos, pos2
// IF IS_PLAYER_PLAYING(PLAYER_ID())
// // player vec
// GET_ENTITY_COORDS(PLAYER_PED_ID(), pos.x, pos.y, pos.z)
// pos2 = pos + vPlayerVec
// LINE(pos.x, pos.y, pos.z, pos2.x, pos2.y, pos2.z)
// // stick vec
// pos2 = pos + vStickVec
// LINE(pos.x, pos.y, pos.z, pos2.x, pos2.y, pos2.z)
// ENDIF
// check the angle between stick and player heading
IF (GET_ANGLE_BETWEEN_2D_VECTORS(vPlayerVec.x, vPlayerVec.y, vStickVec.x, vStickVec.y) > 60.0)
RETURN(TRUE)
ENDIF
RETURN(FALSE)
ENDFUNC
/// PURPOSE:
/// updates the player's allowed to ride in taxi's status
/// Scripts can set the status to false so this safe guards against the scripts not resetting the status back when they terminate
PROC UPDATE_PLAYER_ALLOWED_TO_RIDE_IN_TAXIS_STATUS()
// taxi script appears to track hailing disabled using bool (g_bTaxiHailingIsDisabled) and a stored script name (g_sTaxiHailingDisabledByThisScript)
IF NOT IS_PLAYER_ALLOWED_TO_RIDE_IN_TAXIS()
IF ARE_STRINGS_EQUAL("NULL", g_sTaxiHailingDisabledByThisScript)
DISABLE_TAXI_HAILING(FALSE)
ELSE
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY(g_sTaxiHailingDisabledByThisScript)) = 0
DISABLE_TAXI_HAILING(FALSE)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// checks to decide if it's safe for the player be given the enter vehicle task
/// NOTE: safe checks will have already been performed at this stage
/// RETURNS:
/// TRUE if ok to apply task
FUNC BOOL IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK(VEHICLE_INDEX &vehicleIndex)
// can't apply task when player doesn't have controls
IF NOT IS_PLAYER_PLAYING(PLAYER_ID())
RETURN FALSE
ENDIF
// only process enter controls when player gets close
IF NOT IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), vehicleIndex, <<5.0, 5.0, 2.0>>, FALSE)
RETURN FALSE
ENDIF
// make sure the player doesn't try to enter a speeding vehicle
IF GET_ENTITY_SPEED(vehicleIndex) > 0.5
RETURN FALSE
ENDIF
// interior check - don't give enter task if player isn't in same room
//IF GET_ROOM_KEY_FROM_ENTITY(vehicleIndex) != GET_ROOM_KEY_FROM_ENTITY(PLAYER_PED_ID())
IF GET_INTERIOR_FROM_ENTITY(vehicleIndex) != GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())
RETURN FALSE
ENDIF
// taxi not suitable for player to enter
IF NOT IS_CAR_ROLL_ACCEPTABLE(vehicleIndex)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Get handles to the closest taxi for PROCESS_PLAYER_ENTER_CLOSEST_TAXI
/// and also the most desireable to hail for PROCESS_PLAYER_HAILING_TAXI
/// using GET_PED_NEARBY_VEHICLES
FUNC BOOL ALT_UPDATE_TAXI_SEARCH_HANDLES()
// only search for taxis if the player isn't currently getting into one
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
IF HAS_TIME_PASSED(iTimer_DelayTaxiSearch, 500)
INT iMaxDesiredTaxiHandles
INT iHailTargetIndex = -1
INT iClosestTaxiIndex = -1
INT iCount
INT i
INT iNumTaxisFound = 0
FLOAT fTaxiScore
FLOAT fTaxiHighScore = -99999
FLOAT fMinRange
VECTOR vTaxiCoords
FLOAT fDistance
VECTOR vPlayerForward
VECTOR vDiff
// only update the hail taxi target if we are waiting for the player to hail
IF (eHailTaxiState != TL_HAIL_TAXI_STATE_IDLE
AND eHailTaxiState != TL_HAIL_TAXI_STATE_DETECT_HAIL)
bUpdateHailTargetThisFrame = FALSE
ENDIF
// and when the update timer has passed
IF bUpdateHailTargetThisFrame
iMaxDesiredTaxiHandles = 3 // grab three closest taxis
fMinRange = TAXI_HAIL_DISTANCE // only worry about vehicles with in the hail distance
ELSE
// if we aren't searching for hail targets this frame only need a small number of close vehicle
iMaxDesiredTaxiHandles = 1 // only grab the one closest taxi
fMinRange = 10.0 // only worry about vehicles with 10m
ENDIF
VEHICLE_INDEX vehIndexArray[12]
// this function returns vehicles in order of closeness
iCount = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(), vehIndexArray)
IF iCount > 0
FOR i = 0 TO (iCount - 1)
IF iNumTaxisFound < iMaxDesiredTaxiHandles
// if the entity doesn't exist (drop out the loop since all other entities shouldn't exist either
IF DOES_ENTITY_EXIST(vehIndexArray[i])
// check the vehicle is a taxi
IF (GET_ENTITY_MODEL(vehIndexArray[i]) = mnTaxiModel)
// dist check first (break out loop if veh isn't in range since the array in filled closest first)
vTaxiCoords = GET_ENTITY_COORDS(vehIndexArray[i], FALSE)
fDistance = VDIST2(vPlayerPos, vTaxiCoords)
IF fDistance <= (fMinRange * fMinRange)
// check the taxi and it's driver is suitable
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(vehIndexArray[i], mnTaxiModel, mnTaxiDriverModel)
// Store the closest Taxi
IF iClosestTaxiIndex = -1
iClosestTaxiIndex = i
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : Closest taxi set this frame : ", GET_FRAME_COUNT(), " array index = ", i) ENDIF #ENDIF
ENDIF
// only care about the rest of the checks if searching for a taxi to hail
IF bUpdateHailTargetThisFrame
// don't hail the waiting taxi (potential move this check to hail so he never hails when one is pulled up waiting?
IF (vehIndexArray[i] != g_WaitingTaxi)
// not allowed to hail taxis with light off
//IF NOT DOES_TAXI_HAVE_LIGHT_ON(vehicleIndex)
// don't consider if not in same interior
IF GET_INTERIOR_FROM_ENTITY(vehIndexArray[i]) = GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())
// Update hail score
fTaxiScore = 1.0
// score the distance
fDistance /= fDistance
fDistance -= TAXI_HAIL_DISTANCE
fDistance *= -1.0
fDistance /= TAXI_HAIL_DISTANCE
fDistance *= 0.5 // min score is 0.5
fDistance += 0.5
// multiple score by distance score
fTaxiScore *= fDistance
fDistance = vPlayerPos.z - vTaxiCoords.z
IF fDistance < 0.0
fDistance *= -1.0
ENDIF
// don't hail taxi if the Z diff is too high
IF fDistance < 4.0
// if taxi isn't inside 120 2D arc of player don't consider it (using Sam's IS_ENTITY_IN_ARC_2D)
vPlayerForward = GET_ENTITY_FORWARD_VECTOR(PLAYER_PED_ID())
vDiff = vTaxiCoords - vPlayerPos
IF (((vPlayerForward.x*vDiff.x)+(vPlayerForward.y*vDiff.y)) / VDIST(vDiff, <<0,0,0>>)) > COS(120)
// reduce score if taxi is off screen
IF IS_SPHERE_VISIBLE(vTaxiCoords, 2)
fTaxiScore *= 0.5
ENDIF
// reduce score if taxi is occupied, so unoccupied taxis have priority
IF DOES_TAXI_ALREADY_HAVE_A_FARE(vehIndexArray[i])
fTaxiScore *= 0.2
ENDIF
// disregard if unside down or in water
IF NOT IS_ENTITY_UPRIGHT(vehIndexArray[i])
OR IS_ENTITY_IN_WATER(vehIndexArray[i])
fTaxiScore = 0
ENDIF
// set the highscore and store the index for the hail target
IF fTaxiScore > fTaxiHighScore
fTaxiHighScore = fTaxiScore
iHailTargetIndex = i
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : Updated iHailTargetIndex = ", i, " score = ", fTaxiHighScore) ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected wasn't infront of player ") ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected Z diff to high = ", fDistance) ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected interior check ") ENDIF #ENDIF
ENDIF
//ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected taxi is g_WaitingTaxi ") ENDIF #ENDIF
ENDIF
ENDIF
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : i = ", i, " grabbed handle to taxi") ENDIF #ENDIF
iNumTaxisFound++
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected not suitable") ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : i = ", i, " looped ended as detected veh dist out of range = ", fDistance) ENDIF #ENDIF
i = iCount
ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : i = ", i, " looped ended as detected veh didn't exist ") ENDIF #ENDIF
i = iCount
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : i = ", i, " looped ended as iNumTaxisFound = ", iNumTaxisFound) ENDIF #ENDIF
i = iCount
ENDIF
ENDFOR
ENDIF
// Store the closest Taxi
IF iClosestTaxiIndex = -1
// ensure the previous taxi's driver's flag is reset to normal behaviour
SET_TAXI_DRIVER_ENTER_AS_PASSENGER_FLAG(vehClosestTaxi, FALSE)
vehClosestTaxi = NULL
// reset timer for delaying search for hailable taxis
//iTimer_DelayTaxiSearch = GET_GAME_TIMER()
ELSE
//iTimer_DelayTaxiSearch = 0 // ensure the taxi search goes through every frame when a taxi is in range
// update the handle if it's changed
IF vehClosestTaxi != vehIndexArray[iClosestTaxiIndex]
// ensure the previous taxi's driver's flag is reset to normal behaviour
SET_TAXI_DRIVER_ENTER_AS_PASSENGER_FLAG(vehClosestTaxi, FALSE)
vehClosestTaxi = vehIndexArray[iClosestTaxiIndex]
// Set the new closest driver's flag so the player can enter as passenger
SET_TAXI_DRIVER_ENTER_AS_PASSENGER_FLAG(vehClosestTaxi, TRUE)
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : Closest taxi updated this frame : ", GET_FRAME_COUNT(), " array index = ", iClosestTaxiIndex) ENDIF #ENDIF
ENDIF
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : Closest taxi set this frame : ", GET_FRAME_COUNT(), " array index = ", iClosestTaxiIndex) ENDIF #ENDIF
ENDIF
// update whether or not we want to search for hail targets next opportunity
IF bUpdateHailTargetThisFrame
// Store the hail Taxi
IF iHailTargetIndex = -1
vehHailTarget = NULL
ELSE
vehHailTarget = vehIndexArray[iHailTargetIndex]
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : Hail target taxi set this frame : ", GET_FRAME_COUNT(), " array index = ", iHailTargetIndex) ENDIF #ENDIF
ENDIF
bUpdateHailTargetThisFrame = FALSE // don't recheck next frame
ELSE
bUpdateHailTargetThisFrame = TRUE // recheck next frame
ENDIF
// reset timer for delaying search for taxis
iTimer_DelayTaxiSearch = GET_GAME_TIMER()
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ALT_UPDATE_TAXI_SEARCH_HANDLES : handles update this frame : ", GET_FRAME_COUNT()) ENDIF #ENDIF
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Get handles to the closest taxi for PROCESS_PLAYER_ENTER_CLOSEST_TAXI
/// and also the most desireable to hail for PROCESS_PLAYER_HAILING_TAXI
/// using GET_RANDOM_VEHICLE_IN_SPHERE
PROC UPDATE_TAXI_SEARCH_HANDLES()
// only search for taxis if the player is currently getting into one
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
IF HAS_TIME_PASSED(iTimer_DelayTaxiSearch, 750)
INT iHailTargetIndex = -1
INT iClosestTaxiIndex = -1
INT iCount
INT i
FLOAT fTaxiScore
FLOAT fTaxiHighScore = -99999
FLOAT fMinRange = TAXI_HAIL_DISTANCE // only worry about vehicles with in the hail distance
VECTOR vTaxiCoords
FLOAT fDistance
VECTOR vPlayerForward
VECTOR vDiff
FLOAT fClosestTaxiDist = 9999999.0
iCount = 3
VEHICLE_INDEX vehIndexArray[3]
vehIndexArray[0] = GET_RANDOM_VEHICLE_IN_SPHERE(vPlayerPos, TAXI_HAIL_DISTANCE * 0.33, mnTaxiModel, VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES | VEHICLE_SEARCH_FLAG_CHECK_VEHICLE_OCCUPANTS_STATES | VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES | VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK)
vehIndexArray[1] = GET_RANDOM_VEHICLE_IN_SPHERE(vPlayerPos, TAXI_HAIL_DISTANCE * 0.66, mnTaxiModel, VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES | VEHICLE_SEARCH_FLAG_CHECK_VEHICLE_OCCUPANTS_STATES | VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES | VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK)
vehIndexArray[2] = GET_RANDOM_VEHICLE_IN_SPHERE(vPlayerPos, TAXI_HAIL_DISTANCE * 1.00, mnTaxiModel, VEHICLE_SEARCH_FLAG_RETURN_RANDOM_VEHICLES | VEHICLE_SEARCH_FLAG_CHECK_VEHICLE_OCCUPANTS_STATES | VEHICLE_SEARCH_FLAG_RETURN_MISSION_VEHICLES | VEHICLE_SEARCH_FLAG_ALLOW_VEHICLE_OCCUPANTS_TO_BE_PERFORMING_A_SCRIPTED_TASK)
FOR i = 0 TO (iCount - 1)
// check the taxi and it's driver is suitable
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(vehIndexArray[i], mnTaxiModel, mnTaxiDriverModel)
vTaxiCoords = GET_ENTITY_COORDS(vehIndexArray[i], FALSE)
fDistance = VDIST2(vPlayerPos, vTaxiCoords)
// only worry about taxis close enough to hail
IF fDistance <= (fMinRange * fMinRange)
// update the closest taxi index
IF fDistance < fClosestTaxiDist
fClosestTaxiDist = fDistance
iClosestTaxiIndex = i
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : Closest taxi updated dist = ", fClosestTaxiDist, " array index = ", i) ENDIF #ENDIF
ENDIF
// don't hail the waiting taxi (potential move this check to hail so he never hails when one is pulled up waiting?
IF (vehIndexArray[i] != g_WaitingTaxi)
// not allowed to hail taxis with light off
//IF NOT DOES_TAXI_HAVE_LIGHT_ON(vehicleIndex[i])
// don't consider if not in same interior
IF GET_INTERIOR_FROM_ENTITY(vehIndexArray[i]) = GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID())
// Update hail score
fTaxiScore = 1.0
// score the distance
fDistance /= fDistance
fDistance -= TAXI_HAIL_DISTANCE
fDistance *= -1.0
fDistance /= TAXI_HAIL_DISTANCE
fDistance *= 0.5 // min score is 0.5
fDistance += 0.5
// multiple score by distance score
fTaxiScore *= fDistance
// don't hail taxi if the Z diff is too different
fDistance = vPlayerPos.z - vTaxiCoords.z
IF fDistance < 0.0
fDistance *= -1.0
ENDIF
IF fDistance < 4.0
// if taxi isn't inside 120 2D arc of player don't consider it (using Sam's IS_ENTITY_IN_ARC_2D)
vPlayerForward = GET_ENTITY_FORWARD_VECTOR(PLAYER_PED_ID())
vDiff = vTaxiCoords - vPlayerPos
IF (((vPlayerForward.x*vDiff.x)+(vPlayerForward.y*vDiff.y)) / VDIST(vDiff, <<0,0,0>>)) > COS(120)
// reduce score if taxi is off screen
IF IS_SPHERE_VISIBLE(vTaxiCoords, 2)
fTaxiScore *= 0.5
ENDIF
// reduce score if taxi is occupied, so unoccupied taxis have priority
IF DOES_TAXI_ALREADY_HAVE_A_FARE(vehIndexArray[i])
fTaxiScore *= 0.2
ENDIF
// set the highscore and store the index for the hail target
IF fTaxiScore > fTaxiHighScore
fTaxiHighScore = fTaxiScore
iHailTargetIndex = i
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : Updated iHailTargetIndex = ", i, " score = ", fTaxiHighScore) ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected wasn't infront of player ") ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected Z diff to high = ", fDistance) ENDIF #ENDIF
ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected interior check ") ENDIF #ENDIF
ENDIF
//ENDIF
ELSE
//#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : taxi ", i, " rejected taxi is g_WaitingTaxi ") ENDIF #ENDIF
ENDIF
ENDIF
ENDIF
ENDFOR
// Store the closest Taxi
IF iClosestTaxiIndex = -1
vehClosestTaxi = NULL
ELSE
// discard the taxi if its not going to be close enough to enter
IF fClosestTaxiDist < (10.0 * 10.0)
vehClosestTaxi = vehIndexArray[iClosestTaxiIndex]
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : Closest taxi set this frame : ", GET_FRAME_COUNT(), " array index = ", iClosestTaxiIndex) ENDIF #ENDIF
ELSE
vehClosestTaxi = NULL
ENDIF
ENDIF
iTimer_DelayTaxiSearch = GET_GAME_TIMER()
// only update the hail target when one isn't waiting
IF (eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
OR eHailTaxiState = TL_HAIL_TAXI_STATE_DETECT_HAIL)
IF iHailTargetIndex = -1
vehHailTarget = NULL
ELSE
vehHailTarget = vehIndexArray[iHailTargetIndex]
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_TAXI_SEARCH_HANDLES : Hail target taxi set this frame : ", GET_FRAME_COUNT(), " array index = ", iHailTargetIndex) ENDIF #ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// check if the waiting taxi should cleanup
/// RETURNS:
/// TRUE if reason to cleanup found
FUNC BOOL SHOULD_WAITING_TAXI_CLEANUP()
// Check for hailed taxi timing out
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
IF g_iTaxiHailedTime = -1 OR g_iTaxiHailedTime = 0
g_iTaxiHailedTime = GET_GAME_TIMER()
ELSE
IF HAS_TIME_PASSED(g_iTaxiHailedTime, 30000)
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
OR eEnterTaxiState = TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), g_WaitingTaxi, TRUE) // Bug fix - extra check to make sure player isn't in the process of getting in the taxi
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), ": SHOULD_WAITING_TAXI_CLEANUP : return TRUE : hail timer expired : timer = ", g_iTaxiHailedTime)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// taxi checks
IF IS_VEHICLE_OK(g_WaitingTaxi)
VECTOR vTaxiCoords = GET_ENTITY_COORDS(g_WaitingTaxi, FALSE)
// Check for player abandoning taxi
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
IF NOT TAXI_IS_COORD_IN_RANGE_OF_COORD(vPlayerPos, vTaxiCoords, 75.0)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : player abandoned taxi")
RETURN TRUE
ENDIF
ENDIF
// player attacked taxi
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(g_WaitingTaxi, PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : damaged taxi check")
RETURN TRUE
ENDIF
// bullet fired near taxi
IF IS_BULLET_IN_AREA(vTaxiCoords, 7.0, FALSE)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : bullet fired near taxi")
RETURN TRUE
ENDIF
FLOAT fProjectileRadiusCheck = 15.0
VECTOR vMin, vMax // is one of the player's projectiles nearby?
vMin = vTaxiCoords
vMax = vMin
vMin.x= vMin.x - fProjectileRadiusCheck
vMin.y = vMin.y -fProjectileRadiusCheck
vMin.z = vMin.z - fProjectileRadiusCheck
vMax.x = vMax.x + fProjectileRadiusCheck
vMax.y = vMax.y + fProjectileRadiusCheck
vMax.z = vMax.z + fProjectileRadiusCheck
IF IS_PROJECTILE_IN_AREA(vMin, vMax, TRUE)
CPRINTLN(DEBUG_TAXI_SERVICE, " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : projectile near taxi")
RETURN TRUE
ENDIF
IF TAXI_IS_COORD_IN_RANGE_OF_COORD(vPlayerPos, vTaxiCoords, 20.0)
// aiming at the taxi
IF IS_PLAYER_FREE_AIMING_AT_ENTITY(PLAYER_ID(), g_WaitingTaxi)
OR IS_PLAYER_TARGETTING_ENTITY(PLAYER_ID(), g_WaitingTaxi)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : aiming at the taxi")
RETURN TRUE
ENDIF
// check for player shooting near waiting taxi
IF IS_PED_SHOOTING(PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : player shooting check")
RETURN TRUE
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_TAXI_SERVICE_END_EARLY : return TRUE : taxi ok check")
RETURN TRUE
ENDIF
// check the driver is ok
IF IS_PED_UNINJURED(g_WaitingTaxiDriver)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(g_WaitingTaxiDriver, PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : damaged taxi driver check")
RETURN TRUE
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_WAITING_TAXI_CLEANUP : return TRUE : taxi driver ok check")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// handles the player hailing nearby taxi
PROC HAIL_STATE_DETECT_HAIL()
PLAY_FUCK_YOU_DIALOGUE()
CLEAR_HINT_CAM_IF_PLAYER_IS_MOVING()
// don't process taxi hailing if a taxi wasn't found to hail
IF DOES_ENTITY_EXIST(vehHailTarget)
// contains safe checks on taxi and it's driver
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(vehHailTarget, mnTaxiModel, mnTaxiDriverModel)
IF IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI()
REQUEST_ANIM_DICT(tlTaxiAnimDict)
IF HAS_ANIM_DICT_LOADED(tlTaxiAnimDict)
IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FUCK_U")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FORGET_IT")
IF NOT DOES_TAXI_ALREADY_HAVE_A_FARE(vehHailTarget)
IF NOT IS_TAXI_LIGHT_ON(vehHailTarget)
SET_TAXI_LIGHTS(vehHailTarget, TRUE)
ENDIF
ENDIF
IF iTaxiHailIntention = NEW_CONTEXT_INTENTION
REGISTER_CONTEXT_INTENTION(iTaxiHailIntention, CP_TAXI_PRIORITY, "TXM_H01", TRUE) // Press ~INPUT_CONTEXT~ to hail a Taxi.
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_HAILING_TAXI() : REGISTER_CONTEXT_INTENTION - TX_H01") ENDIF #ENDIF
ENDIF
// Wait to detect player input for taxi hail
IF HAS_CONTEXT_BUTTON_TRIGGERED(iTaxiHailIntention)
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TXM_H01") // Press ~INPUT_CONTEXT~ to hail a Taxi.
CLEAR_HELP()
ENDIF
// B*1991223 - RESET need to block ambient anims during hail anims
IF bBlockingPlayerAmbientIdles = FALSE
SET_PED_CAN_PLAY_AMBIENT_ANIMS(PLAYER_PED_ID(), FALSE)
bBlockingPlayerAmbientIdles = TRUE
ENDIF
// task the player
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), vehHailTarget, 5000)
PLAY_HAIL_ANIMS_AND_DIALOGUE()
// B*2074743 - block aiming during hail animation
DISABLE_PLAYER_WEAPON_CONTROLS_FOR_HAIL_THIS_FRAME()
iTimer_HailAnimTriggered = GET_GAME_TIMER()
RELEASE_CONTEXT_INTENTION(iTaxiHailIntention)
// Failed attempt if taxi already has passengers
IF DOES_TAXI_ALREADY_HAVE_A_FARE(vehHailTarget)
IF IS_VEHICLE_DRIVEABLE(vehHailTarget)
SET_TAXI_LIGHTS(vehHailTarget, FALSE)
ENDIF
bHintTriggeredByTaxiLauncher = FALSE
eHailTaxiState = TL_HAIL_TAXI_STATE_FAILED_ATTEMPT
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_HAILING_TAXI() : eHailTaxiState = TL_HAIL_TAXI_STATE_FAILED_ATTEMPT") ENDIF #ENDIF
ELSE
// Successful attempt to hail a taxi
//update handles g_WaitingTaxi = vehicleIndex, g_WaitingTaxiDriver = pedIndex
PED_INDEX pedIndex
pedIndex = GET_PED_IN_VEHICLE_SEAT(vehHailTarget)
IF STORE_CAR_AS_TAXI_WAITING_FOR_PLAYER(vehHailTarget, pedIndex)
//release handle
vehHailTarget = NULL
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), g_WaitingTaxi, 5000)
g_iTaxiHailedTime = GET_GAME_TIMER()
IF IS_VEHICLE_DRIVEABLE(g_WaitingTaxi)
IF NOT IS_GAMEPLAY_HINT_ACTIVE()
SET_GAMEPLAY_VEHICLE_HINT(g_WaitingTaxi, <<0,0,0>>, TRUE, 4000)
bHintTriggeredByTaxiLauncher = TRUE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_HAILING_TAXI() : TRIGGER hint cam for taxi hail")
ENDIF
ENDIF
g_savedGlobals.sAmbient.bTaxiHailingHelpDisplayed = TRUE
eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_HAILING_TAXI() : eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT") ENDIF #ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
CLEANUP_HAIL_TAXI()
ENDIF
ELSE
CLEANUP_HAIL_TAXI()
ENDIF
ENDPROC
/// PURPOSE:
/// handle taxi driver gesturing to player to get in
PROC HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT()
// contains safe checks on taxi and it's driver
IF IS_TAXI_AND_DRIVER_OK_FOR_PLAYER_TO_ENTER_AS_PASSENGER(g_WaitingTaxi, g_WaitingTaxiDriver, mnTaxiModel, mnTaxiDriverModel)
BOOL bFlag = FALSE
IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_ENTER)
bFlag = TRUE
ENDIF
IF HAS_TIME_PASSED(iTimer_HailAnimTriggered, 1000)
IF (GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_PLAY_ANIM) = FINISHED_TASK)
IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FUCK_U")
AND NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FORGET_IT")
IF (GET_SCRIPT_TASK_STATUS(PLAYER_PED_ID(), SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK)
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, FALSE)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT: PCF_KeepWeaponHolsteredUnlessFired, FALSE")
// B*1991223 - RESET need to block ambient anims during hail anims
IF bBlockingPlayerAmbientIdles = TRUE
SET_PED_CAN_PLAY_AMBIENT_ANIMS(PLAYER_PED_ID(), TRUE)
bBlockingPlayerAmbientIdles = FALSE
ENDIF
bFlag = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
IF (bFlag)
REQUEST_ANIM_DICT(tlTaxiAnimDict)
IF HAS_ANIM_DICT_LOADED(tlTaxiAnimDict)
// chance shouting for taxi
IF GET_RANDOM_INT_IN_RANGE(0, 10) < 8
IF NOT IS_ANY_DIALOGUE_PLAYING(NULL, FALSE)
BOOL bPauseAmbientSpeech = IS_AMBIENT_SPEECH_DISABLED(PLAYER_PED_ID())
IF bPauseAmbientSpeech
STOP_PED_SPEAKING(PLAYER_PED_ID(), FALSE)
ENDIF
PLAY_PED_AMBIENT_SPEECH(PLAYER_PED_ID(), "TAXI_HAIL", SPEECH_PARAMS_SHOUTED)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT() : trigger TAXI_HAIL dialogue : bPauseAmbientSpeech = ", bPauseAmbientSpeech)
IF bPauseAmbientSpeech
STOP_PED_SPEAKING(PLAYER_PED_ID(), TRUE)
ENDIF
ENDIF
ENDIF
SEQUENCE_INDEX seq
OPEN_SEQUENCE_TASK(seq)
TASK_LOOK_AT_ENTITY(NULL, PLAYER_PED_ID(), 5000, SLF_WHILE_NOT_IN_FOV)
IF IS_PLAYER_TO_RIGHT_OF_CAR(g_WaitingTaxi)
TASK_PLAY_ANIM(NULL, tlTaxiAnimDict, "Aknowledge_R", NORMAL_BLEND_IN, SLOW_BLEND_OUT, -1, AF_SECONDARY|AF_UPPERBODY|AF_ABORT_ON_WEAPON_DAMAGE|AF_EXIT_AFTER_INTERRUPTED)
ELSE
TASK_PLAY_ANIM(NULL, tlTaxiAnimDict, "Aknowledge_L", NORMAL_BLEND_IN, SLOW_BLEND_OUT, -1, AF_SECONDARY|AF_UPPERBODY|AF_ABORT_ON_WEAPON_DAMAGE|AF_EXIT_AFTER_INTERRUPTED)
ENDIF
TASK_VEHICLE_MISSION(NULL, g_WaitingTaxi, g_WaitingTaxi, MISSION_PULL_OVER, 12.0, DRIVINGMODE_STOPFORCARS_STRICT, 3, 3)
TASK_VEHICLE_MISSION(NULL, g_WaitingTaxi, g_WaitingTaxi, MISSION_STOP, 12.0, DRIVINGMODE_STOPFORCARS_STRICT, 3, 3)
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(g_WaitingTaxiDriver, seq)
CLEAR_SEQUENCE_TASK(seq)
//INCREMENT_INT_STAT_NO_MESSAGE(STAT_NUMBER_TAXIS_HAILED, 1)
CREATE_WAITING_TAXI_BLIP()
eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT() : eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING") ENDIF #ENDIF
ENDIF
ENDIF
ELSE
CLEANUP_HAIL_TAXI()
ENDIF
ENDPROC
/// PURPOSE:
/// player aknowledges failed attempt
PROC HAIL_TAXI_STATE_FAILED_ATTEMPT()
// wait for the hail anims to end
IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
OR IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
EXIT
ELIF HAS_TIME_PASSED(iTimer_HailAnimTriggered, 3000)
REQUEST_ANIM_DICT(tlTaxiAnimDict)
IF HAS_ANIM_DICT_LOADED(tlTaxiAnimDict)
// contains checks to make anim can play safely
IF IS_PLAYER_ALLOWED_TO_HAIL_A_TAXI()
CLEAR_PED_TASKS(PLAYER_PED_ID())
SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, TRUE)
IF (GET_RANDOM_INT_IN_RANGE(0,3) < 2)
TASK_PLAY_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FORGET_IT", SLOW_BLEND_IN, REALLY_SLOW_BLEND_OUT, -1, AF_UPPERBODY|AF_SECONDARY)
ELSE
TASK_PLAY_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FUCK_U", SLOW_BLEND_IN, REALLY_SLOW_BLEND_OUT, -1, AF_UPPERBODY|AF_SECONDARY)
ENDIF
ENDIF
IF (GET_RANDOM_INT_IN_RANGE(0,5) = 1)
IF NOT (g_playerIsDrunk)
bPlayAdditionalFuckYouDialogue = TRUE
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "Played additional taxi fuck you dialogue ")
ENDIF
ENDIF
iTimer_HailAnimTriggered = GET_GAME_TIMER() // reset for fuck you dialogue
iTimer_HailFailedDialogueDelay = GET_GAME_TIMER() // dialogue delay
// B*1991223 - RESET need to block ambient anims during hail anims
IF bBlockingPlayerAmbientIdles = TRUE
SET_PED_CAN_PLAY_AMBIENT_ANIMS(PLAYER_PED_ID(), TRUE)
bBlockingPlayerAmbientIdles = FALSE
ENDIF
IF iTaxiHailIntention <> NEW_CONTEXT_INTENTION
RELEASE_CONTEXT_INTENTION(iTaxiHailIntention)
//SET_PED_CONFIG_FLAG(PLAYER_PED_ID(), PCF_KeepWeaponHolsteredUnlessFired, FALSE)
CPRINTLN(DEBUG_TAXI_SERVICE, "HAIL_TAXI_STATE_FAILED_ATTEMPT() - RELEASE_CONTEXT_INTENTION iTaxiHailIntention")
ENDIF
eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " HAIL_TAXI_STATE_FAILED_ATTEMPT() : eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE") ENDIF #ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// handles taxi which is classed as waiting for the player
PROC HAIL_TAXI_STATE_TAXI_WAITING()
IF IS_TAXI_AND_DRIVER_OK_FOR_PLAYER_TO_ENTER_AS_PASSENGER(g_WaitingTaxi, g_WaitingTaxiDriver, mnTaxiModel, mnTaxiDriverModel)
IF NOT SHOULD_WAITING_TAXI_CLEANUP()
IF NOT TAXI_IS_PED_PERFORMING_TASK(g_WaitingTaxiDriver, SCRIPT_TASK_VEHICLE_TEMP_ACTION)
TASK_VEHICLE_TEMP_ACTION(g_WaitingTaxiDriver, g_WaitingTaxi, TEMPACT_WAIT, 1000000)
ENDIF
// B*1536974 - Press to enter taxi as passenger hold to jack driver - opposite to how it worked on IV
// to get IV behaviour you have to ensur this flag is false then task the player in script to enter as rear passenger when input detected
SET_PED_CONFIG_FLAG(g_WaitingTaxiDriver, PCF_AICanDrivePlayerAsRearPassenger, TRUE)
CLEAR_HINT_CAM_IF_PLAYER_IS_MOVING()
// taxi blip flash updated (if exists) could get here from entering nearby taxi
IF DOES_BLIP_EXIST(blipWaitingTaxi)
SET_BLIP_FLASH_TIMER(blipWaitingTaxi, 10000)
ENDIF
ELSE
CLEANUP_HAIL_TAXI()
ENDIF
ELSE
CLEANUP_HAIL_TAXI()
ENDIF
ENDPROC
/// PURPOSE:
/// handles script task for the player getting in the taxi vehicleIndex
/// Sets eEnterTaxiState = TL_ENTER_TAXI_STATE_ENTERING when attempt has been made
/// NOTE: safe checks will have already been performed at this stage
PROC DETECT_PLAYER_ATTEMPT_TO_ENTER_TAXI()
IF IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK(vehClosestTaxi)
//IF NOT IS_ENTITY_UPRIGHT(vehIndexArray[i])
//OR IS_ENTITY_IN_WATER(vehIndexArray[i])
// if it's the hailed taxi pull up help text
IF NOT bHelpEnterTaxiDisplayed
// only show help if this is a taxi we have called / hailed
IF (vehClosestTaxi = g_WaitingTaxi)
AND eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
IF NOT IS_HELP_MESSAGE_ON_SCREEN()
IF NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TX_H02") // Hold ~INPUT_ENTER~ to enter the cab as a passenger.
IF g_savedGlobals.sAmbient.iTaxiEnterPromptDisplayed < 5
PRINT_HELP("TX_H02") //Hold ~INPUT_ENTER~ to enter the cab as a passenger.
g_savedGlobals.sAmbient.iTaxiEnterPromptDisplayed++
ENDIF
bHelpEnterTaxiDisplayed = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
VEHICLE_INDEX vehTemp = GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID()) // this will return active task so when he's also pathing to the vehicle
// check for player getting into the taxi
IF DOES_ENTITY_EXIST(vehTemp)
IF (vehTemp = vehClosestTaxi)
// grab handle to the taxi driver
PED_INDEX pedIndex = GET_PED_IN_VEHICLE_SEAT(vehClosestTaxi) // all safe checks have already been performed in IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER
// if this taxi isn't the current waiting taxi cleanup the hailed state
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
OR eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
IF (vehClosestTaxi != g_WaitingTaxi)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DETECT_PLAYER_ATTEMPT_TO_ENTER_TAXI reset eHailTaxiState for already inside a taxi which isn't g_WaitingTaxi")
CLEANUP_HAIL_TAXI()
ENDIF
ENDIF
DISABLE_SELECTOR_THIS_FRAME() // B*1559411 - block char switching whilst entering a taxi
//update handles g_WaitingTaxi = vehicleIndex, g_WaitingTaxiDriver = pedIndex
IF STORE_CAR_AS_TAXI_WAITING_FOR_PLAYER(vehClosestTaxi, pedIndex)
//release handle - don't do this since we can kick back here from enter failed
//vehClosestTaxi = NULL
IF bHintTriggeredByTaxiLauncher // B* 1478914 - stop hint cam when player getting in
IF IS_GAMEPLAY_HINT_ACTIVE()
STOP_GAMEPLAY_HINT()
ENDIF
bHintTriggeredByTaxiLauncher = FALSE
ENDIF
// just doing this when player is in seat now
//SET_PLAYER_GROUP_MEMBERS_INTO_TAXI(g_WaitingTaxi, ePlayerChosenSeat) // GET_GROUP_INTO_CAB(GET_NEAREST_PASSENGER_SIDE(g_WaitingTaxi))
IF NOT IS_PED_INJURED(g_WaitingTaxiDriver)
AND IS_VEHICLE_DRIVEABLE(g_WaitingTaxi)
IF IS_PED_SITTING_IN_VEHICLE(g_WaitingTaxiDriver, g_WaitingTaxi)
IF NOT TAXI_IS_PED_PERFORMING_TASK(g_WaitingTaxiDriver, SCRIPT_TASK_VEHICLE_TEMP_ACTION)
TASK_VEHICLE_TEMP_ACTION(g_WaitingTaxiDriver, g_WaitingTaxi, TEMPACT_WAIT, 10000)
ENDIF
ENDIF
ENDIF
bHelpEnterTaxiDisplayed = FALSE
eEnterTaxiState = TL_ENTER_TAXI_STATE_ENTERING
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : DETECT_PLAYER_ATTEMPT_TO_ENTER_TAXI() : eEnterTaxiState = TL_ENTER_TAXI_STATE_ENTERING FC = ", GET_FRAME_COUNT())
ENDIF
ENDIF
ENDIF
ELSE
// should'nt require any cleanup at this point
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TX_H02") // Hold ~INPUT_ENTER~ to enter the cab as a passenger.
CLEAR_HELP()
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// updates the player's script task to get into the taxi vehicleIndex
/// NOTE: safe checks will have already been performed at this stage
PROC UPDATE_PLAYER_ENTER_TAXI_TASK()
IF IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK(g_WaitingTaxi) // should only get tasked to enter g_waitingtaxi
VEHICLE_INDEX vehTemp = GET_VEHICLE_PED_IS_ENTERING(PLAYER_PED_ID()) // this will return active task so when he's also pathing to the vehicle
// check for player getting into the taxi
IF DOES_ENTITY_EXIST(vehTemp)
IF (vehTemp = vehClosestTaxi)
DISABLE_SELECTOR_THIS_FRAME() // B*1559411 - block char switching whilst entering a taxi
// make sure the driver waits until the player gets in
IF NOT IS_PED_INJURED(g_WaitingTaxiDriver)
AND IS_VEHICLE_DRIVEABLE(g_WaitingTaxi)
IF IS_PED_SITTING_IN_VEHICLE(g_WaitingTaxiDriver, g_WaitingTaxi)
IF NOT TAXI_IS_PED_PERFORMING_TASK(g_WaitingTaxiDriver, SCRIPT_TASK_VEHICLE_TEMP_ACTION)
TASK_VEHICLE_TEMP_ACTION(g_WaitingTaxiDriver, g_WaitingTaxi, TEMPACT_WAIT, 1000000)
ENDIF
ENDIF
ENDIF
ELSE
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_PLAYER_ENTER_TAXI_TASK reset to IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK player entering different vehicle check FC = ", GET_FRAME_COUNT())
ENDIF
ELSE
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_PLAYER_ENTER_TAXI_TASK reset to IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK player not entering vehicle now check FC = ", GET_FRAME_COUNT())
ENDIF
ELSE
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : UPDATE_PLAYER_ENTER_TAXI_TASK reset to IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK check FC = ", GET_FRAME_COUNT())
ENDIF
ENDPROC
/// PURPOSE:
/// handle awaiting player attempt to enter a taxi state
PROC ENTER_TAXI_STATE_IDLE()
// don't process checks if the closest taxi hasn't been found
IF DOES_ENTITY_EXIST(vehClosestTaxi)
// make sure the taxi is suitable to get in
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(vehClosestTaxi, mnTaxiModel, mnTaxiDriverModel)
// don't process checks if player is already in vehicle
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
// now Handles by UPDATE_TAXI_SEARCH_HANDLES()
//vehIndexTemp = GET_CLOSEST_VEHICLE(vPlayerPos, 10.0, TAXI, GET_TAXI_SEARCH_FLAGS())
// once detected enter taxi attempt g_WaitingTaxi and g_WaitingTaxiDriver handles are updated
DETECT_PLAYER_ATTEMPT_TO_ENTER_TAXI()
ELSE
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
// check the vehicle he's in isn't infact the taxi
IF IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), vehClosestTaxi)
//IF (GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), FALSE) = vehClosestTaxi)
// grab handle to the taxi driver
PED_INDEX pedIndex = GET_PED_IN_VEHICLE_SEAT(vehClosestTaxi) // all safe checks have already been performed in IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER
// store the seat Player is in to task the group members to enter
IF NOT IS_VEHICLE_SEAT_FREE(vehClosestTaxi, VS_BACK_LEFT)
IF (GET_PED_IN_VEHICLE_SEAT(vehClosestTaxi, VS_BACK_LEFT) = PLAYER_PED_ID())
ePlayerChosenSeat = VS_BACK_LEFT
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_IDLE player already sat in taxi seat VS_BACK_LEFT")
ENDIF
ENDIF
IF NOT IS_VEHICLE_SEAT_FREE(vehClosestTaxi, VS_BACK_RIGHT)
IF (GET_PED_IN_VEHICLE_SEAT(vehClosestTaxi, VS_BACK_RIGHT) = PLAYER_PED_ID())
ePlayerChosenSeat = VS_BACK_RIGHT
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_IDLE player already sat in taxi seat VS_BACK_RIGHT")
ENDIF
ENDIF
// if this taxi isn't the current waiting taxi cleanup the hailed state
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
OR eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
IF (vehClosestTaxi != g_WaitingTaxi)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_IDLE reset eHailTaxiState for entering a veh which isn't g_WaitingTaxi")
CLEANUP_HAIL_TAXI()
ENDIF
ENDIF
DISABLE_SELECTOR_THIS_FRAME() // B*1559411 - block char switching whilst entering a taxi
//update handles g_WaitingTaxi = vehicleIndex, g_WaitingTaxiDriver = pedIndex
IF STORE_CAR_AS_TAXI_WAITING_FOR_PLAYER(vehClosestTaxi, pedIndex)
//release handle
vehClosestTaxi = NULL
eEnterTaxiState = TL_ENTER_TAXI_STATE_INSIDE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_IDLE() : TL_ENTER_TAXI_STATE_IDLE -> TL_ENTER_TAXI_STATE_INSIDE FC = ", GET_FRAME_COUNT())
ENDIF
ELSE
// got in a vehicle which wasn't the closest taxi so cleanup
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_IDLE() : cleanup for entering veh which wasn't vehClosestTaxi FC = ", GET_FRAME_COUNT())
CLEANUP_ENTER_CLOSEST_TAXI()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Player is process of entering taxi using scripted task
PROC ENTER_TAXI_STATE_ENTERING()
// make sure the vehicle the player has been tasks to enter is still ok
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(g_WaitingTaxi, mnTaxiModel, mnTaxiDriverModel)
// check for the player making it into the taxi (IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER checks driver if in driver seat)
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), g_WaitingTaxi)
IF IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), g_WaitingTaxi)
eEnterTaxiState = TL_ENTER_TAXI_STATE_INSIDE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_ENTERING() : TL_ENTER_TAXI_STATE_ENTERING -> TL_ENTER_TAXI_STATE_INSIDE FC = ", GET_FRAME_COUNT())
ENDIF
DISABLE_SELECTOR_THIS_FRAME() // B*1559411 - block char switching whilst entering a taxi
ELSE
UPDATE_PLAYER_ENTER_TAXI_TASK()
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_ENTERING() : cleanup for IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK check")
CLEANUP_ENTER_CLOSEST_TAXI()
ENDIF
ENDPROC
/// PURPOSE:
/// Player has successfully got in the back of a taxi - launche the taxiService.sc script
PROC ENTER_TAXI_STATE_INSIDE()
// make sure the vehicle the player has been tasks to enter is still ok
IF IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER(g_WaitingTaxi, mnTaxiModel, mnTaxiDriverModel)
// check for the player making it into the taxi (IS_PLAYER_OK_TO_ENTER_VEHICLE_AS_PASSENGER checks driver if in driver seat)
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), g_WaitingTaxi)
IF IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), g_WaitingTaxi)
DISABLE_SELECTOR_THIS_FRAME() // B*1559411 - block char switching whilst entering a taxi
// store the seat the player is in to task the group members
IF GET_PED_IN_VEHICLE_SEAT(g_WaitingTaxi, VS_BACK_LEFT) = PLAYER_PED_ID()
ePlayerChosenSeat = VS_BACK_LEFT
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_INSIDE() : stored ePlayerChosenSeat = VS_BACK_LEFT")
ELSE
ePlayerChosenSeat = VS_BACK_RIGHT
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_INSIDE() : stored ePlayerChosenSeat = VS_BACK_RIGHT but test only based of not being in back left seat")
ENDIF
SET_PLAYER_GROUP_MEMBERS_INTO_TAXI(g_WaitingTaxi, ePlayerChosenSeat) // GET_GROUP_INTO_CAB(GET_NEAREST_PASSENGER_SIDE(g_WaitingTaxi))
// make sure the driver waits until the script kicks in
IF NOT IS_PED_INJURED(g_WaitingTaxiDriver)
AND IS_VEHICLE_DRIVEABLE(g_WaitingTaxi)
IF IS_PED_SITTING_IN_VEHICLE(g_WaitingTaxiDriver, g_WaitingTaxi)
IF NOT TAXI_IS_PED_PERFORMING_TASK(g_WaitingTaxiDriver, SCRIPT_TASK_VEHICLE_TEMP_ACTION)
TASK_VEHICLE_TEMP_ACTION(g_WaitingTaxiDriver, g_WaitingTaxi, TEMPACT_WAIT, 1000000)
ENDIF
ENDIF
ENDIF
// make sure any taxi on route to the player cleans up
CLEANUP_DISPATCHED_TAXI_DATA()
CLEANUP_HAIL_TAXI()
IF bHelpEnterTaxiDisplayed
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("TX_H02") // Hold ~INPUT_ENTER~ to enter the cab as a passenger.
CLEAR_HELP()
ENDIF
bHelpEnterTaxiDisplayed = FALSE
ENDIF
NON_GROUPED_PASSENGERS_SHOULD_FLEE()
SET_JACKED_PED_TO_FLEE()
SET_PLAYER_CAN_DO_DRIVE_BY(PLAYER_ID(), FALSE)
// request the taxiService.sc script
REQUEST_SCRIPT("taxiService")
IF HAS_SCRIPT_LOADED("taxiService")
tTaxiServiceThread = START_NEW_SCRIPT("taxiService", SPECIAL_ABILITY_STACK_SIZE)
SET_SCRIPT_AS_NO_LONGER_NEEDED("taxiService")
eTaxiLauncherState = TL_STATE_PLAYER_IN_TAXI
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_INSIDE() : TL_ENTER_TAXI_STATE_INSIDE launched taxiService.sc FC = ", GET_FRAME_COUNT())
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_INSIDE() : player got out cab so RESET_TAXI_LAUNCHER() FC = ", GET_FRAME_COUNT())
RESET_TAXI_LAUNCHER()
ENDIF
ELSE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : ENTER_TAXI_STATE_INSIDE() : cleanup for IS_PLAYER_OK_TO_USE_ENTER_VEHICLE_TASK check FC = ", GET_FRAME_COUNT())
CLEANUP_ENTER_CLOSEST_TAXI()
ENDIF
ENDPROC
/// PURPOSE:
/// Check reasons to reset and cleanup the dispatched taxi
/// RETURNS:
/// TRUE if dispatched taxi should cleanup
FUNC BOOL SHOULD_DISPATCHED_TAXI_CLEANUP()
// check for player leaving area taxi was requested from if so clenup
IF NOT TAXI_IS_COORD_IN_RANGE_OF_COORD(vPlayerPos, sDispatchedTaxi.vPlayerCalledCoords, 100.0)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : Player left area taxi requested from ")
RETURN TRUE
ENDIF
// cleanup if player char has changed
IF GET_PLAYER_PED_ENUM(PLAYER_PED_ID()) <> sDispatchedTaxi.eCharDispatchedFor
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : Player char changed ")
RETURN TRUE
ENDIF
// cleanup if player has a waiting taxi
IF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING")
RETURN TRUE
ENDIF
// stage specific checks
IF eDispatchedTaxiState = TL_DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER
OR eDispatchedTaxiState = TL_DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER
IF NOT IS_PED_UNINJURED(sDispatchedTaxi.pedIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : sDispatchedTaxi.pedIndex injured")
RETURN TRUE
ENDIF
IF NOT IS_VEHICLE_OK(sDispatchedTaxi.vehicleIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : sDispatchedTaxi.vehicleIndex veh wrecked")
RETURN TRUE
ENDIF
// driver no longer in the taxi
IF NOT IS_PED_SITTING_IN_VEHICLE(sDispatchedTaxi.pedIndex, sDispatchedTaxi.vehicleIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : sDispatchedTaxi.pedIndex not sat in DispatchedTaxi.vehicleIndex")
RETURN TRUE
ENDIF
IF IS_PED_FLEEING(sDispatchedTaxi.pedIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : sDispatchedTaxi.pedIndex is fleeing")
RETURN TRUE
ENDIF
IF IS_PED_IN_COMBAT(sDispatchedTaxi.pedIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP() : return TRUE : sDispatchedTaxi.pedIndex is in combat")
RETURN TRUE
ENDIF
// player attacked taxi
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sDispatchedTaxi.vehicleIndex, PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : damaged taxi check")
RETURN TRUE
ENDIF
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sDispatchedTaxi.pedIndex, PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : damaged taxi driver check")
RETURN TRUE
ENDIF
VECTOR vTaxiCoords = GET_ENTITY_COORDS(sDispatchedTaxi.vehicleIndex, FALSE)
// bullet fired near taxi
IF IS_BULLET_IN_AREA(vTaxiCoords, 7.0, FALSE)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : bullet fired near taxi")
RETURN TRUE
ENDIF
FLOAT fProjectileRadiusCheck = 15.0
VECTOR vMin, vMax // is one of the player's projectiles nearby?
vMin = vTaxiCoords
vMax = vMin
vMin.x= vMin.x - fProjectileRadiusCheck
vMin.y = vMin.y -fProjectileRadiusCheck
vMin.z = vMin.z - fProjectileRadiusCheck
vMax.x = vMax.x + fProjectileRadiusCheck
vMax.y = vMax.y + fProjectileRadiusCheck
vMax.z = vMax.z + fProjectileRadiusCheck
IF IS_PROJECTILE_IN_AREA(vMin, vMax, TRUE)
CPRINTLN(DEBUG_TAXI_SERVICE, " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : projectile near taxi")
RETURN TRUE
ENDIF
IF TAXI_IS_COORD_IN_RANGE_OF_COORD(vPlayerPos, vTaxiCoords, 20.0)
// aiming at the taxi
IF IS_PLAYER_FREE_AIMING_AT_ENTITY(PLAYER_ID(), sDispatchedTaxi.vehicleIndex)
OR IS_PLAYER_TARGETTING_ENTITY(PLAYER_ID(), sDispatchedTaxi.vehicleIndex)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : aiming at the taxi")
RETURN TRUE
ENDIF
// check for player shooting near waiting taxi
IF IS_PED_SHOOTING(PLAYER_PED_ID())
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : SHOULD_DISPATCHED_TAXI_CLEANUP : return TRUE : player shooting check")
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// handles the player calling for a taxi and it arriving to pick him up
PROC PROCESS_TAXI_PHONECALLS()
// Player starts by calling the taxi firm
IF eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
IF IS_CALLING_CONTACT(CHAR_TAXI)
#IF IS_DEBUG_BUILD OR bDebug_CallCab #ENDIF
IF IS_TAXI_SERVICE_LISTED_IN_PLAYERS_PHONEBOOK(GET_CURRENT_PLAYER_PED_ENUM())
IDENTIFY_PLAYER()
ADD_PED_FOR_DIALOGUE(phonecallStruct, 0, PLAYER_PED_ID(), playerVoice)
ADD_PED_FOR_DIALOGUE(phonecallStruct, 1, NULL, "TaxiDispatch")
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " IS_CALLING_CONTACT(CHAR_TAXI)")
IF IS_PLAYER_ALLOWED_TO_CALL_TAXI()
// #if USE_TU_CHANGES
// IF IS_CURRENT_MISSION_DLC() //Added by Steve T to make taxi calls DLC compliant. 06.02.14
//
// IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_3_LINES_USING_V_CONTENT_IN_DLC(phonecallStruct, CHAR_TAXI, "TAXISAU", playerLine1, playerLine1, "TX_2", "TX_2", playerLine3, playerLine3, CONV_PRIORITY_NON_CRITICAL_CALL)
// #IF IS_DEBUG_BUILD OR bDebug_CallCab #ENDIF
// bPhonecallReachedSuccessfulLine = FALSE
// eCallTaxiServiceState = TL_PHONE_STATE_CALL_IN_PROGRESS
// CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_AWAITING_CALL -> TL_PHONE_STATE_CALL_IN_PROGRESS : using ",
// " FirstRootLabel = ", playerLine1, " FirstSpecificLabel = ", playerLine1, " SecondRootLabel = TX_2 ", " SecondSpecificLabel = TX_2",
// " ThirdRootLabel = ", playerLine3, " ThirdSpecificLabel = ", playerLine3)
// ENDIF
//
// ELSE
// #endif
IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_3_LINES(phonecallStruct, CHAR_TAXI, "TAXISAU", playerLine1, playerLine1, "TX_2", "TX_2", playerLine3, playerLine3, CONV_PRIORITY_NON_CRITICAL_CALL)
#IF IS_DEBUG_BUILD OR bDebug_CallCab #ENDIF
bPhonecallReachedSuccessfulLine = FALSE
eCallTaxiServiceState = TL_PHONE_STATE_CALL_IN_PROGRESS
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_AWAITING_CALL -> TL_PHONE_STATE_CALL_IN_PROGRESS : using ",
" FirstRootLabel = ", playerLine1, " FirstSpecificLabel = ", playerLine1, " SecondRootLabel = TX_2 ", " SecondSpecificLabel = TX_2",
" ThirdRootLabel = ", playerLine3, " ThirdSpecificLabel = ", playerLine3)
ENDIF
// #if USE_TU_CHANGES
// ENDIF
// #endif
ELSE
// #if USE_TU_CHANGES
// IF IS_CURRENT_MISSION_DLC() //Added by Steve T to make taxi calls DLC compliant. 06.02.14
//
// IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_2_LINES_USING_V_CONTENT_IN_DLC(phonecallStruct, CHAR_TAXI, "TAXISAU", playerLine1, playerLine1, "TX_2A", "TX_2A", CONV_PRIORITY_NON_CRITICAL_CALL)
// eCallTaxiServiceState = TL_PHONE_STATE_WAIT_TO_RESET_CALL
// CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_AWAITING_CALL -> TL_PHONE_STATE_WAIT_TO_RESET_CALL : using ",
// " FirstRootLabel = ", playerLine1, " FirstSpecificLabel = ", playerLine1, " SecondRootLabel = TX_2A ", " SecondSpecificLabel = TX_2A")
// ENDIF
//
// ELSE
// #endif
IF PLAYER_CALL_CHAR_CELLPHONE_MULTIPART_WITH_2_LINES(phonecallStruct, CHAR_TAXI, "TAXISAU", playerLine1, playerLine1, "TX_2A", "TX_2A", CONV_PRIORITY_NON_CRITICAL_CALL)
eCallTaxiServiceState = TL_PHONE_STATE_WAIT_TO_RESET_CALL
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_AWAITING_CALL -> TL_PHONE_STATE_WAIT_TO_RESET_CALL : using ",
" FirstRootLabel = ", playerLine1, " FirstSpecificLabel = ", playerLine1, " SecondRootLabel = TX_2A ", " SecondSpecificLabel = TX_2A")
ENDIF
// #if USE_TU_CHANGES
// ENDIF
// #endif
ENDIF
ENDIF
ENDIF
// state to wait in until an unsuccessful call for a taxi has finished
ELIF eCallTaxiServiceState = TL_PHONE_STATE_WAIT_TO_RESET_CALL
IF HAS_CELLPHONE_CALL_FINISHED()
eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_WAIT_TO_RESET_CALL -> TL_PHONE_STATE_AWAITING_CALL")
ENDIF
// successful call to order a taxi
ELIF eCallTaxiServiceState = TL_PHONE_STATE_CALL_IN_PROGRESS
IF HAS_CELLPHONE_CALL_FINISHED()
// check for player hanging up before phnecall finished
IF WAS_LAST_CELLPHONE_CALL_INTERRUPTED()
// if phonecall reached successful line allow register as successful call anyway
IF NOT bPhonecallReachedSuccessfulLine
eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_CALL_IN_PROGRESS -> TL_PHONE_STATE_AWAITING_CALL : WAS_LAST_CELLPHONE_CALL_INTERRUPTED()")
ENDIF
// check if the player receives an injury or starts ragdolling then during the phonecall
ELIF HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()
// if phonecall reached successful line allow register as successful call anyway
IF NOT bPhonecallReachedSuccessfulLine
eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_CALL_IN_PROGRESS -> TL_PHONE_STATE_AWAITING_CALL : HAS_CELLPHONE_JUST_BEEN_FORCED_AWAY()")
ENDIF
ENDIF
// successful phonecall
IF eCallTaxiServiceState != TL_PHONE_STATE_AWAITING_CALL
IF NOT HAS_ONE_TIME_HELP_DISPLAYED(FHM_TAXI_PHONE_INTRODUCED)
SET_ONE_TIME_HELP_MESSAGE_DISPLAYED(FHM_TAXI_PHONE_INTRODUCED)
ENDIF
CLEANUP_DISPATCHED_TAXI_DATA()
sDispatchedTaxi.iTimer_TaxiDispatchDelay = GET_GAME_TIMER() // set timer ready for delay
sDispatchedTaxi.vPlayerCalledCoords = vPlayerPos // set position player is when call was processed
sDispatchedTaxi.eCharDispatchedFor = GET_PLAYER_PED_ENUM(PLAYER_PED_ID()) // store which ped we are dispatched for
sDispatchedTaxi.iNodeSearchNumber = 0 // set ready for creation node checks
sDispatchedTaxi.iSpawnAttempts = 0 // set ready for creation checks
// set the dispatched taxi state running
eDispatchedTaxiState = TL_DISPATCHED_STATE_CREATE_TAXI
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : eDispatchedTaxiState = TL_DISPATCHED_STATE_CREATE_TAXI")
eCallTaxiServiceState = TL_PHONE_STATE_AWAITING_CALL
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_CALL_IN_PROGRESS -> TL_PHONE_STATE_AWAITING_CALL : dispatched taxi")
ENDIF
ELSE
// register when we've reached the positive response line to set call as successful
IF NOT bPhonecallReachedSuccessfulLine
// info from Steven - If audio added SFX pauses at a later date it may screw up your logic.
// Unfortunately GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_ROOT() & GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_LABEL() don't work for this
IF GET_CURRENT_SCRIPTED_CONVERSATION_LINE() = 1
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), "PROCESS_TAXI_PHONECALLS : TL_PHONE_STATE_CALL_IN_PROGRESS : reached successful call line > 2 TX_2 : ")
bPhonecallReachedSuccessfulLine = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// we now have to maintain some checks everyframe the player is not in a taxi
PROC PROCESS_EVERYFRAME_NOT_IN_TAXI_UPDATES()
// B*2074743 - need to call the aim blocking everyframe the hail animation is active
IF eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
OR eHailTaxiState = TL_HAIL_TAXI_STATE_FAILED_ATTEMPT
IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "HAIL_TAXI")
OR IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), tlTaxiAnimDict, "FP_HAIL_TAXI")
DISABLE_PLAYER_WEAPON_CONTROLS_FOR_HAIL_THIS_FRAME()
ENDIF
ENDIF
//CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : PROCESS_EVERYFRAME_NOT_IN_TAXI_UPDATES hit this frame: ", GET_FRAME_COUNT())
ENDPROC
/// PURPOSE:
/// handles creating the dispatched taxi and navigating it to the player
PROC PROCESS_DISPATCHED_TAXI()
// Check reasons to reset and cleanup the dispatched taxi
IF eDispatchedTaxiState != TL_DISPATCHED_STATE_IDLE
IF SHOULD_DISPATCHED_TAXI_CLEANUP()
CLEANUP_DISPATCHED_TAXI_DATA()
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_DISPATCHED_TAXI() : CLEANUP_DISPATCHED_TAXI_DATA()")
ENDIF
ENDIF
// state where the script will wait until a request to dispatch a taxi has been processed
IF eDispatchedTaxiState = TL_DISPATCHED_STATE_IDLE
// create a taxi to go over to the player
ELIF eDispatchedTaxiState = TL_DISPATCHED_STATE_CREATE_TAXI
DISPATCHED_STATE_CREATE_TAXI()
// handle driving the taxi over to the player
ELIF eDispatchedTaxiState = TL_DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER
DISPATCHED_STATE_DRIVE_TO_PICKUP_PLAYER()
// make the taxi pull over to pickup the player
ELIF eDispatchedTaxiState = TL_DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER
DISPATCHED_STATE_PULL_OVER_TO_PICKUP_PLAYER()
ENDIF
ENDPROC
/// PURPOSE:
/// handles the player hailing taxis
PROC PROCESS_PLAYER_HAILING_TAXI()
// state to wait until a hail target has been found by UPDATE_TAXI_SEARCH_HANDLES
IF eHailTaxiState = TL_HAIL_TAXI_STATE_IDLE
IF DOES_ENTITY_EXIST(vehHailTarget)
eHailTaxiState = TL_HAIL_TAXI_STATE_DETECT_HAIL
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_HAILING_TAXI() : TL_HAIL_TAXI_STATE_IDLE -> TL_HAIL_TAXI_STATE_DETECT_HAIL") ENDIF #ENDIF
ENDIF
// waiting to for player to attempt to hail a taxi
ELIF eHailTaxiState = TL_HAIL_TAXI_STATE_DETECT_HAIL
HAIL_STATE_DETECT_HAIL()
// taxi driver responses - gestures player to get in
ELIF eHailTaxiState = TL_HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT
HAIL_TAXI_STATE_SUCCESSFUL_ATTEMPT()
// player aknowledges failed attempt
ELIF eHailTaxiState = TL_HAIL_TAXI_STATE_FAILED_ATTEMPT
HAIL_TAXI_STATE_FAILED_ATTEMPT()
// Taxi is classed a waiting (blipped up waits for player to enter)
ELIF eHailTaxiState = TL_HAIL_TAXI_STATE_TAXI_WAITING
HAIL_TAXI_STATE_TAXI_WAITING()
ENDIF
ENDPROC
/// PURPOSE:
/// handles the player getting into the back of the closest taxi
PROC PROCESS_PLAYER_ENTER_CLOSEST_TAXI()
// Waiting to detect player attempt to enter a taxi
IF eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
ENTER_TAXI_STATE_IDLE()
// Player has been tasked to enter the Taxi, wait to see if he gets in
ELIF eEnterTaxiState = TL_ENTER_TAXI_STATE_ENTERING
ENTER_TAXI_STATE_ENTERING()
// Player is in the back of the taxi - launch the taxiService.sc script
ELIF eEnterTaxiState = TL_ENTER_TAXI_STATE_INSIDE
ENTER_TAXI_STATE_INSIDE()
// State waiting until player left the taxi
ELIF eEnterTaxiState = TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
eEnterTaxiState = TL_ENTER_TAXI_STATE_IDLE
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_ENTER_CLOSEST_TAXI() : TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT -> TL_ENTER_TAXI_STATE_IDLE : FC = ", GET_FRAME_COUNT()) ENDIF #ENDIF
ELSE
#IF IS_DEBUG_BUILD IF bDebug_DisplayInfo CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " PROCESS_PLAYER_ENTER_CLOSEST_TAXI() : TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT waiting for player to leave veh : FC = ", GET_FRAME_COUNT()) ENDIF #ENDIF
ENDIF
ENDIF
ENDPROC
SCRIPT
IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_MAGDEMO)
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : force cleanup occured, script set to terminate")
TAXI_LAUNCHER_SCRIPT_CLEANUP()
TERMINATE_THIS_THREAD()
ENDIF
#IF IS_DEBUG_BUILD DEBUG_SETUP_WIDGETS() #ENDIF
//#IF IS_DEBUG_BUILD DEBUG_SETUP_AREAS_WIDGETS() #ENDIF
g_savedGlobals.sAmbient.bTaxiHailingHelpDisplayed = TRUE
WHILE TRUE
SWITCH eTaxiLauncherState
// State where the launch will wait until it's safe to run
CASE TL_STATE_IDLE
IF IS_TAXI_SERVICE_SAFE_TO_RUN()
eTaxiLauncherState = TL_STATE_PLAYER_NOT_IN_TAXI
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : TL_STATE_IDLE -> TL_STATE_PLAYER_NOT_IN_TAXI")
ELSE
WAIT(500)
ENDIF
BREAK
// State where player can use a taxi
CASE TL_STATE_PLAYER_NOT_IN_TAXI
IF IS_TAXI_SERVICE_SAFE_TO_RUN()
// used multiple times so only grabbed once per frame, injured status is tested in IS_TAXI_SERVICE_SAFE_TO_RUN
vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE)
PROCESS_TAXI_PHONECALLS()
IF IS_PLAYER_ALLOWED_TO_ENTER_TAXI_AS_PASSENGER()
SET_VEHICLE_MODEL_IS_SUPPRESSED(TAXI, FALSE)
// We now have first instance of something which needs to be maintained everyframe
PROCESS_EVERYFRAME_NOT_IN_TAXI_UPDATES()
// optimisation - only process funcs if handles weren't updated this frame
IF NOT ALT_UPDATE_TAXI_SEARCH_HANDLES()
PROCESS_DISPATCHED_TAXI()
PROCESS_PLAYER_HAILING_TAXI()
PROCESS_PLAYER_ENTER_CLOSEST_TAXI()
ENDIF
ELSE
RESET_TAXI_LAUNCHER(FALSE)
eTaxiLauncherState = TL_STATE_PLAYER_NOT_IN_TAXI // esure we remain in this launcher state
UPDATE_PLAYER_ALLOWED_TO_RIDE_IN_TAXIS_STATUS()
WAIT(500)
ENDIF
ELSE
RESET_TAXI_LAUNCHER()
eTaxiLauncherState = TL_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : TL_STATE_PLAYER_NOT_IN_TAXI -> TL_STATE_IDLE")
ENDIF
BREAK
// State where TaxiService.sc has been launched and we await the script terminating
CASE TL_STATE_PLAYER_IN_TAXI
IF NOT IS_THREAD_ACTIVE(tTaxiServiceThread)
RESET_TAXI_LAUNCHER()
// because the taxiService script can terminate before player is completely out the taxi - wait to recheck
eEnterTaxiState = TL_ENTER_TAXI_STATE_WAIT_FOR_PLAYER_TO_EXIT
eTaxiLauncherState = TL_STATE_IDLE
CPRINTLN(DEBUG_TAXI_SERVICE, GET_THIS_SCRIPT_NAME(), " : TL_STATE_PLAYER_IN_TAXI -> TL_STATE_IDLE")
ENDIF
BREAK
ENDSWITCH
#IF IS_DEBUG_BUILD DEBUG_UPDATE_WIDGETS() #ENDIF
//#IF IS_DEBUG_BUILD DEBUG_UPDATE_AREA_WIDGETS() #ENDIF
WAIT(0)
ENDWHILE
ENDSCRIPT