3230 lines
119 KiB
Scheme
Executable File
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
|