// ***************************************************************************************** // ***************************************************************************************** // ***************************************************************************************** // // 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], <>, 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