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

1268 lines
52 KiB
Scheme
Executable File

USING "cutscene_public.sch"
USING "replay_private.sch"
USING "vehicle_gen_public.sch"
USING "respawn_location_private.sch"
#IF IS_DEBUG_BUILD
USING "debug_channels_structs.sch"
#ENDIF
// *****************************************************************************************
//
// MISSION NAME : replay_public.sch
// AUTHOR : Keith McLeman
// MAINTAINED : Ben Rollinson
// : Andy Minghella
// DESCRIPTION : Public Access to Replay functionality.
//
// *****************************************************************************************
/// PURPOSE:
/// Returns whether the player accepted the replay.
/// Should only be called after GET_MISSION_FLOW_SAFE_TO_CLEANUP has returned true.
/// RETURNS:
/// TRUE if the player accepted replay. FALSE otherwise.
FUNC BOOL HAS_PLAYER_ACCEPTED_REPLAY()
IF g_replay.replayStageID = RS_ACCEPTING
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Allows replay controller to tell mission scripts when it is safe to cleanup
/// RETURNS:
/// TRUE when it is safe to do the full cleanup. FALSE otherwise
FUNC BOOL GET_MISSION_FLOW_SAFE_TO_CLEANUP()
IF g_bMagDemoActive
RETURN TRUE // safe to do the full cleanup
ENDIF
IF g_replay.replayStageID = RS_ACCEPTING
OR g_replay.replayStageID = RS_REJECTING
RETURN TRUE // safe to do the full cleanup
ENDIF
// otherwise it is not safe to do the full cleanup
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks if a replay is in progress
/// RETURNS:
/// BOOL TRUE if a replay is in progress, otherwise FALSE
FUNC BOOL IS_REPLAY_IN_PROGRESS()
IF g_replay.replayStageID = RS_ACTIVE
OR g_replay.replayStageID = RS_ACTIVATE
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks if a replay is being processed.
/// Anywhere between mission failed and the replay starting / being declined.
/// NOTE: if this function is edited you will need to update PRIVATE_Is_Safe_To_Start_Communication()
/// RETURNS:
/// True if replay is being processed. False otherwise.
FUNC BOOL IS_REPLAY_BEING_PROCESSED()
IF g_replay.replayStageID = RS_NOT_REQUIRED
OR g_replay.replayStageID = RS_ACTIVE
OR g_replay.replayStageID = RS_REJECTED
OR g_replay.replayStageID = RS_NOT_RUNNING
// either not processing replay screen, or we're currently on a replay
RETURN FALSE
ENDIF
#IF IS_DEBUG_BUILD
IF g_replay.replayStageID =RS_WAITING_FOR_FLOW
// or we're waiting for gameflow to setup (after a debug menu force cleanup)
RETURN FALSE
ENDIF
#ENDIF
RETURN TRUE // we are currently processing a replay
ENDFUNC
// ===========================================================================================================
// Replay Mid-Mission Stage Public Access Functions
// ===========================================================================================================
/// PURPOSE: Sets the mid-mission stage for the current mission and sets a debug name for stat tracking.
/// NOTES: Only the current mission needs to know what this INT represents for that mission.
///
/// PARAMS:
/// paramMidMissionStage - An INT (represents a mission-specific stage of a mission)
/// paramDebugName - A debug string that will be written into Metrics Zone and Smoketest results.
/// bFinalCheckpoint - Would skipping from this checkpoint end the mission? (used in shitskips)
/// bCanLowerCheckpoint - Is this checkpoint allowed to be lower then the previous checkpoint?
/// (This is only used if multiple checkpoints can be completed out of order)
/// (If you need to use this speak to Andy Minghella otherwise the game will assert)
/// mPedForVehicleSnapshot - use this if you need to store the vehicle info for any ped other than the current player ped (defaults to null, to use the current player ped)
PROC SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(INT paramMidMissionStage, STRING paramDebugName, BOOL bFinalCheckpoint = FALSE, BOOL bCanLowerCheckpoint = FALSE, PED_INDEX mPedForVehicleSnapshot=NULL, BOOL bStoreCheckpointVehicle = TRUE)
IF bCanLowerCheckpoint = TRUE
#if not IS_DEBUG_BUILD
IF NOT ARE_STRINGS_EQUAL("FinaleC2", GET_THIS_SCRIPT_NAME())
CPRINTLN(DEBUG_REPLAY,"Script is force lowering replay checkpoint, bug for Andy Minghella. script= ", GET_THIS_SCRIPT_NAME())
SCRIPT_ASSERT("Script is force lowering replay checkpoint, bug for Andy Minghella.")
ENDIF
#endif
ENDIF
BOOL bNewCheckpoint = FALSE
IF bCanLowerCheckpoint = TRUE
//special case mission that can lower checkpoint
// store new checkpoint if the checkpoint number is different to stored
IF paramMidMissionStage <> g_replayMissionStage
bNewCheckpoint = TRUE
ENDIF
ELSE
// normal mission, only store checkpoint if new checkpoint number is higher than stored one
IF paramMidMissionStage > g_replayMissionStage
bNewCheckpoint = TRUE
ENDIF
ENDIF
// only update snapshot etc if this is a new mission stage
IF bNewCheckpoint = TRUE
CPRINTLN(DEBUG_REPLAY, GET_THIS_SCRIPT_NAME(), " has set Mid-Mission replay stage to: ", paramMidMissionStage)
CPRINTLN(DEBUG_REPLAY,"replayStageReadOnly was previously ", g_replay.replayStageReadOnly)
CPRINTLN(DEBUG_REPLAY,"g_replayMissionStage was previously ", g_replayMissionStage)
COPY_BANK_TRANSLOGS()
IF paramMidMissionStage <= g_replayMissionStage
CPRINTLN(DEBUG_REPLAY,"bCanLowerCheckpoint being used ")
ENDIF
// --------shitskip---------------------------
//Update mission fails without progress if this is a story mission.
SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(GET_THIS_SCRIPT_NAME(), TRUE)
#if USE_CLF_DLC
IF eMissionID != SP_MISSION_NONE AND eMissionID != SP_MISSION_MAX_CLF
g_savedGlobalsClifford.sFlow.missionSavedData[eMissionID].missionFailsNoProgress = 0
// Tell the playstats system this story mission has hit a checkpoint.
INT iVariation = GET_MISSION_VARIATION(eMissionID)
TEXT_LABEL_7 txtStatID = g_sMissionStaticData[eMissionID].statID
PLAYSTATS_MISSION_CHECKPOINT(txtStatID, iVariation, g_replayMissionStage, paramMidMissionStage)
CDEBUG1LN(DEBUG_FLOW, "Flagging playstat MISSION CHECKPOINT for story mission. MissionID:", txtStatID, " Variation:", iVariation, " Checkpoint:", paramMidMissionStage)
endif
#endif
#if USE_NRM_DLC
IF eMissionID != SP_MISSION_NONE AND eMissionID != SP_MISSION_MAX_NRM
g_savedGlobalsnorman.sFlow.missionSavedData[eMissionID].missionFailsNoProgress = 0
// Tell the playstats system this story mission has hit a checkpoint.
INT iVariation = GET_MISSION_VARIATION(eMissionID)
TEXT_LABEL_7 txtStatID = g_sMissionStaticData[eMissionID].statID
PLAYSTATS_MISSION_CHECKPOINT(txtStatID, iVariation, g_replayMissionStage, paramMidMissionStage)
CDEBUG1LN(DEBUG_FLOW, "Flagging playstat MISSION CHECKPOINT for story mission. MissionID:", txtStatID, " Variation:", iVariation, " Checkpoint:", paramMidMissionStage)
endif
#endif
#if not USE_CLF_DLC
#if not USE_NRM_DLC
IF eMissionID != SP_MISSION_NONE AND eMissionID != SP_MISSION_MAX
g_savedGlobals.sFlow.missionSavedData[eMissionID].missionFailsNoProgress = 0
// Tell the playstats system this story mission has hit a checkpoint.
INT iVariation = GET_MISSION_VARIATION(eMissionID)
TEXT_LABEL_7 txtStatID = g_sMissionStaticData[eMissionID].statID
IF eMissionID = 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
PLAYSTATS_MISSION_CHECKPOINT(txtStatID, iVariation, g_replayMissionStage, paramMidMissionStage)
CDEBUG1LN(DEBUG_FLOW, "Flagging playstat MISSION CHECKPOINT for story mission. MissionID:", txtStatID, " Variation:", iVariation, " Checkpoint:", paramMidMissionStage)
ELSE
// not a story mission, see if its an RC that uses shitskips
g_eRC_MissionIDs eRCMissionID = Get_RC_MissionID_For_Script(GET_THIS_SCRIPT_NAME(), TRUE)
IF eRCMissionID <> NO_RC_MISSION
g_savedGlobals.sRandomChars.savedRC[eRCMissionID].iFailsNoProgress = 0
// Tell the playstats system this story mission has hit a checkpoint.
TEXT_LABEL tStatLabel = GET_RC_STAT_ID(eRCMissionID)
PLAYSTATS_MISSION_CHECKPOINT(tStatLabel, 0, g_replayMissionStage, paramMidMissionStage)
CDEBUG1LN(DEBUG_FLOW, "Flagging playstat MISSION CHECKPOINT for RC mission. Script:", GET_THIS_SCRIPT_NAME(), " Variation:", 0, " Checkpoint:", paramMidMissionStage, " RC statID = ", tStatLabel)
ELSE
// check if this is a bailbond mission
INT iBailBond
iBailBond = GET_BAIL_BOND_MISSION_FROM_SCRIPT(g_replay.replayScriptName)
IF iBailBond >-1
g_savedGlobals.sBailBondData.iFailsNoProgress[iBailBond] = 0
ENDIF
ENDIF
ENDIF
#endif
#endif
g_bShitskipToEnd = bFinalCheckpoint // if this is the final checkpoint, shitskipping from here would end the mission
// --------------replay variables ------------------------------
g_replayMissionStage = paramMidMissionStage
Store_Game_State_Snapshot_For_Stage(paramMidMissionStage, paramDebugName, mPedForVehicleSnapshot, bStoreCheckpointVehicle)
#IF IS_FINAL_BUILD
//Keeps final build compiling.
IF ARE_STRINGS_EQUAL(paramDebugName, "")
ENDIF
#ENDIF
ELSE
IF paramMidMissionStage < g_replayMissionStage
CPRINTLN(DEBUG_REPLAY, GET_THIS_SCRIPT_NAME(), " tried to set Mid-Mission replay stage to a lower value: ", paramMidMissionStage)
CPRINTLN(DEBUG_REPLAY,"g_replayMissionStage is currently ", g_replayMissionStage)
ELSE
CPRINTLN(DEBUG_REPLAY, GET_THIS_SCRIPT_NAME(), " tried to set Mid-Mission replay stage to its current value: ", paramMidMissionStage)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Sets the mid-mission stage for the current mission.
/// NOTES: Only the current mission needs to know what this INT represents for that mission.
/// It is the original version of this variable that gets written to by the mission. A copy of
/// this variable is read by the mission - this ensures that a mission being replayed has
/// access to a mid-mission stage value from the previous play of the mission that is in
/// no danger of being overwritten by the current replay of the mission.
/// PARAMS:
/// paramMidMissionStage - An INT (represents a mission-specific stage of a mission)
/// bFinalCheckpoint - Would skipping from this checkpoint end the mission? (used in shitskips)
PROC SET_REPLAY_MID_MISSION_STAGE(INT paramMidMissionStage, BOOL bFinalCheckpoint = FALSE)
SET_REPLAY_MID_MISSION_STAGE_WITH_NAME(paramMidMissionStage, "NOT SET", bFinalCheckpoint)
ENDPROC
// PURPOSE: Returns the mid-mission stage to the current mission.
// NOTES: The meaning of this INT is known only to the mission being replayed.
// It is a copy of the variable that gets returned to the mission. The original
// can get written to while the mission is in progress so we use a read-only
// copy to ensure the data doesn't get corrupted during a replay.
//
// RETURN VALUE: INT Replay Mid-Mission Stage
FUNC INT GET_REPLAY_MID_MISSION_STAGE()
// Only a mission being replayed needs access to this variable - it means nothing to every other mission
IF NOT (g_replay.replayStageID = RS_ACTIVE)
AND NOT (g_replay.replayStageID = RS_ACTIVATE)
CERRORLN(DEBUG_REPLAY, GET_THIS_SCRIPT_NAME(), " has requested access to the Mid-Mission Stage variable when not on a replay.")
SCRIPT_ASSERT("Mid-Mission Replay Stage variable being requested when a replay is not active - Tell Andrew Minghella")
RETURN 0
ENDIF
RETURN g_replay.replayStageReadOnly
ENDFUNC
/// PURPOSE:
/// Returns the vehicle index that was stored when the mission launched
/// (the index is the player's last vehicle if close enough to be stored)
/// RETURNS:
/// VEHICLE_INDEX of the vehicle the player triggered mission with
FUNC VEHICLE_INDEX GET_MISSION_START_VEHICLE_INDEX()
RETURN g_startSnapshot.mVehicleIndex
ENDFUNC
/// PURPOSE:
/// Moves the mission start vehicle to position specified
/// PARAMS:
/// vPos - position to move it o
/// fHeading - new heading to use
PROC SET_POSITION_OF_MISSION_START_VEHICLE(VECTOR vPos, FLOAT fHeading)
IF DOES_ENTITY_EXIST(g_startSnapshot.mVehicleIndex)
IF IS_VEHICLE_DRIVEABLE(g_startSnapshot.mVehicleIndex)
SET_ENTITY_COORDS(g_startSnapshot.mVehicleIndex, vPos)
SET_ENTITY_HEADING(g_startSnapshot.mVehicleIndex, fHeading)
SET_VEHICLE_ON_GROUND_PROPERLY(g_startSnapshot.mVehicleIndex)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Sets the mission start vehicle as a car gen
/// PARAMS:
/// vPos = where to set the vehicle as a vehicle gen (if set to <<0.0,0.0,0.0>> it will use the vehicle's current pos and heading
/// fHeading: the heading to use when setting vehicle as a vehicle gen
/// bUseClosestSafehouse = would you like to set this vehicle as a vehicle gen at the nearest savehouse?
/// eCharacter = which character's savehouse would you like to use?
PROC SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN(VECTOR vPos, FLOAT fHeading, BOOL bUseClosestSafehouse = FALSE, enumCharacterList eCharacter = NO_CHARACTER)
//CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN called")
IF DOES_ENTITY_EXIST(g_startSnapshot.mVehicleIndex)
IF IS_VEHICLE_DRIVEABLE(g_startSnapshot.mVehicleIndex)
IF GET_VEHICLE_GEN_VEHICLE_INDEX(VEHGEN_MISSION_VEH) != g_startSnapshot.mVehicleIndex
// nearest savehouse?
IF bUseClosestSafehouse = TRUE
VECTOR vSafehousePos
FLOAT fSavehouseHeading
IF GET_CAR_RESPOT_POS_FOR_NEAREST_SAVEHOUSE(GET_ENTITY_COORDS(g_startSnapshot.mVehicleIndex), eCharacter, vSafehousePos, fSaveHouseHeading)
// we found a safehouse, update pos and heading used
vPos = vSafehousePos
fHeading = fSavehouseHeading
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN got savehouse pos ", vPos, " heading", fHeading)
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN failed to find nearest savehouse")
ENDIF
ENDIF
SET_MISSION_VEHICLE_GEN_VEHICLE(g_startSnapshot.mVehicleIndex, vPos, fHeading)
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN using custom pos ", vPos, " heading", fHeading)
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN vehicle is already vehicle gen")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN not driveable")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_START_VEHICLE_AS_VEHICLE_GEN doesn't exist")
ENDIF
ENDPROC
/// PURPOSE:
/// Sets the current/last vehicle of the players as a car gen
/// PARAMS:
/// vPos = where to set the vehicle as a vehicle gen (if set to <<0.0,0.0,0.0>> it will use the vehicle's current pos and heading
/// fHeading: the heading to use when setting vehicle as a vehicle gen
/// bUseClosestSafehouse = would you like to set this vehicle as a vehicle gen at the nearest savehouse?
/// eCharacter = which character's savehouse would you like to use?
PROC SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN(VECTOR vPos, FLOAT fHeading, BOOL bUseClosestSafehouse = FALSE, enumCharacterList eCharacter = NO_CHARACTER)
//CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN called")
IF DOES_ENTITY_EXIST(GET_PLAYERS_LAST_VEHICLE())
IF IS_VEHICLE_DRIVEABLE(GET_PLAYERS_LAST_VEHICLE())
IF GET_VEHICLE_GEN_VEHICLE_INDEX(VEHGEN_MISSION_VEH) != GET_PLAYERS_LAST_VEHICLE()
// nearest savehouse?
IF bUseClosestSafehouse = TRUE
VECTOR vSafehousePos
FLOAT fSavehouseHeading
IF GET_CAR_RESPOT_POS_FOR_NEAREST_SAVEHOUSE(GET_ENTITY_COORDS(GET_PLAYERS_LAST_VEHICLE()), eCharacter, vSafehousePos, fSaveHouseHeading)
// we found a safehouse, update pos and heading used
vPos = vSafehousePos
fHeading = fSavehouseHeading
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN got savehouse pos ", vPos, " heading", fHeading)
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN failed to find nearest savehouse")
ENDIF
ENDIF
SET_MISSION_VEHICLE_GEN_VEHICLE(GET_PLAYERS_LAST_VEHICLE(), vPos, fHeading)
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN using custom pos ", vPos, " heading", fHeading)
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN vehicle is already vehicle gen")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN not driveable")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "SET_MISSION_LAST_VEHICLE_AS_VEHICLE_GEN doesn't exist")
ENDIF
ENDPROC
/// PURPOSE:
/// Returns whether the start snapshot has a vehicle saved in it.
/// RETURNS:
/// True if the start snapshot has a vehicle saved in it
FUNC BOOL IS_REPLAY_START_VEHICLE_AVAILABLE()
RETURN IsSnapshotVehicleAvailable(g_startSnapshot.mVehicleStruct)
ENDFUNC
/// PURPOSE:
/// Start loading the model for a replay start vehicle.
PROC REQUEST_REPLAY_START_VEHICLE_MODEL()
RequestSnapshotVehicleModel(g_startSnapshot.mVehicleStruct)
ENDPROC
/// PURPOSE:
/// Check if a the model for a replay start vehicle is loaded.
/// RETURNS:
/// True if the model has loaded
FUNC BOOL HAS_REPLAY_START_VEHICLE_LOADED()
RETURN HasSnapshotVehicleLoaded(g_startSnapshot.mVehicleStruct)
ENDFUNC
/// PURPOSE:
/// Returns the model of the replay start vehicle (stored in the mission start snapshot)
/// RETURNS:
/// MODEL_NAMES vehicle model stored in start snapshot or DUMMY_MODEL if there isn't one
FUNC MODEL_NAMES GET_REPLAY_START_VEHICLE_MODEL()
RETURN g_startSnapshot.mVehicleStruct.mVehicle.eModel
ENDFUNC
/// PURPOSE:
/// Returns the model of the replay vehicle (stored in the mission stage snapshot)
/// RETURNS:
/// MODEL_NAMES vehicle model stored in stage snapshot or DUMMY_MODEL if there isn't one
FUNC MODEL_NAMES GET_REPLAY_CHECKPOINT_VEHICLE_MODEL()
RETURN g_stageSnapshot.mVehicleStruct.mVehicle.eModel
ENDFUNC
/// PURPOSE:
/// Checks whether the model is under an allowed size
/// PARAMS:
/// vAllowableSize - how large the vehicle is allowed to be
/// bUseDefaultSize - just use the default size check? (ok for most average vehicles)
/// RETURNS:
/// TRUE if the vehicle is of allowable size. FALSE otherwise
FUNC BOOL IS_REPLAY_VEHICLE_MODEL_UNDER_SIZE_LIMIT(MODEL_NAMES eModel, VECTOR vAllowableSize, BOOL bUseDefaultSize = TRUE)
VECTOR vVehicleSizeMin
VECTOR vVehicleSizeMax
IF eModel = DUMMY_MODEL_FOR_SCRIPT
RETURN FALSE // no vehicle available
ENDIF
// default allowable size
IF bUseDefaultSize = TRUE
vAllowableSize = GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR()
ENDIF
GET_MODEL_DIMENSIONS(eModel, vVehicleSizeMin, vVehicleSizeMax)
IF vVehicleSizeMax.x - vVehicleSizeMin.x > vAllowableSize.x
RETURN FALSE // vehicle too large
ELIF vVehicleSizeMax.y - vVehicleSizeMin.y > vAllowableSize.y
RETURN FALSE // vehicle too large
ELIF vVehicleSizeMax.z - vVehicleSizeMin.z > vAllowableSize.z
RETURN FALSE // vehicle too large
ENDIF
RETURN TRUE // vehicle is under the size limit
ENDFUNC
/// PURPOSE:
/// Checks whether the checkpoint vehicle is under an allowed size
/// PARAMS:
/// vAllowableSize - how large the vehicle is allowed to be
/// bUseDefaultSize - just use the default size check? (ok for most average vehicles)
/// RETURNS:
/// TRUE if the vehicle is of allowable size. FALSE otherwise
FUNC BOOL IS_REPLAY_CHECKPOINT_VEHICLE_UNDER_SIZE_LIMIT(VECTOR vAllowableSize, BOOL bUseDefaultSize = TRUE)
RETURN IS_REPLAY_VEHICLE_MODEL_UNDER_SIZE_LIMIT(g_stageSnapshot.mVehicleStruct.mVehicle.eModel, vAllowableSize, bUseDefaultSize)
ENDFUNC
/// PURPOSE:
/// Checks whether the stored replay start vehicle is under an allowed size
/// PARAMS:
/// vAllowableSize - how large the vehicle is allowed to be
/// bUseDefaultSize - just use the default size check? (ok for most average vehicles)
/// RETURNS:
/// TRUE if the vehicle is of allowable size. FALSE otherwise
FUNC BOOL IS_REPLAY_START_VEHICLE_UNDER_SIZE_LIMIT(VECTOR vAllowableSize, BOOL bUseDefaultSize = TRUE)
RETURN IS_REPLAY_VEHICLE_MODEL_UNDER_SIZE_LIMIT(g_startSnapshot.mVehicleStruct.mVehicle.eModel, vAllowableSize, bUseDefaultSize)
ENDFUNC
/// PURPOSE:
/// Checks if the stored replay start vehicle is a specific model.
// IS_REPLAY_START_VEHICLE_AVAILABLE() should be checked before attempting
// this query.
/// PARAMS:
/// paramVehicleModel - the model type we are checking against
/// RETURNS:
/// TRUE if the start replay vehicle is the model specified.
FUNC BOOL IS_REPLAY_START_VEHICLE_THIS_MODEL(MODEL_NAMES paramVehicleModel)
RETURN IsSnapshotVehicleThisModel(g_startSnapshot, paramVehicleModel)
ENDFUNC
/// PURPOSE:
/// Creates the replay vehicle saved for the start of the mission.
// IS_REPLAY_START_VEHICLE_AVAILABLE() should be checked before attempting to create
// a replay checkpoint vehicle.
/// PARAMS:
/// paramCoords - where to create the replay vehicle (if <<0.0,0.0,0.0>> it is created at the co-ords from the snapshot)
/// paramHeading - the replay vehicle's heading
/// RETURNS:
/// The vehicle index of the replay vehicle
FUNC VEHICLE_INDEX CREATE_REPLAY_START_VEHICLE(VECTOR paramCoords, FLOAT paramHeading = 0.0)
RETURN CreateSnapshotVehicle(g_startSnapshot.mVehicleStruct, paramCoords, paramHeading)
ENDFUNC
/// PURPOSE:
/// Returns whether the checkpoint snapshot has a vehicle saved in it.
/// RETURNS:
/// True if the checkpoint snapshot has a vehicle saved in it
FUNC BOOL IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE()
RETURN IsSnapshotVehicleAvailable(g_stageSnapshot.mVehicleStruct)
ENDFUNC
/// PURPOSE:
/// Allows the automatically stored replay checkpoint vehicle to be overriden by the mission
/// scripter.
PROC OVERRIDE_REPLAY_CHECKPOINT_VEHICLE(VEHICLE_INDEX paramVehicle)
Store_Vehicle_Snapshot_For_Vehicle(g_stageSnapshot.mVehicleStruct, g_stageSnapshot, paramVehicle, TRUE)
ENDPROC
/// PURPOSE:
/// Returns which player character the vehicle snapshot was stored for
/// PARAMS:
/// bStartSnapshot - are we checking the start snapshot (if false it checks the stage snapshot)
/// RETURNS:
/// enumCharacterList the player character that the vehicle snapshot was stored for (or NO_CHARACTER)
FUNC enumCharacterList GET_REPLAY_VEHICLE_OWNER(BOOL bStartSnapshot)
IF bStartSnapshot = TRUE
RETURN g_startSnapshot.eVehicleOwner
ELSE
RETURN g_stageSnapshot.eVehicleOwner
ENDIF
ENDFUNC
/// PURPOSE:
/// Start loading the model for a replay checkpoint vehicle.
PROC REQUEST_REPLAY_CHECKPOINT_VEHICLE_MODEL()
RequestSnapshotVehicleModel(g_stageSnapshot.mVehicleStruct)
ENDPROC
/// PURPOSE:
/// Checks the model of the checkpoint vehicle and returns whether its suitable for a car chase
/// PARAMS:
/// bAllowHelis - Are helicopters allowed for this car chase?
/// bAllowCopCars - Are cop cars allowed for this car chase?
/// RETURNS:
/// TRUE if the vehicle is suitable for use in a car chase
FUNC BOOL IS_REPLAY_CHECKPOINT_VEHICLE_OK_FOR_CHASE()
// no vehicle available
IF NOT IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE()
RETURN FALSE
ENDIF
// don't use boats, planes or trains
IF IS_THIS_MODEL_A_BOAT(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
OR IS_THIS_MODEL_A_PLANE(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
OR IS_THIS_MODEL_A_TRAIN(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
RETURN FALSE
ENDIF
// check that the vehicle is fast enough for use in car chase
FLOAT fSpeed = GET_VEHICLE_MODEL_ESTIMATED_MAX_SPEED(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "Vehicle speed is: ", fSpeed, "Min for car chase is 37")
IF fSpeed < 37.0
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Check if a the model for a replay checkpoint vehicle is loaded.
/// RETURNS:
/// True if the model has loaded
FUNC BOOL HAS_REPLAY_CHECKPOINT_VEHICLE_LOADED()
RETURN HasSnapshotVehicleLoaded(g_stageSnapshot.mVehicleStruct)
ENDFUNC
/// PURPOSE:
/// Checks if the stored replay checkpoint vehicle is a specific model.
// IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE() should be checked before attempting
// this query.
/// PARAMS:
/// paramVehicleModel - the model type we are checking against
/// RETURNS:
/// TRUE if the start replay vehicle is the model specified.
FUNC BOOL IS_REPLAY_CHECKPOINT_VEHICLE_THIS_MODEL(MODEL_NAMES paramVehicleModel)
RETURN IsSnapshotVehicleThisModel(g_stageSnapshot, paramVehicleModel)
ENDFUNC
/// PURPOSE:
/// Creates the replay vehicle saved for the checkpoint of the mission.
// IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE() should be checked before attempting to create
// a replay checkpoint vehicle.
/// PARAMS:
/// paramCoords - where to create the replay vehicle (if <<0.0,0.0,0.0>> it is created at the co-ords from the snapshot)
/// paramHeading - the replay vehicle's heading
/// RETURNS:
/// The vehicle index of the replay vehicle
FUNC VEHICLE_INDEX CREATE_REPLAY_CHECKPOINT_VEHICLE(VECTOR paramCoords, FLOAT paramHeading = 0.0)
RETURN CreateSnapshotVehicle(g_stageSnapshot.mVehicleStruct, paramCoords, paramHeading)
ENDFUNC
/// PURPOSE:
/// Returns the coords the player was standing at when they hit the last replay checkpoint.
/// RETURNS:
/// Vector: player co-ords at the last replay checkpoint
FUNC VECTOR GET_REPLAY_CHECKPOINT_PLAYER_POSITION()
RETURN g_stageSnapshot.mPlayerStruct.vPos
ENDFUNC
/// PURPOSE:
/// Returns the heading the player was facing when they hit the last replay checkpoint.
/// RETURNS:
/// Float: player heading at the last replay checkpoint
FUNC FLOAT GET_REPLAY_CHECKPOINT_PLAYER_HEADING()
RETURN g_stageSnapshot.mPlayerStruct.fHeading
ENDFUNC
/// PURPOSE:
/// Called by launchers for missions that trigger by the player entering a vehicle
/// This stores the player's last vehicle instead of the mission trigger vehicle
PROC STORE_START_PLAYER_VEHICLE_SNAPSHOT()
Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_startSnapshot.mVehicleStruct, g_startSnapshot)
ENDPROC
/// PURPOSE:
/// Used to set where the player's vehicle will be recreated if he rejects a replay for this mission.
/// (This is only used if the player fails without being killed / arrested)
/// PARAMS:
/// vVehiclePos - where the respawn the player's vehicle
/// fVehicleHeading - the heading to use for the player's vehicle
PROC SET_REPLAY_DECLINED_VEHICLE_WARP_LOCATION(VECTOR vVehiclePos, FLOAT fVehicleHeading)
Set_Vehicle_Snapshot_Pos(g_stageSnapshot.mVehicleStruct, vVehiclePos, fVehicleHeading)
ENDPROC
/// PURPOSE:
/// Checks if a replay is being processed for the RC mission specified
/// PARAMS:
/// eRCMissionID - the RC mission we are checking for
/// RETURNS:
/// TRUE if this RC mission is being processed for a replay.
#if not USE_CLF_DLC
#if not USE_NRM_DLC
FUNC BOOL IS_THIS_RC_MISSION_BEING_PROCESSED_FOR_REPLAY(g_eRC_MissionIDs eRCMissionID)
IF IS_REPLAY_BEING_PROCESSED()
AND g_replay.replayType = REPLAY_TYPE_RANDOM_CHARACTER
AND eRCMissionID = Get_RC_MissionID_For_Script(g_replay.replayScriptName)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
#endif
#endif
/// PURPOSE:
/// Puts the player back in the clothes he started the mission in
PROC RESTORE_MISSION_START_OUTFIT()
CPRINTLN(DEBUG_REPLAY, "Restoring start outfit for", GET_THIS_SCRIPT_NAME())
Restore_Game_State_Snapshot_Clothes(g_startSnapshot)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_PED_VARIATIONS(PLAYER_PED_ID(), g_sLastStoredPlayerPedClothes[GET_PLAYER_PED_ENUM(PLAYER_PED_ID())])
ENDIF
ENDPROC
/// PURPOSE:
/// Returns which character the player was controlling when they launched this mission
/// This is the character they were when the mission start snapshot was taken
FUNC enumCharacterList GET_PLAYER_CHARACTER_AT_MISSION_START()
RETURN g_startSnapshot.eCharacter
ENDFUNC
/// PURPOSE:
/// Returns whether the player was in a vehicle at his last checkpoint
/// RETURNS:
/// TRUE if he was in a vehicle at last checkpoint, otherwise returns FALSE
FUNC BOOL WAS_PLAYER_IN_VEHICLE_AT_CHECKPOINT()
RETURN g_stageSnapshot.mVehicleStruct.bInVehicle
ENDFUNC
/// PURPOSE:
/// Returns whether the player was in a vehicle when he triggered the mission
/// RETURNS:
/// TRUE if he was in a vehicle when he triggered the mission, otherwise returns FALSE
FUNC BOOL WAS_PLAYER_IN_VEHICLE_AT_MISSION_START()
RETURN g_startSnapshot.mVehicleStruct.bInVehicle
ENDFUNC
/// PURPOSE:
/// Checks if the vehicle is suitable for creation for a replay
/// PARAMS:
/// bCarChase - does this vehicle need to be suitable for a car chase?
/// bAllowHelis - is a helicopter a suitable vehicle?
/// bAllowCopCars - are cop vehicles suitable?
/// RETURNS:
/// TRUE if all checks are passed, FALSE otherwise
FUNC BOOL IS_CHECKPOINT_VEHICLE_SUITABLE(BOOL bCarChase = FALSE, BOOL bAllowHelis= FALSE, BOOL bAllowCopCars = FALSE, BOOL bAllowPlanes = TRUE)
// don't allow boats (if a mission needs this, will set up on a bool param)
IF IS_THIS_MODEL_A_BOAT(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "Boats not allowed for this replay.")
RETURN FALSE
ENDIF
IF bAllowHelis= FALSE
AND IS_THIS_MODEL_A_HELI(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "Helicopters not allowed for this replay.")
RETURN FALSE
ENDIF
IF bAllowCopCars= FALSE
AND IS_MODEL_POLICE_VEHICLE(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "Cop vehicles not allowed for this replay.")
RETURN FALSE
ENDIF
IF bAllowPlanes = FALSE
AND IS_THIS_MODEL_A_PLANE(g_stageSnapshot.mVehicleStruct.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "Planes not allowed for this replay.")
RETURN FALSE
ENDIF
// check car chase suitability
IF bCarChase = TRUE
IF NOT IS_REPLAY_CHECKPOINT_VEHICLE_OK_FOR_CHASE()
CPRINTLN(DEBUG_REPLAY, "Vehicle needed for car chase and is not suitable")
RETURN FALSE
ENDIF
ENDIF
RETURN TRUE // checkpoint vehicle is suitable
ENDFUNC
/// PURPOSE:
/// Checks if this replay has a vehicle associated with it.
/// If so, it recreates the vehicle at the co-ords specified. (if the vehicle is suitable)
/// If not, it creates a new vehicle at the co-ords specified (bool available to turn this off)
/// PARAMS:
/// mVehicle - vehicle index of the new vehicle.
/// vVehiclePos - where to create the vehicle.
/// fVehicleHeading - heading of the vehicle.
/// bWarpPlayerIn - If true we warp the player into the car. If false we leave him where he is.
/// bCarChase - does this vehicle need to be suitable for a car chase?
/// bAllowHelis - is a helicopter a suitable vehicle?
/// bAllowCopCars - are cop vehicles suitable?
/// bCreateNewVehicle - if there is no replay vehicle (or it isn't suitable), should we create a new one?
/// mVehicleModel - the model for the new vehicle (only used if no replay vehicle available or it is unsuitable)
/// iColour - the colour of the new vehicle (only used if no replay vehicle available or it is unsuitable)
/// ePlayerPed- if this set to one of the 3 player characters we create that player character's default vehicle (if a replay vehicle isn't available)
PROC CREATE_VEHICLE_FOR_REPLAY(VEHICLE_INDEX &mVehicle, VECTOR vVehiclePos, FLOAT fVehicleHeading, BOOL bWarpPlayerIn = TRUE, BOOL bCarChase = FALSE, BOOL bAllowHelis= FALSE, BOOL bAllowCopCars = FALSE, BOOL bCreateNewVehicle = TRUE, MODEL_NAMES mVehicleModel = ASTEROPE, INT iColour = 0, enumCharacterList ePlayerPed = NO_CHARACTER, BOOL bAllowPlanes = TRUE)
BOOL bUseReplayVehicle = TRUE
IF NOT IS_REPLAY_IN_PROGRESS()
OR NOT IS_REPLAY_CHECKPOINT_VEHICLE_AVAILABLE()
bUseReplayVehicle = FALSE
CPRINTLN(DEBUG_REPLAY, "Not on a replay, or no replay vehicle available")
ENDIF
// check the optional vehicle types
IF bUseReplayVehicle = TRUE
IF NOT IS_CHECKPOINT_VEHICLE_SUITABLE(bCarChase, bAllowHelis, bAllowCopCars, bAllowPlanes)
bUseReplayVehicle = FALSE
ENDIF
ENDIF
IF bUseReplayVehicle = TRUE
CPRINTLN(DEBUG_REPLAY, "Creating replay checkpoint vehicle")
REQUEST_REPLAY_CHECKPOINT_VEHICLE_MODEL()
WHILE NOT HAS_REPLAY_CHECKPOINT_VEHICLE_LOADED()
WAIT(0)
ENDWHILE
// This replay has a vehicle available, create it
mVehicle = CREATE_REPLAY_CHECKPOINT_VEHICLE(vVehiclePos, fVehicleHeading)
ELSE
// No vehicle available for replay. Create a new one?
IF bCreateNewVehicle = TRUE
CPRINTLN(DEBUG_REPLAY, "No replay checkpoint vehicle available- creating a new one")
// If no vector specified, use the vector in the snapshot
IF ARE_VECTORS_EQUAL(vVehiclePos, <<0.0,0.0,0.0>>)
vVehiclePos = g_stageSnapshot.mVehicleStruct.vVehiclePos
fVehicleHeading = g_stageSnapshot.mVehicleStruct.fVehicleHeading
ENDIF
// clear space for the vehicle
CLEAR_AREA(vVehiclePos, 5.0, TRUE) // clear area so we can create the car
DELETE_VEHICLE_GEN_VEHICLES_IN_AREA(vVehiclePos, 5.0)
// create default player vehicle or use model specified?
IF IS_PLAYER_PED_PLAYABLE(ePlayerPed)
CPRINTLN(DEBUG_REPLAY, "Create player's default vehicle: ePlayerPed= ", ePlayerPed)
DELETE_ALL_SCRIPT_CREATED_PLAYER_VEHICLES(ePlayerPed)
WHILE NOT CREATE_PLAYER_VEHICLE(mVehicle, ePlayerPed, vVehiclePos, fVehicleHeading)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPLAY, "Created player's default vehicle: ePlayerPed= ", ePlayerPed)
ELSE
CPRINTLN(DEBUG_REPLAY, "Create new vehicle")
REQUEST_MODEL(mVehicleModel)
WHILE NOT HAS_MODEL_LOADED(mVehicleModel)
WAIT(0)
ENDWHILE
mVehicle = CREATE_VEHICLE(mVehicleModel, vVehiclePos, fVehicleHeading)
IF DOES_ENTITY_EXIST(mVehicle)
AND NOT IS_ENTITY_DEAD(mVehicle)
IF iColour = 0
SET_VEHICLE_COLOUR_COMBINATION(mVehicle,0)
ELIF iColour > 0
SET_VEHICLE_COLOURS(mVehicle, iColour, iColour)
ENDIF
ENDIF
SET_MODEL_AS_NO_LONGER_NEEDED(mVehicleModel)
ENDIF
ENDIF
ENDIF
IF bWarpPlayerIn = TRUE
IF DOES_ENTITY_EXIST(mVehicle)
AND NOT IS_ENTITY_DEAD(mVehicle)
AND DOES_ENTITY_EXIST(PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), mVehicle)
SET_VEHICLE_ON_GROUND_PROPERLY(mVehicle)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Checks if this replay has a vehicle associated with it.
/// If so it recreates the vehicle:
/// If the player triggered mission in a car it recreates the car where it was (if suitable)
/// Otherwise it puts the player in his snapshot car at nearest road node
///
/// If a snapshot vehicle isnt available it puts him in a new car at nearest road node (can be toggled)
/// PARAMS:
/// mVehicle - vehicle index of the new vehicle.
/// bCarChase - does this vehicle need to be suitable for a car chase?
/// bAllowHelis - is a helicopter a suitable vehicle?
/// bAllowCopCars - are cop vehicles suitable?
/// bCreateNewVehicle - if there is no replay vehicle (or it isn't suitable), should we create a new one?
/// mVehicleModel - the model for the new vehicle (only used if no replay vehicle available or it is unsuitable)
/// iColour - the colour of the new vehicle (only used if no replay vehicle available or it is unsuitable)
/// ePlayerPed- if this set to one of the 3 player characters we create that player character's default vehicle (if a replay vehicle isn't available)
PROC CREATE_VEHICLE_FOR_PHONECALL_TRIGGER_REPLAY(VEHICLE_INDEX &mVehicle, BOOL bCarChase = FALSE, BOOL bAllowHelis= FALSE, BOOL bAllowCopCars = FALSE, BOOL bCreateNewVehicle = TRUE, MODEL_NAMES mVehicleModel = ASTEROPE, INT iColour = 0, enumCharacterList ePlayerPed = NO_CHARACTER)
VECTOR vPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
FLOAt fHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
IF WAS_PLAYER_IN_VEHICLE_AT_MISSION_START()
AND IS_CHECKPOINT_VEHICLE_SUITABLE(bCarChase, bAllowHelis, bAllowCopCars)
CPRINTLN(DEBUG_REPLAY, "player was in vehicle when mission triggerd, use the snapshot pos and heading")
// setting these to 0 causes CreateSnapshotVehicle to use the snapshot values
vPos = <<0.0,0.0,0.0>>
fHeading = 0.0
CREATE_VEHICLE_FOR_REPLAY(mVehicle, vPos, fHeading, TRUE, bCarChase, bAllowHelis, bAllowCopCars, bCreateNewVehicle, mVehicleModel, iColour, ePlayerPed)
ELSE
// player wasn't in a vehicle
// OR checkpoint vehicle isn't suitable (may be a heli in the air etc)
// put him in his snapshot vehicle (or a new one) at nearest road node
IF GET_CLOSEST_VEHICLE_NODE_WITH_HEADING(vPos, vPos, fHeading)
CREATE_VEHICLE_FOR_REPLAY(mVehicle, vPos, fHeading, TRUE, bCarChase, bAllowHelis, bAllowCopCars, bCreateNewVehicle, mVehicleModel, iColour, ePlayerPed)
ELSE
// couldn't get a nearby road node, leave player where he is
ENDIF
ENDIF
ENDPROC
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Starts a new metrics tracking stage. Used for metrics and smoketest.
/// This is to be used for missions that don't have many replay checkpoints.
/// PARAMS:
/// sStageName - the debug name for this metrics stage
PROC Start_New_Metrics_Stage(STRING sStageName)
StartNewMetricsStage(1, GET_THIS_SCRIPT_NAME(), sStageName)
ENDPROC
#ENDIF
/// PURPOSE:
/// Attempts to store the weapon the player character was using when he failed a mission.
/// If he had this weapon at his last checkpoint, it is stored.
/// If he didn't have it at his last checkpoint, WEAPONTYPE_INVALID is stored.
/// PARAMS:
/// mPed - the ped index of the player character we want to store the fail weapon of
/// iCharIndex - the index of the player character (CHAR_MICHAEL = 0, CHAR_FRANKLIN = 1 or CHAR_TREVOR = 2)
PROC Store_Fail_Weapon(PED_INDEX mPed, INt iCharIndex)
WEAPON_TYPE mWeapon = WEAPONTYPE_INVALID
IF DOES_ENTITY_EXIST(mPed)
IF GET_CURRENT_PED_WEAPON(mPed, mWeapon, FALSE)
// found usable weapon
IF mWeapon <> WEAPONTYPE_INVALID
AND mWeapon <> WEAPONTYPE_UNARMED
// weapon isn't invalid or unarmed
IF NOT Had_Weapon_At_Last_Checkpoint(iCharIndex, mWeapon)
// player didn't have this weapon at last checkpoint
mWeapon = WEAPONTYPE_INVALID
ENDIF
ENDIF
ENDIF
ENDIF
CPRINTLN(DEBUG_REPLAY, "Storing Fail weapon for Char: ", iCharIndex, " weapon: ", ENUM_TO_INT(mWeapon))
// store fail weapon. Will be WEAPONTYPE_INVALID if player didn't have this weapon at last checkpoint
IF g_replayMissionStage > 0
g_stageSnapshot.mFailWeapon[iCharIndex] = mWeapon
ELSE
g_startSnapshot.mFailWeapon[iCharIndex] = mWeapon
ENDIF
ENDPROC
/// PURPOSE:
/// Returns the weapontype the player character specified was using when he failed this mission
/// (Will be invalid if he didn't have that weapon at his last checkpoint)
/// PARAMS:
/// iCharIndex - the index of the player character (CHAR_MICHAEL = 0, CHAR_FRANKLIN = 1 or CHAR_TREVOR = 2)
/// RETURNS:
/// WEAPON_TYPE the weapon the player had equipped when he failed this misison
FUNC WEAPON_TYPE Get_Fail_Weapon(INT iCharIndex)
IF g_replayMissionStage > 0
RETURN g_stageSnapshot.mFailWeapon[iCharIndex]
ELSE
RETURN g_startSnapshot.mFailWeapon[iCharIndex]
ENDIF
ENDFUNC
/// PURPOSE:
/// Sets a vehicle as restricted. (This should be called when the vehicle is created)
/// The player will be removed from restricted vehicles when they reject a replay, and the vehicle will be deleted.
/// They will also not be recreated when the replay controller creates a snapshot car for the player after rejecting a replay
/// PARAMS:
/// mVehicle - the vehicle index of the vehicle you want to restrict
/// iVehicleNumber - where in the restricted vehicles array you want to put this car
/// (this should be the same each time you create this particular car)
PROC SET_VEHICLE_AS_RESTRICTED(VEHICLE_INDEX mVehicle, INT iVehicleNumber)
g_replay.mRestrictedVehicles[iVehicleNumber] = mVehicle
CPRINTLN(DEBUG_REPLAY, "Restricted vehicle added: ", iVehicleNumber)
ENDPROC
/// PURPOSE:
/// Sets what character the player will be if he rejects the mission replay
/// This should only be used in special cases (e.g. Exile 2 where we can't have the player return to game as Franklin)
/// This does not need to be called to avoid the player returning to gameplay as a locked character (That is already handled by the replay controller)
/// If you want to use this function- check with Andy Minghella or Ben Rollinson
PROC SET_REPLAY_REJECTED_CHARACTER(enumCharacterList eReplayRejectCharacter)
g_replay.eReplayRejectCharacter = eReplayRejectCharacter
CPRINTLN(DEBUG_REPLAY, "SET_REPLAY_REJECTED_CHARACTER: to ", ENUM_TO_INT(eReplayRejectCharacter))
ENDPROC
/// PURPOSE:
/// Allows missions that only have the "mission start" checkpoint to have shitskips display "skip mission"
PROC SET_START_CHECKPOINT_AS_FINAL()
g_bShitskipToEnd = TRUE
ENDPROC
/// PURPOSE:
/// Returns the position and heading of the player, from when he triggered this mission
/// PARAMS:
/// vPos - the pos he was in.
/// fHeading - his heading.
PROC GET_MISSION_START_POS_AND_HEADING(VECTOR &vPos, FLOAT &fHeading)
vPos = g_startSnapshot.mPlayerStruct.vPos
fHeading = g_startSnapshot.mPlayerStruct.fHeading
ENDPROC
/// PURPOSE:
/// Checks if a replay is currently being set up.
/// This is only used by the new replay warp system.
/// RETURNS:
/// This will return TRUE after START_REPLAY_SETUP has been called, until END_REPLAY_SETUP is called.
FUNC BOOL IS_REPLAY_BEING_SET_UP()
RETURN IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_REPLAY_SETUP_STARTED))
ENDFUNC
/// PURPOSE:
/// Returns the size of the load scene the replay controller will use to set up the replay
/// RETURNS:
/// INT size to use
FUNC FLOAT GET_REPLAY_LOAD_SCENE_SIZE()
IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_FULLY_INTERIOR))
CPRINTLN(DEBUG_REPLAY, "GET_REPLAY_LOAD_SCENE_SIZE: Interior.")
RETURN REPLAY_LOAD_SCENE_SIZE_INTERIOR // smaller stream size for interior
ENDIF
CPRINTLN(DEBUG_REPLAY, "GET_REPLAY_LOAD_SCENE_SIZE: Normal.")
RETURN REPLAY_LOAD_SCENE_SIZE
ENDFUNC
/// PURPOSE:
/// Handles warping the player for a replay setup.
/// THIS SHOULD ONLY BE CALLED BY THE REPLAY CONTROLLER
/// PARAMS:
/// iEarlyOutTime - timer used for early out of vehicle repopulation
/// streamVolID - handle to the volumne we are streaming
/// RETURNS:
/// TRUE when warp is complete.
FUNC BOOL REPLAY_WARP_PLAYER(INT &iEarlyOutTime)
IF NOT IS_REPLAY_IN_PROGRESS()
RETURN TRUE
ENDIF
IF IS_PLAYER_PLAYING(PLAYER_ID())
SWITCH g_eReplayWarpStage
CASE RWS_WAIT
// waiting for mission to setup warp pos
BREAK
// start the teleport
CASE RWS_START
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER started")
SET_GAME_PAUSED(FALSE)
// turn off emergency streaming (pausing game will ensure player doesnt fall through floor)
//SET_GAME_PAUSES_FOR_STREAMING(FALSE)
// move player now
CLEAR_AREA(g_eReplayWarpPos, 5.0, TRUE)
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_ENTITY_COORDS(PLAYER_PED_ID(), g_eReplayWarpPos)
SET_ENTITY_HEADING(PLAYER_PED_ID(), g_eReplayWarpHeading)
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
ENDIF
ENDIF
NEW_LOAD_SCENE_START_SPHERE(g_eReplayWarpPos, GET_REPLAY_LOAD_SCENE_SIZE()) // start the load scene in same frame (1481684- requested by Ian)
WAIT(0) // wait a frame for the camera to catch up before pausing
// clear the area
CLEAR_AREA(g_eReplayWarpPos, 5000, TRUE, FALSE)
CLEAR_AREA_OF_OBJECTS(g_eReplayWarpPos, 5000)
ReplayClearParticles(5000)
CLEAR_ALL_MUST_LEAVE_AREA_VEHICLE_GEN_FLAGS()
RESET_VEHICLE_GEN_LOADED_CHECKS()
SETTIMERA(0)
SET_GAME_PAUSED(TRUE)
g_eReplayWarpStage = RWS_START_LOAD
BREAK
// try to create the new load scene
CASE RWS_START_LOAD
IF IS_NEW_LOAD_SCENE_ACTIVE()
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER new load scene succesfully started.")
SETTIMERA(0)
g_eReplayWarpStage = RWS_DO_WARP
ELSE
IF NEW_LOAD_SCENE_START_SPHERE(g_eReplayWarpPos, GET_REPLAY_LOAD_SCENE_SIZE())
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER new load scene succesfully started.")
SETTIMERA(0)
g_eReplayWarpStage = RWS_DO_WARP
ELSE
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER trying to start new load scene. ", TIMERA())
// early out check
IF TIMERA() > 5000
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER took too long to create new load scene. Go to RWS_POST_WARP.")
g_eReplayWarpStage =RWS_POST_WARP
ENDIF
ENDIF
ENDIF
BREAK
// wait for the new load scene to finish
CASE RWS_DO_WARP
// wait for warp to finish
IF IS_NEW_LOAD_SCENE_ACTIVE()
IF IS_NEW_LOAD_SCENE_LOADED()
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER warp finished")
g_eReplayWarpStage = RWS_POST_WARP
ELSE
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER new load scene still loading: ", TIMERA())
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER new load scene not active")
ENDIF
// check for early out
IF TIMERA() > REPLAY_LOAD_SCENE_TIMEOUT
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER took too long: early out")
g_eReplayWarpStage = RWS_POST_WARP
ENDIF
// check for debug skip
#IF IS_DEBUG_BUILD
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_V))
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER debug skipping streaming.")
g_eReplayWarpStage = RWS_POST_WARP
ENDIF
#ENDIF
BREAK
// post warp cleanup- then start repopulation
CASE RWS_POST_WARP
// debug only breaks for checking missions aren't clearing the area we've just repopulated
//BREAK_ON_NATIVE_COMMAND("CLEAR_AREA", FALSE)
//BREAK_ON_NATIVE_COMMAND("CLEAR_AREA_OF_PEDS", FALSE)
// 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)
// allow emergency streaming again
//SET_GAME_PAUSES_FOR_STREAMING(TRUE)
// refill population
INSTANTLY_FILL_PED_POPULATION()
IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DO_VEHICLE_REPOP))
INSTANTLY_FILL_VEHICLE_POPULATION()
iEarlyOutTime = GET_GAME_TIMER() + REPOP_EARLY_OUT
ELSE
// if not doing vehicle repop, set the early out
iEarlyOutTime = GET_GAME_TIMER() + REPOP_MIN_WAIT
ENDIF
POPULATE_NOW()
ENDIF
ENDIF
g_eReplayWarpStage = RWS_REPOPULATE
BREAK
// wait for repopulation to finish
CASE RWS_REPOPULATE
IF (HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED()
AND HAVE_ALL_VEHICLE_GENS_LOADED_NEAR_PLAYER()
AND GET_GAME_TIMER() > iEarlyOutTime - (REPOP_EARLY_OUT-REPOP_MIN_WAIT))
OR GET_GAME_TIMER() > iEarlyOutTime
IF GET_GAME_TIMER() > iEarlyOutTime
IF IS_BIT_SET(g_replay.iReplayBits, ENUM_TO_INT(RB_DO_VEHICLE_REPOP))
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER repopulation took too long, early out.")
ELSE
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER skipping vehicle repopulation.")
ENDIF
ENDIF
// reset camera behind player
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
// repause the game
SET_GAME_PAUSED(TRUE)
// finished
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER: repopulation finished")
g_eReplayWarpStage = RWS_DONE
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "REPLAY_WARP_PLAYER waiting for vehicle repopulation.")
ENDIF
BREAK
// replay warp finished
CASE RWS_DONE
RETURN TRUE
BREAK
ENDSWITCH
ENDIF
RETURN FALSE // not finished warp / repopulate
ENDFUNC
/// PURPOSE:
/// Call this when your mission starts setting up for a replay.
/// Disables audio, pauses the game and disables player control etc.
/// PARAMS:
/// vPos - where you want to put the player
/// fHeading - the heading you want the player to have
/// bRefillVehiclePop - do you want to refill the vehicle population?
/// bFullyInterior - if this area is fully interior with no view of outside we can use a smaller stream area
PROC START_REPLAY_SETUP(VECTOR vPos, FLOAT fHeading, BOOL bRefillVehiclePop = TRUE, BOOL bFullyInterior = FALSE)
CPRINTLN(DEBUG_REPLAY, "START_REPLAY_SETUP called. vPos= ", vPos, " fHeading= ", fHeading)
IF IS_REPLAY_IN_PROGRESS()
// ensure the mission script can't be paused
SET_THIS_SCRIPT_CAN_BE_PAUSED(FALSE)
// pause the game
CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_PAUSED_GAME)) //stops replay controller unpausing
SET_GAME_PAUSED(TRUE)
// disable player control
IF IS_PLAYER_PLAYING(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
// reset any replay setup variables here:
g_eReplayWarpPos = vPos
g_eReplayWarpHeading = fHeading
g_eReplayWarpStage = RWS_START
IF bRefillVehiclePop = TRUE
SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DO_VEHICLE_REPOP))
ELSE
CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_DO_VEHICLE_REPOP))
ENDIF
IF bFullyInterior = TRUE
CPRINTLN(DEBUG_REPLAY, "Doing set up for interior checkpoint.")
SET_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FULLY_INTERIOR))
ELSE
CPRINTLN(DEBUG_REPLAY, "Doing set up for normal checkpoint.")
CLEAR_BIT(g_replay.iReplayBits, ENUM_TO_INT(RB_FULLY_INTERIOR))
ENDIF
// replay set up has started
Replay_Toggle_Setup(TRUE)
ENDIF
ENDPROC
/// PURPOSE:
/// Call this when your mission has finished setting up for a replay.
/// REPLAY_WARP_PLAYER() should already have returned true.
/// Enables audio, unpauses the game, enables player control etc.
/// PARAMS:
/// mVehicle - the vehicle to put the player in. If left as null is left on foot.
/// mSeat - the seat of the vehicle that you want to put the player in.
/// bReturnPlayerControl- do we want to turn player control back on now?
PROC END_REPLAY_SETUP(VEHICLE_INDEX mVehicle = NULL, VEHICLE_SEAT mSeat= VS_DRIVER, BOOL bReturnPlayerControl = TRUE)
CPRINTLN(DEBUG_REPLAY, "END_REPLAY_SETUP called.")
IF IS_REPLAY_IN_PROGRESS()
AND IS_REPLAY_BEING_SET_UP()
WHILE g_eReplayWarpStage <> RWS_DONE
WAIT(0)
//CPRINTLN(DEBUG_REPLAY, "END_REPLAY_SETUP: Waiting for warp to finish")
ENDWHILE
// unpause the game
SET_GAME_PAUSED(FALSE)
// clear wetness here as it no longer seems to work while paused
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CLEAR_PED_WETNESS(PLAYER_PED_ID())
ENDIF
ENDIF
// put the player in the vehicle specified
IF mVehicle <> NULL
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF DOES_ENTITY_EXIST(mVehicle)
IF IS_VEHICLE_DRIVEABLE(mVehicle)
IF NOT IS_PED_IN_VEHICLE(PLAYER_PED_ID(), mVehicle)
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), mVehicle, mSeat)
// reset camera behind player
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
WAIT(0) // wait a frame for camera to catch up
CPRINTLN(DEBUG_REPLAY, "END_REPLAY_SETUP: Put player in vehicle")
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// return player control
IF bReturnPlayerControl = TRUE
IF IS_PLAYER_PLAYING(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
ENDIF
ENDIF
//Make sure all PostFX are cleared at this point.
ANIMPOSTFX_STOP_ALL()
// replay set up is complete
Replay_Toggle_Setup(FALSE)
// allow mission script to be paused as normal from now on
//SET_THIS_SCRIPT_CAN_BE_PAUSED(TRUE)
ENDIF
ENDPROC