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(<>,<>,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 ¶mSnapshot, 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 ¶mSnapshot, 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 ¶mSnapshot) 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 ¶mSnapshot) 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 ¶mSnapshot) 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 ¶mSnapshot, 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 + <> 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