// ***************************************************************************************** // // SCRIPT NAME : replay_controller.sc // AUTHOR : Andy Minghella // DESCRIPTION : Controls the setting up and activation of mission replays. // // ***************************************************************************************** //Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. USING "commands_brains.sch" USING "replay_public.sch" USING "shop_public.sch" USING "RC_Launcher_public.sch" USING "script_misc.sch" #IF IS_DEBUG_BUILD USING "replay_debug.sch" USING "flow_debug_GAME.sch" USING "debug_channels_structs.sch" USING "commands_debug.sch" BOOL bWaitingForFlowToStart = FALSE // Used to avoid replays being setup just before flow setup begins after using debug menu #ENDIF BOOL bForceSkipReplayScreen = FALSE // Used for callbacks since they don't all terminate the script BOOL bCallbacksSetup = FALSE BOOL bFadeInOnSkipReplayScreen = FALSE INT iButtonNumber = 0 // used to display the button prompts in correct order BOOL bScreenAlreadyFading = FALSE // used in special cases like start of FBI 1 BOOL bSetSystemTime = FALSE //Used to set the scaleform to use the system timer, see B* 2036584 // variables used for handling replay warps INT iReplayWarpTimer ENUM REPLAY_SCREEN_BUTTONS RSB_NONE, RSB_OK, RSB_YES, RSB_RETRY, RSB_NO, RSB_EXIT, RSB_RESTART, RSB_FORCE_RESTART, RSB_SKIP_SECTION, RSB_SKIP_MISSION ENDENUM // =========================================================================================================== // Cleanup // =========================================================================================================== /// PURPOSE: /// Ensures that the script gets a chance to cleanup under specific circumstances (ie: moving from SP to MP) PROC Script_Cleanup() CPRINTLN(DEBUG_REPLAY, "Replay controller cleaning up.") #IF IS_DEBUG_BUILD Delete_Replay_Debug_Widgets() #ENDIF Cleanup_Replay_Controller() CPRINTLN(DEBUG_REPLAY, "Replay controller thread terminating now.") g_replay.replayStageID = RS_NOT_RUNNING TERMINATE_THIS_THREAD() ENDPROC /// PURPOSE: /// Used to skip over the replay screen, and reset any changes made. PROC SkipReplayScreen(BOOL bFadeIn #IF IS_DEBUG_BUILD , BOOL bDebugMenuCleanup #ENDIF) CPRINTLN(DEBUG_REPLAY, "Replay screen was skipped- J/F skip or debug menu cleanup.") IF bFadeIn DO_SCREEN_FADE_IN(0) ENDIF SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_HUD) ResetCommonReplayChanges() // If we were part way through setting up a replay we need to handle it as rejected IF IS_REPLAY_BEING_PROCESSED() // set state to one which passes GET_MISSION_FLOW_SAFE_TO_CLEANUP + wait for cleanup g_replay.replayStageID = RS_REJECTING Wait_For_Mission_To_Cleanup() CLEAR_TIMECYCLE_MODIFIER() // then handle it as rejected CPRINTLN(DEBUG_REPLAY, "SkipReplayScreen: Mission script terminated, treating as rejected", g_replay.replayScriptName) RESET_MISSION_STATS_SYSTEM() TERMINATE_STAT_WATCHER() //B* 2194192 Replay_RejectionCleanup() ELSE #IF IS_DEBUG_BUILD // replay isn't being processed, // need to enter the waiting for flow state // to avoid trying to setup a replay just as the gameflow setup begins IF bDebugMenuCleanup = TRUE IF g_savedGlobals.sFlow.isGameflowActive = TRUE // don't need this in debug mode bWaitingForFlowToStart = TRUE g_replay.replayStageID = RS_WAITING_FOR_FLOW CPRINTLN(DEBUG_REPLAY, "Entering RS_WAITING_FOR_FLOW.") ENDIF ENDIF #ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the chosen button prompt as the next button in the current list /// PARAMS: /// eButton - the replay button propt (ok, yes, no, restart etc) PROC DrawButtonPrompt(REPLAY_SCREEN_BUTTONS eButton) STRING eButtonIcon STRING sButtonString CONTROL_ACTION eButtonClickInput = MAX_INPUTS SWITCH eButton CASE RSB_OK eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) sButtonString = "REPLAY_OK" eButtonClickInput = INPUT_FRONTEND_ACCEPT BREAK CASE RSB_YES eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) sButtonString = "REPLAY_YES" eButtonClickInput = INPUT_FRONTEND_ACCEPT BREAK CASE RSB_RETRY eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) sButtonString = "REPLAY_RETRY" eButtonClickInput = INPUT_FRONTEND_ACCEPT BREAK CASE RSB_NO eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) sButtonString = "REPLAY_NO" eButtonClickInput = INPUT_FRONTEND_CANCEL BREAK CASE RSB_EXIT eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) sButtonString = "REPLAY_EXIT" eButtonClickInput = INPUT_FRONTEND_CANCEL BREAK CASE RSB_RESTART eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_Y) sButtonString = "REPLAY_RESTART" eButtonClickInput = INPUT_FRONTEND_Y BREAK CASE RSB_FORCE_RESTART eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) sButtonString = "REPLAY_RESTART" eButtonClickInput = INPUT_FRONTEND_ACCEPT BREAK CASE RSB_SKIP_SECTION eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_X) sButtonString = "REPLAY_SKIP_S" eButtonClickInput = INPUT_FRONTEND_X BREAK CASE RSB_SKIP_MISSION eButtonIcon = GET_CONTROL_INSTRUCTIONAL_BUTTONS_STRING(FRONTEND_CONTROL, INPUT_FRONTEND_X) sButtonString = "REPLAY_SKIP_M" eButtonClickInput = INPUT_FRONTEND_X BREAK DEFAULT // no button, exit EXIT BREAK ENDSWITCH // set data slot info for this button BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "SET_DATA_SLOT") SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(iButtonNumber) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INSTRUCTIONAL_BUTTONS(eButtonIcon) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(sButtonString) // Add clickable input [PC platform only] IF IS_PC_VERSION() IF eButtonClickInput = MAX_INPUTS SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(FALSE) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(ENUM_TO_INT(MAX_INPUTS)) ELSE SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(ENUM_TO_INT(eButtonClickInput)) ENDIF ENDIF END_SCALEFORM_MOVIE_METHOD() CPRINTLN(DEBUG_REPLAY, "button prompt set up for button: ", iButtonNumber) iButtonNumber++ ENDPROC /// PURPOSE: /// Checks if we are currently handling shitskips /// (Shitskips not handled during restart confirmation screens) /// RETURNS: /// True if we are handling shitskips FUNC BOOL HandleShitskips() IF g_bShitskipOffered = TRUE AND g_replay.replayStageID <> RS_SCREEN_RESTART_CONFIRMATION // don't show shitskip on confirmation screen RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks whether shitskips are allowed for this mission type /// And whether this mission has been failed enough for a shitskip /// If so it displays the correct button prompt (skip section / mission) /// PARAMS: /// bShitskipsAllowed - is this type of replay screen allowed to show the "skip" option? PROC DrawShitskipButtonPrompts(BOOL bShitskipsAllowed = TRUE) IF bShitskipsAllowed = TRUE IF HandleShitskips() IF g_bShitskipToEnd = TRUE DrawButtonPrompt(RSB_SKIP_MISSION) ELSE DrawButtonPrompt(RSB_SKIP_SECTION) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Returns whether the button prompts scaleform movie has loaded /// This needs to be checked before setting up any button prompts /// RETURNS: /// TRUE if scaleform has loaded, FALSE otherwise FUNC BOOL HasButtonsScaleformLoaded() RETURN HAS_SCALEFORM_MOVIE_LOADED(g_replay.mFailButtonsScaleform) ENDFUNC /// PURPOSE: /// Requests the fail screen scaleform PROC RequestScaleform() // main scaleform IF g_replay.mFailTextScaleform = NULL g_replay.mFailTextScaleform = REQUEST_SCALEFORM_MOVIE("MP_BIG_MESSAGE_FREEMODE") bSetSystemTime = FALSE ELSE IF NOT HAS_SCALEFORM_MOVIE_LOADED(g_replay.mFailTextScaleform) g_replay.mFailTextScaleform = REQUEST_SCALEFORM_MOVIE("MP_BIG_MESSAGE_FREEMODE") ENDIF ENDIF // instructional buttons IF g_replay.mFailButtonsScaleform = NULL g_replay.mFailButtonsScaleform = REQUEST_SCALEFORM_MOVIE("INSTRUCTIONAL_BUTTONS") ELSE IF NOT HAS_SCALEFORM_MOVIE_LOADED(g_replay.mFailButtonsScaleform) g_replay.mFailButtonsScaleform = REQUEST_SCALEFORM_MOVIE("INSTRUCTIONAL_BUTTONS") ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws button prompts for 2 buttons /// Then handles the shitskip button prompts /// (This ensures that the skip options are always the last button prompts) /// PARAMS: /// eButton1 - 1st button to display /// eButton2 - 2nd button to display PROC DrawButtonPrompts(REPLAY_SCREEN_BUTTONS eButton1, REPLAY_SCREEN_BUTTONS eButton2, BOOL bAllowShitskips = TRUE) // check if player has switched between mouse/joypad IF IS_PC_VERSION() IF HAVE_CONTROLS_CHANGED(FRONTEND_CONTROL) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BUTTONS_SETUP)) ENDIF IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) SET_MOUSE_CURSOR_THIS_FRAME() ENDIF ENDIF IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BUTTONS_SETUP)) IF HasButtonsScaleformLoaded() // only do the setup once the scaleform has loaded // reset the button number (so buttons get displayed in correct order) iButtonNumber = 0 // clear all BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "CLEAR_ALL") END_SCALEFORM_MOVIE_METHOD() // clear space BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "SET_CLEAR_SPACE") SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(200) END_SCALEFORM_MOVIE_METHOD() // set background colour BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "SET_BACKGROUND_COLOUR") SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(80) END_SCALEFORM_MOVIE_METHOD() // enable clickable input [PC platform only] IF IS_PC_VERSION() BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "TOGGLE_MOUSE_BUTTONS") SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) END_SCALEFORM_MOVIE_METHOD() ENDIF // Set up each button DrawButtonPrompt(eButton1) DrawButtonPrompt(eButton2) DrawShitskipButtonPrompts(bAllowShitskips) CPRINTLN(DEBUG_REPLAY, "Replay button prompts have been setup.") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BUTTONS_SETUP)) // draw the buttons BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailButtonsScaleform, "DRAW_INSTRUCTIONAL_BUTTONS") END_SCALEFORM_MOVIE_METHOD() ENDIF ENDIF ENDPROC /// PURPOSE: /// Displays the question text if we have any, otherwise the fail reason /// PARAMS: /// sQuestionText - text label of the question text to use PROC HANDLE_SECONDARY_FAIL_TEXT(STRING sQuestionText) IF NOT IS_STRING_NULL_OR_EMPTY(sQuestionText) // if we have question text, display it SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(sQuestionText) ELSE // otherwise show fail reason #IF IS_DEBUG_BUILD // show a debug fail reason if we don't have one set IF IS_STRING_NULL_OR_EMPTY(g_txtMissionFailReason) g_txtMissionFailReason= "REPLAY_NFR" CPRINTLN(DEBUG_REPLAY, "Setting fail reason to debug fail.") ENDIF #ENDIF // handle string insertions IF IS_STRING_NULL_OR_EMPTY(g_txtMissionFailAddText) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(g_txtMissionFailReason) ELSE BEGIN_TEXT_COMMAND_SCALEFORM_STRING(g_txtMissionFailReason) ADD_TEXT_COMPONENT_SUBSTRING_TEXT_LABEL(g_txtMissionFailAddText) END_TEXT_COMMAND_SCALEFORM_STRING() ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the replay screen /// PARAMS: /// sQuestionText - the question text to be displayed /// bButtonPrompts - display the button prompts /// bShowFailReason- If true we show the fail reason, otherwise we show the question text. /// bDoAudio - only true while we need to play the failed audio (before screen faded out) PROC DrawReplayScreen(STRING sQuestionText, BOOL bButtonPrompts = TRUE, BOOL bDoAudio = FALSE) RequestScaleform() SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_FADE) // fail screen scaleforms IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_TEXT_SCALE_LOADED)) IF HAS_SCALEFORM_MOVIE_LOADED(g_replay.mFailTextScaleform) // set bit once scaleform has loaded IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_TEXT_SCALE_LOADED)) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_TEXT_SCALE_LOADED)) // set transition time g_replay.fTextTransitionTime = GET_GAME_TIMER() + (FAIL_TRANSITION_DELAY * FAIL_OUT_EFFECT_SLO_MO) ENDIF //Set scaleform to use system timer IF NOT bSetSystemTime CPRINTLN(debug_replay,"Setting scaleform to use system timer") SET_SCALEFORM_MOVIE_TO_USE_SYSTEM_TIME(g_replay.mFailTextScaleform,TRUE) bSetSystemTime = true ENDIF ELSE CPRINTLN(DEBUG_REPLAY, "Loading replay scaleform movie, mFailTextScaleform.") ENDIF ENDIF // only do the fail text if scaleform has loaded IF HAS_SCALEFORM_MOVIE_LOADED(g_replay.mFailTextScaleform) // draw the scaleform DRAW_SCALEFORM_MOVIE_FULLSCREEN(g_replay.mFailTextScaleform,255,255,255,0) //#2053591 - Don't record footage for the Rockstar Editor while drawing a fail screen. REPLAY_PREVENT_RECORDING_AND_UI_THIS_FRAME() IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_QUESTION_SETUP)) // set info for fail text CPRINTLN(DEBUG_REPLAY, "Updating info for scaleform, mFailTextScaleform.") BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailTextScaleform, "SHOW_SHARD_CENTERED_MP_MESSAGE_LARGE") IF g_replay.replayType = REPLAY_TYPE_MINIGAME OR IS_REPLAY_MISSION_A_RAMPAGE() // minigames, bail bonds + rampages just say failed SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("REPLAY_TMG") ELSE SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("REPLAY_T") // mission failed ENDIF HANDLE_SECONDARY_FAIL_TEXT(sQuestionText) SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(100.0) SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(TRUE) END_SCALEFORM_MOVIE_METHOD() SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_QUESTION_SETUP)) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_2ND_TEXT_SETUP)) CPRINTLN(DEBUG_REPLAY, "Updated Fail text with '",sQuestionText) ENDIF // handle the secondary text (fail reason / question) IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_2ND_TEXT_SETUP)) BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailTextScaleform, "UPDATE_MESSAGE") HANDLE_SECONDARY_FAIL_TEXT(sQuestionText) END_SCALEFORM_MOVIE_METHOD_RETURN_VALUE() CPRINTLN(DEBUG_REPLAY, "Updating secondary text now with '",sQuestionText) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_2ND_TEXT_SETUP)) ENDIF // transition the fail message up the screen IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DONE_TRANSITION)) // if we've paused before transition has finished- unpause Replay_Pause_Game(FALSE) IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_STARTED_TRANSITION)) CDEBUG1LN(debug_replay,"Started transition bit not set: ",GET_GAME_TIMER(),"/",g_replay.fTextTransitionTime) // transition hasn't started yet, is it time? IF GET_GAME_TIMER() > g_replay.fTextTransitionTime CDEBUG1LN(debug_replay,"Starting transition") // start the transition now BEGIN_SCALEFORM_MOVIE_METHOD(g_replay.mFailTextScaleform, "TRANSITION_UP") SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(0.15 * FAIL_OUT_EFFECT_SLO_MO) END_SCALEFORM_MOVIE_METHOD_RETURN_VALUE() SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_STARTED_TRANSITION)) // set the time that the transition will be complete g_replay.fTextTransitionTime = GET_GAME_TIMER() + (150 * FAIL_OUT_EFFECT_SLO_MO) CPRINTLN(DEBUG_REPLAY, "Triggering text transition now 1") ELSE CPRINTLN(DEBUG_REPLAY, "Waiting to do text transition: ", GET_GAME_TIMER()) ENDIF ENDIF //Bug 1926954: If the fade-out is hurried up, make sure the RB_DONE_TRANSITION bit is set in the same frame IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_STARTED_TRANSITION)) CDEBUG1LN(debug_replay,"Checking if transition finished:", GET_GAME_TIMER(),"/",g_replay.fTextTransitionTime) // transition has been started, has it finished? IF GET_GAME_TIMER() > g_replay.fTextTransitionTime CPRINTLN(DEBUG_REPLAY, "Text transition finished") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DONE_TRANSITION)) IF bButtonPrompts = TRUE // if we're not paused after started showing button prompts, pause now CPRINTLN(DEBUG_REPLAY, "Pausing as transition done, as we're showing button prompts") Replay_Pause_Game(TRUE) ENDIF ENDIF ENDIF ENDIF IF bDoAudio = TRUE // play the audio as the text appears IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) // don't try to play audio after we've faded out IF IS_SCREEN_FADED_OUT() AND IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DONE_TRANSITION)) // already faded out, don't do audio CPRINTLN(DEBUG_REPLAY, "Already faded and done transition. Don't do Texthit audio") ELSE IF g_replay.iFailSoundID = -1 g_replay.iFailSoundID = GET_SOUND_ID() PLAY_SOUND_FRONTEND(g_replay.iFailSoundID, "TextHit", "MissionFailedSounds") CPRINTLN(DEBUG_REPLAY, "Playing fail audio now. TextHit") ENDIF ENDIF ENDIF ENDIF ENDIF IF bButtonPrompts = TRUE IF iButtonNumber > 0 // button prompts (only do this if we've set a button to display) IF NOT HasButtonsScaleformLoaded() CPRINTLN(DEBUG_REPLAY, "Loading replay scaleform movie, mFailButtonsScaleform.") EXIT ENDIF DRAW_SCALEFORM_MOVIE_FULLSCREEN(g_replay.mFailButtonsScaleform, 255,255,255,0) ENDIF ENDIF ENDPROC /// PURPOSE: /// Resets scaleform setup variables as we need to change text / button prompts /// Updates state to go to correct screen PROC ChangeReplayScreen(g_eReplayStages eStage) CPRINTLN(DEBUG_REPLAY, "Changing replay screen to ", eStage) ResetScaleformSetupVariables() g_replay.replayStageID = eStage ENDPROC /// PURPOSE: /// Sets the replay stage to show correct fail screen based on which replay type we are processing PROC SetReplayScreenType() SWITCH g_replay.replayType CASE REPLAY_TYPE_MISSION_FORCE_RESTART IF IS_REPEAT_PLAY_ACTIVE() // in repeat play, just use the default screen for this mission ChangeReplayScreen(RS_SCREEN_DEFAULT) ELSE ChangeReplayScreen(RS_SCREEN_FORCE_RESTART) ENDIF BREAK CASE REPLAY_TYPE_FAIL_SCREEN_ONLY ChangeReplayScreen(RS_SCREEN_FAIL_ONLY) BREAK DEFAULT ChangeReplayScreen(RS_SCREEN_DEFAULT) // this currently covers these replay types: // REPLAY_TYPE_MISSION, REPLAY_TYPE_RANDOM_CHARACTER, REPLAY_TYPE_MINIGAME // REPLAY_TYPE_MICHAEL_EVENT, REPLAY_TYPE_PHONECALL_TRIGGER BREAK ENDSWITCH ENDPROC // =========================================================================================================== // Replay Progression Control Functions // =========================================================================================================== /// PURPOSE: /// Shows the fail reason and triggers fail effects /// If the player was killed / arrested it waits for code to fade the screen out /// Moves on to RS_SCREEN_FORCE_RESTART, RS_SCREEN_FAIL_ONLY or RS_SCREEN_DEFAULT PROC Replay_Do_Blur() // TimerA is reset when fail effect is triggered // and is used to time triggering of fail out effect // TimerB is reset when failOut effect is triggered // and is used to time when to fade out // debug stuff #IF IS_DEBUG_BUILD IF g_bDebugDisableFailScreen //Replay screens blocked. Cancel replay. Reset_All_Replay_Variables() EXIT ENDIF #ENDIF // Trigger the death fail effect here IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) AND NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_OUT_EFFECT_TRIGGERED)) IF IS_SCREEN_FADED_OUT() // if we're already faded out, skip to showing the fail reason // special case for FBI 1 fail cut-scene CPRINTLN(DEBUG_REPLAY, "Skipping initial fail effect as screen is faded out") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) SETTIMERA(CEIL(FAIL_EFFECT_TIME * FAIL_EFFECT_SLO_MO)) Replay_Control_Slow_Motion(TRUE, 1) ELSE // not started fail effect, do it now Replay_Control_Fail_Effect(TRUE) PLAY_SOUND_FRONTEND(-1, "ScreenFlash", "MissionFailedSounds") CPRINTLN(DEBUG_REPLAY, "Playing fail audio now. ScreenFlash") SETTIMERA(0) ENDIF // start audio scene as effect appears Replay_Control_Audio_Scene(TRUE) // ------------other stuff that only needs to be done once-------------- DISABLE_CELLPHONE(TRUE) //Added for bug 1591786 // block the death jingle, so we don't get 2 fail sounds played // if the player dies during the fail screen Replay_Block_Death_Jingle(TRUE) Replay_Block_Damage_Overlay(TRUE) // clear stunt jump display CANCEL_STUNT_JUMP() Replay_Block_Load_Screen(TRUE) // check if screen is already fading out (used for special cases like start of FBI1) IF IS_SCREEN_FADING_OUT() OR IS_SCREEN_FADED_OUT() bScreenAlreadyFading = TRUE // block load screen so failed screen displays correctly (needs to be done as close to fade out as possible) ELSE bScreenAlreadyFading = FALSE ENDIF // B*1575302 - We need to clear the mission title during a fail MISSION_FLOW_CLEAR_DISPLAY_MISSION_TITLE() // kill chase hint cam effects IF IS_GAMEPLAY_HINT_ACTIVE() CPRINTLN(DEBUG_REPLAY, "Stopping hint effects") ANIMPOSTFX_STOP("FocusIn") ANIMPOSTFX_PLAY("FocusOut",0,false) STOP_GAMEPLAY_HINT() ENDIF //Unblock the respawn controller CPRINTLN(DEBUG_REPLAY,"Unblocking the respawn controller") CLEAR_BIT(g_replay.iReplayBits,ENUM_TO_INT(RB_BLOCK_RESPAWN)) ENDIF // things we need to block every frame // remove any god text / subtitles IF NOT IS_CUTSCENE_PLAYING() CLEAR_PRINTS() ELSE // block load screen so failed screen displays correctly // (needs to be done as close to fade out as possible) Replay_Block_Load_Screen(TRUE) ENDIF // hide the feed THEFEED_HIDE_THIS_FRAME() // disable the pause menu during fail screen DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE) // block aggresive cop clean-up SUPPRESS_AMBIENT_PED_AGGRESSIVE_CLEANUP_THIS_FRAME() //#2067723 - Ensure the game is in 3rd person view on all fail screens. DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_NEXT_CAMERA) DISABLE_ON_FOOT_FIRST_PERSON_VIEW_THIS_UPDATE() // stop player from being able to right upside down vehicles IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_VEH_CONT)) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_LR) DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_UD) ENDIF // don't let the player use the sniper scope (since HUD needs to be hidden) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) WEAPON_TYPE mCurrentWeapon GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), mCurrentWeapon) IF mCurrentWeapon = WEAPONTYPE_SNIPERRIFLE OR mCurrentWeapon = WEAPONTYPE_HEAVYSNIPER OR mCurrentWeapon = WEAPONTYPE_REMOTESNIPER DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_AIM) ENDIF ENDIF ENDIF // disable weapon switching Disable_Weapon_Select(TRUE) // load the fail screen audio + play sound as soon as loaded IF Load_Replay_Audio() IF NOT IS_SCREEN_FADED_OUT() IF g_replay.iFailBedSoundID = -1 g_replay.iFailBedSoundID = GET_SOUND_ID() PLAY_SOUND_FRONTEND(g_replay.iFailBedSoundID, "Bed", "MissionFailedSounds") CPRINTLN(DEBUG_REPLAY, "Playing fail audio now. Bed") ENDIF ENDIF ENDIF // check if it is time to start showing fail text CDEBUG1LN(debug_replay,"Show fail text time: ",TIMERA(),"/",FAIL_EFFECT_TIME * FAIL_EFFECT_SLO_MO) IF TIMERA() > FAIL_EFFECT_TIME * FAIL_EFFECT_SLO_MO // Display the mission failed text DrawReplayScreen("", FALSE, TRUE) // Trigger the Death Fail Out Effect here IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_OUT_EFFECT_TRIGGERED)) // not started fail out effect, do it now + pause the game Replay_Block_Load_Screen(TRUE) //Block the load screen early Replay_Control_Fail_Out_Effect(TRUE) SETTIMERB(0) ELSE // we are waiting for the fail out effect to finish // check if effect has finished CDEBUG1LN(debug_replay,"---Check if effect has finished: ",TIMERB(),"/",FAIL_OUT_EFFECT_TIME * FAIL_OUT_EFFECT_SLO_MO) IF TIMERB() > FAIL_OUT_EFFECT_TIME * FAIL_OUT_EFFECT_SLO_MO OR (IS_SCREEN_FADED_OUT() // used for skipping fail cut-scenes AND bScreenAlreadyFading = FALSE) // if screen was already fading out for a special case, wait as normal CDEBUG1LN(debug_replay,"Finished fadeout effect") // --------finished fail out effect ------------------------------ // start fading out IF NOT IS_SCREEN_FADED_OUT() IF NOT IS_SCREEN_FADING_OUT() AND NOT IS_CUTSCENE_PLAYING() SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_FADE) DO_SCREEN_FADE_OUT(FAIL_FADE_OUT_TIME) // block load screen so failed screen displays correctly (needs to be done as close to fade out as possible) Replay_Block_Load_Screen(TRUE) ENDIF ELSE // -------------screen has faded out-------------------------- // Do necessary setup, and then move on to showing the replay screen CPRINTLN(DEBUG_REPLAY, "\nFail effect for script [", GET_THIS_SCRIPT_NAME(), "] completed.") // disable player control IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), FALSE) ENDIF // stuff that needs to be set after fade SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE) DISABLE_CELLPHONE(TRUE) SET_FRONTEND_ACTIVE(FALSE) SET_PAUSE_MENU_ACTIVE(FALSE) CLEAR_HELP() CLEAR_PRINTS() Replay_Control_Audio_Scene(FALSE) RESET_RETICULE_VALUES() IF IS_GAMEPLAY_CAM_SHAKING() STOP_GAMEPLAY_CAM_SHAKING(TRUE) ENDIF KILL_ANY_CONVERSATION() IF IS_PLAYER_SWITCH_IN_PROGRESS() STOP_PLAYER_SWITCH() CPRINTLN(DEBUG_REPLAY, "Stopping current player switch") ENDIF STOP_ALL_ALARMS(TRUE) // ------Wait here for a short time before updating the fail text--------- // brief delay before showing the button prompts //DrawReplayScreen("", FALSE) FLOAT fDelayTimer = GET_GAME_TIMER() + (FAIL_PROMPT_DELAY *FAIL_OUT_EFFECT_SLO_MO) WHILE GET_GAME_TIMER() < fDelayTimer //B*1926954: Keep waiting until the text transition finishes OR GET_GAME_TIMER() < g_replay.fTextTransitionTime WAIT(0) DrawReplayScreen("", FALSE) ENDWHILE // store vehicle's velocity before pause IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) VEHICLE_INDEX mPlayerVehicle = GET_PLAYERS_LAST_VEHICLE() IF DOES_ENTITY_EXIST(mPlayerVehicle) IF IS_VEHICLE_DRIVEABLE(mPlayerVehicle) g_replay.vVehicleVelocity = GET_ENTITY_VELOCITY(mPlayerVehicle) CPRINTLN(DEBUG_REPLAY, "Stored velocity as g_replay.vVehicleVelocity x= ", g_replay.vVehicleVelocity.x, " y= ", g_replay.vVehicleVelocity.y, " z= ", g_replay.vVehicleVelocity.z) ENDIF ENDIF ENDIF ENDIF // pause the game (only if we've done the text transition) IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DONE_TRANSITION)) Replay_Pause_Game(TRUE) ENDIF // set which state we're moving on to // based on which replay type we are configuring SetReplayScreenType() ENDIF ELSE CDEBUG1LN(DEBUG_REPLAY, "Accepting input, TimerB = .", TIMERB()) // Allow player to skip to the retry options IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) AND (TIMERB() 0 sQuestionText = "" DrawButtonPrompts(RSB_RETRY, RSB_RESTART) // Fail reason + A: RETRY Y: RESTART ELSE sQuestionText = "" DrawButtonPrompts(RSB_FORCE_RESTART, RSB_NONE) // Fail reason + A: RESTART ENDIF DrawReplayScreen(sQuestionText) //-----------Wait for selection button press-------------------------------------------- IF HandleShitskips() AND IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_X) PLAY_SOUND_FRONTEND(-1, "SKIP", "HUD_FRONTEND_DEFAULT_SOUNDSET") ChangeReplayScreen(RS_SCREEN_SKIP_CONFIRMATION) ELSE // not shitskipping- handle other options IF g_replay.replayStageReadOnly > 0 // retry from checkpoint, or restart IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "RETRY", "HUD_FRONTEND_DEFAULT_SOUNDSET") Replay_Player_Has_Accepted(FALSE) ELSE IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_Y) PLAY_SOUND_FRONTEND(-1, "RESTART", "HUD_FRONTEND_DEFAULT_SOUNDSET") // player is choosing restart over checkpoint- give confirmation screen ChangeReplayScreen(RS_SCREEN_RESTART_CONFIRMATION) ENDIF ENDIF ELSE IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "RESTART", "HUD_FRONTEND_DEFAULT_SOUNDSET") // player is choosing to restart, when he has made no progress, same as accepting replay Replay_Player_Has_Accepted(FALSE) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the restart confirmation screen and waits for the player to respond /// Moves on to one of these: /// REPLAY_PREPARE_ACTIVATION (player has accepted restarting from the beginning) /// RS_SCREEN_FORCE_RESTART (player has cancelled restarting from begininng, back to previous screen) PROC Display_RS_SCREEN_RESTART_CONFIRMATION() DoCommonReplayScreenSetup() DrawButtonPrompts(RSB_YES,RSB_NO, FALSE) // Restarting the mission will result in losing checkpoint progress. Are you sure you want to restart? A: YES B: NO DrawReplayScreen("REPLAY_AYS") //-----------Wait for selection button press-------------------------------------------- IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "YES", "HUD_FRONTEND_DEFAULT_SOUNDSET") Replay_Player_Has_Accepted(TRUE) ELSE // handle player rejecting replay IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) PLAY_SOUND_FRONTEND(-1, "NO", "HUD_FRONTEND_DEFAULT_SOUNDSET") // rejecting a restart confirmation screen takes you back to the force restart screen ChangeReplayScreen(RS_SCREEN_FORCE_RESTART) ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the replay rejection confirmation screen and waits for the player to respond /// Moves on to one of these: /// RS_NOT_REQUIRED (player has confirmed rejecting the non story / flow mission) /// RS_REJECTED (player has confirmed rejecting the story / flow mission) /// PREVIOUS SCREEN: If player cancels rejection we return to one of the other fail screens /// Currently if cancelled this always goes back to RS_SCREEN_DEFAULT as it is only one that offers replay rejection PROC Display_RS_SCREEN_REJECT_CONFIRMATION() DoCommonReplayScreenSetup() DrawButtonPrompts(RSB_YES,RSB_NO, FALSE) // Exiting the mission will result in losing mission progress. Are you sure you want to exit? A: YES B: NO DrawReplayScreen("REPLAY_REJ") //-----------Wait for selection button press-------------------------------------------- IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "YES", "HUD_FRONTEND_DEFAULT_SOUNDSET") CPRINTLN(DEBUG_REPLAY, "Player rejected replay") Replay_Player_Has_Rejected() ELSE // handle player rejecting replay IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) PLAY_SOUND_FRONTEND(-1, "NO", "HUD_FRONTEND_DEFAULT_SOUNDSET") // rejecting a restart confirmation screen takes you back to the previous replay screen CPRINTLN(DEBUG_REPLAY, "Player rejected reject confirmation screen, going back to previous screen") SetReplayScreenType() ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the shitskip confirmation screen and waits for the player to respond /// Moves on to one of these: /// REPLAY_PREPARE_ACTIVATION (player has accepted the shitskip) /// PREVIOUS SCREEN: If player cancels the shitskip we return to one of the other fail screens PROC Display_RS_SCREEN_SKIP_CONFIRMATION() DoCommonReplayScreenSetup() DrawButtonPrompts(RSB_YES,RSB_NO, FALSE) IF g_bShitskipToEnd = TRUE DrawReplayScreen("REPLAY_SKIPM") // Are you sure you want to skip this mission? A: YES B: NO ELSE DrawReplayScreen("REPLAY_SKIPS") // Are you sure you want to skip this section? A: YES B: NO ENDIF //-----------Wait for selection button press-------------------------------------------- IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "YES", "HUD_FRONTEND_DEFAULT_SOUNDSET") CPRINTLN(DEBUG_REPLAY, "Player accepted shitskip") g_bShitskipAccepted = TRUE INFORM_MISSION_STATS_SYSTEM_OF_SHITSKIP() //Update the profile stat tracking how many times this player has skipped a checkpoint. INT iTimesSkipped STAT_GET_INT(TIMES_MISSION_SKIPPED, iTimesSkipped) STAT_SET_INT(TIMES_MISSION_SKIPPED, iTimesSkipped+1) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Replay_Player_Has_Accepted(FALSE) ELSE // handle player rejecting shitskip IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_CANCEL) PLAY_SOUND_FRONTEND(-1, "NO", "HUD_FRONTEND_DEFAULT_SOUNDSET") // rejecting a shitskip confirmation screen takes you back to the previous replay screen CPRINTLN(DEBUG_REPLAY, "Player rejected shitskip confirmation screen, going back to previous screen") SetReplayScreenType() ENDIF ENDIF ENDPROC /// PURPOSE: /// Draws the Fail Only mission reaply screen and waits for the player to respond /// Moves on to one of these: /// RS_NOT_REQUIRED (player rejected non story / flow mission) /// RS_REJECTED (player rejected replay on a story / flow mission) PROC Display_RS_SCREEN_FAIL_ONLY() DoCommonReplayScreenSetup() DrawButtonPrompts(RSB_OK, RSB_NONE, FALSE) // fail reason + A: OK DrawReplayScreen(" ") //-----------Wait for selection button press-------------------------------------------- IF IS_CONTROL_JUST_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) PLAY_SOUND_FRONTEND(-1, "OK", "HUD_FRONTEND_DEFAULT_SOUNDSET") CPRINTLN(DEBUG_REPLAY, "Player rejected replay- fail only") Replay_Player_Has_Rejected() ENDIF ENDPROC /// PURPOSE: /// Sets the bit that lets the mission know it is being replayed PROC Setup_Mission_Specific_Replay_State() CPRINTLN(DEBUG_REPLAY, "Setting up Mission replay state.") // Stop the flow from prestreaming intro mocaps for replayed missions. g_eMissionIDToLoadCutscene = SP_MISSION_NONE g_bFlowLoadIntroCutscene = FALSE g_bFlowLoadRequestStarted = FALSE g_bFlowCleanupIntroCutscene = TRUE g_bFlowLoadingIntroCutscene = FALSE IF IsThisAPrepMission() CPRINTLN(DEBUG_REPLAY, "Accepted replay for prep mission") // set replay as rejected for prep missions // as we don't want them to retrigger (just re-blip) // also need to clear the candidate ID as the mission needs to be able to retrigger normally Replay_RejectionCleanup() ELSE SET_BIT(g_availableMissions[Get_Available_Mission_Index_For_Stored_Mission(g_replay.replayCoreVarsIndex)].bitflags, BITS_AVAILABLE_MISSION_BEING_REPLAYED) ENDIF ENDPROC /// PURPOSE: /// Flag a global flag to inform all minigame launchers that a minigame replay is ready to be processed. PROC Setup_Minigame_Specific_Replay_State() CPRINTLN(DEBUG_REPLAY, "Setting up Minigame replay state.") g_bLaunchMinigameReplay = TRUE ENDPROC /// PURPOSE: /// Sets up any requirements for an RC mission to trigger its replay /// then waits until the replay activates PROC Setup_Random_Character_Specific_Replay_State() CPRINTLN(DEBUG_REPLAY, "Setting up Random Character replay state. for ", g_replay.replayScriptName) //Get RC mission data. g_eRC_MissionIDs eRCMissionID = Get_RC_MissionID_For_Script(g_replay.replayScriptName) g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(eRCMissionID, sRCMissionDetails) // Unpause the game here, so we can do the warp / reactivate properly Replay_Pause_Game(FALSE) g_structRCScriptArgs sRCLauncherData // Scene information to pass to mission script RC_Reset_LauncherData(sRCLauncherData) sRCLauncherData.sScriptName = g_replay.replayScriptName sRCLauncherData.eMissionID = eRCMissionID INFORM_MISSION_STATS_SYSTEM_OF_RESTART() WHILE NOT LAUNCH_RC_MISSION(sRCLauncherData) WAIT(0) CPRINTLN(DEBUG_REPLAY, "Waiting for RC mission to relaunch.") ENDWHILE CPRINTLN(DEBUG_REPLAY, "RC mission has relaunched.") SET_RC_AS_RUNNING(eRCMissionID) ENDPROC /// PURPOSE: /// Waits for player to respawn, sets him to have at least a decent amount of health /// Sets up any specific requirements for this replay type then resets common replay changes (enables phone etc) /// Moves on to RS_ACTIVE PROC ReplayActivate() BOOL bDoFade = TRUE #IF IS_DEBUG_BUILD bDoFade = bFadeOut // skip the fade? #ENDIF // DO NOT CHECK THIS IN!! DEBUG ONLY! //#IF IS_DEBUG_BUILD BREAK_ON_NATIVE_COMMAND("NEW_LOAD_SCENE_START_SPHERE", FALSE) #ENDIF //#IF IS_DEBUG_BUILD BREAK_ON_NATIVE_COMMAND("SET_GAMEPLAY_CAM_RELATIVE_HEADING", FALSE) #ENDIF //#IF IS_DEBUG_BUILD BREAK_ON_NATIVE_COMMAND("SET_GAMEPLAY_CAM_RELATIVE_PITCH", FALSE) #ENDIF IF DOES_MISSION_USE_NEW_REPLAY_SYSTEM() IF IsThisAPrepMission() = FALSE // for normal replays, don't let the replay controller get paused // so it can handle the teleport whilst the mission sets up CPRINTLN(DEBUG_REPLAY, "Using new replay warp system for this mission.") SET_THIS_SCRIPT_CAN_BE_PAUSED(FALSE) g_eReplayWarpStage = RWS_WAIT ENDIF ENDIF // Fade out if needed IF bDoFade = TRUE AND NOT IS_SCREEN_FADED_OUT() AND NOT IS_SCREEN_FADING_OUT() DO_SCREEN_FADE_OUT(0) ENDIF // Ensure player health is at a minimum level (ensure this is after the player swap). IF NOT IS_PED_INJURED(PLAYER_PED_ID()) INT iPlayerHealth = GET_ENTITY_HEALTH(PLAYER_PED_ID()) CPRINTLN(DEBUG_REPLAY, "Current Player Health: ", iPlayerHealth) IF (iPlayerHealth < MINIMUM_REPLAY_HEALTH) CPRINTLN(DEBUG_REPLAY, "Health for Replay too low. Being boosted to ", MINIMUM_REPLAY_HEALTH, ".") SET_ENTITY_HEALTH(PLAYER_PED_ID(), MINIMUM_REPLAY_HEALTH) ENDIF ENDIF // launcher setup IF DoesThisReplayTypeUseStoryMissionLauncher() Setup_Mission_Specific_Replay_State() ELSE SWITCH g_replay.replayType CASE REPLAY_TYPE_MINIGAME Setup_Minigame_Specific_Replay_State() BREAK CASE REPLAY_TYPE_RANDOM_CHARACTER Setup_Random_Character_Specific_Replay_State() BREAK DEFAULT SCRIPT_ASSERT("Replay_Controller: Wrong replay type in Maintain_Wait_Until_Replay_Ready_To_Launch()") BREAK ENDSWITCH ENDIF IF IsThisAPrepMission() = FALSE // prep missions handle this stuff via the rejection cleanup // as they don't actually launch the mission again //TODO, add check here for invalidation type relating to bug 536824 IF GET_REPLAY_MID_MISSION_STAGE()!= 0 INFORM_MISSION_STATS_SYSTEM_OF_RESTART() ENDIF //ELSE // INFORM_MISSION_STATS_SYSTEM_OF_RESTART(TRUE) //ENDIF // reset necessary replay variables Reset_Fail_Warp_Location() ResetFailReasons() ENDIF ResetCommonReplayChanges() WAIT(0) // wait needed as we are unpausing IF IsThisAPrepMission() = FALSE // prep missions handle this stuff via the rejection cleanup // as they don't actually launch the mission again // Replay now active - mission flow should take over now and re-launch the script. g_replay.replayStageID = RS_ACTIVE ELSE // slight delay before fading back in so we don't see repopulated area peds not having anims WAIT(500) CPRINTLN(DEBUG_REPLAY, "Fading screen back in for prep mission.") DO_SCREEN_FADE_IN(DEFAULT_FADE_TIME) ENDIF ENDPROC // =========================================================================================================== // Script Loop // =========================================================================================================== SCRIPT CPRINTLN(DEBUG_REPLAY, "Replay_controller.sc is now being launched.") #IF IS_DEBUG_BUILD Initialise_Replay_Debug_Widgets() #ENDIF WHILE (TRUE) // ----------------------Handle debug menu callback -------------------------- IF bCallbacksSetup = FALSE CPRINTLN(DEBUG_REPLAY, "bCallbacksSetup = false.") bCallbacksSetup = TRUE bForceSkipReplayScreen = FALSE bFadeInOnSkipReplayScreen = FALSE CPRINTLN(DEBUG_REPLAY, "SETTING UP CALLBACKS.") IF HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_DEBUG_MENU | FORCE_CLEANUP_FLAG_SP_TO_MP | FORCE_CLEANUP_FLAG_MAGDEMO | FORCE_CLEANUP_FLAG_REPEAT_PLAY) SWITCH GET_CAUSE_OF_MOST_RECENT_FORCE_CLEANUP() CASE FORCE_CLEANUP_FLAG_DEBUG_MENU CPRINTLN(DEBUG_REPLAY, "Replay_controller.sc skipping replay: DebugMenu force cleanup.") bForceSkipReplayScreen = TRUE bFadeInOnSkipReplayScreen = TRUE bCallbacksSetup = FALSE BREAK CASE FORCE_CLEANUP_FLAG_REPEAT_PLAY CPRINTLN(DEBUG_REPLAY, "Replay_controller.sc skipping replay: Repeat Play force cleanup.") bForceSkipReplayScreen = TRUE bFadeInOnSkipReplayScreen = FALSE bCallbacksSetup = FALSE BREAK CASE FORCE_CLEANUP_FLAG_SP_TO_MP CPRINTLN(DEBUG_REPLAY, "Replay_controller.sc has been forced to cleanup SP to MP.") Script_Cleanup() BREAK CASE FORCE_CLEANUP_FLAG_MAGDEMO CPRINTLN(DEBUG_REPLAY, "Replay_controller.sc has been forced to cleanup Magdemo.") Script_Cleanup() BREAK DEFAULT // other force cleanups are ignored BREAK ENDSWITCH ENDIF ENDIF If bForceSkipReplayScreen = TRUE CPRINTLN(DEBUG_REPLAY, "Skipping replay screen caused by debug menu force cleanup.") SkipReplayScreen(bFadeInOnSkipReplayScreen #IF IS_DEBUG_BUILD ,TRUE #ENDIF) ELSE // -----------------------Debug stuff-------------------------------- #IF IS_DEBUG_BUILD Maintain_Replay_Debug_Widgets() //Allow us to F / J skip replays. (J skip is used by missionTester / autoplaythrough) IF IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F) OR IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J) IF IsReplayWaitingForReplayScreen() SkipReplayScreen(TRUE #IF IS_DEBUG_BUILD ,FALSE #ENDIF) ENDIF ENDIF #ENDIF BOOL bCheckState = TRUE #IF IS_DEBUG_BUILD // only check replay stage if gameflow isn't being setup // or we're in the RS_WAITING_FOR_FLOW stage IF g_flowUnsaved.bUpdatingGameflow = FALSE OR g_replay.replayStageID = RS_WAITING_FOR_FLOW bCheckState = TRUE ELSE bCheckState = FALSE // Gameflow is updating, so don't try to set up a new replay //CPRINTLN(DEBUG_REPLAY, "Gameflow is busy, so pausing replay controller.") ENDIF #ENDIF // ------------Main Replay Flow ------------------------------------------ IF bCheckState = TRUE SWITCH (g_replay.replayStageID) // If replay controller loads up in this state move straight into not required CASE RS_NOT_RUNNING g_replay.replayStageID = RS_NOT_REQUIRED BREAK // show fail reason, wait if necessary then fade out CASE RS_DO_BLUR Replay_Do_Blur() BREAK // Replay screen for normal missions. CASE RS_SCREEN_DEFAULT Display_RS_SCREEN_DEFAULT() BREAK // Replay screen for force restart missions. CASE RS_SCREEN_FORCE_RESTART Display_RS_SCREEN_FORCE_RESTART() BREAK // Replay screen for force restart missions. CASE RS_SCREEN_RESTART_CONFIRMATION Display_RS_SCREEN_RESTART_CONFIRMATION() BREAK // Replay screen for confirming the player wants to exit the mission. CASE RS_SCREEN_REJECT_CONFIRMATION Display_RS_SCREEN_REJECT_CONFIRMATION() BREAK // Replay screen for confirming the player wants to skip forwards in the mission. CASE RS_SCREEN_SKIP_CONFIRMATION Display_RS_SCREEN_SKIP_CONFIRMATION() BREAK // Replay screen for fail screen only missions. No replay options. CASE RS_SCREEN_FAIL_ONLY Display_RS_SCREEN_FAIL_ONLY() BREAK // Does some setup and terminates the mission thread CASE RS_ACCEPTING // This is handled in Replay_Player_Has_Accepted in replay private // as it needs to run in same frame as player accepting the replay BREAK // Does some setup and terminates the mission thread CASE RS_REJECTING // This is handled in Replay_Player_Has_Accepted in replay private // as it needs to run in same frame as player rejecting the replay BREAK // Waiting for the replay preparations to finish ready to start the replay CASE RS_ACTIVATE ReplayActivate() BREAK // The replay is now active - control has been handed over to the replaying activity CASE RS_ACTIVE IF DOES_MISSION_USE_NEW_REPLAY_SYSTEM() // Handle warping the player into position // Clearing + repopulating area IF g_eReplayWarpStage <> RWS_DONE IF REPLAY_WARP_PLAYER(iReplayWarpTimer) SET_THIS_SCRIPT_CAN_BE_PAUSED(TRUE) ELSE /* #IF IS_DEBUG_BUILD // do not check in! IF g_eReplayWarpStage > RWS_START AND g_eReplayWarpStage < RWS_DONE // warp ongoing, check for player and camera movement VECTOR vPos IF NOT IS_PED_INJURED(PLAYER_PED_ID()) vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) IF GET_DISTANCE_BETWEEN_COORDS(vPos, g_eReplayWarpPos) > 30 SCRIPT_ASSERT("ReplayWarp: Player moved too far from g_eReplayWarpPos!") ENDIF vPos = GET_GAMEPLAY_CAM_COORD() IF GET_DISTANCE_BETWEEN_COORDS(vPos, g_eReplayWarpPos) > 30 SCRIPT_ASSERT("ReplayWarp: Camera moved too far from g_eReplayWarpPos!") ENDIF ENDIF ENDIF #ENDIF */ ENDIF ENDIF ENDIF BREAK // The player has rejected the replay, and we have done the teleport etc (story / flow only) CASE RS_REJECTED // This is currently only used by story missions to get the mission flow to work correctly // Flow waits for replay to finish processing, // Then if it was rejected, cleans up + moves on, otherwise it relaunches mission BREAK // Not currently processing a replay and a replay is not being played CASE RS_NOT_REQUIRED IF NOT(IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_FRIENDS) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY_PREP) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_CHAR) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_MINIGAME) OR IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_MINIGAME_FRIENDS)) CPRINTLN(DEBUG_REPLAY, "Cleaning up replay controller as there are no missions running to service.") Script_Cleanup() ENDIF BREAK // debug only states #IF IS_DEBUG_BUILD // A debug menu force cleanup was triggred // Now wait in this state until flow setup is done // So a replay can't be offered just before flow setup begins CASE RS_WAITING_FOR_FLOW IF bWaitingForFlowToStart = TRUE IF g_flowUnsaved.bUpdatingGameflow = FALSE //CPRINTLN(DEBUG_REPLAY, "Waiting for flow setup to begin.") ELSE bWaitingForFlowToStart = FALSE //CPRINTLN(DEBUG_REPLAY, "Flow setup has started.") ENDIF ELSE IF g_flowUnsaved.bUpdatingGameflow = FALSE //CPRINTLN(DEBUG_REPLAY, "Exiting RS_WAITING_FOR_FLOW.") g_replay.replayStageID = RS_NOT_REQUIRED // Can also get out of this state by calling CleanupReplayController ENDIF ENDIF BREAK #ENDIF DEFAULT SCRIPT_ASSERT("Replay_Controller: Unknown Replay Stage ID") BREAK ENDSWITCH ENDIF ENDIF WAIT (0) ENDWHILE // Script should never reach here. Always terminate with cleanup function. ENDSCRIPT