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

3654 lines
121 KiB
Python
Executable File

// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : Fanatic2.sc
// AUTHOR : Kev Edwards (originally)/Ian Gander (June '12 onwards)
// DESCRIPTION : Downhill bike race within a time limit
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//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 "commands_vehicle.sch"
USING "script_player.sch"
USING "randomChar_public.sch"
USING "script_races.sch"
USING "dialogue_public.sch"
USING "shared_hud_displays.sch"
USING "RC_Helper_Functions.sch"
USING "CompletionPercentage_public.sch"
USING "chase_hint_cam.sch" CHASE_HINT_CAM_STRUCT localChaseHintCamStruct
USING "RC_Threat_public.sch"
USING "RC_Setup_public.sch"
USING "initial_scenes_fanatic.sch"
USING "rgeneral_include.sch"
USING "commands_recording.sch"
#IF IS_DEBUG_BUILD
USING "select_mission_stage.sch"
#ENDIF
// Enums
ENUM MISSION_STAGE
stateNULL,
stateInit,
stateIntro,
stateCountdown,
stateRace,
stateOutro,
stateResult,
stateMissionPassed,
stateMissionFailed
ENDENUM
ENUM FAILED_REASON
FAILED_GENERIC = 0,
FAILED_BIKE_DESTROYED,
FAILED_LEFT_BEHIND,
FAILED_WOMAN_DIED,
FAILED_WOMAN_HURT,
FAILED_WOMAN_SCARED,
FAILED_LEFT_BIKE,
FAILED_PUSHED_WOMAN,
FAILED_LOST_RACE,
FAILED_ABANDONED,
FAILED_MISSED_CHECK
ENDENUM
ENUM RACE_LENGTH
RACE_SHORT,
RACE_LONGA,
RACE_LONGB
ENDENUM
ENUM FAN2_CONV_STATE
FAN2_CONV_STATE_FREE,
FAN2_CONV_STATE_START,
FAN2_CONV_STATE_BANTER_PLAYING,
FAN2_CONV_STATE_BANTER_PAUSED,
FAN2_CONV_STATE_PUSHWARNING,
FAN2_CONV_STATE_OVERTAKE,
FAN2_CONV_STATE_ONELINER,
FAN2_CONV_STATE_ROADRAGE,
FAN2_CONV_STATE_TOOFAR,
FAN2_CONV_STATE_END
ENDENUM
ENUM BANTER_STATE
BANTER_WAIT,
BANTER_ACT
ENDENUM
ENUM RECOVER_STATE
RECOVER_WAIT,
RECOVER_NEEDED,
RECOVER_RECOVERING
ENDENUM
RACE_LENGTH raceLength = RACE_LONGA
// Variables etc
MISSION_STAGE missionStage = stateInit // Used to track what mission stage we are at
MISSION_STAGE missionStageSkip = stateNULL
FAILED_REASON failedReason = FAILED_GENERIC
MODEL_NAMES cyclistModel = U_M_Y_CYCLIST_01
FAN2_CONV_STATE ConvState = FAN2_CONV_STATE_START
BANTER_STATE BanterState = BANTER_WAIT
RECOVER_STATE RecoverState = RECOVER_WAIT
INT iRecoverTimer
CONST_INT CP_START 0
CONST_FLOAT MA_CHECKPOINTSIZE 6.0
CONST_INT MARY_ANN_ID 0
CONST_INT MARY_ANN_FRIEND_ID 1
CONST_INT PLAYER_BIKE_ID 0
CONST_INT MARY_ANN_BIKE_ID 1
CONST_INT MAX_CHECKPOINTS 27
CONST_FLOAT START_SPEED 3.5
BOOL bInitStage = TRUE
BOOL bCleanupStage = FALSE
BOOL bDoneMissionSetup = FALSE
BOOL bDebugPrintBikePlaybackSpeed = FALSE
BOOL bDoBikeExit = FALSE
BOOL bDoneTrevExit = FALSE
BOOL bDoneTrevCelebrate = FALSE
BOOL bDoneLeadInConv = FALSE
REL_GROUP_HASH relGroupPlayer
#IF IS_DEBUG_BUILD
CONST_INT MAX_SKIP_MENU_LENGTH 5
MissionStageMenuTextStruct mSkipMenu[MAX_SKIP_MENU_LENGTH]
BOOL bAllowDebugSkipForward = TRUE
BOOL bDebug_PrintToTTY = TRUE
WIDGET_GROUP_ID widgetGroup
#ENDIF
//CAMERA_INDEX camCutscene
INT iCutsceneStage
INT iFailStage = 0
INT iPushTimer
INT iHonkTimer
//INT block_time
INT iFadeTimer
int iClosestWaypoint // Constantly updated with the closest waypoint to Mary Ann
INT iRecoverWaypoint // Used to know which waypoint to recover to
SCENARIO_BLOCKING_INDEX mScenarioBlocker
CONST_INT NUM_BIKES 2
VEHICLE_INDEX vehBike[NUM_BIKES]
BLIP_INDEX blipBike
MODEL_NAMES modelPlayerBike
VECTOR vLongRaceStart[NUM_BIKES]
FLOAT fLongRaceStart[NUM_BIKES]
VECTOR vLongRaceEnd[NUM_BIKES]
FLOAT fLongRaceEnd[NUM_BIKES]
BOOL bPlayerIsOnBike
BLIP_INDEX opponentBlip
CONST_FLOAT LOST_RANGE 230.0
INT start_time
INT finish_time
RACER_INFO_STRUCT playerInfo
RACE_INFO_STRUCT raceInfo
CONST_INT NUM_ROAD_RAGE_CONVERSATIONS 5
structPedsForConversation sRoadRageConversation
STRING sRoadRageConversationString[NUM_ROAD_RAGE_CONVERSATIONS]
BOOL bPlayedRoadRageConversation[NUM_ROAD_RAGE_CONVERSATIONS]
INT iRoadRageConversationsPlayed
int iBanterTimer
int iBanterSequence
CONST_INT NUM_WOMAN_CONVERSATIONS 4
structPedsForConversation sWomanConversation
STRING sWomanConversationString[NUM_WOMAN_CONVERSATIONS]
INT iWomanConversationsPlayed
CONST_INT NUM_WOMAN_BEHIND_ONELINERS 4
int iWomanBehindOnelinersPlayed
CONST_INT NUM_WOMAN_AHEAD_ONELINERS 4
int iWomanAheadOnelinersPlayed
CONST_INT NUM_TREVOR_ONELINERS 6
int iTrevorOnelinersPlayed
CONST_INT NUM_OVERTAKE_LINES 4
INT iOverTakeLinesPlayed
INT iConversationGapTimer
BOOL bDoMaryAnnOneliner
BOOL bOvertakeOccurred = FALSE
INT iOvertakeSpamTimer
BOOL bPlayedStartConv = FALSE
BOOL bPlayedPushConv = FALSE
BOOL bPlayedOvertakeLine = FALSE
BOOL bPlayedBanterOneliner = FALSE
BOOL bStartEndConv = FALSE
structPedsForConversation sOutroConversation
//STRING sOutroConverationString
INT iIntroStage = 0
BOOL bIntroSkipped = FALSE
BOOL bIntroSkippedWhile = FALSE
//BOOL bDoneTrevExit = FALSE
BOOL bUsedSkip = FALSE
BOOL bSkipToEnd = FALSE
BOOL bUsedCheckpoints = FALSE
BOOL bReleaseMAEarly = FALSE
int iCountdown
INT iRacePos
BOOL bFinishedRace
BOOL bLostRace = FALSE
INT iWomanNextCheckpoint
BOOL bDisplayedGetBackOnBike
BOOL bPlayedFinalConv = FALSE
BOOL bFinalConvWinning = FALSE
bool bRoadRagePlaying
BOOL bGivePushWarning
BOOL bStartedCyclist = FALSE
BOOL bStartedDrivers = FALSE
SCENARIO_BLOCKING_INDEX sbiDeerArea
VEHICLE_INDEX viDriver
VEHICLE_INDEX viDriverCop
VEHICLE_INDEX viCyclist
PED_INDEX piDriver
PED_INDEX piDriverCop
PED_INDEX piJogger1
PED_INDEX piJogger2
PED_INDEX piCyclist
BOOL bDoneFailDialogue
SEQUENCE_INDEX seq
FLOAT fHintFov = 30.0
FLOAT fHintFollow = 0.35
FLOAT fHintPitchOrbit = 0.000
FLOAT fHintSide = 0.05
FLOAT fHintVert = -0.050
INT iPushInTimer
//BOOL bDoneFakeCheck = FALSE
//CHECKPOINT_INDEX fakeFirstCheck
// The Random Character - sRCLauncherDataLocal.pedID[MARY_ANN_ID]
g_structRCScriptArgs sRCLauncherDataLocal
//PURPOSE: Print debug string to Rag.
PROC RCM_DEBUG_PRINT(STRING s)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s)
ENDIF
#ENDIF
// Stop release compile error
s = s
ENDPROC
//PURPOSE: Print debug string with int to Rag.
PROC RCM_DEBUG_PRINTINT(STRING s, INT i)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, i)
ENDIF
#ENDIF
// Stop release compile error
s = s
i = i
ENDPROC
//PURPOSE: Print debug string with float to Rag.
PROC RCM_DEBUG_PRINTFLOAT(STRING s, FLOAT f)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, f)
ENDIF
#ENDIF
// Stop release compile error
s = s
f = f
ENDPROC
//PURPOSE: Print debug string with float to Rag.
PROC RCM_DEBUG_PRINTVEC(STRING s, VECTOR v)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, "<<", v, ">>")
ENDIF
#ENDIF
// Stop release compile error
s = s
v = v
ENDPROC
//PURPOSE: Print debug output text for the bike speed to RAG.
PROC RCM_DEBUG_PRINTBIKESPEED(string s1, float f1, string s2, float f2, string s3, float f3)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s1, f1, s2, f2, s3, f3)
ENDIF
#ENDIF
// Stop release compile error
s1 = s1
f1 = f1
s2 = s2
f2 = f2
s3 = s3
f3 = f3
ENDPROC
//PURPOSE: Check whether a particular conversation root is playing.
FUNC BOOL IS_THIS_CONVERSATION_ROOT_PLAYING(STRING RootToCheck)
TEXT_LABEL_23 blah
blah = GET_CURRENTLY_PLAYING_STANDARD_CONVERSATION_ROOT()
IF ARE_STRINGS_EQUAL(blah,RootToCheck)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
//PURPOSE: Checks whether the player has touched any of the flight controls.
//RETURNS: TRUE if any player flight input is detected, FALSE otherwise.
FUNC BOOL HAS_PLAYER_TOUCHED_STEERING_CONTROLS()
IF IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_MOVE_LR)
OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_MOVE_UD) // Leave old inputs, just in case
OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_HANDBRAKE)
OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_DUCK)
OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_JUMP)
OR IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_VEH_BRAKE)
RCM_DEBUG_PRINT("*** Player input detected")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
//PURPOSE: Handles initialising the current missionStage.
FUNC BOOL RCM_INIT_STAGE()
IF bInitStage = TRUE
bInitStage = FALSE
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDFUNC
//PURPOSE: Use anywhere in the current missionStage loop to advance to the next missionStage.
PROC RCM_ADVANCE_STAGE()
bCleanupStage = TRUE
ENDPROC
//PURPOSE: Handles cleaning up the current missionStage, resetting flags and incrementing missionStage.
FUNC BOOL RCM_CLEANUP_STAGE()
IF bCleanupStage = TRUE
CLEAR_HELP(TRUE)
bInitStage = TRUE
bCleanupStage = FALSE
IF missionStageSkip = stateNULL
missionStage = INT_TO_ENUM(MISSION_STAGE, ENUM_TO_INT(missionStage) + 1)
ELSE
missionStage = missionStageSkip
ENDIF
missionStageSkip = stateNULL
RETURN TRUE
ELSE
#IF IS_DEBUG_BUILD
bAllowDebugSkipForward = TRUE
#ENDIF
RETURN FALSE
ENDIF
ENDFUNC
//PURPOSE: Returns true if player ped exists and is alive.
FUNC BOOL RCM_IS_PLAYER_OK()
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
//PURPOSE: Generates the race information prior to the mission starting
PROC RCM_SETUP_RACE_INFO()
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
RCM_DEBUG_PRINT("Setting up race info")
raceInfo.chosenCourse = RACE_COURSE_RC_FANATIC2ALT
GENERATE_RACE_INFO(raceInfo)
ENDPROC
//PURPOSE: Safely remove all blips in this mission.
PROC RCM_REMOVE_ALL_BLIPS()
SAFE_REMOVE_BLIP(blipBike)
SAFE_REMOVE_BLIP(opponentBlip)
ENDPROC
//PURPOSE: Safely spawn a vehicle.
PROC RCM_SPAWN_VEHICLE(VEHICLE_INDEX &vehIndex, MODEL_NAMES eModel, VECTOR vStart, FLOAT fStart = 0.0, INT iColour = -1, FLOAT fDirt = 0.0)
IF NOT DOES_ENTITY_EXIST(vehIndex)
IF HAS_MODEL_LOADED(eModel)
vehIndex = CREATE_VEHICLE(eModel, vStart, fStart)
IF iColour >= 0
SET_VEHICLE_COLOUR_COMBINATION(vehIndex, iColour)
ENDIF
SET_VEHICLE_DIRT_LEVEL(vehIndex, fDirt)
ENDIF
ENDIF
ENDPROC
//PURPOSE: Safely remove all vehicles in this mission.
PROC RCM_REMOVE_ALL_VEHICLES(BOOL bForceDelete = FALSE)
INT i = 0
REPEAT NUM_BIKES i
IF NOT bForceDelete
SAFE_RELEASE_VEHICLE(vehBike[i])
ELSE
SAFE_DELETE_VEHICLE(vehBike[i])
ENDIF
ENDREPEAT
IF NOT bForceDelete
SAFE_RELEASE_VEHICLE(viDriver)
SAFE_RELEASE_VEHICLE(viDriverCop)
SAFE_RELEASE_VEHICLE(viCyclist)
ELSE
SAFE_DELETE_VEHICLE(viDriver)
SAFE_DELETE_VEHICLE(viDriverCop)
SAFE_DELETE_VEHICLE(viCyclist)
ENDIF
RCM_DEBUG_PRINT("Removed all vehicles")
ENDPROC
/// PURPOSE:
/// Removes the checkpoints and blips from the minimap/world
PROC RCM_REMOVE_RACE_BLIPS()
SAFE_REMOVE_BLIP(playerInfo.checkBlip)
DELETE_CHECKPOINT(playerInfo.checkPoint)
SAFE_REMOVE_BLIP(playerInfo.nextCheckBlip)
ENDPROC
//PURPOSE: Safely remove or delete a ped.
PROC RCM_REMOVE_PED(PED_INDEX &ped, BOOL bForceDelete = FALSE)
IF bForceDelete
SAFE_DELETE_PED(ped)
ELSE
SAFE_RELEASE_PED(ped)
ENDIF
ENDPROC
//PURPOSE: Safely remove all peds in this mission.
PROC RCM_REMOVE_ALL_PEDS(BOOL bForceDelete = FALSE)
RCM_REMOVE_PED(sRCLauncherDataLocal.pedID[MARY_ANN_ID], bForceDelete)
RCM_REMOVE_PED(piDriver, bForceDelete)
RCM_REMOVE_PED(piJogger1, bForceDelete)
RCM_REMOVE_PED(piJogger2, bForceDelete)
RCM_REMOVE_PED(piDriverCop, bForceDelete)
RCM_REMOVE_PED(piCyclist, bForceDelete)
RCM_DEBUG_PRINT("Removed all peds")
ENDPROC
/// PURPOSE:
/// Reset the bools and timer for the conversations back to the default state
PROC RCM_RESET_CONVERSATIONS()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
iBanterTimer = GET_GAME_TIMER()
iOvertakeSpamTimer = GET_GAME_TIMER()
iConversationGapTimer = GET_GAME_TIMER()
bOvertakeOccurred = FALSE
bPlayedStartConv = FALSE
bPlayedPushConv = FALSE
bPlayedOvertakeLine = FALSE
bPlayedBanterOneliner = FALSE
bStartEndConv = FALSE
bRoadRagePlaying = FALSE
bGivePushWarning = FALSE
ConvState = FAN2_CONV_STATE_START
BanterState = BANTER_WAIT
iWomanAheadOnelinersPlayed = 0
iWomanBehindOnelinersPlayed = 0
iWomanConversationsPlayed = 0
iTrevorOnelinersPlayed = 0
iBanterSequence = 0
ENDPROC
/// PURPOSE:
/// Cleanup the bools and timer for the conversations so they restart properly, but keep current progress
PROC RCM_CLEANUP_CONVERSATIONS()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
iBanterTimer = GET_GAME_TIMER()
iOvertakeSpamTimer = GET_GAME_TIMER()
iConversationGapTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
bOvertakeOccurred = FALSE
bPlayedStartConv = FALSE
bPlayedPushConv = FALSE
bPlayedOvertakeLine = FALSE
bPlayedBanterOneliner = FALSE
bStartEndConv = FALSE
bRoadRagePlaying = FALSE
bGivePushWarning = FALSE
ENDPROC
/// PURPOSE:
/// Reset the bikes at the start of the race
PROC RESET_BIKES()
RCM_DEBUG_PRINT("Resetting bikes...")
INT i
REPEAT NUM_BIKES i
IF IS_VEHICLE_OK(vehBike[i])
SET_ENTITY_COORDS(vehBike[i], vLongRaceStart[i])
SET_ENTITY_HEADING(vehBike[i], fLongRaceStart[i])
SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[i])
RCM_DEBUG_PRINTINT("Bike exists, set coords/heading: ", i)
// IF i = PLAYER_BIKE_ID
// AND NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
// RCM_DEBUG_PRINT("Putting Trevor on bike...")
// SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
// //TASK_WARP_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID], VS_DRIVER)
// SIMULATE_PLAYER_INPUT_GAIT(PLAYER_ID(), PEDMOVE_RUN)
// ENDIF
ELSE
RCM_SPAWN_VEHICLE(vehBike[i], modelPlayerBike, vLongRaceStart[i], fLongRaceStart[i], i)
RCM_DEBUG_PRINTINT("Bike doesn't exist, recreate: ", i)
SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[i])
IF i = PLAYER_BIKE_ID
AND NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
IF NOT IS_REPLAY_BEING_SET_UP()
RCM_DEBUG_PRINT("Putting Trevor on bike...")
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
//TASK_WARP_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID], VS_DRIVER)
SIMULATE_PLAYER_INPUT_GAIT(PLAYER_ID(), PEDMOVE_RUN)
ENDIF
ELIF i = MARY_ANN_BIKE_ID
IF IS_AUDIO_SCENE_ACTIVE("FANATIC_MIX_SCENE")
ADD_ENTITY_TO_AUDIO_MIX_GROUP(vehBike[MARY_ANN_BIKE_ID],"FANATIC_MIX_MARY_BIKE")
ENDIF
ENDIF
ENDIF
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Resets Mary Ann to the start position on the top of the hill and sets her going. NOT safe, do death checks before this!
PROC RESET_MARY_ANN()
CLEAR_PED_TASKS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF NOT IS_PED_IN_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
SET_PED_INTO_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
ENDIF
IF bIntroSkipped
OR IS_REPLAY_IN_PROGRESS()
// If we've skipped the intro (or retrying after a fail), place Mary Ann ahead a little bit to simulate the delay we otherwise miss
SET_PED_COORDS_KEEP_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], << 845.9933, 1274.4996, 358.8672 >>)
SET_ENTITY_HEADING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], 229.7011)
ELSE
SET_PED_COORDS_KEEP_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], << 831.5367, 1275.3864, 359.3159 >>)
SET_ENTITY_HEADING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], 273.46)
ENDIF
IF NOT IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID], "Fan2_BikeRoute", DRIVINGMODE_AVOIDCARS_RECKLESS,
0, EWAYPOINT_START_FROM_CLOSEST_POINT)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Place Mary Ann's knocked-out friend on the ground
PROC RCM_PLACE_KNOCKED_OUT_FRIEND()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID])
FORCE_PED_MOTION_STATE(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], MS_DO_NOTHING, FALSE, FAUS_DEFAULT)
TASK_PLAY_ANIM(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], "rcm_fanatic2", "ef_2_rcm_cyclist_punched_out", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING|AF_NOT_INTERRUPTABLE)
FLOAT newZ
VECTOR vNewPos
GET_GROUND_Z_FOR_3D_COORD(GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID]), newZ)
vNewPos = GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID])
vNewPos.z = newZ
SAFE_TELEPORT_ENTITY(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], vNewPos, GET_ENTITY_HEADING(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID]))
SET_PED_KEEP_TASK(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], TRUE)
SET_MODEL_AS_NO_LONGER_NEEDED(cyclistModel)
ENDIF
ENDPROC
/// PURPOSE:
/// Stop any conversation is one is ongoing
/// PARAMS:
/// bDoNotFinishLastLine - If true, kill any playing line mid-sentence
PROC RCM_STOP_ANY_ACTIVE_CONVERSATION(BOOL bDoNotFinishLastLine = TRUE)
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF bDoNotFinishLastLine
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
ELSE
KILL_ANY_CONVERSATION()
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Main mission script cleanup
PROC Script_Cleanup()
// Ensure launcher is cleaned up
RC_CLEANUP_LAUNCHER()
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_FACE_TO_FACE_CONVERSATION_DO_NOT_FINISH_LAST_LINE()
ENDIF
#IF IS_DEBUG_BUILD
IF DOES_WIDGET_GROUP_EXIST(widgetGroup)
DELETE_WIDGET_GROUP(widgetGroup)
ENDIF
#ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
MODIFY_VEHICLE_TOP_SPEED(vehBike[MARY_ANN_BIKE_ID], 0.0) // Resets top speed back to default
ENDIF
// If the mission was triggered then additional mission cleanup will be required.
IF (Random_Character_Cleanup_If_Triggered())
PRINTSTRING("...Random Character Script was triggered so additional cleanup required") PRINTNL()
ENDIF
IF IS_AUDIO_SCENE_ACTIVE("FANATIC_MIX_SCENE")
IF DOES_ENTITY_EXIST(vehBike[MARY_ANN_BIKE_ID])
REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(vehBike[MARY_ANN_BIKE_ID])
ENDIF
STOP_AUDIO_SCENE("FANATIC_MIX_SCENE")
ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
TASK_CLEAR_LOOK_AT(PLAYER_PED_ID())
ENDIF
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
TASK_CLEAR_LOOK_AT(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ENDIF
FORCE_RENDER_IN_GAME_UI(FALSE)
REMOVE_PED_FOR_DIALOGUE(sRoadRageConversation, 0)
REMOVE_PED_FOR_DIALOGUE(sWomanConversation, 0)
REMOVE_PED_FOR_DIALOGUE(sWomanConversation, 1)
RCM_REMOVE_RACE_BLIPS()
RCM_REMOVE_ALL_BLIPS()
RCM_REMOVE_ALL_PEDS(FALSE)
RCM_REMOVE_ALL_VEHICLES(FALSE)
SET_ROADS_BACK_TO_ORIGINAL_IN_ANGLED_AREA(<<864.302063,1274.851807,361.473602>>, <<393.978210,1197.083862,224.314072>>, 176.0)
REMOVE_SCENARIO_BLOCKING_AREA(sbiDeerArea)
REMOVE_SCENARIO_BLOCKING_AREA(mScenarioBlocker)
//Cleanup the scene created by the launcher
//RC_CleanupSceneEntities(sRCLauncherDataLocal, FALSE)
TERMINATE_THIS_THREAD()
ENDPROC
PROC Script_Passed()
Random_Character_Passed(CP_RAND_C_FAN2)
ADD_CONTACT_TO_PHONEBOOK(CHAR_MARY_ANN, TREVOR_BOOK)
Script_Cleanup()
ENDPROC
/// PURPOSE:
/// Delete every entity from the world
PROC DeleteEverything()
// Killing any convo since we're going to delete Mary Ann now
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_ANY_CONVERSATION()
ENDIF
SAFE_DELETE_PED(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SAFE_DELETE_PED(piJogger1)
SAFE_DELETE_PED(piJogger2)
SAFE_DELETE_PED(piDriver)
SAFE_DELETE_VEHICLE(viDriver)
SAFE_DELETE_PED(piCyclist)
SAFE_DELETE_VEHICLE(viCyclist)
SAFE_DELETE_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
ENDPROC
/// PURPOSE:
/// Main mission failed fade state
PROC MS_FAILED()
SWITCH iFailStage
CASE 0
RCM_REMOVE_ALL_BLIPS()
RCM_REMOVE_RACE_BLIPS()
RCM_STOP_ANY_ACTIVE_CONVERSATION()
CLEAR_PRINTS()
// set if there is any fail dialogue to play
bDoneFailDialogue = TRUE
IF failedReason = FAILED_WOMAN_SCARED
bDoneFailDialogue = FALSE
ENDIF
STRING sFailReason
SWITCH failedReason
CASE FAILED_GENERIC
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_GENERIC")
BREAK
CASE FAILED_BIKE_DESTROYED
sFailReason = "FAN2_F1" // ~r~The bike was destroyed.
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_BIKE_DESTROYED")
BREAK
CASE FAILED_LEFT_BEHIND
sFailReason = "FAN2_F2" // ~r~You fell too far behind.
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_OUT_OF_TIME")
BREAK
CASE FAILED_WOMAN_DIED
sFailReason = "FAN2_F3" // ~r~Mary Ann died.
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_WOMAN_DIED")
BREAK
CASE FAILED_WOMAN_HURT
sFailReason = "FAN2_F4" // ~r~Mary Ann was hurt.
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_WOMAN_HURT")
BREAK
CASE FAILED_WOMAN_SCARED
sFailReason = "FAN2_F5" // ~r~Mary Ann was scared off.
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_WOMAN_SCARED")
BREAK
CASE FAILED_LEFT_BIKE
sFailReason = "FAN2_F6" // ~r~You wandered too far from the bike.
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_LEFT_BIKE")
BREAK
CASE FAILED_PUSHED_WOMAN
sFailReason = "FAN2_F7" // ~r~You pushed Mary Ann.
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_PUSHED_WOMAN")
BREAK
CASE FAILED_LOST_RACE
sFailReason = "FAN2_F8" // ~r~You lost the race.
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_LOST_RACE")
BREAK
CASE FAILED_ABANDONED
sFailReason = "FAN2_F9" // ~r~You abandoned the race.
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_ABANDONED_RACE")
BREAK
CASE FAILED_MISSED_CHECK
sFailReason = "FAN2_F10" // ~r~A checkpoint was missed.
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("MISSION_FAILED reason=FAILED_ABANDONED_RACE")
BREAK
ENDSWITCH
IF failedReason = FAILED_GENERIC
Random_Character_Failed()
ELSE
Random_Character_Failed_With_Reason(sFailReason)
ENDIF
iFailStage = 1
BREAK
CASE 1
IF GET_MISSION_FLOW_SAFE_TO_CLEANUP()
// 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(<< 822.7919, 1278.0978, 359.4304 >>, 105.0195)
//SET_REPLAY_DECLINED_VEHICLE_WARP_LOCATION(<<823.432, 1280.526, 359.923>>, -90.133)
DeleteEverything()
Script_Cleanup()
ELSE
// not finished fading out
// you may want to handle dialogue etc here.
IF bDoneFailDialogue = FALSE
IF failedReason = FAILED_WOMAN_SCARED
bDoneFailDialogue = CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_SCARED", CONV_PRIORITY_HIGH, DO_NOT_DISPLAY_SUBTITLES)
ENDIF
ENDIF
ENDIF
BREAK
ENDSWITCH
ENDPROC
//PURPOSE: Mission is failed.
PROC RCM_MISSION_FAILED(FAILED_REASON reason = FAILED_GENERIC)
TRIGGER_MUSIC_EVENT("FANATIC2_FAIL")
failedReason = reason
missionStage = stateMissionFailed
ENDPROC
//PURPOSE: Set up mission prior to going into any mission states
PROC RCM_MISSION_SETUP()
RCM_DEBUG_PRINT("MISSION_SETUP")
REQUEST_ADDITIONAL_TEXT("FATIC2", MISSION_TEXT_SLOT)
WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
RCM_DEBUG_PRINT("Loading text")
WAIT(0)
ENDWHILE
#IF IS_DEBUG_BUILD
mSkipMenu[0].sTxtLabel = "Intro"
mSkipMenu[1].sTxtLabel = "Race start"
mSkipMenu[2].sTxtLabel = "Skip to checkpoint 11"
mSkipMenu[3].sTxtLabel = "Skip to checkpoint 22"
mSkipMenu[4].sTxtLabel = "End race"
#ENDIF
bStartedCyclist = FALSE
modelPlayerBike = SCORCHER
sRoadRageConversationString[0] = "FAN2_RANT1"
sRoadRageConversationString[1] = "FAN2_RANT2"
sRoadRageConversationString[2] = "FAN2_RANT3"
sRoadRageConversationString[3] = "FAN2_RANT4"
sRoadRageConversationString[4] = "FAN2_RANT5"
sWomanConversationString[0] = "FAN2_FEM1"
// There's not normally enough time to play the 4th conversation - so swap the order of FEM3 and FEM4 around if it's a replay so there's a chance to hear FEM4
IF IS_REPLAY_IN_PROGRESS()
IF IS_OUTFIT_SUITABLE_FOR_FANATIC_MISSION(2)
sWomanConversationString[2] = "FAN2_FEM4B"
ELSE
sWomanConversationString[2] = "FAN2_FEM4A"
ENDIF
sWomanConversationString[3] = "FAN2_FEM3"
ELSE
IF IS_OUTFIT_SUITABLE_FOR_FANATIC_MISSION(2)
sWomanConversationString[3] = "FAN2_FEM4B"
ELSE
sWomanConversationString[3] = "FAN2_FEM4A"
ENDIF
sWomanConversationString[2] = "FAN2_FEM3"
ENDIF
// Set up specific dialogue if the player's in the right outfit
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF IS_OUTFIT_SUITABLE_FOR_FANATIC_MISSION(2)
sWomanConversationString[1] = "FAN2_FEM2B"
ELSE
sWomanConversationString[1] = "FAN2_FEM2A"
ENDIF
ENDIF
vLongRaceStart[0] = << 808.8217, 1276.9392, 359.4989 >>
fLongRaceStart[0] = 261.78
vLongRaceStart[1] = << 820.96, 1274.52, 359.47 >>
fLongRaceStart[1] = 268.5713
vLongRaceEnd[0] = << 280.9698, 948.4752, 209.7963 >>
fLongRaceEnd[0] = 167.6198
vLongRaceEnd[1] = << 284.93, 968.38, 210.09 >>
fLongRaceEnd[1] = 167.6198
SET_ROADS_IN_ANGLED_AREA(<<864.302063,1274.851807,361.473602>>, <<393.978210,1197.083862,224.314072>>, 176.0, FALSE, FALSE)
sbiDeerArea = ADD_SCENARIO_BLOCKING_AREA(<<379.31, 1017.51, 218.82>>, <<419.57, 1062.59, 247.17>>)
RCM_DEBUG_PRINT("Finished mission setup.")
ENDPROC
//PURPOSE: Check if all the assets for the required mission stage have been loaded.
FUNC BOOL HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(MISSION_STAGE currentStage)
BOOL bAssetsLoaded = FALSE
SWITCH currentStage
CASE stateIntro
REQUEST_MODEL(modelPlayerBike)
REQUEST_MODEL(cyclistModel)
IF HAS_MODEL_LOADED(modelPlayerBike)
AND HAS_MODEL_LOADED(cyclistModel)
RCM_DEBUG_PRINT("All assets loaded.")
bAssetsLoaded = TRUE
ELSE
RCM_DEBUG_PRINT("Still loading assets.")
ENDIF
BREAK
CASE stateCountdown
REQUEST_MODEL(modelPlayerBike)
REQUEST_MODEL(TRIBIKE)
REQUEST_MODEL(S_M_Y_Cop_01)
REQUEST_MODEL(A_F_Y_Runner_01)
REQUEST_MODEL(A_M_Y_Runner_01)
REQUEST_WAYPOINT_RECORDING("Fan2_BikeRoute")
REQUEST_VEHICLE_RECORDING(500, "Fan2_Cyclist")
REQUEST_WAYPOINT_RECORDING("Fan2_Jogger1")
REQUEST_WAYPOINT_RECORDING("Fan2_Jogger2")
REQUEST_ANIM_DICT("rcm_fanatic2")
REQUEST_ANIM_DICT("rcmfanatic2")
IF HAS_VEHICLE_RECORDING_BEEN_LOADED(500, "Fan2_Cyclist")
AND GET_IS_WAYPOINT_RECORDING_LOADED("Fan2_BikeRoute")
AND GET_IS_WAYPOINT_RECORDING_LOADED("Fan2_Jogger1")
AND GET_IS_WAYPOINT_RECORDING_LOADED("Fan2_Jogger2")
and HAS_MODEL_LOADED(modelPlayerBike)
and HAS_MODEL_LOADED(TRIBIKE)
and HAS_MODEL_LOADED(S_M_Y_Cop_01)
and HAS_MODEL_LOADED(A_F_Y_Runner_01)
and HAS_MODEL_LOADED(A_M_Y_Runner_01)
AND HAS_ANIM_DICT_LOADED("rcm_fanatic2")
AND HAS_ANIM_DICT_LOADED("rcmfanatic2")
bAssetsLoaded = TRUE
ELSE
RCM_DEBUG_PRINT("Still loading assets.")
ENDIF
BREAK
ENDSWITCH
RETURN bAssetsLoaded
ENDFUNC
/// PURPOSE:
/// Jump to a particular point during the race
/// PARAMS:
/// iStage - The stage of the race we wish to jump to
PROC JUMP_TO_STAGE(int iStage)
RC_START_Z_SKIP()
RCM_DEBUG_PRINTINT("Jumping to stage: ", iStage)
RecoverState = RECOVER_WAIT // Reset just in case
IF iStage = 0
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 1
playerInfo.nextCheck = 2
missionStageSkip = stateInit
IF IS_ENTITY_ALIVE(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
CLEAR_PED_TASKS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ENDIF
ENDIF
TRIGGER_MUSIC_EVENT("FANATIC2_STOP")
RCM_DEBUG_PRINT("Doing music trigger stop")
IF IS_AUDIO_SCENE_ACTIVE("FANATIC_MIX_SCENE")
REMOVE_ENTITY_FROM_AUDIO_MIX_GROUP(vehBike[MARY_ANN_BIKE_ID])
STOP_AUDIO_SCENE("FANATIC_MIX_SCENE")
ENDIF
RCM_DEBUG_PRINT("Reset bikes from JUMP_TO_STAGE(0)")
RCM_RESET_CONVERSATIONS()
RESET_BIKES()
SET_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
bStartedCyclist = FALSE
bDoBikeExit = FALSE
RCM_ADVANCE_STAGE()
ELIF iStage = 1
RCM_DEBUG_PRINT("Reset bikes from JUMP_TO_STAGE(1)")
RESET_BIKES()
raceInfo.sourcePos = vLongRaceStart[0]
raceInfo.sourceHeading = fLongRaceStart[0]
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 1
playerInfo.nextCheck = 2
missionStageSkip = stateCountdown
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateCountdown)
WAIT(0) //Load in race assets now before skipping ahead
ENDWHILE
WHILE IS_CUTSCENE_ACTIVE()
STOP_CUTSCENE()
WAIT(0)
ENDWHILE
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
RCM_DEBUG_PRINT("Putting Trevor on bike...")
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
ENDIF
RCM_PLACE_KNOCKED_OUT_FRIEND()
RCM_RESET_CONVERSATIONS()
IF IS_ENTITY_ALIVE(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RESET_MARY_ANN()
ENDIF
SET_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
bStartedCyclist = FALSE
RCM_ADVANCE_STAGE()
ELIF iStage = 2
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 11
playerInfo.nextCheck = 12
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateCountdown)
WAIT(0) //Load in race assets now before skipping ahead
ENDWHILE
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_PED_COORDS_KEEP_VEHICLE(PLAYER_PED_ID(), << 438.3714, 1292.8068, 269.9339 >>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 24)
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF NOT IS_PED_IN_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
SET_PED_INTO_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
ENDIF
SET_PED_COORDS_KEEP_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], << 449.6093, 1261.4745, 272.4526 >>)
SET_ENTITY_HEADING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], 13.4976)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID], "Fan2_BikeRoute", DRIVINGMODE_AVOIDCARS_RECKLESS,
0, EWAYPOINT_START_FROM_CLOSEST_POINT)
ENDIF
ENDIF
RCM_CLEANUP_CONVERSATIONS()
SET_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
bStartedCyclist = FALSE
iWomanNextCheckpoint = 12
ELIF iStage = 3
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 22
playerInfo.nextCheck = 23
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateCountdown)
WAIT(0) //Load in race assets now before skipping ahead
ENDWHILE
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_PED_COORDS_KEEP_VEHICLE(PLAYER_PED_ID(), << 272.8283, 1261.0051, 232.5672 >>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 122.43)
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF NOT IS_PED_IN_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
SET_PED_INTO_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
ENDIF
SET_PED_COORDS_KEEP_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], << 295.4509, 1244.0754, 233.5478 >>)
SET_ENTITY_HEADING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], 43.0307)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID], "Fan2_BikeRoute", DRIVINGMODE_AVOIDCARS_RECKLESS,
0, EWAYPOINT_START_FROM_CLOSEST_POINT)
ENDIF
ENDIF
RCM_CLEANUP_CONVERSATIONS()
SET_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
iWomanNextCheckpoint = 23
ELIF iStage = 4
IF IS_ENTITY_ALIVE(vehBike[MARY_ANN_BIKE_ID])
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
CLEAR_PED_TASKS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ENDIF
ENDIF
INT i
REPEAT NUM_BIKES i
IF IS_VEHICLE_OK(vehBike[i])
SET_ENTITY_COORDS(vehBike[i], vLongRaceEnd[i])
SET_ENTITY_HEADING(vehBike[i], fLongRaceEnd[i])
SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[i])
RCM_DEBUG_PRINTINT("Bike exists, set coords/heading: ", i)
ELSE
RCM_SPAWN_VEHICLE(vehBike[i], modelPlayerBike, vLongRaceEnd[i], fLongRaceEnd[i], i)
SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[i])
RCM_DEBUG_PRINTINT("Bike doesn't exist, recreate: ", i)
ENDIF
ENDREPEAT
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
AND IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
ENDIF
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
CLEAR_PED_TASKS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF NOT IS_PED_IN_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
SET_PED_INTO_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
ENDIF
ENDIF
missionStageSkip = stateOutro
bSkipToEnd = TRUE
WAIT(1000)
RCM_ADVANCE_STAGE()
ENDIF
ENDPROC
//PURPOSE: Deal with stage skipping forwards to a later point in the race.
PROC Script_SkipStageForward()
SWITCH missionStage
CASE stateIntro
WHILE IS_CUTSCENE_ACTIVE()
STOP_CUTSCENE()
WAIT(0)
ENDWHILE
JUMP_TO_STAGE(1)
BREAK
CASE stateRace
IF playerInfo.currentCheck < 11
JUMP_TO_STAGE(2)
ELIF playerInfo.currentCheck < 22
JUMP_TO_STAGE(3)
ELSE
JUMP_TO_STAGE(4)
ENDIF
BREAK
ENDSWITCH
ENDPROC
//PURPOSE: Deal with stage skipping back to an earlier point in the race.
PROC Script_SkipStageBack()
SWITCH missionStage
CASE stateRace
IF playerInfo.currentCheck > 23
JUMP_TO_STAGE(3)
ELIF playerInfo.currentCheck > 12
JUMP_TO_STAGE(2)
ELIF playerInfo.currentCheck > 2
JUMP_TO_STAGE(1)
ELSE
JUMP_TO_STAGE(0)
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Handles whether the player needs to see the global stamina help message low on stamina. B*1416022.
PROC HANDLE_GLOBAL_STAMINA_HELP()
IF NOT g_savedGlobals.sRandomChars.g_bFanaticStamina
IF GET_PLAYER_SPRINT_TIME_REMAINING(PLAYER_ID()) <= 5.0
IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
PRINT_HELP("AM_H_NOSTAM")
g_savedGlobals.sRandomChars.g_bFanaticStamina = TRUE
ENDIF
ENDIF
ENDIF
ENDPROC
//PURPOSE: Death checks for any mission critical entities.
PROC RCM_DEATH_CHECKS()
IF missionStage = stateRace
IF NOT IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
RCM_MISSION_FAILED(FAILED_BIKE_DESTROYED)
ENDIF
ENDIF
IF NOT bReleaseMAEarly
// If the player wins by a large margin, we delete Mary Ann from the mission to simulate her being so far away she's just given up
// If we do that, we set this bool to true so the mission doesn't fail for Mary Ann being "dead" while Trevor's line is playing
IF NOT IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RCM_MISSION_FAILED(FAILED_WOMAN_DIED)
ENDIF
ENDIF
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PLAYER_PED_ID())
IF HAS_PED_BEEN_DAMAGED_BY_WEAPON(sRCLauncherDataLocal.pedID[MARY_ANN_ID], WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
if HAS_PLAYER_THREATENED_PED(piJogger1) OR HAS_PLAYER_THREATENED_PED(piJogger2)
IF IS_PED_UNINJURED(piJogger1) AND IS_PED_UNINJURED(piJogger2)
TASK_SMART_FLEE_PED(piJogger1, PLAYER_PED_ID(), 100, -1)
TASK_SMART_FLEE_PED(piJogger2, PLAYER_PED_ID(), 100, -1)
ENDIF
SAFE_RELEASE_PED(piJogger1)
SAFE_RELEASE_PED(piJogger2)
ENDIF
RCM_MISSION_FAILED(FAILED_WOMAN_HURT)
ENDIF
ENDIF
ENDIF
if IS_PLAYER_SHOOTING_NEAR_PED(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
//CLEAR_PED_TASKS_IMMEDIATELY(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_PED_KEEP_TASK(sRCLauncherDataLocal.pedID[MARY_ANN_ID], true)
SET_PED_FLEE_ATTRIBUTES(sRCLauncherDataLocal.pedID[MARY_ANN_ID], FA_USE_VEHICLE, TRUE)
TASK_SMART_FLEE_PED(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PLAYER_PED_ID(), 100, -1)
if HAS_PLAYER_THREATENED_PED(piJogger1) OR HAS_PLAYER_THREATENED_PED(piJogger2)
IF IS_PED_UNINJURED(piJogger1) AND IS_PED_UNINJURED(piJogger2)
TASK_SMART_FLEE_PED(piJogger1, PLAYER_PED_ID(), 100, -1)
TASK_SMART_FLEE_PED(piJogger2, PLAYER_PED_ID(), 100, -1)
ENDIF
SAFE_RELEASE_PED(piJogger1)
SAFE_RELEASE_PED(piJogger2)
ENDIF
RCM_MISSION_FAILED(FAILED_WOMAN_SCARED)
ENDIF
ENDPROC
//PURPOSE: Check for Forced Pass or Fail
PROC DEBUG_Check_Debug_Keys()
#IF IS_DEBUG_BUILD
IF missionStage <> stateMissionFailed
// Check for Pass
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S))
WAIT_FOR_CUTSCENE_TO_STOP()
CLEAR_PRINTS()
TRIGGER_MUSIC_EVENT("FANATIC2_STOP")
RCM_DEBUG_PRINT("Doing music trigger stop")
Script_Passed()
ENDIF
// Check for Fail
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F))
WAIT_FOR_CUTSCENE_TO_STOP()
CLEAR_PRINTS()
RCM_MISSION_FAILED()
ENDIF
// Check for Skips
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J))
IF bAllowDebugSkipForward = TRUE
bUsedSkip = TRUE
bUsedCheckpoints = TRUE
Script_SkipStageForward()
ENDIF
ENDIF
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_P))
bUsedSkip = TRUE
bUsedCheckpoints = TRUE
bPlayedFinalConv = FALSE
Script_SkipStageBack()
ENDIF
INT iNewStage
IF LAUNCH_MISSION_STAGE_MENU(mSkipMenu, iNewStage)
bUsedSkip = TRUE
bUsedCheckpoints = TRUE
RCM_DEBUG_PRINT("Doing z-skip!")
JUMP_TO_STAGE(iNewStage)
ENDIF
ENDIF
#ENDIF
ENDPROC
/// PURPOSE:
/// Run the intro cutscene
PROC RUN_CUTSCENE()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], "Mary_Ann", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
//SET_PED_COMPONENT_VARIATION(sRCLauncherDataLocal.pedID[MARY_ANN_ID], INT_TO_ENUM(PED_COMPONENT, 4), 1, 0)
ENDIF
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID])
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], "MaryAnnes_Friend", CU_ANIMATE_EXISTING_SCRIPT_ENTITY, A_M_Y_CYCLIST_01)
ELSE
sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID] = CREATE_PED(PEDTYPE_MISSION, cyclistModel, <<808.43, 1279.16, 360.48>>, -79.11)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], TRUE)
SET_PED_COMPONENT_VARIATION(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], PED_COMP_TORSO, 1, 2)
SET_PED_COMPONENT_VARIATION(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], PED_COMP_LEG, 1, 0)
SET_PED_PROP_INDEX(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], ANCHOR_HEAD, 0)
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[MARY_ANN_FRIEND_ID], "MaryAnnes_Friend", CU_ANIMATE_EXISTING_SCRIPT_ENTITY, A_M_Y_CYCLIST_01)
ENDIF
IF DOES_OBJECT_OF_TYPE_EXIST_AT_COORDS(<<801.714844,1270.138306,359.285522>>, 6.0, prop_facgate_03_l)
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(prop_facgate_03_l, <<801.714844,1270.138306,359.285522>>, TRUE, 0.0)
RCM_DEBUG_PRINT("Fanatic2: Gate 1 Closed")
ENDIF
IF DOES_OBJECT_OF_TYPE_EXIST_AT_COORDS(<<802.919495, 1280.919678, 360.727234>>, 6.0, prop_facgate_03_r)
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(prop_facgate_03_r, <<802.919495, 1280.919678, 360.727234>>, TRUE, 0.0)
RCM_DEBUG_PRINT("Fanatic2:Gate 2 Closed")
ENDIF
// Clear area here instead of mission init, otherwise taxi might get cleared (B*1980643)
CLEAR_ANGLED_AREA_OF_VEHICLES(<<864.302063,1274.851807,361.473602>>, <<393.978210,1197.083862,224.314072>>, 176.0)
CLEAR_ANGLED_AREA_OF_VEHICLES(<<878.295532,1291.727783,355.536591>>, <<817.823486,1271.438599,362.973633>>, 12.75)
INT i = 0
REPEAT NUM_BIKES i
RCM_SPAWN_VEHICLE(vehBike[i], modelPlayerBike, vLongRaceStart[i], fLongRaceStart[i], i)
IF IS_VEHICLE_OK(vehBike[i])
IF i = 0
// SET_ENTITY_COORDS(vehBike[PLAYER_BIKE_ID], <<808.35, 1277.20, 360.15>>)
// SET_ENTITY_HEADING(vehBike[PLAYER_BIKE_ID], 216.50)
// SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[PLAYER_BIKE_ID])
REGISTER_ENTITY_FOR_CUTSCENE(vehBike[PLAYER_BIKE_ID], "Players_Bike", CU_ANIMATE_EXISTING_SCRIPT_ENTITY, DUMMY_MODEL_FOR_SCRIPT, CEO_IS_CASCADE_SHADOW_FOCUS_ENTITY_DURING_EXIT)
ELSE
// SET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID], <<807.89, 1275.73, 360.18>>)
// SET_ENTITY_HEADING(vehBike[MARY_ANN_BIKE_ID], 208.20)
// SET_VEHICLE_ON_GROUND_PROPERLY(vehBike[MARY_ANN_BIKE_ID])
REGISTER_ENTITY_FOR_CUTSCENE(vehBike[MARY_ANN_BIKE_ID], "MaryAnnes_Bike", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
ENDIF
ENDREPEAT
bIntroSkipped = FALSE // Reset tracking bool
RC_CLEANUP_LAUNCHER()
START_CUTSCENE(CUTSCENE_PLAYER_EXITS_IN_A_VEHICLE)
SET_VEHICLE_MODEL_PLAYER_WILL_EXIT_SCENE(modelPlayerBike)
WAIT(0)
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT(<<803.136292,1275.784546,357.813049>>, <<862.741150,1287.390747,365.551422>>, 40.75,
<< 836.74, 1284.85, 359.59 >>, 102.86, GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR())
RC_START_CUTSCENE_MODE(<< 807.57, 1275.24, 359.47 >>, TRUE, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
RCM_DEBUG_PRINT("Starting cutscene...")
ENDPROC
/// PURPOSE:
/// Main initialisation stage for the mission
PROC MS_INIT()
IF RCM_INIT_STAGE()
RCM_DEBUG_PRINT("Init MS_INIT")
#IF IS_DEBUG_BUILD
IF NOT DOES_WIDGET_GROUP_EXIST(widgetGroup)
widgetGroup= START_WIDGET_GROUP("Fanatic 2 widgets")
ADD_WIDGET_BOOL("TTY Toggle - Print Mission Debug Info", bDebug_PrintToTTY)
ADD_WIDGET_BOOL("Opponent bike speed debug", bDebugPrintBikePlaybackSpeed)
STOP_WIDGET_GROUP()
ENDIF
#ENDIF
IF Is_Replay_In_Progress()
START_REPLAY_SETUP(<<815.2971, 1277.6364, 359.4897>>, 274.5829)
ELSE
IF NOT IS_GAMEPLAY_HINT_ACTIVE()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_GAMEPLAY_ENTITY_HINT(sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<0,0,0>>, TRUE, 30000)
SET_GAMEPLAY_HINT_FOV(fHintFov)
SET_GAMEPLAY_HINT_FOLLOW_DISTANCE_SCALAR(fHintFollow)
SET_GAMEPLAY_HINT_BASE_ORBIT_PITCH_OFFSET(fHintPitchOrbit)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_SIDE_OFFSET(fHintSide)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_VERTICAL_OFFSET(fHintVert)
SET_GAMEPLAY_HINT_CAMERA_BLEND_TO_FOLLOW_PED_MEDIUM_VIEW_MODE(TRUE)
iPushInTimer = GET_GAME_TIMER()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
TASK_FOLLOW_TO_OFFSET_OF_ENTITY(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<0,0,0>>, PEDMOVEBLENDRATIO_WALK)
ENDIF
ENDIF
ELSE
STOP_GAMEPLAY_HINT_BEING_CANCELLED_THIS_UPDATE(TRUE)
ENDIF
ENDIF
IF bDoneMissionSetup = FALSE
RCM_MISSION_SETUP()
ENDIF
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateIntro)
WAIT(0)
ENDWHILE
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_PED_RELATIONSHIP_GROUP_HASH(sRCLauncherDataLocal.pedID[MARY_ANN_ID], relGroupPlayer)
SET_PED_CONFIG_FLAG(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PCF_KeepRelationshipGroupAfterCleanUp, TRUE)
ENDIF
ADD_PED_FOR_DIALOGUE(sRoadRageConversation, ENUM_TO_INT(CHAR_TREVOR), PLAYER_PED_ID(), "TREVOR")
ADD_PED_FOR_DIALOGUE(sWomanConversation, ENUM_TO_INT(CHAR_TREVOR), PLAYER_PED_ID(), "TREVOR")
ADD_PED_FOR_DIALOGUE(sWomanConversation, 3, sRCLauncherDataLocal.pedID[MARY_ANN_ID], "MARYANN")
ADD_PED_FOR_DIALOGUE(sOutroConversation, ENUM_TO_INT(CHAR_TREVOR), PLAYER_PED_ID(), "TREVOR")
ADD_PED_FOR_DIALOGUE(sOutroConversation, 3, sRCLauncherDataLocal.pedID[MARY_ANN_ID], "MARYANN")
RCM_DEBUG_PRINT("Running MS_INIT")
ELSE
IF NOT Is_Replay_In_Progress()
OR bUsedCheckpoints = TRUE
IF NOT IS_GAMEPLAY_HINT_ACTIVE()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_GAMEPLAY_ENTITY_HINT(sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<0,0,0>>, TRUE, 30000)
SET_GAMEPLAY_HINT_FOV(fHintFov)
SET_GAMEPLAY_HINT_FOLLOW_DISTANCE_SCALAR(fHintFollow)
SET_GAMEPLAY_HINT_BASE_ORBIT_PITCH_OFFSET(fHintPitchOrbit)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_SIDE_OFFSET(fHintSide)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_VERTICAL_OFFSET(fHintVert)
SET_GAMEPLAY_HINT_CAMERA_BLEND_TO_FOLLOW_PED_MEDIUM_VIEW_MODE(TRUE)
iPushInTimer = GET_GAME_TIMER()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
TASK_FOLLOW_TO_OFFSET_OF_ENTITY(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<0,0,0>>, PEDMOVEBLENDRATIO_WALK)
ENDIF
ENDIF
ELSE
STOP_GAMEPLAY_HINT_BEING_CANCELLED_THIS_UPDATE(TRUE)
ENDIF
IF NOT HAS_CUTSCENE_LOADED()
RC_REQUEST_CUTSCENE("ef_2_rcm")
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
RCM_DEBUG_PRINT("Trying to set Mary Ann component variation")
SET_CUTSCENE_PED_COMPONENT_VARIATION_FROM_PED("Mary_Ann", sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ENDIF
RCM_DEBUG_PRINT("Requesting cutscene...")
ELSE
IF (GET_GAME_TIMER() - iPushInTimer) > 3000
RCM_DEBUG_PRINT("Cutscene loaded & timer expired, moving on...")
RCM_ADVANCE_STAGE()
ELSE
RCM_DEBUG_PRINT("Waiting for focus push timer...")
IF iPushInTimer > 1000
IF NOT bDoneLeadInConv
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_AMB", CONV_PRIORITY_MEDIUM)
bDoneLeadInConv = TRUE
ENDIF
ENDIF
ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARY_ANN_ID]) < 6.0
RCM_DEBUG_PRINT("Trevor got too close to Mary Ann, breaking out of focus push and playing intro")
RCM_ADVANCE_STAGE()
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
RCM_DEBUG_PRINT("Replay detected, skipping cutscene init...")
// Clear area here instead of mission init, otherwise taxi might get cleared (B*1980643)
CLEAR_ANGLED_AREA_OF_VEHICLES(<<864.302063,1274.851807,361.473602>>, <<393.978210,1197.083862,224.314072>>, 176.0)
CLEAR_ANGLED_AREA_OF_VEHICLES(<<878.295532,1291.727783,355.536591>>, <<817.823486,1271.438599,362.973633>>, 12.75)
RCM_ADVANCE_STAGE()
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RCM_DEBUG_PRINT("Cleaned up MS_INIT")
ENDIF
ENDPROC
/// PURPOSE:
/// Do Mary Ann's exit actions when the cutscene ends
PROC DO_MARY_ANN_EXIT()
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Mary_Ann", IG_MARYANN)
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RCM_DEBUG_PRINT("Setting exit state for Mary Ann")
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
RESET_MARY_ANN()
FORCE_PED_MOTION_STATE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], MS_DO_NOTHING, FALSE, FAUS_CUTSCENE_EXIT)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Do Trevor's exit actions when the cutscene ends
FUNC BOOL DO_TREVOR_EXIT()
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Trevor")
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
RCM_DEBUG_PRINT("Setting exit state for Trevor")
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
RCM_DEBUG_PRINT("Putting Trevor on bike")
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
//TASK_WARP_PED_INTO_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID], VS_DRIVER)
ENDIF
IF bIntroSkipped
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
ENDIF
bDoneTrevExit = TRUE
SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_PreventGoingIntoStillInVehicleState, TRUE)
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_DO_NOTHING, FALSE, FAUS_CUTSCENE_EXIT)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Do the bike actions for exiting the cutscene (also from a replay when the cutscene isn't active)
PROC DO_BIKE_EXIT()
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Players_Bike")
RCM_DEBUG_PRINT("Setting exit state for bike")
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
AND IS_ENTITY_ALIVE(PLAYER_PED_ID())
RCM_DEBUG_PRINTFLOAT("Bike speed on exit: ", GET_ENTITY_SPEED(vehBike[PLAYER_BIKE_ID]))
bDoBikeExit = TRUE
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
// IF HAS_VEHICLE_RECORDING_BEEN_LOADED(500, "Fan2_TrevExitRec")
// AND NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[PLAYER_BIKE_ID])
// //AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(),vehBike[PLAYER_BIKE_ID])
// RCM_DEBUG_PRINT("Doing bike exit playback")
// START_PLAYBACK_RECORDED_VEHICLE(vehBike[PLAYER_BIKE_ID], 500, "Fan2_TrevExitRec")
// FORCE_PLAYBACK_RECORDED_VEHICLE_UPDATE(vehBike[PLAYER_BIKE_ID])
// ENDIF
ENDIF
ENDIF
ENDPROC
PROC CHECK_EXIT_STATES()
DO_MARY_ANN_EXIT()
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("MaryAnnes_Friend")
// Set friend in knocked out pose here when available - until then, delete
RCM_PLACE_KNOCKED_OUT_FRIEND()
ENDIF
DO_BIKE_EXIT()
ENDPROC
/// PURPOSE:
/// Main loop for the intro cutscene stage
PROC MS_INTRO()
INT i = 0
IF RCM_INIT_STAGE()
RCM_DEBUG_PRINT("Init MS_INTRO")
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateIntro)
WAIT(0)
ENDWHILE
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)
TASK_LEAVE_ANY_VEHICLE(PLAYER_PED_ID(), DEFAULT, ECF_DONT_WAIT_FOR_VEHICLE_TO_STOP|ECF_WARP_PED)
ENDIF
iIntroStage = 0
bIntroSkipped = FALSE
bIntroSkippedWhile = FALSE
bUsedSkip = FALSE
// bDoneTrevExit = FALSE
SET_CUTSCENE_FADE_VALUES(FALSE, FALSE, FALSE, FALSE) // Reset to default when skipping back to the intro
IF NOT Is_Replay_In_Progress()
OR bUsedCheckpoints = TRUE
WHILE NOT RC_IS_CUTSCENE_OK_TO_START()
WAIT(0)
ENDWHILE
raceInfo.sourcePos = vLongRaceStart[0]
raceInfo.sourceHeading = fLongRaceStart[0]
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 1
playerInfo.nextCheck = 2
RCM_SETUP_RACE_INFO()
FORCE_RENDER_IN_GAME_UI(TRUE)
RUN_CUTSCENE()
REPLAY_START_EVENT(REPLAY_IMPORTANCE_LOW)
STOP_GAMEPLAY_HINT()
ENDIF
RCM_DEBUG_PRINT("Running MS_INTRO")
ELSE
HIDE_STREET_AND_CAR_NAMES_THIS_FRAME()
IF Is_Replay_In_Progress()
AND bUsedCheckpoints = FALSE
RCM_DEBUG_PRINT("Replay detected, skipping Intro state...")
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateCountdown)
WAIT(0) //Load in race assets now before skipping ahead
ENDWHILE
bUsedSkip = TRUE
// Generate the bikes now so we can use them for setting up the race infO
RCM_DEBUG_PRINT("Reset bikes from MS_INTRO skip")
RESET_BIKES()
raceInfo.sourcePos = vLongRaceStart[0]
raceInfo.sourceHeading = fLongRaceStart[0]
playerInfo.raceVehicle = vehBike[PLAYER_BIKE_ID]
playerInfo.racer = PLAYER_PED_ID()
playerInfo.currentCheck = 1
playerInfo.nextCheck = 2
RCM_SETUP_RACE_INFO()
RCM_PLACE_KNOCKED_OUT_FRIEND()
iFadeTimer = GET_GAME_TIMER()
JUMP_TO_STAGE(1)
ELSE
IF WAS_CUTSCENE_SKIPPED()
RCM_DEBUG_PRINT("Detected the cutscene was skipped!! Do our own fade...")
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_CUTSCENE_FADE_VALUES(FALSE, FALSE, TRUE, FALSE)
bIntroSkipped = TRUE
iIntroStage = 1
ENDIF
IF IS_CUTSCENE_PLAYING()
IF GET_CUTSCENE_TIME() > 64000
RUN_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo, FALSE)
RCM_DEBUG_PRINT("Running checkpoints during intro now")
ENDIF
ENDIF
IF iIntroStage = 0
WHILE NOT HAVE_ASSETS_FOR_MISSION_STAGE_LOADED(stateCountdown)
WAIT(0) //Load in race assets while the cutscene is playing to speed things up
IF IS_CUTSCENE_SKIP_BUTTON_JUST_PRESSED()
RCM_DEBUG_PRINT("Cutscene skipped in while!!")
IF bIntroSkipped = FALSE
IF IS_CUTSCENE_ACTIVE()
STOP_CUTSCENE()
ENDIF
bIntroSkipped = TRUE
iFadeTimer = GET_GAME_TIMER()
ENDIF
ENDIF
IF WAS_CUTSCENE_SKIPPED()
RCM_DEBUG_PRINT("Detected the cutscene was skipped!! Do our own fade... (in while)")
SET_CUTSCENE_FADE_VALUES(FALSE, FALSE, TRUE, FALSE)
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_CUTSCENE_FADE_VALUES(FALSE, FALSE, TRUE, FALSE)
bIntroSkipped = TRUE
iIntroStage = 1
ENDIF
CHECK_EXIT_STATES()
DO_TREVOR_EXIT()
ENDWHILE
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
CHECK_EXIT_STATES()
IF DO_TREVOR_EXIT()
iIntroStage = 1
ENDIF
ELIF iIntroStage = 1
CHECK_EXIT_STATES()
DO_TREVOR_EXIT()
IF bDoneTrevExit
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_PreventGoingIntoStillInVehicleState, TRUE)
RCM_DEBUG_PRINT("Setting PRF_PreventGoingIntoStillInVehicleState on Trevor")
ENDIF
ENDIF
IF bDoBikeExit
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ENDIF
IF bIntroSkipped
IF NOT bIntroSkippedWhile
RCM_DEBUG_PRINT("Doing out-of-loop Z-skip")
iFadeTimer = GET_GAME_TIMER()
SAFE_FADE_SCREEN_OUT_TO_BLACK(DEFAULT, FALSE)
WHILE (GET_GAME_TIMER() - iFadeTimer) < 750
WAIT(0)
RCM_DEBUG_PRINT("In fade out wait...")
// If we're waiting for the fade, keep doing the rolling start
CHECK_EXIT_STATES()
DO_TREVOR_EXIT()
IF IS_SCREEN_FADED_OUT()
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ENDIF
ENDWHILE
iFadeTimer = GET_GAME_TIMER() // Reset timer to use it again for the fade in
bIntroSkippedWhile = TRUE // Stop this looping over and over
ENDIF
RCM_PLACE_KNOCKED_OUT_FRIEND() // Just to ensure he's placed if the exit state is missed
// This is an attempt to stop #354555
// This is TERRIBLE. I feel like a CRIMINAL.
ENDIF
IF NOT IS_CUTSCENE_PLAYING()
REPLAY_STOP_EVENT()
REPLAY_RECORD_BACK_FOR_TIME(0.0, 10.0, REPLAY_IMPORTANCE_LOW)
#IF IS_DEBUG_BUILD
bAllowDebugSkipForward = FALSE // Prevents J skipping through an extra state
#ENDIF
// This is still needed while 1028909 is an issue
// 551021 needs fixing first, then 864739 needs looked at
// IF NOT bUsedSkip
// RCM_DEBUG_PRINT("Reset bikes from MS_INTRO loop")
// RESET_BIKES() // Don't reset the bikes if we've used a debug skip
// ENDIF
// CLEAR_AREA_OF_VEHICLES(<<820.66, 1275.33, 359.48>>, 14.0)
// CLEAR_AREA_OF_VEHICLES(<<839.00, 1277.36, 359.11>>, 14.0)
CLEAR_AREA_OF_VEHICLES(<<850.99, 1284.06, 358.39>>, 14.0)
CLEAR_AREA_OF_VEHICLES(<<856.54, 1270.78, 358.24>>, 14.0)
CLEAR_AREA_OF_VEHICLES(<<850.71, 1256.57, 356.34>>, 14.0)
CLEAR_AREA_OF_VEHICLES(<<840.86, 1245.39, 352.97>>, 14.0)
IF NOT bIntroSkipped
RC_END_CUTSCENE_MODE()
ENDIF
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF RCM_IS_PLAYER_OK()
bDoBikeExit = TRUE
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ENDIF
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, FALSE)
REPEAT NUM_BIKES i
IF IS_ENTITY_ALIVE(vehBike[i])
SET_ENTITY_PROOFS(vehBike[i], FALSE, FALSE, FALSE, FALSE, FALSE)
ENDIF
ENDREPEAT
RCM_ADVANCE_STAGE()
ENDIF
ENDIF
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RUN_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo) // Keep the checkpoint onscreen during the blend
RCM_DEBUG_PRINT("Cleaned up MS_INTRO")
ENDIF
ENDPROC
/// PURPOSE:
/// Control function for the cop and car being chased up the mountain roughly midway through the race
PROC RCM_DRIVE_PAST_PLAYER()
IF NOT Is_Replay_In_Progress()
if IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<435.162811,1275.777466,269.505432>>, <<455.596619,1285.541504,278.748474>>, 8.500000)
IF bStartedDrivers = FALSE
// We're only going to create the Driver and Cop the moment they're supposed to be triggered
// Otherwise, you could bike off a cliff and see them waiting on the road
// (You'll then fail the mission, but you'd still 'see the strings' so to speak)
REQUEST_MODEL(Penumbra)
REQUEST_MODEL(POLICE3)
REQUEST_VEHICLE_RECORDING(500, "Fan2_Driver")
REQUEST_VEHICLE_RECORDING(500, "Fan2_DriverCop")
IF HAS_MODEL_LOADED(Penumbra)
and HAS_MODEL_LOADED(POLICE3)
AND HAS_VEHICLE_RECORDING_BEEN_LOADED(500, "Fan2_Driver")
AND HAS_VEHICLE_RECORDING_BEEN_LOADED(500, "Fan2_DriverCop")
RCM_SPAWN_VEHICLE(viDriver, PENUMBRA, << 543.5132, 1022.7282, 216.7213 >>)
IF NOT IS_ENTITY_ALIVE(piDriver) AND IS_VEHICLE_OK(viDriver)
IF IS_VEHICLE_SEAT_FREE(viDriver)
piDriver = CREATE_PED_INSIDE_VEHICLE(viDriver, PEDTYPE_MISSION, A_M_Y_Runner_01)
RCM_DEBUG_PRINT("Created car.")
ENDIF
ENDIF
SET_MODEL_AS_NO_LONGER_NEEDED(PENUMBRA)
SET_MODEL_AS_NO_LONGER_NEEDED(A_M_Y_Runner_01)
RCM_SPAWN_VEHICLE(viDriverCop, POLICE3, << 537.1293, 1009.8887, 214.4232 >>)
IF NOT IS_ENTITY_ALIVE(piDriverCop) AND IS_VEHICLE_OK(viDriverCop)
IF IS_VEHICLE_SEAT_FREE(viDriverCop)
piDriverCop = CREATE_PED_INSIDE_VEHICLE(viDriverCop, PEDTYPE_COP, S_M_Y_Cop_01)
RCM_DEBUG_PRINT("Created cop car.")
ENDIF
ENDIF
SET_MODEL_AS_NO_LONGER_NEEDED(POLICE3)
SET_MODEL_AS_NO_LONGER_NEEDED(S_M_Y_Cop_01)
if IS_VEHICLE_OK(viDriver)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viDriver)
START_PLAYBACK_RECORDED_VEHICLE(viDriver, 500, "Fan2_Driver")
ENDIF
ENDIF
if IS_VEHICLE_OK(viDriverCop)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viDriverCop)
START_PLAYBACK_RECORDED_VEHICLE(viDriverCop, 500, "Fan2_DriverCop")
SET_VEHICLE_SIREN(viDriverCop, TRUE)
ENDIF
ENDIF
bStartedDrivers = TRUE // Stop trying to create the drivers
ENDIF
ENDIF
ELSE // If the vehicles have started playback and the player has passed the trigger zone, modify their playback speed
IF IS_VEHICLE_OK(viDriver)
IF IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viDriver)
SET_PLAYBACK_SPEED(viDriver, 1.20)
ENDIF
ENDIF
IF IS_VEHICLE_OK(viDriverCop)
IF IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viDriverCop)
SET_PLAYBACK_SPEED(viDriverCop, 1.30)
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Control function for the two joggers by the Vinewood sign
PROC RCM_JOG_PAST_PLAYER()
IF raceLength = RACE_LONGA OR raceLength = RACE_LONGB
if IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<838.825256,1255.184814,352.553162>>, <<871.473328,1263.308228,364.424377>>, 30.250000)
IF NOT IS_ENTITY_ALIVE(piJogger1)
AND HAS_MODEL_LOADED(A_F_Y_Runner_01)
piJogger1 = CREATE_PED(PEDTYPE_MISSION, A_F_Y_Runner_01, <<590.1751, 1203.1410, 307.6940>>, 293.40)
RCM_DEBUG_PRINT("Created jogger 1")
SET_MODEL_AS_NO_LONGER_NEEDED(A_F_Y_Runner_01)
ELSE
IF NOT IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_PED(piJogger1)
TASK_FOLLOW_WAYPOINT_RECORDING(piJogger1, "Fan2_Jogger1")
ELSE
IF GET_PED_WAYPOINT_PROGRESS(piJogger1) > 93
RCM_DEBUG_PRINT("Released jogger 1 (waypoint > 93)")
SAFE_RELEASE_PED(piJogger1)
ENDIF
ENDIF
ENDIF
IF NOT IS_ENTITY_ALIVE(piJogger2)
AND HAS_MODEL_LOADED(A_M_Y_Runner_01)
piJogger2 = CREATE_PED(PEDTYPE_MISSION, A_M_Y_Runner_01, <<592.1368, 1200.9105, 307.7926>>, 286.58)
RCM_DEBUG_PRINT("Created jogger 2")
IF IS_REPLAY_IN_PROGRESS() // If we're on a replay, we can release this model now as it's not used for the car chase sequence
SET_MODEL_AS_NO_LONGER_NEEDED(A_M_Y_Runner_01)
ENDIF
ELSE
IF NOT IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_PED(piJogger2)
TASK_FOLLOW_WAYPOINT_RECORDING(piJogger2, "Fan2_Jogger2")
ELSE
IF GET_PED_WAYPOINT_PROGRESS(piJogger2) > 93
RCM_DEBUG_PRINT("Released jogger 2 (waypoint > 93)")
SAFE_RELEASE_PED(piJogger2)
ENDIF
ENDIF
ENDIF
ELSE
IF IS_ENTITY_ALIVE(piJogger1)
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_PED(piJogger1)
IF GET_PED_WAYPOINT_PROGRESS(piJogger1) > 93
SAFE_RELEASE_PED(piJogger1)
RCM_DEBUG_PRINT("Released jogger 1 (waypoint > 93)")
ELIF GET_PED_WAYPOINT_PROGRESS(piJogger1) > 51
IF GET_DISTANCE_BETWEEN_ENTITIES(piJogger1, PLAYER_PED_ID()) > 70
SAFE_RELEASE_PED(piJogger1)
RCM_DEBUG_PRINT("Released jogger 1 (distance > 70)")
ENDIF
ENDIF
ELSE
SAFE_RELEASE_PED(piJogger1)
RCM_DEBUG_PRINT("Released jogger 1 (no waypoint playback)")
ENDIF
ELSE
SAFE_RELEASE_PED(piJogger1)
ENDIF
IF IS_ENTITY_ALIVE(piJogger2)
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_PED(piJogger2)
IF GET_PED_WAYPOINT_PROGRESS(piJogger2) > 93
SAFE_RELEASE_PED(piJogger2)
RCM_DEBUG_PRINT("Released jogger 2 (waypoint > 93)")
ELIF GET_PED_WAYPOINT_PROGRESS(piJogger2) > 51
IF GET_DISTANCE_BETWEEN_ENTITIES(piJogger2, PLAYER_PED_ID()) > 70
SAFE_RELEASE_PED(piJogger2)
RCM_DEBUG_PRINT("Released jogger 2 (distance > 70)")
ENDIF
ENDIF
ELSE
SAFE_RELEASE_PED(piJogger2)
RCM_DEBUG_PRINT("Released jogger 2 (no waypoint playback)")
ENDIF
ELSE
SAFE_RELEASE_PED(piJogger2)
ENDIF
if HAS_PLAYER_THREATENED_PED(piJogger1) OR HAS_PLAYER_THREATENED_PED(piJogger2)
IF IS_PED_UNINJURED(piJogger1) AND IS_PED_UNINJURED(piJogger2)
TASK_SMART_FLEE_PED(piJogger1, PLAYER_PED_ID(), 100, -1)
TASK_SMART_FLEE_PED(piJogger2, PLAYER_PED_ID(), 100, -1)
ENDIF
SAFE_RELEASE_PED(piJogger1)
SAFE_RELEASE_PED(piJogger2)
RCM_DEBUG_PRINT("Released joggers 1 & 2 (threatened)")
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Control function for the cyclist on the forest path during the second half of the race
PROC RCM_CYCLE_PAST_PLAYER()
IF raceLength = RACE_LONGA OR raceLength = RACE_LONGB
if IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<458.592285,1066.150757,232.179642>>, <<428.820862,1059.496948,241.894241>>, 9.750000)
AND NOT bStartedCyclist
REQUEST_MODEL(A_M_Y_Cyclist_01)
IF HAS_MODEL_LOADED(A_M_Y_Cyclist_01)
if IS_VEHICLE_OK(viCyclist)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viCyclist)
START_PLAYBACK_RECORDED_VEHICLE(viCyclist, 500, "Fan2_Cyclist")
FORCE_PLAYBACK_RECORDED_VEHICLE_UPDATE(viCyclist)
RCM_DEBUG_PRINT("Playing cyclist")
bStartedCyclist = TRUE
ENDIF
ELSE
RCM_SPAWN_VEHICLE(viCyclist, TRIBIKE, << 292.3295, 1244.0404, 234.0005 >>)
IF NOT IS_ENTITY_ALIVE(piCyclist) AND IS_VEHICLE_OK(viCyclist)
IF IS_VEHICLE_SEAT_FREE(viCyclist)
piCyclist = CREATE_PED_INSIDE_VEHICLE(viCyclist, PEDTYPE_MISSION, A_M_Y_Cyclist_01)
RCM_DEBUG_PRINT("Created cyclist.")
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_VEHICLE_OK(viCyclist) AND IS_ENTITY_ALIVE(piCyclist)
IF bStartedCyclist
SET_MODEL_AS_NO_LONGER_NEEDED(A_M_Y_Cyclist_01)
IF NOT IS_PLAYBACK_GOING_ON_FOR_VEHICLE(viCyclist)
SAFE_RELEASE_PED(piCyclist)
SAFE_RELEASE_VEHICLE(viCyclist)
RCM_DEBUG_PRINT("Killing cyclist")
ENDIF
ENDIF
ENDIF
IF IS_ENTITY_ALIVE(piCyclist)
if HAS_PLAYER_THREATENED_PED(piCyclist)
TASK_SMART_FLEE_PED(piCyclist, PLAYER_PED_ID(), 200, -1)
SAFE_RELEASE_PED(piCyclist)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Make any vehicles close to the front of the player's bike honk their horn at them
PROC RCM_HONK_NEAR_PLAYER()
VECTOR vOffset
VEHICLE_INDEX vIdx
IF RCM_IS_PLAYER_OK()
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID]) AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF GET_ENTITY_SPEED(PLAYER_PED_ID()) > 5
vOffset = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), <<0,6,0>>)
//DRAW_DEBUG_SPHERE(vOffset, 8, 0, 0, 255, 125)
if (GET_GAME_TIMER() - iHonkTimer) > 4000
//RCM_DEBUG_PRINT("HONKING: Checking for vehicle...")
vIdx = GET_CLOSEST_VEHICLE(vOffset, 8, DUMMY_MODEL_FOR_SCRIPT, 2) // 2 = Return mission vehicles
if vIdx <> NULL
RCM_DEBUG_PRINT("HONKING: Entity exists!")
if not IS_VEHICLE_MODEL(vIdx, SCORCHER)
AND NOT IS_VEHICLE_MODEL(vIdx, TRIBIKE)
AND NOT IS_VEHICLE_SEAT_FREE(vIdx)
START_VEHICLE_HORN(vIdx, 4000)
RCM_DEBUG_PRINT("Honking!")
IF IS_PED_UNINJURED(PLAYER_PED_ID())
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), vIdx, 3000)
ENDIF
iHonkTimer = GET_GAME_TIMER()
ENDIF
ENDIF
vIdx = GET_CLOSEST_VEHICLE(vOffset, 8, DUMMY_MODEL_FOR_SCRIPT, 4) // 4 = Return random vehicles
if vIdx <> NULL
RCM_DEBUG_PRINT("HONKING: Entity exists!")
if not IS_VEHICLE_MODEL(vIdx, SCORCHER)
AND NOT IS_VEHICLE_MODEL(vIdx, TRIBIKE)
AND NOT IS_VEHICLE_SEAT_FREE(vIdx)
START_VEHICLE_HORN(vIdx, 4000)
RCM_DEBUG_PRINT("Honking!")
IF IS_PED_UNINJURED(PLAYER_PED_ID())
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(), vIdx, 3000)
ENDIF
iHonkTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Update the checks to make sure the player is still on their bike, and display God text where needed
PROC RCM_CHECK_PLAYER_ON_BIKE()
IF RCM_IS_PLAYER_OK()
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF bPlayerIsOnBike = TRUE
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
IF NOT DOES_BLIP_EXIST(blipBike)
blipBike = CREATE_VEHICLE_BLIP(vehBike[PLAYER_BIKE_ID])
ENDIF
IF bDisplayedGetBackOnBike = FALSE
PRINT_NOW("FATIC2_1", DEFAULT_GOD_TEXT_TIME, 1) // Get on the ~b~bike.
bDisplayedGetBackOnBike = TRUE
ENDIF
bPlayerIsOnBike = FALSE
ENDIF
ELSE
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
CLEAR_PRINTS()
SAFE_REMOVE_BLIP(blipBike)
bPlayerIsOnBike = TRUE
ENDIF
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID]) > 40.0
RCM_MISSION_FAILED(FAILED_LEFT_BIKE)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Manage playing the final race-ending dialogue as the player reaches the finish line
PROC RCM_MANAGE_PENULTIMATE_CONVERSATION()
IF playerInfo.currentCheck >= MAX_CHECKPOINTS-1
IF bStartEndConv = FALSE
KILL_ANY_CONVERSATION()
bStartEndConv = TRUE
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Work out if Trevor should play a line of Road Rage dialogue, and play one if able
/// PARAMS:
/// KillExistingConvo - End any ongoing conversation before trying to play a road rage line
PROC RCM_TRY_ROAD_RAGE_CONVERSATION()
IF iRoadRageConversationsPlayed < NUM_ROAD_RAGE_CONVERSATIONS
IF bRoadRagePlaying = FALSE
VECTOR vOffset
VEHICLE_INDEX vIdx
IF RCM_IS_PLAYER_OK()
IF GET_ENTITY_SPEED(PLAYER_PED_ID()) > 5
vOffset = GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), <<0,8,0>>)
IF IS_ANY_VEHICLE_NEAR_POINT(vOffset, 3.5)
vIdx = GET_CLOSEST_VEHICLE(vOffset, 3.5, DUMMY_MODEL_FOR_SCRIPT, 2) // 2 = Return mission vehicles
if vIdx <> NULL
if not IS_VEHICLE_MODEL(vIdx, SCORCHER)
OR NOT IS_VEHICLE_MODEL(vIdx, TRIBIKE)
bRoadRagePlaying = TRUE
iConversationGapTimer = GET_GAME_TIMER()
ENDIF
ENDIF
vIdx = GET_CLOSEST_VEHICLE(vOffset, 3.5, DUMMY_MODEL_FOR_SCRIPT, 4) // 4 = Return random vehicles
if vIdx <> NULL
if not IS_VEHICLE_MODEL(vIdx, SCORCHER)
OR NOT IS_VEHICLE_MODEL(vIdx, TRIBIKE)
bRoadRagePlaying = TRUE
iConversationGapTimer = GET_GAME_TIMER()
// If banter is paused, kill it early - we'll play road rage instead and forget about it
IF ConvState = FAN2_CONV_STATE_BANTER_PAUSED
OR ConvState = FAN2_CONV_STATE_TOOFAR
KILL_ANY_CONVERSATION()
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Try to set up either a banter conversation or a one-liner.
/// Is a state machine that waits for 4 seconds to pass before trying to do either of those.
/// The sequence of conversations that are triggered is set up specifically here.
PROC RCM_TRY_BANTER_OR_ONELINERS()
SWITCH BanterState
CASE BANTER_WAIT
if (GET_GAME_TIMER() - iBanterTimer) > 10000
BanterState = BANTER_ACT
ENDIF
BREAK
CASE BANTER_ACT
SWITCH iBanterSequence
CASE 0
ConvState = FAN2_CONV_STATE_BANTER_PLAYING
BREAK
CASE 1
ConvState = FAN2_CONV_STATE_ONELINER
BREAK
CASE 2
ConvState = FAN2_CONV_STATE_BANTER_PLAYING
BREAK
CASE 3
ConvState = FAN2_CONV_STATE_ONELINER
BREAK
CASE 4
ConvState = FAN2_CONV_STATE_BANTER_PLAYING
BREAK
CASE 5
ConvState = FAN2_CONV_STATE_ONELINER
BREAK
CASE 6
ConvState = FAN2_CONV_STATE_BANTER_PLAYING
BREAK
DEFAULT
ConvState = FAN2_CONV_STATE_ONELINER
BREAK
ENDSWITCH
iBanterSequence++
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Keep trying to do the given road rage conversation index
/// PARAMS:
/// i - the road rage conversation index we want to try and play
/// RETURNS:
/// TRUE if the conversation launches, FALSE if not
FUNC BOOL DO_ROAD_RAGE(int i)
IF bPlayedRoadRageConversation[i] = FALSE
IF CREATE_CONVERSATION(sRoadRageConversation, "FAN2AU", sRoadRageConversationString[i], CONV_PRIORITY_HIGH)
bPlayedRoadRageConversation[i] = TRUE
iRoadRageConversationsPlayed++
RCM_DEBUG_PRINTINT("iRoadRageConversationsPlayed = ", iRoadRageConversationsPlayed)
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// A large state machine that controls all of the conversations during the race!
/// Starts off in FAN2_CONV_STATE_START by default - the very first line Trevor says as the race starts.
/// Then cycles between FAN2_CONV_STATE_FREE to various other states.
/// The exception to this is FAN2_CONV_STATE_END - it stays there as we're about to finish the race
PROC RCM_MANAGE_CONVERSATIONS()
FLOAT fDist
SWITCH ConvState
// Line by Trevor at very start of race
CASE FAN2_CONV_STATE_START
IF bPlayedStartConv = FALSE
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_START", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Doing start conversation")
bPlayedStartConv = TRUE
ENDIF
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_DEBUG_PRINT("*** Start conversation over, conv state free")
iBanterTimer = GET_GAME_TIMER()
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
BREAK
// No conversation is ongoing, try various conditions in case we can do one
// If we get too far away from Mary Ann (>30m), stop any conversations from firing, but otherwise...
// See if we have to start the penultimate conversation (FAN2_CONV_STATE_END)...
// Then check if we need to make Mary Ann give a push warning (FAN2_CONV_STATE_PUSHWARNING)...
// Then see if we need to try and make Mary Ann react to Trevor overtaking (FAN2_CONV_STATE_OVERTAKE)...
// If we don't need to do any of these, then try and see if we can do either a banter conversation or a one-liner
CASE FAN2_CONV_STATE_FREE
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID]))
IF bRoadRagePlaying // Do road rage if trying, regardless of distance between Mary Ann and Trevor
RCM_DEBUG_PRINT("*** Starting road rage")
ConvState = FAN2_CONV_STATE_ROADRAGE
ELIF fDist > 30 // Set conv status as too far if over 30m apart
RCM_DEBUG_PRINT("*** Too far apart (>30m) to do anything with a conversation")
ConvState = FAN2_CONV_STATE_TOOFAR
ELSE
IF NOT IS_MESSAGE_BEING_DISPLAYED()
OR GET_PROFILE_SETTING(PROFILE_DISPLAY_SUBTITLES) = 0
IF bStartEndConv
RCM_DEBUG_PRINT("*** Starting end conversation routine")
ConvState = FAN2_CONV_STATE_END
ELIF bGivePushWarning
RCM_DEBUG_PRINT("*** Starting push warning")
ConvState = FAN2_CONV_STATE_PUSHWARNING
ELIF bOvertakeOccurred
RCM_DEBUG_PRINT("*** Starting overtake routine")
ConvState = FAN2_CONV_STATE_OVERTAKE
ELSE
RCM_TRY_BANTER_OR_ONELINERS()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
// Hang about here and keep checking to see if we're close enough to try doing conversations again
CASE FAN2_CONV_STATE_TOOFAR
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID]))
IF fDist <= 30 // Set conv status as too far if over 30m apart
RCM_DEBUG_PRINT("*** Close enough (<=30m) to do a conversation")
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
ENDIF
BREAK
// Near the last checkpoint, do the final line(s)
CASE FAN2_CONV_STATE_END
IF NOT bPlayedFinalConv
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF iRacePos = 1
IF CREATE_CONVERSATION(sRoadRageConversation, "FAN2AU", "FAN2_WINNING", CONV_PRIORITY_HIGH)
bPlayedFinalConv = TRUE
bFinalConvWinning = TRUE
RCM_DEBUG_PRINT("*** Trevor saying FAN2_WINNING")
ENDIF
ELSE
IF CREATE_CONVERSATION(sRoadRageConversation, "FAN2AU", "FAN2_LOSING", CONV_PRIORITY_HIGH)
bPlayedFinalConv = TRUE
RCM_DEBUG_PRINT("*** Trevor saying FAN2_LOSING")
ENDIF
ENDIF
ENDIF
ELSE
IF bFinalConvWinning = TRUE // The convo played was the winning one
IF iRacePos = 2 // If the player gets overtaken by Mary Ann after this...
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RCM_DEBUG_PRINT("*** Mary Ann passed player after saying 'WINNING' line...")
PLAY_PED_AMBIENT_SPEECH_WITH_VOICE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], "FAN2_BQAA", "MARYANN", SPEECH_PARAMS_FORCE_FRONTEND)
// I think this will make her just go to the last checkpoint
TASK_DRIVE_BY(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PLAYER_PED_ID(), NULL, <<0,0,0>>, 50, 100, TRUE, FIRING_PATTERN_FULL_AUTO)
bFinalConvWinning = FALSE // Stop trying to do this
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
// Do a push warning line from Mary Ann
CASE FAN2_CONV_STATE_PUSHWARNING
IF bPlayedPushConv = FALSE
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_PUSH", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Done a push warning")
bPlayedPushConv = TRUE
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_DEBUG_PRINT("*** Push warning over, conv state free")
bGivePushWarning = FALSE
bPlayedPushConv = FALSE
iPushTimer = GET_GAME_TIMER()
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
BREAK
// Do an overtake reaction line from Mary Ann
CASE FAN2_CONV_STATE_OVERTAKE
IF bPlayedOvertakeLine = FALSE
// If the player overtakes Mary Ann while another conversation is happening, it'll try playing an overtake line when it finishes
// This will sound weird, so we'll only play the overtake line if less than a second has passed between overtaking and trying to say the line
IF (GET_GAME_TIMER() - iConversationGapTimer) < 750
IF iRacePos = 1 // If Trevor has overtaken Mary Ann...
IF iOverTakeLinesPlayed < NUM_OVERTAKE_LINES
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_OVERT", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Doing overtake line")
bPlayedOvertakeLine = TRUE
iOverTakeLinesPlayed++
ENDIF
ELSE
// We've played all the available overtake lines and don't want to repeat, so just set the conv status back to free
RCM_DEBUG_PRINT("*** All overtake lines played!")
bOvertakeOccurred = FALSE
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ELSE // iRacePos = 2
// We don't want a line when Mary Ann overtakes Trevor, so just reset the conv status back to free
RCM_DEBUG_PRINT("*** Tried to do overtake line when Mary Ann passed Trevor!")
bOvertakeOccurred = FALSE
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Too much time passed between overtake and a free spot in the conversation; skipping...")
bOvertakeOccurred = FALSE
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_DEBUG_PRINT("*** Overtake line over, conv state free")
bOvertakeOccurred = FALSE
bPlayedOvertakeLine = FALSE
iOvertakeSpamTimer = GET_GAME_TIMER()
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
BREAK
// Try and do a road rage conversation if a car honks at Trevor during a free moment
CASE FAN2_CONV_STATE_ROADRAGE
// If the time elapsed from triggering the road rage convo and actually being able to do it is too large, don't bother, it'll sound odd
IF (GET_GAME_TIMER() - iConversationGapTimer) < 1000
INT i
i = GET_RANDOM_INT_IN_RANGE(0, NUM_ROAD_RAGE_CONVERSATIONS)
IF DO_ROAD_RAGE(i)
RCM_DEBUG_PRINT("*** Did a road rage line")
bRoadRagePlaying = FALSE
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Too long between trying to trigger road rage and free moment in conversation, skipping...")
bRoadRagePlaying = FALSE
ConvState = FAN2_CONV_STATE_FREE
ENDIF
BREAK
// Trying to play a banter conversation
CASE FAN2_CONV_STATE_BANTER_PLAYING
IF bPlayedBanterOneliner = FALSE
IF iWomanConversationsPlayed < NUM_WOMAN_CONVERSATIONS
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", sWomanConversationString[iWomanConversationsPlayed], CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINTINT("*** Started banter conversation #", iWomanConversationsPlayed+1)
bPlayedBanterOneliner = TRUE
iWomanConversationsPlayed++
ENDIF
ENDIF
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Tried to play more banter than convos available... not good!")
bPlayedBanterOneliner = FALSE
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ELSE
// If the conversation ends, set status back to free
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_DEBUG_PRINT("*** Finished banter!")
bPlayedBanterOneliner = FALSE
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
// But if Mary Ann and Trevor get too far apart, pause the banter to resume it later
ELSE
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID]))
IF fDist > 30 // Set conv status paused if over 30m apart
OR NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE) // or if the player comes off their bike
RCM_DEBUG_PRINT("*** Paused banter!")
PAUSE_SCRIPTED_CONVERSATION(TRUE)
ConvState = FAN2_CONV_STATE_BANTER_PAUSED
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
// Banter conversation is ongoing, but paused - keep checking if we can unpause it
CASE FAN2_CONV_STATE_BANTER_PAUSED
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID]))
IF fDist <= 30 // Resume the conversation if they're close enough again
AND IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID(), TRUE)
RCM_DEBUG_PRINT("*** Unpaused banter!")
RESTART_SCRIPTED_CONVERSATION()
ConvState = FAN2_CONV_STATE_BANTER_PLAYING
ENDIF
ENDIF
ENDIF
BREAK
// Play a one-liner comment from either character
CASE FAN2_CONV_STATE_ONELINER
IF bPlayedBanterOneliner = FALSE
bDoMaryAnnOneliner = GET_RANDOM_BOOL()
// If bDoMaryAnnOneliner = true, do one of Mary Ann's lines - otherwise, do one of Trevor's
IF bDoMaryAnnOneliner
// If the player's ahead, do one of Mary Ann's "behind" one liners
IF iRacePos = 1
IF iWomanBehindOnelinersPlayed < NUM_WOMAN_BEHIND_ONELINERS
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_BEHIND", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Doing Behind line")
iWomanBehindOnelinersPlayed++
bPlayedBanterOneliner = TRUE
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Tried doing a Behind one-liner, but have run out!")
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
ENDIF
// Otherwise, she's ahead, so do one of those instead
ELSE
IF iWomanAheadOnelinersPlayed < NUM_WOMAN_AHEAD_ONELINERS
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_AHEAD", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Doing Ahead line")
iWomanAheadOnelinersPlayed++
bPlayedBanterOneliner = TRUE
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Tried doing an Ahead one-liner, but have run out!")
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
ELSE
IF iTrevorOnelinersPlayed < NUM_TREVOR_ONELINERS
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_TREV1L", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("*** Doing Trevor one-liner")
iTrevorOnelinersPlayed++
bPlayedBanterOneliner = TRUE
ENDIF
ELSE
RCM_DEBUG_PRINT("*** Tried doing a Trevor one-liner, but have run out!")
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_DEBUG_PRINT("*** Oneliner over, conv state free")
bPlayedBanterOneliner = FALSE
iBanterTimer = GET_GAME_TIMER()
BanterState = BANTER_WAIT
ConvState = FAN2_CONV_STATE_FREE
ENDIF
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Manage Mary Ann's bike speed during the race using rubber-banding
PROC RCM_MANAGE_BIKE_SPEED()
FLOAT fDist
FLOAT fPlaybackModifier
IF RCM_IS_PLAYER_OK()
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
fDist = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]))
IF fDist > 60
fDist = 60
ENDIF
fPlaybackModifier = (fDist / 50) * 1.6
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
// We get the nearest waypoint to the opponent's current position...
int iCurrWaypoint
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT("Fan2_BikeRoute", GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]), iCurrWaypoint)
// ... and then dial-down the speed of that waypoint to set the opponent's rubber-banded speed
float fPlaybackSpd = WAYPOINT_RECORDING_GET_SPEED_AT_POINT("Fan2_BikeRoute", iCurrWaypoint)
// Going to globally increase the playback speed because it's too slow by default
FLOAT fGlobalIncrease
// IF iCurrWaypoint > 150
// fGlobalIncrease = 3.8 // Go a little slower on the final stretch to give the player more of a chance
// ELSE
fGlobalIncrease = 4.8
// ENDIF
fPlaybackSpd = fPlaybackSpd + fGlobalIncrease
// The ratio modifier is by default calculated for on-foot speeds at 0.2, 0.3, etc
// Here, we want it to apply to vehicle values, between 2.0, 3.0, etc - so multiply by 10
IF iRacePos = 2
fPlaybackSpd = (fPlaybackSpd - fPlaybackModifier - 0.5) // If player is behind, decrease speed/do nothing
ELSE
fPlaybackSpd = (fPlaybackSpd + fPlaybackModifier + 2.0) // If player is ahead, increase speed
ENDIF
IF bDebugPrintBikePlaybackSpeed = TRUE
RCM_DEBUG_PRINTBIKESPEED("Player fDist=", fDist, " fPlaybackModifier=", fPlaybackModifier, " Final fPlaybackSpeed=", fPlaybackSpd)
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RCM_DEBUG_PRINTFLOAT("Actual opponent speed= ", GET_ENTITY_SPEED(sRCLauncherDataLocal.pedID[MARY_ANN_ID]))
ENDIF
ENDIF
VEHICLE_WAYPOINT_PLAYBACK_OVERRIDE_SPEED(vehBike[MARY_ANN_BIKE_ID], fPlaybackSpd)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Enable the hint camera during the race when Mary Ann is close enough to Trevor
PROC RCM_DO_HINT_CAM()
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID])) <= 50
IF iRacePos = 2 // Only enable when behind
CONTROL_VEHICLE_CHASE_HINT_CAM_IN_VEHICLE(localChaseHintCamStruct, vehBike[MARY_ANN_BIKE_ID])
ELSE
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
ENDIF
ELSE
KILL_CHASE_HINT_CAM(localChaseHintCamStruct)
ENDIF
ENDIF
ENDPROC
FUNC INT GET_WAYPOINT_FOR_CHECKPOINT(INT iCheckpoint)
SWITCH iCheckpoint
CASE 0
CASE 1
CASE 2
RETURN 10
BREAK
CASE 3
RETURN 17
BREAK
CASE 4
RETURN 22
BREAK
CASE 5
RETURN 29
BREAK
CASE 6
RETURN 37
BREAK
CASE 7
RETURN 43
BREAK
CASE 8
RETURN 50
BREAK
CASE 9
RETURN 58
BREAK
CASE 10
RETURN 67
BREAK
CASE 11
RETURN 77
BREAK
CASE 12
RETURN 81
BREAK
CASE 13
RETURN 90
BREAK
CASE 14
RETURN 101
BREAK
CASE 15
RETURN 110
BREAK
CASE 16
RETURN 116
BREAK
CASE 17
RETURN 121
BREAK
CASE 18
RETURN 124
BREAK
CASE 19
RETURN 129
BREAK
CASE 20
RETURN 137
BREAK
CASE 21
RETURN 144
BREAK
CASE 22
RETURN 151
BREAK
CASE 23
RETURN 157
BREAK
CASE 24
RETURN 167
BREAK
CASE 25
RETURN 176
BREAK
CASE 26
RETURN 184
BREAK
DEFAULT
RETURN 0
BREAK
ENDSWITCH
RETURN 0
ENDFUNC
/// PURPOSE:
/// If Mary Ann gets knocked off course, this should set her next checkpoint correctly so the race still tracks as it should
/// PARAMS:
/// iNewWaypoint - The waypoint Mary Ann's been teleported too
PROC SET_RECOVERED_CHECKPOINT(int iNewWaypoint)
if iNewWaypoint <= 10
iWomanNextCheckpoint = 2
ELIF iNewWaypoint <= 17
iWomanNextCheckpoint = 3
ELIF iNewWaypoint <= 22
iWomanNextCheckpoint = 4
ELIF iNewWaypoint <= 29
iWomanNextCheckpoint = 5
ELIF iNewWaypoint <= 37
iWomanNextCheckpoint = 6
ELIF iNewWaypoint <= 43
iWomanNextCheckpoint = 7
ELIF iNewWaypoint <= 50
iWomanNextCheckpoint = 8
ELIF iNewWaypoint <= 58
iWomanNextCheckpoint = 9
ELIF iNewWaypoint <= 67
iWomanNextCheckpoint = 10
ELIF iNewWaypoint <= 77
iWomanNextCheckpoint = 11
ELIF iNewWaypoint <= 81
iWomanNextCheckpoint = 12
ELIF iNewWaypoint <= 90
iWomanNextCheckpoint = 13
ELIF iNewWaypoint <= 101
iWomanNextCheckpoint = 14
ELIF iNewWaypoint <= 110
iWomanNextCheckpoint = 15
ELIF iNewWaypoint <= 116
iWomanNextCheckpoint = 16
ELIF iNewWaypoint <= 121
iWomanNextCheckpoint = 17
ELIF iNewWaypoint <= 124
iWomanNextCheckpoint = 18
ELIF iNewWaypoint <= 129
iWomanNextCheckpoint = 19
ELIF iNewWaypoint <= 137
iWomanNextCheckpoint = 20
ELIF iNewWaypoint <= 144
iWomanNextCheckpoint = 21
ELIF iNewWaypoint <= 151
iWomanNextCheckpoint = 22
ELIF iNewWaypoint <= 157
iWomanNextCheckpoint = 23
ELIF iNewWaypoint <= 167
iWomanNextCheckpoint = 24
ELIF iNewWaypoint <= 176
iWomanNextCheckpoint = 25
ELIF iNewWaypoint <= 184
iWomanNextCheckpoint = 26
ENDIF
RCM_DEBUG_PRINTINT("*** Recovery race checkpoint for Mary Ann set to: ", iWomanNextCheckpoint)
ENDPROC
/// PURPOSE:
/// Keep track of Mary Ann's checkpoint progress during the race
PROC RCM_UPDATE_WOMAN_CHECKPOINTS()
FLOAT fDistPlayer, fDistWoman
IF IS_ENTITY_AT_COORD(sRCLauncherDataLocal.pedID[MARY_ANN_ID], raceInfo.checkPos[iWomanNextCheckpoint], <<MA_CHECKPOINTSIZE, MA_CHECKPOINTSIZE, MA_CHECKPOINTSIZE>>, FALSE)
iWomanNextCheckpoint++
RCM_DEBUG_PRINTINT("Next Mary Ann checkpoint: ", iWomanNextCheckpoint)
//RCM_DEBUG_PRINTINT("Current closest WP:", iClosestWaypoint)
IF iWomanNextCheckpoint = 22
SET_DRIVE_TASK_DRIVING_STYLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], ENUM_TO_INT(DRIVINGMODE_AVOIDCARS_RECKLESS))
RCM_DEBUG_PRINT("Also setting Mary Ann to never go offroad")
ENDIF
ENDIF
IF iWomanNextCheckpoint >= MAX_CHECKPOINTS // Woman has finished so stop any further checking
iRacePos = 2
bLostRace = TRUE
RCM_DEBUG_PRINT("You lost!")
ELSE
// If Mary Ann misses a checkpoint, this should recover her
IF iWomanNextCheckpoint > 2
IF (GET_WAYPOINT_FOR_CHECKPOINT(iWomanNextCheckpoint)+10) < (iClosestWaypoint)
RCM_DEBUG_PRINTINT("iWomanNextCheckpoint+10 is ", (iWomanNextCheckpoint+10))
RCM_DEBUG_PRINTINT("but iClosestWaypoint is ", iClosestWaypoint)
RCM_DEBUG_PRINT("Re-setting Mary Ann's current checkpoint...")
SET_RECOVERED_CHECKPOINT(iClosestWaypoint)
ENDIF
ENDIF
IF iWomanNextCheckpoint > playerInfo.currentCheck
IF iRacePos != 2
iRacePos = 2
ENDIF
ELIF iWomanNextCheckpoint < playerInfo.currentCheck
IF iRacePos != 1
iRacePos = 1
IF (GET_GAME_TIMER() - iOvertakeSpamTimer) > 3000
bOvertakeOccurred = TRUE
iConversationGapTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ELSE
IF RCM_IS_PLAYER_OK()
fDistPlayer = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), raceInfo.checkPos[playerInfo.currentCheck])
ENDIF
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fDistWoman = GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID]), raceInfo.checkPos[iWomanNextCheckpoint])
ENDIF
IF fDistPlayer > fDistWoman
IF iRacePos != 2
iRacePos = 2
ENDIF
ELSE
IF iRacePos != 1
iRacePos = 1
IF (GET_GAME_TIMER() - iOvertakeSpamTimer) > 3000
bOvertakeOccurred = TRUE
iConversationGapTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handle ending the race early and failing the mission when this is called
PROC RCM_END_RACE_EARLY()
if bLostRace
//RCM_MISSION_FAILED(FAILED_LOST_RACE)
RCM_ADVANCE_STAGE() // Go to Outro
ELSE
// Fail the race if the player gets too far away
IF iRacePos = 2
IF RCM_IS_PLAYER_OK()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
if GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), GET_ENTITY_COORDS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])) > LOST_RANGE
RCM_MISSION_FAILED(FAILED_LEFT_BEHIND)
ENDIF
ENDIF
ENDIF
ENDIF
if GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), raceInfo.checkPos[playerInfo.currentCheck]) > 130
IF playerInfo.currentCheck+1 <= raceInfo.totalChecks // Make sure we don't go array out of bounds if the player is abandoning the race at the last checkpoint
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), raceInfo.checkPos[playerInfo.currentCheck+1]) < 100
RCM_MISSION_FAILED(FAILED_MISSED_CHECK)
ELSE
RCM_MISSION_FAILED(FAILED_ABANDONED)
ENDIF
ELSE
RCM_MISSION_FAILED(FAILED_ABANDONED)
ENDIF
ENDIF
ENDIF
ENDPROC
PROC RECOVER_FROM_PUSH()
// I'd rather have these in the appropriate parts of the recover functionality, but the compiler doesn't like them being defined in a switch... oh well...
VECTOR vWaypointTeleTo
VECTOR vWaypointTeleNext
FLOAT fOldSpeed
SWITCH RecoverState
CASE RECOVER_WAIT
// Do nothing - CHECK_PUSHING() will change this if it's needed
BREAK
CASE RECOVER_NEEDED
WAYPOINT_RECORDING_GET_COORD("Fan2_BikeRoute", iRecoverWaypoint, vWaypointTeleTo)
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]), vWaypointTeleTo) < 2.0
RCM_DEBUG_PRINTINT("*** Mary Ann seems to have got herself back on track, carrying on as normal from #", iRecoverWaypoint)
SET_RECOVERED_CHECKPOINT(iRecoverWaypoint)
RecoverState = RECOVER_WAIT
ENDIF
// Recover when we can't see Mary Ann or if 2.5 seconds pass after she's been pushed off-course
IF (NOT IS_SPHERE_VISIBLE(GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]), 3)
AND NOT IS_SPHERE_VISIBLE(vWaypointTeleTo, 3))
OR (GET_GAME_TIMER() - iRecoverTimer) > 2500
RecoverState = RECOVER_RECOVERING
ENDIF
ENDIF
BREAK
CASE RECOVER_RECOVERING
WAYPOINT_RECORDING_GET_COORD("Fan2_BikeRoute", iRecoverWaypoint, vWaypointTeleTo)
WAYPOINT_RECORDING_GET_COORD("Fan2_BikeRoute", iRecoverWaypoint+1, vWaypointTeleNext)
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
fOldSpeed = GET_ENTITY_SPEED(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID], vWaypointTeleTo)
SET_ENTITY_HEADING_FACE_COORDS(vehBike[MARY_ANN_BIKE_ID], vWaypointTeleNext) // Face next checkpoint
IF NOT IS_PED_IN_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
SET_PED_INTO_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID])
ENDIF
TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING(sRCLauncherDataLocal.pedID[MARY_ANN_ID], vehBike[MARY_ANN_BIKE_ID], "Fan2_BikeRoute", DRIVINGMODE_AVOIDCARS_RECKLESS, 0,
EWAYPOINT_START_FROM_CLOSEST_POINT)
SET_VEHICLE_FORWARD_SPEED(vehBike[MARY_ANN_BIKE_ID], fOldSpeed)
RCM_DEBUG_PRINTINT("*** Teleported Mary Ann to waypoint ", iRecoverWaypoint)
SET_RECOVERED_CHECKPOINT(iRecoverWaypoint)
RecoverState = RECOVER_WAIT
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Check for the player trying to push Mary Ann off the track and fail if she actually goes off one of the cliffs
PROC RCM_CHECK_PUSHING()
IF NOT bGivePushWarning
IF (GET_GAME_TIMER() - iPushTimer) > 3000
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID]) AND IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF IS_ENTITY_TOUCHING_ENTITY(vehBike[PLAYER_BIKE_ID], vehBike[MARY_ANN_BIKE_ID])
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
bGivePushWarning = TRUE
INFORM_STAT_SYSTEM_OF_BOOL_STAT_HAPPENED(FA2_BUMPED_INTO_MARY_ANN)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID]) AND IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF IS_ENTITY_TOUCHING_ENTITY(vehBike[PLAYER_BIKE_ID], vehBike[MARY_ANN_BIKE_ID])
VECTOR pushDir = -GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(vehBike[MARY_ANN_BIKE_ID], GET_ENTITY_COORDS(PLAYER_PED_ID()))
APPLY_FORCE_TO_ENTITY(vehBike[PLAYER_BIKE_ID], APPLY_TYPE_IMPULSE, pushDir, <<0,0,0>>, 0, FALSE, FALSE, TRUE)
ENDIF
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT("Fan2_BikeRoute", GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]), iClosestWaypoint)
ENDIF
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
AND RecoverState != RECOVER_NEEDED
// Vinewood sign hillside
IF IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<797.198792,1150.204712,297.759247>>, <<636.304688,1194.311279,323.591858>>, 33.75)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<529.257446,1137.587402,244.045837>>, <<636.878784,1189.193604,321.858551>>, 33.75)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<595.232422,1124.200073,260.294556>>, <<497.323914,1209.940552,306.278442>>, 30.75)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<510.078430,1209.081177,266.611572>>, <<446.286285,1214.469727,295.925415>>, 30.75)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<433.502319,1264.279175,259.039734>>, <<440.984833,1213.486572,275.721893>>, 18.0)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<436.522522,1281.198608,263.654968>>, <<435.094818,1271.009155,277.885498>>, 11.5)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<441.861053,1238.899902,260.414825>>, <<458.780121,1220.360718,283.416473>>, 11.5)
// Second dirt path leading to forest
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<451.618958,1060.920654,212.001404>>, <<434.743774,1015.888184,251.338745>>, 14.0)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<442.671234,1022.329163,210.537384>>, <<387.165100,1018.869751,244.841858>>, 14.0)
// Forest area
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<374.609375,1002.934387,187.244186>>, <<353.487640,1095.726318,253.139267>>, 14.0)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<362.522095,1059.685425,209.332779>>, <<302.626556,1158.892700,250.179825>>, 14.0)
OR IS_ENTITY_IN_ANGLED_AREA(vehBike[MARY_ANN_BIKE_ID], <<279.92, 1234.31 ,209.726959>>, <<305.605835,1150.026855,246.750626>>, 15.0)
RecoverState = RECOVER_NEEDED
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
WAYPOINT_RECORDING_GET_CLOSEST_WAYPOINT("Fan2_BikeRoute", GET_ENTITY_COORDS(vehBike[MARY_ANN_BIKE_ID]), iRecoverWaypoint)
ENDIF
iRecoverTimer = GET_GAME_TIMER()
ENDIF
ENDIF
// Keep checking if we need to recover from a push
RECOVER_FROM_PUSH()
ENDPROC
/// PURPOSE:
/// Give the player a verbal warning from Mary Ann about pushing her if able
/// This needs to repeat until the warning has actually been given, since it takes a while for the conversation to build
PROC RCM_DO_PUSH_WARNING()
IF bGivePushWarning
IF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_PUSH", CONV_PRIORITY_HIGH)
bGivePushWarning = FALSE
iPushTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Handle changing around Mary Ann's AI style during the race
/// This exists to try and solve B*595794, to make Mary Ann smash through the joggers instead of trying to avoid them and getting knocked off the cliff
PROC RCM_HANDLE_MARY_ANN_AI_STYLE()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
// IF IS_ENTITY_IN_ANGLED_AREA(sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<720.957031,1197.793579,324.516602>>, <<722.723145,1212.702637,328.908997>>, 2.000000)
// RCM_DEBUG_PRINT("*** Setting Mary Ann to PloughThrough")
// SET_DRIVE_TASK_DRIVING_STYLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], ENUM_TO_INT(DRIVINGMODE_PLOUGHTHROUGH))
// ENDIF
IF IS_ENTITY_IN_ANGLED_AREA(sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<591.093323,1192.419312,305.529022>>, <<585.452881,1205.725464,311.526031>>, 2.000000)
RCM_DEBUG_PRINT("*** Setting Mary Ann to AvoidCars_Reckless (if this works)")
SET_DRIVE_TASK_DRIVING_STYLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], ENUM_TO_INT(DRIVINGMODE_AVOIDCARS_RECKLESS))
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Main Countdown state loop
PROC MS_COUNTDOWN()
INT i
IF RCM_INIT_STAGE()
HIDE_STREET_AND_CAR_NAMES_THIS_FRAME()
RCM_DEBUG_PRINT("Init MS_COUNTDOWN")
FORCE_RENDER_IN_GAME_UI(FALSE)
raceInfo.sourcePos = vLongRaceStart[0]
raceInfo.sourceHeading = fLongRaceStart[0]
playerInfo.currentCheck = 1
playerInfo.nextCheck = 2
RCM_RESET_CONVERSATIONS()
IF bUsedSkip
or bIntroSkipped
RCM_DEBUG_PRINT("Doing Countdown init reset...")
//RESET_BIKES()
RESET_MARY_ANN()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
RC_END_CUTSCENE_MODE()
ENDIF
RCM_SETUP_RACE_INFO()
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF RCM_IS_PLAYER_OK()
bDoBikeExit = TRUE
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ELSE
RCM_DEBUG_PRINT("No bike in MS_COUNTDOWN init?")
ENDIF
IF bDoneTrevExit
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_PreventGoingIntoStillInVehicleState, TRUE)
RCM_DEBUG_PRINT("Setting PRF_PreventGoingIntoStillInVehicleState on Trevor")
ENDIF
ENDIF
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], KNOCKOFFVEHICLE_NEVER)
SET_ENTITY_CAN_BE_DAMAGED(vehBike[MARY_ANN_BIKE_ID], FALSE)
SET_VEHICLE_DOORS_LOCKED(vehBike[MARY_ANN_BIKE_ID], VEHICLELOCK_LOCKOUT_PLAYER_ONLY)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(sRCLauncherDataLocal.pedID[MARY_ANN_ID], TRUE)
SET_ENTITY_LOAD_COLLISION_FLAG(sRCLauncherDataLocal.pedID[MARY_ANN_ID], TRUE)
SET_DRIVER_RACING_MODIFIER(sRCLauncherDataLocal.pedID[MARY_ANN_ID], 1.0)
MODIFY_VEHICLE_TOP_SPEED(vehBike[MARY_ANN_BIKE_ID], 125.0)
ENDIF
ENDIF
IF bIntroSkipped
OR IS_REPLAY_IN_PROGRESS()
iWomanNextCheckpoint = 2 // Start opponent from checkpoint 2 as the extra distance when skipping the intro makes her skip 1
ELSE
iWomanNextCheckpoint = 1 // Start opponent from checkpoint 1 normally as the rolling start recording doesn't take us through 0
ENDIF
iRacePos = 2
bPlayerIsOnBike = TRUE
iRoadRageConversationsPlayed = 0
iWomanConversationsPlayed = 0
i = 0
REPEAT NUM_ROAD_RAGE_CONVERSATIONS i
bPlayedRoadRageConversation[i] = FALSE
ENDREPEAT
IF DOES_OBJECT_OF_TYPE_EXIST_AT_COORDS(<<801.714844,1270.138306,359.285522>>, 6.0, prop_fnclink_03gate1)
RCM_DEBUG_PRINT("Unlock gate 1.")
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(prop_fnclink_03gate1, <<801.714844,1270.138306,359.285522>>, FALSE, 0.0)
ENDIF
IF DOES_OBJECT_OF_TYPE_EXIST_AT_COORDS(<<802.921814,1281.675049,359.296234>>, 6.0, prop_fnclink_03gate1)
RCM_DEBUG_PRINT("Unlock gate 2.")
SET_STATE_OF_CLOSEST_DOOR_OF_TYPE(prop_fnclink_03gate1, <<802.921814,1281.675049,359.296234>>, FALSE, 0.0)
ENDIF
IF bUsedSkip
TRIGGER_MUSIC_EVENT("FANATIC2_RESTART1")
ELSE
TRIGGER_MUSIC_EVENT("FANATIC2_START")
ENDIF
IF NOT IS_AUDIO_SCENE_ACTIVE("FANATIC_MIX_SCENE")
START_AUDIO_SCENE("FANATIC_MIX_SCENE")
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ADD_ENTITY_TO_AUDIO_MIX_GROUP(sRCLauncherDataLocal.pedID[MARY_ANN_ID],"FANATIC_MIX_MARY_ANNE")
ENDIF
IF IS_ENTITY_ALIVE(vehBike[MARY_ANN_BIKE_ID])
RCM_DEBUG_PRINT("Trying to add Mary Ann's bike to mix group...")
ADD_ENTITY_TO_AUDIO_MIX_GROUP(vehBike[MARY_ANN_BIKE_ID],"FANATIC_MIX_MARY_BIKE")
ENDIF
ENDIF
// If we're in a replay, fade the screen in now
IF IS_REPLAY_IN_PROGRESS()
SETTIMERA(0)
IF IS_REPLAY_BEING_SET_UP()
END_REPLAY_SETUP(vehBike[PLAYER_BIKE_ID])
ENDIF
WHILE TIMERA() < 750 // Game timer is paused during replays, use TimerA instead!
WAIT(0)
RCM_DEBUG_PRINT("In fade in wait...")
// If we're waiting for the fade, keep doing the rolling start
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ENDWHILE
RC_END_Z_SKIP()
ELSE
IF bIntroSkipped
WHILE (GET_GAME_TIMER() - iFadeTimer) < 1250
WAIT(0)
RCM_DEBUG_PRINT("In fade wait...")
// If we're waiting for the fade, keep doing the rolling start
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
ENDWHILE
SAFE_FADE_SCREEN_IN_FROM_BLACK(DEFAULT, FALSE)
ENDIF
ENDIF
IF bUsedSkip
or bIntroSkipped
bIntroSkipped = FALSE
bUsedSkip = FALSE
bPlayedFinalConv = FALSE
SAFE_DELETE_PED(piJogger1) // Deleting the joggers so we see them again if we've skipped back to the start of the race
SAFE_DELETE_PED(piJogger2) // if the player's skipped the intro, they won't exist yet anyway, so this is safe...
ENDIF
RESET_PLAYER_STAMINA(PLAYER_ID())
PRINT_NOW("FAN2_OBJ", DEFAULT_GOD_TEXT_TIME, 1)
start_time = GET_GAME_TIMER()
iCountdown = GET_GAME_TIMER()
RCM_DEBUG_PRINT("Running MS_COUNTDOWN")
ELSE
//HIDE_HUD_AND_RADAR_THIS_FRAME()
HIDE_STREET_AND_CAR_NAMES_THIS_FRAME()
SET_FAR_RIGHT_TITLE_POSITION_HUD_THIS_FRAME()
DRAW_RACE_HUD((GET_GAME_TIMER() - start_time), "", -1, -1, "", iRacePos, 2)
RUN_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
RCM_DEATH_CHECKS()
RCM_DO_HINT_CAM()
RCM_UPDATE_WOMAN_CHECKPOINTS() // Need to start checking this now because Mary-Ann goes through a checkpoint in the rolling start
IF bDoBikeExit
RCM_DEBUG_PRINT("Continuing push")
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
SET_VEHICLE_FORWARD_SPEED(vehBike[PLAYER_BIKE_ID], START_SPEED)
ENDIF
IF HAS_PLAYER_TOUCHED_STEERING_CONTROLS()
bDoBikeExit = FALSE
ENDIF
ENDIF
IF (GET_GAME_TIMER() - iCountdown) > 2000
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF IS_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[PLAYER_BIKE_ID])
STOP_PLAYBACK_RECORDED_VEHICLE(vehBike[PLAYER_BIKE_ID])
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
RCM_ADVANCE_STAGE()
ELSE // Just in case...
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
RCM_ADVANCE_STAGE()
ENDIF
ENDIF
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RCM_DEBUG_PRINT("Cleaned up MS_COUNTDOWN")
ENDIF
ENDPROC
/// PURPOSE:
/// Main race loop for the mission
PROC MS_RACE()
INT i
IF RCM_INIT_STAGE()
// Carry on drawing the race HUD and running checkpoints during the init frame
SET_FAR_RIGHT_TITLE_POSITION_HUD_THIS_FRAME()
DRAW_RACE_HUD((GET_GAME_TIMER() - start_time), "", -1, -1, "", iRacePos, 2)
RUN_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
RCM_DEBUG_PRINT("Init MS_RACE")
i = 0
REPEAT NUM_BIKES i
IF IS_VEHICLE_OK(vehBike[i])
FREEZE_ENTITY_POSITION(vehBike[i], FALSE)
ENDIF
ENDREPEAT
bFinishedRace = FALSE
bDisplayedGetBackOnBike = FALSE
iPushTimer = GET_GAME_TIMER()
iHonkTimer = GET_GAME_TIMER()
RCM_DEBUG_PRINT("Run MS_RACE")
ELSE
IF bUsedSkip
RC_END_Z_SKIP()
bUsedSkip = FALSE
ENDIF
SET_FAR_RIGHT_TITLE_POSITION_HUD_THIS_FRAME()
DRAW_RACE_HUD((GET_GAME_TIMER() - start_time), "", -1, -1, "", iRacePos, 2)
RCM_DEATH_CHECKS()
IF bFinishedRace = FALSE
// B*1422947
IF NOT g_savedGlobals.sRandomChars.g_bFanaticHelp
IF NOT IS_HELP_MESSAGE_BEING_DISPLAYED()
PRINT_HELP("FAN_HELP")
g_savedGlobals.sRandomChars.g_bFanaticHelp = TRUE
ENDIF
ENDIF
RUN_PLAYER_CHECKPOINTS_AND_BLIPS(playerInfo, raceInfo)
RCM_UPDATE_WOMAN_CHECKPOINTS()
RCM_CHECK_PLAYER_ON_BIKE()
RCM_HONK_NEAR_PLAYER()
RCM_DRIVE_PAST_PLAYER()
RCM_JOG_PAST_PLAYER()
RCM_CYCLE_PAST_PLAYER()
RCM_END_RACE_EARLY()
RCM_HANDLE_MARY_ANN_AI_STYLE()
RCM_DO_HINT_CAM()
IF bPlayerIsOnBike = TRUE
MANAGE_SLIDY_BLIP_FOR_ENTITY(opponentBlip, sRCLauncherDataLocal.pedID[MARY_ANN_ID], TRUE)
UPDATE_CHASE_BLIP(opponentBlip, sRCLauncherDataLocal.pedID[MARY_ANN_ID], LOST_RANGE, 0.8)
ELSE
SAFE_REMOVE_BLIP(opponentBlip)
ENDIF
IF bPlayerIsOnBike = TRUE
RCM_MANAGE_PENULTIMATE_CONVERSATION()
RCM_TRY_ROAD_RAGE_CONVERSATION()
RCM_CHECK_PUSHING()
ENDIF
RCM_MANAGE_CONVERSATIONS()
RCM_MANAGE_BIKE_SPEED()
IF playerInfo.racerStatus = RACER_STATUS_FINISHED
INT piR, piG, piB, piA
GET_HUD_COLOUR(HUD_COLOUR_WHITE, piR, piG, piB, piA)
PrevAlpha = 180
VECTOR tempPos = <<279.85, 946.37, 209.82>>
tempPos += <<0,0,7.5>>
playerInfo.PrevCheckpoint = CREATE_CHECKPOINT(CHECKPOINT_RACE_GROUND_FLAG, tempPos, <<279.85, 946.37, 209.82>>, 20, PiR, PiG, PiB, PrevAlpha)
SET_CHECKPOINT_CYLINDER_HEIGHT(playerInfo.PrevCheckpoint,3.0,3.0,100)
SET_CHECKPOINT_RGBA(playerInfo.PrevCheckpoint, PiR, PiG, PiB, PrevAlpha)
SET_CHECKPOINT_RGBA2(playerInfo.PrevCheckpoint, PiR, PiG, PiB, PrevAlpha)
bFinishedRace = TRUE
finish_time = GET_GAME_TIMER()
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF IS_WAYPOINT_PLAYBACK_GOING_ON_FOR_VEHICLE(vehBike[MARY_ANN_BIKE_ID])
REMOVE_WAYPOINT_RECORDING("Fan2_BikeRoute")
BRING_VEHICLE_TO_HALT(vehBike[MARY_ANN_BIKE_ID], 4.0, 1)
ENDIF
ENDIF
ENDIF
ELSE
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
if not IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
bFinishedRace = FALSE // If player has got off the bike, go back to the race and make sure it's definitely ended
ELSE
TRIGGER_MUSIC_EVENT("FANATIC2_STOP")
RCM_DEBUG_PRINT("Doing music trigger stop")
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(vehBike[PLAYER_BIKE_ID], 10, 1, 0.3)
RCM_DEBUG_PRINTINT("Total race time: ", (finish_time - start_time))
IF (finish_time - start_time) <= 102000 // Race time 1:42, 102,000 seconds!
INFORM_STAT_SYSTEM_OF_BOOL_STAT_HAPPENED(FA2_QUICK_WIN)
ENDIF
ENDIF
ENDIF
RCM_ADVANCE_STAGE()
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RCM_STOP_ANY_ACTIVE_CONVERSATION(FALSE)
RCM_DEBUG_PRINT("Cleaned up MS_RACE")
ENDIF
ENDPROC
PROC MS_OUTRO()
IF playerInfo.PrevCheckpoint != NULL
PrevAlpha -= 25
IF PrevAlpha > 0
INT piR, piG, piB, piA
GET_HUD_COLOUR(HUD_COLOUR_WHITE, piR, piG, piB, piA)
SET_CHECKPOINT_RGBA(playerInfo.PrevCheckpoint, piR, piG, piB, PrevAlpha)
SET_CHECKPOINT_RGBA2(playerInfo.PrevCheckpoint, piR, piG, piB, PrevAlpha)
ELSE
DELETE_CHECKPOINT(playerInfo.PrevCheckpoint)
ENDIF
ENDIF
IF RCM_INIT_STAGE()
RCM_DEBUG_PRINT("Init MS_OUTRO")
IF bUsedSkip
RC_END_Z_SKIP()
bUsedSkip = FALSE
ENDIF
bDoneTrevCelebrate = FALSE
RCM_REMOVE_RACE_BLIPS()
RCM_REMOVE_ALL_BLIPS()
REPLAY_RECORD_BACK_FOR_TIME(10.0, 15.0, REPLAY_IMPORTANCE_LOW)
RCM_DEBUG_PRINT("Running MS_OUTRO")
ELSE
IF NOT bLostRace
SWITCH iCutsceneStage
CASE 0
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
RCM_REMOVE_ALL_BLIPS()
RCM_REMOVE_RACE_BLIPS()
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARY_ANN_ID]) > 80
IF CREATE_CONVERSATION(sOutroConversation, "FAN2AU", "FAN2_BIGWIN", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("Player won by large margin")
RCM_REMOVE_ALL_BLIPS()
RCM_REMOVE_RACE_BLIPS()
SAFE_RELEASE_PED(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
bReleaseMAEarly = TRUE
WAIT(500)
iCutsceneStage++
ENDIF
ELIF CREATE_CONVERSATION(sOutroConversation, "FAN2AU", "FAN2_WIN", CONV_PRIORITY_HIGH)
RCM_DEBUG_PRINT("Player won normally")
IF IS_ENTITY_ALIVE(PLAYER_PED_ID()) AND IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(),sRCLauncherDataLocal.pedID[MARY_ANN_ID], -1, SLF_WHILE_NOT_IN_FOV|SLF_WIDEST_PITCH_LIMIT|SLF_WIDEST_YAW_LIMIT, SLF_LOOKAT_VERY_HIGH)
TASK_LOOK_AT_ENTITY(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PLAYER_PED_ID(), -1, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH)
CLEAR_PED_TASKS(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
ENDIF
iCutsceneStage++
ENDIF
ELSE
RCM_DEBUG_PRINT("Mary Ann not found in the outro?!")
ENDIF
BREAK
CASE 1
IF NOT bReleaseMAEarly
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID]) AND IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF NOT IS_VEHICLE_STOPPED(vehBike[MARY_ANN_BIKE_ID])
RCM_DEBUG_PRINT("Bringing Mary Ann to a halt...")
BRING_VEHICLE_TO_HALT(vehBike[MARY_ANN_BIKE_ID], 2.0, 1)
ELSE
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF NOT bDoneTrevCelebrate
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF NOT IS_VEHICLE_STOPPED(vehBike[PLAYER_BIKE_ID])
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(vehBike[PLAYER_BIKE_ID], 10, 1, 0.3)
ELSE
IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehBike[PLAYER_BIKE_ID])
TASK_PLAY_ANIM(PLAYER_PED_ID(), "rcmfanatic2", "celebrate_a", DEFAULT, DEFAULT, -1, AF_UPPERBODY)
bDoneTrevCelebrate = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
IF GET_CURRENT_SCRIPTED_CONVERSATION_LINE() > 3
IF IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
MODIFY_VEHICLE_TOP_SPEED(vehBike[MARY_ANN_BIKE_ID], 0.0) // Resets top speed back to default
ENDIF
// If Mary Ann's overshot the toilet shed, don't do the first drive-to (B*1316809)
IF IS_ENTITY_IN_ANGLED_AREA(sRCLauncherDataLocal.pedID[MARY_ANN_ID], <<282.217926,954.202698,209.251694>>, <<279.217010,937.984924,213.628647>>, 14.0)
OPEN_SEQUENCE_TASK(seq)
TASK_VEHICLE_DRIVE_TO_COORD(NULL, vehBike[MARY_ANN_BIKE_ID], << 262.37, 961.25, 209.75 >>, 13, DRIVINGSTYLE_NORMAL, modelPlayerBike, DRIVINGMODE_AVOIDCARS, 5, 50)
TASK_VEHICLE_DRIVE_WANDER(NULL, vehBike[MARY_ANN_BIKE_ID], 16, DRIVINGMODE_STOPFORCARS)
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], seq)
CLEAR_SEQUENCE_TASK(seq)
iCutsceneStage++
ELSE
OPEN_SEQUENCE_TASK(seq)
TASK_VEHICLE_DRIVE_TO_COORD(NULL, vehBike[MARY_ANN_BIKE_ID], << 281.59, 951.66, 209.85 >>, 7, DRIVINGSTYLE_NORMAL, modelPlayerBike, DRIVINGMODE_PLOUGHTHROUGH, 3, 50)
TASK_VEHICLE_DRIVE_TO_COORD(NULL, vehBike[MARY_ANN_BIKE_ID], << 262.37, 961.25, 209.75 >>, 13, DRIVINGSTYLE_NORMAL, modelPlayerBike, DRIVINGMODE_AVOIDCARS, 5, 50)
TASK_VEHICLE_DRIVE_WANDER(NULL, vehBike[MARY_ANN_BIKE_ID], 16, DRIVINGMODE_STOPFORCARS)
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], seq)
CLEAR_SEQUENCE_TASK(seq)
iCutsceneStage++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
IF NOT bDoneTrevCelebrate
IF IS_VEHICLE_OK(vehBike[PLAYER_BIKE_ID])
IF NOT IS_VEHICLE_STOPPED(vehBike[PLAYER_BIKE_ID])
BRING_VEHICLE_TO_HALT_AND_DISABLE_VEH_CONTROLS(vehBike[PLAYER_BIKE_ID], 10, 1, 0.3)
ELSE
TASK_PLAY_ANIM(PLAYER_PED_ID(), "rcmfanatic2", "celebrate_a", DEFAULT, DEFAULT, -1, AF_UPPERBODY)
bDoneTrevCelebrate = TRUE
iCutsceneStage++
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
CASE 2
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_ADVANCE_STAGE()
ENDIF
BREAK
ENDSWITCH
ELSE
SWITCH iCutsceneStage
CASE 0
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_ANY_CONVERSATION()
iCutsceneStage++
ELSE
iCutsceneStage++
ENDIF
BREAK
CASE 1
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARY_ANN_ID]) < 25
IF IS_PED_UNINJURED(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
AND IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
IF NOT IS_VEHICLE_STOPPED(vehBike[MARY_ANN_BIKE_ID])
RCM_DEBUG_PRINT("Bringing Mary Ann to a halt...")
BRING_VEHICLE_TO_HALT(vehBike[MARY_ANN_BIKE_ID], 2.0, 1)
ELIF CREATE_CONVERSATION(sWomanConversation, "FAN2AU", "FAN2_MAWIN", CONV_PRIORITY_HIGH)
// Play Mary Ann's winning animations here
TASK_PLAY_ANIM(sRCLauncherDataLocal.pedID[MARY_ANN_ID], "rcmfanatic2", "celebrate_b", DEFAULT, DEFAULT, -1, AF_UPPERBODY)
TASK_LOOK_AT_ENTITY(PLAYER_PED_ID(),sRCLauncherDataLocal.pedID[MARY_ANN_ID], -1, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH)
TASK_LOOK_AT_ENTITY(sRCLauncherDataLocal.pedID[MARY_ANN_ID], PLAYER_PED_ID(), -1, SLF_WHILE_NOT_IN_FOV, SLF_LOOKAT_VERY_HIGH)
iCutsceneStage++
WAIT(0) // Just wait a frame to ensure the convo starts
ENDIF
ENDIF
ELSE
RCM_MISSION_FAILED(FAILED_LOST_RACE)
ENDIF
BREAK
CASE 2
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
RCM_MISSION_FAILED(FAILED_LOST_RACE)
ENDIF
BREAK
ENDSWITCH
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RCM_STOP_ANY_ACTIVE_CONVERSATION()
RCM_DEBUG_PRINT("Cleaned up MS_OUTRO")
ENDIF
ENDPROC
/// PURPOSE:
/// Main loop to handle the end of the race
PROC MS_RESULT()
IF RCM_INIT_STAGE()
RCM_DEBUG_PRINT("Init MS_RESULT")
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARY_ANN_ID])
AND IS_VEHICLE_OK(vehBike[MARY_ANN_BIKE_ID])
SET_PED_CAN_BE_KNOCKED_OFF_VEHICLE(sRCLauncherDataLocal.pedID[MARY_ANN_ID], KNOCKOFFVEHICLE_DEFAULT)
SET_ENTITY_CAN_BE_DAMAGED(vehBike[MARY_ANN_BIKE_ID], TRUE)
SET_VEHICLE_DOORS_LOCKED(vehBike[MARY_ANN_BIKE_ID], VEHICLELOCK_UNLOCKED)
ENDIF
RCM_DEBUG_PRINT("Running MS_RESULT")
ELSE
IF bLostRace = FALSE
or bSkipToEnd
RCM_ADVANCE_STAGE()
ELSE
RCM_MISSION_FAILED(FAILED_LOST_RACE)
ENDIF
ENDIF
IF RCM_CLEANUP_STAGE()
RCM_DEBUG_PRINT("Cleaned up MS_RESULT")
ENDIF
ENDPROC
// ===========================================================================================================
// Script Loop
// ===========================================================================================================
SCRIPT(g_structRCScriptArgs sRCLauncherDataIn)
sRCLauncherDataLocal = sRCLauncherDataIn
RC_TakeEntityOwnership(sRCLauncherDataLocal)
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]")
TRIGGER_MUSIC_EVENT("FANATIC2_FAIL")
Random_Character_Failed()
Script_Cleanup()
ENDIF
IF Is_Replay_In_Progress() // Set up the initial scene for replays
OR IS_REPEAT_PLAY_ACTIVE()
g_bSceneAutoTrigger = TRUE
eInitialSceneStage = IS_REQUEST_SCENE
WHILE NOT SetupScene_FANATIC_2(sRCLauncherDataLocal)
WAIT(0)
ENDWHILE
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, FALSE)
g_bSceneAutoTrigger = FALSE
ENDIF
vehBike[PLAYER_BIKE_ID] = sRCLauncherDataLocal.vehID[0]
vehBike[MARY_ANN_BIKE_ID] = sRCLauncherDataLocal.vehID[1]
mScenarioBlocker = Fan2_Scenario_Blocker()
CLEAR_AREA_OF_PEDS(<<816.30, 1275.61, 359.50>>, 75.0)
IF IS_PED_UNINJURED(PLAYER_PED_ID())
relGroupPlayer = GET_PED_RELATIONSHIP_GROUP_HASH(PLAYER_PED_ID())
ENDIF
// Loop within here until the mission passes or fails
WHILE(TRUE)
REPLAY_CHECK_FOR_EVENT_THIS_FRAME("SF_EDT")
WAIT(0)
UPDATE_MISSION_NAME_DISPLAYING(sRCLauncherDataLocal.sIntroCutscene, TRUE)
RCM_DEATH_CHECKS()
HANDLE_GLOBAL_STAMINA_HELP()
SWITCH missionStage
CASE stateInit
MS_INIT()
BREAK
CASE stateIntro
MS_INTRO()
BREAK
CASE stateCountdown
MS_COUNTDOWN()
BREAK
CASE stateRace
MS_RACE()
BREAK
CASE stateOutro
MS_OUTRO()
BREAK
CASE stateResult
MS_RESULT()
BREAK
CASE stateMissionPassed
Script_Passed()
BREAK
CASE stateMissionFailed
MS_FAILED()
BREAK
ENDSWITCH
DEBUG_Check_Debug_Keys()
ENDWHILE
// Script should never reach here. Always terminate with cleanup function.
ENDSCRIPT