#if not USE_CLF_DLC #if not USE_NRM_DLC USING "randomchar_private.sch" #endif #endif USING "snapshot_private.sch" USING "commands_water.sch" USING "commands_ped.sch" USING "area_checks.sch" USING "flow_help_public.sch" USING "respawn_location_data.sch" USING "commands_recording.sch" #if USE_CLF_DLC USING "static_mission_data_helpCLF.sch" #endif #if USE_NRM_DLC USING "static_mission_data_helpNRM.sch" #endif #IF IS_DEBUG_BUILD USING "debug_channels_structs.sch" #ENDIF // ***************************************************************************************** // SCRIPT NAME : replay_private.sch // AUTHOR : Andy Minghella // DESCRIPTION : Private Replay functionality. // ***************************************************************************************** CONST_INT RAMPAGE_REJECTION_FADE_TIME 1600 // how long the fade back to gameplay is after rejecting a rampage replay CONST_INT MINIMUM_REPLAY_HEALTH 150 // If health is below this value then set it to this value on a replay CONST_INT FAIL_EFFECT_TIME 2000 // milliseconds before the fail text is shown (how long the fail effect takes) CONST_INT FAIL_OUT_EFFECT_TIME 4000 // how long the fail out effect takes (how long after the text comes on that the fade out starts) CONST_INT FAIL_TRANSITION_DELAY 800 // how long after the text until it moves up the screen CONST_INT FAIL_FADE_OUT_TIME 1000 // how long the fade out is CONST_INT FAIL_PROMPT_DELAY 100 // how long after fade out before prompts shown CONST_FLOAT FAIL_EFFECT_SLO_MO 0.2 // time scale used by the fail effects CONST_FLOAT FAIL_OUT_EFFECT_SLO_MO 0.075 #IF IS_DEBUG_BUILD BOOL bFadeOut = TRUE // set to false to keep replay screen see through (for debugging) #ENDIF // -------------------FUNCTIONS ---------------------------------------------------------- /// PURPOSE: /// Checks if the mission being set up for replay is a rampage /// RETURNS: /// TRUE if rampage, FALSE otherwise FUNC BOOL IS_REPLAY_MISSION_A_RAMPAGE() IF g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER g_eRC_MissionIDs eRCMission = INT_TO_ENUM(g_eRC_MissionIDs, g_replay.replayCoreVarsIndex) IF eRCMission = RC_RAMPAGE_1 OR eRCMission = RC_RAMPAGE_2 OR eRCMission = RC_RAMPAGE_3 OR eRCMission = RC_RAMPAGE_4 OR eRCMission = RC_RAMPAGE_5 CPRINTLN(DEBUG_REPLAY, "IS_REPLAY_MISSION_A_RAMPAGE is true.") RETURN TRUE ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Returns true if this replay type uses the story mission launchers /// Useful for anything that wants to access anything using mission data index /// RETURNS: /// TRUE if this replay type uses the story mission launchers FUNC BOOL DoesThisReplayTypeUseStoryMissionLauncher() IF g_replay.replayType = REPLAY_TYPE_MISSION OR g_replay.replayType = REPLAY_TYPE_MISSION_FORCE_RESTART OR g_replay.replayType = REPLAY_TYPE_FAIL_SCREEN_ONLY OR g_replay.replayType = REPLAY_TYPE_PHONECALL_TRIGGER OR g_replay.replayType = REPLAY_TYPE_MICHAEL_EVENT RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the current mission has been set up to use the new replay warp system /// Once all missions have been set up to use the new system, this will get removed /// RETURNS: /// TRUE if mission uses new replay warp system, FALSE otherwise #if USE_CLF_DLC FUNC BOOL DOES_MISSION_USE_NEW_REPLAY_SYSTEM_CLF() IF DoesThisReplayTypeUseStoryMissionLauncher() // All Clifford missions should use the "new" replay system. RETURN TRUE ENDIF RETURN FALSE ENDFUNC #ENDIF #if USE_NRM_DLC FUNC BOOL DOES_MISSION_USE_NEW_REPLAY_SYSTEM_NRM() IF DoesThisReplayTypeUseStoryMissionLauncher() // All Norman missions should use the "new" replay system. RETURN TRUE ENDIF RETURN FALSE ENDFUNC #ENDIF FUNC BOOL DOES_MISSION_USE_NEW_REPLAY_SYSTEM() //If CLF T playing then run check of new missions instead #if USE_CLF_DLC return DOES_MISSION_USE_NEW_REPLAY_SYSTEM_CLF() #endif #if USE_NRM_DLC return DOES_MISSION_USE_NEW_REPLAY_SYSTEM_NRM() #endif #if not USE_CLF_DLC #if not USE_NRM_DLC IF DoesThisReplayTypeUseStoryMissionLauncher() // story mission SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(g_replay.replayScriptName, FALSE) SWITCH eMissionID CASE SP_MISSION_PROLOGUE RETURN TRUE BREAK CASE SP_MISSION_MICHAEL_1 RETURN TRUE BREAK CASE SP_HEIST_FINALE_2A RETURN TRUE BREAK CASE SP_HEIST_FINALE_2B RETURN TRUE BREAK CASE SP_HEIST_JEWELRY_2 RETURN TRUE BREAK CASE SP_MISSION_ARMENIAN_1 RETURN TRUE BREAK CASE SP_MISSION_ARMENIAN_2 RETURN TRUE BREAK CASE SP_MISSION_ARMENIAN_3 RETURN TRUE BREAK CASE SP_MISSION_CARSTEAL_1 RETURN TRUE BREAK CASE SP_MISSION_CARSTEAL_2 RETURN TRUE BREAK CASE SP_MISSION_CARSTEAL_3 RETURN TRUE BREAK CASE SP_MISSION_CARSTEAL_4 RETURN TRUE BREAK CASE SP_MISSION_TREVOR_1 RETURN TRUE BREAK CASE SP_MISSION_TREVOR_2 RETURN TRUE BREAK CASE SP_MISSION_CHINESE_1 RETURN TRUE BREAK CASE SP_MISSION_CHINESE_2 RETURN TRUE BREAK CASE SP_MISSION_LAMAR RETURN TRUE BREAK CASE SP_MISSION_LESTER_1 RETURN TRUE BREAK CASE SP_HEIST_DOCKS_1 RETURN TRUE BREAK CASE SP_HEIST_DOCKS_2A RETURN TRUE BREAK CASE SP_HEIST_DOCKS_2B RETURN TRUE BREAK CASE SP_MISSION_FBI_3 RETURN TRUE BREAK CASE SP_HEIST_AGENCY_1 RETURN TRUE BREAK CASE SP_HEIST_AGENCY_2 RETURN TRUE BREAK CASE SP_HEIST_AGENCY_PREP_1 RETURN TRUE BREAK CASE SP_HEIST_AGENCY_3B RETURN TRUE BREAK CASE SP_HEIST_JEWELRY_PREP_1A RETURN TRUE BREAK CASE SP_HEIST_JEWELRY_PREP_2A RETURN TRUE BREAK CASE SP_MISSION_FINALE_A RETURN TRUE BREAK CASE SP_MISSION_FINALE_B RETURN TRUE BREAK CASE SP_MISSION_FAMILY_1 RETURN TRUE BREAK CASE SP_MISSION_FAMILY_2 RETURN TRUE BREAK CASE SP_MISSION_FAMILY_3 RETURN TRUE BREAK CASE SP_MISSION_FAMILY_5 RETURN TRUE BREAK CASE SP_MISSION_FAMILY_6 RETURN TRUE BREAK CASE SP_MISSION_FRANKLIN_1 RETURN TRUE BREAK CASE SP_MISSION_FRANKLIN_2 RETURN TRUE BREAK CASE SP_MISSION_SOLOMON_1 RETURN TRUE BREAK CASE SP_HEIST_DOCKS_PREP_1 RETURN TRUE BREAK CASE SP_HEIST_RURAL_1 RETURN TRUE BREAK CASE SP_HEIST_RURAL_PREP_1 RETURN TRUE BREAK CASE SP_HEIST_RURAL_2 RETURN TRUE BREAK CASE SP_HEIST_FINALE_1 RETURN TRUE BREAK CASE SP_HEIST_JEWELRY_PREP_1B RETURN TRUE BREAK CASE SP_MISSION_TREVOR_3 RETURN TRUE BREAK CASE SP_MISSION_TREVOR_4 RETURN TRUE BREAK CASE SP_MISSION_FBI_4_INTRO RETURN TRUE BREAK CASE SP_MISSION_FBI_4_PREP_1 RETURN TRUE BREAK CASE SP_MISSION_FBI_4_PREP_2 RETURN TRUE BREAK CASE SP_MISSION_FBI_4_PREP_4 RETURN TRUE BREAK CASE SP_MISSION_FBI_4_PREP_5 RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_A RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_C1 RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_C2 RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_C3 RETURN TRUE BREAK CASE SP_MISSION_SOLOMON_2 RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_D RETURN TRUE BREAK CASE SP_MISSION_FRANKLIN_0 RETURN TRUE BREAK CASE SP_MISSION_FBI_2 RETURN TRUE BREAK CASE SP_MISSION_EXILE_1 RETURN TRUE BREAK CASE SP_MISSION_EXILE_3 RETURN TRUE BREAK CASE SP_MISSION_FINALE_C1 RETURN TRUE BREAK CASE SP_MISSION_FINALE_C2 RETURN TRUE BREAK CASE SP_MISSION_MICHAEL_2 RETURN TRUE BREAK CASE SP_MISSION_MICHAEL_3 RETURN TRUE BREAK CASE SP_MISSION_MICHAEL_4 RETURN TRUE BREAK CASE SP_MISSION_ME_TRACEY RETURN TRUE BREAK CASE SP_HEIST_DOCKS_PREP_2B RETURN TRUE BREAK CASE SP_HEIST_JEWELRY_1 RETURN TRUE BREAK CASE SP_MISSION_MARTIN_1 RETURN TRUE BREAK CASE SP_MISSION_SOLOMON_3 RETURN TRUE BREAK CASE SP_HEIST_FINALE_PREP_B RETURN TRUE BREAK CASE SP_MISSION_ASSASSIN_1 RETURN TRUE BREAK CASE SP_MISSION_ASSASSIN_2 RETURN TRUE BREAK CASE SP_MISSION_ASSASSIN_3 RETURN TRUE BREAK CASE SP_MISSION_ASSASSIN_4 RETURN TRUE BREAK CASE SP_MISSION_ASSASSIN_5 RETURN TRUE BREAK CASE SP_MISSION_FAMILY_4 RETURN TRUE BREAK CASE SP_MISSION_FBI_1 RETURN TRUE BREAK CASE SP_MISSION_FBI_4 RETURN TRUE BREAK CASE SP_MISSION_FBI_5 RETURN TRUE BREAK CASE SP_MISSION_EXILE_2 RETURN TRUE BREAK CASE SP_HEIST_AGENCY_3A RETURN TRUE BREAK ENDSWITCH ELSE SWITCH g_replay.replayType // RC missions CASE REPLAY_TYPE_RANDOM_CHARACTER g_eRC_MissionIDs eRCMissionID eRCMissionID = Get_RC_MissionID_For_Script(g_replay.replayScriptName) SWITCH eRCMissionID CASE RC_ABIGAIL_2 RETURN TRUE BREAK CASE RC_BARRY_1 RETURN TRUE BREAK CASE RC_BARRY_2 RETURN TRUE BREAK CASE RC_BARRY_3 RETURN TRUE BREAK CASE RC_BARRY_3A RETURN TRUE BREAK CASE RC_BARRY_3C RETURN TRUE BREAK CASE RC_BARRY_4 RETURN TRUE BREAK CASE RC_DREYFUSS_1 RETURN TRUE BREAK CASE RC_EPSILON_3 RETURN TRUE BREAK CASE RC_EPSILON_4 RETURN TRUE BREAK CASE RC_EPSILON_6 RETURN TRUE BREAK CASE RC_EPSILON_7 RETURN TRUE BREAK CASE RC_EPSILON_8 RETURN TRUE BREAK CASE RC_EXTREME_1 RETURN TRUE BREAK CASE RC_EXTREME_2 RETURN TRUE BREAK CASE RC_EXTREME_3 RETURN TRUE BREAK CASE RC_EXTREME_4 RETURN TRUE BREAK CASE RC_FANATIC_1 RETURN TRUE BREAK CASE RC_FANATIC_2 RETURN TRUE BREAK CASE RC_FANATIC_3 RETURN TRUE BREAK CASE RC_HUNTING_1 RETURN TRUE BREAK CASE RC_HUNTING_2 RETURN TRUE BREAK CASE RC_HAO_1 RETURN TRUE BREAK CASE RC_JOSH_2 RETURN TRUE BREAK CASE RC_JOSH_3 RETURN TRUE BREAK CASE RC_JOSH_4 RETURN TRUE BREAK CASE RC_MAUDE_1 RETURN TRUE BREAK CASE RC_NIGEL_1A RETURN TRUE BREAK CASE RC_NIGEL_1B RETURN TRUE BREAK CASE RC_NIGEL_1C RETURN TRUE BREAK CASE RC_NIGEL_1D RETURN TRUE BREAK CASE RC_NIGEL_2 RETURN TRUE BREAK CASE RC_NIGEL_3 RETURN TRUE BREAK CASE RC_MINUTE_1 RETURN TRUE BREAK CASE RC_MINUTE_2 RETURN TRUE BREAK CASE RC_MINUTE_3 RETURN TRUE BREAK CASE RC_MRS_PHILIPS_2 RETURN TRUE BREAK CASE RC_PAPARAZZO_1 RETURN TRUE BREAK CASE RC_PAPARAZZO_2 RETURN TRUE BREAK CASE RC_PAPARAZZO_3A RETURN TRUE BREAK CASE RC_PAPARAZZO_3B RETURN TRUE BREAK CASE RC_PAPARAZZO_4 RETURN TRUE BREAK CASE RC_RAMPAGE_1 RETURN TRUE BREAK CASE RC_RAMPAGE_2 RETURN TRUE BREAK CASE RC_RAMPAGE_3 RETURN TRUE BREAK CASE RC_RAMPAGE_4 RETURN TRUE BREAK CASE RC_RAMPAGE_5 RETURN TRUE BREAK CASE RC_THELASTONE RETURN TRUE BREAK CASE RC_TONYA_1 RETURN TRUE BREAK CASE RC_TONYA_2 RETURN TRUE BREAK CASE RC_TONYA_3 RETURN TRUE BREAK CASE RC_TONYA_4 RETURN TRUE BREAK CASE RC_TONYA_5 RETURN TRUE BREAK ENDSWITCH BREAK // minigames CASE REPLAY_TYPE_MINIGAME IF ARE_STRINGS_EQUAL(g_replay.replayScriptName, "Traffick_Ground") OR ARE_STRINGS_EQUAL(g_replay.replayScriptName, "Traffick_Air") OR ARE_STRINGS_EQUAL(g_replay.replayScriptName, "BailBond1") OR ARE_STRINGS_EQUAL(g_replay.replayScriptName, "BailBond2") OR ARE_STRINGS_EQUAL(g_replay.replayScriptName, "BailBond3") OR ARE_STRINGS_EQUAL(g_replay.replayScriptName, "BailBond4") RETURN TRUE ENDIF BREAK ENDSWITCH ENDIF RETURN FALSE #endif #endif ENDFUNC /// PURPOSE: /// Stops any currently running cut-scene /// This needs to be called before removing player from restricted vehicle /// As if we delete a vehicle while cut-scene is running the game will assert /// PARAMS: PROC REPLAY_WAIT_FOR_CUTSCENE_TO_STOP() BOOL bLoop = TRUE IF IS_CUTSCENE_ACTIVE() WHILE (bLoop) bLoop = IS_CUTSCENE_ACTIVE() IF IS_CUTSCENE_PLAYING() STOP_CUTSCENE() ENDIF IF HAS_CUTSCENE_LOADED() REMOVE_CUTSCENE() ENDIF IF IS_CUTSCENE_ACTIVE() AND NOT IS_CUTSCENE_PLAYING() CPRINTLN(DEBUG_REPLAY, "WAITING FOR CUTSCENE TO STOP - EMERGENCY BREAK OUT!") bLoop = FALSE ENDIF CPRINTLN(DEBUG_REPLAY, "WAITING FOR CUTSCENE TO STOP") WAIT(0) ENDWHILE ENDIF ENDPROC /// PURPOSE: /// Pauses / unpauses the game (only unpauses if replay controller paused the game) /// PARAMS: /// bPause - are we pausing or unpausing? PROC Replay_Pause_Game(BOOL bPause) BOOL bIgnore = FALSE #IF IS_DEBUG_BUILD bIgnore = g_bFlowAutoplayInProgress #ENDIF IF bIgnore = FALSE // don't pause the game if we are doing an auto playthrough IF bPause = TRUE // pause the game IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is pausing the game.") SET_GAME_PAUSED(TRUE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) ENDIF ELSE // unpause the game IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unpausing the game.") SET_GAME_PAUSED(FALSE) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Teleports the player and waits for teleport to complete. Reset camera behind player. /// PARAMS: /// vPos - where to teleport player. /// fHeading - heading to use with teleport. FUNC BOOL Replay_TeleportPlayer(VECTOR vPos, FLOAT fHeading, BOOL bSnapToGround = FALSE, BOOL bRepopulate = TRUE) IF IS_PLAYER_PLAYING(PLAYER_ID()) // start the teleport CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer started") Replay_Pause_Game(FALSE) CLEAR_AREA(vPos, 5.0, TRUE) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) SET_ENTITY_HEADING(PLAYER_PED_ID(), fHeading) SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0) ENDIF ENDIF NEW_LOAD_SCENE_START_SPHERE(vPos, REPLAY_LOAD_SCENE_SIZE) WAIT(0) // wait a frame for the camera to catch up before pausing // clear the area CLEAR_AREA(vPos, 5000, TRUE, FALSE) CLEAR_AREA_OF_OBJECTS(vPos, 5000) REMOVE_PARTICLE_FX_IN_RANGE(vPos, 5000) REMOVE_DECALS_IN_RANGE(vPos, 5000) CLEAR_ALL_MUST_LEAVE_AREA_VEHICLE_GEN_FLAGS() RESET_VEHICLE_GEN_LOADED_CHECKS() // start timer + pause game SETTIMERA(0) Replay_Pause_Game(TRUE) // try to create the new load scene IF NOT IS_NEW_LOAD_SCENE_ACTIVE() WHILE NOT NEW_LOAD_SCENE_START_SPHERE(vPos, REPLAY_LOAD_SCENE_SIZE) WAIT(0) IF TIMERA() > 2000 CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer failed to create load scene- exit.") SET_GAME_PAUSED(FALSE) RETURN FALSE ENDIF ENDWHILE ENDIF // wait for scene to load CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer new load scene succesfully started.") SETTIMERA(0) WHILE NOT IS_NEW_LOAD_SCENE_LOADED() WAIT(0) CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer new load scene still loading: ", TIMERA()) // check for early out IF TIMERA() > REPLAY_LOAD_SCENE_TIMEOUT CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer took too long: early out") SET_GAME_PAUSED(FALSE) // get rid of the stream vol IF IS_NEW_LOAD_SCENE_ACTIVE() NEW_LOAD_SCENE_STOP() ENDIF RETURN FALSE ENDIF // check for debug skip #IF IS_DEBUG_BUILD IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_V)) CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer debug skipping streaming.") SET_GAME_PAUSED(FALSE) // get rid of the stream vol IF IS_NEW_LOAD_SCENE_ACTIVE() NEW_LOAD_SCENE_STOP() ENDIF RETURN FALSE ENDIF #ENDIF ENDWHILE CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer warp finished") // post warp cleanup- then start repopulation // clear and repopulate the area IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) // get rid of the stream vol IF IS_NEW_LOAD_SCENE_ACTIVE() NEW_LOAD_SCENE_STOP() ENDIF // need to unpause for repopulate stuff to work SET_GAME_PAUSED(FALSE) SETTIMERA(0) // refill population INSTANTLY_FILL_PED_POPULATION() IF bRepopulate = TRUE INSTANTLY_FILL_VEHICLE_POPULATION() ELSE // if not doing vehicle repop, set the early out SETTIMERA(5000) ENDIF POPULATE_NOW() ENDIF ENDIF // wait for repopulation to finish WHILE NOT HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED() AND NOT HAVE_ALL_VEHICLE_GENS_LOADED_NEAR_PLAYER() AND TIMERA() < 1500 WAIT(0) CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer waiting for vehicle repopulation.") ENDWHILE IF TIMERA() > 1500 IF bRepopulate = TRUE CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer repopulation took too long, early out.") ELSE CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer skipping vehicle repopulation.") ENDIF ENDIF // ground the player (needs to be done after world has loaded in) IF bSnapToGround = TRUE GET_GROUND_Z_FOR_3D_COORD(vPos, vPos.z) CLEAR_AREA(vPos, 5.0, TRUE) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) SET_ENTITY_HEADING(PLAYER_PED_ID(), fHeading) ENDIF ENDIF ENDIF // reset camera behind player SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0) // finished CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer: repopulation finished") Replay_Pause_Game(FALSE) RETURN TRUE ENDIF CPRINTLN(DEBUG_REPLAY, "Replay_TeleportPlayer: player not playing") Replay_Pause_Game(FALSE) RETURN FALSE ENDFUNC /// PURPOSE: /// Clears out restricted vehicles array. Sets all to null PROC ResetRestrictedVehiclesArray() INT iVehicleNumber FOR iVehiclenumber = 0 TO MAX_RESTRICTED_VEHICLES -1 g_replay.mRestrictedVehicles[iVehicleNumber] = NULL ENDFOR ENDPROC /// PURPOSE: /// Deletes a restricted vehicle. Should be called after player has been taken out of it /// PARAMS: /// mVehicle - the restricted vehicle we want to delete PROC DeleteRestrictedVehicle(VEHICLE_INDEX mVehicle) IF DOES_ENTITY_EXIST(mVehicle) #IF USE_CLF_DLC if spy_vehicle_is_this_vehicle_the_spy_vehicle(mVehicle) spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_remove_all_system_assets(temp_spy_veh_system) else SET_ENTITY_AS_MISSION_ENTITY(mVehicle, TRUE, TRUE) DELETE_VEHICLE(mVehicle) endif #endif #IF not USE_CLF_DLC SET_ENTITY_AS_MISSION_ENTITY(mVehicle, TRUE, TRUE) DELETE_VEHICLE(mVehicle) // delete vehicle #endif CPRINTLN(DEBUG_REPLAY, "DeleteRestrictedVehicle: vehicle deleted") ELSE CPRINTLN(DEBUG_REPLAY, "DeleteRestrictedVehicle- vehicle doesn't exist") ENDIF ENDPROC /// PURPOSE: /// Checks if the player is in the restricted vehicle. /// If he is, we place him where the vehicle is and delete it. /// Otherwise we just delete it /// PARAMS: /// mVehicle - the restricted vehicle /// mVehiclePlayerDiedIn - if the player died in a vehicle we store its vehicle index, so we can delete it after he respawns PROC RemovePlayerFromRestrictedVehicle(VEHICLE_INDEX mVehicle, VEHICLE_INDEX &mVehiclePlayerDiedIn) VECTOR vPos IF DOES_ENTITY_EXIST(mVehicle) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), mVehicle) vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) // get out of vehicle CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID()) SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) IF DOES_ENTITY_EXIST(mVehicle) #IF USE_CLF_DLC if spy_vehicle_is_this_vehicle_the_spy_vehicle(mVehicle) spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_remove_all_system_assets(temp_spy_veh_system) else SET_ENTITY_AS_MISSION_ENTITY(mVehicle, TRUE, TRUE) DELETE_VEHICLE(mVehicle) endif #endif #IF not USE_CLF_DLC SET_ENTITY_AS_MISSION_ENTITY(mVehicle, TRUE, TRUE) DELETE_VEHICLE(mVehicle) // delete vehicle #endif ENDIF SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) // put player on ground CPRINTLN(DEBUG_REPLAY, "RemovePlayerFromRestrictedVehicle: player removed from vehicle") EXIT ELSE IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) AND NOT IS_PED_GETTING_INTO_A_VEHICLE(PLAYER_PED_ID()) IF IS_ENTITY_ATTACHED(PLAYER_PED_ID()) DETACH_ENTITY(PLAYER_PED_ID()) ENDIF ENDIF CPRINTLN(DEBUG_REPLAY, "RemovePlayerFromRestrictedVehicle: player not in vehicle") ENDIF ELSE // player died, if he is in the car we delete it later once he has respawned IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), mVehicle) mVehiclePlayerDiedIn = mVehicle EXIT ENDIF ENDIF ENDIF // player not in vehicle, delete it DeleteRestrictedVehicle(mVehicle) ELSE CPRINTLN(DEBUG_REPLAY, "RemovePlayerFromRestrictedVehicle- vehicle doesn't exist") ENDIF ENDPROC /// PURPOSE: /// Checks the whole of the restricted vehicle array and removes the player from them and deletes them PROC RemovePlayerFromAnyRestrictedVehicle(VEHICLE_INDEX &mVehiclePlayerDiedIn) INT iVehicleNumber FOR iVehiclenumber = 0 TO MAX_RESTRICTED_VEHICLES -1 RemovePlayerFromRestrictedVehicle(g_replay.mRestrictedVehicles[iVehicleNumber], mVehiclePlayerDiedIn) ENDFOR ENDPROC /// PURPOSE: /// Clears visible damage and wetness from the player PROC Clear_Damage_And_Wetness() IF NOT IS_PED_INJURED(PLAYER_PED_ID()) CLEAR_PED_WETNESS(PLAYER_PED_ID()) CLEAR_PED_BLOOD_DAMAGE(PLAYER_PED_ID()) RESET_PED_VISIBLE_DAMAGE(PLAYER_PED_ID()) ENDIF ENDPROC /// PURPOSE: /// Checks if we need to warp the player to a script defined warp location /// Performs the warp if needed. /// This is called when a replay is rejected /// Or when a replay is accepted for a prep mission /// RETURNS: /// TRUE if we have warped the player. FALSE otherwise FUNC BOOL Do_Replay_Rejected_Warp() MODEL_NAMES ePlayerVehicleModel IF ARE_VECTORS_EQUAL(g_vMissionFailWarp, <<0,0,0>>) CPRINTLN(DEBUG_REPLAY, "Leaving the player where they failed the mission.") BOOL bDoGroundedWarp = TRUE IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) ePlayerVehicleModel = GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) IF IS_THIS_MODEL_A_PLANE(ePlayerVehicleModel) OR IS_THIS_MODEL_A_HELI(ePlayerVehicleModel) OR IS_THIS_MODEL_A_BOAT(ePlayerVehicleModel) CPRINTLN(DEBUG_REPLAY, "Not doing grounding warp checks as the player is in a plane/heli/boat.") bDoGroundedWarp = FALSE ENDIF ENDIF IF bDoGroundedWarp IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) IF NOT IS_ENTITY_IN_WATER(PLAYER_PED_ID()) VECTOR vPlayerCoords = GET_ENTITY_COORDS(PLAYER_PED_ID()) float hPlayerhead = GET_ENTITY_HEADING(PLAYER_PED_ID()) FLOAT fGroundZ GET_GROUND_Z_FOR_3D_COORD(vPlayerCoords, fGroundZ) IF ABSF(fGroundZ - vPlayerCoords.Z) > 1.0 //Dan H: Check if player is on top of his vehicle VEHICLE_INDEX vehLastDrive = GET_LAST_DRIVEN_VEHICLE() IF DOES_ENTITY_EXIST(vehLastDrive) IF NOT IS_ENTITY_DEAD(vehLastDrive) IF NOT IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(),GET_LAST_DRIVEN_VEHICLE()) CPRINTLN(DEBUG_REPLAY, "Player is over 1m above the ground teleport them: ",vPlayerCoords) //warping player to the ground so return true Replay_TeleportPlayer(vPlayerCoords, hPlayerhead,true) RETURN TRUE ELSE CPRINTLN(DEBUG_REPLAY, "Player is on top of his vehicle, over 1m above the ground,not grounding him") ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ENDIF ELSE CPRINTLN(DEBUG_REPLAY, "Warping player to script-defined fail warp location: ", g_vMissionFailWarp, ".") Replay_TeleportPlayer(g_vMissionFailWarp, g_fMissionFailHeading) RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if the player is in a restricted area and warps him out of it if he is /// PARAMS: /// bPlayerHasWarped - if this isn't already true it will be set to true if we warp the player PROC Do_Replay_Restricted_Area_Warp(BOOL &bPlayerHasWarped) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_AIRPORT_AIRSIDE) Replay_TeleportPlayer(<<-1036.1206, -2731.8335, 12.7565>>, 332.5734) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<-1023.8408, -2728.1885, 12.7005>>, 238.4360) bPlayerHasWarped = TRUE ELIF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_MILITARY_BASE) Replay_TeleportPlayer(<<-1588.7277, 2787.3594, 15.8569>>, 225.7622) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<-1549.0930, 2765.3672, 16.7419>>, 230.0104) bPlayerHasWarped = TRUE ELIF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_PRISON) Replay_TeleportPlayer(<<1850.7642, 2586.4238, 44.6721>>, 269.1614) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<1870.1000, 2581.2407, 44.6721>>, 89.2920) bPlayerHasWarped = TRUE ELIF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_BIOTECH) Replay_TeleportPlayer(<<3413.7683, 3764.5522, 29.4592>>, 172.4372) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<3406.9092, 3753.4368, 29.6532>>, 143.9102 ) bPlayerHasWarped = TRUE ELIF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_MILITARY_DOCKS) Replay_TeleportPlayer(<<512.8470, -3041.4504, 5.0693>>, 262.3306) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<540.0468, -3053.9167, 5.0693>>, 179.4150) bPlayerHasWarped = TRUE ELIF IS_COORD_IN_SPECIFIED_AREA(GET_ENTITY_COORDS(PLAYER_PED_ID(), FALSE), AC_MOVIE_STUDIO) Replay_TeleportPlayer(<<-1068.5808, -463.2691, 35.6624>>, 275.0622) Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, <<-1068.0143, -456.7559, 35.5259>>, 219.4607) bPlayerHasWarped = TRUE ENDIF ENDIF ENDPROC /// PURPOSE: /// Removes the player's bike helmet is necessary PROC Do_Replay_Helmet_Check() BOOL bRemoveHelmet = TRUE MODEL_NAMES ePlayerVehicleModel IF NOT IS_PED_INJURED(PLAYER_PED_ID()) // check if we need to remove the player's bike helmet IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) ePlayerVehicleModel = GET_ENTITY_MODEL(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) IF IS_THIS_MODEL_A_BIKE(ePlayerVehicleModel) CPRINTLN(DEBUG_REPLAY, "Not removing player helmet as he is on a bike.") bRemoveHelmet = FALSE ENDIF ENDIF IF bRemoveHelmet REMOVE_PLAYER_HELMET(GET_PLAYER_INDEX(), TRUE) // remove player's bike helmet if he has one ENDIF // reset the flag that allows the player to use helmets SET_PED_HELMET(PLAYER_PED_ID(), TRUE) ENDIF ENDPROC /// PURPOSE: /// Checks the replay stage to see if it is waiting to display the replay screen /// RETURNS: /// True if waiting to display replay screen FUNC BOOL IsReplayWaitingForReplayScreen() IF g_replay.replayStageID = RS_SCREEN_DEFAULT OR g_replay.replayStageID = RS_SCREEN_FORCE_RESTART OR g_replay.replayStageID = RS_SCREEN_RESTART_CONFIRMATION OR g_replay.replayStageID = RS_SCREEN_REJECT_CONFIRMATION OR g_replay.replayStageID = RS_SCREEN_SKIP_CONFIRMATION OR g_replay.replayStageID = RS_SCREEN_FAIL_ONLY OR g_replay.replayStageID = RS_DO_BLUR RETURN TRUE ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Checks if this is a prep mission (replays for these are handled differently) /// RETURNS: /// TRUE if this is a prep mission, FALSE otherwise FUNC BOOL IsThisAPrepMission() IF NOT IS_REPEAT_PLAY_ACTIVE() // prep missions are treated the same as normal missions in repeat play IF DoesThisReplayTypeUseStoryMissionLauncher() = TRUE SP_MISSIONS eMissionID #if USE_CLF_DLC eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME_CLF(g_replay.replayScriptName, FALSE) SWITCH eMissionID CASE SP_MISSION_CLF_CAS_PR1 CASE SP_MISSION_CLF_CAS_PR2 RETURN TRUE BREAK DEFAULT // not a prep mission BREAK ENDSWITCH #ENDIF #if USE_NRM_DLC eMissionID = eMissionID // eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME_NRM(g_replay.replayScriptName, FALSE) // SWITCH eMissionID // CASE SP_MISSION_NRM_2 // RETURN TRUE // BREAK // DEFAULT // // not a prep mission // BREAK // ENDSWITCH #ENDIF #if not USE_CLF_DLC #if not USE_NRM_DLC eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(g_replay.replayScriptName, FALSE) SWITCH eMissionID CASE SP_HEIST_JEWELRY_PREP_2A CASE SP_HEIST_JEWELRY_PREP_1B CASE SP_MISSION_FBI_4_PREP_1 CASE SP_HEIST_AGENCY_PREP_1 CASE SP_HEIST_RURAL_PREP_1 RETURN TRUE BREAK DEFAULT // not a prep mission BREAK ENDSWITCH #ENDIF #ENDIF endif ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Called if the player acceptes a prep mission replay /// If the player is in a position he can't be left in for the replay we set a warp position /// The warp position will cause the blip to re-appear but not trigger the mission /// RETURNS: /// TRUE if warp required. FALSE otherwise FUNC BOOL SetPrepMissionReplayAcceptedWarp() #if USE_CLF_DLC VECTOR vPlayerWarpPos FLOAT fPlayerWarpHeading VECTOR vCarWarpPos FLOAT fCarWarpHeading BOOL bForceWarp SP_MISSIONS eMissionID eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME_CLF(g_replay.replayScriptName, FALSE) SWITCH eMissionID // garbage truck mission CASE SP_MISSION_CLF_CAS_PR1 vPlayerWarpPos = <<918.8851, -269.7890, 67.2145>> fPlayerWarpHeading = 68.2149 vCarWarpPos = <<917.2133, -263.7077, 67.3712>> fCarWarpHeading = 183.2868 BREAK CASE SP_MISSION_CLF_CAS_PR2 vPlayerWarpPos = <<918.8851, -269.7890, 67.2145>> fPlayerWarpHeading = 68.2149 vCarWarpPos = <<917.2133, -263.7077, 67.3712>> fCarWarpHeading = 183.2868 BREAK DEFAULT CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, not a prep mission or mission doesn't need a replay accepted warp") RETURN FALSE BREAK ENDSWITCH // if we reach this point this mission does need to check to warp player STATIC_BLIP_NAME_ENUM eBlip VECTOR vBlipPos FLOAT fLeaveAreaDistance FLOAT fLeaveAreaDistanceSquared FLOAT fDistanceSquaredFromTrigger VECTOR vPlayerPos eBlip = g_sMissionStaticData[eMissionID].blip IF IS_BIT_SET(g_GameBlips[eBlip].iSetting,STATIC_BLIP_SETTING_MULTI_COORD_AND_SPRITE)//g_GameBlips[eBlip].bMultiCoordAndSprite vBlipPos = g_GameBlips[eBlip].vCoords[GET_CURRENT_PLAYER_PED_INT()] ELSE vBlipPos = g_GameBlips[eBlip].vCoords[0] ENDIF //Is this a blipped mission or a trigger scene mission? fLeaveAreaDistance = g_sMissionActiveData[eMissionID].leaveAreaDistance fLeaveAreaDistanceSquared = fLeaveAreaDistance * fLeaveAreaDistance vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) fDistanceSquaredFromTrigger = VDIST2(vPlayerPos, vBlipPos) IF fDistanceSquaredFromTrigger < fLeaveAreaDistanceSquared OR bForceWarp // Too close to the trigger pos, move player g_vMissionFailWarp = vPlayerWarpPos g_fMissionFailHeading = fPlayerWarpHeading g_stageSnapshot.mVehicleStruct.vVehiclePos = vCarWarpPos g_stageSnapshot.mVehicleStruct.fVehicleHeading = fCarWarpHeading CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, SET WARP") RETURN TRUE ELSE // far away enough, leave him CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, NOT AT CO-ORD") ENDIF RETURN FALSE #ENDIF #if USE_NRM_DLC RETURN FALSE #ENDIF #if not USE_CLF_DLC #if not USE_NRM_DLC VECTOR vPlayerWarpPos FLOAT fPlayerWarpHeading VECTOR vCarWarpPos FLOAT fCarWarpHeading BOOL bForceWarp SP_MISSIONS eMissionID eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(g_replay.replayScriptName, FALSE) SWITCH eMissionID // garbage truck mission CASE SP_MISSION_FBI_4_PREP_1 vPlayerWarpPos = <<918.8851, -269.7890, 67.2145>> fPlayerWarpHeading = 68.2149 vCarWarpPos = <<917.2133, -263.7077, 67.3712>> fCarWarpHeading = 183.2868 BREAK // fire truck mission CASE SP_HEIST_AGENCY_PREP_1 vPlayerWarpPos = <<354.3055, -1722.2062, 28.2590>> fPlayerWarpHeading = 109.6154 BREAK // swat truck mission CASE SP_HEIST_JEWELRY_PREP_1B g_JP1b_tod_NextTriggerTime = GET_CURRENT_TIMEOFDAY() IF ARE_STRINGS_EQUAL(g_JP1b_string_WayPoint, "jhp1b") vPlayerWarpPos = <<1015.0224, -919.7524, 29.3237>> fPlayerWarpHeading = 26.8044 vCarWarpPos = <<1015.9702, -918.5801, 29.3330>> fCarWarpHeading = 26.8105 ELIF ARE_STRINGS_EQUAL(g_JP1b_string_WayPoint, "jhp1bRoute2") vPlayerWarpPos = <<-1189.9877, -427.8112, 32.9417>> fPlayerWarpHeading = 82.7980 vCarWarpPos = <<-1190.4031, -426.3514, 33.0150>> fCarWarpHeading = 82.7692 ENDIF bForceWarp = TRUE ADD_HELP_TO_FLOW_QUEUE("AM_H_JHP1B_REAP", FHP_HIGH, 1000, 1000, DEFAULT_HELP_TEXT_TIME, BIT_MICHAEL) BREAK // humane van/gas steal missions CASE SP_HEIST_JEWELRY_PREP_2A g_JHP2A_tod_NextTriggerTime = GET_CURRENT_TIMEOFDAY() IF ARE_STRINGS_EQUAL(g_JHP2A_string_WayPoint, "jhp2a_alt") vPlayerWarpPos = <<931.8422, 259.7393, 79.5024>> fPlayerWarpHeading = 271.3570 vCarWarpPos = <<932.5095, 258.4100, 79.4414>> fCarWarpHeading = 271.3582 ELIF ARE_STRINGS_EQUAL(g_JHP2A_string_WayPoint, "jhp2a_main") vPlayerWarpPos = <<1063.7484, -1183.3339, 54.8147>> fPlayerWarpHeading = 284.8731 vCarWarpPos = <<1064.5625, -1184.4543, 54.8234>> fCarWarpHeading = 284.8881 ENDIF bForceWarp = TRUE ADD_HELP_TO_FLOW_QUEUE("AM_H_JHP2A_REAP", FHP_HIGH, 1000, 1000, DEFAULT_HELP_TEXT_TIME, BIT_MICHAEL) BREAK // military convoy CASE SP_HEIST_RURAL_PREP_1 g_RHP_tod_NextTriggerTime = GET_CURRENT_TIMEOFDAY() vPlayerWarpPos = <<50.2976, 3069.6589, 40.0506>> fPlayerWarpHeading = 213.1591 vCarWarpPos = <<53.7574, 3065.5022, 40.0371>> fCarWarpHeading = 309.5496 bForceWarp = TRUE ADD_HELP_TO_FLOW_QUEUE("AM_RHP_REAP", FHP_HIGH, 1000, 1000, DEFAULT_HELP_TEXT_TIME,BIT_TREVOR | BIT_MICHAEL) BREAK DEFAULT CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, not a prep mission or mission doesn't need a replay accepted warp") RETURN FALSE BREAK ENDSWITCH // if we reach this point this mission does need to check to warp player STATIC_BLIP_NAME_ENUM eBlip VECTOR vBlipPos FLOAT fLeaveAreaDistance FLOAT fLeaveAreaDistanceSquared FLOAT fDistanceSquaredFromTrigger VECTOR vPlayerPos eBlip = g_sMissionStaticData[eMissionID].blip IF IS_BIT_SET(g_GameBlips[eBlip].iSetting,STATIC_BLIP_SETTING_MULTI_COORD_AND_SPRITE)//g_GameBlips[eBlip].bMultiCoordAndSprite vBlipPos = g_GameBlips[eBlip].vCoords[GET_CURRENT_PLAYER_PED_INT()] ELSE vBlipPos = g_GameBlips[eBlip].vCoords[0] ENDIF //Is this a blipped mission or a trigger scene mission? fLeaveAreaDistance = g_sMissionActiveData[eMissionID].leaveAreaDistance fLeaveAreaDistanceSquared = fLeaveAreaDistance * fLeaveAreaDistance vPlayerPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) fDistanceSquaredFromTrigger = VDIST2(vPlayerPos, vBlipPos) IF fDistanceSquaredFromTrigger < fLeaveAreaDistanceSquared OR bForceWarp // Too close to the trigger pos, move player g_vMissionFailWarp = vPlayerWarpPos g_fMissionFailHeading = fPlayerWarpHeading g_stageSnapshot.mVehicleStruct.vVehiclePos = vCarWarpPos g_stageSnapshot.mVehicleStruct.fVehicleHeading = fCarWarpHeading CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, SET WARP") RETURN TRUE ELSE // far away enough, leave him CPRINTLN(DEBUG_REPLAY, "SetPrepMissionReplayAcceptedWarp, NOT AT CO-ORD") ENDIF RETURN FALSE #ENDIF #ENDIF ENDFUNC /// PURPOSE: /// Uses the global replay variables to return the mission index for this replay mission /// (Should only be used if this is a story mission) /// RETURNS: /// INT the mission data index for this replay mission FUNC INT GetReplayMissionDataIndex() RETURN g_flowUnsaved.coreVars[g_replay.replayCoreVarsIndex].iValue1 ENDFUNC /// PURPOSE: /// Sets the appropriate leave area flag for this replay type /// PARAMS: /// bForceLeaveArea - true if we are forcing the player to leave the area before retrying this missions PROC SetLeaveAreaFlag(BOOL bForceLeaveArea) IF DoesThisReplayTypeUseStoryMissionLauncher() Set_Leave_Area_Flag_For_Mission(INT_TO_ENUM(SP_MISSIONS, GetReplayMissionDataIndex()), bForceLeaveArea) ELIF g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER //CPRINTLN(DEBUG_REPLAY, "Setting RC force leave area flag to ", bForceLeaveArea) g_RandomChars[g_replay.replayCoreVarsIndex].rcLeaveAreaCheck = bForceLeaveArea ENDIF ENDPROC /// PURPOSE: /// Returns index of bail bond mission from script name /// RETURNS: /// index of bail bond or -1 if this isnt a bail bond mission FUNC INT GET_BAIL_BOND_MISSION_FROM_SCRIPT(STRING sScript) IF ARE_STRINGS_EQUAL("BailBond1", sScript) RETURN 0 ELIF ARE_STRINGS_EQUAL("BailBond2", sScript) RETURN 1 ELIF ARE_STRINGS_EQUAL("BailBond3", sScript) RETURN 2 ELIF ARE_STRINGS_EQUAL("BailBond4", sScript) RETURN 3 ENDIF RETURN -1 ENDFUNC /// PURPOSE: /// Checks if the mission type we are processing a replay for uses the shitskip system /// (Currently this is just story mission + RC replays) /// RETURNS: /// TRUE if this replay type uses the shitskip system FUNC BOOL IsShitskipUsedInThisReplayType() IF g_replay.replayType = REPLAY_TYPE_MISSION OR g_replay.replayType = REPLAY_TYPE_MISSION_FORCE_RESTART OR g_replay.replayType = REPLAY_TYPE_FAIL_SCREEN_ONLY OR g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER OR g_replay.replayType = REPLAY_TYPE_PHONECALL_TRIGGER RETURN TRUE ENDIF IF g_replay.replayType = REPLAY_TYPE_MINIGAME IF GET_BAIL_BOND_MISSION_FROM_SCRIPT(g_replay.replayScriptName) > -1 RETURN TRUE //bailbonds are the only minigames that use shitskips ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Returns the 1st checkpoint that this mission allows shitskips from. /// This is only used for story missions and allows us to not have shitskips until a certain part /// of the mission has been reached. /// RETURNS: /// INT the lowest checkpoint that this mission offers shitskips from FUNC INT GET_MINIMUM_CHECKPOINT_FOR_SHITSKIP() #if USE_CLF_DLC //SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME_CLF(g_replay.replayScriptName, FALSE) INT iMinCheckpoint = 0 #endif #if USE_NRM_DLC SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME_NRM(g_replay.replayScriptName, FALSE) INT iMinCheckpoint = 0 IF eMissionID = SP_MISSION_NRM_SUR_START iMinCheckpoint = 1 ENDIF #endif #if not USE_CLF_DLC #if not USE_NRM_DLC SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(g_replay.replayScriptName, FALSE) INT iMinCheckpoint = 0 IF eMissionID = SP_MISSION_PROLOGUE iMinCheckpoint = 1 ENDIF #endif #endif RETURN iMinCheckpoint ENDFUNC /// PURPOSE: /// Resets all shistkip variables. Call when setting up a new replay PROC ResetShitskipVariables() g_bShitskipOffered = FALSE g_bShitskipAccepted = FALSE // don't reset g_bShitskipToEnd -this is handled when setting checkpoints ENDPROC /// PURPOSE: /// Waits for the mission that offered the replay to cleanup PROC Wait_For_Mission_To_Cleanup() WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY(g_replay.replayScriptName)) > 0 CPRINTLN(DEBUG_REPLAY, "Waiting for mission script to terminate", g_replay.replayScriptName) WAIT(0) ENDWHILE ENDPROC // =========================================================================================================== // Replay Reset // =========================================================================================================== /// PURPOSE: /// Blocks / unblocks the loading screen. /// PARAMS: /// bBlock - are we blocking or unblocking? PROC Replay_Block_Load_Screen(BOOL bBlock) IF bBlock = TRUE // block the load screen IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_LOAD_SCREEN)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is blocking the load screen.") SET_NO_LOADING_SCREEN(TRUE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_LOAD_SCREEN)) ENDIF ELSE // unblock the load screen IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_LOAD_SCREEN)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unblocking the load screen.") SET_NO_LOADING_SCREEN(FALSE) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_LOAD_SCREEN)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Blocks / unblocks the death jingle. /// PARAMS: /// bBlock - are we blocking or unblocking? PROC Replay_Block_Death_Jingle(BOOL bBlock) IF bBlock = TRUE // block the jingle IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_DEATH_JINGLE)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is blocking the death jingle.") BLOCK_DEATH_JINGLE(TRUE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_DEATH_JINGLE)) ENDIF ELSE // unblock the jingle IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_DEATH_JINGLE)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unblocking the death jingle.") BLOCK_DEATH_JINGLE(FALSE) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCKED_DEATH_JINGLE)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Blocks / unblocks the damage overlay /// PARAMS: /// bBlock - are we blocking or unblocking? PROC Replay_Block_Damage_Overlay(BOOL bBlock) IF bBlock = TRUE // block the overlay IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_DAMAGE_OVERLAY)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is blocking the damage overlay.") TOGGLE_PLAYER_DAMAGE_OVERLAY(FALSE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_DAMAGE_OVERLAY)) ENDIF ELSE // unblock the jingle IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_DAMAGE_OVERLAY)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unblocking the damage overlay.") TOGGLE_PLAYER_DAMAGE_OVERLAY(TRUE) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_DAMAGE_OVERLAY)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Starts / stops the replay screen audio scene. /// PARAMS: /// bStart - are we starting or stopping? PROC Replay_Control_Audio_Scene(BOOL bStart) IF bStart = TRUE // start the scene IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SCENE_STARTED)) START_AUDIO_SCENE("REPLAY_SCREEN_SCENE") CPRINTLN(DEBUG_REPLAY, "Starting mission failed audio scene now") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SCENE_STARTED)) ENDIF ELSE // stop the scene IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SCENE_STARTED)) CPRINTLN(DEBUG_REPLAY, "Stopping mission failed audio scene now") STOP_AUDIO_SCENE("REPLAY_SCREEN_SCENE") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SCENE_STARTED)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Sets whether a replay is currently being set up /// PARAMS: /// bDoingSetup - are we setting up a replay? PROC Replay_Toggle_Setup(BOOL bDoingSetup) IF bDoingSetup = TRUE // set the bit CPRINTLN(DEBUG_REPLAY, "A replay is now being set up.") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SETUP_STARTED)) ELSE // clear the bit CPRINTLN(DEBUG_REPLAY, "Replay set up is complete.") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SETUP_STARTED)) ENDIF ENDPROC /// PURPOSE: /// Pauses / unpauses the feed(only unpauses if replay controller paused the feed) /// PARAMS: /// bPause - are we pausing or unpausing? PROC Replay_Pause_Feed(BOOL bPause) IF bPause = TRUE // pause the feed CPRINTLN(DEBUG_REPLAY, "Replay Controller is pausing the feed.") THEFEED_PAUSE() SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_FEED)) ELSE // unpause the feed IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_FEED)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unpausing the feed.") THEFEED_RESUME() CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_FEED)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Controls the slow motion effect used during the fail screen /// PARAMS: /// bStart - if TRUE we trigger the slow motion, if FALSE we return to normal timescale /// iFailEffect - 1 = faildeathEffect. 2 = failOutEffect PROC Replay_Control_Slow_Motion(BOOL bStart, INT iFailEffect=1) IF bStart = TRUE CPRINTLN(DEBUG_REPLAY, "Starting slo-mo now ", GET_THIS_SCRIPT_NAME()) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_TRIGGERED_SLO_MO)) // start slow motion IF iFailEffect = 1 SET_TIME_SCALE(FAIL_EFFECT_SLO_MO) ELSE SET_TIME_SCALE(FAIL_OUT_EFFECT_SLO_MO) ENDIF ELSE IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_TRIGGERED_SLO_MO)) CPRINTLN(DEBUG_REPLAY, "Disabling slo-mo now ", GET_THIS_SCRIPT_NAME()) SET_TIME_SCALE(1.0) ENDIF CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_TRIGGERED_SLO_MO)) ENDIF ENDPROC /// PURPOSE: /// Trigger or cleans up the fail effect /// PARAMS: /// bStart - are we starting or stopping the fail effect? PROC Replay_Control_Fail_Effect(BOOL bStart) STRING sEffect SWITCH GET_CURRENT_PLAYER_PED_ENUM() CASE CHAR_MICHAEL sEffect = "DeathFailMichaelIn" BREAK CASE CHAR_FRANKLIN sEffect = "DeathFailFranklinIn" BREAK CASE CHAR_TREVOR sEffect = "DeathFailTrevorIn" BREAK ENDSWITCH IF bStart = TRUE IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) CPRINTLN(DEBUG_REPLAY, "Starting fail effect now: ", sEffect, " ", GET_THIS_SCRIPT_NAME()) ANIMPOSTFX_PLAY(sEffect, 0, FALSE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) // start camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INTRO) // start slow motion Replay_Control_Slow_Motion(TRUE, 1) ENDIF ELSE IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) CPRINTLN(DEBUG_REPLAY, "Disabling fail effect now: ", sEffect, " ", GET_THIS_SCRIPT_NAME()) IF ANIMPOSTFX_IS_RUNNING(sEffect) ANIMPOSTFX_STOP(sEffect) ENDIF // stop camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INACTIVE) ENDIF CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_EFFECT_TRIGGERED)) ENDIF ENDPROC /// PURPOSE: /// Trigger or cleans up the fail out effect /// PARAMS: /// bStart - are we starting or stopping the fail out effect? PROC Replay_Control_Fail_Out_Effect(BOOL bStart) IF bStart = TRUE // super slow motion IF NOT g_bBlockUltraSloMoOnDeath Replay_Control_Fail_Effect(FALSE) CPRINTLN(DEBUG_REPLAY, "Starting fail out effect now ", GET_THIS_SCRIPT_NAME()) ANIMPOSTFX_PLAY("DeathFailOut", 0, FALSE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_OUT_EFFECT_TRIGGERED)) // start camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_OUTRO) Replay_Control_Slow_Motion(TRUE, 2) ENDIF ELSE IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_OUT_EFFECT_TRIGGERED)) CPRINTLN(DEBUG_REPLAY, "Disabling fail out effect now ", GET_THIS_SCRIPT_NAME()) IF ANIMPOSTFX_IS_RUNNING("DeathFailOut") ANIMPOSTFX_STOP("DeathFailOut") ENDIF // stop camera effect SET_CAM_DEATH_FAIL_EFFECT_STATE(CAM_DEATH_FAIL_EFFECT_INACTIVE) ENDIF CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FAIL_OUT_EFFECT_TRIGGERED)) ENDIF ENDPROC /// PURPOSE: /// Checks if fail screen audio has loaded, requests it if not /// RETURNS: /// TRUE if audio loaded, FALSE otherwise FUNC BOOL Load_Replay_Audio() // failed screen audio IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) IF REQUEST_SCRIPT_AUDIO_BANK("generic_failed") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) ENDIF ENDIF RETURN IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) ENDFUNC /// PURPOSE: /// Stops the fail sound playing and releases the audio bank PROC Cleanup_Fail_Audio() CDEBUG1LN(DEBUG_REPLAY, "Cleaning up fail audio assets.") IF g_replay.iFailSoundID <> -1 IF NOT HAS_SOUND_FINISHED(g_replay.iFailSoundID) STOP_SOUND(g_replay.iFailSoundID) ENDIF g_replay.iFailSoundID = -1 ENDIF IF g_replay.iFailBedSoundID <> -1 IF NOT HAS_SOUND_FINISHED(g_replay.iFailBedSoundID) STOP_SOUND(g_replay.iFailBedSoundID) ENDIF g_replay.iFailBedSoundID = -1 ENDIF IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) ENDIF //Fix for 2193769. Only release audio if calling thread is the replay controller. //This can be called from main.sc as part of a general script cleanup. In that case this //command could release other unrelated audio banks associated with main. IF GET_HASH_KEY(GET_THIS_SCRIPT_NAME()) = HASH("replay_controller") RELEASE_SCRIPT_AUDIO_BANK() #IF IS_DEBUG_BUILD ELSE CDEBUG1LN(DEBUG_REPLAY, "Skipped releasing script due to cleanup being run from none replay controller thread.") #ENDIF ENDIF ENDPROC /// PURPOSE: /// Shows / hides the HUD and radar /// PARAMS: /// bShow - Are we showing or hiding the HUD PROC Replay_Show_Hud(BOOL bShow) CPRINTLN(DEBUG_REPLAY, "Replay_Show_Hud: bShow= ", bShow) DISPLAY_HUD(bShow) DISPLAY_RADAR(bShow) ENDPROC /// PURPOSE: /// (Un)Freezes the player /// PARAMS: /// bFreeze- are we freezing or unfreezing? PROC Replay_Freeze_Player(BOOL bFreeze) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF bFreeze = TRUE // freeze SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FROZEN_PLAYER)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is freezing the player.") CLEAR_PED_TASKS(PLAYER_PED_ID()) IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_REPLAY, "The player is in a vehcile. Freezing this vehicle instead.") FREEZE_ENTITY_POSITION(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), TRUE) ELSE IF NOT IS_PED_GETTING_INTO_A_VEHICLE(PLAYER_PED_ID()) IF IS_ENTITY_ATTACHED(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_REPLAY, "The player is attached. Detatching.") DETACH_ENTITY(PLAYER_PED_ID()) ENDIF ENDIF IF NOT IS_ENTITY_ATTACHED(PLAYER_PED_ID()) CDEBUG1LN(DEBUG_REPLAY, "The player is not attached. Freezing player.") FREEZE_ENTITY_POSITION(PLAYER_PED_ID(), TRUE) ENDIF ENDIF ELSE // unfreeze IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FROZEN_PLAYER)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is unfreezing the player.") BOOL bAttached = FALSE IF IS_ENTITY_ATTACHED(PLAYER_PED_ID()) // unfreeze player ENTITY_INDEX entityAttached = GET_ENTITY_ATTACHED_TO(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(entityAttached) IF NOT IS_THIS_MODEL_A_BOAT(GET_ENTITY_MODEL(entityAttached)) CDEBUG1LN(DEBUG_REPLAY, "The player is attached to an entity. Unfreezing this entity instead.") FREEZE_ENTITY_POSITION(entityAttached, FALSE) bAttached = TRUE ENDIF ENDIF ENDIF IF NOT bAttached CDEBUG1LN(DEBUG_REPLAY, "The player is not attached to anything unfreezing.") FREEZE_ENTITY_POSITION(PLAYER_PED_ID(), FALSE) ENDIF CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FROZEN_PLAYER)) ENDIF ENDIF ENDIF ENDPROC /// PURPOSE: /// Enables / disables the character select wheeel (only enables if replay controller diabled the selector) /// PARAMS: /// bEnable - are we disabling or enabling the select wheel? PROC Replay_Enable_Character_Select_Wheel(BOOL bEnable) IF bEnable = TRUE // enable the select wheel IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_SELECTOR)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is enabling character select wheel.") ENABLE_SELECTOR() CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_SELECTOR)) ENDIF ELSE // disable the select wheel CPRINTLN(DEBUG_REPLAY, "Replay Controller is disabling character select wheel.") DISABLE_SELECTOR() SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_SELECTOR)) ENDIF ENDPROC /// PURPOSE: /// resets scaleform variables setup variables /// Call this when you need to set up the question and / or buttons again PROC ResetScaleformSetupVariables() CPRINTLN(DEBUG_REPLAY, "ResetScaleformSetupVariables called.") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_2ND_TEXT_SETUP)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BUTTONS_SETUP)) ENDPROC /// PURPOSE: /// Releases the scaleform movies and sets the indexes to be null PROC ReleaseReplayScaleform() IF g_replay.mFailTextScaleform <> NULL CPRINTLN(DEBUG_REPLAY, "Releasing mFailTextScaleform and setting to null.") SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(g_replay.mFailTextScaleform) g_replay.mFailTextScaleform = NULL ENDIF IF g_replay.mFailButtonsScaleform <> NULL CPRINTLN(DEBUG_REPLAY, "Releasing mFailButtonsScaleform and setting to null.") SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(g_replay.mFailButtonsScaleform) g_replay.mFailButtonsScaleform = NULL ENDIF ENDPROC /// PURPOSE: /// (Un)pauses the comm queues and prints a debug message PROC PauseCommQueues(BOOL bPause) IF bPause = TRUE CPRINTLN(DEBUG_REPLAY, "Paused communication queue.") g_bPauseCommsQueues = TRUE ELSE CPRINTLN(DEBUG_REPLAY, "Unpaused communication queue.") g_bPauseCommsQueues = FALSE ENDIF ENDPROC /// PURPOSE: /// Clears out the replay globals. PROC Reset_Core_Replay_Variables() CPRINTLN(DEBUG_REPLAY, "Resetting core replay global data.") g_replay.replayStageID = RS_NOT_REQUIRED g_replay.replayCoreVarsIndex = -1 g_replay.replayStageReadOnly = 0 g_replay.fTextTransitionTime = 0 CLEAR_BIT(g_replay.iReplayBits,ENUM_TO_INT(RB_BLOCK_RESPAWN)) g_bLaunchMinigameReplay = FALSE PauseCommQueues(FALSE) // clean up the scaleform + audio ReleaseReplayScaleform() ResetScaleformSetupVariables() g_replay.iFailSoundID = -1 g_replay.iFailBedSoundID = -1 ENDPROC /// PURPOSE: /// Resets the position that the player will be warped to if he rejects a replay /// also resets the forced character change PROC Reset_Fail_Warp_Location() CPRINTLN(DEBUG_REPLAY, "Resetting fail warp location + forced character change.") g_vMissionFailWarp = <<0,0,0>> g_fMissionFailHeading = 0.0 g_replay.eReplayRejectCharacter = NO_CHARACTER ENDPROC /// PURPOSE: /// Resets the fail reason + fail add text PROC ResetFailReasons() g_txtMissionFailReason = "" g_txtMissionFailAddText = "" ENDPROC /// PURPOSE: /// Resets everything used in the replay controller PROC Reset_All_Replay_Variables() Reset_Start_Snapshot() Reset_Stage_Snapshot() Reset_Core_Replay_Variables() ResetRestrictedVehiclesArray() // reset respawn locations + fail reasons ResetFailReasons() Reset_Fail_Warp_Location() // reset the replay stage g_replayMissionStage = 0 // reset shitskip monitor g_iLastObservedRetryStatusOnFail = -1 CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) // Reset death / arrest stuff g_bReplayDoRejectWarp = FALSE // player will be warped to hospital / police station if he dies off mission PAUSE_DEATH_ARREST_RESTART(FALSE) IGNORE_NEXT_RESTART(FALSE) SET_FADE_IN_AFTER_DEATH_ARREST(TRUE) SET_FADE_OUT_AFTER_ARREST(TRUE) SET_FADE_OUT_AFTER_DEATH(TRUE) // reset the replay set up / warp stuff Replay_Toggle_Setup(FALSE) ENDPROC /// PURPOSE: /// Resets player state variables at end of replay setup. /// These were originally called in respawn controller but have been moved here so they don't break replay setup PROC REPLAY_RESET_PLAYER_STATE() IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) SET_ENTITY_COLLISION(PLAYER_PED_ID(), TRUE) ENDIF IF NOT NETWORK_IS_GAME_IN_PROGRESS() SET_PED_CAN_BE_SHOT_IN_VEHICLE(PLAYER_PED_ID(), TRUE) // this command is SP only SET_PED_GRAVITY(PLAYER_PED_ID(), TRUE) ENDIF SET_ENTITY_CAN_BE_DAMAGED(PLAYER_PED_ID(), TRUE) SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), FALSE) SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(PLAYER_PED_ID(), FALSE) SET_ENTITY_PROOFS(PLAYER_PED_ID(), FALSE, FALSE, FALSE, FALSE, FALSE) SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(PLAYER_PED_ID(), FALSE) SET_ENTITY_VISIBLE(PLAYER_PED_ID(), TRUE) ENDIF ENDPROC /// PURPOSE: /// Toggles player invincibility /// PARAMS: /// bSet - are we setting or clearing? PROC Replay_Toggle_Invincibility(BOOL bSet) IF bSet = TRUE // set invincible IF NOT IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_SET_INVINCIBLE)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is setting player as invincible.") SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), TRUE) IF NOT NETWORK_IS_GAME_IN_PROGRESS() SET_PED_CAN_BE_SHOT_IN_VEHICLE(PLAYER_PED_ID(), FALSE) // this command is SP only ENDIF SET_ENTITY_CAN_BE_DAMAGED(PLAYER_PED_ID(), FALSE) SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(PLAYER_PED_ID(), TRUE) SET_ENTITY_PROOFS(PLAYER_PED_ID(), TRUE, TRUE, TRUE, TRUE, TRUE) IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) SET_ENTITY_COLLISION(PLAYER_PED_ID(), FALSE) ENDIF CLEAR_ENTITY_LAST_DAMAGE_ENTITY(PLAYER_PED_ID()) CLEAR_ENTITY_LAST_WEAPON_DAMAGE(PLAYER_PED_ID()) // clear a small area so we can clear anything that might kill the player VECTOR vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) CLEAR_AREA(vPos, 100.0, TRUE) SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_SET_INVINCIBLE)) ENDIF ELSE // clear invincibility IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_SET_INVINCIBLE)) CPRINTLN(DEBUG_REPLAY, "Replay Controller is clearing player invincibility.") REPLAY_RESET_PLAYER_STATE() CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_SET_INVINCIBLE)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Disables / enables the weapon select wheel /// PARAMS: /// bDisable - are we disabling or enabling the weapon select wheel? PROC Disable_Weapon_Select(BOOL bDisable) IF bDisable = TRUE DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON) // needs to be called every frame SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_WEAPON_SELECT_DISABLED)) ELSE IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_WEAPON_SELECT_DISABLED)) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_WEAPON_SELECT_DISABLED)) ENDIF ENDIF ENDPROC /// PURPOSE: /// Always called before the replay controller exits (just before replay starts, or once player rejects replay) /// Enables phone, set script safe for cut-scene, unpause, remove effects etc /// PARAMS: PROC ResetCommonReplayChanges() CPRINTLN(DEBUG_REPLAY, "ResetCommonReplayChanges called.") DISABLE_CELLPHONE(FALSE) SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE) // reset controls ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_LR) ENABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_VEH_MOVE_UD) Disable_Weapon_Select(FALSE) // clear text CLEAR_HELP() CLEAR_PRINTS() // scaleform bits: CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_QUESTION_SETUP)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_2ND_TEXT_SETUP)) // other cleanup Replay_Show_Hud(TRUE) Replay_Control_Audio_Scene(FALSE) Replay_Pause_Game(FALSE) Replay_Pause_Feed(FALSE) Replay_Block_Death_Jingle(FALSE) Replay_Enable_Character_Select_Wheel(TRUE) Cleanup_Fail_Audio() Replay_Control_Fail_Effect(FALSE) Replay_Control_Fail_Out_Effect(FALSE) Replay_Control_Slow_Motion(FALSE) Replay_Block_Damage_Overlay(FALSE) Replay_Toggle_Invincibility(FALSE) Replay_Freeze_Player(FALSE) Replay_Block_Load_Screen(FALSE) // remove stealth pose IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_PED_STEALTH_MOVEMENT(PLAYER_PED_ID(), FALSE) SET_PED_USING_ACTION_MODE(PLAYER_PED_ID(), FALSE) ENDIF // return player control IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), TRUE) ENDIF ENDPROC /// PURPOSE: /// Resets all replay controller changes and variables PROC Cleanup_Replay_Controller() CPRINTLN(DEBUG_REPLAY, "Cleanup_Replay_Controller has been called.") ResetCommonReplayChanges() Reset_All_Replay_Variables() ENDPROC /// PURPOSE: /// Clears partcile FX from around the player PROC ReplayClearParticles(FLOAT fClearAreaSize) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) VECTOR vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) // Clear up any smoke / fire effects and blood decals in the area REMOVE_PARTICLE_FX_IN_RANGE(vPos, fClearAreaSize) REMOVE_DECALS_IN_RANGE(vPos, fClearAreaSize) ENDIF ENDIF ENDPROC /// PURPOSE: /// Before the fail screen pauses the game we store the player vehicle's velocity /// This is then restored if the player rejects the replay and hasn't been warped /// PARAMS: /// mVehicle - the vehcile we're restoring the velocity for PROC RESTORE_VEHICLE_VELOCITY(VEHICLE_INDEX mVehicle) // restore velocity of vehicle player is in vehicle + hasn't warped IF DOES_ENTITY_EXIST(mVehicle) IF IS_VEHICLE_DRIVEABLE(mVehicle) FREEZE_ENTITY_POSITION(mVehicle, FALSE) SET_ENTITY_VELOCITY(mVehicle, g_replay.vVehicleVelocity) CPRINTLN(DEBUG_REPLAY, "Restored velocity as g_replay.vVehicleVelocity x= ", g_replay.vVehicleVelocity.x, " y= ", g_replay.vVehicleVelocity.y, " z= ", g_replay.vVehicleVelocity.z) ENDIF ENDIF ENDPROC /// PURPOSE: /// Grabs the player's last vehicle so it doesn't get deleted when we clear the area PROC GrabPlayersLastVehicle(VEHICLE_INDEX &vehPlayer) vehPlayer = GET_PLAYERS_LAST_VEHICLE() IF IS_VEHICLE_DRIVEABLE(vehPlayer) CPRINTLN(DEBUG_REPLAY, "Replaycontroller found player's last car") SET_ENTITY_AS_MISSION_ENTITY(vehPlayer, TRUE, TRUE) ELSE CPRINTLN(DEBUG_REPLAY, "Replaycontroller did not find player's last car") ENDIF ENDPROC /// PURPOSE: /// set player's last vehicle as no longer needed /// (if it exists, it means we have set as mission entity so it doesnt get deleted) /// Also deletes any peds that are in the vehicle (other than the player) /// This is needed to ensure any battle buddies get cleaned up /// PARAMS: /// vehPlayer - the vehicle we grabbed before the mission cleaned up /// bDelete - if true we delete it, if false we set as no longer needed PROC ReleaseGrabbedVehicle(VEHICLE_INDEX &vehPlayer, BOOL bDelete) PED_INDEX mPedInSeat INT iSeat IF DOES_ENTITY_EXIST(vehPlayer) // delete any peds in the vehicle FOR iSeat = -1 TO ENUM_TO_INT(VS_EXTRA_RIGHT_3) -1 IF IS_VEHICLE_DRIVEABLE(vehPlayer) mPedInSeat = GET_PED_IN_VEHICLE_SEAT(vehPlayer, INT_TO_ENUM(VEHICLE_SEAT, iSeat)) IF DOES_ENTITY_EXIST(mPedInSeat) IF mPedInSeat <> PLAYER_PED_ID() IF INT_TO_ENUM(VEHICLE_SEAT, iSeat) != VS_DRIVER OR GET_ENTITY_MODEL(vehPlayer) != TAXI CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle deleting ped in seat: ", iSeat) SET_ENTITY_AS_MISSION_ENTITY(mPedInSeat, TRUE, TRUE) DELETE_PED(mPedInSeat) ELSE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle a taxi driver is in the drivers seat.") CPRINTLN(DEBUG_REPLAY, "Saving driver and requesting taxi service cleans up.") CPRINTLN(DEBUG_TAXI_SERVICE, "Script ", GET_THIS_SCRIPT_NAME(), " has requested the taxi service cleans up.") //B* 1906471: Only request the taxiservice.sc cleanup when the script is running IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("taxiservice")) > 0 g_bRequestTaxiServiceCleanup = TRUE ENDIF ENDIF #IF IS_DEBUG_BUILD ELSE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle the player is in seat: ", iSeat) #ENDIF ENDIF #IF IS_DEBUG_BUILD ELSE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle Seat is empty: ", iSeat) #ENDIF ENDIF ENDIF ENDFOR SET_ENTITY_AS_MISSION_ENTITY(vehPlayer, TRUE, TRUE) // get the player out and release / delete the vehicle IF bDelete = TRUE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle deleting player vehicle.") IF IS_VEHICLE_DRIVEABLE(vehPlayer) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF IS_PED_IN_VEHICLE(PLAYER_PED_ID(), vehPlayer) // get player out before delete CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID()) ENDIF ENDIF ENDIF #IF USE_CLF_DLC if spy_vehicle_is_this_vehicle_the_spy_vehicle(vehPlayer) spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_remove_all_system_assets(temp_spy_veh_system) else DELETE_VEHICLE(vehPlayer) endif #endif #IF not USE_CLF_DLC DELETE_VEHICLE(vehPlayer) #endif ELSE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle setting player vehicle as no longer needed.") #IF USE_CLF_DLC if spy_vehicle_is_this_vehicle_the_spy_vehicle(vehPlayer) spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_set_spy_vehicle_for_soft_deletion(temp_spy_veh_system) else SET_VEHICLE_AS_NO_LONGER_NEEDED(vehPlayer) endif #endif #IF not USE_CLF_DLC SET_VEHICLE_AS_NO_LONGER_NEEDED(vehPlayer) #endif ENDIF ELSE CPRINTLN(DEBUG_REPLAY, "ReleaseGrabbedVehicle player vehicle does not exist.") ENDIF ENDPROC /// PURPOSE: /// Clears and refills populations of nearby area /// PARAMS: /// bLeaveLastPlayerVehicle - if TRUE the player's last vehicle won't get deleted by the clear area /// bResetCam - do we want to reset the camera behind the player after the clear area? /// bHasPlayerWarped- if the player has warped we don't need to keep his vehicle for him, so we delete it /// bLargeClearArea- if this is true we clear the large area and wait for population to refill /// If it is false we just clear a small area around the player (this is to avoid player getting run over after rejecting replay) /// bReleasePlayerVehicle - if true we set player's last vehicle as no longer needed after clear area /// set this to false if we are going to clear another area before we return to gameplay (replay rejection) PROC ReplayClearArea(VEHICLE_INDEX &vehPlayer, BOOL bResetCam, BOOL bHasPlayerWarped, BOOL bLargeClearArea = TRUE, BOOL bReleasePlayerVehicle = TRUE) VECTOR vPos BOOL bPlayerNeedsRespot = FALSE BOOL bRepause = FALSE INT iEarlyOutTime // when to bail out of the wait for HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED FLOAT fClearAreaSize // Set the size of the area we are clearing IF bLargeClearArea = TRUE fClearAreaSize = 5000 ELSE fClearAreaSize = 10 ENDIF IF bHasPlayerWarped = TRUE // if we're warping the player we don't need to keep his vehicle for him ReleaseGrabbedVehicle(vehPlayer, TRUE) ENDIF //Reset area. IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) // if the player is in an undrivable vehicle, delete it IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) VEHICLE_INDEX mVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(mVehicle) IF NOT IS_VEHICLE_DRIVEABLE(mVehicle) SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) // get out of vehicle bPlayerNeedsRespot = TRUE CPRINTLN(DEBUG_REPLAY, "ReplayClearArea: player removed from undriveable vehicle") // if this is the vehicle we had stored for the player, release it IF vehPlayer = mVehicle ReleaseGrabbedVehicle(vehPlayer, FALSE) ENDIF ENDIF ENDIF ENDIF IF bHasPlayerWarped = FALSE // replayTeleportPlayer now also does a clear area- so not needed here if warped // clear the area CLEAR_AREA(vPos, fClearAreaSize, TRUE, FALSE) CLEAR_AREA_OF_OBJECTS(vPos, fClearAreaSize) ENDIF // if player was in an undriveable vehicle, he needs respotting now IF bPlayerNeedsRespot = TRUE SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos) // put player on ground ENDIF ENDIF ENDIF ReplayClearParticles(fClearAreaSize) IF bLargeClearArea = TRUE AND bHasPlayerWarped = FALSE // replayTeleportPlayer now also does a clear area / repopulate- so not needed here if warped // need to unpause for repopulate stuff to work // if we're currently paused we'll repause after the repopulation is done IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) bRepause = TRUE Replay_Pause_Game(FALSE) ENDIF // refill population INSTANTLY_FILL_PED_POPULATION() INSTANTLY_FILL_VEHICLE_POPULATION() POPULATE_NOW() iEarlyOutTime = GET_GAME_TIMER() + 1000 WHILE NOT HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED() AND GET_GAME_TIMER() < iEarlyOutTime WAIT(0) CPRINTLN(DEBUG_REPLAY, "ReplayClearArea Waiting for HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED to return true") ENDWHILE IF GET_GAME_TIMER() > iEarlyOutTime CPRINTLN(DEBUG_REPLAY, "HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED took too long, early out.") ENDIF // if we were paused before repopulation, repause here IF bRepause = TRUE Replay_Pause_Game(TRUE) ENDIF ENDIF IF bReleasePlayerVehicle = TRUE // set player's last vehicle as no longer needed ReleaseGrabbedVehicle(vehPlayer, FALSE) ENDIF IF bResetCam = TRUE // reset camera behind player SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0) SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0) ENDIF ENDPROC // =========================================================================================================== // Replay Setup Functions // =========================================================================================================== /// PURPOSE: /// Handles setup that is common to all replay types /// Checks if player should be offered a shitskip /// PARAMS: /// sReplayScriptName - the script offering the replay /// eReplayType - the replay type (RC mission, minigame etc) /// iMissionID - the mission ID is used for offering a shitsktip /// bDelayFade - should we delay fading out? FUNC BOOL SetupReplay(STRING sReplayScriptName, g_eReplayTypes eReplayType, INT iMissionID = -1) // don't set up the replay if we're waiting for flow setup to finish #IF IS_DEBUG_BUILD IF g_replay.replayStageID = RS_WAITING_FOR_FLOW CPRINTLN(DEBUG_REPLAY, "Cancelling offered replay as we are in RS_WAITING_FOR_FLOW state") RETURN FALSE ENDIF #ENDIF // reset replay and shitskip variables Reset_Core_Replay_Variables() ResetShitskipVariables() // common replay setup variables g_replay.replayStageID = RS_DO_BLUR g_replay.replayScriptName = sReplayScriptName g_replay.replayType = eReplayType CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") CPRINTLN(DEBUG_REPLAY, " Replay offered by ",sReplayScriptName) CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") //Ensure code doesn't respawn the player while we're fading out for the replay screen PAUSE_DEATH_ARREST_RESTART(TRUE) SET_FADE_OUT_AFTER_ARREST(FALSE) SET_FADE_OUT_AFTER_DEATH(FALSE) // Set when we can skip the fail screen #IF IS_DEBUG_BUILD g_iSkipFailScreenTime = GET_GAME_TIMER() + 1000 #ENDIF // stop phone being up during replay screen HANG_UP_AND_PUT_AWAY_PHONE(TRUE) DISABLE_CELLPHONE(TRUE) // stop player being able to switch characters Replay_Enable_Character_Select_Wheel(FALSE) // stop any feed messages being displayed on the fail screen Replay_Pause_Feed(TRUE) // clear scaleform and audio bits CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_TEXT_SCALE_LOADED)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_AUDIO_LOADED)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_STARTED_TRANSITION)) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DONE_TRANSITION)) // stop player from being able to right upside down vehicles CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_VEH_CONT)) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) CPRINTLN(DEBUG_REPLAY, "Player in car") VEHICLE_INDEX mVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) IF IS_ENTITY_UPSIDEDOWN(mVehicle) CPRINTLN(DEBUG_REPLAY, "car upside down, disable controls") SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DISABLED_VEH_CONT)) ENDIF ENDIF ENDIF ENDIF // Clear any text, HUD etc CLEAR_HELP() CLEAR_PRINTS() Replay_Show_Hud(FALSE) //Pause the communication queues so that phonecalls can't trigger during replay screen. PauseCommQueues(TRUE) // Store a copy of the mid-mission replay stage global which can be safely read by the mission // if it gets replayed without danger of it being overwritten. g_replay.replayStageReadOnly = g_replayMissionStage // check for potential shitskip IF IsShitskipUsedInThisReplayType() IF DoesThisReplayTypeUseStoryMissionLauncher() IF g_replayMissionStage >= GET_MINIMUM_CHECKPOINT_FOR_SHITSKIP() // we've at least reached the 1st checkpoint in this mission that offers a skip IF NOT IS_BIT_SET(g_sMissionStaticData[iMissionID].settingsBitset, MF_INDEX_NO_SHITSKIP) #if USE_CLF_DLC CPRINTLN(DEBUG_REPLAY, g_sMissionStaticData[iMissionID].statID, " failed", g_savedGlobalsClifford.sFlow.missionSavedData[iMissionID].missionFailsNoProgress, "of max", SHITSKIP_MAX) //Check if the mission been failed enough times without progress to warrant a shitskip. IF g_savedGlobalsClifford.sFlow.missionSavedData[iMissionID].missionFailsNoProgress >= SHITSKIP_MAX CPRINTLN(DEBUG_REPLAY, "Failed enough times to trigger a shitskip") g_bShitskipOffered = TRUE // we will offer the player a shitskip on the replay screen ELSE CPRINTLN(DEBUG_REPLAY, "not failed enough times for a shitskip to be offered") ENDIF #endif #if USE_NRM_DLC CPRINTLN(DEBUG_REPLAY, g_sMissionStaticData[iMissionID].statID, " failed", g_savedGlobalsnorman.sFlow.missionSavedData[iMissionID].missionFailsNoProgress, "of max", SHITSKIP_MAX) //Check if the mission been failed enough times without progress to warrant a shitskip. IF g_savedGlobalsnorman.sFlow.missionSavedData[iMissionID].missionFailsNoProgress >= SHITSKIP_MAX CPRINTLN(DEBUG_REPLAY, "Failed enough times to trigger a shitskip") g_bShitskipOffered = TRUE // we will offer the player a shitskip on the replay screen ELSE CPRINTLN(DEBUG_REPLAY, "not failed enough times for a shitskip to be offered") ENDIF #endif #if not USE_CLF_DLC #if not USE_NRM_DLC CPRINTLN(DEBUG_REPLAY, g_sMissionStaticData[iMissionID].statID, " failed", g_savedGlobals.sFlow.missionSavedData[iMissionID].missionFailsNoProgress, "of max", SHITSKIP_MAX) //Check if the mission been failed enough times without progress to warrant a shitskip. IF g_savedGlobals.sFlow.missionSavedData[iMissionID].missionFailsNoProgress >= SHITSKIP_MAX CPRINTLN(DEBUG_REPLAY, "Failed enough times to trigger a shitskip") g_bShitskipOffered = TRUE // we will offer the player a shitskip on the replay screen ELSE CPRINTLN(DEBUG_REPLAY, "not failed enough times for a shitskip to be offered") ENDIF #endif #endif ELSE CPRINTLN(DEBUG_REPLAY, "This story mission does not use shitskips.") ENDIF ENDIF ELSE #if not USE_CLF_DLC #if not USE_NRM_DLC IF g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER // RC missions CPRINTLN(DEBUG_REPLAY, g_replay.replayScriptName, " failed", g_savedGlobals.sRandomChars.savedRC[iMissionID].iFailsNoProgress, "of max", SHITSKIP_MAX) // Check if this particular RC mission uses shitskips g_structRCMissionsStatic sRCMissionDetails Retrieve_Random_Character_Static_Mission_Details(INT_TO_ENUM(g_eRC_MissionIDs,iMissionID), sRCMissionDetails) IF sRCMissionDetails.bUsesShitSkips = TRUE //Check if the mission been failed enough times without progress to warrant a shitskip. IF g_savedGlobals.sRandomChars.savedRC[iMissionID].iFailsNoProgress >= SHITSKIP_MAX CPRINTLN(DEBUG_REPLAY, "Failed enough times to trigger a shitskip") g_bShitskipOffered = TRUE // we will offer the player a shitskip on the replay screen ELSE CPRINTLN(DEBUG_REPLAY, "not failed enough times for a shitskip to be offered") ENDIF ENDIF ELSE // other types don't use shit skip...except bail bonds INT iBailBondIndex iBailBondIndex = GET_BAIL_BOND_MISSION_FROM_SCRIPT(GET_THIS_SCRIPT_NAME()) IF iBailBondIndex > -1 //Check if the bail bond mission been failed enough times without progress to warrant a shitskip. IF g_savedGlobals.sBailBondData.iFailsNoProgress[iBailbondIndex] >= SHITSKIP_MAX CPRINTLN(DEBUG_REPLAY, "Failed enough times to trigger a shitskip") g_bShitskipOffered = TRUE // we will offer the player a shitskip on the replay screen ELSE CPRINTLN(DEBUG_REPLAY, "not failed enough times for a shitskip to be offered") ENDIF ENDIF ENDIF #endif #endif ENDIF ENDIF // replay setup succesful RETURN TRUE ENDFUNC /// PURPOSE: /// Sets up replay for a story mission /// Also checks if the player should be offered a shitskip /// PARAMS: /// paramCoreVarsArrayPos - Index into the Core Vars array containing details of this mission PROC Setup_Mission_Replay(INT paramCoreVarsArrayPos) TEXT_LABEL_23 sScriptName IF g_replay.replayStageID <> RS_NOT_RUNNING // Is this mission allowed to offer a replay? INT iMissionID = g_flowUnsaved.coreVars[paramCoreVarsArrayPos].iValue1 sScriptName = g_sMissionStaticData[iMissionID].scriptName #if USE_CLF_DLC if IS_STRING_NULL_OR_EMPTY(sScriptName) sScriptName = GET_SCRIPT_FROM_HASH(g_sMissionStaticData[iMissionID].scriptHash) endif #endif #if USE_NRM_DLC if IS_STRING_NULL_OR_EMPTY(sScriptName) sScriptName = GET_SCRIPT_FROM_HASH_NRM(g_sMissionStaticData[iMissionID].scriptHash) endif #endif IF IS_BIT_SET(g_sMissionStaticData[iMissionID].settingsBitset, MF_INDEX_NO_FAIL) CPRINTLN(DEBUG_REPLAY, sScriptName, " did not set up a replay as it is not flagged to offer one.") EXIT ENDIF // Set replay type g_eReplayTypes eReplayType IF ARE_STRINGS_EQUAL(sScriptName, "me_amanda1") OR ARE_STRINGS_EQUAL(sScriptName, "me_jimmy1") OR ARE_STRINGS_EQUAL(sScriptName, "me_tracey1") eReplayType = REPLAY_TYPE_MICHAEL_EVENT ELSE // phone call trigger missions IF ARE_STRINGS_EQUAL(sScriptName, "carsteal4") OR ARE_STRINGS_EQUAL(sScriptName, "fbi3") eReplayType = REPLAY_TYPE_PHONECALL_TRIGGER ELSE // other missions IF NOT IS_BIT_SET(g_sMissionStaticData[iMissionID].settingsBitset, MF_INDEX_NO_REPLAY) IF IS_BIT_SET(g_sMissionStaticData[iMissionID].settingsBitset, MF_INDEX_FORCE_RESTART) eReplayType = REPLAY_TYPE_MISSION_FORCE_RESTART ELSE eReplayType = REPLAY_TYPE_MISSION ENDIF ELSE eReplayType = REPLAY_TYPE_FAIL_SCREEN_ONLY ENDIF ENDIF ENDIF // Tell the playstats system this mission has failed. INT iVariation = GET_MISSION_VARIATION(INT_TO_ENUM(SP_MISSIONS, iMissionID)) TEXT_LABEL_7 txtStatID = g_sMissionStaticData[iMissionID].statID #if not USE_CLF_DLC #if not USE_NRM_DLC IF INT_TO_ENUM(SP_MISSIONS, iMissionID) = SP_HEIST_JEWELRY_2 SWITCH g_savedGlobals.sFlow.controls.intIDs[FLOWINT_HEIST_CHOICE_JEWEL] CASE HEIST_CHOICE_JEWEL_STEALTH txtStatID += "A" BREAK CASE HEIST_CHOICE_JEWEL_HIGH_IMPACT txtStatID += "B" BREAK ENDSWITCH ENDIF #endif #endif PLAYSTATS_MISSION_CHECKPOINT(txtStatID, iVariation, g_replayMissionStage, 0) SCRIPT_PLAYSTATS_MISSION_OVER(txtStatID, iVariation, g_replayMissionStage, TRUE) CPRINTLN(DEBUG_FLOW, "Flagging playstat MISSION FAILED for story mission. MissionID:", txtStatID, " Variation:", iVariation) IF SetupReplay(sScriptName, eReplayType, iMissionID) // common replay setup // Mission specific replay setup g_replay.replayCoreVarsIndex = paramCoreVarsArrayPos ENDIF ELSE CPRINTLN(DEBUG_REPLAY, "Replay controller is not running, aborting replay setup.") ENDIF ENDPROC /// PURPOSE: /// Sets up a replay for a minigame /// PARAMS: /// paramLauncherScriptName - the script that is offering the replay PROC Setup_Minigame_Replay(STRING paramLauncherScriptName) IF g_replay.replayStageID <> RS_NOT_RUNNING SetupReplay(paramLauncherScriptName, REPLAY_TYPE_MINIGAME) ELSE CPRINTLN(DEBUG_REPLAY, "Replay controller is not running, aborting replay setup.") ENDIF ENDPROC /// PURPOSE: /// Sets up a replay for a Random Character mission /// PARAMS: /// paramRCScriptName - the script offering a replay /// bDelayFade - should we delay fading out? PROC Setup_RC_Replay(STRING paramRCScriptName, INT iMissionID) IF g_replay.replayStageID <> RS_NOT_RUNNING IF SetupReplay(paramRCScriptName, REPLAY_TYPE_RANDOM_CHARACTER, iMissionID) g_replay.replayCoreVarsIndex = iMissionID ENDIF ELSE CPRINTLN(DEBUG_REPLAY, "Replay controller is not running, aborting replay setup.") ENDIF ENDPROC /// PURPOSE: /// Stores a game state snapshot for a mission replay as the mission is just starting. /// These game state variables are stored as the mission launches so that we can restore /// the game world to the correct state if the mission is aborted midway through. /// PARAMS: /// paramCoreVarsArrayPos - The core vars array position PROC Store_Mission_Replay_Starting_Snapshot(INT paramCoreVarsArrayPos) SP_MISSIONS eMissionID = INT_TO_ENUM(SP_MISSIONS, g_flowUnsaved.coreVars[paramCoreVarsArrayPos].iValue1) #if USE_CLF_DLC CPRINTLN(DEBUG_REPLAY, "Saving mission start gamestate snapshot for ", GET_SCRIPT_FROM_HASH(g_sMissionStaticData[eMissionID].scriptHash), ".") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Store_Game_State_Snapshot_For_Start(GET_SCRIPT_FROM_HASH(g_sMissionStaticData[eMissionID].scriptHash), TRUE) #endif #if USE_NRM_DLC CPRINTLN(DEBUG_REPLAY, "Saving mission start gamestate snapshot for ", GET_SCRIPT_FROM_HASH_NRM(g_sMissionStaticData[eMissionID].scriptHash), ".") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Store_Game_State_Snapshot_For_Start(GET_SCRIPT_FROM_HASH_NRM(g_sMissionStaticData[eMissionID].scriptHash), TRUE) #endif #if not USE_CLF_DLC #if not USE_NRM_DLC CPRINTLN(DEBUG_REPLAY, "Saving mission start gamestate snapshot for ", g_sMissionStaticData[eMissionID].scriptName, ".") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Store_Game_State_Snapshot_For_Start(g_sMissionStaticData[eMissionID].scriptName, TRUE) #endif #endif //Check if the mission start snapshot has a time saved that is not in valid mission triggering hours. //If so override the start hour to the valid mission start hour. IF (g_sMissionStaticData[eMissionID].startHour != NULL_HOUR) AND (g_sMissionStaticData[eMissionID].endHour != NULL_HOUR) AND NOT IS_BIT_SET(g_sMissionStaticData[eMissionID].settingsBitset, MF_INDEX_MID_MISSION_TOD) // ignore if the TOD skip is done mid mission INT iSavedStartHour = GET_TIMEOFDAY_HOUR(g_startSnapshot.tTime) INT iStartHour = g_sMissionStaticData[eMissionID].startHour INT iEndHour = g_sMissionStaticData[eMissionID].endHour IF NOT IS_HOUR_BETWEEN_THESE_HOURS(iSavedStartHour, iStartHour, iEndHour) CPRINTLN(DEBUG_REPLAY, "Mission start hour was saved as ", iSavedStartHour, " which is not in the valid mission triggering hours of ", iStartHour, "->", iEndHour, ".") CPRINTLN(DEBUG_REPLAY, "Overriding saved start hour to be ", iStartHour, ".") SET_TIMEOFDAY_HOUR(g_startSnapshot.tTime, iStartHour) SET_TIMEOFDAY_HOUR(g_stageSnapshot.tTime, iStartHour) ENDIF ENDIF //only use these cases if the game type is GTA not CLF T #if not USE_CLF_DLC #if not USE_NRM_DLC // Trevor 1 needs to overwrite the mission start character as Trevor // so that we don't get changed to Franklin or Michael when accepting replay from start IF eMissionID = SP_MISSION_TREVOR_1 g_startSnapshot.eCharacter = CHAR_TREVOR g_stageSnapshot.eCharacter = CHAR_TREVOR CPRINTLN(DEBUG_REPLAY, "Overriding mission start character for Trevor 1") ENDIF //When switching in to Family4 sometimes we pick up the starting character as Franklin. //Franklin is not a valid character to restart the mission as so we need to safeguard //againts storing him here. IF eMissionID = SP_MISSION_FAMILY_4 IF g_startSnapshot.eCharacter = CHAR_FRANKLIN g_startSnapshot.eCharacter = CHAR_MICHAEL g_stageSnapshot.eCharacter = CHAR_MICHAEL CPRINTLN(DEBUG_REPLAY, "Overriding mission start character for Family 4") ENDIf ENDIF #endif #endif ENDPROC /// PURPOSE: /// Stores a game state snapshot for a minigame replay as the minigame is just starting. /// These game state variables are stored as the minigame launches so that we can restore /// the game world to the correct state if the minigame is aborted midway through. /// PARAMS: /// paramLauncherScriptName - The name of the minigame launcher starting the minigame. /// bStoreVehicleInfo - Do we want to store the player's vehicle info? PROC Store_Minigame_Replay_Starting_Snapshot(STRING paramLauncherScriptName, BOOL bStoreVehicleInfo = TRUE) CPRINTLN(DEBUG_REPLAY, "Saving minigame start gamestate snapshot for launcher ", paramLauncherScriptName, ".") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Store_Game_State_Snapshot_For_Start(paramLauncherScriptName, bStoreVehicleInfo) ENDPROC /// PURPOSE: /// Stores a game state snapshot for a RC replay as the RC mission is just starting. /// These game state variables are stored as the RC mission launches so that we can restore /// the game world to the correct state if the mission is aborted midway through. /// PARAMS: /// paramRCScriptName - The name of the RC mission script that is just starting. /// bStoreVehicleInfo - Do we want to store the player's vehicle info? PROC Store_RC_Replay_Starting_Snapshot(STRING paramRCScriptName, BOOL bStoreVehicleInfo = TRUE) CPRINTLN(DEBUG_REPLAY, "Saving RC mission start gamestate snapshot for ", paramRCScriptName, ".") CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DID_WE_EVER_SHITSKIP)) Store_Game_State_Snapshot_For_Start(paramRCScriptName, bStoreVehicleInfo) ENDPROC /// PURPOSE: /// Waits for player to respawn and debug prints how long we waited /// Ensures the screen doesn't fade in after respawn /// Deletes any restricted vehicle that the player died in /// Repeauses the game PROC WaitForPlayerToRespawn(VEHICLE_INDEX &mPlayerDiedInRestrictedVehicle) SET_FADE_IN_AFTER_DEATH_ARREST(FALSE) PAUSE_DEATH_ARREST_RESTART(FALSE) CPRINTLN(DEBUG_REPLAY, "Waiting for player to be playing...") #IF IS_DEBUG_BUILD INT iAliveWaitFrames = 0 #ENDIF WHILE NOT (IS_PLAYER_PLAYING(PLAYER_ID())) #IF IS_DEBUG_BUILD iAliveWaitFrames++ #ENDIF WAIT(0) ENDWHILE CPRINTLN(DEBUG_REPLAY, "Player is now playing. Waited ", iAliveWaitFrames, " frames.") SET_FADE_IN_AFTER_DEATH_ARREST(TRUE) DeleteRestrictedVehicle(mPlayerDiedInRestrictedVehicle) Replay_Pause_Game(TRUE) ENDPROC /// PURPOSE: /// Waits for screen to fade out. (Toggled by debug bool) PROC DoQuickFadeOut() BOOL bDoFade = TRUE #IF IS_DEBUG_BUILD bDoFade = bFadeOut #ENDIF SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_AFTER_HUD) IF bDoFade = TRUE WHILE NOT IS_SCREEN_FADED_OUT() WAIT(0) IF NOT IS_SCREEN_FADING_OUT() DO_SCREEN_FADE_OUT(DEFAULT_FADE_TIME_SHORT) ENDIF ENDWHILE ENDIF ENDPROC /// PURPOSE: /// Removes any weapons from the player that haven't been unlocked in flow yet /// Only called if replay is rejected PROC RemoveUnavailableweapons() INT iWeaponSlot = 0 WEAPON_SLOT eWeaponSlot WEAPON_TYPE eWeaponInSlot INT iPed BOOL bSkipPed = FALSE FOR iPed = 0 TO NUM_OF_PLAYABLE_PEDS -1 //CPRINTLN(DEBUG_REPLAY, "iPed = ", iPed) // skip player ped if he is dead (should never happen) IF iPed = GET_CURRENT_PLAYER_PED_INT() IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF IS_PED_INJURED(PLAYER_PED_ID()) iPed++ bSkipPed = TRUE CPRINTLN(DEBUG_REPLAY, "RemoveUnavailableweapons: Player ped is dead") ENDIF ELSE iPed++ bSkipPed = TRUE CPRINTLN(DEBUG_REPLAY, "RemoveUnavailableweapons: Player ped d") ENDIF ENDIF IF bSkipPed = FALSE FOR iWeaponSlot = 0 TO NUM_PLAYER_PED_WEAPON_SLOTS -1 //CPRINTLN(DEBUG_REPLAY, "iWeaponSlot = ", iWeaponSlot) eWeaponSlot = GET_PLAYER_PED_WEAPON_SLOT_FROM_INT(iWeaponSlot) IF eWeaponSlot != WEAPONSLOT_INVALID //CPRINTLN(DEBUG_REPLAY, "weapon type is: ", g_savedGlobals.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].eWeaponType) IF g_bLoadedClifford IF NOT IS_PLAYER_PED_WEAPON_UNLOCKED(INT_TO_ENUM(enumCharacterList, iPed), g_savedGlobalsClifford.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].eWeaponType) // it is not yet unlocked in flow, remove it if player has it IF iPed = GET_CURRENT_PLAYER_PED_INT() // current player ped eWeaponInSlot = GET_PED_WEAPONTYPE_IN_SLOT(PLAYER_PED_ID(), eWeaponSlot) IF eWeaponInSlot != WEAPONTYPE_INVALID AND eWeaponInSlot != WEAPONTYPE_UNARMED // player has this weapon, remove it SET_PED_AMMO(PLAYER_PED_ID(), eWeaponInSlot, 0) REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), eWeaponInSlot) CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ELSE // other player ped IF g_savedGlobalsClifford.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].iAmmoCount > 0 // player has this weapon, remove it g_savedGlobalsClifford.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].iAmmoCount = 0 g_savedGlobalsClifford.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].eWeaponType = WEAPONTYPE_INVALID CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ENDIF ENDIF ELIF g_bLoadedNorman IF NOT IS_PLAYER_PED_WEAPON_UNLOCKED(INT_TO_ENUM(enumCharacterList, iPed), g_savedGlobalsnorman.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].eWeaponType) // it is not yet unlocked in flow, remove it if player has it IF iPed = GET_CURRENT_PLAYER_PED_INT() // current player ped eWeaponInSlot = GET_PED_WEAPONTYPE_IN_SLOT(PLAYER_PED_ID(), eWeaponSlot) IF eWeaponInSlot != WEAPONTYPE_INVALID AND eWeaponInSlot != WEAPONTYPE_UNARMED // player has this weapon, remove it SET_PED_AMMO(PLAYER_PED_ID(), eWeaponInSlot, 0) REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), eWeaponInSlot) CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ELSE // other player ped IF g_savedGlobalsnorman.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].iAmmoCount > 0 // player has this weapon, remove it g_savedGlobalsnorman.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].iAmmoCount = 0 g_savedGlobalsnorman.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].eWeaponType = WEAPONTYPE_INVALID CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ENDIF ENDIF ELSE IF NOT IS_PLAYER_PED_WEAPON_UNLOCKED(INT_TO_ENUM(enumCharacterList, iPed), g_savedGlobals.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].eWeaponType) // it is not yet unlocked in flow, remove it if player has it IF iPed = GET_CURRENT_PLAYER_PED_INT() // current player ped eWeaponInSlot = GET_PED_WEAPONTYPE_IN_SLOT(PLAYER_PED_ID(), eWeaponSlot) IF eWeaponInSlot != WEAPONTYPE_INVALID AND eWeaponInSlot != WEAPONTYPE_UNARMED // player has this weapon, remove it SET_PED_AMMO(PLAYER_PED_ID(), eWeaponInSlot, 0) REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), eWeaponInSlot) CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ELSE // other player ped IF g_savedGlobals.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[iWeaponSlot].iAmmoCount > 0 // player has this weapon, remove it g_savedGlobals.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].iAmmoCount = 0 g_savedGlobals.sPlayerData.sInfo.sWeapons[iPed].sWeaponInfo[GET_INT_FROM_PLAYER_PED_WEAPON_SLOT(eWeaponSlot)].eWeaponType = WEAPONTYPE_INVALID CPRINTLN(DEBUG_REPLAY, "Removing weapon as it is not yet unlocked in flow, iWeaponSlot= ", iWeaponSlot, "iPed = ", iPed) ELSE //CPRINTLN(DEBUG_REPLAY, "Not unlocked in flow, but: player doesn't have this weapon, iWeaponSlot= ", iWeaponSlot) ENDIF ENDIF ENDIF ENDIF ELSE //CPRINTLN(DEBUG_REPLAY, "eWeaponSlot is invalid. iWeaponSlot = ", iWeaponSlot) ENDIF ENDFOR ENDIF bSkipPed = FALSE ENDFOR ENDPROC /// PURPOSE: /// Moves player out of water and sets him to be invincible and detaches him /// Also removes helmet PROC Replay_PostRespawnChecks(BOOL bDoWaterCheck = TRUE) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) Replay_Toggle_Invincibility(TRUE) REMOVE_PLAYER_HELMET(GET_PLAYER_INDEX(), TRUE) // remove player's bike helmet if he has one IF bDoWaterCheck = TRUE VECTOR vPlayerCoords = GET_ENTITY_COORDS(PLAYER_PED_ID()) SCRIPT_WATER_TEST_RESULT eWaterTestResult FLOAT fWaterHeight BOOL bPlayerInWater = FALSE vPlayerCoords.z = vPlayerCoords.z + 1.5 eWaterTestResult = TEST_VERTICAL_PROBE_AGAINST_ALL_WATER(vPlayerCoords,SCRIPT_INCLUDE_MOVER, fWaterHeight) IF eWaterTestResult = SCRIPT_WATER_TEST_RESULT_WATER bPlayerInWater = TRUE ELSE IF IS_ENTITY_IN_WATER(PLAYER_PED_ID()) bPlayerInWater = TRUE ENDIF ENDIF IF bPlayerInWater = TRUE CPRINTLN(DEBUG_REPLAY, "Player respawned in water: moving him.") vPlayerCoords.Z = fWaterHeight + 10.0 SET_ENTITY_COORDS(PLAYER_PED_ID(), vPlayerCoords) ELSE IF eWaterTestResult = SCRIPT_WATER_TEST_RESULT_BLOCKED CPRINTLN(DEBUG_REPLAY, "Water test result blocked.") ELSE CPRINTLN(DEBUG_REPLAY, "Player not respawned in water.") ENDIF ENDIF ENDIF Replay_Freeze_Player(TRUE) ENDIF ENDPROC /// PURPOSE: /// Called if the player accepts a replay in a shop whilst a shop intro was active. /// Warps the player to just outisde the shop /// PARAMS: /// vCoords - where we are moving the player to /// fHeading - new heading to use PROC WarpPlayerOutOfShop(VECTOR vCoords, FLOAT fHeading) CPRINTLN(DEBUG_REPLAY, "Player failed in shop during intro cut-scene. warping him out.") Replay_TeleportPlayer(vCoords, fHeading, FALSE, FALSE) ENDPROC // =========================================================================================================== // Replay Progression Control Functions // =========================================================================================================== /// PURPOSE: /// Handles any setup required for replay a prep mission PROC Replay_Accepted_PrepMission() VEHICLE_INDEX vehPlayer VEHICLE_INDEX mDiedInVehicle = null VEHICLE_INDEX mPlayerDiedInRestrictedVehicle BOOL bDoShopWarp = FALSE VECTOR vShopWarpPos FLOAT fShopWarpHeading CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") CPRINTLN(DEBUG_REPLAY, " Player Has Accepted Prep mission replay") CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") PASTE_BANK_TRANSLOGS() // Short fade out, unpause, wait for mission to cleanup + pause again Cleanup_Fail_Audio() Replay_Show_Hud(FALSE) DoQuickFadeOut() ReleaseReplayScaleform() Replay_Pause_Game(FALSE) REPLAY_WAIT_FOR_CUTSCENE_TO_STOP() GrabPlayersLastVehicle(vehPlayer) // stop player's last vehicle getting deleted by clear area #if use_CLF_dlc //always remove the spy vehicle on a mission fail -> retry spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_remove_all_system_assets(temp_spy_veh_system) #endif RemovePlayerFromAnyRestrictedVehicle(mPlayerDiedInRestrictedVehicle) g_replay.replayStageID = RS_ACCEPTING Wait_For_Mission_To_Cleanup() CLEAR_TIMECYCLE_MODIFIER() // check if the player died in a car, if so we'll put him back in the car after respawn IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF IS_PED_INJURED(PLAYER_PED_ID()) IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) CPRINTLN(DEBUG_REPLAY, "Player died in a vehicle") mDiedInVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()) ENDIF ENDIF ENDIF // clear the mission's vehicle gen to avoid duplicate cars DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_MISSION_VEH) // -----reset all shops---------------- bDoShopWarp =FORCE_SHOP_RESET_FOR_MISSION_FAILED(TRUE, vShopWarpPos, fShopWarpHeading) // unblock loading screen now so we can get the loading icon WAIT(0) Replay_Block_Load_Screen(FALSE) // if the player is alive we re-pause the game here. (it gets unpaused just before we fade in) // if he is not alive we need the game to be unpaused so he can respawn IF IS_PLAYER_PLAYING(PLAYER_ID()) Replay_Pause_Game(TRUE) ELSE CPRINTLN(DEBUG_REPLAY, "Skipping code's next respawn: player was dead/arrested but has accepted a mission replay.") IGNORE_NEXT_RESTART(TRUE) ENDIF WaitForPlayerToRespawn(mPlayerDiedInRestrictedVehicle) // ----------move player out of water and ensure he is invincible------------------------- Replay_PostRespawnChecks(FALSE) // ---------warp player out of shop if needed-------------------------------------- IF bDoShopWarp = TRUE WarpPlayerOutOfShop(vShopWarpPos, fShopWarpHeading) ENDIF // -----------MISSION PREP------------------------------------------ // Restore start snapshot CPRINTLN(DEBUG_REPLAY, "Restoring replay start snapshot + resetting replay stage as player has chosen to restart from beginning.") Restore_Game_State_Snapshot(g_startSnapshot) g_replay.replayStageReadOnly = 0 // need to reset his current checkpoint g_replayMissionStage = 0 // -----------Clear area and handle warps-------------------------------------------- // Prep missions warp to script defined locations if needed // Handled the same way as rejection warps BOOL bPlayerHasWarped = FALSE // store player's last vehicle as checkpoint vehicle (So we can restore it if needed) Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_stageSnapshot.mVehicleStruct, g_stageSnapshot, NULL, FALSE, FALSE) // see if we need to set a prep mission accepted warp location SetPrepMissionReplayAcceptedWarp() bPlayerHasWarped = Do_Replay_Rejected_Warp() Do_Replay_Restricted_Area_Warp(bPlayerHasWarped) Do_Replay_Helmet_Check() // start battle buddies restoring CPRINTLN(DEBUG_REPLAY, "Waiting for friend activity script to shut down.") WHILE NOT CAN_RESTORE_BATTLEBUDDY_SNAPSHOT() WAIT(0) ENDWHILE CPRINTLN(DEBUG_REPLAY, "Friend activity script is shutdown. Request battle buddies to restore in background.") RESTORE_BATTLEBUDDY_SNAPSHOT(g_stageSnapshot.mBattleBuddyStruct) // clear and repopulate the area ReplayClearArea(vehPlayer, TRUE, bPlayerHasWarped) IF bPlayerHasWarped = TRUE // restore player's car if needed // block cop cars for Jewel Prep 2a BOOL bAllowCopCars = TRUE #if not USE_CLF_DLC #if not USE_NRM_DLC SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(g_replay.replayScriptName, FALSE) IF eMissionID = SP_HEIST_JEWELRY_PREP_2A bAllowCopCars = FALSE ENDIF #endif #endif RestoreAnySnapshotVehicle(GET_PLAYER_PED_ENUM(PLAYER_PED_ID()), bAllowCopCars) // clear visible damage and holster weapon Clear_Damage_And_Wetness() SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, FALSE) ELSE //if player hasn't warped we may need to put him back in vehicle he died in IF mDiedInVehicle <> NULL IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF DOES_ENTITY_EXIST(mDiedInVehicle) IF IS_VEHICLE_DRIVEABLE(mDiedInVehicle) CPRINTLN(DEBUG_REPLAY, "Putting player back in the car they died in.") Replay_Freeze_Player(FALSE) SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), mDiedInVehicle) // fix the vehicle up SET_ENTITY_HEALTH(mDiedInVehicle, GET_ENTITY_MAX_HEALTH(mDiedInVehicle)) INT iWindow FOR iWindow = 0 TO SC_WINDSCREEN_REAR FIX_VEHICLE_WINDOW(mDiedInVehicle, INT_TO_ENUM(SC_WINDOW_LIST, iWindow)) ENDFOR ENDIF ENDIF ENDIF ENDIF ENDIF CPRINTLN(DEBUG_REPLAY, "Waiting for battle buddies to restore.") WHILE NOT IS_BATTLEBUDDY_SNAPSHOT_RESTORED(g_stageSnapshot.mBattleBuddyStruct) WAIT(0) ENDWHILE CPRINTLN(DEBUG_REPLAY, "Battle buddies are restored.") IF (IS_PLAYER_PLAYING(PLAYER_ID())) //Make extra sure wanted levels are cleared at this point. CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID()) ENDIF // Ensure all PostFX are stopped. ANIMPOSTFX_STOP_ALL() //Ensure all TVs are switched off. INT i REPEAT TV_LOC_END i IF g_TVStruct[i].bIsTVOn CPRINTLN(DEBUG_REPLAY, "Turning off TV ", i, " as it was on as a replay was accepted.") g_TVStruct[i].bForceStopTV = TRUE ENDIF ENDREPEAT PauseCommQueues(FALSE) g_replay.replayStageID = RS_ACTIVATE ENDPROC PROC ClearMissionDialogueBrief() CPRINTLN(debug_replay,"Clearing previous mission dialogue brief messages") CLEAR_ADDITIONAL_TEXT(MISSION_DIALOGUE_TEXT_SLOT,TRUE) ENDPROC /// PURPOSE: /// Called when the player has accepted a replay. /// Handles getting him into position to restart the mission. /// (Any changes to this may need to go in Replay_Accepted_PrepMission) /// PARAMS: /// bRestart - True if the player has chosen to restart the mission from the beginning PROC Replay_Accepted_NormalMission(BOOL bRestart) // normal replay (not prep mission) BOOL bDoShopWarp = FALSE VECTOR vShopWarpPos FLOAT fShopWarpHeading VEHICLE_INDEX mPlayerDiedInRestrictedVehicle VEHICLE_INDEX vehPlayer // REPLAY! remove for new replay warp stuff CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") CPRINTLN(DEBUG_REPLAY, " Player Has Accepted normal Replay") CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") // Short fade out, unpause, wait for mission to cleanup + pause again Cleanup_Fail_Audio() Replay_Show_Hud(FALSE) DoQuickFadeOut() ReleaseReplayScaleform() ClearMissionDialogueBrief() Replay_Pause_Game(FALSE) REPLAY_WAIT_FOR_CUTSCENE_TO_STOP() #if use_CLF_dlc //always remove the spy vehicle on a mission fail -> retry spy_vehicle_system_struct temp_spy_veh_system spy_vehicle_remove_all_system_assets(temp_spy_veh_system) #endif RemovePlayerFromAnyRestrictedVehicle(mPlayerDiedInRestrictedVehicle) g_replay.replayStageID = RS_ACCEPTING Wait_For_Mission_To_Cleanup() CLEAR_TIMECYCLE_MODIFIER() // -----reset all shops---------------- bDoShopWarp = FORCE_SHOP_RESET_FOR_MISSION_FAILED(TRUE, vShopWarpPos, fShopWarpHeading) // unblock loading screen now so we can get the loading icon WAIT(0) Replay_Block_Load_Screen(FALSE) // if the player is alive we re-pause the game here. (it gets unpaused just before we fade in) // if he is not alive we need the game to be unpaused so he can respawn IF IS_PLAYER_PLAYING(PLAYER_ID()) Replay_Pause_Game(TRUE) g_bSkipWeatherResetOnRespawn = FALSE ELSE CPRINTLN(DEBUG_REPLAY, "Skipping code's next respawn: player was dead/arrested but has accepted a mission replay.") IGNORE_NEXT_RESTART(TRUE) g_bSkipWeatherResetOnRespawn = TRUE ENDIF WaitForPlayerToRespawn(mPlayerDiedInRestrictedVehicle) // ----------move player out of water and ensure he is invincible------------------------- IF NOT IS_PED_INJURED(PLAYER_PED_ID()) CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID()) Replay_PostRespawnChecks() ENDIF // ---------warp player out of shop if needed-------------------------------------- IF bDoShopWarp = TRUE WarpPlayerOutOfShop(vShopWarpPos, fShopWarpHeading) ENDIF // -----------MISSION PREP------------------------------------------ // Restore correct snapshot IF bRestart = TRUE // if player accepts replay from restart confirmation screen, he restarts from beginning of mission CPRINTLN(DEBUG_REPLAY, "Restoring replay start snapshot + resetting replay stage as player has chosen to restart from beginning.") Restore_Game_State_Snapshot(g_startSnapshot) g_replay.replayStageReadOnly = 0 // need to reset his current checkpoint g_replayMissionStage = 0 // reset shitskip to end bool, as shitskipping from start won't pass the mission g_bShitskipToEnd = FALSE RESET_MISSION_REGISTERS_FROM_START() // to fix time carrying over between full restarts ELSE // restarting from last checkpoint CPRINTLN(DEBUG_REPLAY, "Restoring replay snapshot state for the last checkpoint reached. Checkpoint no: ", g_replay.replayStageReadOnly) Restore_Game_State_Snapshot(g_stageSnapshot) ENDIF IF bRestart PASTE_BANK_TRANSLOGS(FALSE) //paste from start //reset mission stat invalidations 1535234 RESET_MISSION_STATS_INVALIDATIONS() ELSE PASTE_BANK_TRANSLOGS() ENDIF // Michael Events + REPLAY_TYPE_PHONECALL_TRIGGER warp player back to phonecall position if starting from beginning // This is because the player can answer the phone call from anywhere IF g_replay.replayStageReadOnly = 0 IF g_replay.replayType = REPLAY_TYPE_MICHAEL_EVENT OR g_replay.replayType = REPLAY_TYPE_PHONECALL_TRIGGER CPRINTLN(DEBUG_REPLAY, "Michael Event / Phonecall trigger: Starting from beginning...Warping player back to the position they started the mission in.") Replay_TeleportPlayer(g_startSnapshot.mPlayerStruct.vPos, g_startSnapshot.mPlayerStruct.fHeading, TRUE) ENDIF ENDIF // -----------Clear wanted level-------------------------------------------- IF NOT DOES_MISSION_USE_NEW_REPLAY_SYSTEM() ReplayClearArea(vehPlayer, FALSE, FALSE) ENDIF IF (IS_PLAYER_PLAYING(PLAYER_ID())) //Make extra sure wanted levels are cleared at this point. CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID()) ENDIF // Ensure all PostFX are stopped. ANIMPOSTFX_STOP_ALL() //Ensure all TVs are switched off. INT i REPEAT TV_LOC_END i IF g_TVStruct[i].bIsTVOn CPRINTLN(DEBUG_REPLAY, "Turning off TV ", i, " as it was on as a replay was accepted.") g_TVStruct[i].bForceStopTV = TRUE ENDIF ENDREPEAT PauseCommQueues(FALSE) g_replay.replayStageID = RS_ACTIVATE ENDPROC /// PURPOSE: /// Called when the player has accepted a replay. /// Checks which accepted proc to call (normal or prep mission) /// PARAMS: /// bRestart - True if the player has chosen to restart the mission from the beginning PROC Replay_Player_Has_Accepted(BOOL bRestart) Update_Stored_Drown_Stats() Replay_Control_Slow_Motion(FALSE) CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_RESPAWN)) IF IsThisAPrepMission() = TRUE Replay_Accepted_PrepMission() ELSE Replay_Accepted_NormalMission(bRestart) ENDIF ENDPROC /// PURPOSE: /// Calls any necessary cleanup functions as this replay is rejected /// Flow waits for replay to finish processing, /// Then if it was rejected, cleans up + moves on, otherwise it relaunches mission /// RC missions call RC mission over + mission over here PROC Replay_RejectionCleanup() // If the player isn't in a vehicle, we clear his tasks upon replay rejection IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID()) CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID()) ENDIF ENDIF ENDIF // flow related cleanup IF DoesThisReplayTypeUseStoryMissionLauncher() g_replay.replayStageID = RS_REJECTED ELSE // non story missions just finish cleaning up, and tell flow that mission is over (if needed) SWITCH g_replay.replayType #if not USE_CLF_DLC #if not USE_NRM_DLC CASE REPLAY_TYPE_RANDOM_CHARACTER // Call the common RC Mission Over procedure (also called if player passes mission, or fails non-replay mission) g_eRC_MissionIDs eRCMission eRCMission = INT_TO_ENUM(g_eRC_MissionIDs, g_replay.replayCoreVarsIndex) Mission_Over(g_RandomChars[eRCMission].rcMissionCandidateID) // don't update playstats, as this was done when the RC was failed RC_MISSION_OVER(eRCMission, FALSE) BREAK #ENDIF #ENDIF CASE REPLAY_TYPE_MINIGAME // handled by launchers BREAK CASE REPLAY_TYPE_MISSION BREAK ENDSWITCH Reset_All_Replay_Variables() ENDIF ENDPROC /// PURPOSE: /// Checks if the character specified exists and has been killed /// PARAMS: /// eChar - the player character we are checking /// RETURNS: /// TRUE if char exists and has been killed, FALSE otherwise FUNC BOOL HAS_CHAR_DIED(enumCharacterList eChar) INT iChar enumCharacterList Eped FOR iChar = 0 TO NUM_PLAYER_PED_IDS -1 ePed = GET_PLAYER_PED_ENUM(g_piCreatedPlayerPedIDs[iChar]) IF ePed = eChar IF DOES_ENTITY_EXIST(g_piCreatedPlayerPedIDs[iChar]) IF IS_PED_INJURED(g_piCreatedPlayerPedIDs[iChar]) RETURN TRUE ENDIF ENDIF ENDIF ENDFOR RETURN FALSE ENDFUNC /// PURPOSE: /// Called when the player rejects a replay. /// Returns the player to gameplay, where they were when they failed. /// Unless this is a special case where we need to respawn the player elsewhere. /// (Any changes to this may need to go in Replay_Accepted_PrepMission) PROC Replay_Player_Has_Rejected() VEHICLE_INDEX vehPlayer VEHICLE_INDEX mPlayerDiedInRestrictedVehicle BOOL bPlayerHasWarped = FALSE VECTOR vShopWarpPos FLOAT fShopWarpHeading CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") CPRINTLN(DEBUG_REPLAY, " Player Has Rejected Replay") CPRINTLN(DEBUG_REPLAY, "------------------------------------------------") RESET_MISSION_STATS_SYSTEM() //fix for 1588127 #if USE_CLF_DLC IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watchCLF")) > 0 TERMINATE_STAT_WATCHER() ENDIF #endif #if USE_NRM_DLC IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watchNRM")) > 0 TERMINATE_STAT_WATCHER() ENDIF #endif #if not USE_CLF_DLC #if not USE_NRM_DLC IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("mission_stat_watcher")) > 0 TERMINATE_STAT_WATCHER() ENDIF #endif #endif // Fade out, unpause, wait for mission to cleanup + pause again Cleanup_Fail_Audio() Replay_Control_Slow_Motion(FALSE) Replay_Show_Hud(FALSE) DoQuickFadeOut() ReleaseReplayScaleform() Replay_Pause_Game(FALSE) REPLAY_WAIT_FOR_CUTSCENE_TO_STOP() GrabPlayersLastVehicle(vehPlayer) // stop player's last vehicle getting deleted by clear area RemovePlayerFromAnyRestrictedVehicle(mPlayerDiedInRestrictedVehicle) g_replay.replayStageID = RS_REJECTING CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_BLOCK_RESPAWN)) Wait_For_Mission_To_Cleanup() CLEAR_TIMECYCLE_MODIFIER() // don't need to do the rest of the cleanup if in repeat play // as we will be loading a save anyway IF IS_REPEAT_PLAY_ACTIVE() //We don't need to load the hospital scene if the player rejects a replay restart (about to load game) PAUSE_DEATH_ARREST_RESTART(TRUE) IGNORE_NEXT_RESTART(TRUE) CPRINTLN(DEBUG_REPLAY, "Repeat play early replay rejection exit. Set rejected.") g_replay.replayStageID =RS_REJECTED Replay_Pause_Game(FALSE) Replay_Control_Fail_Effect(FALSE) EXIT ENDIF IF g_replay.replayType = REPLAY_TYPE_MISSION OR g_replay.replayType = REPLAY_TYPE_PHONECALL_TRIGGER //Reset mission checkpoint fail count INT iMissionID = GetReplayMissionDataIndex() #IF USE_CLF_DLC g_savedGlobalsClifford.sFlow.missionSavedData[iMissionID].missionFailsNoProgress = 0 #ENDIF #IF USE_NRM_DLC g_savedGlobalsnorman.sFlow.missionSavedData[iMissionID].missionFailsNoProgress = 0 #ENDIF #IF NOT USE_SP_DLC g_savedGlobals.sFlow.missionSavedData[iMissionID].missionFailsNoProgress = 0 #ENDIF ENDIF // -----reset all shops---------------- FORCE_SHOP_RESET_FOR_MISSION_FAILED(FALSE, vShopWarpPos, fShopWarpHeading) // if player is a ped that is not unlocked in flow, we'll need to change him to the mission start character IF NOT IS_PLAYER_PED_AVAILABLE(GET_PLAYER_PED_ENUM(PLAYER_PED_ID())) CPRINTLN(DEBUG_REPLAY, "Player character not unlocked in flow: will change to mission start character.") g_replay.eReplayRejectCharacter = g_startSnapshot.eCharacter ENDIF // if player is being force changed to another character, check if we need to spawn him at the hospital IF g_replay.eReplayRejectCharacter <> NO_CHARACTER IF HAS_CHAR_DIED(g_replay.eReplayRejectCharacter) CPRINTLN(DEBUG_REPLAY, "Player character not unlocked in flow / forced changed and he is dead: respawn at hospital.") Replay_Change_Player_Ped(g_replay.eReplayRejectCharacter) IF DOES_ENTITY_EXIST(PLAYER_PED_ID()) IF NOT IS_PED_INJURED(PLAYER_PED_ID()) EXPLODE_PED_HEAD(PLAYER_PED_ID()) // reset force switch ped here (if this fails as both peds are dead we do switch after respawn) g_replay.eReplayRejectCharacter = NO_CHARACTER ENDIF ENDIF g_bReplayDoRejectWarp = FALSE ELSE CPRINTLN(DEBUG_REPLAY, "Player character not unlocked in flow / forced changed and he is not dead: don't respawn at hospital.") IGNORE_NEXT_RESTART(TRUE) g_bReplayDoRejectWarp = TRUE ENDIF ENDIF // unblock loading screen now so we can get the loading icon WAIT(0) Replay_Block_Load_Screen(FALSE) // if the player is alive we re-pause the game here. (it gets unpaused just before we fade in) // if he is not alive we need the game to be unpaused so he can respawn IF IS_PLAYER_PLAYING(PLAYER_ID()) Replay_Pause_Game(TRUE) ENDIF WaitForPlayerToRespawn(mPlayerDiedInRestrictedVehicle) SetLeaveAreaFlag(TRUE) // force player to leave area before retrying this mission // make invincible so he cant die before we fade back in Replay_Toggle_Invincibility(TRUE) Replay_Freeze_Player(TRUE) // see if mission has specified we need to force change the character IF g_replay.eReplayRejectCharacter <> NO_CHARACTER CPRINTLN(DEBUG_REPLAY, "Player character force changed to ", ENUM_TO_INT(g_replay.eReplayRejectCharacter)) Replay_Change_Player_Ped(g_replay.eReplayRejectCharacter) ELSE // store player's last vehicle as checkpoint vehicle (So we can restore it if needed) // not done if we're switching the player to another character Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_stageSnapshot.mVehicleStruct, g_stageSnapshot, NULL, FALSE, FALSE) ENDIF // respawning // Dead = Hospital. Arrested = Police Station // Other = leave them where they were unless warp location specified IF g_bReplayDoRejectWarp = FALSE CPRINTLN(DEBUG_REPLAY, "Player killed or arrested, not warping.") ELSE bPlayerHasWarped = Do_Replay_Rejected_Warp() ENDIF // check if the player is in a restricted area, remove his helmet // NOTE: Anything that gets added to this section may need to // get added to the prep missions section of replay accepted Do_Replay_Restricted_Area_Warp(bPlayerHasWarped) Do_Replay_Helmet_Check() // clear and repopulate the area ReplayClearArea(vehPlayer, TRUE, bPlayerHasWarped, TRUE, FALSE) IF bPlayerHasWarped = TRUE // player has warped, restore his snapshot vehicle RestoreAnySnapshotVehicle(GET_PLAYER_PED_ENUM(PLAYER_PED_ID())) // clear visible damage and holster weapon Clear_Damage_And_Wetness() SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE) ENDIF // remove any weapons that the player has collected on mission // that aren't yet unlocked in flow RemoveUnavailableweapons() // Remove headset props REMOVE_ALL_HEADSETS() //Make extra sure wanted levels are cleared at this point. IF (IS_PLAYER_PLAYING(PLAYER_ID())) CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID()) ENDIF // Ensure all PostFX are stopped. ANIMPOSTFX_STOP_ALL() //Ensure all TVs are switched off. INT i REPEAT TV_LOC_END i IF g_TVStruct[i].bIsTVOn CPRINTLN(DEBUG_REPLAY, "Turning off TV ", i, " as it was on as a replay was rejected.") g_TVStruct[i].bForceStopTV = TRUE ENDIF ENDREPEAT // reset shitskip skip-to-end variable g_bShitskipToEnd = FALSE // set fade in time (needs to be done before replay rejection cleanup as that resets all variables) INT iFadeTime = DEFAULT_FADE_TIME IF IS_REPLAY_MISSION_A_RAMPAGE() // rejected a rampage, use longer fade CPRINTLN(DEBUG_REPLAY, "Rejected rampage, using longer fade time.") iFadeTime = RAMPAGE_REJECTION_FADE_TIME ENDIF // -----------------Update flow -------------------------------------------------- Replay_RejectionCleanup() // return player control ResetCommonReplayChanges() REPLAY_RESET_EVENT_INFO() // slight delay before fading back in so we don't see repopulated area peds not having anims WAIT(500) IF bPlayerHasWarped = FALSE // restore vehicle's velocity so its not stuck after we unfreeze it RESTORE_VEHICLE_VELOCITY(vehPlayer) // if player hasn't been warped, clear small area around him so he doesn't get run over ReplayClearArea(vehPlayer, TRUE, bPlayerHasWarped, FALSE, TRUE) ENDIF WAIT(0) // fade back in CPRINTLN(DEBUG_REPLAY, "Fading screen back in.") DO_SCREEN_FADE_IN(iFadeTime) ENDPROC