Files
gtav-src/script/dev_ng/singleplayer/scripts/main/main.sc
T
2025-09-29 00:52:08 +02:00

1631 lines
65 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
USING "rage_builtins.sch"
USING "globals.sch"
USING "commands_camera.sch"
USING "commands_hud.sch"
USING "commands_misc.sch"
USING "commands_pad.sch"
USING "commands_script.sch"
USING "commands_replay.sch"
USING "flow_help_messages.sch"
USING "cutscene_control.sch"
USING "cutscene_private.sch"
USING "finance_control_public.sch"
USING "trains_control_public.sch"
USING "script_launch_control.sch"
USING "socialclub_leaderboard.sch"
USING "Minigame_private.sch"
USING "family_controller.sch"
USING "slow_zone_private.sch"
USING "comms_control_private.sch"
USING "selector_public.sch"
USING "flow_reset_game.sch"
USING "achievement_public.sch"
USING "player_ped_public.sch"
USING "noirEffects.sch"
USING "socialclub_leaderboard.sch"
// Keith 15/7/13: Joblist maintenance for cross-session invites to join MP to players in SP allowing them to accept on the phone
USING "net_mission_joblist.sch"
// Kenneth 30/08/13: Moving property system from the building_controller to main in order to reduce script store in GTA Online
USING "properties_private.sch"
USING "ply_to_ply_calls.sch"
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : main.sc
// AUTHOR : Keith
// DESCRIPTION : Initial setup for the game.
// Launches 'Initial'.
// Launches 'Debug'.
// Endlessly performs the scripting main loop.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
BOOL bGauntletSuppressed = FALSE
BOOL bJimmySUVSuppressed = FALSE
BOOL bDoProfileSettingCheckForLastGen = FALSE
BOOL bProfileSettingCheckForLastGenDone = FALSE
INT iGameTime
INT iOneSecondTimer = 0
INT iFiveSecondTimer = 0
//DirectorTravelLocation eDirectorLocation = INT_TO_ENUM(DirectorTravelLocation, 0)
//Cover help state.
BOOL bDisplayingCoverHelpLastFrame = FALSE
INT iFramesCoverHelpCheckPassed = 0
//Vehicle duck help state.
BOOL bDisplayingVehDuckHelpLastFrame = FALSE
INT iFramesVehDuckHelpCheckPassed = 0
INT iVehIdDuckHelpCurrent
INT iVehIdDuckHelpLast
INT iTimeVehDuckHelpLastDisplayed = 0
ScriptLaunchVars sScriptLaunchVars
FlowHelpMessageVars sFlowHelpMessageVars
FriendControllerVars sFriendControllerVars
SlowZoneLocalVars sSlowZoneVars
ActivityFeedLocalVars sActivityFeedVars
DLC_WEAPON_UNLOCK_VARS sDLCWeaponVars
NOIR_DATA noirData
#IF IS_DEBUG_BUILD
WIDGET_GROUP_ID main_widget
#ENDIF
// ===========================================================================================================
// Cleanup
// ===========================================================================================================
// PURPOSE: Ensures that the script gets a chance to cleanup under specific circumstances (ie: moving from SP to MP)
//
PROC SCRIPT_CLEANUP()
CPRINTLN(DEBUG_INIT_SP, "Main thread cleaning up.")
SET_GAME_BOOTED_TO_SP(FALSE)
NOIR_FORCE_OFF(noirData)
CLEANUP_CUTSCENE_CONTROL()
RESET_PLATFORM_UPGRADE_LB_CHECK_STRUCT(platformUpgradeLBCheckSP)
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------------------------
/// PURPOSE: Outputs the #defines for this script image configuration to the log files
DEBUGONLY PROC OUTPUT_SCRIPT_IMAGE_CONFIGURATION_TO_CONSOLE_LOG()
CPRINTLN(DEBUG_INIT, "-----------------------------------")
CPRINTLN(DEBUG_INIT, "SCRIPT IMAGE CONFIGURATION DETAILS:")
IF IS_XBOX360_VERSION()
CPRINTLN(DEBUG_INIT, " XBOX 360")
ENDIF
IF IS_SCARLETT_VERSION()
CPRINTLN(DEBUG_INIT, " XBOX Series S/X")
ELIF IS_DURANGO_VERSION()
CPRINTLN(DEBUG_INIT, " XBOX ONE")
ENDIF
IF IS_PS3_VERSION()
CPRINTLN(DEBUG_INIT, " PS3")
ENDIF
IF IS_PROSPERO_VERSION()
CPRINTLN(DEBUG_INIT, " PS5")
ELIF IS_ORBIS_VERSION()
CPRINTLN(DEBUG_INIT, " PS4")
ENDIF
#IF IS_DEBUG_BUILD
CPRINTLN(DEBUG_INIT, " DEBUG")
#ENDIF
#IF IS_FINAL_BUILD
CPRINTLN(DEBUG_INIT, " FINAL")
#ENDIF
#IF IS_JAPANESE_BUILD
CPRINTLN(DEBUG_INIT, " JAPANESE")
#ENDIF
IF NOT IS_XBOX360_VERSION()
CPRINTLN(DEBUG_INIT, " ......not xbox 360")
ENDIF
IF NOT IS_XBOX_PLATFORM()
CPRINTLN(DEBUG_INIT, " ......not xbox one or XBSX")
ENDIF
IF NOT IS_PS3_VERSION()
CPRINTLN(DEBUG_INIT, " ......not ps3")
ENDIF
IF NOT IS_PLAYSTATION_PLATFORM()
CPRINTLN(DEBUG_INIT, " ......not ps4 or PS5")
ENDIF
#IF NOT IS_JAPANESE_BUILD
CPRINTLN(DEBUG_INIT, " ......not japanese")
#ENDIF
CPRINTLN(DEBUG_INIT, "-----------------------------------")
ENDPROC
/// PURPOSE: Monitor unexpected termination of core script threads.
DEBUGONLY PROC RUN_CORE_SP_THREAD_CHECKS()
IF NOT g_bMagDemoActive
AND NOT g_bInMultiplayer
AND GET_INDEX_OF_CURRENT_LEVEL() = LEVEL_GTA5
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("flow_controller")) < 1
SCRIPT_ASSERT("Core SP script thread \"flow_controller\" has terminated unexpectedly. Bug BenR.")
ENDIF
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("blip_controller")) < 1
SCRIPT_ASSERT("Core SP script thread \"blip_controller\" has terminated unexpectedly. Bug *Default Levels*")
ENDIF
ENDIF
ENDPROC
/// PURPOSE: Requests the 'Initial' script, waits for it to stream in, then launches it
PROC REQUEST_AND_LAUNCH_INITIAL_SCRIPT_WITH_WAIT()
STRING initialScriptName = "initial"
REQUEST_SCRIPT(initialScriptName)
WHILE NOT (HAS_SCRIPT_LOADED(initialScriptName))
REQUEST_SCRIPT(initialScriptName)
WAIT(0)
ENDWHILE
START_NEW_SCRIPT(initialScriptName, FRIEND_STACK_SIZE)
SET_SCRIPT_AS_NO_LONGER_NEEDED(initialScriptName)
ENDPROC
PROC MAINTAIN_GAUNTLET_SUPPRESSION()
IF NOT bGauntletSuppressed
IF GET_MISSION_COMPLETE_STATE(SP_HEIST_FINALE_2_INTRO)
IF GET_MISSION_FLOW_INT_VALUE(FLOWINT_HEIST_CHOICE_FINALE) = HEIST_CHOICE_FINALE_TRAFFCONT
AND NOT GET_MISSION_COMPLETE_STATE(SP_HEIST_FINALE_2A)
IF (NOT IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C1)
AND NOT GET_MISSION_COMPLETE_STATE(SP_HEIST_FINALE_PREP_C1))
AND (NOT IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C2)
AND NOT GET_MISSION_COMPLETE_STATE(SP_HEIST_FINALE_PREP_C2))
AND (NOT IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C3)
AND NOT GET_MISSION_COMPLETE_STATE(SP_HEIST_FINALE_PREP_C3))
CPRINTLN(DEBUG_MISSION, "Suppressing Gauntlet model for Big score prep C missions. From ", GET_THIS_SCRIPT_NAME())
bGauntletSuppressed = TRUE
SET_VEHICLE_MODEL_IS_SUPPRESSED(GAUNTLET, TRUE)
ENDIF
ENDIF
ENDIF
ELSE
IF IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C1)
AND IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C2)
AND IS_MISSION_AVAILABLE(SP_HEIST_FINALE_PREP_C3)
bGauntletSuppressed = FALSE
CPRINTLN(DEBUG_MISSION, "Unsuppressed Gauntlet model. From ", GET_THIS_SCRIPT_NAME())
SET_VEHICLE_MODEL_IS_SUPPRESSED(GAUNTLET, FALSE)
ENDIF
ENDIF
ENDPROC
PROC MAINTAIN_JIMMY_VEHICLE_SUPPRESSED_CHECKS()
IF NOT bJimmySUVSuppressed
IF g_savedGlobals.sFlow.isGameflowActive
IF NOT GET_MISSION_COMPLETE_STATE(SP_MISSION_TREVOR_1)
CPRINTLN(DEBUG_FLOW, "Main thread suppressed Jimmy's SUV model until Trevor1 is completed or gameflow is inactive.")
SET_VEHICLE_MODEL_IS_SUPPRESSED(BJXL, TRUE)
bJimmySUVSuppressed = TRUE
ENDIF
ENDIF
ELSE
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_TREVOR_1)
OR NOT g_savedGlobals.sFlow.isGameflowActive
CPRINTLN(DEBUG_FLOW, "Main thread unsuppressed Jimmy's SUV model as Trevor1 is completed or gameflow is inactive.")
SET_VEHICLE_MODEL_IS_SUPPRESSED(BJXL, FALSE)
bJimmySUVSuppressed = FALSE
ENDIF
ENDIF
ENDPROC
PROC MANAGE_SUB_CRUSH_DEPTH()
//Fix for B* 1772703: Player can exit sub below -200 m and gets teleported to the surface
VEHICLE_INDEX viTemp = GET_VEHICLE_PED_IS_USING(PLAYER_PED_ID())
IF DOES_ENTITY_EXIST(viTemp)
IF IS_VEHICLE_MODEL(viTemp,SUBMERSIBLE)
OR IS_VEHICLE_MODEL(viTemp,CHERNOBOG)
Vector pos = GET_ENTITY_COORDS(PLAYER_PED_ID())
IF IS_VEHICLE_FUCKED(viTemp)
OR (pos.z <-190 AND IS_ENTITY_IN_WATER(PLAYER_PED_ID()))
EXPLODE_PED_HEAD(PLAYER_PED_ID())
ENDIF
ENDIF
ENDIF
ENDPROC
PROC MAINTAIN_MISSION_RECORDING_CLEANUP_CHECKS()
IF REPLAY_SYSTEM_HAS_REQUESTED_A_SCRIPT_CLEANUP()
// #IF IS_DEBUG_BUILD
// OR IS_DEBUG_KEY_PRESSED(KEY_END, KEYBOARD_MODIFIER_SHIFT, "Do recoring system script cleanup test.")
// #ENDIF
CPRINTLN(DEBUG_CLEANUP_SP, "The mission recording system has requested scripts clean up.")
g_bForceCleaupVehgenForRecordingPlayback = TRUE
g_bForceCleaupShopsForRecordingPlayback = TRUE
RUN_GENERAL_SCRIPT_CLEANUP(TRUE)
RESET_GAMEFLOW()
//Disabling trains for bug:2341432
SET_RANDOM_TRAINS(false)
DELETE_ALL_TRAINS()
// #2173929 Informing code to block invites while in the R*Editor. Allows net code to display
// a message to explain why accepting the invite isn't transitioning. Block must be cleaned
// up on SP starting back up.
NETWORK_BLOCK_INVITES(TRUE)
CPRINTLN(DEBUG_CLEANUP_SP, "Flagging that the recording system is now active.")
g_bRockstarEditorActive = TRUE
SET_SCRIPTS_HAVE_CLEANED_UP_FOR_REPLAY_SYSTEM()
CPRINTLN(DEBUG_CLEANUP_SP, "Scripts have cleaned up for recording system.")
ENDIF
ENDPROC
PROC MAINTAIN_FIRST_PERSON_COVER_HELP()
BOOL bBaseCheckPassed = FALSE
BOOL bSafeToDisplay = FALSE
BOOL bDisplayingCoverHelpThisFrame = FALSE
// Mission or flow specific checks.
IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY)
IF MISSION_FLOW_GET_RUNNING_MISSION() != SP_MISSION_PROLOGUE
IF g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountMission < 3
bBaseCheckPassed = TRUE
ENDIF
ENDIF
ELIF g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountFlow < 3
IF IS_FLOW_HELP_QUEUE_EMPTY()
bBaseCheckPassed = TRUE
ENDIF
ENDIF
// Checks to run against flow and mission help.
IF bBaseCheckPassed
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF GET_FOLLOW_PED_CAM_VIEW_MODE() = CAM_VIEW_MODE_FIRST_PERSON
IF IS_PED_IN_COVER(PLAYER_PED_ID())
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
IF NOT IS_CUTSCENE_PLAYING()
IF IS_SCREEN_FADED_IN()
IF NOT IS_WARNING_MESSAGE_ACTIVE()
IF (NOT IS_HELP_MESSAGE_BEING_DISPLAYED())
OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("FP_COVER_HLP")
bSafeToDisplay = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// Wait for 10 consecutive safe frames before allowing the help to display.
// This will give scripts a chance to queue up back to back help messages
// without this help interrupting.
IF bSafeToDisplay
iFramesCoverHelpCheckPassed++
IF iFramesCoverHelpCheckPassed > 10
DISPLAY_HELP_TEXT_THIS_FRAME("FP_COVER_HLP", FALSE)
bDisplayingCoverHelpThisFrame = TRUE
ENDIF
ELIF iFramesCoverHelpCheckPassed > 0
CDEBUG2LN(DEBUG_FLOW_HELP, "<FP_COVER> No longer safe to display. Resetting safe frame count.")
iFramesCoverHelpCheckPassed = 0
ENDIF
// Check if we've just finished displaying help.
IF bDisplayingCoverHelpLastFrame AND NOT bDisplayingCoverHelpThisFrame
IF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_STORY)
g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountMission++
CPRINTLN(DEBUG_FLOW_HELP, "<FP_COVER> Finished displaying first person cover help while on mission. New count is ", g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountMission, ".")
ELSE
g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountFlow++
CPRINTLN(DEBUG_FLOW_HELP, "<FP_COVER> Finished displaying first person cover help while off mission. New count is ", g_savedGlobals.sFlowCustom.iFirstPersonCoverHelpCountFlow, ".")
ENDIF
ENDIF
// Update last frame variable.
bDisplayingCoverHelpLastFrame = bDisplayingCoverHelpThisFrame
ENDPROC
// TODO 1925330
PROC MAINTAIN_VEHICLE_DUCK_HELP()
BOOL bSafeToDisplay = FALSE
BOOL bDisplayingVehDuckHelpThisFrame = FALSE
VEHICLE_INDEX vehCurrent
// Display condition checks.
IF g_savedGlobals.sFlowCustom.iVehDuckHelpCount < 4
IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE()
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF IS_PLAYER_CONTROL_ON(PLAYER_ID())
IF NOT IS_CUTSCENE_PLAYING()
AND NOT IS_PLAYER_IN_PROPERTY(PLAYER_ID(), TRUE, TRUE)
AND NOT IS_PLAYER_BROWSING_ITEMS_IN_ANY_SHOP()
IF IS_SCREEN_FADED_IN()
IF NOT IS_WARNING_MESSAGE_ACTIVE()
IF IS_PED_SITTING_IN_ANY_VEHICLE(PLAYER_PED_ID())
vehCurrent = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF IS_VEHICLE_DRIVEABLE(vehCurrent)
IF NOT IS_VEHICLE_A_SUPERMOD_MODEL(GET_ENTITY_MODEL(vehCurrent), SUPERMOD_FLAG_HAS_HYDRAULICS)
iVehIdDuckHelpCurrent = NATIVE_TO_INT(vehCurrent)
IF GET_GAME_TIMER() > iTimeVehDuckHelpLastDisplayed + 120000 //Don't display more often than once every 2 mins.
IF iVehIdDuckHelpLast != iVehIdDuckHelpCurrent
IF IS_THIS_MODEL_A_CAR(GET_ENTITY_MODEL(vehCurrent))
IF IS_CONTROL_ENABLED(PLAYER_CONTROL, INPUT_VEH_DUCK)
IF (NOT IS_HELP_MESSAGE_BEING_DISPLAYED())
OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("HELP_DCK")
bSafeToDisplay = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
//If we get into a vehicle with a timer blocking, don't allow the help
//to pop up while still in that vehicle. It will seem like it came up
//at an arbitrary moment. Better to try and display it just after the
//player enters a fresh vehicle.
iVehIdDuckHelpLast = iVehIdDuckHelpCurrent
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// Wait for 10 consecutive safe frames before allowing the help to display.
// This will give scripts a chance to queue up back to back help messages
// without this help interrupting.
IF bSafeToDisplay
iFramesVehDuckHelpCheckPassed++
IF iFramesVehDuckHelpCheckPassed > 10
IF GET_FLOW_HELP_MESSAGE_STATUS("HELP_DCK") = FHS_EXPIRED
ADD_HELP_TO_FLOW_QUEUE("HELP_DCK", FHP_LOW, 0, 1000)
ENDIF
ENDIF
ELIF iFramesVehDuckHelpCheckPassed > 0
CDEBUG2LN(DEBUG_FLOW_HELP, "<VEH_DUCK> No longer safe to display. Resetting safe frame count.")
iFramesVehDuckHelpCheckPassed = 0
IF GET_FLOW_HELP_MESSAGE_STATUS("HELP_DCK") = FHS_QUEUED
REMOVE_HELP_FROM_FLOW_QUEUE("HELP_DCK")
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("HELP_DCK")
CLEAR_HELP()
ENDIF
ENDIF
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("HELP_DCK")
bDisplayingVehDuckHelpThisFrame = TRUE
ENDIF
// Check if we've just finished displaying help.
IF bDisplayingVehDuckHelpLastFrame AND NOT bDisplayingVehDuckHelpThisFrame
g_savedGlobals.sFlowCustom.iVehDuckHelpCount++
iTimeVehDuckHelpLastDisplayed = GET_GAME_TIMER()
iVehIdDuckHelpLast = iVehIdDuckHelpCurrent
g_txtFlowHelpLastDisplayed = "" //Clear last displayed message.
CPRINTLN(DEBUG_FLOW_HELP, "<VEH_DUCK> Finished displaying vehicle duck help. New count is ", g_savedGlobals.sFlowCustom.iVehDuckHelpCount, ".")
ENDIF
// Update last frame variable.
bDisplayingVehDuckHelpLastFrame = bDisplayingVehDuckHelpThisFrame
ENDPROC
ENUM MAGIC_MOMENT_TYPE
MAGICMOMENT_TYPE_5_STAR_CRIMINAL, //1. 5 Star Criminal Records video of a player ticking over to 5 starts during a wanted rating spree
MAGICMOMENT_TYPE_CHAIN_REACTION, //2. Chain Reaction Records a video if the player blow up X cars within X seconds
MAGICMOMENT_TYPE_BIRD_DOWN, //3. Bird Down Records when the player kills the pilot to make a helicopter crash to make it spiral and crash
MAGICMOMENT_TYPE_SCOPED, //4. Scoped Records the player performing a headshot rom a large distance using a sniper rifle
MAGICMOMENT_TYPE_TOP_GUN, //5. Top Gun Records a video when the player destroys something using an aircraft
MAGICMOMENT_TYPE_AIRTIME, //6. Airtime Records any massive jump over a certain distance / height
MAGICMOMENT_TYPE_UNTOUCHABLE, //7. Untouchable Records when the player drives at speed into oncoming traffic without hitting anything for X time
MAGICMOMENT_TYPE_WHEELIE_RIDER, //8. Wheelie Rider Records when the player has performed a wheelie for X distance (500m?).
MAGICMOMENT_TYPE_BUCKLE_UP, //9. Buckle Up! Records when the player crashes and flies through the windscreen of their car
MAGICMOMENT_TYPE_ROLLED_OVER, //10. Rolled Over Records when the player crashes and flips / rolls X times in a vehicle (Like achievement in IV)
MAGICMOMENT_TYPE_DIZZYING_LOWS, //11. Dizzying Lows Records when the player flies upside down and low to the ground for x time
MAGICMOMENT_TYPE_YANK_THE_CORD, //12. Yank the Cord! Records when the player free falls X distance and opens their chute at the last second
MAGICMOMENT_TYPE_ANIMAUL, //13. Animaul Records when the player is killed by any animals (Mountain Lions, Sharks and Dogs etc.)
MAGICMOMENT_TYPE_FULLY_MODDED, //14. Fully Modded Records when a players fully mods their vehicle and exits LS Custom
MAGICMOMENT_TYPE_GLORY_HOLE, //15. Glory Hole Records when the player gets a Hole in 1 during Golf
MAGICMOMENT_TYPE_ARRAY_SIZE
ENDENUM
//FIVE_START_CRIMINAL = 0,
//CHAIN_REACTION,
//BIRD_DOWN,
//SCOPED,
//TOP_GUN,
//AIRTIME,
//UNTOUCHABLE,
//WHEELIE_RIDER,
//BUCKLE_UP,
//ROLLED_OVER,
//DIZZYING_LAWS,
//YANK_THE_CORD,
//ANIMAUL,
//FULLY_MODDED,
//GLORY_HOLE
ENUM MAGIC_MOMENT_TYPE_VARIABLE_STATE //Labels our previous and current array values
MM_PREVIOUS,
MM_CURRENT
ENDENUM
MAGIC_MOMENT_TYPE eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_5_STAR_CRIMINAL
MAGIC_MOMENT_TYPE eCurrentlyProcessedMagicMomentTypeMinigame = MAGICMOMENT_TYPE_GLORY_HOLE
MAGIC_MOMENT_TYPE eCurrentlyProcessedMagicMomentTypeOnFoot = MAGICMOMENT_TYPE_SCOPED
MAGIC_MOMENT_TYPE eCurrentlyProcessedMagicMomentTypeInPlane = MAGICMOMENT_TYPE_DIZZYING_LOWS
MAGIC_MOMENT_TYPE eCurrentlyProcessedMagicMomentTypeInVehicle = MAGICMOMENT_TYPE_AIRTIME
//Actually make native stat procedure useful
FUNC INT STAT_RETURN_INT(STATSENUM seThisStat)
INT iTempStat
STAT_GET_INT(seThisStat, iTempStat)
RETURN iTempStat
ENDFUNC
//Actually make native stat procedure useful
FUNC FLOAT STAT_RETURN_FLOAT(STATSENUM seThisStat)
FLOAT fTempStat
STAT_GET_FLOAT(seThisStat, fTempStat)
RETURN fTempStat
ENDFUNC
FLOAT iMMStats[MAGICMOMENT_TYPE_ARRAY_SIZE][2]
INT iChainReactionTimer = -1
INT iUntouchableTimer = -1
INT iMagicMomentsTimer
INT iAirstrikeWindowTime
FLOAT fChainReactionInProgressCount = 0
BOOL bForceResetTopgunStats
BOOL bCheckedLastDestroyedHeli
BOOL bLastDestroyedHeliInAir
BOOL bInitialisedMagicMoments
BOOL bDontSpamMagicMoments
BOOL bHitAnimal
PROC SET_MAGIC_MOMENT_CURRENT_VALUE(MAGIC_MOMENT_TYPE thisMoment, BOOL bAlsoSetPreviousValue = FALSE)
SWITCH thisMoment
CASE MAGICMOMENT_TYPE_5_STAR_CRIMINAL
iMMStats[thisMoment][MM_CURRENT] = 0
BREAK
CASE MAGICMOMENT_TYPE_CHAIN_REACTION
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_CARS_EXPLODED)+STAT_RETURN_INT(SP1_CARS_EXPLODED)+STAT_RETURN_INT(SP2_CARS_EXPLODED))
BREAK
CASE MAGICMOMENT_TYPE_BIRD_DOWN
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_HELIS_EXPLODED) + STAT_RETURN_INT(SP1_HELIS_EXPLODED) + STAT_RETURN_INT(SP2_HELIS_EXPLODED))
BREAK
CASE MAGICMOMENT_TYPE_YANK_THE_CORD
iMMStats[thisMoment][MM_CURRENT] = g_savedGlobals.sBasejumpData.fLongestSkydive//STAT_RETURN_FLOAT(SP0_LONGEST_SKYDIVE) + STAT_RETURN_FLOAT(SP1_LONGEST_SKYDIVE) + STAT_RETURN_FLOAT(SP2_LONGEST_SKYDIVE)
BREAK
CASE MAGICMOMENT_TYPE_BUCKLE_UP
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_THROWNTHROUGH_WINDSCREEN) + STAT_RETURN_INT(SP1_THROWNTHROUGH_WINDSCREEN) + STAT_RETURN_INT(SP2_THROWNTHROUGH_WINDSCREEN))
BREAK
CASE MAGICMOMENT_TYPE_GLORY_HOLE
iMMStats[thisMoment][MM_CURRENT] = 0
BREAK
CASE MAGICMOMENT_TYPE_SCOPED
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_HEADSHOTS) + STAT_RETURN_INT(SP1_HEADSHOTS) + STAT_RETURN_INT(SP2_HEADSHOTS))
BREAK
CASE MAGICMOMENT_TYPE_ANIMAUL
iMMStats[thisMoment][MM_CURRENT] = -60000
BREAK
CASE MAGICMOMENT_TYPE_DIZZYING_LOWS
iMMStats[thisMoment][MM_CURRENT] = 0
BREAK
CASE MAGICMOMENT_TYPE_TOP_GUN
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_KILLS) + STAT_RETURN_INT(SP1_KILLS) + STAT_RETURN_INT(SP2_KILLS))
BREAK
CASE MAGICMOMENT_TYPE_AIRTIME
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_AIR_LAUNCHES_OVER_5S) + STAT_RETURN_INT(SP1_AIR_LAUNCHES_OVER_5S) + STAT_RETURN_INT(SP2_AIR_LAUNCHES_OVER_5S))
BREAK
CASE MAGICMOMENT_TYPE_WHEELIE_RIDER
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_LONGEST_WHEELIE_TIME) + STAT_RETURN_INT(SP1_LONGEST_WHEELIE_TIME) + STAT_RETURN_INT(SP2_LONGEST_WHEELIE_TIME))
BREAK
CASE MAGICMOMENT_TYPE_ROLLED_OVER
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_MOST_FLIPS_IN_ONE_JUMP) + STAT_RETURN_INT(SP1_MOST_FLIPS_IN_ONE_JUMP) + STAT_RETURN_INT(SP2_MOST_FLIPS_IN_ONE_JUMP))
BREAK
CASE MAGICMOMENT_TYPE_UNTOUCHABLE
iMMStats[thisMoment][MM_CURRENT] = TO_FLOAT(STAT_RETURN_INT(SP0_NUMBER_NEAR_MISS) + STAT_RETURN_INT(SP1_NUMBER_NEAR_MISS) + STAT_RETURN_INT(SP2_NUMBER_NEAR_MISS)) //STAT_RETURN_FLOAT(SP0_LONGEST_DRIVE_NOCRASH) + STAT_RETURN_FLOAT(SP1_LONGEST_DRIVE_NOCRASH) + STAT_RETURN_FLOAT(SP2_LONGEST_DRIVE_NOCRASH)
BREAK
ENDSWITCH
IF bAlsoSetPreviousValue
iMMStats[thisMoment][MM_PREVIOUS] = iMMStats[thisMoment][MM_CURRENT]
ENDIF
ENDPROC
BOOL bResetGroundVehicleStatsFlag
BOOL bResetAirVehicleStatsFlag
PROC MANAGE_MAGIC_MOMENTS()
IF NOT bInitialisedMagicMoments
// initialise values on load to what is currently stored in stats
IF IS_PLAYER_PLAYING(PLAYER_ID())
INT i
REPEAT MAGICMOMENT_TYPE_ARRAY_SIZE i
SET_MAGIC_MOMENT_CURRENT_VALUE(INT_TO_ENUM(MAGIC_MOMENT_TYPE, i), TRUE)
ENDREPEAT
iMagicMomentsTimer = -30000
bInitialisedMagicMoments = TRUE
ENDIF
ELSE
// process after initialisation
// 2048106 - ensure destroyed heli is in air
INT iCount
STRUCT_ENTITY_ID sei
EVENT_NAMES eventType
// rob - 2079393 - ensure last destroyed heli is checked for in air/has pilot before processed from the stat increment
// rob - 2099008 - don't count birds for air strike
REPEAT GET_NUMBER_OF_EVENTS(SCRIPT_EVENT_QUEUE_AI) iCount
eventType = GET_EVENT_AT_INDEX(SCRIPT_EVENT_QUEUE_AI, iCount)
IF eventType = EVENT_ENTITY_DESTROYED
GET_EVENT_DATA(SCRIPT_EVENT_QUEUE_AI,iCount, sei,SIZE_OF(STRUCT_ENTITY_ID))
IF DOES_ENTITY_EXIST(sei.EntityId)
IF IS_THIS_MODEL_A_HELI(GET_ENTITY_MODEL(sei.EntityId))
IF NOT bCheckedLastDestroyedHeli
bLastDestroyedHeliInAir = FALSE
bCheckedLastDestroyedHeli = TRUE
IF IS_ENTITY_DEAD(sei.EntityId)
OR NOT IS_ENTITY_DEAD(sei.EntityId)
IF IS_ENTITY_IN_AIR(sei.EntityId)
OR DOES_ENTITY_EXIST(GET_PED_IN_VEHICLE_SEAT(GET_VEHICLE_INDEX_FROM_ENTITY_INDEX(sei.EntityId))) // rob - 2079393 - some helis shot down by kiing the pilot weren't triggering this
bLastDestroyedHeliInAir = TRUE
ENDIF
ENDIF
ENDIF
ELIF IS_ENTITY_A_PED(sei.EntityId)
iAirstrikeWindowTime = GET_GAME_TIMER() + 1000
IF NOT IS_PED_HUMAN(GET_PED_INDEX_FROM_ENTITY_INDEX(sei.EntityId))
bHitAnimal = TRUE
ELSE
bHitAnimal = FALSE
ENDIF
ENDIF
ENDIF
ENDIF
ENDREPEAT
BOOL bWasInAircraft = FALSE
//Magic moments that can happen at any time.
SWITCH eCurrentlyProcessedMagicMomentType
CASE MAGICMOMENT_TYPE_5_STAR_CRIMINAL
IF iMMStats[MAGICMOMENT_TYPE_5_STAR_CRIMINAL][MM_PREVIOUS] < 5
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) = 5
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
AND NOT IS_CURRENTLY_ON_MISSION_OF_ANY_TYPE()
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(FIVE_START_CRIMINAL, -5000, 8000)
printstring("Record Greatest Moment - Five star criminal") printnl()
ENDIF
ENDIF
iMMStats[MAGICMOMENT_TYPE_5_STAR_CRIMINAL][MM_PREVIOUS] = TO_FLOAT(GET_PLAYER_WANTED_LEVEL(PLAYER_ID()))
eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_CHAIN_REACTION
BREAK
CASE MAGICMOMENT_TYPE_CHAIN_REACTION
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_CHAIN_REACTION)
IF iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_PREVIOUS] > 1.0
IF iChainReactionTimer = -1
//Start Timer!
fChainReactionInProgressCount = iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT]
iChainReactionTimer = GET_GAME_TIMER()
ENDIF
IF iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_PREVIOUS] >= 4.0
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(CHAIN_REACTION, -6000, 12000)
printstring("Record Greatest Moment - Chain reaction") printnl()
ENDIF
iChainReactionTimer = -1
iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT]
ENDIF
IF iChainReactionTimer >= 0
// rob - 2079393 - add to the timer while the chain reaction's still ongoing
IF iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT] > fChainReactionInProgressCount
fChainReactionInProgressCount = iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT]
IF GET_GAME_TIMER() - iChainReactionTimer > 2000
iChainReactionTimer = GET_GAME_TIMER() - 2000
ENDIF
ENDIF
IF GET_GAME_TIMER() - iChainReactionTimer > 4000
iChainReactionTimer = -1
iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_CHAIN_REACTION][MM_CURRENT]
ENDIF
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_BIRD_DOWN
BREAK
CASE MAGICMOMENT_TYPE_BIRD_DOWN
//Number of helis exploded
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_BIRD_DOWN)
IF iMMStats[MAGICMOMENT_TYPE_BIRD_DOWN][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_BIRD_DOWN][MM_PREVIOUS] > 0.0
IF bCheckedLastDestroyedHeli
IF bLastDestroyedHeliInAir
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(BIRD_DOWN, -8000, 12000)
printstring("Record Greatest Moment - Bird down") printnl()
ENDIF
ENDIF
bLastDestroyedHeliInAir = FALSE
bCheckedLastDestroyedHeli = FALSE
// don't let them buffer up
iMMStats[MAGICMOMENT_TYPE_BIRD_DOWN][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_BIRD_DOWN][MM_CURRENT]
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_YANK_THE_CORD
BREAK
CASE MAGICMOMENT_TYPE_YANK_THE_CORD
//Implementation incomplete. Awaiting proper stat from Miguel.
IF GET_PED_PARACHUTE_STATE(PLAYER_PED_ID()) = PPS_SKYDIVING
//Init
IF iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS] = 0.0
iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_CURRENT] = 100.0
iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS] = 100.0
ENDIF
ELIF GET_PED_PARACHUTE_STATE(PLAYER_PED_ID()) = PPS_DEPLOYING
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_YANK_THE_CORD)
PRINTLN("deployed data:", GET_ENTITY_HEIGHT_ABOVE_GROUND(PLAYER_PED_ID()), " < ", iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS])
IF GET_ENTITY_HEIGHT_ABOVE_GROUND(PLAYER_PED_ID()) < iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS]
iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS] = GET_ENTITY_HEIGHT_ABOVE_GROUND(PLAYER_PED_ID())
iMagicMomentsTimer = GET_GAME_TIMER()
bDontSpamMagicMoments = FALSE
ENDIF
ELIF GET_PED_PARACHUTE_STATE(PLAYER_PED_ID()) = PPS_LANDING
//Now check if they land safely...
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF NOT IS_ENTITY_IN_AIR(PLAYER_PED_ID())
IF GET_GAME_TIMER() - iMagicMomentsTimer < 10000
IF bDontSpamMagicMoments = FALSE
g_savedGlobals.sBasejumpData.fLongestSkydive = iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS]
RECORD_GREATEST_MOMENT(YANK_THE_CORD, -7000, 10000)
printstring("Record Greatest Moment - Yank the cord") printnl()
bDontSpamMagicMoments = TRUE
ENDIF
ELSE
PRINTLN("GET_GAME_TIMER() - iMagicMomentsTimer:, ", (GET_GAME_TIMER() - iMagicMomentsTimer))
iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS] = g_savedGlobals.sBasejumpData.fLongestSkydive
//SCRIPT_ASSERT("timer expired")
ENDIF
ENDIF
ELSE
iMMStats[MAGICMOMENT_TYPE_YANK_THE_CORD][MM_PREVIOUS] = g_savedGlobals.sBasejumpData.fLongestSkydive
//SCRIPT_ASSERT("reseting value")
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_BUCKLE_UP
BREAK
CASE MAGICMOMENT_TYPE_BUCKLE_UP
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_BUCKLE_UP)
IF iMMStats[MAGICMOMENT_TYPE_BUCKLE_UP][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_BUCKLE_UP][MM_PREVIOUS] > 0.0
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(BUCKLE_UP, -3000, 8000)
printstring("Record Greatest Moment - Buckle up") printnl()
ENDIF
iMMStats[MAGICMOMENT_TYPE_BUCKLE_UP][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_BUCKLE_UP][MM_CURRENT]
ENDIF
eCurrentlyProcessedMagicMomentType = MAGICMOMENT_TYPE_5_STAR_CRIMINAL
BREAK
ENDSWITCH
//Magic moments that can only happen during minigames
//IF IS_MINIGAME_ACTIVE(MINIGAME_GOLF)
// rob - 2079393 - change is golf running check
IF GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("golf")) > 0
SWITCH eCurrentlyProcessedMagicMomentTypeMinigame
CASE MAGICMOMENT_TYPE_GLORY_HOLE
IF IS_GLOBAL_GOLF_CONTROL_FLAG_SET(GGCF_PLAYER_HOLE_IN_ONE)
IF iMMStats[MAGICMOMENT_TYPE_GLORY_HOLE][MM_CURRENT] = 0
RECORD_GREATEST_MOMENT(GLORY_HOLE, -15000, 18000)
printstring("Record Greatest Moment - Glory") printnl()
iMagicMomentsTimer = GET_GAME_TIMER()
iMMStats[MAGICMOMENT_TYPE_GLORY_HOLE][MM_CURRENT] = 1
ENDIF
ELSE
iMMStats[MAGICMOMENT_TYPE_GLORY_HOLE][MM_CURRENT] = 0
ENDIF
BREAK
ENDSWITCH
//Magic moments that can only happen on foot
ELIF IS_PED_ON_FOOT(PLAYER_PED_ID())
//If a player pulls off a "magic moment" bug exits the vehicle before it finishes processing
//we need to reset.
IF bResetGroundVehicleStatsFlag = FALSE
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_AIRTIME, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_WHEELIE_RIDER, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_ROLLED_OVER, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_UNTOUCHABLE, TRUE)
bResetGroundVehicleStatsFlag = TRUE
ENDIF
//If a player pulls off a "magic moment" bug exits the aircraft before it finishes processing
//we need to reset.
IF bResetAirVehicleStatsFlag = FALSE
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_TOP_GUN, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_DIZZYING_LOWS, TRUE)
bResetAirVehicleStatsFlag = TRUE
ENDIF
ENTITY_INDEX eiPlayerKiller
PED_INDEX piPlayerKillerPedIndex
WEAPON_TYPE MMReturnWeaponType
SWITCH eCurrentlyProcessedMagicMomentTypeOnFoot
CASE MAGICMOMENT_TYPE_SCOPED
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_SCOPED)
IF iMMStats[MAGICMOMENT_TYPE_SCOPED][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_SCOPED][MM_PREVIOUS] > 0.0
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
IF GET_CURRENT_PED_WEAPON(PLAYER_PED_ID(),MMReturnWeaponType, FALSE)
// rob - 2090369 - limit "scoped" to using a sniper rifle
IF MMReturnWeaponType = WEAPONTYPE_SNIPERRIFLE
OR MMReturnWeaponType = WEAPONTYPE_HEAVYSNIPER
OR MMReturnWeaponType = WEAPONTYPE_DLC_MARKSMANRIFLE
RECORD_GREATEST_MOMENT(SCOPED, -4000, 8000)
printstring("Record Greatest Moment - Scoped") printnl()
iMagicMomentsTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
iMMStats[MAGICMOMENT_TYPE_SCOPED][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_SCOPED][MM_CURRENT]
eCurrentlyProcessedMagicMomentTypeOnFoot = MAGICMOMENT_TYPE_ANIMAUL
BREAK
CASE MAGICMOMENT_TYPE_ANIMAUL
IF IS_PED_INJURED(PLAYER_PED_ID())
eiPlayerKiller = GET_PED_SOURCE_OF_DEATH(PLAYER_PED_ID())
IF IS_ENTITY_A_PED(eiPlayerKiller)
piPlayerKillerPedIndex = GET_PED_INDEX_FROM_ENTITY_INDEX(eiPlayerKiller)
IF NOT IS_ENTITY_DEAD(piPlayerKillerPedIndex)
IF GET_PED_TYPE(piPlayerKillerPedIndex) = PEDTYPE_ANIMAL
AND GET_GAME_TIMER() - iMMStats[MAGICMOMENT_TYPE_ANIMAUL][MM_CURRENT] > 60000.0
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
RECORD_GREATEST_MOMENT(ANIMAUL, -8000, 12000)
printstring("Record Greatest Moment - Animaul") printnl()
iMagicMomentsTimer = GET_GAME_TIMER()
iMMStats[MAGICMOMENT_TYPE_ANIMAUL][MM_CURRENT] = TO_FLOAT(GET_GAME_TIMER())
ENDIF
ENDIF
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentTypeOnFoot = MAGICMOMENT_TYPE_SCOPED
BREAK
ENDSWITCH
//Magic moments that can only happen in vehicles
ELIF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
//Magic moments that can only happen in planes
IF IS_PED_IN_ANY_PLANE(PLAYER_PED_ID())
OR IS_PED_IN_ANY_HELI(PLAYER_PED_ID())
bWasInAircraft = TRUE
//If a player pulls off a "magic moment" bug exits the vehicle before it finishes processing
//we need to reset.
IF bResetGroundVehicleStatsFlag = FALSE
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_AIRTIME, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_WHEELIE_RIDER, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_ROLLED_OVER, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_UNTOUCHABLE, TRUE)
bResetGroundVehicleStatsFlag = TRUE
ENDIF
bResetAirVehicleStatsFlag = FALSE
SWITCH eCurrentlyProcessedMagicMomentTypeInPlane
CASE MAGICMOMENT_TYPE_DIZZYING_LOWS
// url:bugstar:2102428
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
AND NOT IS_ENTITY_DEAD(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
IF IS_ENTITY_UPSIDEDOWN(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()))
IF GET_ENTITY_HEIGHT_ABOVE_GROUND(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())) < 30.0
IF iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] = 0.0
//Use current here to store time and previous to store record time
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] = TO_FLOAT(GET_GAME_TIMER() )
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_PREVIOUS] = 3000.0
ENDIF
IF GET_GAME_TIMER() - iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] > iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_PREVIOUS]
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_PREVIOUS] = TO_FLOAT(GET_GAME_TIMER()) - iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT]
RECORD_GREATEST_MOMENT(DIZZYING_LAWS, -5000, 8000)
printstring("Record Greatest Moment - Dizzying lows") printnl()
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] = 0.0
iMagicMomentsTimer = GET_GAME_TIMER()
ENDIF
ELSE
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] = 0.0
ENDIF
ELSE
iMMStats[MAGICMOMENT_TYPE_DIZZYING_LOWS][MM_CURRENT] = 0.0
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentTypeInPlane = MAGICMOMENT_TYPE_TOP_GUN
BREAK
CASE MAGICMOMENT_TYPE_TOP_GUN
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_TOP_GUN)
// force reset when only just entered vehicle, to avoid situations where you can get a kill on foot then it records soon as you get in a plane
IF bForceResetTopgunStats
iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_CURRENT]
ENDIF
IF iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_PREVIOUS] > 0.0
AND GET_GAME_TIMER() < iAirstrikeWindowTime
VEHICLE_INDEX airVehicle
airVehicle = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
AND IS_VEHICLE_DRIVEABLE(airVehicle) // check the plane you are in is OK - 2049101
AND NOT bHitAnimal // not a bird - 2099008
RECORD_GREATEST_MOMENT(TOP_GUN, -3000, 8000)
printstring("Record Greatest Moment - Top") printnl()
iMagicMomentsTimer = GET_GAME_TIMER()
ENDIF
//Dont let them buffer up
iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_TOP_GUN][MM_CURRENT]
ENDIF
eCurrentlyProcessedMagicMomentTypeInPlane = MAGICMOMENT_TYPE_DIZZYING_LOWS
bForceResetTopgunStats = FALSE
BREAK
ENDSWITCH
ELSE
//If a player pulls off a "magic moment" bug exits the aircraft before it finishes processing
//we need to reset.
IF bResetAirVehicleStatsFlag = FALSE
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_TOP_GUN, TRUE)
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_DIZZYING_LOWS, TRUE)
bResetAirVehicleStatsFlag = TRUE
ENDIF
bResetGroundVehicleStatsFlag = FALSE
SWITCH eCurrentlyProcessedMagicMomentTypeInVehicle
CASE MAGICMOMENT_TYPE_AIRTIME
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_AIRTIME)
// IF iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT] < 1.0
// iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT] = 1.0
// iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_PREVIOUS] = 1.0
// ENDIF
PRINTLN("Values: ", iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT], ", ", iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_PREVIOUS])
IF iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_PREVIOUS] - iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT] <> 0
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
RECORD_GREATEST_MOMENT(AIRTIME, -9000, 12000)
printstring("Record Greatest Moment - Airtime") printnl()
PRINTLN("Values: ", iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT], ", ", iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_PREVIOUS])
iMagicMomentsTimer = GET_GAME_TIMER()
ENDIF
iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_AIRTIME][MM_CURRENT]
eCurrentlyProcessedMagicMomentTypeInVehicle = MAGICMOMENT_TYPE_WHEELIE_RIDER
BREAK
CASE MAGICMOMENT_TYPE_WHEELIE_RIDER
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_WHEELIE_RIDER)
// IF iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_CURRENT] < 1.0
// iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_CURRENT] = 1.0
// iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_PREVIOUS] = 1.0
// ENDIF
IF iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_PREVIOUS] - iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_CURRENT] <> 0
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
RECORD_GREATEST_MOMENT(WHEELIE_RIDER, -6000, 8000)
printstring("Record Greatest Moment - Wheelie") printnl()
PRINTLN("Values: ", iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_CURRENT], ", ", iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_PREVIOUS])
iMagicMomentsTimer = GET_GAME_TIMER()
ENDIF
iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_WHEELIE_RIDER][MM_CURRENT]
eCurrentlyProcessedMagicMomentTypeInVehicle = MAGICMOMENT_TYPE_ROLLED_OVER
BREAK
CASE MAGICMOMENT_TYPE_ROLLED_OVER
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_ROLLED_OVER)
IF iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_PREVIOUS] > 0.0
AND GET_GAME_TIMER() - iMagicMomentsTimer > 30000
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(ROLLED_OVER, -5000, 8000)
printstring("Record Greatest Moment - Rolled over") printnl()
PRINTLN("Values: ", iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_CURRENT], ", ", iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_PREVIOUS])
ENDIF
iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_ROLLED_OVER][MM_CURRENT]
eCurrentlyProcessedMagicMomentTypeInVehicle = MAGICMOMENT_TYPE_UNTOUCHABLE
BREAK
CASE MAGICMOMENT_TYPE_UNTOUCHABLE
//Longest drive without crashing
SET_MAGIC_MOMENT_CURRENT_VALUE(MAGICMOMENT_TYPE_UNTOUCHABLE)
//PRINTLN("Values: ", iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_CURRENT], ", ", iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_PREVIOUS], " Speed: ", GET_ENTITY_SPEED(PLAYER_PED_ID()))
IF iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_PREVIOUS] > 1.0
IF iUntouchableTimer = -1
//Start Timer!
//SCRIPT_ASSERT("timer started!")
iUntouchableTimer = GET_GAME_TIMER()
ENDIF
IF iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_CURRENT] - iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_PREVIOUS] >= 8.0
IF GET_GAME_TIMER() - iMagicMomentsTimer > 30000
AND GET_ENTITY_SPEED(PLAYER_PED_ID()) > 22.8
iMagicMomentsTimer = GET_GAME_TIMER()
RECORD_GREATEST_MOMENT(UNTOUCHABLE, -4000, 8000)
printstring("Record Greatest Moment - Untouchable") printnl()
ENDIF
//SCRIPT_ASSERT("reset!")
iUntouchableTimer = -1
iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_CURRENT]
ENDIF
IF iUntouchableTimer >= 0
IF GET_GAME_TIMER() - iUntouchableTimer > 6000
//SCRIPT_ASSERT("timer up!")
iUntouchableTimer = -1
iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_PREVIOUS] = iMMStats[MAGICMOMENT_TYPE_UNTOUCHABLE][MM_CURRENT]
ENDIF
ENDIF
ENDIF
eCurrentlyProcessedMagicMomentTypeInVehicle = MAGICMOMENT_TYPE_AIRTIME
BREAK
//Taken care of in Mod Shop script
// CASE MAGICMOMENT_TYPE_FULLY_MODDED
ENDSWITCH
ENDIF
ENDIF
IF NOT bWasInAircraft
bForceResetTopgunStats = TRUE
ENDIF
ENDIF
ENDPROC
PROC PRINT_AVAILABLE_SAVE_DATA_STRUCT(STRUCT_AVAILABLE_SAVE_DATA &sData, STRING strDebugName)
CDEBUG1LN(DEBUG_INIT_SP, "--- ", strDebugName, " ---")
CDEBUG1LN(DEBUG_INIT_SP, "m_totalProgressMadeInSp = ", sData.m_totalProgressMadeInSp)
CDEBUG1LN(DEBUG_INIT_SP, "m_numberOfChars = ", sData.m_numberOfChars)
CDEBUG1LN(DEBUG_INIT_SP, "m_lastchar = ", sData.m_lastchar)
CDEBUG1LN(DEBUG_INIT_SP, "m_gamerName = ", sData.m_gamerName)
CDEBUG1LN(DEBUG_INIT_SP, "m_gamerHandle = ", sData.m_gamerHandle)
CDEBUG1LN(DEBUG_INIT_SP, "m_pvc = ", sData.m_pvc)
CDEBUG1LN(DEBUG_INIT_SP, "m_evc = ", sData.m_evc)
CDEBUG1LN(DEBUG_INIT_SP, "m_bank = ", sData.m_bank)
INT i
REPEAT 5 i
CDEBUG1LN(DEBUG_INIT_SP, "m_wallet[", i, "] = ", sData.m_wallet[i])
ENDREPEAT
REPEAT 5 i
CDEBUG1LN(DEBUG_INIT_SP, "m_xp[", i, "] = ", sData.m_xp[i])
ENDREPEAT
REPEAT 5 i
CDEBUG1LN(DEBUG_INIT_SP, "m_isactive[", i, "] = ", sData.m_isactive[i])
ENDREPEAT
CDEBUG1LN(DEBUG_INIT_SP, "-----------------------")
ENDPROC
// Work out if this player had the Collector's or Special edition versions of the game
// in last gen. Do this by querying the social club commerce leaderboard, or if we're online
// check cached player settings.
PROC MAINTAIN_LAST_GEN_PLAYER_SE_AND_CE_CHECKS_IN_SP()
// Are we online?
IF NETWORK_HAS_SOCIAL_CLUB_ACCOUNT()
AND NETWORK_IS_SIGNED_ONLINE()
AND ARE_PROFILE_SETTINGS_VALID()
// Has the leaderboard check already run?
IF NOT platformUpgradeLBCheckSP.bComplete
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Player is online with a Social Club account. Running server checks.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Player is online with a Social Club account. Running server checks.")
#ENDIF
// If the profile setting test has run this session clear it now we are
// running online tests. This will let it run again if we switch offline.
IF bProfileSettingCheckForLastGenDone
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Clearing profile setting test flag so it can run again.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Clearing profile setting test flag so it can run again.")
#ENDIF
bProfileSettingCheckForLastGenDone = FALSE
ENDIF
// First of all check this player is a last gen player.
IF GET_PLAYER_LAST_GEN_CHECK() = LAST_GEN_STATUS_NONE
CDEBUG3LN(DEBUG_LASTGEN, "<SE-CE> Waiting for server query...")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Waiting for server query...")
#ENDIF
ELIF GET_PLAYER_LAST_GEN_CHECK() = LAST_GEN_STATUS_FAILED
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> The last gen check failed this session.")
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Giving up online test but checking profile settings.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] The last gen check failed this session.")
PRINTLN_FINAL("[LASTGEN][SE-CE] Giving up online test but checking profile settings.")
#ENDIF
platformUpgradeLBCheckSP.bComplete = TRUE
bDoProfileSettingCheckForLastGen = TRUE
ELIF GET_PLAYER_LAST_GEN_CHECK() = LAST_GEN_STATUS_IS_NOT_LAST_GEN
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> The player wasn't a last gen player. Nothing to do.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] The player wasn't a last gen player. Nothing to do.")
#ENDIF
platformUpgradeLBCheckSP.bComplete = TRUE
// Player has a last gen account.
ELSE
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> The player is a last gen player. Checking if we have the required data to run leaderboard checks...")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] The player is a last gen player. Checking if we have the required data to run leaderboard checks...")
#ENDIF
// Do we have the information we need to query leaderboards?
IF (g_struct_Save_transfer_data_PS3.m_totalProgressMadeInSp <= 0
OR IS_STRING_NULL_OR_EMPTY(g_struct_Save_transfer_data_PS3.m_gamerHandle))
AND (g_struct_Save_transfer_data_XBOX360.m_totalProgressMadeInSp <= 0
OR IS_STRING_NULL_OR_EMPTY(g_struct_Save_transfer_data_XBOX360.m_gamerHandle))
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Data not present. Doing nothing this pass.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Data not present. Doing nothing this pass.")
#ENDIF
ELSE
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Data is present. Running leaderboard check.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Data is present. Running leaderboard check.")
#ENDIF
// We have the information we need. Let's query the leaderboard.
// This will update g_iPlayerHasLastGenSpecialContentBitset for us.
IF RUN_PLATFORM_UPGRADE_LB_CHECKS(platformUpgradeLBCheckSP, TRUE)
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Lastgen special content query complete.")
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> -----------------------------------------------")
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Lastgen PS3 Collectors Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_PS3_COLLECTORS), "TRUE", "FALSE"))
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Lastgen PS3 Special Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_PS3_SPECIAL), "TRUE", "FALSE"))
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Lastgen 360 Collectors Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_360_COLLECTORS), "TRUE", "FALSE"))
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Lastgen 360 Special Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_360_SPECIAL), "TRUE", "FALSE"))
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> -----------------------------------------------")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Lastgen special content query complete.")
PRINTLN_FINAL("[LASTGEN][SE-CE] -----------------------------------------------")
PRINTLN_FINAL("[LASTGEN][SE-CE] Lastgen PS3 Collectors Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_PS3_COLLECTORS), "TRUE", "FALSE"))
PRINTLN_FINAL("[LASTGEN][SE-CE] Lastgen PS3 Special Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_PS3_SPECIAL), "TRUE", "FALSE"))
PRINTLN_FINAL("[LASTGEN][SE-CE] Lastgen 360 Collectors Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_360_COLLECTORS), "TRUE", "FALSE"))
PRINTLN_FINAL("[LASTGEN][SE-CE] Lastgen 360 Special Edition: ", PICK_STRING(IS_BIT_SET(g_iPlayerHasLastGenSpecialContentBitset, BIT_LAST_GEN_SPECIAL_CONTENT_360_SPECIAL), "TRUE", "FALSE"))
PRINTLN_FINAL("[LASTGEN][SE-CE] -----------------------------------------------")
#ENDIF
platformUpgradeLBCheckSP.bComplete = TRUE //Flag not to run leaderboard check again.
bProfileSettingCheckForLastGenDone = TRUE //Flag not to run profile setting check again.
ENDIF
ENDIF
ENDIF
ENDIF
// We're offline. We can't run the leaderboard check.
ELSE
// If the online leaderboard check has run this session clean it up now we are
// offline. This will let it run again if we go online again.
IF platformUpgradeLBCheckSP.bComplete
OR platformUpgradeLBCheckSP.bSuccessful
OR platformUpgradeLBCheckSP.iTotalStage != 0
OR platformUpgradeLBCheckSP.iReadStage != 0
CPRINTLN(DEBUG_LASTGEN, "<SE-CE> Player is offline resetting the state of the online test so it runs again.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Player is offline resetting the state of the online test so it runs again.")
#ENDIF
RESET_PLATFORM_UPGRADE_LB_CHECK_STRUCT(platformUpgradeLBCheckSP)
ENDIF
// Do we have access to this user's profile settings?
IF NETWORK_IS_SIGNED_IN()
AND ARE_PROFILE_SETTINGS_VALID()
// We can query cached profile settings.
IF NOT bProfileSettingCheckForLastGenDone
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Player is offline but has valid profile. Running profile setting test.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Player is offline but has valid profile. Running profile setting test.")
#ENDIF
bDoProfileSettingCheckForLastGen = TRUE
ENDIF
// We're offline with no valid profile settings. There is nothing we can query. Remove access to the content.
ELSE
// If the profile setting test has run this session clear it now we are
// signed out. This will let it run again if we sign back in.
IF bProfileSettingCheckForLastGenDone
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Clearing profile setting test flag so it can run again.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Clearing profile setting test flag so it can run again.")
#ENDIF
bProfileSettingCheckForLastGenDone = FALSE
ENDIF
//Remove access to content.
g_iPlayerHasLastGenSpecialContentBitset = 0
ENDIF
ENDIF
// Handle requests to query the profile settings.
IF bDoProfileSettingCheckForLastGen
AND NOT bProfileSettingCheckForLastGenDone
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Profile setting test requested.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Profile setting test requested.")
#ENDIF
IF NETWORK_IS_SIGNED_IN()
AND ARE_PROFILE_SETTINGS_VALID()
CDEBUG1LN(DEBUG_LASTGEN, "<SE-CE> Updating lastget SE/CE unlock to cached profile setting.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("[LASTGEN][SE-CE] Updating lastget SE/CE unlock to cached profile setting.")
#ENDIF
g_iPlayerHasLastGenSpecialContentBitset = GET_PROFILE_SETTING(GAMER_HAS_SPECIALEDITION_CONTENT)
ENDIF
bDoProfileSettingCheckForLastGen = FALSE
bProfileSettingCheckForLastGenDone = TRUE
ENDIF
ENDPROC
#IF IS_NEXTGEN_BUILD
// Last gen gives you the weapons automatically from startup.sc - they are not unlocked in the flow like NG so no email need to be sent.
PROC MAINTAIN_DLC_WEAPON_EMAILS()
IF IS_MP_CHRISTMAS2_PACK_PRESENT()
//Proximity mine email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_PROXIMITY_MINE_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_TREVOR_3)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_10, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_PROXIMITY_MINE_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
//Homing missile email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_HOMING_MISSILE_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_EXILE_1)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_11, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_HOMING_MISSILE_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_MP_LUXE_PACK_PRESENT()
//Knuckle duster email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_KNUCKLE_DUSTER_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_ARMENIAN_3)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_12, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_KNUCKLE_DUSTER_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
//Combat PDW email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_COMBAT_PDW_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_HEIST_RURAL_PREP_1)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_13, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_COMBAT_PDW_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
//Marksman pistol email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MARKSMAN_PISTOL_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_SOLOMON_1)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_14, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MARKSMAN_PISTOL_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
IF IS_MP_LOWRIDER_PACK_PRESENT()
//Machete email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MACHETE_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_TREVOR_2)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_15, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MACHETE_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
//Machine Pistol email.
IF NOT GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MACHINE_PISTOL_EMAIL)
IF GET_MISSION_COMPLETE_STATE(SP_MISSION_FRANKLIN_1)
IF REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_WEAPON_STOCK_16, CT_AMBIENT, BIT_MICHAEL|BIT_FRANKLIN|BIT_TREVOR, CHAR_AMMUNATION, 20000, 10000)
SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_SENT_MACHINE_PISTOL_EMAIL, TRUE)
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
#ENDIF
PROC MAINTAIN_FEED_HIDE_WHILE_TRANSITIONING()
IF IS_PLAYER_SWITCH_IN_PROGRESS()
IF GET_FRAME_COUNT() % 30 = 0
CDEBUG1LN(DEBUG_INIT_SP, "Player switch in progress, hiding the feed.")
ENDIF
THEFEED_HIDE_THIS_FRAME()
ENDIF
ENDPROC
PROC INIT_DLC_WEAPON_VARS(DLC_WEAPON_UNLOCK_VARS &sWeaponVars)
sWeaponVars.iDLCWeaponCount = GET_NUM_DLC_WEAPONS()
sWeaponVars.iFirstDLCWeaponIndex = 45
#IF IS_DEBUG_BUILD
IF ENUM_TO_INT(WEAPON_DLC_BOTTLE_BIT_FIELD) != sWeaponVars.iFirstDLCWeaponIndex
ASSERTLN(" THE WEAPONTYPE BITSET ORDERING HAS CHANGED - The SC unlocks will be unordered - Change sWeaponVars.IFirstDLCWeaponIndex to the correct index - Speak to Rowan Jones! - main - INIT_DLC_WEAPON_VARS")
ENDIF
PRINT_WEAPON_NAMES_AND_HASHES()
#ENDIF
ENDPROC
PROC MAINTAIN_DLC_WEAPON_UNLOCKS( DLC_WEAPON_UNLOCK_VARS &sWeaponVars )
INT iWeaponID = GET_FRAME_COUNT() % sWeaponVars.iDLCWeaponCount
IF GET_DLC_WEAPON_DATA(iWeaponID, sWeaponVars.weaponData)
INT iWeaponUnlocked = IS_WEAPON_UNLOCKED_IN_FLOW( INT_TO_ENUM(WEAPON_TYPE, sWeaponVars.weaponData.m_nameHash) )
IF iWeaponUnlocked = 1
SET_DLC_WEAPON_SC_UNLOCKED_BIT( sWeaponVars )
ELIF iWeaponUnlocked = 0
CLEAR_DLC_WEAPON_SC_UNLOCKED_BIT( sWeaponVars )
ENDIF
ENDIF
ENDPROC
//===========================================================================================================
SCRIPT
CPRINTLN(DEBUG_INIT_SP, "Main.sc started.")
IF (HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP))
Script_Cleanup()
ENDIF
#IF IS_DEBUG_BUILD
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceCriminalEnterprisePremiumPackOn")
g_bForce_PREMIUM_true = TRUE
g_bForce_PREMIUM_false = FALSE
ENDIF
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceCriminalEnterprisePremiumPackOff")
g_bForce_PREMIUM_false = TRUE
g_bForce_PREMIUM_true = FALSE
ENDIF
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceCriminalEnterpriseStarterPackOn")
g_bForce_STARTER_true = TRUE
g_bForce_STARTER_false = FALSE
ENDIF
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceCriminalEnterpriseStarterPackOff")
g_bForce_STARTER_false = TRUE
g_bForce_STARTER_true = FALSE
ENDIF
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceHackerTruckOn")
g_bForce_HACKER_TRUCK_true = TRUE
g_bForce_HACKER_TRUCK_false = FALSE
ENDIF
IF GET_COMMANDLINE_PARAM_EXISTS("sc_ForceHackerTruckOff")
g_bForce_HACKER_TRUCK_false = TRUE
g_bForce_HACKER_TRUCK_true = FALSE
ENDIF
#ENDIF
// Immediately set this FALSE now we know SP is running and we need to verify the character
// model the player is loading. MAINTAIN_CHARACTER_MODEL_CHECK() will set this TRUE again.
CPRINTLN(DEBUG_INIT_SP, "Main flagged to run a character mode validation check.")
#IF USE_FINAL_PRINTS
PRINTLN_FINAL("<2140379> Main flagged to run a character mode validation check.")
#ENDIF
SET_CHARACTER_MODEL_CHECK_DONE(FALSE)
CLEAR_ALL_PRIORITY_HUD_ELEMENTS()
CPRINTLN(DEBUG_INIT_SP, "Main.sc started waiting for Initial.sc")
REQUEST_AND_LAUNCH_INITIAL_SCRIPT_WITH_WAIT()
WHILE (GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(HASH("initial")) > 0)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_INIT, "Main.sc finished waiting for Initial.sc")
#IF IS_DEBUG_BUILD
//Validate enums. Code request TODO #252153.
VALIDATE_ENUM_VALUES()
OUTPUT_SCRIPT_IMAGE_CONFIGURATION_TO_CONSOLE_LOG()
main_widget = START_WIDGET_GROUP("main.sc")
STOP_WIDGET_GROUP()
#ENDIF
INITIALISE_SCRIPT_LAUNCH_CHECKS( #IF IS_DEBUG_BUILD main_widget #ENDIF )
BANK_INITIALISE_STARTING_BALANCES()
SETUP_SLOW_ZONE_DATA(sSlowZoneVars)
INIT_DLC_WEAPON_VARS( sDLCWeaponVars )
// Keith 15/7/13: To clear out any cross-session and joblist data when SP starts
Initialise_SP_Joblist()
// Calculate the initial target values for the PS4 activity feed.
IF IS_PLAYSTATION_PLATFORM()
ACTIVITY_FEED_INITIALISE_TARGET_VALUES(sActivityFeedVars)
ENDIF
// Unlock Director Mode characters for the current save progress.
// Required when loading an old save after just patching in Director Mode.
#IF FEATURE_SP_DLC_DIRECTOR_MODE
CPRINTLN(DEBUG_DIRECTOR, "Unlocking Director Mode features as SP starts.")
UNLOCK_ALL_DIRECTOR_PROGRESS_FOR_CURRENT_PLAYTHROUGH()
#ENDIF
DO_MISSION_STAT_INITIAL_CONFIGURATION()
CHECK_REPLAY_MISSION_STAT_STATE()
SET_CASINO_ROOFTOP_STATIC_EMITTERS(FALSE)
// Check strip club is unlocked.
IF g_savedGlobals.sFlow.missionSavedData[SP_MISSION_ARMENIAN_1].completed
AND NOT (GET_MISSION_FLOW_BITSET_BIT_STATE(FLOWBITSET_MINIGAME_ACTIVE, ENUM_TO_INT(MINIGAME_STRIPCLUB)))
CPRINTLN(DEBUG_INIT_SP, "Strip club locked when it shouldn't be on startup! Unlocking now.")
SET_MISSION_FLOW_BITSET_BIT_STATE(FLOWBITSET_MINIGAME_ACTIVE, ENUM_TO_INT(MINIGAME_STRIPCLUB), TRUE)
SET_STATIC_BLIP_ACTIVE_STATE(STATIC_BLIP_MINIGAME_STRIPCLUB, TRUE)
ENDIF
// enable prospero activity processing
#IF FEATURE_GEN9_STANDALONE
SET_ACTIVITY_SCRIPT_ROUTING_ENABLED(TRUE)
#ENDIF
//**************************
// MAIN LOOP
//**************************
// This should be the last thing done before the main loop launches
g_isSPMainInitialised = TRUE
CPRINTLN(DEBUG_INIT_SP, "GTA5 starting main loop.")
WHILE (TRUE)
iGameTime = GET_GAME_TIMER()
#IF IS_DEBUG_BUILD
IF g_flowUnsaved.bUpdatingGameflow //Prevents a debug menu issue with blip flashing
g_bBlipDebugPreventFlash = TRUE
ENDIF
#ENDIF
#IF IS_DEBUG_BUILD
RUN_CORE_SP_THREAD_CHECKS()//
#ENDIF
PROCESS_SP_HELP_MESSAGES(sFlowHelpMessageVars) //Help text displaying.
UPDATE_CUTSCENE_CONTROL() //Off mission cutscene loading handshake system.
DO_SCRIPT_LAUNCH_CHECKS(sScriptLaunchVars) //Script thread relaunch checks.
MAINTAIN_CACHE_CLEARING() //added for maintenance of leaderboard cache Let me know if there are any issues. Conor McGuire
MAINTAIN_FREE_PLAYER_PARACHUTE()
MAINTAIN_FAMILY_CONTROLLER(sFriendControllerVars #IF IS_DEBUG_BUILD , main_widget #ENDIF )
PRIVATE_Safe_For_Cutscene_Update()
PRIVATE_Cutscene_Failsafe_Update()
UPDATE_SLOW_ZONES(sSlowZoneVars) //Forces the player to walk in specific areas of the map.
MAINTAIN_MINIGAME_BLIP_STATES()
MAINTAIN_GAUNTLET_SUPPRESSION()
MAINTAIN_FIRST_PERSON_COVER_HELP()
MAINTAIN_VEHICLE_DUCK_HELP()
MAINTAIN_LAST_GEN_PLAYER_SE_AND_CE_CHECKS_IN_SP() //Make sure we detect if a player had SE/CE editions in last gen.
MAINTAIN_DLC_WEAPON_UNLOCKS( sDLCWeaponVars )
IF IS_PLAYSTATION_PLATFORM()
MAINTAIN_ACTIVITY_FEED_CHECKS(sActivityFeedVars) //The PS4 "What's New" Feed.
ENDIF
UPDATE_PROPERTIES_SYSTEM() //SP only for now.
IF IS_XBOX_PLATFORM()
MANAGE_MAGIC_MOMENTS() //SP only for now
ENDIF
// Keith 15/7/13: Every frame maintenance of cross-session invites being listed and accepted on the joblist (minimal processing if no invites)
Maintain_SP_Joblist()
MAINTAIN_MISSION_RECORDING_CLEANUP_CHECKS()
// Run updates in here on a 1 second tick.
IF iGameTime > iOneSecondTimer
BANK_CHECK_FOR_CODE_DEPOSITS() //Keep singleplayer bank balances
PRIVATE_Maintain_Phone_Sleep_Mode_Flag()
MANAGE_SUB_CRUSH_DEPTH() //Kills player if in sub and it has crushed.
MAINTAIN_JIMMY_VEHICLE_SUPPRESSED_CHECKS()
//Validate our SP character model in case it has been hacked. #1945436
MAINTAIN_SP_CHARACTER_MODEL_CHECK()
iOneSecondTimer = iGameTime + 1000
ENDIF
// Run updates in here on a 5 second tick.
IF iGameTime > iFiveSecondTimer
MAINTAIN_FACEBOOK_ACCOUNT_LINKED_FEED()
MAINTAIN_FACEBOOK_ALL_VEHICLES_DRIVEN_CHECKS()
MAINTAIN_FACEBOOK_MAP_REVEALED_CHECKS()
#IF IS_NEXTGEN_BUILD
MAINTAIN_DLC_WEAPON_EMAILS() // MAINTAIN_CHRISTMAS2_DLC_WEAPON_EMAILS()
#ENDIF
iFiveSecondTimer = iGameTime + 5000
ENDIF
MAINTAIN_INCOMING_PLAYER_CALLS()
//MAINTAIN_DIRECTOR_LOCATION_REVEALED_CHECKS(eDirectorLocation) // Removed for B* 2412706
NOIR_UPDATE_EFFECTS(noirData) // updates film noir effects for murder mystery
MAINTAIN_FEED_HIDE_WHILE_TRANSITIONING()
WAIT(0)
ENDWHILE
ENDSCRIPT