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

3330 lines
160 KiB
Scheme
Executable File

USING "rage_builtins.sch"
USING "globals.sch"
USING "vehicle_public.sch"
USING "commands_clock.sch"
USING "player_ped_public.sch"
USING "selector_public.sch"
USING "battlebuddy_private.sch"
USING "vehicle_gen_public.sch"
USING "comms_control_private.sch"
USING "commands_water.sch"
#IF IS_DEBUG_BUILD
USING "debug_channels_structs.sch"
#ENDIF
#IF USE_CLF_DLC
USING "spy_vehicle_system.sch"
#ENDIF
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// SCRIPT NAME : snapshot_private.sch
// AUTHOR : Andrew Minghella
// DESCRIPTION : Handles gameplay state snapshots used in replay controller and repeat play
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
// ===========================================================================================================
// Metrics tracking functions
// ===========================================================================================================
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Starts new metrics / smoketest stage
/// PARAMS:
/// iStage - the replay checkpoint stage (this is only used to check if we're doing a new mission)
/// eMissionID - the mission that is starting the metrics stage
/// sStageName - the debug name for this stage
PROC StartNewMetricsStage(INT iStage, STRING sScriptName, STRING sStageName)
// check if this is a stroy or RC mission
SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(sScriptName, TRUE)
// increment the metrics tracking stage (used for metrics and smoketests)
// also let the autoplay system know which mission is running
IF iStage = 0
g_iMetricsTrackingStage = 0
TEXT_LABEL_31 tMissionName
IF eMissionID = SP_MISSION_NONE
// RC mission
tMissionName = "M_"
tMissionName += sScriptName
ELSE
tMissionName = GET_SP_MISSION_NAME_LABEL(eMissionID)
ENDIF
g_txtFlowAutoplayRunningMission = tMissionName
CPRINTLN(DEBUG_AUTOPLAY, "New autoplay mission, name: ", g_txtFlowAutoplayRunningMission)
ELSE
g_iMetricsTrackingStage++
ENDIF
// --------------metrics---------------------
IF g_bFlowMetricZonesEnabled
IF iStage = 0
// start new metrics zone
METRICS_ZONES_HIDE()
METRICS_ZONES_CLEAR()
g_bFlowMetricZoneInProgress = TRUE
CPRINTLN(DEBUG_METRICS, "Mission started. Resetting metrics zone system.")
ELSE
// stage
METRICS_ZONE_STOP()
CPRINTLN(DEBUG_METRICS, "Stopped running metrics zone.")
ENDIF
IF g_bFlowMetricZoneInProgress
TEXT_LABEL_63 tMetricsZoneName = "["
IF eMissionID = SP_MISSION_NONE
// RC mission
tMetricsZoneName += sScriptName
ELSE
tMetricsZoneName += g_sMissionStaticData[eMissionID].statID
ENDIF
tMetricsZoneName += ":"
tMetricsZoneName += g_iMetricsTrackingStage
tMetricsZoneName += "] "
tMetricsZoneName += sStageName
METRICS_ZONE_START(tMetricsZoneName)
CPRINTLN(DEBUG_METRICS, "Started new metrics zone ", tMetricsZoneName,".")
ENDIF
ENDIF
// --------------smoketests-------------------------------------------
IF g_bFlowSmoketestEnabled
IF g_bFlowSmoketestSectionActive
//End current smoketest section.
CPRINTLN(DEBUG_AUTOPLAY, "Mission checkpoint. Ending tracking for smoketest section.")
SMOKETEST_STOP_CAPTURE_SECTION()
g_bFlowSmoketestSectionActive = FALSE
ENDIF
//Start new smoketest section.
TEXT_LABEL_63 tSmoketestSection = "["
IF eMissionID <> SP_MISSION_NONE
tSmoketestSection += g_sMissionStaticData[eMissionID].statID
ENDIF
tSmoketestSection += ":"
tSmoketestSection += g_iMetricsTrackingStage
tSmoketestSection += "] "
tSmoketestSection += sStageName
SMOKETEST_START_CAPTURE_SECTION(tSmoketestSection)
CPRINTLN(DEBUG_AUTOPLAY, "Started new smoketest section ", tSmoketestSection,".")
g_bFlowSmoketestSectionActive = TRUE
ENDIF
ENDPROC
PROC Stop_Metrics_For_Mission_Over(STRING sScriptName)
IF g_bFlowMetricZonesEnabled
IF g_bFlowMetricZoneInProgress
// check if this is a story or RC mission
SP_MISSIONS eMissionID = GET_SP_MISSION_ID_FOR_SCRIPT_NAME(sScriptName, TRUE)
//Stop tracking current metrics zone.
CPRINTLN(DEBUG_METRICS, "Mission over. Ending metrics zone tracking for mission.")
METRICS_ZONE_STOP()
g_bFlowMetricZoneInProgress = FALSE
//Write metrics for this mission to file.
TEXT_LABEL_63 tMetricsFileName = "METRICS_"
IF eMissionID = SP_MISSION_NONE
// rc mission
tMetricsFileName += sScriptName
ELSE
// story mission
tMetricsFileName += g_sMissionStaticData[eMissionID].statID
ENDIF
tMetricsFileName += "_"
tMetricsFileName += g_iMetricsIteration
tMetricsFileName += ".xml"
METRICS_ZONE_SAVE_TO_FILE(tMetricsFileName)
CPRINTLN(DEBUG_METRICS, "Metrics data written to file \"", tMetricsFileName, "\".")
//Display metrics data to screen for a time.
METRICS_ZONES_SHOW()
g_bDisplayingMetricsZoneResults = TRUE
g_iTimeDisplayedMetricsReport = GET_GAME_TIMER()
CPRINTLN(DEBUG_METRICS, "Started displaying in-game metrics report.")
ENDIF
ENDIF
IF g_bFlowSmoketestEnabled
IF g_bFlowSmoketestSectionActive
//End current smoketest section.
CPRINTLN(DEBUG_AUTOPLAY, "Mission over. Ending tracking for current smoketest section.")
SMOKETEST_STOP_CAPTURE_SECTION()
ENDIF
ENDIF
ENDPROC
// other debug functions
/// PURPOSE:
/// Prints the model dimensions of the vehicle passed in
/// PARAMS:
/// mVehicle - the vehicle we are printing info for
PROC PRINT_MODEL_DIMENSIONS(VEHICLE_INDEX mVehicle)
// print model dimension info
VECTOR vMin, vMax
GET_MODEL_DIMENSIONS(GET_ENTITY_MODEL(mVehicle), vMin, vMax)
//CPRINTLN(DEBUG_REPLAY, "model dimensions are: vMin =", vMin, "vMax= ", vMax)
CPRINTLN(DEBUG_REPLAY, "x =", vMax.x - vMin.x)
CPRINTLN(DEBUG_REPLAY, "y =", vMax.y - vMin.y)
CPRINTLN(DEBUG_REPLAY, "z =", vMax.z - vMin.z)
ENDPROC
#ENDIF
// ===========================================================================================================
// SNAPSHOT HELPER FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// check if vPosToCheck is inside the specified interior
/// uses IS_COLLISION_MARKED_OUTSIDE & GET_INTERIOR_AT_COORDS_WITH_TYPE
/// PARAMS:
/// vPosToCheck - the position to test
/// sInteriorName - the name of the specific interior you want to test for
/// vInteriorCoords - a position from inside the specific interior
/// RETURNS:
/// TRUE if vPosToCheck is inside the specific interior
FUNC BOOL IS_POSITION_INSIDE_SPECIFC_INTERIOR(VECTOR vPosToCheck, STRING sInteriorName, VECTOR vInteriorCoords)
IF NOT IS_COLLISION_MARKED_OUTSIDE(vPosToCheck)
INTERIOR_INSTANCE_INDEX interiorIndexToCheck = GET_INTERIOR_AT_COORDS_WITH_TYPE(vInteriorCoords, sInteriorName)
// make sure the handle to the specific interior to check is valid first
IF NOT IS_VALID_INTERIOR(interiorIndexToCheck)
//CPRINTLN(DEBUG_REPLAY, " IS_POSITION_INSIDE_SPECIFC_INTERIOR() : return FALSE unable to test interiorIndexToCheck ins't valid interior ")
RETURN FALSE
ENDIF
INTERIOR_INSTANCE_INDEX interiorIndexAtPosition = GET_INTERIOR_FROM_COLLISION(vPosToCheck)
IF interiorIndexAtPosition = interiorIndexToCheck
//CPRINTLN(DEBUG_REPLAY, "IS_POSITION_INSIDE_SPECIFC_INTERIOR() : return TRUE - for vPosToCheck : ", vPosToCheck)
RETURN TRUE
ELSE
//CPRINTLN(DEBUG_REPLAY, "IS_POSITION_INSIDE_SPECIFC_INTERIOR() : [pos inside interior but not the specific interior! return FALSE - for vPosToCheck : ", vPosToCheck)
ENDIF
ELSE
//CPRINTLN(DEBUG_REPLAY, "IS_POSITION_INSIDE_SPECIFC_INTERIOR() - collision marked outside return FALSE - for vPosToCheck : ", vPosToCheck)
ENDIF
RETURN FALSE
ENDFUNC
// ===========================================================================================================
// CLEAN UP FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// Resets the data in a player snapshot struct
/// PARAMS:
/// mSnapshot - the player snapshot struct
PROC Reset_Player_Snapshot(PLAYER_SNAPSHOT &mSnapshot)
mSnapshot.vPos = <<0,0,0>>
mSnapshot.fHeading = 0.0
mSnapshot.iWantedLevel = 0
mSnapshot.eParachuteState = PPS_INVALID
ENDPROC
/// PURPOSE:
/// Resets the data in a vehicle snapshot struct
/// PARAMS:
/// mSnapshot - the vehicle snapshot struct
PROC Reset_Vehicle_Snapshot(VEHICLE_SNAPSHOT &mSnapshot)
RESET_VEHICLE_SETUP_STRUCT(mSnapshot.mVehicle)
mSnapshot.vVehiclePos = <<0.0,0.0,0.0>>
mSnapshot.vVehicleVelocity = <<0.0,0.0,0.0>>
mSnapshot.fVehicleHeading = 0.0
mSnapshot.bInVehicle = FALSE
mSnapshot.bTrackedForImpound = FALSE
ENDPROC
/// PURPOSE:
/// Resets the data in a vehicle snapshot struct
/// PARAMS:
/// mSnapshot - the vehicle snapshot struct
PROC Reset_BattleBuddy_Snapshot(structBattleBuddySnapshot &mSnapshot)
mSnapshot.eMission = SP_MISSION_NONE
mSnapshot.iAllowedChars = 0
mSnapshot.iReplayChars = 0
mSnapshot.iFailedChars = 0
ENDPROC
/// PURPOSE:
/// Resets the player and vehicle snapshots in the repeat play snapshot
PROC Reset_RepeatPlay_SnapshotCLF()
Reset_Player_Snapshot(g_savedGlobalsClifford.sRepeatPlayData.mPlayerStruct)
Reset_Vehicle_Snapshot(g_savedGlobalsClifford.sRepeatPlayData.mVehicleStruct)
g_savedGlobalsClifford.sRepeatPlayData.eMission = SP_MISSION_NONE
g_savedGlobalsClifford.sRepeatPlayData.eRCMissionToBlock = NO_RC_MISSION
ENDPROC
PROC Reset_RepeatPlay_SnapshotNRM()
Reset_Player_Snapshot(g_savedGlobalsnorman.sRepeatPlayData.mPlayerStruct)
Reset_Vehicle_Snapshot(g_savedGlobalsnorman.sRepeatPlayData.mVehicleStruct)
g_savedGlobalsnorman.sRepeatPlayData.eMission = SP_MISSION_NONE
g_savedGlobalsnorman.sRepeatPlayData.eRCMissionToBlock = NO_RC_MISSION
ENDPROC
PROC Reset_RepeatPlay_Snapshot()
#if USE_CLF_DLC
Reset_RepeatPlay_SnapshotCLF()
exit
#endif
#if USE_NRM_DLC
Reset_RepeatPlay_SnapshotNRM()
exit
#endif
Reset_Player_Snapshot(g_savedGlobals.sRepeatPlayData.mPlayerStruct)
Reset_Vehicle_Snapshot(g_savedGlobals.sRepeatPlayData.mVehicleStruct)
g_savedGlobals.sRepeatPlayData.eMission = SP_MISSION_NONE
g_savedGlobals.sRepeatPlayData.eRCMissionToBlock = NO_RC_MISSION
ENDPROC
/// PURPOSE:
/// Clear out the data in a snapshot struct.
/// NOTE: If this gets updated you'll need to update CopyStartSnapshotToStageSnapshot (below)
/// PARAMS:
/// paramSnapshot - the start or checkpoint snapshot
PROC Reset_Snapshot(SNAPSHOT_STRUCT &mSnapshot)
INT iTempIndex
INT iCharIndex
// character, position and time of day etc
mSnapshot.eCharacter = NO_CHARACTER
Clear_TimeOfDay(mSnapshot.tTime)
mSnapshot.iPreviousWeather = -1
mSnapshot.iNextWeather = -1
mSnapshot.fWeatherInterp = 0
mSnapshot.mCurrentWeapon = WEAPONTYPE_INVALID
mSnapshot.bRestrictedVehicle = FALSE
mSnapshot.mVehicleIndex = NULL
mSnapshot.eVehicleOwner = NO_CHARACTER
// all player characters
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
// bank accounts
mSnapshot.iBankLogIndex[iCharIndex] = -1
mSnapshot.iCash[iCharIndex] = 0
// armour
mSnapshot.iArmour[iCharIndex] = 0
// fail weapons
mSnapshot.mFailWeapon[iCharIndex] = WEAPONTYPE_INVALID
// Player's default vehicles
RESET_PED_VEH_DATA_STRUCT(mSnapshot.mPlayerVehicle[0][iCharIndex])
RESET_PED_VEH_DATA_STRUCT(mSnapshot.mPlayerVehicle[1][iCharIndex])
// ped varaitions
REPEAT NUM_PED_COMPONENTS iTempIndex
mSnapshot.mVariations[iCharIndex].iTextureVariation[iTempIndex] = -1
mSnapshot.mVariations[iCharIndex].iDrawableVariation[iTempIndex] = -1
mSnapshot.mVariations[iCharIndex].iPaletteVariation[iTempIndex] = -1
ENDREPEAT
// Hair / beard / mask stuff
mSnapshot.mVariations[iCharIndex].eStoredHairstyle = INT_TO_ENUM(PED_COMP_NAME_ENUM, 0) // all SP chars use hair 0 as default
mSnapshot.mVariations[iCharIndex].eItemThatForcedHairChange = DUMMY_PED_COMP
mSnapshot.mVariations[iCharIndex].eTypeThatForcedHairChange = COMP_TYPE_HAIR
mSnapshot.mVariations[iCharIndex].eStoredBeard = INT_TO_ENUM(PED_COMP_NAME_ENUM, 0) // all SP chars use beard 0 as default
mSnapshot.mVariations[iCharIndex].eItemThatForcedBeardChange = DUMMY_PED_COMP
mSnapshot.mVariations[iCharIndex].eTypeThatForcedBeardChange = COMP_TYPE_BERD
REPEAT NUM_PLAYER_PED_PROPS iTempIndex
mSnapshot.mVariations[iCharIndex].iPropIndex[iTempIndex] = -1
mSnapshot.mVariations[iCharIndex].iPropTexture[iTempIndex] = -1
ENDREPEAT
// weapons
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
mSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount = 0
mSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iModsAsBitfield = 0
mSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iTint = 0
mSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iCamo = 0
mSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].eWeaponType = WEAPONTYPE_INVALID
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
mSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iAmmoCount = 0
mSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iModsAsBitfield = 0
mSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iTint = 0
mSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iCamo = 0
mSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].eWeaponType = WEAPONTYPE_INVALID
ENDREPEAT
//Purchased weapon states.
REPEAT 4 iTempIndex
mSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[iTempIndex] = 0
ENDREPEAT
REPEAT 10 iTempIndex
mSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[iTempIndex] = 0
ENDREPEAT
REPEAT 15 iTempIndex
mSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[iTempIndex] = 0
ENDREPEAT
// special ability
mSnapshot.iSpecialAbility[iCharIndex] = 0
// tattoos
FOR iTempIndex = 0 TO MAX_NUMBER_OF_TATTOO_BITSETS -1
mSnapshot.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex] = 0
mSnapshot.sTattoos[iCharIndex].iViewedTattoos[iTempIndex] = 0
mSnapshot.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex] = 0
ENDFOR
// clothes
FOR iTempIndex = 0 TO PED_COMPONENT_USED_SLOT
mSnapshot.sComponents[iCharIndex].iHeadBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iBeardBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iHairBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset2[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset3[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset4[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset5[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset6[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset7[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset8[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTorsoBitset9[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iLegsBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iLegsBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iLegsBitset2[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iLegsBitset3[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iHandBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iFeetBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iFeetBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iFeetBitset2[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iFeetBitset3[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iFeetBitset4[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iTeethBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iSpecialBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iSpecialBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iSpecialBitset2[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iDeclBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iDeclBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iJbibBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iJbibBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iOutfitBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iOutfitBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset0[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset1[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset2[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset3[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset4[iTempIndex] = 0
mSnapshot.sComponents[iCharIndex].iPropsBitset5[iTempIndex] = 0
ENDFOR
ENDREPEAT
// other structs
Reset_Player_Snapshot(mSnapshot.mPlayerStruct)
Reset_Vehicle_Snapshot(mSnapshot.mVehicleStruct)
Reset_BattleBuddy_Snapshot(mSnapshot.mBattleBuddyStruct)
ENDPROC
/// PURPOSE:
/// Copies the star snapshot over the stage snapshot
/// NOTE: If this gets updated you'll need to update Reset_Snapshot (above)
PROC CopyStartSnapshotToStageSnapshot()
// --------------------Copy this start snapshot to the stage snapshot-----------------------
INT iTempIndex
INT iCharIndex
// character, position and time of day etc
g_stageSnapshot.eCharacter = g_startSnapshot.eCharacter
g_stageSnapshot.tTime = g_startSnapshot.tTime
g_stageSnapshot.iPreviousWeather = g_startSnapshot.iPreviousWeather
g_stageSnapshot.iNextWeather = g_startSnapshot.iNextWeather
g_stageSnapshot.fWeatherInterp = g_startSnapshot.fWeatherInterp
g_stageSnapshot.mCurrentWeapon = g_startSnapshot.mCurrentWeapon
g_stageSnapshot.bRestrictedVehicle = g_startSnapshot.bRestrictedVehicle
g_stageSnapshot.mVehicleIndex = g_startSnapshot.mVehicleIndex
g_stageSnapshot.eVehicleOwner = g_startSnapshot.eVehicleOwner
// all player characters
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
// bank accounts
g_stageSnapshot.iBankLogIndex[iCharIndex] = g_startSnapshot.iBankLogIndex[iCharIndex]
g_stageSnapshot.iCash[iCharIndex] = g_startSnapshot.iCash[iCharIndex]
//Armor.
g_stageSnapshot.iArmour[iCharIndex] = g_startSnapshot.iArmour[iCharIndex]
// Fail Weapons
g_stageSnapshot.mFailWeapon[iCharIndex] = g_startSnapshot.mFailWeapon[iCharIndex]
// Player's default vehicles
g_stageSnapshot.mPlayerVehicle[0][iCharIndex] = g_startSnapshot.mPlayerVehicle[0][iCharIndex]
g_stageSnapshot.mPlayerVehicle[1][iCharIndex] = g_startSnapshot.mPlayerVehicle[1][iCharIndex]
//Ped variations.
REPEAT NUM_PED_COMPONENTS iTempIndex
g_stageSnapshot.mVariations[iCharIndex].iTextureVariation[iTempIndex] = g_startSnapshot.mVariations[iCharIndex].iTextureVariation[iTempIndex]
g_stageSnapshot.mVariations[iCharIndex].iDrawableVariation[iTempIndex] = g_startSnapshot.mVariations[iCharIndex].iDrawableVariation[iTempIndex]
g_stageSnapshot.mVariations[iCharIndex].iPaletteVariation[iTempIndex] = g_startSnapshot.mVariations[iCharIndex].iPaletteVariation[iTempIndex]
ENDREPEAT
// hair / beard / mask stuff
g_stageSnapshot.mVariations[iCharIndex].eStoredHairstyle = g_startSnapshot.mVariations[iCharIndex].eStoredHairstyle
g_stageSnapshot.mVariations[iCharIndex].eItemThatForcedHairChange = g_startSnapshot.mVariations[iCharIndex].eItemThatForcedHairChange
g_stageSnapshot.mVariations[iCharIndex].eTypeThatForcedHairChange = g_startSnapshot.mVariations[iCharIndex].eTypeThatForcedHairChange
g_stageSnapshot.mVariations[iCharIndex].eStoredBeard = g_startSnapshot.mVariations[iCharIndex].eStoredBeard
g_stageSnapshot.mVariations[iCharIndex].eItemThatForcedBeardChange = g_startSnapshot.mVariations[iCharIndex].eItemThatForcedBeardChange
g_stageSnapshot.mVariations[iCharIndex].eTypeThatForcedBeardChange = g_startSnapshot.mVariations[iCharIndex].eTypeThatForcedBeardChange
REPEAT NUM_PLAYER_PED_PROPS iTempIndex
g_stageSnapshot.mVariations[iCharIndex].iPropIndex[iTempIndex] = g_startSnapshot.mVariations[iCharIndex].iPropIndex[iTempIndex]
g_stageSnapshot.mVariations[iCharIndex].iPropTexture[iTempIndex] = g_startSnapshot.mVariations[iCharIndex].iPropTexture[iTempIndex]
ENDREPEAT
//Weapons.
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
g_stageSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex] = g_startSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex]
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
g_stageSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex] = g_startSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex]
ENDREPEAT
//Purchased weapon states.
REPEAT 4 iTempIndex
g_stageSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[iTempIndex] = g_startSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[iTempIndex]
ENDREPEAT
REPEAT 10 iTempIndex
g_stageSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[iTempIndex] = g_startSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[iTempIndex]
ENDREPEAT
REPEAT 15 iTempIndex
g_stageSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[iTempIndex] = g_startSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[iTempIndex]
ENDREPEAT
// special ability
g_stageSnapshot.iSpecialAbility[iCharIndex] = g_startSnapshot.iSpecialAbility[iCharIndex]
// tattoos
FOR iTempIndex = 0 TO MAX_NUMBER_OF_TATTOO_BITSETS -1
g_stageSnapshot.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex] = g_startSnapshot.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex]
g_stageSnapshot.sTattoos[iCharIndex].iViewedTattoos[iTempIndex] = g_startSnapshot.sTattoos[iCharIndex].iViewedTattoos[iTempIndex]
g_stageSnapshot.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex] = g_startSnapshot.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex]
ENDFOR
// clothes
FOR iTempIndex = 0 TO PED_COMPONENT_USED_SLOT
g_stageSnapshot.sComponents[iCharIndex].iHeadBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iHeadBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iBeardBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iBeardBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iHairBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iHairBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset2[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset2[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset3[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset3[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset4[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset4[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset5[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset5[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset6[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset6[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset7[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset7[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset8[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset8[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTorsoBitset9[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTorsoBitset9[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iLegsBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iLegsBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iLegsBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iLegsBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iLegsBitset2[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iLegsBitset2[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iLegsBitset3[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iLegsBitset3[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iHandBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iHandBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iFeetBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iFeetBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iFeetBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iFeetBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iFeetBitset2[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iFeetBitset2[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iFeetBitset3[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iFeetBitset3[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iFeetBitset4[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iFeetBitset4[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iTeethBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iTeethBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iSpecialBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iSpecialBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iSpecialBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iSpecialBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iSpecialBitset2[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iSpecialBitset2[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iDeclBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iDeclBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iDeclBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iDeclBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iJbibBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iJbibBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iJbibBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iJbibBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iOutfitBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iOutfitBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iOutfitBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iOutfitBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset0[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset0[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset1[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset1[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset2[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset2[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset3[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset3[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset4[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset4[iTempIndex]
g_stageSnapshot.sComponents[iCharIndex].iPropsBitset5[iTempIndex] = g_startSnapshot.sComponents[iCharIndex].iPropsBitset5[iTempIndex]
ENDFOR
ENDREPEAT
// other structs
g_stageSnapshot.mPlayerStruct.vPos = g_startSnapshot.mPlayerStruct.vPos
g_stageSnapshot.mPlayerStruct.fHeading = g_startSnapshot.mPlayerStruct.fHeading
g_stageSnapshot.mVehicleStruct.vVehiclePos = g_startSnapshot.mVehicleStruct.vVehiclePos
g_stageSnapshot.mVehicleStruct.vVehicleVelocity = g_startSnapshot.mVehicleStruct.vVehicleVelocity
g_stageSnapshot.mVehicleStruct.fVehicleHeading = g_startSnapshot.mVehicleStruct.fVehicleHeading
g_stageSnapshot.mVehicleStruct.bInVehicle = g_stageSnapshot.mVehicleStruct.bInVehicle
g_stageSnapshot.mVehicleStruct.bPersonalVehicle = g_startSnapshot.mVehicleStruct.bPersonalVehicle
g_stageSnapshot.mVehicleStruct.bTrackedForImpound = g_startSnapshot.mVehicleStruct.bTrackedForImpound
g_stageSnapshot.mVehicleStruct.ePlayerCharacter = g_startSnapshot.mVehicleStruct.ePlayerCharacter
g_stageSnapshot.mVehicleStruct.bVehGen = g_startSnapshot.mVehicleStruct.bVehGen
g_stageSnapshot.mVehicleStruct.mVehicle.iPlateIndex = g_startSnapshot.mVehicleStruct.mVehicle.iPlateIndex
g_stageSnapshot.mVehicleStruct.mVehicle.tlPlateText = g_startSnapshot.mVehicleStruct.mVehicle.tlPlateText
g_stageSnapshot.mVehicleStruct.mVehicle.iColour1 = g_startSnapshot.mVehicleStruct.mVehicle.iColour1
g_stageSnapshot.mVehicleStruct.mVehicle.iColour2 = g_startSnapshot.mVehicleStruct.mVehicle.iColour2
g_stageSnapshot.mVehicleStruct.mVehicle.iColourExtra1 = g_startSnapshot.mVehicleStruct.mVehicle.iColourExtra1
g_stageSnapshot.mVehicleStruct.mVehicle.iColourExtra2 = g_startSnapshot.mVehicleStruct.mVehicle.iColourExtra2
g_stageSnapshot.mVehicleStruct.mVehicle.iModIndex = g_startSnapshot.mVehicleStruct.mVehicle.iModIndex
g_stageSnapshot.mVehicleStruct.mVehicle.iModVariation = g_startSnapshot.mVehicleStruct.mVehicle.iModVariation
g_stageSnapshot.mVehicleStruct.mVehicle.iTyreR = g_startSnapshot.mVehicleStruct.mVehicle.iTyreR
g_stageSnapshot.mVehicleStruct.mVehicle.iTyreG = g_startSnapshot.mVehicleStruct.mVehicle.iTyreG
g_stageSnapshot.mVehicleStruct.mVehicle.iTyreB = g_startSnapshot.mVehicleStruct.mVehicle.iTyreB
g_stageSnapshot.mVehicleStruct.mVehicle.iWindowTintColour = g_startSnapshot.mVehicleStruct.mVehicle.iWindowTintColour
g_stageSnapshot.mVehicleStruct.mVehicle.iFlags = g_startSnapshot.mVehicleStruct.mVehicle.iFlags
g_stageSnapshot.mVehicleStruct.mVehicle.eModel = g_startSnapshot.mVehicleStruct.mVehicle.eModel
g_stageSnapshot.mVehicleStruct.mVehicle.iLivery = g_startSnapshot.mVehicleStruct.mVehicle.iLivery
g_stageSnapshot.mVehicleStruct.mVehicle.eRoofState = g_startSnapshot.mVehicleStruct.mVehicle.eRoofState
g_stageSnapshot.mVehicleStruct.mVehicle.iWheelType = g_startSnapshot.mVehicleStruct.mVehicle.iWheelType
g_stageSnapshot.mVehicleStruct.mVehicle.iCustomR = g_startSnapshot.mVehicleStruct.mVehicle.iCustomR
g_stageSnapshot.mVehicleStruct.mVehicle.iCustomG = g_startSnapshot.mVehicleStruct.mVehicle.iCustomG
g_stageSnapshot.mVehicleStruct.mVehicle.iCustomB = g_startSnapshot.mVehicleStruct.mVehicle.iCustomB
g_stageSnapshot.mVehicleStruct.mVehicle.iNeonR = g_startSnapshot.mVehicleStruct.mVehicle.iNeonR
g_stageSnapshot.mVehicleStruct.mVehicle.iNeonG = g_startSnapshot.mVehicleStruct.mVehicle.iNeonG
g_stageSnapshot.mVehicleStruct.mVehicle.iNeonB = g_startSnapshot.mVehicleStruct.mVehicle.iNeonB
g_stageSnapshot.mBattleBuddyStruct.eMission = g_startSnapshot.mBattleBuddyStruct.eMission
g_stageSnapshot.mBattleBuddyStruct.iAllowedChars = g_startSnapshot.mBattleBuddyStruct.iAllowedChars
g_stageSnapshot.mBattleBuddyStruct.iReplayChars = g_startSnapshot.mBattleBuddyStruct.iReplayChars
g_stageSnapshot.mBattleBuddyStruct.iFailedChars = g_startSnapshot.mBattleBuddyStruct.iFailedChars
ENDPROC
/// PURPOSE:
/// Clears out snapshot data being held for the start of the mission.
PROC Reset_Start_Snapshot()
CPRINTLN(DEBUG_REPLAY, "Resetting mission start snapshot data.")
g_snapshotScriptName = ""
Reset_Snapshot(g_startSnapshot)
ENDPROC
/// PURPOSE:
/// Clears out snapshot data being held for the last mission stage.
PROC Reset_Stage_Snapshot()
CPRINTLN(DEBUG_REPLAY, "Resetting last stage snapshot data.")
Reset_Snapshot(g_stageSnapshot)
ENDPROC
// ===========================================================================================================
// SNAPSHOT VEHICLE RESTORING FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// Returns whether the specified snapshot has a start vehicle saved in it.
/// PARAMS:
/// mSnapshot - the start or checkpoint snapshot
/// RETURNS:
/// True if the snapshot has a vehicle saved in it
FUNC BOOL IsSnapshotVehicleAvailable(VEHICLE_SNAPSHOT &mSnapshot)
IF mSnapshot.mVehicle.eModel = DUMMY_MODEL_FOR_SCRIPT
RETURN FALSE
ENDIF
IF NOT IS_VEHICLE_AVAILABLE_FOR_GAME(mSnapshot.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "IsSnapshotVehicleAvailable vehicle model ",GET_MODEL_NAME_FOR_DEBUG(mSnapshot.mVehicle.eModel)," not available for game.")
RETURN FALSE
ENDIF
//Stunt plane check - B* 2552130
IF mSnapshot.mVehicle.eModel = STUNT AND ARE_VECTORS_ALMOST_EQUAL(mSnapshot.vVehiclePos, <<1694.62, 3276.27, 41.31>>)
CPRINTLN(DEBUG_REPLAY, "IsSnapshotVehicleAvailable Stunt Trials plane not available for game - should be handled by the minigame.")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Start loading the model for a snapshot vehicle.
/// PARAMS:
/// mSnapshot - the start or checkpoint snapshot
PROC RequestSnapshotVehicleModel(VEHICLE_SNAPSHOT &mSnapshot)
IF IsSnapshotVehicleAvailable(mSnapshot)
REQUEST_MODEL(mSnapshot.mVehicle.eModel)
ELSE
SCRIPT_ASSERT("RequestSnapshotVehicleModel: Tried to request a stored vehicle model for a snapshot that had no vehicle saved. Check IsSnapshotVehicleAvailable() before requesting.")
ENDIF
ENDPROC
/// PURPOSE:
/// Check if a the model for a snapshot vehicle is loaded.
/// PARAMS:
/// mSnapshot - the start or checkpoint snapshot
/// RETURNS:
/// True if the model has loaded.
FUNC BOOL HasSnapshotVehicleLoaded(VEHICLE_SNAPSHOT &mSnapshot)
IF IsSnapshotVehicleAvailable(mSnapshot)
IF HAS_MODEL_LOADED(mSnapshot.mVehicle.eModel)
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
RETURN TRUE
ELSE
SCRIPT_ASSERT("HasSnapshotVehicleLoaded: Tried to check if a vehicle model had loaded for a snapshot that had no vehicle saved. Check IsSnapshotVehicleAvailable() before querying.")
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Checks if the stored snapshot vehicle is a specific model.
/// PARAMS:
/// mSnapshot - the start or checkpoint snapshot
/// paramVehicleModel - the model name we are checking against
/// RETURNS:
/// TRUE if the stored snapshot vehicle is the model specified
FUNC BOOL IsSnapshotVehicleThisModel(VEHICLE_SNAPSHOT &mSnapshot, MODEL_NAMES paramVehicleModel)
IF IsSnapshotVehicleAvailable(mSnapshot)
IF mSnapshot.mVehicle.eModel = paramVehicleModel
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDIF
SCRIPT_ASSERT("IsSnapshotVehicleThisModel: Tried to query a stored vehicle model for a snapshot that had no vehicle saved. Check IsSnapshotVehicleAvailable() before querying.")
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if the special case vehicle index matches the vehgen
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// vehGen - the VEHGEN we are checking against
/// RETURNS:
/// BOOL If vehicle matches vehgen
FUNC BOOL DOES_SPECIAL_CASE_VEHICLE_MATCH(VEHICLE_INDEX snapshotVehicle,VEHICLE_INDEX compareVehicle, BOOL checkColour = TRUE)
IF DOES_ENTITY_EXIST(compareVehicle) AND NOT IS_ENTITY_DEAD(compareVehicle) AND IS_VEHICLE_DRIVEABLE(compareVehicle)
IF checkColour
INT c1,c2,c3,c4
GET_VEHICLE_COLOURS(snapshotVehicle,c1,c2)
GET_VEHICLE_COLOURS(compareVehicle,c3,c4)
IF c1 = c3 AND c2 = c4
RETURN TRUE
ENDIF
ELSE
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if the vehicle index is a special case, hardcoded list designed to stop duplicates
/// Method was first created for bug 1912018
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// RETURNS:
/// BOOL If vehicle matches special case
FUNC BOOL IS_VEHICLE_SNAPSHOT_SPECIAL_CASE(VEHICLE_INDEX mVehicle, VECTOR vVelocity, BOOL bInVehicle)
MODEL_NAMES tempModel = GET_ENTITY_MODEL(mVehicle)
VEHICLE_INDEX tempVehArray[3]
INT i,x
SWITCH tempModel
CASE CARGOBOB
//B* 1912018
IF DOES_SPECIAL_CASE_VEHICLE_MATCH(mVehicle, g_sVehicleGenNSData.vehicleID[VEHGEN_DOCKSP2B_CHINOOK],FALSE)
//duplicate CARGOBOB, remove vehicle gen
DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_DOCKSP2B_CHINOOK)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: specialCase, removing vehgen = VEHGEN_DOCKSP2B_CHINOOK")
RETURN TRUE
ENDIF
BREAK
CASE FIRETRUK
//B* 1932490
IF DOES_SPECIAL_CASE_VEHICLE_MATCH(mVehicle, g_sVehicleGenNSData.vehicleID[VEHGEN_AGENCY_PREP_FIRETRUCK])
//duplicate FIRETRUK, remove vehicle gen
DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_AGENCY_PREP_FIRETRUCK)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: specialCase, removing vehgen = VEHGEN_AGENCY_PREP_FIRETRUCK")
RETURN TRUE
ENDIF
BREAK
CASE CUBAN800
//B* 2009073
i = GET_PED_NEARBY_VEHICLES(PLAYER_PED_ID(),tempVehArray)
FOR x = 0 TO i-1
IF DOES_SPECIAL_CASE_VEHICLE_MATCH(mVehicle, tempVehArray[x])
AND ARE_VECTORS_ALMOST_EQUAL(GET_ENTITY_COORDS(tempVehArray[x]),<<2136.1331, 4780.5635, 39.9702>>,5.0)
IF NOT bInVehicle OR ARE_VECTORS_EQUAL(vVelocity,<<0,0,0>>) OR GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(mVehicle),GET_ENTITY_COORDS(tempVehArray[x])) < 10
DELETE_VEHICLE(mVehicle)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: specialCase, trafficking air cuban800. Removing snapshot vehicle") //replay change
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDIF
ENDFOR
BREAK
CASE LUXOR2
//B*-2334160
IF DOES_ENTITY_EXIST(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HANGAR_TREVOR])
AND IS_VEHICLE_DRIVEABLE(mVehicle) AND IS_VEHICLE_DRIVEABLE(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HANGAR_TREVOR])
IF GET_ENTITY_MODEL(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HANGAR_TREVOR]) = LUXOR2
AND GET_VEHICLE_LIVERY(mVehicle) = GET_VEHICLE_LIVERY(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HANGAR_TREVOR])
DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_WEB_HANGAR_TREVOR)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: specialCase LUXOR2, removing vehgen = VEHGEN_WEB_HANGAR_TREVOR")
RETURN TRUE
ENDIF
ENDIF
BREAK
CASE SWIFT2
//B*-2346022
IF DOES_ENTITY_EXIST(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY])
AND IS_VEHICLE_DRIVEABLE(mVehicle) AND IS_VEHICLE_DRIVEABLE(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY])
IF GET_ENTITY_MODEL(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY]) = SWIFT2
AND GET_VEHICLE_LIVERY(mVehicle) = GET_VEHICLE_LIVERY(g_sVehicleGenNSData.vehicleSelectID[VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY])
DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: specialCase SWIFT2, removing vehgen = VEHGEN_WEB_HELIPAD_TREVOR_COUNTRY")
RETURN TRUE
ENDIF
ENDIF
BREAK
ENDSWITCH
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks to see if the vehicle index matches one stored in the dynamic vehgen vehicles array
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// RETURNS:
/// VEHICLE_GEN_NAME_ENUM if the vehicle matches a vehgen and the vehgen vehicle exists, VEHGEN_NONE otherwise
FUNC VEHICLE_GEN_NAME_ENUM DOES_VEHICLE_MATCH_A_VEHGEN_VEHICLE(VEHICLE_INDEX mVehicle)
INT iVehGen
INT c1,c2,c3,c4
REPEAT NUMBER_OF_VEHICLES_TO_GEN iVehGen
IF DOES_ENTITY_EXIST(g_sVehicleGenNSData.vehicleSelectID[iVehGen])
AND (NOT IS_ENTITY_DEAD(g_sVehicleGenNSData.vehicleSelectID[iVehGen]))
AND IS_VEHICLE_DRIVEABLE(g_sVehicleGenNSData.vehicleSelectID[iVehGen])
GET_VEHICLE_COLOURS(mVehicle,c1,c2)
GET_VEHICLE_COLOURS(g_sVehicleGenNSData.vehicleSelectID[iVehGen],c3,c4)
IF GET_ENTITY_MODEL(mVehicle) = GET_ENTITY_MODEL(g_sVehicleGenNSData.vehicleSelectID[iVehGen])
AND GET_VEHICLE_LIVERY(mVehicle) = GET_VEHICLE_LIVERY(g_sVehicleGenNSData.vehicleSelectID[iVehGen])
AND c1 = c2 AND c3 = c4
RETURN INT_TO_ENUM(VEHICLE_GEN_NAME_ENUM, iVehGen)
ENDIF
ENDIF
ENDREPEAT
RETURN VEHGEN_NONE
ENDFUNC
/// PURPOSE:
/// Checks to see if the vehicle index equals one stored in the dynamic vehgen vehicles array
/// PARAMS:
/// mVehicle - the vehicle we are checking
/// RETURNS:
/// TRUE if the vehicle index equals a vehgen and the vehgen vehicle exists, FALSE otherwise
FUNC BOOL IS_VEHICLE_A_VEHGEN_VEHICLE(VEHICLE_INDEX mVehicle)
INT iVehGen
REPEAT NUMBER_OF_VEHICLES_TO_GEN iVehGen
IF DOES_ENTITY_EXIST(g_sVehicleGenNSData.vehicleSelectID[iVehGen])
IF mVehicle = g_sVehicleGenNSData.vehicleSelectID[iVehGen]
RETURN TRUE
ENDIF
ENDIF
ENDREPEAT
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Creates the vehicle saved for the specified snapshot.
/// PARAMS:
/// mSnapshot - - the start or checkpoint snapshot
/// vPos - where to create the snapshot vehicle (if <<0.0,0.0,0.0>> it is created at the co-ords from the snapshot)
/// fHeading - the snapshot vehicle's heading
/// RETURNS:
/// The vehicle index of the snapshot vehicle
FUNC VEHICLE_INDEX CreateSnapshotVehicle(VEHICLE_SNAPSHOT &mSnapshot, VECTOR vPos, FLOAT fHeading = 0.0, BOOL bDeleteSamePlayerVehicles = FALSE)
VEHICLE_INDEX vehSnapshot
VECTOR vTemp
IF IsSnapshotVehicleAvailable(mSnapshot)
IF ARE_VECTORS_EQUAL(vPos, <<0.0,0.0,0.0>>) // If no vector specified, use the vector in the snapshot
vPos = mSnapshot.vVehiclePos
fHeading = mSnapshot.fVehicleHeading
ENDIF
//B* 1902545: Monster vehicle check
IF (mSnapshot.mVehicle.eModel = MONSTER OR mSnapshot.mVehicle.eModel = MARSHALL)
IF IS_POINT_IN_ANGLED_AREA(vPos, <<-816.871643,185.623840,71.402748>>, <<-807.489441,189.376205,75.273232>>, 6.500000)
//Move monster truck to in front of M's house
vPos = <<-850.93,158.82,65.7>>
fHeading = 89.5
CPRINTLN(debug_replay,"Monster truck vehicle saved inside Michael's garage but unable to be created there, positioning at ",vPos)
ENDIF
ENDIF
IF HasSnapshotVehicleLoaded(mSnapshot)
CLEAR_AREA(vPos, 5.0, TRUE) // Clear area so we can create the car
DELETE_VEHICLE_GEN_VEHICLES_IN_AREA(vPos, 5.0)
#IF USE_CLF_DLC
if mSnapshot.mVehicle.eModel = spy_vehicle_get_spy_vehicle_model()
spy_vehicle_system_struct spy_vehicle_system
spy_vehicle_remove_all_system_assets(spy_vehicle_system) //stops 2 instances of the spy vehicle being in the world and cleans up all the assets
spy_vehicle_create_spy_vehicle(spy_vehicle_system, vPos, fHeading)
vehSnapshot = spy_vehicle_get_vehicle_index()
#if is_debug_build
printstring("spy_vehicle - created via snapshot_private.sch")
printnl()
#endif
else
vehSnapshot = CREATE_VEHICLE(mSnapshot.mVehicle.eModel, vPos, fHeading)
endif
#endif
#IF not USE_CLF_DLC
vehSnapshot = CREATE_VEHICLE(mSnapshot.mVehicle.eModel, vPos, fHeading)
#endif
IF DOES_ENTITY_EXIST(vehSnapshot)
//B* - 2297443, set coords without offset. Bug, loading vehicle under Floyds apartment.
vTemp = GET_ENTITY_COORDS(vehSnapshot)
IF VDIST2(vTemp, <<-1151.15,-1530.32,7.48925>>) <= 3.0
SET_ENTITY_COORDS_NO_OFFSET(vehSnapshot, vPos)
ENDIF
SET_VEHICLE_SETUP(vehSnapshot, mSnapshot.mVehicle)
//B* 2059523: If it's a boat, only place on ground if it's not on land
BOOL bSetOnGround = TRUE
IF IS_THIS_MODEL_A_BOAT(mSnapshot.mVehicle.eModel)
OR IS_THIS_MODEL_A_JETSKI(mSnapshot.mVehicle.eModel)
VECTOR vIntersect
IF NOT TEST_PROBE_AGAINST_WATER(<<vPos.x,vpos.y,vpos.z + 30>>,<<vPos.x,vpos.y,vpos.z - 30>>,vIntersect)
CPRINTLN(debug_replay,"Player vehicle is a boat or jetski on land, NOT setting on ground properly")
bSetOnGround = FALSE
ENDIF
ENDIF
IF bSetOnGround
SET_VEHICLE_ON_GROUND_PROPERLY(vehSnapshot)
ENDIF
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: bPersonalVehicle = ", mSnapshot.bPersonalVehicle)
// Flag this as a personal vehicle if needed
IF mSnapshot.bPersonalVehicle = TRUE
IF bDeleteSamePlayerVehicles
IF IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(vehSnapshot))
DELETE_ALL_SCRIPT_CREATED_PLAYER_VEHICLES(mSnapshot.ePlayerCharacter, VEHICLE_TYPE_CAR)
ELIF IS_THIS_MODEL_A_BIKE(GET_ENTITY_MODEL(vehSnapshot))
DELETE_ALL_SCRIPT_CREATED_PLAYER_VEHICLES(mSnapshot.ePlayerCharacter, VEHICLE_TYPE_BIKE)
ENDIF
ENDIF
SET_VEHICLE_NOT_STEALABLE_AMBIENTLY(vehSnapshot, FALSE)
SET_VEHICLE_CAN_SAVE_IN_GARAGE(vehSnapshot, FALSE)
SET_VEHICLE_HAS_STRONG_AXLES(vehSnapshot, TRUE)
STORE_TEMP_PLAYER_VEHICLE_ID(vehSnapshot, mSnapshot.ePlayerCharacter)
// non-personal vehicle, but was created by vehgen
ELIF NOT IS_VEHICLE_SNAPSHOT_SPECIAL_CASE(vehSnapshot,mSnapshot.vVehicleVelocity,mSnapshot.bInVehicle) AND mSnapshot.bVehGen AND ARE_STRINGS_EQUAL(GET_THIS_SCRIPT_NAME(),"startup_positioning")
//We have the loaded the vehicle from the snapshot, remove the duplicate vehgen B*1821085
VEHICLE_GEN_NAME_ENUM vehGen = DOES_VEHICLE_MATCH_A_VEHGEN_VEHICLE(vehSnapshot)
IF vehGen = VEHGEN_NONE
mSnapshot.bVehGen = FALSE
ELSE
DELETE_VEHICLE_GEN_VEHICLE(vehGen)
ENDIF
ENDIF
// Is the replay controller restoring this vehicle snapshot?
IF g_replay.replayStageID != RS_NOT_REQUIRED
AND g_replay.replayStageID != RS_ACTIVE
AND g_replay.replayStageID != RS_REJECTED
AND g_replay.replayStageID != RS_NOT_RUNNING
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: Replaying being processed.")
// Does the replay owner match the last mission vehgen owner?
IF GET_HASH_KEY(g_replay.replayScriptName) = g_iLastMissionVehgenOwnerHash
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: Replay script matches the last mission vehgen owner.")
// Does the snapshot vehicle's model match the mission vehgen model?
IF mSnapshot.mVehicle.eModel = g_savedGlobals.sVehicleGenData.sDynamicData[21].eModel
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: Mission vehgen model matches the replay snapshot model.")
SET_VEHICLE_GEN_AVAILABLE(VEHGEN_MISSION_VEH, FALSE)
DELETE_VEHICLE_GEN_VEHICLE(VEHGEN_MISSION_VEH)
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: Cleaned up conflicting mission vehgen.")
ENDIF
ENDIF
ENDIF
// Restore whether this vehicle was being tracked for impound
IF mSnapshot.bTrackedForImpound = TRUE
TRACK_VEHICLE_FOR_IMPOUND(vehSnapshot, mSnapshot.ePlayerCharacter)
ENDIF
CPRINTLN(DEBUG_REPLAY, "CreateSnapshotVehicle: bTrackedForImpound = ", mSnapshot.bTrackedForImpound)
// Unload the model
SET_MODEL_AS_NO_LONGER_NEEDED(mSnapshot.mVehicle.eModel)
vTemp = GET_ENTITY_COORDS(vehSnapshot)
CPRINTLN(DEBUG_REPLAY, "Snapshot vehicle restored at ", vPos, " actual vehicle location is ",vTemp)
ENDIF
RETURN vehSnapshot
ELSE
SCRIPT_ASSERT("CreateSnapshotVehicle: Vehicle model not loaded. Use HasSnapshotVehicleLoaded() before calling this command.")
ENDIF
ENDIF
SCRIPT_ASSERT("CreateSnapshotVehicle: Tried to create a vehicle for a snapshot that had no vehicle saved. Check IsSnapshotVehicleAvailable() before creating.")
RETURN vehSnapshot
ENDFUNC
/// PURPOSE:
/// Runs shape test for players vehicle at road node.
/// PARAMS:
/// postion - road node VECTOR postion
/// heading = road node FLOAT heading
/// playerVehicleSnapshot - saved vehicle snapshot
/// vPlayersVeh - the index of the player vehicle (shape test will ignore collisions with this entity)
/// RETURNS:
/// TRUE if shape test passes, FALSE otherwise
FUNC BOOL CAN_LOAD_VEHICLE_AT_ROAD_NODE(VECTOR postion, FLOAT heading, VEHICLE_SNAPSHOT playerVehicleSnapshot, ENTITY_INDEX vPlayersVeh)
//First check to see if the vehicle is about to be placed on an
//active mission trigger.
INT iTriggerIndex
VECTOR vTriggerPosition
STATIC_BLIP_NAME_ENUM eMaxBlip
#IF USE_SP_DLC
REPEAT MAX_MISSION_TRIGGERS_TU iTriggerIndex
IF g_TriggerableMissionsTU[iTriggerIndex].bUsed
STATIC_BLIP_NAME_ENUM eTriggerBlip = g_TriggerableMissionsTU[iTriggerIndex].eBlip
#ENDIF
#IF NOT USE_SP_DLC
REPEAT MAX_MISSION_TRIGGERS iTriggerIndex
IF g_TriggerableMissions[iTriggerIndex].bUsed
STATIC_BLIP_NAME_ENUM eTriggerBlip = g_TriggerableMissions[iTriggerIndex].eBlip
#ENDIF
eMaxBlip = STATIC_BLIP_NAME_DUMMY_FINAL
//B* 2083300: Make sure the blip is in the acceptable range (under name_dummy_final)
IF eTriggerBlip >= eMaxBlip
CPRINTLN(debug_replay,"Blip value out of range, does this mission have a blip?")
RETURN FALSE
ENDIF
IF IS_BIT_SET(g_GameBlips[eTriggerBlip].iSetting, STATIC_BLIP_SETTING_MULTI_COORD_AND_SPRITE)
vTriggerPosition = GET_STATIC_BLIP_POSITION(eTriggerBlip, GET_CURRENT_PLAYER_PED_INT())
ELSE
vTriggerPosition = GET_STATIC_BLIP_POSITION(eTriggerBlip)
ENDIF
//Vehicle is within 3m of a mission trigger. Don't let it spawn here.
IF VDIST2(postion, vTriggerPosition) < 9 //3^2
CPRINTLN(DEBUG_REPLAY,"ROAD_NODE_TEST: FAIL - ON TRIGGER")
RETURN FALSE
ENDIF
#IF USE_SP_DLC
ENDIF
ENDREPEAT
#ENDIF
#IF NOT USE_SP_DLC
ENDIF
ENDREPEAT
#ENDIF
SHAPETEST_INDEX shapeTestIndex
ENTITY_INDEX entityHit
VECTOR vTempMin
VECTOR vTempMax
VECTOR vHitPos
VECTOR vHitNorm
INT iReturnValue = -1
GET_MODEL_DIMENSIONS(playerVehicleSnapshot.mVehicle.eModel, vTempMin, vTempMax)
shapeTestIndex = START_SHAPE_TEST_BOX(postion,vTempMax-vTempMin,<<0.0,0.0,heading>>,DEFAULT,SCRIPT_INCLUDE_VEHICLE|SCRIPT_INCLUDE_OBJECT|SCRIPT_INCLUDE_RAGDOLL|SCRIPT_INCLUDE_GLASS, vPlayersVeh)
WHILE GET_SHAPE_TEST_RESULT(shapeTestIndex,iReturnValue,vHitPos,vHitNorm,entityHit) = SHAPETEST_STATUS_RESULTS_NOTREADY
WAIT(0)
ENDWHILE
IF iReturnValue = 0
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_REPLAY,"ROAD_NODE_TEST: PASS")
#ENDIF
//load vehicle
RETURN TRUE
ELIF iReturnValue = 1
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_REPLAY,"ROAD_NODE_TEST: FAIL")
#ENDIF
//Don't load vehicle
RETURN FALSE
ELSE
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_REPLAY,"ROAD_NODE_TEST: NON EXISTENT!!??!!??")
#ENDIF
//Something went wrong, Don't load vehicle
RETURN FALSE
ENDIF
ENDFUNC
/// PURPOSE:
/// Finds closest road node to player vehicle. If a suitable node is found, the player vehicle snapshot is updated.
/// PARAMS:
/// playerVehicleSnapshot - passed by reference.
/// vPlayersVeh - the index of the player vehicle (shape test will ignore collisions with this entity)
/// RETURNS:
/// TRUE if suitable node is found and snapshot updated, FALSE otherwise
FUNC BOOL CAN_LOAD_VEHICLE_FROM_SNAPSHOT_AT_NEARBY_ROAD_NODE(VEHICLE_SNAPSHOT &playerVehicleSnapshot, ENTITY_INDEX vPlayersVeh)
INT iNodeIterator = 1
INT iNumOfLanes
FLOAT fRotTemp
VECTOR vPosTemp
REQUEST_PATH_NODES_IN_AREA_THIS_FRAME(playerVehicleSnapshot.vVehiclePos.x-DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.y-DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.x+DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.y+DEFAULT_ROAD_NODE_LOAD_DIST)
WHILE NOT ARE_NODES_LOADED_FOR_AREA(playerVehicleSnapshot.vVehiclePos.x-DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.y-DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.x+DEFAULT_ROAD_NODE_LOAD_DIST, playerVehicleSnapshot.vVehiclePos.y+DEFAULT_ROAD_NODE_LOAD_DIST)
WAIT(0)
ENDWHILE
WHILE GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(playerVehicleSnapshot.vVehiclePos,iNodeIterator,vPosTemp,fRotTemp,iNumOfLanes)
IF GET_DISTANCE_BETWEEN_COORDS(playerVehicleSnapshot.vVehiclePos, vPosTemp, FALSE) <= DEFAULT_ROAD_NODE_LOAD_DIST
IF CAN_LOAD_VEHICLE_AT_ROAD_NODE(vPosTemp, fRotTemp, playerVehicleSnapshot, vPlayersVeh)
//set new vehicle postion
playerVehicleSnapshot.vVehiclePos = vPosTemp
playerVehicleSnapshot.fVehicleHeading = fRotTemp
playerVehicleSnapshot.vVehicleVelocity = <<0.0,0.0,0.0>>
RETURN TRUE
ELSE
iNodeIterator++
ENDIF
ELSE
RETURN FALSE
ENDIF
ENDWHILE
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Runs shape test for the players vehicle
/// PARAMS:
/// playerVehicleSnapshot - saved vehicle snapshot
/// vPlayersVeh - the index of the player vehicle (shape test will ignore collisions with this entity)
/// RETURNS:
/// TRUE if shape test passes, FALSE otherwise
FUNC BOOL CAN_LOAD_VEHICLE_AT_SNAPSHOT_POSITION(VEHICLE_SNAPSHOT playerVehicleSnapshot, ENTITY_INDEX vPlayersVeh = NULL)
//First check to see if the vehicle is about to be placed on an
//active mission trigger.
INT iTriggerIndex
VECTOR vTriggerPosition
STATIC_BLIP_NAME_ENUM eMaxBlip
#IF USE_SP_DLC
REPEAT MAX_MISSION_TRIGGERS_TU iTriggerIndex
IF g_TriggerableMissionsTU[iTriggerIndex].bUsed
STATIC_BLIP_NAME_ENUM eTriggerBlip = g_TriggerableMissionsTU[iTriggerIndex].eBlip
#ENDIF
#IF NOT USE_SP_DLC
REPEAT MAX_MISSION_TRIGGERS iTriggerIndex
IF g_TriggerableMissions[iTriggerIndex].bUsed
STATIC_BLIP_NAME_ENUM eTriggerBlip = g_TriggerableMissions[iTriggerIndex].eBlip
#ENDIF
eMaxBlip = STATIC_BLIP_NAME_DUMMY_FINAL
//B* 2083300: Make sure the blip is in the acceptable range (under name_dummy_final)
IF eTriggerBlip >= eMaxBlip
CPRINTLN(debug_replay,"Blip value out of range, does this mission have a blip?")
RETURN FALSE
ENDIF
IF IS_BIT_SET(g_GameBlips[eTriggerBlip].iSetting, STATIC_BLIP_SETTING_MULTI_COORD_AND_SPRITE)
vTriggerPosition = GET_STATIC_BLIP_POSITION(eTriggerBlip, GET_CURRENT_PLAYER_PED_INT())
ELSE
vTriggerPosition = GET_STATIC_BLIP_POSITION(eTriggerBlip)
ENDIF
//Vehicle is within 3m of a mission trigger. Don't let it spawn here.
IF VDIST2(playerVehicleSnapshot.vVehiclePos, vTriggerPosition) < 3 //3^2
CPRINTLN(DEBUG_REPLAY,"LOAD_VEHICLE_SNAPSHOT_SHAPETEST_RESULT: FAIL - ON TRIGGER")
RETURN FALSE
ENDIF
#IF USE_SP_DLC
ENDIF
ENDREPEAT
#ENDIF
#IF NOT USE_SP_DLC
ENDIF
ENDREPEAT
#ENDIF
SHAPETEST_INDEX shapeTestIndex
ENTITY_INDEX hitEntity
VECTOR vTempMin
VECTOR vTempMax
VECTOR vHitPos
VECTOR vHitNorm
INT iReturnValue = -1
//Now run a shapetest to check if the vehicle will collide with any game objects.
GET_MODEL_DIMENSIONS(playerVehicleSnapshot.mVehicle.eModel, vTempMin, vTempMax)
IF NOT IS_ENTITY_DEAD(vPlayersVeh)
shapeTestIndex = START_SHAPE_TEST_BOX(playerVehicleSnapshot.vVehiclePos,vTempMax-vTempMin,<<0.0, 0.0,playerVehicleSnapshot.fVehicleHeading>>,DEFAULT,SCRIPT_INCLUDE_VEHICLE|SCRIPT_INCLUDE_OBJECT|SCRIPT_INCLUDE_RAGDOLL|SCRIPT_INCLUDE_GLASS,vPlayersVeh)
ENDIF
WHILE GET_SHAPE_TEST_RESULT(shapeTestIndex,iReturnValue,vHitPos,vHitNorm,hitEntity) = SHAPETEST_STATUS_RESULTS_NOTREADY
WAIT(0)
ENDWHILE
IF iReturnValue = 0
CPRINTLN(DEBUG_REPLAY,"LOAD_VEHICLE_SNAPSHOT_SHAPETEST_RESULT: PASS")
//load vehicle
RETURN TRUE
ELIF iReturnValue = 1
CPRINTLN(DEBUG_REPLAY,"LOAD_VEHICLE_SNAPSHOT_SHAPETEST_RESULT: FAIL")
//Don't load vehicle
RETURN FALSE
ELSE
CPRINTLN(DEBUG_REPLAY,"LOAD_VEHICLE_SNAPSHOT_SHAPETEST_RESULT: NON EXISTENT!!??!!??")
//Something went wrong, Don't load vehicle
RETURN FALSE
ENDIF
ENDFUNC
/// PURPOSE:
/// Restores the vehicle stored in the specified snapshot
/// Clears the nearby area, waits for model to load, creates vehicle
/// Puts player in if he is very near, sets vehicle as no longer needed
/// PARAMS:
/// mVehicleSnapshot - the start or stage snapshot
/// mPlayerVehicle - the index of the vehicle created
/// bAllowBoats - is this vehicle allowed to be a boat?
/// bWarpInCheck - if this is set to true we warp the player into the vehicle if he was in it when the vehicle was snapshotted
/// bAllowPlanes - is this vehicle allowed to be a plane?
/// bAllowCopCars - is this vehicle allowed to be a cop car?
/// RETURNS:
/// TRUE if vehicle was created, FALSE otherwise
FUNC BOOL RestoreSnapshotVehicle(VEHICLE_SNAPSHOT &mVehicleSnapshot, VEHICLE_INDEX &mPlayerVehicle, BOOL bAllowBoats = FALSE, BOOL bWarpInCheck = FALSE, BOOL bAllowPlanes = TRUE, BOOL bAllowCopCars = TRUE, BOOL bDeleteSamePlayerVehicles = FALSE #IF USE_TU_CHANGES , BOOL bIgnoreCollisionCheck = FALSE #ENDIF )
BOOL bPutPlayerInVehicle = FALSE
VECTOR vMin
VECTOR vMax
VECTOR vVehicleMin
VECTOR vVehicleMax
FLOAT fVehicleX
FLOAT fVehicleY
FLOAT fVehicleZ
FLOAT fVehicleLargestDimension
IF IsSnapshotVehicleAvailable(mVehicleSnapshot)
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: mVehicleSnapshot.mVehicle.eModel =", GET_MODEL_NAME_FOR_DEBUG(mVehicleSnapshot.mVehicle.eModel))
IF bAllowBoats = FALSE
IF IS_THIS_MODEL_A_BOAT(mVehicleSnapshot.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Not restoring snapshot vehicle as it is a boat")
// pass info to impound if needed
IF mVehicleSnapshot.bTrackedForImpound = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: creation aborted: update impound info")
SEND_VEHICLE_DATA_TO_IMPOUND_USING_SETUP(mVehicleSnapshot.mVehicle, mVehicleSnapshot.ePlayerCharacter)
ENDIF
RETURN FALSE
ENDIF
ENDIF
IF bAllowPlanes = FALSE
IF IS_THIS_MODEL_A_PLANE(mVehicleSnapshot.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Not restoring snapshot vehicle as it is a plane")
// pass info to impound if needed
IF mVehicleSnapshot.bTrackedForImpound = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: creation aborted: update impound info")
SEND_VEHICLE_DATA_TO_IMPOUND_USING_SETUP(mVehicleSnapshot.mVehicle, mVehicleSnapshot.ePlayerCharacter)
ENDIF
RETURN FALSE
ENDIF
ENDIF
IF bAllowCopCars = FALSE
IF IS_MODEL_POLICE_VEHICLE(mVehicleSnapshot.mVehicle.eModel)
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Not restoring snapshot vehicle as it is a cop car")
// pass info to impound if needed
IF mVehicleSnapshot.bTrackedForImpound = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: creation aborted: update impound info")
SEND_VEHICLE_DATA_TO_IMPOUND_USING_SETUP(mVehicleSnapshot.mVehicle, mVehicleSnapshot.ePlayerCharacter)
ENDIF
RETURN FALSE
ENDIF
ENDIF
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Restoring snapshot vehicle")
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID()) // need the player to be alive to check his co-ords
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Trying to clear the area now")
GET_MODEL_DIMENSIONS(mVehicleSnapshot.mVehicle.eModel, vVehicleMin, vVehicleMax)
fVehicleX = vVehicleMax.x - vVehicleMin.x
fVehicleY = vVehicleMax.y - vVehicleMin.y
fVehicleZ = vVehicleMax.z - vVehicleMin.z
// see which dimension of the vehicle is the largest
fVehicleLargestDimension = fVehicleX
IF fVehicleY > fVehicleLargestDimension
fVehicleLargestDimension = fVehicleY
ENDIF
IF fVehicleZ > fVehicleLargestDimension
fVehicleLargestDimension = fVehicleZ
ENDIF
// work out area we need to check is clear to create vehicle
vMin = mVehicleSnapshot.vVehiclePos
vMin = vMin -vVehicleMin
vMax = mVehicleSnapshot.vVehiclePos
vMax = vMax +vVehicleMax
//CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: vehicle pos =", mVehicleSnapshot.vVehiclePos)
//CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: vehicle area min pos =", vMin)
//CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: vehicle area max pos =", vMax)
//CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: vVehicleMin =", vVehicleMin)
//CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: vVehicleMax =", vVehicleMax)
//#1676539
#IF USE_TU_CHANGES
ENTITY_INDEX vPlayersVeh
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
vPlayersVeh = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
ELSE
vPlayersVeh = PLAYER_PED_ID()
ENDIF
//#1990795
BOOL bCheckIfAreaOccupied = TRUE
IF bIgnoreCollisionCheck
IF IS_THIS_MODEL_A_PLANE(mVehicleSnapshot.mVehicle.eModel)
OR IS_THIS_MODEL_A_HELI(mVehicleSnapshot.mVehicle.eModel)
bCheckIfAreaOccupied = FALSE
ENDIF
ENDIF
IF bCheckIfAreaOccupied
// AND IF IS_AREA_OCCUPIED(vMin, vMax, FALSE, TRUE, FALSE, TRUE, FALSE, vPlayersVeh)
// and not IS_THIS_MODEL_A_HELI(mVehicleSnapshot.mVehicle.eModel)
//B* 1819425
IF NOT CAN_LOAD_VEHICLE_AT_SNAPSHOT_POSITION(mVehicleSnapshot, vPlayersVeh)
IF NOT CAN_LOAD_VEHICLE_FROM_SNAPSHOT_AT_NEARBY_ROAD_NODE(mVehicleSnapshot, vPlayersVeh)
// position is blocked, abort creation
CPRINTLN(DEBUG_REPLAY, "TU RestoreSnapshotVehicle: Vehicle pos occupied, so aborting creation")
// pass info to impound if needed
IF mVehicleSnapshot.bTrackedForImpound = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: creation aborted: update impound info")
SEND_VEHICLE_DATA_TO_IMPOUND_USING_SETUP(mVehicleSnapshot.mVehicle, mVehicleSnapshot.ePlayerCharacter)
ENDIF
RETURN FALSE
ENDIF
ENDIF
ENDIF
#ENDIF
// clear room for car //Moved clear tasks to run after shape tests
CLEAR_AREA(mVehicleSnapshot.vVehiclePos, fVehicleLargestDimension, TRUE)
CLEAR_AREA_OF_OBJECTS(mVehicleSnapshot.vVehiclePos, fVehicleLargestDimension, CLEAROBJ_FLAG_FORCE)
#IF NOT USE_TU_CHANGES
IF IS_AREA_OCCUPIED(vMin, vMax, FALSE, TRUE, FALSE, TRUE, FALSE)
// position is blocked, abort creation
CPRINTLN(DEBUG_REPLAY, "non TU RestoreSnapshotVehicle: Vehicle pos occupied, so aborting creation")
// pass info to impound if needed
IF mVehicleSnapshot.bTrackedForImpound = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: creation aborted: update impound info")
SEND_VEHICLE_DATA_TO_IMPOUND_USING_SETUP(mVehicleSnapshot.mVehicle, mVehicleSnapshot.ePlayerCharacter)
ENDIF
RETURN FALSE
ENDIF
#ENDIF
// area is ok for creating vehicle, load assets
RequestSnapshotVehicleModel(mVehicleSnapshot)
WHILE NOT HasSnapshotVehicleLoaded(mVehicleSnapshot)
WAIT(0)
ENDWHILE
// create vehicle
mPlayerVehicle = CreateSnapshotVehicle(mVehicleSnapshot, <<0.0,0.0,0.0>>, 0.0, bDeleteSamePlayerVehicles) // create vehicle at the position it was in the start snapshot
IF DOES_ENTITY_EXIST(mPlayerVehicle)
IF IS_VEHICLE_DRIVEABLE(mPlayerVehicle)
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF bWarpInCheck = TRUE
AND mVehicleSnapshot.bInVehicle = TRUE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: player was in vehicle when snapshotted, put in")
bPutPlayerInVehicle= TRUE
ELSE
// see if player is very close to the vehicle
IF GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(mPlayerVehicle), GET_ENTITY_COORDS(PLAYER_PED_ID())) < 3.0
OR IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), mPlayerVehicle)
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: player is very close to vehicle, put in")
bPutPlayerInVehicle= TRUE
ENDIF
ENDIF
#IF USE_TU_CHANGES
// If we are re-creating the vehicle for the startup script, do not spawn the player inside if
// it is in a restricted area.
#IF USE_CLF_DLC
IF (GET_HASH_KEY(GET_THIS_SCRIPT_NAME()) = HASH("startup_pos_CLF"))
#endif
#if USE_NRM_DLC
IF (GET_HASH_KEY(GET_THIS_SCRIPT_NAME()) = HASH("startup_pos_NRM"))
#endif
#if NOT USE_SP_DLC
IF (GET_HASH_KEY(GET_THIS_SCRIPT_NAME()) = HASH("startup_positioning"))
#endif
// in a Vehicle Garage
IF IS_ENTITY_IN_ANGLED_AREA(mPlayerVehicle, <<207.433578,-1019.795410,-100.472763>>, <<189.933777,-1019.623474,-95.568832>>, 17.187500)
bPutPlayerInVehicle = FALSE
// Hayes' Chopshop
ELIF IS_ENTITY_IN_ANGLED_AREA(mPlayerVehicle, <<483.717468,-1326.629883,28.213499>>, <<474.964355,-1307.998291,34.494976>>, 12.000000)
bPutPlayerInVehicle = FALSE
// Impound Garage
ELIF IS_ENTITY_IN_ANGLED_AREA(mPlayerVehicle, <<439.543152,-996.976868,24.883070>>, <<428.293549,-997.019226,28.574581>>, 8.500000)
bPutPlayerInVehicle = FALSE
ENDIF
#IF USE_CLF_DLC
ENDIF
#endif
#if USE_NRM_DLC
ENDIF
#endif
#if NOT USE_SP_DLC
ENDIF
#ENDIF
#ENDIF
IF bPutPlayerInVehicle = TRUE
IF IS_ENTITY_ATTACHED(PLAYER_PED_ID())
FREEZE_ENTITY_POSITION(GET_ENTITY_ATTACHED_TO(PLAYER_PED_ID()), FALSE)
ELSE
FREEZE_ENTITY_POSITION(PLAYER_PED_ID(), FALSE)
ENDIF
SET_ENTITY_COLLISION(PLAYER_PED_ID(), TRUE)
CPRINTLN(DEBUG_REPLAY, "Turning player's collision back on as we're putting him in a vehicle.")
SET_PED_INTO_VEHICLE(PLAYER_PED_ID(), mPlayerVehicle)
// if we're putting the player in a helicopter, start the blades
IF IS_THIS_MODEL_A_HELI(mVehicleSnapshot.mVehicle.eModel)
SET_HELI_BLADES_FULL_SPEED(mPlayerVehicle)
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Snapshot vehicle restored")
RETURN TRUE
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: No snapshot vehicle available to restore")
ENDIF
CPRINTLN(DEBUG_REPLAY, "RestoreSnapshotVehicle: Snapshot vehicle not restored")
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks if the snapshot vehicle is restricted or was snapshotted for another character
/// PARAMS:
/// mSnapshot - start or stage snapshot
/// RETURNS:
/// TRUE if it is safe to restore this snapshot vehicle. FALSE otherwise
FUNC BOOL CanRestoreSnapshotVehicleForCharacter(SNAPSHOT_STRUCT &mSnapshot, enumCharacterList eCharacter)
enumCharacterList eVehicleOwner
IF IsSnapshotVehicleAvailable(mSnapshot.mVehicleStruct)
IF mSnapshot.bRestrictedVehicle = FALSE
// check if this vehicle is owned by another character
eVehicleOwner = mSnapshot.mVehicleStruct.ePlayerCharacter
IF eVehicleOwner = NO_CHARACTER
OR eVehicleOwner = eCharacter
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "CanRestoreSnapshotVehicleForCharacter. Vehicle belongs to a different character.")
CPRINTLN(DEBUG_REPLAY, "eVehicleOwner: ", eVehicleOwner , " eCharacter: ", eCharacter)
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "CanRestoreSnapshotVehicleForCharacter. Vehicle restricted.")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "CanRestoreSnapshotVehicleForCharacter. no vehicle available.")
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Attempts to restore the stage snapshot vehicle, if this fails it attempts to restore the start snapshot vehicle
/// PARAMS:
/// eCharacter - the character we are trying to restore a vehicle for
/// RETURNS:
/// TRUE if vehicle restored. FALSE otherwise
FUNC BOOL RestoreAnySnapshotVehicle(enumCharacterList eCharacter, BOOL bAllowCopCars = TRUE)
VEHICLE_INDEX mPlayerVehicle
// try to create stage snapshot vehicle
IF CanRestoreSnapshotVehicleForCharacter(g_stageSnapshot, eCharacter)
IF RestoreSnapshotVehicle(g_stageSnapshot.mVehicleStruct, mPlayerVehicle, FALSE, FALSE, FALSE, bAllowCopCars, TRUE)
IF DOES_ENTITY_EXIST(mPlayerVehicle)
// clear velocity here as this is only used if the player has warped
SET_ENTITY_VELOCITY(mPlayerVehicle, <<0.0,0.0,0.0>>)
CPRINTLN(DEBUG_REPLAY, "Clear player vehicle velocity as we've warped him.")
SET_VEHICLE_AS_NO_LONGER_NEEDED(mPlayerVehicle)
ENDIF
RETURN TRUE
ENDIF
ENDIF
// try to create start snapshot vehicle
IF CanRestoreSnapshotVehicleForCharacter(g_startSnapshot, eCharacter)
// the stage snapshot has the correct position info in it, so copy it over...
g_startSnapshot.mVehicleStruct.vVehiclePos = g_stageSnapshot.mVehicleStruct.vVehiclePos
g_startSnapshot.mVehicleStruct.fVehicleHeading = g_stageSnapshot.mVehicleStruct.fVehicleHeading
IF RestoreSnapshotVehicle(g_startSnapshot.mVehicleStruct, mPlayerVehicle, FALSE, FALSE, FALSE, bAllowCopCars, TRUE)
IF DOES_ENTITY_EXIST(mPlayerVehicle)
// clear velocity here as this is only used if the player has warped
SET_ENTITY_VELOCITY(mPlayerVehicle, <<0.0,0.0,0.0>>)
CPRINTLN(DEBUG_REPLAY, "Clear player vehicle velocity as we've warped him.")
SET_VEHICLE_AS_NO_LONGER_NEEDED(mPlayerVehicle)
ENDIF
RETURN TRUE
ENDIF
ENDIF
CPRINTLN(DEBUG_REPLAY, "RestoreAnySnapshotVehicle. No valid snapshot vehicle to restore.")
RETURN FALSE
ENDFUNC
// ===========================================================================================================
// FAIL WEAPON FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// Checks if the player character specified had the weapon specified at their last checkpoint
/// PARAMS:
/// iCharIndex - 0,1,2 Michael, Franklin, Trevor
/// mWeapon - the weapon type we are checking
/// RETURNS:
/// BOOL, true if this player character had this weapon at their last checkpoint. false otherwise
FUNC BOOL Had_Weapon_At_Last_Checkpoint(INT iCharIndex, WEAPON_TYPE mWeapon)
INT iTempIndex = 0
#IF NOT USE_TU_CHANGES
SNAPSHOT_STRUCT paramSnapshot
IF g_replayMissionStage > 0
paramSnapshot = g_stageSnapshot
ELSE
paramSnapshot = g_startSnapshot
ENDIF
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
IF paramSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF paramSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
IF paramSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF paramSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
#ENDIF
#IF USE_TU_CHANGES
IF g_replayMissionStage > 0
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
IF g_stageSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF g_stageSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
IF g_stageSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF g_stageSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
ELSE
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
IF g_startSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF g_startSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
IF g_startSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].eWeaponType = mWeapon
IF g_startSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex].iAmmoCount > 0
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Had fail weapon at last checkpoint, but no ammo: don't store.")
ENDIF
ENDIF
ENDREPEAT
ENDIF
#ENDIF
RETURN FALSE
ENDFUNC
// ===========================================================================================================
// SNAPSHOT STORING FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// Returns string value of weather type passed in
/// PARAMS:
/// iWeather - hash of weather type
/// RETURNS:
/// STRING of weather type to restore. or empty string if invalid (asserts)
FUNC STRING GET_WEATHER_STRING_FROM_HASH(INT iWeather)
IF iWeather = HASH("EXTRASUNNY")
RETURN "EXTRASUNNY"
ELIF iWeather = HASH("CLEAR")
RETURN "CLEAR"
ELIF iWeather = HASH("CLOUDS")
RETURN "CLOUDS"
ELIF iWeather = HASH("SMOG")
RETURN "SMOG"
ELIF iWeather = HASH("FOGGY")
RETURN "FOGGY"
ELIF iWeather = HASH("OVERCAST")
RETURN "OVERCAST"
ELIF iWeather = HASH("RAIN")
RETURN "RAIN"
ELIF iWeather = HASH("THUNDER")
RETURN "THUNDER"
ELIF iWeather = HASH("CLEARING")
RETURN "CLEARING"
ELIF iWeather = HASH("NEUTRAL")
RETURN "NEUTRAL"
ELIF iWeather = HASH("SNOW")
RETURN "SNOW"
ELIF iWeather = HASH("BLIZZARD")
RETURN "BLIZZARD"
ELIF iWeather = HASH("SNOWLIGHT")
RETURN "SNOWLIGHT"
ENDIF
// not found stored weather, assert and exit
CPRINTLN(DEBUG_REPLAY, "GET_WEATHER_STRING_FROM_HASH: Stored weather invalid: ", iWeather)
SCRIPT_ASSERT("GET_WEATHER_STRING_FROM_HASH: Stored weather invalid.")
RETURN ""
ENDFUNC
/// PURPOSE:
/// Sets the position of the vehicle in the specified snapshot
/// This is used to alter where the vehicle will be restored if a replay is rejected.
/// e.g. If the player is getting warped out of a restricted area etc.
/// PARAMS:
/// paramSnapshot - the vehicle snapshot we are editing.
/// vVehiclePos - where we will want to respawn vehicle.
/// fVehicleHeading - the heading to use when respawning vehicle.
PROC Set_Vehicle_Snapshot_Pos(VEHICLE_SNAPSHOT &paramSnapshot, VECTOR vVehiclePos, FLOAT fVehicleHeading)
paramSnapshot.vVehiclePos = vVehiclePos
paramSnapshot.fVehicleHeading = fVehicleHeading
ENDPROC
/// PURPOSE:
/// Stores all the info used in a player snapshot struct
/// bQuickSave - true for quick save and repeat play saves. Use to reposition the player away from unsuitable spawn areas.
PROC Store_Player_Snapshot(PLAYER_SNAPSHOT &mSnapshot, BOOL bQuickSave = FALSE)
// get player's position, heading + wanted level
mSnapshot.vPos = GET_ENTITY_COORDS(PLAYER_PED_ID()) // store player's position
mSnapshot.fHeading = GET_ENTITY_HEADING(PLAYER_PED_ID())
mSnapshot.eParachuteState = GET_PED_PARACHUTE_STATE(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPLAY, "Storing eParachuteState as ", mSnapshot.eParachuteState)
IF IS_PLAYER_PLAYING(PLAYER_ID())
mSnapshot.iWantedLevel = GET_PLAYER_WANTED_LEVEL(PLAYER_ID())
CPRINTLN(DEBUG_REPLAY, "Storing player's wanted level as ", mSnapshot.iWantedLevel)
ENDIF
// -----Check to see if we need to overwrite these for any reason--------
// Vinewood cinema
IF VDIST(mSnapshot.vPos, <<320.9934, 265.2515, 82.1221>>) < 10
mSnapshot.vPos = <<301.2162, 202.1357, 103.3797>>
mSnapshot.fHeading = 156.5144
CPRINTLN(DEBUG_REPLAY, "Player in Vinewood cinema, overwrite stored co-ords")
// Downtown cinema
ELIF VDIST(mSnapshot.vPos, << 377.1530, -717.5670, 10.0536 >>) < 10
mSnapshot.vPos = << 394.2567, -713.5439, 28.2853 >>
mSnapshot.fHeading = 276.6273
CPRINTLN(DEBUG_REPLAY, "Player in Downtown cinema, overwrite stored co-ords")
// Morningwood cinema
ELIF VDIST(mSnapshot.vPos, << -1425.5645, -244.3000, 15.8053 >>) < 10
mSnapshot.vPos = <<-1423.4724, -214.2539, 45.5004>>
mSnapshot.fHeading = 353.8757
CPRINTLN(DEBUG_REPLAY, "Player in Morningwood cinema, overwrite stored co-ords")
// Finale Choice in progress
ELIF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("Finale_Choice")) > 0
mSnapshot.vPos = <<4.2587, 525.0214, 173.6281>>
mSnapshot.fHeading = 203.6746
CPRINTLN(DEBUG_REPLAY, "Finale choice in progress, overwrite stored co-ords")
// Cable Car up
ELIF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_ON_CABLE_CAR_UP))
mSnapshot.vPos = <<452.0255, 5571.8501, 780.1859>>
mSnapshot.fHeading = 78.9858
CPRINTLN(DEBUG_REPLAY, "Player on cable car going up, overwrite stored co-ords")
// Cable Car down
ELIF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_ON_CABLE_CAR_DOWN))
mSnapshot.vPos = <<-745.4462, 5595.1465, 40.6594>>
mSnapshot.fHeading = 261.7470
CPRINTLN(DEBUG_REPLAY, "Player on cable car going down, overwrite stored co-ords")
// Ferris Wheel
ELIF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_ON_FERRIS_WHEEL))
mSnapshot.vPos = <<-1675.5215, -1125.5901, 12.0910>>
mSnapshot.fHeading = 271.8208
CPRINTLN(DEBUG_REPLAY, "Player on ferris wheel, overwrite stored co-ords")
// Rollercoaster
ELIF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_ON_ROLLERCOASTER))
mSnapshot.vPos = <<-1631.2192, -1112.8052, 12.0212>>
mSnapshot.fHeading = 316.8879
CPRINTLN(DEBUG_REPLAY, "Player on rollercoaster, overwrite stored co-ords")
// Lester's house
ELIF GET_INTERIOR_FROM_ENTITY(PLAYER_PED_ID()) = GET_INTERIOR_AT_COORDS_WITH_TYPE(<<1272.6588, -1715.4669, 53.7715>>, "v_lesters")
mSnapshot.vPos = <<1276.9564, -1725.1892, 53.6551>>
mSnapshot.fHeading = 204.1703
CPRINTLN(DEBUG_REPLAY, "Player in Lester's house, overwrite stored co-ords")
// Murder Mystery - Mine
ELIF IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-415.436462, 2068.288574, 113.300171>>,
<<-564.951599, 1884.702515, 134.040344>>, 258.750000 )
OR IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-596.470581, 2089.920898, 125.412750>>,
<<-581.213440, 2036.256104, 136.283630>>, 9.500000 )
mSnapshot.vPos = <<-601.5900, 2099.1973, 128.8928>>
mSnapshot.fHeading = 204.7498
CPRINTLN(DEBUG_REPLAY, "Player in mine, overwrite stored co-ords")
// Murder Mystery - Solomon's Office
ELIF VDIST(mSnapshot.vPos, <<-1007.392639, -477.958435, 52.535702>>) < 8
mSnapshot.vPos = <<-1018.3756, -483.9436, 36.0964>>
mSnapshot.fHeading = 114.7664
CPRINTLN(DEBUG_REPLAY, "Player in Solomon's office, overwrite stored co-ords")
// Car Steal - Garage
ELIF VDIST(mSnapshot.vPos, <<480.66620, -1317.80847, 28.20303>>) < 15
mSnapshot.vPos = <<497.7238, -1310.9323, 28.2372>>
mSnapshot.fHeading = 289.3663
CPRINTLN(DEBUG_REPLAY, "Player in Car Steal - Garage, overwrite stored co-ords")
//RC - Omega shed
ELIF VDIST(mSnapshot.vPos, <<2329.5266, 2571.3113, 45.6779>>) < 5
mSnapshot.vPos = <<2316.9304, 2594.1528, 45.7199>>
mSnapshot.fHeading = 348.1325
CPRINTLN(DEBUG_REPLAY, "Player in Omega - Shed, overwrite stored co-ords")
ENDIF
// quick save only checks
IF bQuickSave = TRUE
SHOP_NAME_ENUM eShop
VECTOR vPos
FLOAT fHeading
// closed shop (to avoid issues of getting stuck behind respawned shopkeeper - like 1482459)
IF IS_PLAYER_IN_CLOSED_SHOP(eShop)
IF GET_SHOP_PARKING_SPACE(eShop, vPos, fHeading)
vPos.z = vPos.z + 1 // up the z so we're not in the ground
mSnapshot.vPos = vPos
mSnapshot.fHeading = fHeading
CPRINTLN(DEBUG_REPLAY, "Player in closed shop, overwrite stored co-ords")
ENDIF
// in a Vehicle Garage
ELIF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<207.433578,-1019.795410,-100.472763>>, <<189.933777,-1019.623474,-95.568832>>, 17.187500)
enumCharacterList eChar = GET_CURRENT_PLAYER_PED_ENUM()
IF eChar = CHAR_MICHAEL
mSnapshot.vPos = <<-65.1234, 81.2517, 70.5644>>
mSnapshot.fHeading = 71.6237
ELIF eChar = CHAR_FRANKLIN
mSnapshot.vPos = <<-68.5531, -1824.3774, 25.9424>>
mSnapshot.fHeading = 215.8295
ELIF eChar = CHAR_TREVOR
mSnapshot.vPos = <<-220.8189, -1162.3016, 22.0242>>
mSnapshot.fHeading = 70.2711
ENDIF
CPRINTLN(DEBUG_REPLAY, "Player in garage, overwrite stored co-ords")
// Hayes' Chopshop
ELIF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<483.717468,-1326.629883,28.213499>>, <<474.964355,-1307.998291,34.494976>>, 12.000000)
mSnapshot.vPos = <<495.4108, -1306.0801, 29.2883>>
mSnapshot.fHeading = 213.6273
CPRINTLN(DEBUG_REPLAY, "Player in hayes garage, overwrite stored co-ords")
// Under Floyd's apartment. B*1747233, 2214618
ELIF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<-1146.77, -1534.22, 3.37>>, <<-1158.452515,-1517.749634,6.374244>>, 13.000000)
mSnapshot.vPos = <<-1160.0951, -1515.4070, 3.1496>>
mSnapshot.fHeading = 305.6424
CPRINTLN(DEBUG_REPLAY, "Player under Floyd's apartment, overwrite stored co-ords")
#IF USE_TU_CHANGES
// Impound Garage
ELIF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<439.543152,-996.976868,24.883070>>, <<428.293549,-997.019226,28.574581>>, 8.500000)
mSnapshot.vPos = <<431.8853, -1013.1330, 28.7907>>
mSnapshot.fHeading = 186.6814
CPRINTLN(DEBUG_REPLAY, "Player in impound garage, overwrite stored co-ords")
#ENDIF
// B*1721440 - RC - Nigel 2 hospital interior (still accessible straight after the mission ends)
ELIF IS_POSITION_INSIDE_SPECIFC_INTERIOR(mSnapshot.vPos, "v_hospital", << 307.3065, -589.9595, 43.3020 >>)
mSnapshot.vPos = <<279.4137, -585.8815, 43.2502>>
mSnapshot.fHeading = 48.8028
CPRINTLN(DEBUG_REPLAY, "Player in hospital interior, overwrite stored co-ords : ", mSnapshot.vPos)
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Checks to see if the vehicle index matches one stored in the restricted vehicles array
/// PARAMS:
/// mVehicle - teh vehicle we are checking
/// RETURNS:
/// TRUE if the vehicle is set as restricted, FALSE otherwise
FUNC BOOL IS_VEHICLE_RESTRICTED(VEHICLE_INDEX mVehicle)
INT iVehicleNumber
FOR iVehicleNumber = 0 TO MAX_RESTRICTED_VEHICLES -1
IF g_replay.mRestrictedVehicles[iVehicleNumber] = mVehicle
RETURN TRUE // the vehicle is in the restricted array
ENDIF
ENDFOR
RETURN FALSE //the vehicle is not in the restricted array
ENDFUNC
/// PURPOSE:
/// Stores the vehicle snapshot, does not use the massive replay snapshot struct
PROC Store_Vehicle_Snapshot_Only(VEHICLE_SNAPSHOT &mVehicleSnapshot, VEHICLE_INDEX mVehicle, BOOL bStorePosition = TRUE)
GET_VEHICLE_SETUP(mVehicle, mVehicleSnapshot.mVehicle)
// store whether this is a personal vehicle so we can flag it as such when re-creating it
mVehicleSnapshot.bPersonalVehicle = IS_VEHICLE_A_PLAYER_PERSONAL_VEHICLE(mVehicle)
CPRINTLN(DEBUG_REPLAY, "bPersonalVehicle = ", mVehicleSnapshot.bPersonalVehicle)
mVehicleSnapshot.ePlayerCharacter = GET_PLAYER_PED_PERSONAL_VEHICLE_BELONGS_TO(mVehicle)
CPRINTLN(DEBUG_REPLAY, "ePlayerCharacter = ", GET_PLAYER_PED_STRING(mVehicleSnapshot.ePlayerCharacter))
//If not a personal vehicle check if it was generated by a vehgen - B* 1821085
IF NOT mVehicleSnapshot.bPersonalVehicle
//If VehGen true, remain true
IF NOT mVehicleSnapshot.bVehGen
mVehicleSnapshot.bVehGen = IS_VEHICLE_A_VEHGEN_VEHICLE(mVehicle)
ENDIF
ENDIF
IF bStorePosition = TRUE
// store the vehicle's position and heading + velocity
mVehicleSnapshot.vVehiclePos = GET_ENTITY_COORDS(mVehicle)
mVehicleSnapshot.fVehicleHeading = GET_ENTITY_HEADING(mVehicle)
mVehicleSnapshot.vVehicleVelocity = GET_ENTITY_VELOCITY(mVehicle)
// -----Check to see if we need to overwrite these for any reason--------
// Under Floyd's apartment. B*1747233
IF IS_ENTITY_IN_ANGLED_AREA(mVehicle, <<-1154.325562,-1523.871338,3.262189>>, <<-1158.452515,-1517.749634,6.374244>>, 13.000000)
mVehicleSnapshot.vVehiclePos = <<-1160.0951, -1515.4070, 3.1496>>
mVehicleSnapshot.fVehicleHeading = 305.6424
CPRINTLN(DEBUG_REPLAY, "Player vehicle under Floyd's apartment, overwrite stored co-ords")
ENDIF
CPRINTLN(DEBUG_REPEAT, "vVehicleVelocity x= ", mVehicleSnapshot.vVehicleVelocity.x, " y= ", mVehicleSnapshot.vVehicleVelocity.y, " z= ", mVehicleSnapshot.vVehicleVelocity.z)
IF g_vCarToTrackForImpound = mVehicle
mVehicleSnapshot.bTrackedForImpound = TRUE
ENDIF
CPRINTLN(DEBUG_REPLAY, "bTrackedForImpound = ", mVehicleSnapshot.bTrackedForImpound)
ENDIF
// store whether the player is in a vehicle
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
mVehicleSnapshot.bInVehicle = TRUE
ELSE
mVehicleSnapshot.bInVehicle = FALSE
ENDIF
CPRINTLN(DEBUG_REPLAY, "mVehicleSnapshot.bInVehicle = ", mVehicleSnapshot.bInVehicle)
ENDPROC
/// PURPOSE:
/// Stores information on a specific vehicle that exists in the world.
/// PARAMS:
/// mVehicleSnapshot - the vehicle snapshot we are updating
/// mSnapshot - the start or stage snapshot
/// mVehicle - The vehicle to store.
/// bStorePosition - can set this to FALSE so we don't overwrite the replay rejected warp position
FUNC BOOL Store_Vehicle_Snapshot_For_Vehicle(VEHICLE_SNAPSHOT &mVehicleSnapshot, SNAPSHOT_STRUCT &mSnapshot, VEHICLE_INDEX mVehicle, BOOL bStorePosition = TRUE)
IF IS_VEHICLE_DRIVEABLE(mVehicle)
CPRINTLN(DEBUG_REPLAY, "Storing player's vehicle snapshot now for script: ", GET_THIS_SCRIPT_NAME())
//-------- store the small vehicle snapshot info---------------
Store_Vehicle_Snapshot_Only(mVehicleSnapshot, mVehicle, bStorePosition )
//------- store the other info that is needed in the large replay snapshot-------
// store the vehicle index
mSnapshot.mVehicleIndex = mVehicle
// store whether this vehicle is restricted
IF IS_VEHICLE_RESTRICTED(mVehicle)
mSnapshot.bRestrictedVehicle = TRUE
CPRINTLN(DEBUG_REPLAY, "Snapshot vehicle set as restricted.")
ELSE
mSnapshot.bRestrictedVehicle = FALSE
ENDIF
RETURN TRUE // vehicle succesfully snapshotted
ELSE
CPRINTLN(DEBUG_REPLAY, "Not storing vehicle for snapshot as it is not driveable.")
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Checks if there is a suitable vehicle to snapshot for this character
/// PARAMS:
/// mPlayerPed - which player are we checking this vehicle for?
/// mVehicle - index to the vehicle that is getting snapshotted
/// bDoDistanceCheck - only snapshot this vehicle if nearby?
/// RETURNS:
/// TRUE if there is a suitable vehicle, FALSE otherwise
/// bQuickSave - true for quick save and repeat play saves. Use to ignore vehicles with "IgnoredByQuickSave" decor
FUNC BOOL Is_Vehicle_Available_To_Snapshot(PED_INDEX mPlayerPed, VEHICLE_INDEX &mVehicle, BOOL bDoDistanceCheck = TRUE, BOOL bQuickSave = FALSE)
// works if the player is in a vehicle, or is near his last vehicle
IF DOES_ENTITY_EXIST(mPlayerPed)
IF NOT IS_PED_INJURED(mPlayerPed)
IF mPlayerPed = PLAYER_PED_ID()
mVehicle = GET_PLAYERS_LAST_VEHICLE()
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot checking for non player vehicle.")
mVehicle = GET_VEHICLE_PED_IS_IN(mPlayerPed, TRUE)
ENDIF
IF DOES_ENTITY_EXIST(mVehicle)
IF IS_VEHICLE_DRIVEABLE(mVehicle)
IF bDoDistanceCheck = FALSE
OR GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(mVehicle), GET_ENTITY_COORDS(mPlayerPed)) < MAX_VEHICLE_SNAPSHOT_DIST
//Don't store player vehicle if they are a taxi passenger.
IF IS_VEHICLE_MODEL(mVehicle, TAXI)
IF GET_PED_IN_VEHICLE_SEAT(mVehicle, VS_DRIVER) != mPlayerPed
AND GET_PED_IN_VEHICLE_SEAT(mVehicle, VS_DRIVER) != NULL
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not storing as player is passenger in taxi.")
RETURN FALSE
ENDIF
ENDIF
// don't store the vehicle if it is in the player's garage
IF IS_VEHICLE_IN_PLAYERS_GARAGE(mVehicle, GET_CURRENT_PLAYER_PED_ENUM(), TRUE)
STRING sThisScriptName = GET_THIS_SCRIPT_NAME()
IF NOT ARE_STRINGS_EQUAL(sThisScriptName, "save_anywhere")
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not storing, as vehicle is in player's garage [triggered by \"", sThisScriptName, "\"].")
RETURN FALSE
ELIF NOT IS_PED_IN_ANY_VEHICLE(mPlayerPed, TRUE)
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not storing, as vehicle is in player's garage [triggered by \"", sThisScriptName, "\", player [", GET_CURRENT_PLAYER_PED_STRING(), "] inside vehicle].")
RETURN FALSE
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot ok to store storing, vehicle is in player's garage but script trying to save is \"", sThisScriptName, "\", player [", GET_CURRENT_PLAYER_PED_STRING(), "] not in vehicle].")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot vehicle [", GET_MODEL_NAME_OF_VEHICLE_FOR_DEBUG_ONLY(mVehicle), "] not in current players [", GET_CURRENT_PLAYER_PED_STRING(), "] garage.")
ENDIF
IF bQuickSave = TRUE
IF DECOR_EXIST_ON(mVehicle, "IgnoredByQuickSave")
IF DECOR_GET_BOOL(mVehicle, "IgnoredByQuickSave")
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not storing, as vehicle is flagged to be ignored for quick save.")
RETURN FALSE
ENDIF
ENDIF
// // Impound Garage
// ELIF IS_ENTITY_IN_ANGLED_AREA(mVehicle, <<439.543152,-996.976868,24.883070>>, <<428.293549,-997.019226,28.574581>>, 8.500000)
// CPRINTLN(DEBUG_REPLAY, "Car in impound garage, don't store")
// RETURN FALSE
// ENDIF
ELSE
// don't store the blimp unless quick save / repeat play save
IF IS_VEHICLE_MODEL(mVehicle, BLIMP)
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not storing blimp.")
RETURN FALSE
ENDIF
ENDIF
// the vehicle is safe to snapshot
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot found suitable vehicle.")
RETURN TRUE
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot failed distance check.")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot not driveable.")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "Is_Vehicle_Available_To_Snapshot does not exist.")
ENDIF
ENDIF
ENDIF
RETURN FALSE // vehicle not snapshotted
ENDFUNC
/// PURPOSE:
/// Stores information on the player's current vehicle
/// If he isn't in a vehicle it uses his last vehicle if it is nearby
/// PARAMS:
/// mVehicleSnapshot - the vehicle snapshot we are updating
/// mSnapshot - the start or stage snapshot
/// mPlayerPed - the player ped we are storing this info for
/// bDoDistanceCheck - can be set to false to store this info even if player is far away from the vehicle
/// bStorePosition - can set this to FALSE so we don't overwrite the replay rejected warp position
/// bQuickSave - true for quick save and repeat play saves. Use to ignore vehicles with "IgnoredByQuickSave" decor
PROC Store_Vehicle_Snapshot_For_Last_Player_Vehicle(VEHICLE_SNAPSHOT &mVehicleSnapshot, SNAPSHOT_STRUCT &mSnapshot, PED_INDEX mPlayerPed = NULL, BOOL bDoDistanceCheck = TRUE, BOOL bStorePosition = TRUE, BOOL bQuickSave = FALSE)
VEHICLE_INDEX mVehicle
// set who we are storing this vehicle for
IF mPlayerPed = NULL
CPRINTLN(DEBUG_REPLAY, "Storing vehicle snapshot for current player ped")
mPlayerPed = PLAYER_PED_ID() // default to the player ped
ELSE
CPRINTLN(DEBUG_REPLAY, "Storing vehicle snapshot for non-current player ped")
ENDIF
// store vehicle owner info
IF DOES_ENTITY_EXIST(mPlayerPed)
mSnapshot.eVehicleOwner = GET_PLAYER_PED_ENUM(mPlayerPed)
ENDIF
// see if there is a suitable vehicle to snapshot
IF Is_Vehicle_Available_To_Snapshot(mPlayerPed, mVehicle, bDoDistanceCheck, bQuickSave)
// store the snapshot info
Store_Vehicle_Snapshot_For_Vehicle(mVehicleSnapshot, mSnapshot, mVehicle, bStorePosition)
//B* 1774589: Disabling saving the heli causes player to fall to his death after loading
ELIF DOES_ENTITY_EXIST(mVehicle)
IF NOT IS_ENTITY_DEAD(mVehicle)
IF IS_VEHICLE_MODEL(mVehicle,SKYLIFT) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(),mVehicle)
//Store the heli anyway if in air
Store_Vehicle_Snapshot_For_Vehicle(mVehicleSnapshot, mSnapshot, mVehicle, bStorePosition)
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Stores information on the player's current vehicle
/// If he isn't in a vehicle it uses his last vehicle if it is nearby
/// This only uses the small vehicle snapshot, so doesn't store the replay snapshot info
/// PARAMS:
/// mVehicleSnapshot - the vehicle snapshot we are updating
/// mPlayerPed - the player ped we are storing this info for
/// bDoDistanceCheck - can be set to false to store this info even if player is far away from the vehicle
/// bStorePosition - can set this to FALSE so we don't overwrite the replay rejected warp position
/// RETURNS:
/// VEHICLE_INDEX index of the snapshotted vehicle. Will be invalid if no vehicle was snapshotted
FUNC VEHICLE_INDEX Store_Vehicle_Snapshot_Only_For_Last_Vehicle(VEHICLE_SNAPSHOT &mVehicleSnapshot, PED_INDEX mPlayerPed = NULL, BOOL bDoDistanceCheck = TRUE, BOOL bStorePosition = TRUE)
VEHICLE_INDEX mVehicle
VEHICLE_INDEX mSnapshotVehicle
// set who we are storing this vehicle for
IF mPlayerPed = NULL
CPRINTLN(DEBUG_REPLAY, "Storing vehicle snapshot for current player ped")
mPlayerPed = PLAYER_PED_ID() // default to the player ped
ELSE
CPRINTLN(DEBUG_REPLAY, "Storing vehicle snapshot for non-current player ped")
ENDIF
// see if there is a suitable vehicle to snapshot
IF Is_Vehicle_Available_To_Snapshot(mPlayerPed, mSnapshotVehicle, bDoDistanceCheck)
// store the snapshot info
Store_Vehicle_Snapshot_Only(mVehicleSnapshot, mSnapshotVehicle, bStorePosition)
// update the return index
mVehicle = mSnapshotVehicle
//B* 1774589: Disabling saving the heli causes player to fall to his death after loading
ELIF DOES_ENTITY_EXIST(mSnapshotVehicle)
IF NOT IS_ENTITY_DEAD(mSnapshotVehicle)
IF IS_VEHICLE_MODEL(mSnapshotVehicle,SKYLIFT) AND IS_PED_IN_VEHICLE(PLAYER_PED_ID(),mSnapshotVehicle)
//Store the heli anyway if in air
Store_Vehicle_Snapshot_Only(mVehicleSnapshot, mSnapshotVehicle, bStorePosition)
ENDIF
ENDIF
ENDIF
RETURN mVehicle // this will be null if vehicle not snapshotted
ENDFUNC
/// PURPOSE:
/// Stores the player and vehicle snapshots in the repeat play snapshot
/// (Passes the start snapshot into the vehicle command, though this data isn't used for save anywhere and repeat play)
/// (This command should only be used at the star of repeat play, or when save anywhere is used)
PROC Store_RepeatPlay_Snapshot()
#IF USE_CLF_DLC
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT, "Storing repeat play snapshot")
Store_Player_Snapshot(g_savedGlobalsClifford.sRepeatPlayData.mPlayerStruct, TRUE)
Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_savedGlobalsClifford.sRepeatPlayData.mVehicleStruct, g_startSnapshot, NULL, TRUE, TRUE, TRUE)
g_savedGlobalsClifford.sRepeatPlayData.eMission = g_eMissionSceneToCleanup
ENDIF
#ENDIF
#IF USE_NRM_DLC
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT, "Storing repeat play snapshot")
Store_Player_Snapshot(g_savedGlobalsnorman.sRepeatPlayData.mPlayerStruct, TRUE)
Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_savedGlobalsnorman.sRepeatPlayData.mVehicleStruct, g_startSnapshot, NULL, TRUE, TRUE, TRUE)
g_savedGlobalsnorman.sRepeatPlayData.eMission = g_eMissionSceneToCleanup
ENDIF
#ENDIF
#IF NOT USE_SP_DLC
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT, "Storing repeat play snapshot")
Store_Player_Snapshot(g_savedGlobals.sRepeatPlayData.mPlayerStruct, TRUE)
Store_Vehicle_Snapshot_For_Last_Player_Vehicle(g_savedGlobals.sRepeatPlayData.mVehicleStruct, g_startSnapshot, NULL, TRUE, TRUE, TRUE)
g_savedGlobals.sRepeatPlayData.eMission = g_eMissionSceneToCleanup
// if nearest valid RC mission is waiting for player to leavbe area we need to store it
// so when this save is loaded we can stop it from trying to immediately launch
g_savedGlobals.sRepeatPlayData.eRCMissionToBlock = PRIVATE_Get_Nearest_Valid_RC_Mission()
IF g_savedGlobals.sRepeatPlayData.eRCMissionToBlock <> NO_RC_MISSION
IF g_RandomChars[g_savedGlobals.sRepeatPlayData.eRCMissionToBlock].rcIsAwaitingTrigger = FALSE
AND g_RandomChars[g_savedGlobals.sRepeatPlayData.eRCMissionToBlock].rcLeaveAreaCheck = TRUE
CPRINTLN(DEBUG_REPEAT, "Saving near an RC mission that is waiting for player to leave area. Store details: ", GET_RC_MISSION_DISPLAY_STRING_FROM_ID(g_savedGlobals.sRepeatPlayData.eRCMissionToBlock))
ELSE
// nearest RC mission is not blocked, don't store
g_savedGlobals.sRepeatPlayData.eRCMissionToBlock = NO_RC_MISSION
ENDIF
ENDIF
ENDIF
#ENDIF
ENDPROC
/// PURPOSE:
/// Stores various information about the current player character, and some info on all player characters
/// This can then be restored later on
/// PARAMS:
/// paramSnapshot - the mission start snapshot or the checkpoint snapshot
/// bStoreVehicleInfo - Do we want to store info about the player's vehicle?
/// iStage - the number of the checkpoint stage
/// sStageName - the name of this checkpoint stage
PROC Store_Game_State_Snapshot(SNAPSHOT_STRUCT &paramSnapshot, STRING sScriptName, INT iStage, STRING sStageName, BOOL bStoreVehicleInfo = TRUE, PED_INDEX mPedForVehicleSnapshot = NULL)
INT iTempIndex
INT iCharIndex
paramSnapshot.eCharacter = GET_CURRENT_PLAYER_PED_ENUM() // store player character
paramSnapshot.tTime = GET_CURRENT_TIMEOFDAY() // store time of day
// store weather details
GET_CURR_WEATHER_STATE(paramSnapshot.iPreviousWeather, paramSnapshot.iNextWeather, paramSnapshot.fWeatherInterp)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
Store_Player_Snapshot(paramSnapshot.mPlayerStruct) // store player pos and heading
STORE_PLAYER_PED_ARMOUR(PLAYER_PED_ID()) // store weapons and armour in globals
STORE_PLAYER_PED_WEAPONS(PLAYER_PED_ID())
GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), paramSnapshot.mCurrentWeapon) // store current weapon
IF paramSnapshot.mCurrentWeapon = WEAPONTYPE_INVALID
OR paramSnapshot.mCurrentWeapon = WEAPONTYPE_OBJECT // cellphone
paramSnapshot.mCurrentWeapon = WEAPONTYPE_UNARMED // if weapon invalid, use unarmed instead
ENDIF
CPRINTLN(DEBUG_REPLAY, "Storing current weapon as: ", paramSnapshot.mCurrentWeapon, " With ammo: ", GET_AMMO_IN_PED_WEAPON(PLAYER_PED_ID(), paramSnapshot.mCurrentWeapon))
ENDIF
// store info for all playable characters
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
//Armor.
paramSnapshot.iArmour[iCharIndex] = g_savedGlobals.sPlayerData.sInfo.iArmour[iCharIndex]
//Ped variations.
IF iCharIndex = GET_CURRENT_PLAYER_PED_INT()
GET_PED_VARIATIONS(PLAYER_PED_ID(), paramSnapshot.mVariations[iCharIndex])
ELSE
REPEAT NUM_PED_COMPONENTS iTempIndex
paramSnapshot.mVariations[iCharIndex].iTextureVariation[iTempIndex] = g_sLastStoredPlayerPedClothes[iCharIndex].iTextureVariation[iTempIndex]
paramSnapshot.mVariations[iCharIndex].iDrawableVariation[iTempIndex] = g_sLastStoredPlayerPedClothes[iCharIndex].iDrawableVariation[iTempIndex]
ENDREPEAT
// hair / mask / beard stuff
paramSnapshot.mVariations[iCharIndex].eStoredHairstyle = g_sLastStoredPlayerPedClothes[iCharIndex].eStoredHairstyle
paramSnapshot.mVariations[iCharIndex].eItemThatForcedHairChange = g_sLastStoredPlayerPedClothes[iCharIndex].eItemThatForcedHairChange
paramSnapshot.mVariations[iCharIndex].eTypeThatForcedHairChange = g_sLastStoredPlayerPedClothes[iCharIndex].eTypeThatForcedHairChange
paramSnapshot.mVariations[iCharIndex].eStoredBeard = g_sLastStoredPlayerPedClothes[iCharIndex].eStoredBeard
paramSnapshot.mVariations[iCharIndex].eItemThatForcedBeardChange = g_sLastStoredPlayerPedClothes[iCharIndex].eItemThatForcedBeardChange
paramSnapshot.mVariations[iCharIndex].eTypeThatForcedBeardChange = g_sLastStoredPlayerPedClothes[iCharIndex].eTypeThatForcedBeardChange
REPEAT NUM_PLAYER_PED_PROPS iTempIndex
paramSnapshot.mVariations[iCharIndex].iPropIndex[iTempIndex] = g_sLastStoredPlayerPedClothes[iCharIndex].iPropIndex[iTempIndex]
paramSnapshot.mVariations[iCharIndex].iPropTexture[iTempIndex] = g_sLastStoredPlayerPedClothes[iCharIndex].iPropTexture[iTempIndex]
ENDREPEAT
ENDIF
//Weapons.
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
paramSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex] = g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sWeaponInfo[iTempIndex]
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
paramSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex] = g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex]
ENDREPEAT
//Purchased weapon stats.
SWITCH INT_TO_ENUM(enumCharacterList, iCharIndex)
CASE CHAR_MICHAEL
STAT_GET_INT(SP0_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_GET_INT(SP0_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_GET_INT(SP0_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_GET_INT(SP0_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_GET_INT(SP0_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_GET_INT(SP0_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_GET_INT(SP0_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_GET_INT(SP0_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
CASE CHAR_FRANKLIN
STAT_GET_INT(SP1_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_GET_INT(SP1_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_GET_INT(SP1_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_GET_INT(SP1_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_GET_INT(SP1_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_GET_INT(SP1_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_GET_INT(SP1_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_GET_INT(SP1_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
CASE CHAR_TREVOR
STAT_GET_INT(SP2_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_GET_INT(SP2_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_GET_INT(SP2_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_GET_INT(SP2_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_GET_INT(SP2_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_GET_INT(SP2_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_GET_INT(SP2_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_GET_INT(SP2_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
ENDSWITCH
// Bank accounts
paramSnapshot.iBankLogIndex[iCharIndex] = g_savedGlobals.sFinanceData.PLAYER_ACCOUNT_LOGS[iCharIndex].iLogIndexPoint
paramSnapshot.iCash[iCharIndex] = g_BankAccounts[iCharIndex].iBalance
// Default vehicle mods
paramSnapshot.mPlayerVehicle[0][iCharIndex] = g_savedGlobals.sPlayerData.sInfo.sPlayerVehicle[0][iCharIndex]
paramSnapshot.mPlayerVehicle[1][iCharIndex] = g_savedGlobals.sPlayerData.sInfo.sPlayerVehicle[1][iCharIndex]
// tattoos
FOR iTempIndex = 0 TO MAX_NUMBER_OF_TATTOO_BITSETS -1
paramSnapshot.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex] = g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex]
paramSnapshot.sTattoos[iCharIndex].iViewedTattoos[iTempIndex] = g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iViewedTattoos[iTempIndex]
paramSnapshot.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex] = g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex]
ENDFOR
// clothes
FOR iTempIndex = 0 TO PED_COMPONENT_USED_SLOT
paramSnapshot.sComponents[iCharIndex].iHeadBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHeadBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iBeardBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iBeardBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iHairBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHairBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset2[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset2[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset3[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset3[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset4[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset4[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset5[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset5[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset6[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset6[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset7[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset7[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset8[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset8[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTorsoBitset9[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset9[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iLegsBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iLegsBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iLegsBitset2[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset2[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iLegsBitset3[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset3[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iHandBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHandBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iFeetBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iFeetBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iFeetBitset2[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset2[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iFeetBitset3[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset3[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iFeetBitset4[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset4[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iTeethBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTeethBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iSpecialBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iSpecialBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iSpecialBitset2[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset2[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iDeclBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iDeclBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iDeclBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iDeclBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iJbibBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iJbibBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iJbibBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iJbibBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iOutfitBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iOutfitBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iOutfitBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iOutfitBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset0[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset0[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset1[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset1[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset2[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset2[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset3[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset3[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset4[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset4[iTempIndex]
paramSnapshot.sComponents[iCharIndex].iPropsBitset5[iTempIndex] = g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset5[iTempIndex]
ENDFOR
ENDREPEAT
// Special Ability
STAT_GET_INT(SP0_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[0])
STAT_GET_INT(SP1_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[1])
STAT_GET_INT(SP2_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[2])
CPRINTLN(DEBUG_REPLAY, "Special Ability stored as M= ", paramSnapshot.iSpecialAbility[0], " F= ", paramSnapshot.iSpecialAbility[1], " T= ",paramSnapshot.iSpecialAbility[2])
// Vehicle
paramSnapshot.eVehicleOwner = NO_CHARACTER
IF bStoreVehicleInfo = TRUE
Store_Vehicle_Snapshot_For_Last_Player_Vehicle(paramSnapshot.mVehicleStruct, paramSnapshot, mPedForVehicleSnapshot)
ENDIF
// Battle buddy
TAKE_BATTLEBUDDY_SNAPSHOT(paramSnapshot.mBattleBuddyStruct)
// --------------------------------------print debug info-------------------------------------------------
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tTimeOfDay = TIMEOFDAY_TO_TEXT_LABEL(paramSnapshot.tTime)
CPRINTLN(DEBUG_REPLAY, "Player Char: ",GET_CHARSHEET_DISPLAY_STRING_FROM_CHARSHEET(paramSnapshot.eCharacter))
CPRINTLN(DEBUG_REPLAY, "Position: ", paramSnapshot.mPlayerStruct.vPos)
CPRINTLN(DEBUG_REPLAY, "", tTimeOfDay)
STRING sWeather = GET_WEATHER_STRING_FROM_HASH(paramSnapshot.iPreviousWeather)
IF NOT IS_STRING_NULL_OR_EMPTY(sWeather)
CPRINTLN(DEBUG_REPLAY,"Storing previous weather as: ", sWeather)
ENDIF
sWeather = GET_WEATHER_STRING_FROM_HASH(paramSnapshot.iNextWeather)
IF NOT IS_STRING_NULL_OR_EMPTY(sWeather)
CPRINTLN(DEBUG_REPLAY,"Storing next weather as: ", sWeather)
ENDIF
CPRINTLN(DEBUG_REPLAY,"Storing weather interp as: ", paramSnapshot.fWeatherInterp)
/* commented out- add back in if debugging ammo / armour /bank accounts
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
STRING strCharName = GET_CHARSHEET_DISPLAY_STRING_FROM_CHARSHEET(INT_TO_ENUM(enumCharacterList, iCharIndex))
INT iCharAmmo = 0
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
iCharAmmo += paramSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount
ENDREPEAT
CPRINTLN(DEBUG_REPLAY, " -", strCharName, " Armor: ", paramSnapshot.iArmour[iCharIndex]
ENDREPEAT
// bank info
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
CPRINTLN(DEBUG_REPLAY, "Character ", iCharIndex, " Bank log: ", paramSnapshot.iBankLogIndex[iCharIndex], " Cash: ", paramSnapshot.iCash[iCharIndex])
ENDREPEAT
*/
#ENDIF
CPRINTLN(DEBUG_REPLAY, "-----------------------------------------------------------------")
CPRINTLN(DEBUG_REPLAY, "")
// ---------metrics tracking--------------------------------
//Update start tracking a new metric zone as we step to a new mission stage.
#IF IS_DEBUG_BUILD
StartNewMetricsStage(iStage, sScriptName, sStageName)
#ENDIF
#IF IS_FINAL_BUILD
//Keeps final build compiling.
sStageName = sStageName
iStage = iStage
#ENDIF
ENDPROC
/// PURPOSE:
/// Stores a snapshot of the current game state, and saves it as the start snapshot
/// PARAMS:
/// paramScriptName - which script is saving the snapshot
/// bStoreVehicleInfo - do we want to store info about the player's vehicle?
PROC Store_Game_State_Snapshot_For_Start(STRING paramScriptName, BOOL bStoreVehicleInfo = TRUE, PED_INDEX mPedForVehicleSnapshot = NULL)
// don't do anything if we're on a replay
IF g_replay.replayStageID <> RS_ACTIVE
AND g_replay.replayStageID <> RS_ACTIVATE
CPRINTLN(DEBUG_REPLAY, "")
CPRINTLN(DEBUG_REPLAY, "-------------- Gamestate Snapshot - Start ----------------")
//---------------- store start snapshot------------------------------------
g_snapshotScriptName = paramScriptName
Store_Game_State_Snapshot(g_startSnapshot, paramScriptName, 0, "Start", bStoreVehicleInfo, mPedForVehicleSnapshot)
// --------------------Copy this start snapshot to the stage snapshot-----------------------
CopyStartSnapshotToStageSnapshot()
// reset shitskip to end bool, as shitskipping from start won't pass the mission
g_bShitskipToEnd = FALSE
ELSE
CPRINTLN(DEBUG_REPLAY, "Not storing start snapshot as we're on a replay")
ENDIF
ENDPROC
/// PURPOSE:
/// Stores a snapshot of the current game state, and saves it as the checkpoint snapshot
PROC Store_Game_State_Snapshot_For_Stage(INT iStage, STRING sStageName, PED_INDEX mPedForVehicleSnapshot = NULL, BOOL bStoreCheckpointVehicle = TRUE)
CPRINTLN(DEBUG_REPLAY, "")
CPRINTLN(DEBUG_REPLAY, "-------------- Gamestate Snapshot - Stage ----------------")
// --------snapshot-----------------------------------------
Store_Game_State_Snapshot(g_stageSnapshot, GET_THIS_SCRIPT_NAME(), iStage, sStageName, bStoreCheckpointVehicle, mPedForVehicleSnapshot)
ENDPROC
// ===========================================================================================================
// SNAPSHOT RESTORING FUNCTIONS
// ===========================================================================================================
/// PURPOSE:
/// Uses the specified game state snapshot to restore player's clothes to the state they were in when the snapshot was taken
/// PARAMS:
/// paramSnapshot - the mission start or checkpoint snapshot
PROC Restore_Game_State_Snapshot_Clothes(SNAPSHOT_STRUCT &paramSnapshot)
INT iCharIndex
INT iTempIndex
CPRINTLN(DEBUG_REPLAY, "Restoring player outfit.")
// Restoring player character variations to snapshot values.
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
REPEAT NUM_PED_COMPONENTS iTempIndex
g_sLastStoredPlayerPedClothes[iCharIndex].iTextureVariation[iTempIndex] = paramSnapshot.mVariations[iCharIndex].iTextureVariation[iTempIndex]
g_sLastStoredPlayerPedClothes[iCharIndex].iDrawableVariation[iTempIndex] = paramSnapshot.mVariations[iCharIndex].iDrawableVariation[iTempIndex]
ENDREPEAT
REPEAT NUM_PLAYER_PED_PROPS iTempIndex
g_sLastStoredPlayerPedClothes[iCharIndex].iPropIndex[iTempIndex] = paramSnapshot.mVariations[iCharIndex].iPropIndex[iTempIndex]
g_sLastStoredPlayerPedClothes[iCharIndex].iPropTexture[iTempIndex] = paramSnapshot.mVariations[iCharIndex].iPropTexture[iTempIndex]
ENDREPEAT
// hair / mask / Beard stuff
g_sLastStoredPlayerPedClothes[iCharIndex].eStoredHairstyle = paramSnapshot.mVariations[iCharIndex].eStoredHairstyle
g_sLastStoredPlayerPedClothes[iCharIndex].eItemThatForcedHairChange = paramSnapshot.mVariations[iCharIndex].eItemThatForcedHairChange
g_sLastStoredPlayerPedClothes[iCharIndex].eTypeThatForcedHairChange = paramSnapshot.mVariations[iCharIndex].eTypeThatForcedHairChange
g_sLastStoredPlayerPedClothes[iCharIndex].eStoredBeard = paramSnapshot.mVariations[iCharIndex].eStoredBeard
g_sLastStoredPlayerPedClothes[iCharIndex].eItemThatForcedBeardChange = paramSnapshot.mVariations[iCharIndex].eItemThatForcedBeardChange
g_sLastStoredPlayerPedClothes[iCharIndex].eTypeThatForcedBeardChange = paramSnapshot.mVariations[iCharIndex].eTypeThatForcedBeardChange
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Uses the specified game state snapshot to restore player's weapon purchased stats to the state they were in when the snapshot was taken
/// PARAMS:
/// paramSnapshot - the mission start or checkpoint snapshot
/// NOTES:
/// This restores the purchased weapon states in the snap shot
PROC Restore_Game_State_Snapshot_Purchased_Weapons(SNAPSHOT_STRUCT &paramSnapshot)
CPRINTLN(DEBUG_REPLAY, "Restoring player purchased weapons stats.")
// Restoring player character weapon loadouts to replay snapshot values.
INT iCharIndex
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
SWITCH INT_TO_ENUM(enumCharacterList, iCharIndex)
CASE CHAR_MICHAEL
STAT_SET_INT(SP0_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_SET_INT(SP0_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_SET_INT(SP0_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_SET_INT(SP0_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_SET_INT(SP0_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_SET_INT(SP0_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_SET_INT(SP0_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_SET_INT(SP0_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
CASE CHAR_FRANKLIN
STAT_SET_INT(SP1_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_SET_INT(SP1_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_SET_INT(SP1_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_SET_INT(SP1_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_SET_INT(SP1_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_SET_INT(SP1_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_SET_INT(SP1_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_SET_INT(SP1_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
CASE CHAR_TREVOR
STAT_SET_INT(SP2_WEAP_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0])
STAT_SET_INT(SP2_WEAP_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
STAT_SET_INT(SP2_WEAP_ADDON_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
STAT_SET_INT(SP2_WEAP_ADDON_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[1])
STAT_SET_INT(SP2_WEAP_ADDON_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2])
STAT_SET_INT(SP2_WEAP_ADDON_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
STAT_SET_INT(SP2_WEAP_ADDON_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[4])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_0, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_1, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_2, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_3, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_4, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[4])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_5, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[5])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_6, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[6])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_7, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[7])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_8, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[8])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_9, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[9])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_10, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[10])
STAT_SET_INT(SP2_WEAP_TINT_PURCH_11, paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[11])
BREAK
ENDSWITCH
CDEBUG3LN(DEBUG_REPLAY, "Character ", iCharIndex, ":")
CDEBUG3LN(DEBUG_REPLAY, "WeaponBitset[0]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[0], " WeaponBitset[1]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponBitset[1])
CDEBUG3LN(DEBUG_REPLAY, "AddonBitset[0]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0], " AddonBitset[1]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[0])
CDEBUG3LN(DEBUG_REPLAY, "AddonBitset[2]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[2], " AddonBitset[3]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponAddonBitset[3])
CDEBUG3LN(DEBUG_REPLAY, "TintBitset[0]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[0], " TintBitset[1]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[1])
CDEBUG3LN(DEBUG_REPLAY, "TintBitset[2]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[2], " TintBitset[3]:", paramSnapshot.mPurchasedWeapons[iCharIndex].iWeaponTintBitset[3])
ENDREPEAT
ENDPROC
/// PURPOSE:
/// Uses the specified game state snapshot to restore player's weapons to the state they were in when the snapshot was taken
/// PARAMS:
/// paramSnapshot - the mission start or checkpoint snapshot
/// NOTES:
/// This restores the weapons in the snap shot
/// Be aware it writes to the same place where STORE_PLAYER_PED_WEAPONS() writes to.
PROC Restore_Game_State_Snapshot_Weapons(SNAPSHOT_STRUCT &paramSnapshot)
INT iCharIndex
INT iTempIndex
CPRINTLN(DEBUG_REPLAY, "-------------------------.")
CPRINTLN(DEBUG_REPLAY, "Restoring player weapons.")
// Restoring player character weapon loadouts to replay snapshot values.
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
g_savedGlobals.sPlayerData.sInfo.iArmour[iCharIndex] = paramSnapshot.iArmour[iCharIndex]
REPEAT NUM_PLAYER_PED_WEAPON_SLOTS iTempIndex
g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sWeaponInfo[iTempIndex] = paramSnapshot.mWeapons[iCharIndex].sWeaponInfo[iTempIndex]
#IF IS_DEBUG_BUILD
CDEBUG3LN(DEBUG_REPLAY, "Character ", iCharIndex, ":")
CDEBUG3LN(DEBUG_REPLAY, "WeaponSlot: ", GET_DEBUG_STRING_FROM_WEAPONSLOT(GET_PLAYER_PED_WEAPON_SLOT_FROM_INT(iTempIndex)), " Weapon: ", GET_WEAPON_NAME(g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sWeaponInfo[iTempIndex].eWeaponType), " has ammo: ", g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sWeaponInfo[iTempIndex].iAmmoCount)
#ENDIF
ENDREPEAT
REPEAT NUMBER_OF_DLC_WEAPONS iTempIndex
g_savedGlobals.sPlayerData.sInfo.sWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex] = paramSnapshot.mWeapons[iCharIndex].sDLCWeaponInfo[iTempIndex]
ENDREPEAT
ENDREPEAT
// Restore purchased stat values (including weapon mods and addons).
Restore_Game_State_Snapshot_Purchased_Weapons(paramSnapshot)
CPRINTLN(DEBUG_REPLAY, "-------------------------.")
ENDPROC
/// PURPOSE:
/// Changes the player to the character specified
/// PARAMS:
/// eCharacter - the character to change the player to
/// RETURNS:
/// TRUE if character was valid (michael, franklin or Trevor) FALSE otherwise
FUNC BOOL Replay_Change_Player_Ped(enumCharacterList eCharacter)
SELECTOR_SLOTS_ENUM replaySelectorPed
SWITCH(eCharacter)
CASE CHAR_MICHAEL
CPRINTLN(DEBUG_REPLAY, "Setting character to Michael.")
replaySelectorPed = SELECTOR_PED_MICHAEL
BREAK
CASE CHAR_FRANKLIN
CPRINTLN(DEBUG_REPLAY, "Setting character to Franklin.")
replaySelectorPed = SELECTOR_PED_FRANKLIN
BREAK
CASE CHAR_TREVOR
CPRINTLN(DEBUG_REPLAY, "Setting character to Trevor.")
replaySelectorPed = SELECTOR_PED_TREVOR
BREAK
DEFAULT
SCRIPT_ASSERT("Change_Player_Ped: Chosen character was invalid.")
RETURN FALSE
BREAK
ENDSWITCH
VECTOR vLastKnownCoords
FLOAT fLastKnownHead
INT iLastKnownRoomKey
#IF USE_CLF_DLC
enumCharacterList eCurrentCharacter = GET_CURRENT_PLAYER_PED_ENUMCLF()
IF eCurrentCharacter != NO_CHARACTER
vLastKnownCoords = g_savedGlobalsClifford.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter]
fLastKnownHead = g_savedGlobalsClifford.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter]
iLastKnownRoomKey = g_savedGlobalsClifford.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter]
ENDIF
#ENDIF
#IF USE_NRM_DLC
enumCharacterList eCurrentCharacter = GET_CURRENT_PLAYER_PED_ENUMNRM()
IF eCurrentCharacter != NO_CHARACTER
vLastKnownCoords = g_savedGlobalsnorman.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter]
fLastKnownHead = g_savedGlobalsnorman.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter]
iLastKnownRoomKey = g_savedGlobalsnorman.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter]
ENDIF
#ENDIF
#IF NOT USE_SP_DLC
enumCharacterList eCurrentCharacter = GET_CURRENT_PLAYER_PED_ENUM()
IF eCurrentCharacter != NO_CHARACTER
vLastKnownCoords = g_savedGlobals.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter]
fLastKnownHead = g_savedGlobals.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter]
iLastKnownRoomKey = g_savedGlobals.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter]
ENDIF
#ENDIF
WHILE NOT SET_CURRENT_SELECTOR_PED(replaySelectorPed)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPLAY, "Restore last known coords for ", GET_PLAYER_PED_STRING(eCurrentCharacter), " to ", vLastKnownCoords, ".")
#IF USE_CLF_DLC
IF eCurrentCharacter != NO_CHARACTER
g_savedGlobalsClifford.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter] = vLastKnownCoords
g_savedGlobalsClifford.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter] = fLastKnownHead
g_savedGlobalsClifford.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter] = iLastKnownRoomKey
ENDIF
#ENDIF
#IF USE_NRM_DLC
IF eCurrentCharacter != NO_CHARACTER
g_savedGlobalsnorman.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter] = vLastKnownCoords
g_savedGlobalsnorman.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter] = fLastKnownHead
g_savedGlobalsnorman.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter] = iLastKnownRoomKey
ENDIF
#ENDIF
#IF NOT USE_SP_DLC
IF eCurrentCharacter != NO_CHARACTER
g_savedGlobals.sPlayerData.sInfo.vLastKnownCoords[eCurrentCharacter] = vLastKnownCoords
g_savedGlobals.sPlayerData.sInfo.fLastKnownHead[eCurrentCharacter] = fLastKnownHead
g_savedGlobals.sPlayerData.sInfo.iLastKnownRoomKey[eCurrentCharacter] = iLastKnownRoomKey
ENDIF
#ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Uses the specified game state snapshot to restore variables to the state they were in when the snapshot was taken
/// PARAMS:
/// paramSnapshot - the mission start or checkpoint snapshot
PROC Restore_Game_State_Snapshot(SNAPSHOT_STRUCT &paramSnapshot, BOOL paramSkipCharacterSwap = FALSE)
TIMEOFDAY mTextTime // used to remove text messages
// Setting clock time back to replay snapshot time.
SET_CLOCK_TIME( GET_TIMEOFDAY_HOUR(paramSnapshot.tTime),
GET_TIMEOFDAY_MINUTE(paramSnapshot.tTime),
GET_TIMEOFDAY_SECOND(paramSnapshot.tTime))
SET_CLOCK_DATE( GET_TIMEOFDAY_DAY(paramSnapshot.tTime),
GET_TIMEOFDAY_MONTH(paramSnapshot.tTime),
GET_TIMEOFDAY_YEAR(paramSnapshot.tTime))
SET_CURR_WEATHER_STATE(paramSnapshot.iPreviousWeather, paramSnapshot.iNextWeather, paramSnapshot.fWeatherInterp)
#IF IS_DEBUG_BUILD
STRING sWeather = GET_WEATHER_STRING_FROM_HASH(paramSnapshot.iPreviousWeather)
IF NOT IS_STRING_NULL_OR_EMPTY(sWeather)
CPRINTLN(DEBUG_REPLAY,"Restoring previous weather as: ", sWeather)
ENDIF
sWeather = GET_WEATHER_STRING_FROM_HASH(paramSnapshot.iNextWeather)
IF NOT IS_STRING_NULL_OR_EMPTY(sWeather)
CPRINTLN(DEBUG_REPLAY,"Restoring next weather as: ", sWeather)
ENDIF
CPRINTLN(DEBUG_REPLAY,"Restoring weather interp as: ", paramSnapshot.fWeatherInterp)
#ENDIF
IF NOT paramSkipCharacterSwap
// Switching player character to char used to reach last checkpoint.
IF NOT Replay_Change_Player_Ped(paramSnapshot.eCharacter)
EXIT // invalid character, exit
ENDIF
// Restoring player character variations to replay snapshot values.
Restore_Game_State_Snapshot_Clothes(paramSnapshot)
// Restoring player character weapon loadouts to replay snapshot values.
Restore_Game_State_Snapshot_Weapons(paramSnapshot)
// Special ability
STAT_SET_INT(SP0_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[0])
STAT_SET_INT(SP1_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[1])
STAT_SET_INT(SP2_SPECIAL_ABILITY, paramSnapshot.iSpecialAbility[2])
IF IS_PLAYER_PLAYING(PLAYER_ID())
UPDATE_SPECIAL_ABILITY_FROM_STAT(PLAYER_ID())
ENDIF
CPRINTLN(DEBUG_REPLAY, "Special Ability restored as M= ", paramSnapshot.iSpecialAbility[0], " F= ", paramSnapshot.iSpecialAbility[1], " T= ",paramSnapshot.iSpecialAbility[2])
// Restore text messages (remove any the player received after the snapshot timestamp)
INT iText = 0
FOR iText = 0 TO MAX_TEXT_MESSAGES -1
IF NOT IS_STRING_NULL_OR_EMPTY(g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgLabel)
AND (iText <= SP_TEXT_PORTION_END OR iText >= MP_TEXT_PORTION_START) //B* 2204796: Ignore buffered text messages
CDEBUG1LN( DEBUG_REPLAY, " - ###Text[", iText, "] - TxtMsgMonth(-1) = ", ( g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgMonth - 1 ), " - TxtMsgDay = ", g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgDay )
IF g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgDay = 31
//which iText are we using
CPRINTLN(DEBUG_REPLAY, "### iText = ",iText)
//text info
CPRINTLN(DEBUG_REPLAY, "### TxtMsgLabel = ",g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgLabel)
ENDIF
SET_TIMEOFDAY(mTextTime, g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgSecs,
g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgMins,
g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgHours,
g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgDay,
INT_TO_ENUM(MONTH_OF_YEAR, g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgMonth-1),
g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgTimeSent.TxtMsgYear)
IF IS_TIMEOFDAY_AFTER_TIMEOFDAY(mTextTime, paramSnapshot.tTime)
// text message was sent after the time the snapshot was taken...delete it!
CPRINTLN(DEBUG_REPLAY, "Unlocking and deleting text message ", g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgLabel)
UNLOCK_TEXT_MESSAGE_BY_LABEL(g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgLabel, TRUE)
DELETE_TEXT_MESSAGE_BY_LABEL_FROM_ALL_PLAYER_CHARACTERS(g_SavedGlobals.sTextMessageSavedData.g_TextMessage[iText].TxtMsgLabel)
#IF IS_DEBUG_BUILD
TEXT_LABEL_63 tTOD = TIMEOFDAY_TO_TEXT_LABEL(paramSnapshot.tTime)
CPRINTLN(DEBUG_REPLAY, "Snapshot TOD = ", tTOD)
TEXT_LABEL_63 tTDOText = TIMEOFDAY_TO_TEXT_LABEL(mTextTime)
CPRINTLN(DEBUG_REPLAY, "Text TOD = ", tTDOText)
#ENDIF
ENDIF
ENDIF
ENDFOR
// Don't show cash being updated
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_CASH)
// updates that need to be done for all player characters
INT iCharIndex
INT iTransactionsAltered
INT iTempIndex
REPEAT NUM_OF_PLAYABLE_PEDS iCharIndex
// restore state of default player vehicles
g_savedGlobals.sPlayerData.sInfo.sPlayerVehicle[0][iCharIndex] = paramSnapshot.mPlayerVehicle[0][iCharIndex]
g_savedGlobals.sPlayerData.sInfo.sPlayerVehicle[1][iCharIndex] = paramSnapshot.mPlayerVehicle[1][iCharIndex]
// restoring bank accounts to stored values
CPRINTLN(DEBUG_REPLAY, "Restoring bank account for character: ", iCharIndex)
//CPRINTLN(DEBUG_REPLAY, "Current log is: ", g_BankAccounts[iCharIndex].iLogIndexPoint)
//CPRINTLN(DEBUG_REPLAY, "Target log is: ", paramSnapshot.iBankLogIndex[iCharIndex])
IF g_savedGlobals.sFinanceData.PLAYER_ACCOUNT_LOGS[iCharIndex].iLogIndexPoint <> paramSnapshot.iBankLogIndex[iCharIndex]
// need to undo transactions
WHILE g_savedGlobals.sFinanceData.PLAYER_ACCOUNT_LOGS[iCharIndex].iLogIndexPoint <> paramSnapshot.iBankLogIndex[iCharIndex]
AND iTransactionsAltered < MAX_BANK_ACCOUNT_LOG_ENTRIES // to stop us looping through repeatedly
UNDO_LAST_BANK_ACCOUNT_ACTION(iCharIndex)
iTransactionsAltered++
ENDWHILE
ELSE
//CPRINTLN(DEBUG_REPLAY, "No transactions to undo for this character", iCharIndex)
ENDIF
//CPRINTLN(DEBUG_REPLAY, "After undo logs: Current cash is now: ", g_BankAccounts[iCharIndex].iBalance)
INT iDiff = g_BankAccounts[iCharIndex].iBalance - paramSnapshot.iCash[iCharIndex]
IF iDiff <> 0
//CPRINTLN(DEBUG_REPLAY, "Final update to bank account ")
g_BankAccounts[INT_TO_ENUM(enumBankAccountName, iCharIndex)].iBalance = paramSnapshot.iCash[iCharIndex]//new total
BANK_FORCE_UPDATE_LINKED_ACCOUNT_STATS(INT_TO_ENUM(enumBankAccountName, iCharIndex))
ELSE
//CPRINTLN(DEBUG_REPLAY, "Account is correct")
ENDIF
//CPRINTLN(DEBUG_REPLAY, "Final update: Current cash is now: ", g_BankAccounts[iCharIndex].iBalance)
//CPRINTLN(DEBUG_REPLAY, "----------------------------------------------------------")
// tattoos
FOR iTempIndex = 0 TO MAX_NUMBER_OF_TATTOO_BITSETS -1
g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex] = paramSnapshot.sTattoos[iCharIndex].iUnlockedTattoos[iTempIndex]
g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iViewedTattoos[iTempIndex] = paramSnapshot.sTattoos[iCharIndex].iViewedTattoos[iTempIndex]
g_savedGlobals.sPlayerData.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex] = paramSnapshot.sTattoos[iCharIndex].iCurrentTattoos[iTempIndex]
ENDFOR
// clothes
FOR iTempIndex = 0 TO PED_COMPONENT_USED_SLOT
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHeadBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iHeadBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iBeardBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iBeardBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHairBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iHairBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset2[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset2[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset3[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset3[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset4[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset4[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset5[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset5[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset6[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset6[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset7[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset7[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset8[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset8[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTorsoBitset9[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTorsoBitset9[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iLegsBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iLegsBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset2[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iLegsBitset2[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iLegsBitset3[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iLegsBitset3[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iHandBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iHandBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iFeetBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iFeetBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset2[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iFeetBitset2[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset3[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iFeetBitset3[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iFeetBitset4[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iFeetBitset4[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iTeethBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iTeethBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iSpecialBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iSpecialBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecialBitset2[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iSpecialBitset2[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iSpecial2Bitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iDeclBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iDeclBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iDeclBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iDeclBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iJbibBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iJbibBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iJbibBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iJbibBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iOutfitBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iOutfitBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iOutfitBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iOutfitBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropGroupBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset0[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset0[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset1[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset1[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset2[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset2[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset3[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset3[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset4[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset4[iTempIndex]
g_savedGlobals.sPlayerData.sComponents[iCharIndex].iPropsBitset5[iTempIndex] = paramSnapshot.sComponents[iCharIndex].iPropsBitset5[iTempIndex]
ENDFOR
ENDREPEAT
//Restore current player character state.
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_PLAYER_PED_PLAYABLE(GET_PLAYER_PED_ENUM(PLAYER_PED_ID()))
SET_PED_VARIATIONS(PLAYER_PED_ID(), g_sLastStoredPlayerPedClothes[GET_PLAYER_PED_ENUM(PLAYER_PED_ID())])
ENDIF
RESTORE_PLAYER_PED_ARMOUR(PLAYER_PED_ID())
RESTORE_PLAYER_PED_WEAPONS(PLAYER_PED_ID())
CLEAR_PED_WETNESS(PLAYER_PED_ID())
CLEAR_PED_BLOOD_DAMAGE(PLAYER_PED_ID())
RESET_PED_VISIBLE_DAMAGE(PLAYER_PED_ID())
IF HAS_PED_GOT_WEAPON(PLAYER_PED_ID(), paramSnapshot.mCurrentWeapon)
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), paramSnapshot.mCurrentWeapon, TRUE)
ENDIF
SET_ENTITY_HEALTH(PLAYER_PED_ID(),GET_PED_MAX_HEALTH(PLAYER_PED_ID())) //Always set the player to full health.
IF IS_PLAYER_PLAYING(PLAYER_ID())
RESET_PLAYER_STAMINA(PLAYER_ID())
CPRINTLN(DEBUG_REPLAY, "Player stamina restored!")
ENDIF
RESTORE_PLAYER_PED_TATTOOS(PLAYER_PED_ID()) // clear decorations (scars) + restore tattoos
CPRINTLN(DEBUG_REPLAY, "Player character's state restored!")
ENDIF
ELSE
CPRINTLN(DEBUG_REPLAY, "Skipped restoring character state.")
ENDIF
//Allow all savehouse vehicles to respawn immediately.
CPRINTLN(DEBUG_REPLAY, "Resetting safehouse vehicle gens.")
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_MICHAEL_SAVEHOUSE)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_MICHAEL_SAVEHOUSE_COUNTRY)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_FRANKLIN_SAVEHOUSE_CAR)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_FRANKLIN_SAVEHOUSE_BIKE)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_FRANKLIN_SAVEHOUSE_HILLS_CAR)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_FRANKLIN_SAVEHOUSE_HILLS_BIKE)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_TREVOR_SAVEHOUSE_COUNTRY)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_TREVOR_SAVEHOUSE_CITY)
CLEAR_MUST_LEAVE_AREA_VEHICLE_GEN_FLAG(VEHGEN_TREVOR_SAVEHOUSE_STRIPCLUB)
//Reset the players last known ped info
ResetLastKnownPedInfo(g_savedGlobals.sPlayerData.sInfo, SP_MISSION_NONE)
ENDPROC
FUNC BOOL START_UP_SHAPETEST(VECTOR vStartPos, FLOAT fStartHeading, MODEL_NAMES model = DUMMY_MODEL_FOR_SCRIPT, bool bExcludePlayer = TRUE, BOOL bIsBigModel = FALSE)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF model = DUMMY_MODEL_FOR_SCRIPT
model = GET_ENTITY_MODEL(PLAYER_PED_ID())
ENDIF
ENTITY_INDEX excludeIndex = PLAYER_PED_ID()
INT includeFlags = LOS_FLAGS_BOUNDING_BOX
IF NOT bExcludePlayer
excludeIndex = NULL
includeFlags = LOS_FLAGS_BOUNDING_BOX
ENDIF
INT iReturnValue = -1
VECTOR vTempMin, vTempMax, vHitPos, vHitNorm
SHAPETEST_INDEX shapeTestIndex
ENTITY_INDEX entityHit
GET_MODEL_DIMENSIONS(model, vTempMin, vTempMax)
IF bIsBigModel //Increase the box size by 25% for big models
vTempMin = vTempMin * 1.25
vTempMax = vTempMax * 1.25
ENDIF
vtempMax -= vTempMin
shapeTestIndex = START_SHAPE_TEST_BOX(vStartPos - <<0,0,vTempMin.z>>,vTempMax,<<0.0,0.0,fStartHeading>>,DEFAULT, includeFlags, excludeIndex)
CDEBUG3LN(debug_replay,"doing shapetest at ",vStartPos, " size ",vTempMax)
SHAPETEST_STATUS stResult = GET_SHAPE_TEST_RESULT(shapeTestIndex,iReturnValue,vHitPos,vHitNorm,entityHit)
WHILE stResult = SHAPETEST_STATUS_RESULTS_NOTREADY
WAIT(0)
stResult = GET_SHAPE_TEST_RESULT(shapeTestIndex,iReturnValue,vHitPos,vHitNorm,entityHit)
ENDWHILE
IF stResult = SHAPETEST_STATUS_RESULTS_READY
CDEBUG3LN(debug_replay,"Shapetest result: hitPos:",vHitPos," hitNorm:",vHitNorm, " entity:",NATIVE_TO_INT(entityHit))
IF iReturnValue != 0
RETURN FALSE
ENDIF
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL IS_EXCLUDED_ROAD_NODE(VECTOR pos, BOOL bIsBigModel = FALSE, INT iNumOfLanes = 0)
IF bIsBigModel
//Only use roads with at least 2 lanes
IF iNumOfLanes < 2
RETURN TRUE
ENDIF
//Wide area checks - Pier
IF VDIST2(pos,<<-1601.68, -1013.90, 12.02>>) < (53 * 53)
OR VDIST2(pos,<<-1645.58, -1065.69, 17.53>>) < (53 * 53)
OR VDIST2(pos,<<-1688.35, -1118.13, 12.15>>) < (53 * 53)
OR VDIST2(pos,<<-1751.62, -1133.60, 12.09>>) < (53 * 53)
//Around <<-150.30, 969.48, 234.61>>
OR VDIST2(pos,<<-150.30, 969.48, 234.61>>) < (400) //20 radius
OR VDIST2(pos,<<-160.50, 1006.18, 233.11>>) < (400)
OR VDIST2(pos,<<-215.49, 887.98, 207.17>>) < (400)
OR VDIST2(pos,<<-186.37, 830.33, 202.51>>) < (400)
OR VDIST2(pos,<<-114.10, 784.55, 201.24>>) < (400)
OR VDIST2(pos,<<-140.14, 910.92, 237.18>>) < (400)
RETURN TRUE
ENDIF
ENDIF
IF ARE_VECTORS_ALMOST_EQUAL(pos,<< 24.2857, -663.82, 31.6286 >>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<< -73.2402, -682.619, 32.6686 >>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<20.6539, -673.9974, 31.3274>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<17.0277, -679.2629, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<13.0123, -681.9813, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<9.3300, -683.0215, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-3.0009, -684.3066, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-15.2584, -685.2630, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-27.7868, -686.3926, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-40.3021, -687.2850, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-44.0514, -687.7671, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-49.7120, -688.2113, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<<-57.6906, -686.7383, 31.3381>>,1)
OR ARE_VECTORS_ALMOST_EQUAL(pos,<< 1643.25, 20.25, 169.531 >>,1)
RETURN TRUE
ENDIF
//Road nodes under the ground Z
FLOAT fGround
GET_GROUND_Z_FOR_3D_COORD(pos+<<0,0,10>>,fGround)
IF pos.z < fGround - 0.1
CERRORLN(debug_director, "Road node Z(",pos.z,") is UNDER the ground Z(",fGround,"), this will cause problems!")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Returns a position around a given point going through a spiral pattern
/// PARAMS:
/// vPos - Centre of search area
/// vReturn - Returned vector, if anything found
/// iIndex - point index, should be defined just outside the loop
/// ipointsPerArm - #point per arm (i.e. 1st ring has points 8 points, 0-7, 2nd has 8-15, and so on)
/// fRadius - Maximum search radius, returns false if current point falls outside
/// fRingDist - distance between concentric rings
/// RETURNS:
///
FUNC BOOL GET_POSITION_IN_SPIRAL_AROUND_POINT(VECTOR vPos, VECTOR &vReturn, INT &iIndex, INT ipointsPerArm = 8, FLOAT fRadius = 100.0, FLOAT fRingDist = 0.5)
//Get the current point position
INT iDist = iIndex / iPointsPerArm
INT iPoint = iIndex % iPointsPerArm
//Check if it falls outside the max radius
FLOAT fDist = iDist * fRingDist
IF fDist > fRadius
// CPRINTLN(debug_dan,"Current point ",iIndex," outside of max search range")
RETURN FALSE
ENDIF
//check if its index is > max number of points
IF iIndex > iPointsPerArm * fRadius / fRingDist
// CPRINTLN(debug_dan,"Current point ",iIndex," higher than the max for the given range: ",iPointsPerArm * fRadius / fRingDist)
RETURN FALSE
ENDIF
//Calculate point angle
FLOAT theta = 360.0 / iPointsPerArm * iPoint
// CPRINTLN(debug_dan,iIndex,": Theta is ",theta)
//Calculate point deltas
FLOAT fdx = COS(theta) * fRingDist * (iDist +1)
FLOAT fdy = SIN(theta) * fRingDist * (iDist +1)
vReturn = vPos + <<fdx,fdy,0>>
iIndex ++
RETURN TRUE
ENDFUNC
FUNC BOOL START_UP_ROAD_NODE_TEST(VECTOR &vStartPos, FLOAT &fStartHeading, MODEL_NAMES model = DUMMY_MODEL_FOR_SCRIPT,
BOOL bExcludeInteriorNodes = FALSE, bool bExcludePlayer = TRUE, FLOAT fRodeNodeDistModifier = 1.0)
INT iNodeIterator = 1
INT iNumOfLanes
INT iTemp = 0
FLOAT fRotTemp
VECTOR vPosTemp, vPosTemp2
BOOL b2ndCheckPassed
BOOL bIsBigModel
FLOAT fRoadeNodeLoadDist = TO_FLOAT( DEFAULT_ROAD_NODE_LOAD_DIST ) * fRodeNodeDistModifier
IF model = DUMMY_MODEL_FOR_SCRIPT
model = GET_ENTITY_MODEL(PLAYER_PED_ID())
ENDIF
//Get model's dimensions, check if large vehicle
VECTOR vModelMin, vModelMax
GET_MODEL_DIMENSIONS(model, vModelMin, vModelMax)
vModelMax = vModelMax - vModelMin //Use vModelMax as total model size
bIsBigModel = IS_THIS_MODEL_A_BOAT(model) OR IS_THIS_MODEL_A_HELI(model) OR IS_THIS_MODEL_A_PLANE(model) OR IS_THIS_MODEL_A_TRAIN(model)
OR (vModelMax.x > 6 OR vmodelMax.y > 6 OR vModelMax.z > 6)
REQUEST_PATH_NODES_IN_AREA_THIS_FRAME(vStartPos.X-fRoadeNodeLoadDist, vStartPos.Y-fRoadeNodeLoadDist,
vStartPos.X+fRoadeNodeLoadDist, vStartPos.Y+fRoadeNodeLoadDist)
INT timer = GET_GAME_TIMER()
WHILE NOT ARE_NODES_LOADED_FOR_AREA(vStartPos.X-fRoadeNodeLoadDist, vStartPos.Y-fRoadeNodeLoadDist,
vStartPos.X+fRoadeNodeLoadDist, vStartPos.Y+fRoadeNodeLoadDist)
AND GET_GAME_TIMER() - timer < 5000 // Fail safe for soft crash to drop out of while if stuck for > 5 seconds. B* 2314430
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPLAY, " snapshot_private - START_UP_ROAD_NODE_TEST - ARE_NODES_LOADED_FOR_AREA: PASSED OR timer buffer exceed: ",GET_GAME_TIMER() - timer," /5 seconds")
IF IS_THIS_MODEL_A_BOAT(model) OR IS_THIS_MODEL_A_JETSKI(model)
//Special model checks
OR model = SUBMERSIBLE OR model = SUBMERSIBLE2
iNodeIterator = 0
vModelMax.x = vModelMax.x /2
vModelMax.y = vModelMax.y /2
vModelMax.z = 0
FLOAT fVehicleArea = VMAG(vModelMax)
FLOAT fTestHeight, fGroundZ
CPRINTLN(DEBUG_REPLAY, " snapshot_private - START_UP_ROAD_NODE_TEST - This is a boat, looking for water nodes at ",vstartPos, " with model surface ",fVehicleArea)
WHILE GET_POSITION_IN_SPIRAL_AROUND_POINT(vStartPos,vPosTemp,iNodeIterator,16,300,3.0)
IF TEST_VERTICAL_PROBE_AGAINST_ALL_WATER(vPosTemp + <<0,0,100>>,SCRIPT_INCLUDE_OBJECT|SCRIPT_INCLUDE_GLASS|SCRIPT_INCLUDE_MOVER|SCRIPT_INCLUDE_VEHICLE,fTestHeight) = SCRIPT_WATER_TEST_RESULT_WATER
vPosTemp.z = fTestHeight
GET_GROUND_Z_FOR_3D_COORD(vPosTemp+<<0,0,100>>,fGroundZ)
IF fGroundZ <= vPosTemp.z
//2nd area check
b2ndcheckPassed = TRUE
iTemp = 0
WHILE GET_POSITION_IN_SPIRAL_AROUND_POINT(vPosTemp, vPosTemp2,iTemp,16,fVehicleArea,0.3)
IF TEST_VERTICAL_PROBE_AGAINST_ALL_WATER(vPosTemp2+<<0,0,10>>,SCRIPT_INCLUDE_OBJECT|SCRIPT_INCLUDE_GLASS|SCRIPT_INCLUDE_MOVER|SCRIPT_INCLUDE_VEHICLE,fTestHeight) = SCRIPT_WATER_TEST_RESULT_WATER
vPosTemp2.z = fTestHeight
GET_GROUND_Z_FOR_3D_COORD(vPosTemp2+<<0,0,10>>,fGroundZ)
IF fGroundZ > vPosTemp2.z
b2ndCheckPassed = FALSE
ENDIF
ELSE
b2ndCheckPassed = FALSE
ENDIF
ENDWHILE
IF b2ndCheckPassed
CPRINTLN(DEBUG_REPLAY,"START_UP_ROAD_NODE_TEST: 2nd check passed for vehicle water spawn at ",vPosTemp)
IF START_UP_SHAPETEST(vPosTemp, fRotTemp, model, bExcludePlayer)
vStartPos = vPosTemp
fStartHeading = fRotTemp
CPRINTLN(DEBUG_REPLAY, " snapshot_private - : in water vStartPos = ", vStartPos)
RETURN TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDWHILE
RETURN FALSE
ENDIF
WHILE GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(vStartPos,iNodeIterator,vPosTemp,fRotTemp,iNumOfLanes)
IF VDIST2(vStartPos, vPosTemp) <= (fRoadeNodeLoadDist * fRoadeNodeLoadDist)
IF NOT (bExcludeInteriorNodes AND IS_VALID_INTERIOR(GET_INTERIOR_AT_COORDS(vPosTemp)))
AND NOT IS_EXCLUDED_ROAD_NODE(vPosTemp, bIsBigModel, iNumOfLanes)
IF START_UP_SHAPETEST(vPosTemp, fRotTemp, model, bExcludePlayer, bIsBigModel)
CPRINTLN(DEBUG_REPLAY, "Found valid road node at ", vPosTemp)
vStartPos = vPosTemp
fStartHeading = fRotTemp
RETURN TRUE
ENDIF
ENDIF
iNodeIterator++
ELSE
RETURN FALSE
ENDIF
ENDWHILE
RETURN FALSE
ENDFUNC