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