Files
gtav-src/script/dev_ng/singleplayer/scripts/RandomChar/Barry/Barry3A.sc
T
2025-09-29 00:52:08 +02:00

2735 lines
86 KiB
Python
Executable File

//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
USING "rage_builtins.sch"
USING "globals.sch"
USING "cutscene_public.sch"
USING "commands_cutscene.sch"
USING "commands_entity.sch"
USING "commands_script.sch"
USING "script_player.sch"
USING "randomChar_public.sch"
USING "script_ped.sch"
USING "dialogue_public.sch"
USING "comms_control_public.sch"
USING "RC_Helper_Functions.sch"
USING "CompletionPercentage_public.sch"
USING "replay_public.sch"
USING "locates_public.sch"
USING "initial_scenes_barry.sch"
USING "script_drawing.sch"
USING "shared_hud_displays.sch"
USING "commands_recording.sch"
#IF IS_DEBUG_BUILD
USING "select_mission_stage.sch"
#ENDIF
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : Barry3A.sc
// AUTHOR : Tom Waters
// DESCRIPTION : Franklin collects a vehicle for Barry.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
// Launcher data
g_structRCScriptArgs sRCLauncherDataLocal
//*************************************************************************************************************************************************
// Z-SKIP
//*************************************************************************************************************************************************
#IF IS_DEBUG_BUILD
// Mission specific z-skip enum
ENUM MISSION_SKIP_STAGE
MSS_MISSION_TRIGGERED,
MSS_RESTART,
MSS_WARP_NEAR_END,
MSS_TRIGGER_DELIVERY,
MSS_TRIGGER_COMPLETION//,
// MSS_BODGE_TIMER
ENDENUM
// Z-skip menu/checkpoints stuff
MISSION_SKIP_STAGE eTargetStage
CONST_INT MAX_SKIP_MENU_LENGTH 5//6
MissionStageMenuTextStruct mSkipMenu[MAX_SKIP_MENU_LENGTH]
WIDGET_GROUP_ID widgetGroup
BOOL bDebugClockTo15s
#ENDIF
//*************************************************************************************************************************************************
// :ENUMS:
//*************************************************************************************************************************************************
// Mission stages
ENUM MISSION_STAGE
MS_STAGE_INIT,
MS_STAGE_CALL_BARRY,
MS_STAGE_ENTER_TRUCK,
MS_STAGE_RETURN_VEHICLE,
MS_STAGE_GET_VEHICLE_BACK,
MS_STAGE_LOSE_WANTED,
MS_STAGE_DELIVERY,
MS_STAGE_LEAVE_AREA,
MS_STAGE_TAKE_VEHICLE_BACK,
MS_STAGE_FAIL_FADE
ENDENUM
// Progression for individual cop car handlers
ENUM COP_TRAP_SINGLE_CAR
CTSC_WAITING_FOR_ENTITIES,
CTSC_WAITING_TO_TRIGGER,
CTSC_TRIGGER_DELAY,
CTSC_TRIGGERED,
CTSC_DELETED
ENDENUM
// Progression within a stage
ENUM STAGE_PROGRESS
SP_SETUP,
SP_RUNNING,
SP_CLEANUP
ENDENUM
// Controls the time-out fail check
ENUM TIME_OUT_STAGE
TOS_IDLE,
TOS_START,
TOS_FAILCHECK
ENDENUM
//*************************************************************************************************************************************************
// :STRUCTURES:
//*************************************************************************************************************************************************
// Vehicles to collect
STRUCT COLLECT_VEHICLE
VECTOR location
FLOAT heading
VEHICLE_INDEX vehicle
MODEL_NAMES modelName
BOOL bStuckCheckActive
ENDSTRUCT
// Objectives
STRUCT MISSION_OBJECTIVE
INT iDisplayMax
INT iDisplayCount
STRING sTextLabel
ENDSTRUCT
// Franklin flavour convos
STRUCT FLAVOUR_CONVO
STRING convRoot
INT convDelay
ENDSTRUCT
// Struct for Non-Axis-Aligned triggers
STRUCT NAA_TRIGGER
VECTOR vEnds[2]
FLOAT fWidth
ENDSTRUCT
// Structs for single-triggered cop cars
STRUCT COP_TRIGGER
// Vehicle and initial setup stuff
VEHICLE_INDEX vehicle
PED_INDEX driver
PED_INDEX passenger
VECTOR location
FLOAT heading
// Trigger box coordinates
NAA_TRIGGER triggers[2]
COP_TRAP_SINGLE_CAR ctsProgress
// Delay reaction to player
INT kickOffTimer
// Cleanup stuff
BOOL bDriverDeletedOrReleased
BOOL bPassengerDeletedOrReleased
BOOL bCarDeletedOrReleased
ENDSTRUCT
//*************************************************************************************************************************************************
// :CONSTANTS:
//*************************************************************************************************************************************************
// Checkpoints
CONST_INT CP_DELIVERY 1
CONST_INT CP_SHITSKIP_COMPLETE 2 // Shitskip only - do not set as checkpoint
// Cop stuff:
// Single triggered cop cars
CONST_INT NUM_SINGLE_COPCARS 2
CONST_FLOAT COP_DESPAWN_RANGE 275.0
CONST_INT BARRY3A_ACCURACY 10
CONST_INT COP_TRIGGER_DELAY_TIME 1750 // Set to 750 for B*1415951, increased to 1750 for B*1512323
// Objective label constants. Names should correspond to the text labels for the objectives.
CONST_INT MO_B3ADELV 0 // Take the truck to ~y~Barry's apartment.~s~
CONST_INT MO_B3AGETIN 1 // Get in the truck.
CONST_INT MO_B3AWAN1 2 // Lose the cops.
CONST_INT MO_B3ARTV 3 // Get back in the ~b~truck.~s~
CONST_INT MO_B3AEXIT 4 // Exit the truck.
CONST_INT MO_B3ALEAVE 5 // Leave the area.
CONST_INT NUM_MISSION_OBJECTIVES 6
// Detect player abandoning truck
CONST_INT WARNING_DISTANCE 50
CONST_INT ABANDON_DISTANCE 150
// Distance fail stage after initial delivery
CONST_FLOAT DELIVERY_FAIL_DISTANCE 125.0 // Initially set to same as TOF_GRACE_OFF value
// Flavour conversations
CONST_INT NUM_FLAVOUR_CONVOS 4
// Vehicle restriction
CONST_INT RESTRICTION_STASHVEH 0
//*************************************************************************************************************************************************
// :VARIABLES:
//*************************************************************************************************************************************************
// Mission progression
MISSION_STAGE mStage = MS_STAGE_INIT // track what mission stage we are at
STAGE_PROGRESS sProgress = SP_SETUP // used to track what bit of the current mission stage we're at
// General utility blip
BLIP_INDEX biMissionBlip
// The vehicle
COLLECT_VEHICLE stVehicle
BOOL bStuckCheckActive = FALSE
BOOL bVehicleOnRoofLastFrame = FALSE
INT iStuckTimer
OBJECT_INDEX oiStashBox
VECTOR vecStashOffset = << 0.0, -1.00, 0.64 >>
MODEL_NAMES mnStashBox = Prop_Weed_Tub_01b
BOOL bSetupVehGen = FALSE
// Vehicle delivery destination
VECTOR vecDestination = << -1138.9767, -1252.5486, 6.05 >> // 5.9589 >>//<< -1152.4301, -1238.8237, 5.9752 >>
SCENARIO_BLOCKING_INDEX sbCarPark[2] // Scenario blocker to stop parking scenario
// Objective display structure
MISSION_OBJECTIVE moObjectives[NUM_MISSION_OBJECTIVES]
// Cop trap trigger data
COP_TRIGGER ctTrapInfo[NUM_SINGLE_COPCARS]
BOOL bCopModelsLoaded // Control loading/unloading of cop models
MODEL_NAMES modelCopCar = POLICE4
MODEL_NAMES modelCopPed = A_M_Y_BUSINESS_01
BOOL bDidScannerLine = FALSE
INT iScannerTimer
// general utility counter
INT iCount
// Conversation struct for player
structPedsForConversation mConversationStruct
// Franklin's flavour conversations while wanted
FLAVOUR_CONVO fcFranklinComments[NUM_FLAVOUR_CONVOS]
BOOL bFranklinCompletedComment // Has Franklin completed current comment?
INT iFranklinCommentCount // Counts completed comments
INT iFranklinCommentTimer // Timer (ms)
BOOL bCopsChallenged // Controls whether Franklin says wanted dialogue
// Has Franklin been wanted?
BOOL bBeenWanted = FALSE
BOOL bRestartedAfterCP0 = FALSE
BOOL bWantedObjectiveNeeded // Used to mark objective as needed if there's a conversation going on
// Stuff for Franklin's wanted clear comment
BOOL bFranklinSaidClearComment
// Delivery event
BOOL bHadDeliveryCall // Have we triggered the delivery phone call yet
BOOL bCallDelaySet
INT iCallDelayTimer
// Player removing vehicle tracking stage bools
BOOL bObjectiveNeeded
BOOL bPlayerInTruck
BOOL bPlayerWanted
// Monitor time-out fail
TIME_OUT_STAGE timeOutStage
CONST_INT CLOCK_HOURS_ALLOWED 2 // Limit is 2 hours - B*1112928/1112927
CONST_INT CLOCK_MINS_ALLOWED 0
CONST_INT CLOCK_WARNING_MINUTES 30
INT iTimeLimit // Stores the end limit for mission time in ms
INT iWarningTime // Stores the point at which the warning comment should trigger in ms
BOOL bDoTheClock // Controls whether the clock gets displayed
BOOL bFranklinTimeWarnComment // Franklin comment if time is short
// Timeout beeper stuff
INT iTenSecondsLeft
INT iFiveSecondsLeft
INT iZeroSecondsLeft // This is the time when the timer shows zero, which is actually < 1s, not 0
INT iBeepTimer
BOOL bStartedBeepTimer
// Fail reason store
STRING sFailReason
// Conversation subtitle interruption
RC_CONV_RESTORE_STATE stateRestoreConversation
TEXT_LABEL_23 tSavedConversationRoot
TEXT_LABEL_23 tSavedConversationLabel
//*************************************************************************************************************************************************
// :OBJECTIVE FUNCS/PROCS:
//*************************************************************************************************************************************************
/// PURPOSE:
/// Returns a completed struct that holds an objective's info
/// PARAMS:
/// stTextLabel - The name of the text label that will be displayed as God text
/// iDisMax - Maximum number of times it can display. Set to -1 for no limit.
FUNC MISSION_OBJECTIVE CREATE_MISSION_OBJECTIVE(STRING stTextLabel, INT iDisMax = 1)
MISSION_OBJECTIVE tmpMissionObj
tmpMissionObj.sTextLabel = stTextLabel
tmpMissionObj.iDisplayMax = iDisMax
tmpMissionObj.iDisplayCount = 0
RETURN tmpMissionObj
ENDFUNC
/// PURPOSE:
/// Test whether an objective will display
/// Saves having a seperate bool for blip updates, or lets you see whether you need to clear an objective
/// PARAMS:
/// iObj - which objective to check (use the constants)
/// RETURNS:
/// TRUE if the objective will display
FUNC BOOL MISSION_OBJECTIVE_WILL_DISPLAY(INT iObj)
IF moObjectives[iObj].iDisplayCount < moObjectives[iObj].iDisplayMax
OR moObjectives[iObj].iDisplayMax = -1
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDFUNC
/// PURPOSE:
/// Display an objective, unless it has already been displayed as many times as allowed
/// PARAMS:
/// iObj - which objective to display (use the constants)
PROC DISPLAY_MISSION_OBJECTIVE(INT iObj)
IF MISSION_OBJECTIVE_WILL_DISPLAY(iObj)
PRINT_NOW(moObjectives[iObj].sTextLabel, DEFAULT_GOD_TEXT_TIME, 1)
moObjectives[iObj].iDisplayCount++
ENDIF
ENDPROC
/// PURPOSE:
/// Remove a specific objective that is being displayed
/// PARAMS:
/// iObj - which objective we are removing (use the constants)
PROC CLEAR_MISSION_OBJECTIVE(INT iObj)
CLEAR_THIS_PRINT(moObjectives[iObj].sTextLabel)
ENDPROC
/// PURPOSE:
/// Clear any mission objective that might be shown + stop dialogue + put away phone
PROC CLEAR_ALL_MISSION_OBJECTIVES()
CLEAR_PRINTS()
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
HANG_UP_AND_PUT_AWAY_PHONE()
ENDIF
ENDPROC
/// PURPOSE:
/// Are any mission objectives currently on screen?
/// RETURNS:
/// True if there is currently a mission objective on screen
FUNC BOOL MISSION_OBJECTIVES_CURRENTLY_DISPLAYED()
BOOL bResult = FALSE
FOR iCount = 0 TO NUM_MISSION_OBJECTIVES-1
IF IS_THIS_PRINT_BEING_DISPLAYED(moObjectives[iCount].sTextLabel)
bResult = TRUE
ENDIF
ENDFOR
RETURN bResult
ENDFUNC
/// PURPOSE:
/// Allows skip procs to reset objective counter
/// PARAMS:
/// iObj - which objective we're resetting
/// iNewCount - new iDisplayCount value
PROC MISSION_OBJECTIVE_RESET(INT iObj, INT iNewCount = 0)
moObjectives[iObj].iDisplayCount = iNewCount
ENDPROC
/// PURPOSE:
/// Allows skip procs to set an objective to act as if it has already displayed
/// PARAMS:
/// iObj - which objective we're altering
PROC MISSION_OBJECTIVE_EXPIRE(INT iObj)
IF moObjectives[iObj].iDisplayMax = -1
CPRINTLN(DEBUG_MISSION, "Trying to expire an objective that has unlimited repeats! ", iObj)
ELSE
moObjectives[iObj].iDisplayCount = moObjectives[iObj].iDisplayMax
ENDIF
ENDPROC
/// PURPOSE:
/// Set up all the mission objectives
PROC STORE_MISSION_OBJECTIVE_DATA()
moObjectives[MO_B3ADELV] = CREATE_MISSION_OBJECTIVE("B3ADELV", 1) // Take the truck to ~y~Barry's apartment.~s~
moObjectives[MO_B3AGETIN] = CREATE_MISSION_OBJECTIVE("B3AGETIN", 1) // Get in the truck.
moObjectives[MO_B3AWAN1] = CREATE_MISSION_OBJECTIVE("B3AWAN1", -1) // Lose the cops.
moObjectives[MO_B3ARTV] = CREATE_MISSION_OBJECTIVE("B3ARTV", 1) // Get back in the ~b~truck.~s~
moObjectives[MO_B3AEXIT] = CREATE_MISSION_OBJECTIVE("B3AEXIT", 1) // Exit the truck.
moObjectives[MO_B3ALEAVE] = CREATE_MISSION_OBJECTIVE("B3ALEAVE", 1) // Leave the area.
ENDPROC
/// PURPOSE:
/// Stuck check on mission vehicle
/// RETURN:
/// TRUE if the vehicle is stuck!
FUNC BOOL VEHICLE_IS_STUCK()
// Keep track of vehicle on roof
IF IS_VEHICLE_STUCK_ON_ROOF(stVehicle.vehicle)
IF bVehicleOnRoofLastFrame
IF GET_GAME_TIMER() - iStuckTimer > ROOF_TIME
RETURN TRUE
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "Vehicle is now stuck on roof!")
bVehicleOnRoofLastFrame = TRUE
iStuckTimer = GET_GAME_TIMER()
ENDIF
ELSE
IF bVehicleOnRoofLastFrame
CPRINTLN(DEBUG_MISSION, "Vehicle is no longer stuck on roof.")
ENDIF
bVehicleOnRoofLastFrame = FALSE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Beeps on timer for last 10 seconds
/// B*1843890
PROC TRIGGER_WARNING_BEEPS()
INT iTimeNow = GET_GAME_TIMER()
// Less than 1s left
IF iTimeNow >= iZeroSecondsLeft
IF iTimeNow-iBeepTimer > 500
CDEBUG1LN(DEBUG_MISSION, "BOOP :(")
PLAY_SOUND_FRONTEND(-1, "TIMER_STOP", "HUD_MINI_GAME_SOUNDSET")
iBeepTimer = GET_GAME_TIMER() + 1000
ENDIF
// Down to less than 5s, beep every 0.5s
ELIF iTimeNow >= iFiveSecondsLeft
IF iTimeNow-iBeepTimer > 500
CDEBUG1LN(DEBUG_MISSION, "BEEP!")
PLAY_SOUND_FRONTEND(-1, "10_SEC_WARNING", "HUD_MINI_GAME_SOUNDSET")
iBeepTimer = GET_GAME_TIMER()
ENDIF
// Down to less than 10s but still more than 5s, beep every 1.0s
ELIF iTimeNow >= iTenSecondsLeft
IF NOT bStartedBeepTimer
CDEBUG1LN(DEBUG_MISSION, "BEEP!")
PLAY_SOUND_FRONTEND(-1, "10_SEC_WARNING", "HUD_MINI_GAME_SOUNDSET")
iBeepTimer = GET_GAME_TIMER()
bStartedBeepTimer = TRUE
ELIF iTimeNow-iBeepTimer > 1000
CDEBUG1LN(DEBUG_MISSION, "BEEP!")
PLAY_SOUND_FRONTEND(-1, "10_SEC_WARNING", "HUD_MINI_GAME_SOUNDSET")
iBeepTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Check whether the player's taken too long in game-world clock terms
/// RETURNS:
/// TRUE if we should get a time up fail
FUNC BOOL TIME_OUT_FAIL_MONITOR()
SWITCH timeOutStage
CASE TOS_IDLE
RETURN FALSE
BREAK
CASE TOS_START
// Set time limit
iTimeLimit = GET_MILLISECONDS_PER_GAME_MINUTE()*((60*CLOCK_HOURS_ALLOWED) + CLOCK_MINS_ALLOWED)
CPRINTLN(DEBUG_MISSION, "TIME LIMIT::: ", iTimeLimit, "ms. MS per game minute is ", GET_MILLISECONDS_PER_GAME_MINUTE(), "ms")
iTimeLimit += GET_GAME_TIMER()
iWarningTime = iTimeLimit - (GET_MILLISECONDS_PER_GAME_MINUTE()*CLOCK_WARNING_MINUTES)
// Timeout warning beeps stuff
iTenSecondsLeft = iTimeLimit - 11000
iFiveSecondsLeft = iTimeLimit - 6000
iZeroSecondsLeft = iTimeLimit - 1000
bStartedBeepTimer = FALSE
timeOutStage = TOS_FAILCHECK
RETURN FALSE
BREAK
CASE TOS_FAILCHECK
// We are now checking for a timeout fail
// But don't fail if player is nearly there - B*833516
IF GET_GAME_TIMER() >= iTimeLimit
RETURN TRUE
ELSE
// See if Franklin should make hurry up comment.
IF NOT bFranklinTimeWarnComment
AND GET_GAME_TIMER() >= iWarningTime
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF CREATE_CONVERSATION(mConversationStruct, "BAR3AAU", "BAR3A_HURRY", CONV_PRIORITY_MEDIUM, DISPLAY_SUBTITLES)
bFranklinTimeWarnCOmment = TRUE
ENDIF
ENDIF
TRIGGER_WARNING_BEEPS()
// Still OK
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks for the player being killed or the truck being destroyed
/// RETURNS:
/// True if the player has failed the mission
FUNC BOOL MISSION_FAILED_CHECKS()
// Is player still alive
IF NOT IS_ENTITY_ALIVE(PLAYER_PED_ID())
RETURN TRUE // player dead- mission failed
ENDIF
// Check for timeout fail
IF TIME_OUT_FAIL_MONITOR()
sFailReason = "B3ATIMEOUT" // You didn't deliver the stash car in time.
sProgress = SP_SETUP
mStage = MS_STAGE_FAIL_FADE
RETURN TRUE
ENDIF
// Has vehicle been trashed
IF NOT IS_ENTITY_ALIVE(stVehicle.vehicle)
sFailReason = "B3AVHDEST" // The vehicle was destroyed
sProgress = SP_SETUP
mStage = MS_STAGE_FAIL_FADE
RETURN TRUE // truck destroyed- mission failed
ELIF VEHICLE_IS_STUCK()
sFailReason = "B3AVHSTUCK" // The vehicle was destroyed
sProgress = SP_SETUP
mStage = MS_STAGE_FAIL_FADE
RETURN TRUE // truck destroyed- mission failed
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Turns off engine and lights
/// PARAMS:
/// viVehicle - Vehicle to turn off
PROC VEHICLE_SHUTDOWN(VEHICLE_INDEX viVehicle)
IF IS_ENTITY_ALIVE(viVehicle)
SET_VEHICLE_ENGINE_ON(viVehicle, FALSE, FALSE)
SET_VEHICLE_LIGHTS(viVehicle, FORCE_VEHICLE_LIGHTS_OFF)
ENDIF
ENDPROC
/// PURPOSE:
/// Checks whether the player is in a tow truck that is attached to the stash car
/// RETURNS:
/// TRUE if the player is mucking about in this way
FUNC BOOL PLAYER_IS_TOWING()
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
VEHICLE_INDEX vehTmp
vehTmp = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID(), TRUE)
IF IS_ENTITY_ALIVE(vehTmp)
IF GET_ENTITY_MODEL(vehTmp) = TOWTRUCK
OR GET_ENTITY_MODEL(vehTmp) = TOWTRUCK2
IF IS_VEHICLE_ATTACHED_TO_TOW_TRUCK(vehTmp, stVehicle.vehicle)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Save all the stuff we'll need for triggering the single-trigger cops
PROC STORE_COP_TRIGGER_DATA()
// UC cops in lumber yard
ctTrapInfo[0].location = << 1195.30, -1312.74, 34.75 >>
ctTrapInfo[0].heading = 282.4
ctTrapInfo[0].triggers[0].vEnds[0] = <<1216.144287,-1287.003906,33.976418>>
ctTrapInfo[0].triggers[0].vEnds[1] = <<1202.455566,-1306.053833,39.474110>>
ctTrapInfo[0].triggers[0].fWidth = 16.50
ctTrapInfo[0].triggers[1].vEnds[0] = <<1204.858032,-1296.130615,33.976418>>
ctTrapInfo[0].triggers[1].vEnds[1] = <<1198.831909,-1365.925903,39.477051>>
ctTrapInfo[0].triggers[1].fWidth = 37.50
ctTrapInfo[0].ctsProgress = CTSC_WAITING_FOR_ENTITIES
// UC cops past lumber yard
ctTrapInfo[1].location = << 1162.71, -1357.86, 33.73 >>
ctTrapInfo[1].heading = 266.7
ctTrapInfo[1].triggers[0].vEnds[0] = <<1164.457153,-1363.839478,33.510624>>
ctTrapInfo[1].triggers[0].vEnds[1] = <<1180.637207,-1359.837036,39.113964>>
ctTrapInfo[1].triggers[0].fWidth = 15.5
ctTrapInfo[1].triggers[1].vEnds[0] = <<0,0,0>>
ctTrapInfo[1].triggers[1].vEnds[1] = <<0,0,0>>
ctTrapInfo[1].triggers[1].fWidth = 0
ctTrapInfo[1].ctsProgress = CTSC_WAITING_FOR_ENTITIES
ENDPROC
/// PURPOSE:
/// Checks for tripping of cop traps
/// RETURNS:
/// TRUE if the stash vehicle is in a trigger
FUNC BOOL COP_SINGLE_TRIGGER_CHECK(INT iCop)
// This used to check player was in trigger after validating player was in truck - changed to checking truck because of issues like B*1118576 or player towing vehicle
IF IS_ENTITY_IN_ANGLED_AREA(stVehicle.vehicle, ctTrapInfo[iCop].triggers[0].vEnds[0], ctTrapInfo[iCop].triggers[0].vEnds[1], ctTrapInfo[iCop].triggers[0].fWidth)
RETURN TRUE
ELIF ctTrapInfo[iCop].triggers[1].fWidth <> 0
AND IS_ENTITY_IN_ANGLED_AREA(stVehicle.vehicle, ctTrapInfo[iCop].triggers[1].vEnds[0], ctTrapInfo[iCop].triggers[1].vEnds[1], ctTrapInfo[iCop].triggers[1].fWidth)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks whether the player is mucking about with stakeout cops
/// PARAMS:
/// pedCop - cop ped to check
/// RETURNS:
/// TRUE if player is mucking about
FUNC BOOL PLAYER_IS_MESSING_ABOUT_WITH_COP(PED_INDEX pedCop)
IF IS_ENTITY_ALIVE(pedCop)
VECTOR vTmp = GET_ENTITY_COORDS(pedCop)
IF IS_PED_BEING_JACKED(pedCop)
AND IS_ENTITY_IN_RANGE_ENTITY(pedCop, PLAYER_PED_ID(), 2.0)
CPRINTLN(DEBUG_MISSION, "Player jacking a stakeout cop")
RETURN TRUE
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(pedCop, PLAYER_PED_ID())
CPRINTLN(DEBUG_MISSION, "Player damaged a stakeout cop")
RETURN TRUE
ELIF IS_PROJECTILE_IN_AREA(vTmp-<<3,3,3>>, vTmp+<<3,3,3>>, TRUE)
CPRINTLN(DEBUG_MISSION, "Player shot near a stakeout cop")
RETURN TRUE
ELIF IS_PLAYER_VISIBLY_TARGETTING_PED(pedCop)
CPRINTLN(DEBUG_MISSION, "Player visibly targeting a stakeout cop")
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks whether the player is mucking about with the stakeout cops
/// PARAMS:
/// copCar - cop car to check
/// RETURNS:
/// TRUE if shenanigans are afoot
FUNC BOOL PLAYER_IS_MESSING_ABOUT_WITH_COPCAR(VEHICLE_INDEX copCar)
IF DOES_ENTITY_EXIST(copCar)
VECTOR vTmp = GET_ENTITY_COORDS(copCar, FALSE)
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(copCar, PLAYER_PED_ID())
CPRINTLN(DEBUG_MISSION, "Player damaged a stakeout car")
IF NOT IS_ENTITY_DEAD(copCar)
CLEAR_ENTITY_LAST_DAMAGE_ENTITY(copCar)
ENDIF
RETURN TRUE
ELIF IS_PROJECTILE_IN_AREA(vTmp-<<5,5,5>>, vTmp+<<5,5,5>>, TRUE)
CPRINTLN(DEBUG_MISSION, "Player shot near a stakeout car")
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Sets off the cops in this car
/// PARAMS:
/// iCopC - array index of cop stakeout struct
/// bEngineOn - should we instant-on the car engine?
PROC COPS_KICK_OFF(INT iCopC, BOOL bEngineOn = FALSE)
CPRINTLN(DEBUG_MISSION, "COP_TRAP_SINGLETRIGGER wakeywakey on cop car ", iCopC)
// Franklin can start wanted complaint dialogue
IF NOT bCopsChallenged
bCopsChallenged = TRUE
iFranklinCommentTimer = GET_GAME_TIMER()
ENDIF
IF IS_ENTITY_ALIVE(ctTrapInfo[iCopC].driver)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(ctTrapInfo[iCopC].driver, FALSE)
SET_PED_HIGHLY_PERCEPTIVE(ctTrapInfo[iCopC].driver, TRUE)
SAFE_RELEASE_PED(ctTrapInfo[iCopC].driver) // Release cops now - if still owned by script they don't use correct arrest/attack behaviours
ENDIF
IF IS_ENTITY_ALIVE(ctTrapInfo[iCopC].passenger)
SET_PED_AS_COP(ctTrapInfo[iCopC].passenger, TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(ctTrapInfo[iCopC].passenger, FALSE)
SET_PED_HIGHLY_PERCEPTIVE(ctTrapInfo[iCopC].passenger, TRUE)
SAFE_RELEASE_PED(ctTrapInfo[iCopC].passenger) // Release cops now - if still owned by script they don't use correct arrest/attack behaviours
ENDIF
IF bEngineOn
AND IS_ENTITY_ALIVE(ctTrapInfo[iCopC].vehicle)
SET_VEHICLE_ENGINE_ON(ctTrapInfo[iCopC].vehicle, TRUE, TRUE)
SAFE_RELEASE_VEHICLE(ctTrapInfo[iCopC].vehicle)
ENDIF
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 2
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 2)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
ENDIF
REPORT_POLICE_SPOTTED_PLAYER(PLAYER_ID())
ctTrapInfo[iCopC].ctsProgress = CTSC_TRIGGERED
ENDPROC
/// PURPOSE:
/// Handle triggering of seperate cop cars
/// PARAMS:
/// iCop - Array index for the cop struct to use
PROC COP_TRAP_SINGLETRIGGER(INT iCop)
SWITCH ctTrapInfo[iCop].ctsProgress
CASE CTSC_WAITING_FOR_ENTITIES
// Create the entities
IF NOT DOES_ENTITY_EXIST(ctTrapInfo[iCop].driver)
IF IS_ENTITY_ALIVE(ctTrapInfo[iCop].vehicle)
IF HAS_MODEL_LOADED(modelCopPed)
ctTrapInfo[iCop].driver = CREATE_PED_INSIDE_VEHICLE(ctTrapInfo[iCop].vehicle, PEDTYPE_COP, modelCopPed)
ctTrapInfo[iCop].passenger = CREATE_PED_INSIDE_VEHICLE(ctTrapInfo[iCop].vehicle, PEDTYPE_COP, modelCopPed, VS_FRONT_RIGHT)
ENDIF
ELIF HAS_MODEL_LOADED(modelCopCar)
ctTrapInfo[iCop].vehicle = CREATE_VEHICLE(modelCopCar, ctTrapInfo[iCop].location, ctTrapInfo[iCop].heading)
#IF IS_DEBUG_BUILD SET_VEHICLE_NAME_DEBUG(ctTrapInfo[iCop].vehicle, GET_STRING_FROM_INT(iCop)) #ENDIF
ENDIF
ELSE
IF NOT IS_ENTITY_DEAD(ctTrapInfo[iCop].driver)
// If driver exists, car is ready
SET_PED_AS_COP(ctTrapInfo[iCop].driver, TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(ctTrapInfo[iCop].driver, TRUE)
GIVE_DELAYED_WEAPON_TO_PED(ctTrapInfo[iCop].driver, WEAPONTYPE_PISTOL, 100, TRUE)
SET_PED_ACCURACY(ctTrapInfo[iCop].driver, BARRY3A_ACCURACY)
IF IS_ENTITY_ALIVE(ctTrapInfo[iCop].passenger)
SET_PED_AS_COP(ctTrapInfo[iCop].passenger, TRUE)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(ctTrapInfo[iCop].passenger, TRUE)
GIVE_DELAYED_WEAPON_TO_PED(ctTrapInfo[iCop].passenger, WEAPONTYPE_PISTOL, 100, TRUE)
SET_PED_ACCURACY(ctTrapInfo[iCop].passenger, BARRY3A_ACCURACY)
ENDIF
CPRINTLN(DEBUG_MISSION, "COP_TRAP_SINGLETRIGGER finished creating car ", iCop)
ctTrapInfo[iCop].ctsProgress = CTSC_WAITING_TO_TRIGGER
ENDIF
ENDIF
BREAK
CASE CTSC_WAITING_TO_TRIGGER
// Wait for player to set things off
IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), ctTrapInfo[iCop].location, COP_DESPAWN_RANGE)
IF COP_SINGLE_TRIGGER_CHECK(iCop)
CPRINTLN(DEBUG_MISSION, "Cop stakeout triggered on cop car ", iCop)
ctTrapInfo[iCop].kickOffTimer = GET_GAME_TIMER() + COP_TRIGGER_DELAY_TIME // Reduced this from 3s to make events clearer to player
ctTrapInfo[iCop].ctsProgress = CTSC_TRIGGER_DELAY
ELIF PLAYER_IS_MESSING_ABOUT_WITH_COPCAR(ctTrapInfo[iCop].vehicle)
OR PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].driver)
OR PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].passenger)
CPRINTLN(DEBUG_MISSION, "Cop car ", iCop, " woken by player messing about")
COPS_KICK_OFF(iCop)
ELIF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
CPRINTLN(DEBUG_MISSION, "Cop car ", iCop, " woken on wanted level")
COPS_KICK_OFF(iCop)
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "COP_TRAP_SINGLETRIGGER player is quite far from this cop setup: Cleaning up cop car ", iCop)
IF NOT ctTrapInfo[iCop].bDriverDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].driver)
SAFE_DELETE_PED(ctTrapInfo[iCop].driver)
ctTrapInfo[iCop].bDriverDeletedOrReleased = TRUE
ENDIF
IF NOT ctTrapInfo[iCop].bPassengerDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].passenger)
SAFE_DELETE_PED(ctTrapInfo[iCop].passenger)
ctTrapInfo[iCop].bPassengerDeletedOrReleased = TRUE
ENDIF
IF NOT ctTrapInfo[iCop].bCarDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].vehicle)
SAFE_DELETE_VEHICLE(ctTrapInfo[iCop].vehicle)
ctTrapInfo[iCop].bCarDeletedOrReleased = TRUE
ENDIF
IF ctTrapInfo[iCop].bDriverDeletedOrReleased AND ctTrapInfo[iCop].bPassengerDeletedOrReleased AND ctTrapInfo[iCop].bCarDeletedOrReleased
ctTrapInfo[iCop].ctsProgress = CTSC_DELETED
ENDIF
ENDIF
// Check for messing about jacking cops on foot
IF IS_PED_ON_FOOT(PLAYER_PED_ID())
IF PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].driver)
OR PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].passenger)
OR PLAYER_IS_MESSING_ABOUT_WITH_COPCAR(ctTrapInfo[iCop].vehicle)
// Wake up these cops
COPS_KICK_OFF(iCop)
ENDIF
ENDIF
BREAK
CASE CTSC_TRIGGER_DELAY
IF GET_GAME_TIMER() > ctTrapInfo[iCop].kickOffTimer
// Wake up these cops - standard trigger
COPS_KICK_OFF(iCop, TRUE)
ELSE
// Check for messing about jacking cops on foot
IF PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].driver)
OR PLAYER_IS_MESSING_ABOUT_WITH_COP(ctTrapInfo[iCop].passenger)
OR PLAYER_IS_MESSING_ABOUT_WITH_COPCAR(ctTrapInfo[iCop].vehicle)
// Wake up these cops
COPS_KICK_OFF(iCop)
ENDIF
ENDIF
BREAK
CASE CTSC_TRIGGERED
// Monitor the cops to clean them up as soon as it is safe to do so, so we don't get script entities falling through world asserts
IF NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), ctTrapInfo[iCop].location, COP_DESPAWN_RANGE)
IF NOT ctTrapInfo[iCop].bDriverDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].driver)
SAFE_RELEASE_PED(ctTrapInfo[iCop].driver)
ctTrapInfo[iCop].bDriverDeletedOrReleased = TRUE
ENDIF
IF NOT ctTrapInfo[iCop].bPassengerDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].passenger)
SAFE_DELETE_PED(ctTrapInfo[iCop].passenger)
ctTrapInfo[iCop].bPassengerDeletedOrReleased = TRUE
ENDIF
IF NOT ctTrapInfo[iCop].bCarDeletedOrReleased
AND DOES_ENTITY_EXIST(ctTrapInfo[iCop].vehicle)
SAFE_DELETE_VEHICLE(ctTrapInfo[iCop].vehicle)
ctTrapInfo[iCop].bCarDeletedOrReleased = TRUE
ENDIF
IF ctTrapInfo[iCop].bDriverDeletedOrReleased AND ctTrapInfo[iCop].bPassengerDeletedOrReleased AND ctTrapInfo[iCop].bCarDeletedOrReleased
ctTrapInfo[iCop].ctsProgress = CTSC_DELETED
ENDIF
ENDIF
BREAK
CASE CTSC_DELETED
// Done - do nothing
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Handles the scripted cops
PROC HANDLE_COPS()
// Do the single trigger cop cars in lumber yard area
FOR iCount = 0 TO NUM_SINGLE_COPCARS-1
COP_TRAP_SINGLETRIGGER(iCount)
ENDFOR
IF bCopModelsLoaded
AND ctTrapInfo[0].ctsProgress = CTSC_WAITING_TO_TRIGGER
AND ctTrapInfo[1].ctsProgress = CTSC_WAITING_TO_TRIGGER
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopPed)
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopCar)
bCopModelsLoaded = FALSE
ENDIF
ENDPROC
/// PURPOSE:
/// Display the clock when required
PROC DO_CLOCK()
IF bDoTheClock
IF NOT IS_CUTSCENE_PLAYING()
AND NOT IS_PHONE_ONSCREEN()
AND NOT IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()
INT iDisplayTime
// Current time remaining converted to milliseconds so generic timer shows it properly
iDisplayTime = iTimeLimit - GET_GAME_TIMER()
IF iDisplayTime < 0
iDisplayTime = 0
ENDIF
HIDE_STREET_AND_CAR_NAMES_THIS_FRAME()
IF GET_GAME_TIMER() >= iWarningTime
DRAW_GENERIC_TIMER(iDisplayTime, "B3ATIME", 0, TIMER_STYLE_DONTUSEMILLISECONDS, -1, PODIUMPOS_NONE, HUDORDER_DONTCARE, FALSE, HUD_COLOUR_RED)
ELSE
DRAW_GENERIC_TIMER(iDisplayTime, "B3ATIME", 0, TIMER_STYLE_DONTUSEMILLISECONDS, -1, PODIUMPOS_NONE, HUDORDER_DONTCARE, FALSE)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Vehicle-specific cleanup of collect area scenarios
/// PARAMS:
/// bDeleteEntities makes entities get deleted instead of marking as not needed
PROC COLLECT_AREA_CLEANUP(BOOL bDeleteEntities = FALSE)
IF bDeleteEntities
CPRINTLN(DEBUG_MISSION, "Full delete of script entities...")
SAFE_DELETE_OBJECT(oiStashBox)
SAFE_DELETE_VEHICLE(stVehicle.vehicle)
FOR iCount = 0 TO NUM_SINGLE_COPCARS-1
SAFE_DELETE_PED(ctTrapInfo[iCount].driver)
SAFE_DELETE_PED(ctTrapInfo[iCount].passenger)
ENDFOR
FOR iCount = 0 TO NUM_SINGLE_COPCARS-1
SAFE_DELETE_VEHICLE(ctTrapInfo[iCount].vehicle)
ENDFOR
ELSE
CPRINTLN(DEBUG_MISSION, "Releasing script entities...")
SAFE_RELEASE_OBJECT(oiStashBox)
SAFE_RELEASE_VEHICLE(stVehicle.vehicle)
// Clean up cops
FOR iCount = 0 TO NUM_SINGLE_COPCARS-1
SAFE_RELEASE_PED(ctTrapInfo[iCount].driver)
SAFE_RELEASE_PED(ctTrapInfo[iCount].passenger)
SAFE_RELEASE_VEHICLE(ctTrapInfo[iCount].vehicle)
ENDFOR
ENDIF
IF bCopModelsLoaded
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopCar)
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopPed)
ENDIF
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<< -1142.8287, -1254.5848, 0 >>, << -1136.6863, -1246.4720, 8 >>, TRUE)
ENDPROC
// Set up info for flavour monologues
PROC STORE_FLAVOUR_CHAT()
fcFranklinComments[0].convRoot = "BAR3A_C1" // Shit, Motherfuckers had eyes on the place
fcFranklinComments[0].convDelay = 1000
fcFranklinComments[1].convRoot = "BAR3A_W2" // C'mon, c'mon! How fucking slow is this thing?
fcFranklinComments[1].convDelay = 19000
fcFranklinComments[2].convRoot = "BAR3A_W1" // Man, there's gotta be a better way to get weed legalized than this bullshit.
fcFranklinComments[2].convDelay = 20000
fcFranklinComments[3].convRoot = "BAR3A_W4" // Man, fuck, I'm never gonna lose these assholes.
fcFranklinComments[3].convDelay = 22000
// fcFranklinComments[0].convRoot = "BAR3A_C1" // Shit, Motherfuckers had eyes on the place
// fcFranklinComments[0].convDelay = 1000
// fcFranklinComments[1].convRoot = "BAR3A_W1" // Man, there's gotta be a better way to get weed legalized than this bullshit.
// fcFranklinComments[1].convDelay = 9500
// fcFranklinComments[2].convRoot = "BAR3A_W2" // C'mon, c'mon! How fucking slow is this thing?
// fcFranklinComments[2].convDelay = 8000
// fcFranklinComments[3].convRoot = "BAR3A_W2A" // Better head for Vespucci so I'm set to ditch this shit when I'm clear.
// fcFranklinComments[3].convDelay = 8500
// fcFranklinComments[4].convRoot = "BAR3A_W3" // "Fight the good fight!" "San Andreas needs you!" Asshole.
// fcFranklinComments[4].convDelay = 8500
// fcFranklinComments[5].convRoot = "BAR3A_W4" // Man, fuck, I'm never gonna lose these assholes.
// fcFranklinComments[5].convDelay = 10000
ENDPROC
/// PURPOSE:
/// Check for cop proximity. Refines comment triggering.
/// RETURNS:
/// Returns TRUE if player is near a scripted cop
FUNC BOOL IS_PLAYER_NEAR_COP()
IF IS_COP_PED_IN_AREA_3D(GET_ENTITY_COORDS(PLAYER_PED_ID()) - << 70.0, 70.0, 70.0 >>, GET_ENTITY_COORDS(PLAYER_PED_ID()) + << 70.0, 70.0, 70.0 >>)
RETURN TRUE
ENDIF
// If we get here, no scripted cops were found to exist in range
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Update/trigger Franklin wanted complaint dialogue
PROC FRANKLIN_WANTED_DIALOGUE()
// Handle Franklin's comments - don't start checking this stuff until after initial cop loudhailer
IF bCopsChallenged
AND iFranklinCommentCount < NUM_FLAVOUR_CONVOS
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle) // Only start new comments if in truck
// Check whether the conversation has only just finished
IF NOT bFranklinCompletedComment
bFranklinCompletedComment = TRUE
iFranklinCommentTimer = GET_GAME_TIMER()
CPRINTLN(DEBUG_MISSION, "FRANKLIN_WANTED_DIALOGUE: Franklin finished a wanted comment, resetting timer")
ENDIF
// We might need to be playing a conversation, check how long since the timer was reset
IF GET_GAME_TIMER() - iFranklinCommentTimer > fcFranklinComments[iFranklinCommentCount].convDelay
AND (IS_PLAYER_NEAR_COP() OR iFranklinCommentCount = 0) // Franklin always says first comment right away - B*1358891
IF (iFranklinCommentCount <> 2 OR GET_ENTITY_SPEED(stVehicle.vehicle) > 10.0) // Don't play comment 2 when vehicle is stationary - B*1397348
CPRINTLN(DEBUG_MISSION, "FRANKLIN_WANTED_DIALOGUE: Started a new wanted comment")
// Attempt to create new conversation
IF MISSION_OBJECTIVES_CURRENTLY_DISPLAYED()
OR GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
IF CREATE_CONVERSATION(mConversationStruct, "BAR3AAU", fcFranklinComments[iFranklinCommentCount].convRoot, CONV_PRIORITY_MEDIUM, DO_NOT_DISPLAY_SUBTITLES)
// Successfully created conversation, wait for it to finish and set up to fire the next
bFranklinCompletedComment = FALSE
iFranklinCommentCount++
ENDIF
ELSE
IF CREATE_CONVERSATION(mConversationStruct, "BAR3AAU", fcFranklinComments[iFranklinCommentCount].convRoot, CONV_PRIORITY_MEDIUM, DISPLAY_SUBTITLES)
// Successfully created conversation, wait for it to finish and set up to fire the next
bFranklinCompletedComment = FALSE
iFranklinCommentCount++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
//*************************************************************************************************************************************************
//
// Skip procs
//
//*************************************************************************************************************************************************
// Respawn truck and set up stuck check
PROC SKIP_RESPAWN_TRUCK(VECTOR vecRSLoc, FLOAT fRSHead, BOOL bInsertPlayer = TRUE)
REQUEST_MODEL(stVehicle.modelName)
REQUEST_MODEL(mnStashBox)
WHILE NOT HAS_MODEL_LOADED(stVehicle.modelName)
OR NOT HAS_MODEL_LOADED(mnStashBox)
WAIT(0)
ENDWHILE
IF IS_ENTITY_ALIVE(stVehicle.vehicle)
IF bStuckCheckActive
REMOVE_VEHICLE_UPSIDEDOWN_CHECK(stVehicle.vehicle)
bStuckCheckActive = FALSE
ENDIF
ENDIF
IF bInsertPlayer
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_ENTITY_COORDS(PLAYER_PED_ID(), vecRSLoc)
ENDIF
ENDIF
SAFE_DELETE_OBJECT(oiStashBox)
SAFE_DELETE_VEHICLE(stVehicle.vehicle)
stvehicle.vehicle = CREATE_VEHICLE(stVehicle.modelName, vecRSLoc, fRSHead)
SET_VEHICLE_COLOUR_COMBINATION(stVehicle.vehicle, 1)
IF bInsertPlayer
SAFE_SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
ENDIF
SET_VEHICLE_CAN_LEAK_OIL(stVehicle.vehicle, FALSE)
SET_VEHICLE_CAN_LEAK_PETROL(stVehicle.vehicle, FALSE)
SET_VEHICLE_STRONG(stVehicle.vehicle, TRUE)
SET_VEHICLE_HAS_STRONG_AXLES(stVehicle.vehicle, TRUE)
ADD_VEHICLE_UPSIDEDOWN_CHECK(stVehicle.vehicle)
SET_VEHICLE_EXTRA(stVehicle.vehicle, 1, TRUE)
SET_VEHICLE_EXTRA(stVehicle.vehicle, 2, TRUE)
SET_VEHICLE_EXTRA(stVehicle.vehicle, 3, TRUE)
oiStashBox = CREATE_OBJECT(mnStashBox, vecRSLoc)
ATTACH_ENTITY_TO_ENTITY(oiStashBox, stVehicle.vehicle, 0, vecStashOffset, <<0,0,0>>, FALSE, FALSE, TRUE)
SET_ENTITY_COLLISION(oiStashBox, TRUE)
bStuckCheckActive = TRUE
SET_VEHICLE_AS_RESTRICTED(stVehicle.vehicle, RESTRICTION_STASHVEH)
SET_MODEL_AS_NO_LONGER_NEEDED(stVehicle.modelName)
SET_MODEL_AS_NO_LONGER_NEEDED(mnStashBox)
ENDPROC
/// PURPOSE:
/// Get rid of wanted level
PROC SKIP_CLEAR_WANTED()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) // Can occur out of main loop, must check this
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Remove cops
/// PARAMS:
/// bReset - If true, cops will be reset ready to spawn again, if false they will deleted as if spent
PROC SKIP_DELETE_COPS(BOOL bReset = TRUE)
// Delete the single trigger cops
FOR iCount = 0 TO NUM_SINGLE_COPCARS-1
// Clear peds
SAFE_DELETE_PED(ctTrapInfo[iCount].driver)
SAFE_DELETE_PED(ctTrapInfo[iCount].passenger)
SAFE_DELETE_VEHICLE(ctTrapInfo[iCount].vehicle)
IF bReset
ctTrapInfo[iCount].bDriverDeletedOrReleased = FALSE
ctTrapInfo[iCount].bPassengerDeletedOrReleased = FALSE
ctTrapInfo[iCount].bCarDeletedOrReleased = FALSE
ctTrapInfo[iCount].ctsProgress = CTSC_WAITING_FOR_ENTITIES
IF NOT bCopModelsLoaded
REQUEST_MODEL(modelCopPed)
REQUEST_MODEL(modelCopCar)
ENDIF
bCopModelsLoaded = TRUE
ELSE
ctTrapInfo[iCount].bDriverDeletedOrReleased = TRUE
ctTrapInfo[iCount].bPassengerDeletedOrReleased = TRUE
ctTrapInfo[iCount].bCarDeletedOrReleased = TRUE
ctTrapInfo[iCount].ctsProgress = CTSC_DELETED
IF bCopModelsLoaded
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopPed)
SET_MODEL_AS_NO_LONGER_NEEDED(modelCopCar)
ENDIF
bCopModelsLoaded = FALSE
ENDIF
ENDFOR
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// SKIP TO INIT
/// Restart the mission
PROC SKIP_TO_MS_INIT()
CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: SKIP_TO_MS_INIT - restart mission")
// Clear wanted level
SKIP_CLEAR_WANTED()
// Progression stuff
mStage = MS_STAGE_INIT
sProgress = SP_SETUP
// Teleport player out of vehicle, recreate it
SKIP_RESPAWN_TRUCK(stVehicle.location, stVehicle.heading, FALSE)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_ENTITY_COORDS(PLAYER_PED_ID(), <<1205.5319, -1264.5835, 34.2264>>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 37.74)
ENDIF
// Reset cops
SKIP_DELETE_COPS()
bCopsChallenged = FALSE
// Reset comments
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
bFranklinCompletedComment = TRUE
bFranklinSaidClearComment = FALSE
bFranklinTimeWarnComment = FALSE
// Delivery call triggered?
bHadDeliveryCall = FALSE
bCallDelaySet = FALSE
MISSION_OBJECTIVE_RESET(MO_B3AGETIN)// Get in the truck.
MISSION_OBJECTIVE_RESET(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
MISSION_OBJECTIVE_RESET(MO_B3AWAN1) // Lose the cops.
MISSION_OBJECTIVE_RESET(MO_B3ARTV) // Get back in the ~b~truck.~s~
ENDPROC
#ENDIF
/// PURPOSE:
/// SKIP TO player in truck - CP 0
/// Restart the mission
PROC SKIP_TO_START_DRIVE(BOOL bIsACheckpoint = FALSE)
CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: SKIP_TO_START_DRIVE - restart mission")
// Clear wanted level
SKIP_CLEAR_WANTED()
// Progression stuff
mStage = MS_STAGE_RETURN_VEHICLE
sProgress = SP_SETUP
// Reset cops
SKIP_DELETE_COPS()
bCopsChallenged = FALSE
// Reset comments
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
bFranklinCompletedComment = TRUE
bFranklinSaidClearComment = FALSE
bFranklinTimeWarnComment = FALSE
// Delivery call triggered?
bHadDeliveryCall = FALSE
bCallDelaySet = FALSE
MISSION_OBJECTIVE_EXPIRE(MO_B3AGETIN)// Get in the truck.
MISSION_OBJECTIVE_RESET(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
MISSION_OBJECTIVE_RESET(MO_B3AWAN1) // Lose the cops.
MISSION_OBJECTIVE_RESET(MO_B3ARTV) // Get back in the ~b~truck.~s~
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<< -1142.8287, -1254.5848, 0 >>, << -1136.6863, -1246.4720, 8 >>, FALSE)
IF bIsACheckPoint
IF NOT DOES_ENTITY_EXIST(stVehicle.vehicle)
SKIP_RESPAWN_TRUCK(stVehicle.location, stVehicle.heading, FALSE)
ENDIF
WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
WAIT(0)
ENDWHILE
END_REPLAY_SETUP(stVehicle.vehicle, VS_DRIVER, FALSE)
ELSE
SKIP_RESPAWN_TRUCK(stVehicle.location, stVehicle.heading, TRUE)
// WAIT_FOR_WORLD_TO_LOAD(stVehicle.location)
ENDIF
timeOutStage = TOS_START // The mission timer is handled through the fail checks
bDoTheClock = TRUE
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// WARP NEAR END - DEBUG ONLY
/// Warps player close to endpoint so you can test cutscene trigger
PROC SKIP_WARP_TO_END()
CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: SKIP_WARP_TO_END (teleport near destination)")
// Clear wanted level
SKIP_CLEAR_WANTED()
// Progression stuff
mStage = MS_STAGE_RETURN_VEHICLE
sProgress = SP_SETUP
// Teleport player out of vehicle, recreate it
SKIP_RESPAWN_TRUCK(<< -1066.8279, -1259.9740, 4.9642 >>, 209.23)
// Delete cops
SKIP_DELETE_COPS(FALSE)
// Has Franklin said comment?
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
bFranklinCompletedComment = TRUE
bFranklinSaidClearComment = TRUE
bFranklinTimeWarnComment = TRUE
// Delivery call triggered?
bHadDeliveryCall = FALSE
bCallDelaySet = FALSE
MISSION_OBJECTIVE_EXPIRE(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
MISSION_OBJECTIVE_RESET(MO_B3AWAN1) // Lose the cops.
MISSION_OBJECTIVE_RESET(MO_B3ARTV) // Get back in the ~b~truck.~s~
ENDPROC
#ENDIF
/// PURPOSE:
/// WARP TO DELIVERY
/// Trigger the end bit if player has already been warped to end and we skip again
PROC SKIP_WARP_TO_DELIVERY(BOOL bIsACheckpoint = FALSE)
CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: SKIP_WARP_TO_DELIVERY")
// Clear wanted level
SKIP_CLEAR_WANTED()
// Remove blip
SAFE_REMOVE_BLIP(biMissionBlip)
// Progression stuff
mStage = MS_STAGE_DELIVERY
sProgress = SP_SETUP
// Delete cops
SKIP_DELETE_COPS(FALSE)
// Franklin cleared wanted comment
bFranklinSaidClearComment = TRUE
// Delivery call triggered?
bHadDeliveryCall = FALSE
bCallDelaySet = FALSE
MISSION_OBJECTIVE_EXPIRE(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
MISSION_OBJECTIVE_EXPIRE(MO_B3AWAN1) // Lose the cops.
MISSION_OBJECTIVE_EXPIRE(MO_B3ARTV) // Get back in the ~b~truck.~s~
IF bIsACheckpoint
bRestartedAfterCP0 = TRUE
SKIP_RESPAWN_TRUCK(vecDestination, 298.7, FALSE)
WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
WAIT(0)
ENDWHILE
END_REPLAY_SETUP(stVehicle.vehicle, VS_DRIVER, FALSE)
ELSE
// Has Franklin said comment?
IF bFranklinCompletedComment = FALSE
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
bFranklinCompletedComment = TRUE
ENDIF
SKIP_RESPAWN_TRUCK(vecDestination, 298.7, TRUE)
// WAIT_FOR_WORLD_TO_LOAD(vecDestination)
ENDIF
SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_DELIVERY, "Deliver vehicle.", TRUE)
ENDPROC
/// PURPOSE:
/// TRIGGER COMPLETION
/// Sets it to the leave area stage and then sets player far enough away that it counts as leaving area
PROC SKIP_TRIGGER_COMPLETION(BOOL bIsACheckpoint = FALSE)
CPRINTLN(DEBUG_MISSION, "DEBUG SKIP ::: SKIP_TRIGGER_COMPLETION")
// Clear wanted level
SKIP_CLEAR_WANTED()
// Progression stuff
mStage = MS_STAGE_LEAVE_AREA
sProgress = SP_SETUP
// Teleport player out of vehicle, recreate it
SKIP_RESPAWN_TRUCK(vecDestination, 298.7, FALSE)
// Delete cops
SKIP_DELETE_COPS(FALSE)
// Has Franklin said comment?
IF bFranklinCompletedComment = FALSE
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
ENDIF
bFranklinCompletedComment = TRUE
ENDIF
// Franklin cleared wanted comment
bFranklinSaidClearComment = TRUE
// Delivery call triggered?
bHadDeliveryCall = TRUE
bCallDelaySet = TRUE
MISSION_OBJECTIVE_EXPIRE(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
MISSION_OBJECTIVE_EXPIRE(MO_B3AWAN1) // Lose the cops.
MISSION_OBJECTIVE_EXPIRE(MO_B3ARTV) // Get back in the ~b~truck.~s~
IF bIsACheckpoint
bRestartedAfterCP0 = TRUE
WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
WAIT(0)
ENDWHILE
END_REPLAY_SETUP(NULL, DEFAULT, FALSE)
ELSE
SET_ENTITY_COORDS(PLAYER_PED_ID(), << -1243.3162, -1041.6366, 7.5121 >>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 28.2)
ENDIF
SAFE_FADE_SCREEN_IN_FROM_BLACK() // Screen needs to be fully faded back in before the mission complete GUI stuff will display
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Skip to the desired stage or warp
/// PARAMS:
/// iSkipStage - Pass an ENUM_TO_INT from the MISSION_SKIP_STAGE enum
PROC DO_Z_SKIP(INT iSkipStage)
CPRINTLN(DEBUG_MISSION, "::: Starting Z-skip :::")
// Z-skip init
RC_START_Z_SKIP()
// Convert INT to more readbale ENUM
eTargetStage = INT_TO_ENUM(MISSION_SKIP_STAGE, iSkipStage)
// Skip to appropriate stage
IF eTargetStage = MSS_MISSION_TRIGGERED
CPRINTLN(DEBUG_MISSION, "::: Going to SKIP_TO_MS_INIT as if the mission has been freshly triggered :::")
SKIP_TO_MS_INIT()
ELIF eTargetStage = MSS_RESTART
CPRINTLN(DEBUG_MISSION, "::: Going to SKIP_TO_START_DRIVE :::")
SKIP_TO_START_DRIVE()
ELIF eTargetStage = MSS_WARP_NEAR_END
CPRINTLN(DEBUG_MISSION, "::: Going to SKIP_WARP_TO_END :::")
SKIP_WARP_TO_END()
ELIF eTargetStage = MSS_TRIGGER_DELIVERY
CPRINTLN(DEBUG_MISSION, "::: Going to SKIP_WARP_TO_DELIVERY :::")
SKIP_WARP_TO_DELIVERY()
ELIF eTargetStage = MSS_TRIGGER_COMPLETION
CPRINTLN(DEBUG_MISSION, "::: Going to SKIP_TRIGGER_COMPLETION :::")
SKIP_TRIGGER_COMPLETION()
// ELIF eTargetStage = MSS_BODGE_TIMER
// CPRINTLN(DEBUG_MISSION, "::: Z-MENU time-skip!!!")
// IF GET_GAME_TIMER() >= iWarningTime
// CPRINTLN(DEBUG_MISSION, "::: Timer is already past warning timer, doing nothing.")
// ELSE
// iTimeLimit = GET_GAME_TIMER() + (GET_MILLISECONDS_PER_GAME_MINUTE()*(CLOCK_WARNING_MINUTES+5))
// iWarningTime = iTimeLimit - (GET_MILLISECONDS_PER_GAME_MINUTE()*CLOCK_WARNING_MINUTES)
// CPRINTLN(DEBUG_MISSION, "::: Time left was reduced.")
// ENDIF
ENDIF
// Z-skip cleanup
RC_END_Z_SKIP()
CPRINTLN(DEBUG_MISSION, "::: Finishing Z-skip :::")
ENDPROC
#ENDIF
// ===========================================================================================================
// Termination
// ===========================================================================================================
// -----------------------------------------------------------------------------------------------------------
// Script Cleanup
// -----------------------------------------------------------------------------------------------------------
PROC Script_Cleanup()
CPRINTLN(DEBUG_MISSION, "SCRIPT_CLEANUP running")
// If the mission was triggered then additional mission cleanup will be required.
IF (Random_Character_Cleanup_If_Triggered())
CPRINTLN(DEBUG_MISSION, "...Random Character Script was triggered so additional cleanup required")
ENDIF
RC_CleanupSceneEntities(sRCLauncherDataLocal)
COLLECT_AREA_CLEANUP()
#IF IS_DEBUG_BUILD
// Widgets
IF DOES_WIDGET_GROUP_EXIST(widgetGroup)
DELETE_WIDGET_GROUP(widgetGroup)
ENDIF
#ENDIF
// Return ambient cop creation to normal
SET_CREATE_RANDOM_COPS(TRUE)
// Clear GPS disabled zone
SET_GPS_DISABLED_ZONE(<< 0, 0, 0 >>, << 0, 0, 0 >>)
REMOVE_SCENARIO_BLOCKING_AREA(sbCarPark[0])
REMOVE_SCENARIO_BLOCKING_AREA(sbCarPark[1])
SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_NONE)
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------------------------
// Script Pass
// -----------------------------------------------------------------------------------------------------------
PROC Script_Passed()
CPRINTLN(DEBUG_MISSION, "SCRIPT_PASSED running")
Random_Character_Passed(CP_RAND_C_BAR3, FALSE)
Script_Cleanup()
ENDPROC
//*************************************************************************************************************************************************
//
// Data init
//
//*************************************************************************************************************************************************
// General data init regardless of whether we're starting at the beginning or from a checkpoint
PROC DATA_INIT()
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_MISSION, "DATA_INIT running")
mSkipMenu[0].sTxtLabel = "Restart as if from fresh trigger"
mSkipMenu[1].sTxtLabel = "Restart (CP 0)"
mSkipMenu[2].sTxtLabel = "Warp near end"
mSkipMenu[3].sTxtLabel = "Trigger delivery (CP 1)"
mSkipMenu[4].sTxtLabel = "Trigger mission complete"
// mSkipMenu[4].sTxtLabel = "DEVELOPER TOOL: Timeskip"
IF NOT DOES_WIDGET_GROUP_EXIST(widgetGroup)
widgetGroup = START_WIDGET_GROUP("Barry 3A")
ADD_WIDGET_VECTOR_SLIDER("Stash prop offset", vecStashOffset, -4.0, 4.0, 0.05)
ADD_WIDGET_BOOL("Set mission timer to 15 seconds left", bDebugClockTo15s)
STOP_WIDGET_GROUP()
ENDIF
#ENDIF
REQUEST_ADDITIONAL_TEXT("BARR3A", MISSION_TEXT_SLOT)
// Mission vehicle data
stVehicle.modelName = dloader
stVehicle.location = << 1199.80, -1259.22, 34.23 >>
stVehicle.heading = 174.7
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
ADD_PED_FOR_DIALOGUE(mConversationStruct, 1, PLAYER_PED_ID(), "FRANKLIN")
ENDIF
// Franklin cleared wanted comment
bFranklinSaidClearComment = FALSE
bFranklinTimeWarnComment = FALSE
// Init stuff for flavour conversations
iFranklinCommentCount = 0
STORE_FLAVOUR_CHAT()
// Delivery call triggered?
bHadDeliveryCall = FALSE
bCallDelaySet = FALSE
bDidScannerLine = FALSE
STORE_MISSION_OBJECTIVE_DATA()
STORE_COP_TRIGGER_DATA()
// Have cops started after Franklin at start
bCopsChallenged = FALSE
// Request stuff for cop trap
REQUEST_MODEL(modelCopCar)
REQUEST_MODEL(modelCopPed)
bCopModelsLoaded = TRUE
// Init timeout fail
timeOutStage = TOS_IDLE
bDoTheClock = FALSE
sFailReason = "DEFAULT"
// Silently add Barry as contact in case we've launched from debug menu
ADD_CONTACT_TO_PHONEBOOK(CHAR_BARRY, FRANKLIN_BOOK, FALSE)
// Stop car driving behind apartment
sbCarPark[0] = ADD_SCENARIO_BLOCKING_AREA(<< -1156.9, -1274.0, 0.0 >>, << -1141.5, -1239.6, 8.0 >>)
sbCarPark[1] = ADD_SCENARIO_BLOCKING_AREA(<< -1177.0, -1292.0, 0.0 >>, << -1160.0, -1273.3, 8.0 >>)
SET_GPS_DISABLED_ZONE(<< -1132.88, -1262.01, 0.0 >>, << -1102.43, -1196.58, 15.0 >>)
SET_CREATE_RANDOM_COPS(FALSE)
ENDPROC
/// PURPOSE:
/// Set up the truck's configuration
/// Seperated out from main init so we don't mess up the setup when restarting from a checkpoint
PROC TRUCK_INIT()
IF IS_ENTITY_ALIVE(stVehicle.vehicle)
SET_VEHICLE_STRONG(stVehicle.vehicle, TRUE)
SET_VEHICLE_HAS_STRONG_AXLES(stVehicle.vehicle, TRUE)
SET_VEHICLE_CAN_LEAK_OIL(stVehicle.vehicle, FALSE)
SET_VEHICLE_CAN_LEAK_PETROL(stVehicle.vehicle, FALSE)
IF NOT bStuckCheckActive
ADD_VEHICLE_UPSIDEDOWN_CHECK(stVehicle.vehicle)
ENDIF
SET_VEHICLE_AS_RESTRICTED(stVehicle.vehicle, RESTRICTION_STASHVEH)
ENDIF
ENDPROC
//*************************************************************************************************************************************************
//
// Mission stage procs
//
//*************************************************************************************************************************************************
// MISSION STAGE PROC
// Waits for game text
PROC STAGE_INIT()
// Wait for text before proceeding
IF HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
SET_ALL_VEHICLE_GENERATORS_ACTIVE_IN_AREA(<< -1142.8287, -1254.5848, 0 >>, << -1136.6863, -1246.4720, 8 >>, FALSE)
biMissionBlip = CREATE_VEHICLE_BLIP(stVehicle.vehicle)
mStage = MS_STAGE_CALL_BARRY
sProgress = SP_SETUP
ENDIF
ENDPROC
/// PURPOSE:
/// MISSION STAGE PROC
/// Player calls Barry once near to truck
PROC STAGE_CALL_BARRY()
SWITCH sProgress
CASE SP_SETUP
// Franklin calls Barry
ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, NULL, "BARRY")
IF PLAYER_CALL_CHAR_CELLPHONE(mConversationStruct, CHAR_BARRY, "BAR3AAU", "BAR3A_PICK2", CONV_PRIORITY_MEDIUM)
CPRINTLN(DEBUG_MISSION, "STAGE_CALL_BARRY: SP_SETUP started call")
sProgress = SP_RUNNING
ENDIF
BREAK
CASE SP_RUNNING
// Mission can progress either by player getting in truck or by call ending
// Check for player in truck
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
timeOutStage = TOS_START // The mission timer is handled through the fail checks
mStage = MS_STAGE_RETURN_VEHICLE
sProgress = SP_SETUP
// Check for phone call finishing
ELIF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
timeOutStage = TOS_START // The mission timer is handled through the fail checks
mStage = MS_STAGE_ENTER_TRUCK
sProgress = SP_SETUP
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// MISSION STAGE PROC
/// Wait for player to get in the truck
PROC STAGE_ENTER_TRUCK()
SWITCH sProgress
CASE SP_SETUP
// Check whether the player is already in truck
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player not in truck
CPRINTLN(DEBUG_MISSION, "STAGE_ENTER_TRUCK: SP_SETUP going to SP_RUNNING")
DISPLAY_MISSION_OBJECTIVE(MO_B3AGETIN) // Get in the truck.
sProgress = SP_RUNNING
ELSE
// Player alreayd in truck, skip to main driving stage
CPRINTLN(DEBUG_MISSION, "STAGE_ENTER_TRUCK: SP_SETUP going directly to STAGE_RETURN_VEHICLE")
mStage = MS_STAGE_RETURN_VEHICLE
sProgress = SP_SETUP
ENDIF
bDoTheClock = TRUE
BREAK
CASE SP_RUNNING
// Wait until player is in truck
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
CPRINTLN(DEBUG_MISSION, "STAGE_ENTER_TRUCK: SP_RUNNING going to STAGE_RETURN_VEHICLE")
CLEAR_PRINTS()
mStage = MS_STAGE_RETURN_VEHICLE
sProgress = SP_SETUP
ENDIF
BREAK
ENDSWITCH
ENDPROC
// MISSION STAGE PROC
// Get vehicle to Barry if player has collected it
PROC STAGE_RETURN_VEHICLE()
SWITCH sProgress
CASE SP_SETUP
CPRINTLN(DEBUG_MISSION, "STAGE_RETURN_VEHICLE: SP_SETUP")
// Going to start driving
SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_DRIVING)
// Player will be out of their arriving car now
IF NOT bSetupVehGen
SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN(<<0,0,0>>, 0, FALSE)
bSetupVehGen = TRUE
ENDIF
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Remove vehicle blip if it exists
SAFE_REMOVE_BLIP(biMissionBlip)
biMissionBlip = CREATE_COORD_BLIP(vecDestination)
// Show the delivery objective
IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ADELV)
AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED())
DISPLAY_MISSION_OBJECTIVE(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
ENDIF
iFranklinCommentTimer = GET_GAME_TIMER()
// Start stat mission timer
INFORM_MISSION_STATS_SYSTEM_OF_TIME_WINDOW_OPEN(BA3A_DELIVERY_TIME)
sProgress = SP_RUNNING
ELSE
mStage = MS_STAGE_GET_VEHICLE_BACK
ENDIF
// Enable the clock now we're doing the fail check
IF timeOutStage = TOS_FAILCHECK
bDoTheClock = TRUE
ENDIF
BREAK
CASE SP_RUNNING
// Detect player getting out of vehicle
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player is still in truck
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
// Player wanted: State change required
sProgress = SP_CLEANUP
ELSE
// See if we need to show the delivery objective
IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ADELV)
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3ADELV) // Take the truck to ~y~Barry's apartment.~s~
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
ENDIF
// Player not wanted - Check for vehicle arriving at destination
IF IS_PED_SITTING_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle) // Player cannot be bailing out of car!
AND IS_ENTITY_AT_COORD(stVehicle.vehicle, vecDestination, << 6.0, 6.0, LOCATE_SIZE_HEIGHT >>, TRUE)
// AND IS_ENTITY_IN_RANGE_COORDS(stVehicle.vehicle, vecDestination, 6.0)
timeOutStage = TOS_IDLE
sProgress = SP_CLEANUP
ENDIF
// Not arrived yet, handle Franklin's wanted clear comment
IF NOT bFranklinSaidClearComment
IF GET_GAME_TIMER() - iFranklinCommentTimer > 8000
AND iFranklinCommentCount >= NUM_FLAVOUR_CONVOS // Franklin should only say this comment if he was wanted for some time
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF CREATE_CONVERSATION(mConversationStruct, "BAR3AAU", "BAR3A_LW", CONV_PRIORITY_MEDIUM)
bFranklinSaidClearComment = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
// Player not in truck - change states
sProgress = SP_CLEANUP
ENDIF
BREAK
CASE SP_CLEANUP
// Clear blip + text
CLEAR_PRINTS()
SAFE_REMOVE_BLIP(biMissionBlip)
sProgress = SP_SETUP
// choose next stage
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
CPRINTLN(DEBUG_MISSION, "STAGE_RETURN_VEHICLE: SP_CLEANUP going to STAGE_LOSE_WANTED")
mStage = MS_STAGE_LOSE_WANTED
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_RETURN_VEHICLE: SP_CLEANUP going to STAGE_DELIVERY")
SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(CP_DELIVERY, "Deliver vehicle.", TRUE)
mStage = MS_STAGE_DELIVERY
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_RETURN_VEHICLE: SP_CLEANUP going to STAGE_GET_VEHICLE_BACK")
mStage = MS_STAGE_GET_VEHICLE_BACK
ENDIF
BREAK
ENDSWITCH
ENDPROC
// MISSION STAGE PROC
// Tracks player getting back in a collected vehicle if they abandon it en route to Barry
PROC STAGE_GET_VEHICLE_BACK()
SWITCH sProgress
CASE SP_SETUP
CPRINTLN(DEBUG_MISSION, "STAGE_GET_VEHICLE_BACK: SP_SETUP")
// Remove the destination blip until player gets vehicle back
SAFE_REMOVE_BLIP(biMissionBlip)
// Blip vehicle instead
biMissionBlip = CREATE_VEHICLE_BLIP(stVehicle.vehicle)
SET_BLIP_ROUTE(biMissionBlip, TRUE)
IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ARTV)
AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED())
DISPLAY_MISSION_OBJECTIVE(MO_B3ARTV)
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
ENDIF
sProgress = SP_RUNNING
// Enable the clock now we're doing the fail check
IF timeOutStage = TOS_FAILCHECK
bDoTheClock = TRUE
ENDIF
BREAK
CASE SP_RUNNING
HANDLE_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT(stateRestoreConversation, mConversationStruct, "BAR3AAU", tSavedConversationRoot, tSavedConversationLabel)
// Track player entering vehicle
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
sProgress = SP_CLEANUP
ELSE
// See if the objective is needed
IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ARTV)
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3ARTV)
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
ENDIF
// Check if player is in ragdoll - dialogue needs to stop in this case
IF IS_PED_RAGDOLL(PLAYER_PED_ID())
// Player is in ragdoll - if a wanted complaint conversation is ongoing, kill it
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
ENDIF
ELSE
// Player not in ragdoll - are they wanted?
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
// See if we need to update dialogue
FRANKLIN_WANTED_DIALOGUE()
ENDIF
ENDIF
ENDIF
BREAK
CASE SP_CLEANUP
// Clear blip + text
CLEAR_PRINTS()
SAFE_REMOVE_BLIP(biMissionBlip)
sProgress = SP_SETUP
// go to correct stage
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1
CPRINTLN(DEBUG_MISSION, "STAGE_GET_VEHICLE_BACK: SP_CLEANUP going to STAGE_RETURN_VEHICLE")
mStage = MS_STAGE_RETURN_VEHICLE
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_GET_VEHICLE_BACK: SP_CLEANUP going to STAGE_LOSE_WANTED")
mStage = MS_STAGE_LOSE_WANTED
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_GET_VEHICLE_BACK: SP_CLEANUP found player not in vehicle! Go back to SP_RUNNING.")
sProgress = SP_RUNNING
ENDIF
BREAK
ENDSWITCH
ENDPROC
// MISSION STAGE PROC
// Track player being wanted - as a separate proc because of dialogue triggering
PROC STAGE_LOSE_WANTED()
SWITCH sProgress
CASE SP_SETUP
CPRINTLN(DEBUG_MISSION, "STAGE_LOSE_WANTED: SP_SETUP")
// Clear destination blip if it exists
SAFE_REMOVE_BLIP(biMissionBlip)
// Display objective
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
OR GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
DISPLAY_MISSION_OBJECTIVE(MO_B3AWAN1) // Lose your wanted level
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
bWantedObjectiveNeeded = FALSE
ELSE
bWantedObjectiveNeeded = TRUE
ENDIF
// Distance "grace" range does not apply while wanted
IF timeOutStage = TOS_IDLE
timeOutStage = TOS_FAILCHECK
bDoTheClock = TRUE
ENDIF
// Set marker bool for which ending phone call we want to play
bBeenWanted = TRUE
// Set timer for playing custom scanner line
iScannerTimer = GET_GAME_TIMER() + 2500
sProgress = SP_RUNNING
BREAK
CASE SP_RUNNING
HANDLE_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT(stateRestoreConversation, mConversationStruct, "BAR3AAU", tSavedConversationRoot, tSavedConversationLabel)
IF NOT bDidScannerLine
AND GET_GAME_TIMER() > iScannerTimer
PLAY_POLICE_REPORT("SCRIPTED_SCANNER_REPORT_BARRY_3A_01", 0.0)
bDidScannerLine = TRUE
ENDIF
// Detect player getting out of vehicle
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player is still in truck
// Has player lost wanted level?
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1
sProgress = SP_CLEANUP
ELSE
// See if we need to display objective
IF bWantedObjectiveNeeded
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3AWAN1) // Lose your wanted level
CHECK_CONVERSATION_AND_OBJECTIVE_TEXT_CONFLICT_NOW(stateRestoreConversation)
bWantedObjectiveNeeded = FALSE
ENDIF
// Do Franklin's wanted dialogue
FRANKLIN_WANTED_DIALOGUE()
ENDIF
ELSE
// Player not in vehicle - need to change stage
sProgress = SP_CLEANUP
ENDIF
BREAK
CASE SP_CLEANUP
// If player is not wanted, some cleanup is needed
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1
// Kill any wanted conversation
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_FACE_TO_FACE_CONVERSATION()
ENDIF
ENDIF
// Return to appropriate state
sProgress = SP_SETUP
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
CPRINTLN(DEBUG_MISSION, "STAGE_LOSE_WANTED: SP_CLEANUP going to STAGE_RETURN_VEHICLE")
mStage = MS_STAGE_RETURN_VEHICLE
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_LOSE_WANTED: SP_CLEANUP going to STAGE_GET_VEHICLE_BACK")
mStage = MS_STAGE_GET_VEHICLE_BACK
ENDIF
BREAK
ENDSWITCH
ENDPROC
// MISSION STAGE PROC
// Handles the player delivering vehicle - force exit etc.
PROC STAGE_DELIVERY()
SWITCH sProgress
CASE SP_SETUP
// Set health before vehicle has stopped for maximum leniency!
IF GET_VEHICLE_PETROL_TANK_HEALTH(stVehicle.vehicle) < 1
SET_VEHICLE_PETROL_TANK_HEALTH(stVehicle.vehicle, 10.0)
ENDIF
IF GET_VEHICLE_ENGINE_HEALTH(stVehicle.vehicle) < 1
SET_VEHICLE_ENGINE_HEALTH(stVehicle.vehicle, 10.0)
ENDIF
// Stop the vehicle ready for delivery event
IF BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(stVehicle.vehicle)
CPRINTLN(DEBUG_MISSION, "STAGE_DELIVERY: SP_SETUP has stopped car, going to SP_RUNNING")
// Stop the mission stat timer
INFORM_MISSION_STATS_SYSTEM_OF_TIME_WINDOW_CLOSED()
bDoTheClock = FALSE
timeOutStage = TOS_IDLE
sProgress = SP_RUNNING
ENDIF
BREAK
CASE SP_RUNNING
DISPLAY_MISSION_OBJECTIVE(MO_B3AEXIT)
sProgress = SP_CLEANUP
BREAK
CASE SP_CLEANUP
ADD_PED_FOR_DIALOGUE(mConversationStruct, 3, NULL, "BARRY")
CPRINTLN(DEBUG_MISSION, "STAGE_DELIVERY: SP_CLEANUP - going to STAGE_LEAVE_AREA")
sProgress = SP_SETUP
mStage = MS_STAGE_LEAVE_AREA
BREAK
ENDSWITCH
ENDPROC
// Franklin calls Barry to confirm delivery
PROC DO_DELIVERY_PHONE_CALL()
IF NOT bCallDelaySet
iCallDelayTimer = GET_GAME_TIMER() + 3500
bCallDelaySet = TRUE
ELIF NOT bHadDeliveryCall
IF GET_GAME_TIMER() > iCallDelayTimer
// Start phone call to Barry
IF bBeenWanted = TRUE
// Has been wanted - mention cops
IF PLAYER_CALL_CHAR_CELLPHONE(mConversationStruct, CHAR_BARRY, "BAR3AAU", "BAR3A_P1", CONV_PRIORITY_VERY_HIGH)
CPRINTLN(DEBUG_MISSION, "DO_DELIVERY_PHONE_CALL: Started been wanted phone call")
sProgress = SP_RUNNING
bHadDeliveryCall = TRUE
ENDIF
ELSE
// Hasn't been wanted - mock Barry for worrying
IF PLAYER_CALL_CHAR_CELLPHONE(mConversationStruct, CHAR_BARRY, "BAR3AAU", "BAR3A_P1b", CONV_PRIORITY_VERY_HIGH)
CPRINTLN(DEBUG_MISSION, "DO_DELIVERY_PHONE_CALL: Started not been wanted phone call")
sProgress = SP_RUNNING
bHadDeliveryCall = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
// MISSION STAGE PROC
// Handles player leaving area
PROC STAGE_LEAVE_AREA()
SWITCH sProgress
CASE SP_SETUP
// If we're sure the player isn't messing about with vehicle, can start leave area checks
IF IS_ENTITY_AT_COORD(stVehicle.vehicle, vecDestination, << 10.0, 10.0, LOCATE_SIZE_HEIGHT >>, FALSE)
SAFE_REMOVE_BLIP(biMissionBlip)
SET_INSTANCE_PRIORITY_HINT(INSTANCE_HINT_NONE)
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: SP_SETUP: Truck at drop off point, player still in truck")
bPlayerInTruck = TRUE
ELSE
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: SP_SETUP: Truck at drop off point, player has got out")
IF MISSION_OBJECTIVES_CURRENTLY_DISPLAYED()
CLEAR_PRINTS() // May be needed to remove expired objective
ENDIF
bPlayerInTruck = FALSE
ENDIF
sProgress = SP_RUNNING
// Player is mucking about with vehicle
ELSE
// Truck not at delivery point - drive it back
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: SP_SETUP: Truck not at delivery point, go to STAGE_TAKE_VEHICLE_BACK")
mStage = MS_STAGE_TAKE_VEHICLE_BACK
sProgress = SP_SETUP
ENDIF
BREAK
CASE SP_RUNNING
// If we're sure the player isn't dicking about with vehicle, can check for leaving area
IF IS_ENTITY_AT_COORD(stVehicle.vehicle, vecDestination, << 10.0, 10.0, LOCATE_SIZE_HEIGHT >>, FALSE)
// Checks for when player's in vehicle
IF bPlayerInTruck
// Check whether player's got out
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player got out again - can drop to leave area check
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: Player out of vehicle, vehicle at drop-off point")
CLEAR_PRINTS()
bPlayerInTruck = FALSE
ELSE
// Player still in truck
bPlayerInTruck = TRUE
ENDIF
ELIF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player got back in truck
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: Player got back in truck")
CLEAR_PRINTS()
bPlayerInTruck = TRUE
ELSE
// Check for firing phone call
DO_DELIVERY_PHONE_CALL()
// Leave area check
IF NOT IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), stVehicle.vehicle, 55)
AND NOT IS_ENTITY_ON_SCREEN(stVehicle.vehicle)
sProgress = SP_CLEANUP
// See if we still need the objective
ELIF bHadDeliveryCall
AND MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ALEAVE)
AND (GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0 OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED())
DISPLAY_MISSION_OBJECTIVE(MO_B3ALEAVE)
ENDIF
ENDIF
// Player is mucking about with vehicle
ELSE
// Ditch the leave area objective
CLEAR_PRINTS()
mStage = MS_STAGE_TAKE_VEHICLE_BACK
sProgress = SP_SETUP
ENDIF
BREAK
CASE SP_CLEANUP
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: SP_CLEANUP - Player has run off now, script will now exit.")
CLEAR_PRINTS()
SAFE_DELETE_OBJECT(oiStashBox)
SAFE_DELETE_VEHICLE(stVehicle.vehicle)
IF bBeenWanted
OR bRestartedAfterCP0
INFORM_STAT_SYSTEM_OF_BOOL_STAT_HAPPENED(BA3A_AVOID_STAKEOUT)
ENDIF
Script_Passed()
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// MISSION STAGE PROC
/// Player is mucking around with truck and must take it back
PROC STAGE_TAKE_VEHICLE_BACK()
SWITCH sProgress
CASE SP_SETUP
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: SP_SETUP")
SAFE_REMOVE_BLIP(biMissionBlip)
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1
// Player in truck, not wanted
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: SP_SETUP: Player started stage in truck, not wanted")
bPlayerInTruck = TRUE
bPlayerWanted = FALSE
biMissionBlip = CREATE_COORD_BLIP(vecDestination)
ELSE
// Player in truck, wanted
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: SP_SETUP: Player started stage in truck, wanted")
bPlayerInTruck = TRUE
bPlayerWanted = TRUE
IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3AWAN1)
bObjectiveNeeded = FALSE
ELSE
bObjectiveNeeded = TRUE
ENDIF
ENDIF
ELSE
// Player not in truck
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: SP_SETUP: Player started stage not in truck")
bPlayerInTruck = FALSE
IF MISSION_OBJECTIVE_WILL_DISPLAY(MO_B3ARTV)
IF GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
OR NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3ARTV)
bObjectiveNeeded = FALSE
ELSE
bObjectiveNeeded = TRUE
ENDIF
ELSE
bObjectiveNeeded = FALSE
ENDIF
biMissionBlip = CREATE_VEHICLE_BLIP(stVehicle.vehicle)
ENDIF
sProgress = SP_RUNNING
BREAK
CASE SP_RUNNING
// Checks whether truck is too far from delivery location
IF NOT IS_ENTITY_IN_RANGE_COORDS(stVehicle.vehicle, vecDestination, DELIVERY_FAIL_DISTANCE)
// FAIL!
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player wandered off after delivery!")
sFailReason = "B3ANOTDELV" // The truck was not delivered.
sProgress = SP_SETUP
mStage = MS_STAGE_FAIL_FADE
// Checks for while player's on foot
ELIF NOT bPlayerInTruck
// See if Player's back in truck
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Back in vehicle
bPlayerInTruck = TRUE
CLEAR_PRINTS()
SAFE_REMOVE_BLIP(biMissionBlip)
// Check if wanted
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
// Wanted
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player back in truck but is wanted")
bPlayerWanted = TRUE
bObjectiveNeeded = TRUE
ELSE
// All is well - Check if at destination
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player back in vehicle, not wanted")
bPlayerWanted = FALSE
IF IS_ENTITY_AT_COORD(stVehicle.vehicle, vecDestination, << 6.0, 6.0, LOCATE_SIZE_HEIGHT >>, TRUE)
SAFE_REMOVE_BLIP(biMissionBlip)
sProgress = SP_SETUP
mStage = MS_STAGE_DELIVERY
ELSE
// Not there yet - blip
biMissionBlip = CREATE_COORD_BLIP(vecDestination)
ENDIF
ENDIF
ELSE
// Still on foot
IF bObjectiveNeeded
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3ARTV)
bObjectiveNeeded = FALSE
ENDIF
ENDIF
// See if player's just got out
ELIF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player is on foot - priority objective is get truck back
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player got out of truck")
CLEAR_PRINTS()
bPlayerInTruck = FALSE
bObjectiveNeeded = TRUE
SAFE_REMOVE_BLIP(biMissionBlip)
biMissionBlip = CREATE_VEHICLE_BLIP(stVehicle.vehicle)
// Checks for while player is wanted
ELIF bPlayerWanted
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), stVehicle.vehicle)
// Player got out of truck - that state has priority
CLEAR_PRINTS()
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player out of truck while wanted")
bPlayerInTruck = FALSE
biMissionBlip = CREATE_VEHICLE_BLIP(stVehicle.vehicle)
ELIF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) < 1
// Player is in truck and no longer wanted
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player in truck, no longer wanted")
CLEAR_PRINTS()
bPlayerWanted = FALSE
bObjectiveNeeded = FALSE
SAFE_REMOVE_BLIP(biMissionBlip)
biMissionBlip = CREATE_COORD_BLIP(vecDestination)
ELSE
IF bObjectiveNeeded
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
DISPLAY_MISSION_OBJECTIVE(MO_B3AWAN1)
bObjectiveNeeded = FALSE
ENDIF
ENDIF
// See if player's just become wanted
ELIF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
// Player is now wanted and in truck as we already checked that
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player in truck, now wanted")
CLEAR_PRINTS()
bPlayerWanted = TRUE
bObjectiveNeeded = TRUE
SAFE_REMOVE_BLIP(biMissionBlip)
// Checks for while everything is going swimmingly
ELSE
// Check for redelivery
IF IS_ENTITY_AT_COORD(stVehicle.vehicle, vecDestination, << 6.0, 6.0, LOCATE_SIZE_HEIGHT >>, TRUE)
CPRINTLN(DEBUG_MISSION, "STAGE_TAKE_VEHICLE_BACK: Player at delivery location, going to STAGE_DELIVERY")
SAFE_REMOVE_BLIP(biMissionBlip)
sProgress = SP_SETUP
mStage = MS_STAGE_DELIVERY
ENDIF
ENDIF
BREAK
CASE SP_CLEANUP
CPRINTLN(DEBUG_MISSION, "STAGE_LEAVE_AREA: SP_CLEANUP - Player has run off now, script will now exit.")
CLEAR_PRINTS()
SAFE_DELETE_OBJECT(oiStashBox)
SAFE_DELETE_VEHICLE(stVehicle.vehicle)
IF bBeenWanted
OR bRestartedAfterCP0
INFORM_STAT_SYSTEM_OF_BOOL_STAT_HAPPENED(BA3A_AVOID_STAKEOUT)
ENDIF
Script_Passed()
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// MISSION STAGE PROC
/// Handles the fade out
PROC STAGE_FAIL_FADE()
SWITCH sProgress
CASE SP_SETUP
IF NOT IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP() // Block mission fail if the player is in shop menus - they might do this after they use a pay and spray and it looks really weird
SAFE_REMOVE_BLIP(biMissionBlip)
bDoTheClock = FALSE
CLEAR_PRINTS()
CLEAR_HELP(TRUE)
IF IS_STRING_NULL_OR_EMPTY(sFailReason)
// Guard against null string case
SCRIPT_ASSERT("Reached STAGE_FAIL_FADE with NULL/empty fail reason string - Please add detailed repro steps when bugging this.")
sFailReason = "DEFAULT"
ENDIF
IF ARE_STRINGS_EQUAL(sFailReason, "DEFAULT")
// No fail reason
Random_Character_Failed()
ELSE
Random_Character_Failed_With_Reason(sFailReason)
ENDIF
CPRINTLN(DEBUG_MISSION, "STAGE_FAIL_FADE: SP_SETUP - going to SP_RUNNING")
sProgress = SP_RUNNING
ENDIF
BREAK
CASE SP_RUNNING
IF GET_MISSION_FLOW_SAFE_TO_CLEANUP()
CPRINTLN(DEBUG_MISSION, "STAGE_FAIL_FADE: SP_CLEANUP - script will now exit")
bDoTheClock = FALSE
// Do a check here to see if we need to warp the player at all
// (only set the fail warp locations if we can't leave the player where he was)
// MISSION_FLOW_SET_FAIL_WARP_LOCATION(vPos, fHeading)
// SET_REPLAY_DECLINED_VEHICLE_WARP_LOCATION(vPos, fHeading)
COLLECT_AREA_CLEANUP(TRUE)
Script_Cleanup() // script_cleanup should terminate the thread
ELSE
// not finished fading out
// you may want to handle dialogue etc here.
ENDIF
BREAK
ENDSWITCH
ENDPROC
// ===========================================================================================================
// DEBUG FUNCTIONS
// ===========================================================================================================
/// PURPOSE: Check for Forced Pass or Fail
PROC DEBUG_Check_Debug_Keys()
#IF IS_DEBUG_BUILD
INT iNewStage
// Check for Pass
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S))
CLEAR_ALL_MISSION_OBJECTIVES()
Script_Passed()
// Check for Fail
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F))
CLEAR_ALL_MISSION_OBJECTIVES()
mStage = MS_STAGE_FAIL_FADE
sProgress = SP_SETUP
// Check for skip forward
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J))
IF mStage = MS_STAGE_CALL_BARRY
OR mStage = MS_STAGE_ENTER_TRUCK
DO_Z_SKIP(ENUM_TO_INT(MSS_RESTART))
ELIF mStage = MS_STAGE_RETURN_VEHICLE
OR mStage = MS_STAGE_GET_VEHICLE_BACK
OR mStage = MS_STAGE_LOSE_WANTED
IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), vecDestination, 125)
// If the player is close to the drop-off, trigger delivery
DO_Z_SKIP(ENUM_TO_INT(MSS_TRIGGER_DELIVERY))
ELSE
// Player still distant, warp near the drop-off location
DO_Z_SKIP(ENUM_TO_INT(MSS_WARP_NEAR_END))
ENDIF
ELIF mStage = MS_STAGE_DELIVERY
OR mStage = MS_STAGE_LEAVE_AREA
// Complete mission warp
DO_Z_SKIP(ENUM_TO_INT(MSS_TRIGGER_COMPLETION))
ENDIF
// Check for skip backward
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_P))
IF mStage = MS_STAGE_DELIVERY
// If the player's reached the drop-off, warp to the near end location
DO_Z_SKIP(ENUM_TO_INT(MSS_WARP_NEAR_END))
ELIF mStage = MS_STAGE_LEAVE_AREA
// Leaving area - skip back to delivery
DO_Z_SKIP(ENUM_TO_INT(MSS_TRIGGER_DELIVERY))
ELIF mStage = MS_STAGE_RETURN_VEHICLE
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
AND IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), stVehicle.location, 3.0)
DO_Z_SKIP(ENUM_TO_INT(MSS_MISSION_TRIGGERED))
ELSE
DO_Z_SKIP(ENUM_TO_INT(MSS_RESTART))
ENDIF
ELIF mStage = MS_STAGE_LOSE_WANTED
DO_Z_SKIP(ENUM_TO_INT(MSS_RESTART))
ELIF mStage = MS_STAGE_CALL_BARRY
OR mStage = MS_STAGE_ENTER_TRUCK
// Otherwise, restart
DO_Z_SKIP(ENUM_TO_INT(MSS_MISSION_TRIGGERED))
ENDIF
// Check for Z menu
ELIF LAUNCH_MISSION_STAGE_MENU(mSkipMenu, iNewStage)
DO_Z_SKIP(iNewStage)
ENDIF
IF bDebugClockTo15s
bDebugClockTo15s = FALSE
IF timeOutStage = TOS_FAILCHECK
// Set time limit to 15 seconds
iTimeLimit = GET_GAME_TIMER() + 15000
CPRINTLN(DEBUG_MISSION, "TIME LIMIT debug reset::: ", iTimeLimit, "ms. MS per game minute is ", GET_MILLISECONDS_PER_GAME_MINUTE(), "ms")
// Stop Franklin saying his remark so we can hear the beeps
bFranklinTimeWarnComment = TRUE
iTenSecondsLeft = iTimeLimit - 11000
iFiveSecondsLeft = iTimeLimit - 6000
iZeroSecondsLeft = iTimeLimit - 1000
bStartedBeepTimer = FALSE
ENDIF
ENDIF
#ENDIF
ENDPROC
// ===========================================================================================================
// Script Loop
// ===========================================================================================================
SCRIPT(g_structRCScriptArgs sRCLauncherDataIn)
sRCLauncherDataLocal = sRCLauncherDataIn
RC_TakeEntityOwnership(sRCLauncherDataLocal)
RC_CLEANUP_LAUNCHER()
SET_MISSION_FLAG(TRUE)
// Setup callback when player is killed, arrested or goes to multiplayer
IF (HAS_FORCE_CLEANUP_OCCURRED(DEFAULT_FORCE_CLEANUP_FLAGS|FORCE_CLEANUP_FLAG_DEBUG_MENU))
PRINT_LAUNCHER_DEBUG("Force cleanup [TERMINATING]")
Random_Character_Failed()
Script_Cleanup()
ENDIF
// Initialisation
DATA_INIT()
// Grab stash truck now in case checkpoints need to respawn it
IF DOES_ENTITY_EXIST(sRCLauncherDataLocal.vehID[0])
stVehicle.vehicle = sRCLauncherDataLocal.vehID[0]
ENDIF
IF DOES_ENTITY_EXIST(sRCLauncherDataLocal.objID[0])
oiStashBox = sRCLauncherDataLocal.objID[0]
ENDIF
// Check whether this is a replay
IF Is_Replay_In_Progress()
INT iReplayStage = GET_REPLAY_MID_MISSION_STAGE()
// Check for shit skip
IF g_bShitskipAccepted
iReplayStage++
ENDIF
SWITCH iReplayStage
CASE 0
CPRINTLN(DEBUG_MISSION, "On a replay - CP 0")
START_REPLAY_SETUP(stVehicle.location, stVehicle.heading)
SKIP_TO_START_DRIVE(TRUE)
BREAK
CASE CP_DELIVERY
CPRINTLN(DEBUG_MISSION, "On a replay - CP_DELIVERY")
START_REPLAY_SETUP(vecDestination, 298.7)
SKIP_WARP_TO_DELIVERY(TRUE)
BREAK
CASE CP_SHITSKIP_COMPLETE
CPRINTLN(DEBUG_MISSION, "On a replay - CP_SHITSKIP_COMPLETE")
START_REPLAY_SETUP(<< -1243.3162, -1041.6366, 7.5121 >>, 28.2)
SKIP_TRIGGER_COMPLETION(TRUE)
BREAK
DEFAULT
SCRIPT_ASSERT("Replay in progress: Unknown checkpoint selected")
BREAK
ENDSWITCH
RC_END_Z_SKIP()
ELIF IS_REPEAT_PLAY_ACTIVE()
CPRINTLN(DEBUG_MISSION, "Barry3A - repeat play")
RC_END_Z_SKIP()
ENDIF
// Grab cop car
IF DOES_ENTITY_EXIST(sRCLauncherDataLocal.vehID[1])
ASSIGN_VEHICLE_INDEX(ctTrapInfo[0].vehicle, sRCLauncherDataLocal.vehID[1])
ENDIF
IF DOES_ENTITY_EXIST(sRCLauncherDataLocal.pedID[0])
ASSIGN_PED_INDEX(ctTrapInfo[0].driver, sRCLauncherDataLocal.pedID[0])
ENDIF
IF DOES_ENTITY_EXIST(sRCLauncherDataLocal.pedID[1])
ASSIGN_PED_INDEX(ctTrapInfo[0].passenger, sRCLauncherDataLocal.pedID[1])
ENDIF
TRUCK_INIT()
// Loop within here until the mission passes or fails
WHILE(TRUE)
REPLAY_CHECK_FOR_EVENT_THIS_FRAME("SF_GRTP")
UPDATE_MISSION_NAME_DISPLAYING(sRCLauncherDataLocal.sIntroCutscene, FALSE, FALSE, TRUE)
DO_CLOCK() // Clock should stay on in fade if it's active, so this lives outside fail stage check
IF mStage = MS_STAGE_FAIL_FADE
STAGE_FAIL_FADE()
ELSE
IF NOT MISSION_FAILED_CHECKS()
// Check debug completion/failure
DEBUG_Check_Debug_Keys()
HANDLE_COPS()
SWITCH mStage
CASE MS_STAGE_INIT
STAGE_INIT()
BREAK
CASE MS_STAGE_CALL_BARRY
STAGE_CALL_BARRY()
BREAK
CASE MS_STAGE_ENTER_TRUCK
STAGE_ENTER_TRUCK()
BREAK
CASE MS_STAGE_RETURN_VEHICLE
STAGE_RETURN_VEHICLE()
BREAK
CASE MS_STAGE_GET_VEHICLE_BACK
STAGE_GET_VEHICLE_BACK()
BREAK
CASE MS_STAGE_LOSE_WANTED
STAGE_LOSE_WANTED()
BREAK
CASE MS_STAGE_DELIVERY
STAGE_DELIVERY()
BREAK
CASE MS_STAGE_LEAVE_AREA
STAGE_LEAVE_AREA()
BREAK
CASE MS_STAGE_TAKE_VEHICLE_BACK
STAGE_TAKE_VEHICLE_BACK()
BREAK
ENDSWITCH
ENDIF
ENDIF
WAIT(0)
ENDWHILE
// Script should never reach here. Always terminate with cleanup function.
ENDSCRIPT