Files
gtav-src/script/dev_ng/singleplayer/include/private/replay_private.sch
T
2025-09-29 00:52:08 +02:00

3230 lines
119 KiB
Scheme
Executable File

#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