445 lines
15 KiB
Python
Executable File
445 lines
15 KiB
Python
Executable File
//╒═════════════════════════════════════════════════════════════════════════════╕
|
|
//│ Author: Ben Rollinson Date: 13/05/11 │
|
|
//╞═════════════════════════════════════════════════════════════════════════════╡
|
|
//│ │
|
|
//│ Flow Autoplay System │
|
|
//│ │
|
|
//│ A light-weight system that runs alongside the flow controller │
|
|
//│ and automatically steps through the game flow while logging │
|
|
//│ progress. This is done by simulating J-skip and Q-skip key │
|
|
//│ presses on the keyboard. │
|
|
//│ │
|
|
//╘═════════════════════════════════════════════════════════════════════════════╛
|
|
|
|
USING "rage_builtins.sch"
|
|
USING "globals.sch"
|
|
USING "commands_script.sch"
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
USING "commands_cutscene.sch"
|
|
USING "flow_reset_GAME.sch"
|
|
|
|
|
|
CONST_INT SIMULATE_KEYPRESS_DELAY_TIME 6000 //How long does the script wait between simulated skip keypresses (in milliseconds).
|
|
CONST_INT SKIP_LIMIT 30 //How many skips without flow progress before the system decides the flow is stuck.
|
|
|
|
STRING m_strFile = "autoplay.log"
|
|
STRING m_strPath = "X:/gta5/build/dev/"
|
|
|
|
BOOL m_bResetPlaythrough = FALSE
|
|
BOOL bShownCutMessage = FALSE
|
|
INT m_iSimulateDebugPressTimer
|
|
INT m_iSkipWithoutChangeCounter = 0
|
|
INT m_iPlaythroughCount = 0
|
|
TEXT_LABEL_31 m_txtLastRunningMissionName = "NO MISSION"
|
|
TEXT_LABEL_63 m_txtLogString
|
|
TEXT_LABEL_63 m_txtAutoplayMessage
|
|
enumCharacterList m_eLastChar = CHAR_BLANK_ENTRY
|
|
WIDGET_GROUP_ID widgetGroup
|
|
BOOL bPauseTimer = FALSE
|
|
|
|
|
|
//Log the start of a new session.
|
|
PROC Log_New_Autoplay_Session()
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("---------------------------------------------------",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
m_txtLogString = "[NEW AUTOPLAY SESSION | SKIP_LIMIT="
|
|
m_txtLogString += SKIP_LIMIT
|
|
m_txtLogString += "]"
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE(m_txtLogString, m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
ENDPROC
|
|
|
|
|
|
//Log the start of a new playthrough attempt.
|
|
PROC Log_New_Playthrough()
|
|
m_iPlaythroughCount++
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("---------------------------------------------------",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
m_txtLogString = "[PLAYTHROUGH #"
|
|
m_txtLogString += m_iPlaythroughCount
|
|
m_txtLogString += "]"
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE(m_txtLogString, m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
ENDPROC
|
|
|
|
|
|
//Log a single simulated keypress.
|
|
PROC Log_Skip_Keypress()
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE(".",m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
ENDPROC
|
|
|
|
|
|
PROC Draw_Autoplay_Message()
|
|
DRAW_RECT(0.5, 0.26, 0.22, 0.09, 0, 0, 0, 180)
|
|
|
|
SET_TEXT_FONT(FONT_STANDARD)
|
|
SET_TEXT_SCALE (0.4, 0.42)
|
|
SET_TEXT_WRAP(0.0, 1.0)
|
|
SET_TEXT_DROPSHADOW (0,0,0,0,255)
|
|
SET_TEXT_COLOUR(255,255,255,85)
|
|
SET_TEXT_EDGE (0,0,0,0,255)
|
|
SET_TEXT_PROPORTIONAL (FALSE)
|
|
SET_TEXT_JUSTIFICATION(FONT_CENTRE)
|
|
DISPLAY_TEXT_WITH_LITERAL_STRING(0.5, 0.225, "STRING", "AutoPlay")
|
|
|
|
SET_TEXT_FONT(FONT_STANDARD)
|
|
SET_TEXT_SCALE (0.52, 0.57)
|
|
SET_TEXT_WRAP(0.0, 1.0)
|
|
SET_TEXT_DROPSHADOW (0,0,0,0,225)
|
|
SET_TEXT_COLOUR(0,200,0,180)
|
|
SET_TEXT_EDGE (0,0,0,0,255)
|
|
SET_TEXT_PROPORTIONAL (FALSE)
|
|
SET_TEXT_JUSTIFICATION(FONT_CENTRE)
|
|
DISPLAY_TEXT_WITH_LITERAL_STRING(0.5, 0.255, "STRING", m_txtAutoplayMessage)
|
|
ENDPROC
|
|
|
|
PROC SETUP_FOR_RAGE_WIDGETS()
|
|
widgetGroup = START_WIDGET_GROUP("Auto-PT Timer")
|
|
ADD_WIDGET_BOOL("Pause AutoSkip Timer", bPauseTimer)
|
|
STOP_WIDGET_GROUP()
|
|
ENDPROC
|
|
|
|
PROC CLEAN_UP_WIDGET()
|
|
|
|
IF DOES_WIDGET_GROUP_EXIST(widgetGroup)
|
|
DELETE_WIDGET_GROUP(widgetGroup)
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
#ENDIF
|
|
|
|
|
|
SCRIPT
|
|
|
|
#IF IS_DEBUG_BUILD
|
|
|
|
g_bFlowMetricZonesEnabled = TRUE //Output metrics by default - had to turn this off due to the metrics stuff asserting
|
|
g_bDebugBlockAutosaves = TRUE //Disable autosaving by default.
|
|
|
|
//Check command line to see if we want a smoketest running.
|
|
g_bFlowSmokeTestEnabled = ARE_STRINGS_EQUAL(GET_COMMANDLINE_PARAM("smoketest"),"codebuilder_stats")
|
|
|
|
SET_PROFILING_OF_THIS_SCRIPT(TRUE)
|
|
|
|
//Make the player invincible.
|
|
FAKE_KEY_PRESS(KEY_V)
|
|
|
|
//Flag a global to inform other systems that the autoplay system is active.
|
|
g_bFlowAutoplayInProgress = TRUE
|
|
|
|
//Do we need to wait for the smoketest to be ready?
|
|
IF g_bFlowSmoketestEnabled
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Waiting for smoketest to start.")
|
|
WHILE NOT SMOKETEST_STARTED()
|
|
WAIT(0)
|
|
ENDWHILE
|
|
CPRINTLN(DEBUG_AUTOPLAY, "New smoketest started.")
|
|
ENDIF
|
|
|
|
//Put the game into gameflow mode and activate the prologue strand.
|
|
Activate_Gameflow_At_First_Strand()
|
|
|
|
Log_New_Autoplay_Session()
|
|
Log_New_Playthrough()
|
|
|
|
SETUP_FOR_RAGE_WIDGETS()
|
|
|
|
WHILE TRUE
|
|
|
|
//Automatically clear wanted level if we have one. (Cop car check is so we can autoplay past Michael's ambient Amanda mission
|
|
IF IS_PLAYER_PLAYING(PLAYER_ID()) AND NOT IS_PED_IN_ANY_POLICE_VEHICLE(PLAYER_PED_ID())
|
|
IF GET_PLAYER_WANTED_LEVEL(PLAYER_ID()) > 0
|
|
SET_PLAYER_WANTED_LEVEL(PLAYER_ID(), 0)
|
|
SET_PLAYER_WANTED_LEVEL_NOW(PLAYER_ID())
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// Hacks to get around various autoplay issues
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
|
|
// Stop Amanda getting killed if we're playing Michael's Amanda Event
|
|
IF IS_PED_IN_ANY_POLICE_VEHICLE(PLAYER_PED_ID())
|
|
|
|
VEHICLE_INDEX mVeh = GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID())
|
|
IF NOT IS_ENTITY_DEAD(mVeh)
|
|
IF NOT IS_VEHICLE_SEAT_FREE(mVeh, VS_BACK_RIGHT)
|
|
PED_INDEX mAmanda = GET_PED_IN_VEHICLE_SEAT(mVeh, VS_BACK_RIGHT)
|
|
IF NOT IS_ENTITY_DEAD(mAmanda)
|
|
SET_ENTITY_PROOFS(mAmanda, TRUE, TRUE, TRUE, TRUE, TRUE)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
IF m_iSimulateDebugPressTimer < GET_GAME_TIMER()
|
|
|
|
//Is a mocap cutscene running?
|
|
IF IS_CUTSCENE_PLAYING()
|
|
IF NOT bShownCutMessage
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Stopping Cutscene")
|
|
bShownCutMessage = TRUE
|
|
ENDIF
|
|
STOP_CUTSCENE()
|
|
ELSE
|
|
IF bShownCutMessage = TRUE
|
|
bShownCutMessage = FALSE
|
|
ENDIF
|
|
|
|
IF NOT IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_EVENT)
|
|
//Simulate a J-skip, we're on mission or off-mission and not on an RE.
|
|
CPRINTLN(DEBUG_AUTOPLAY, "J-skipping...", m_iSkipWithoutChangeCounter+1 )
|
|
FAKE_KEY_PRESS(KEY_J)
|
|
ELSE
|
|
//Simulate S-pass if we're offmission on an RE.
|
|
CPRINTLN(DEBUG_AUTOPLAY, "S-skipping...", m_iSkipWithoutChangeCounter+1)
|
|
FAKE_KEY_PRESS(KEY_S)
|
|
ENDIF
|
|
|
|
//If we're off mission and the phone has been left on screen, put it away.
|
|
IF NOT IS_CURRENTLY_ON_MISSION_TO_TYPE()
|
|
IF IS_PHONE_ONSCREEN()
|
|
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
|
|
HANG_UP_AND_PUT_AWAY_PHONE()
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//496024: If the player is off mission in water set them to some safe place out of water.
|
|
IF NOT IS_ENTITY_DEAD(PLAYER_PED_ID())
|
|
IF IS_ENTITY_IN_WATER(PLAYER_PED_ID())
|
|
SET_ENTITY_COORDS(PLAYER_PED_ID(), << -325.4346, 1365.6914, 346.2589 >>)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//Log this key press.
|
|
Log_Skip_Keypress()
|
|
|
|
//Increment the skip counter.
|
|
m_iSkipWithoutChangeCounter++
|
|
|
|
m_iSimulateDebugPressTimer = GET_GAME_TIMER() + SIMULATE_KEYPRESS_DELAY_TIME
|
|
|
|
ENDIF
|
|
ELSE
|
|
|
|
IF bPauseTimer
|
|
m_iSimulateDebugPressTimer = GET_GAME_TIMER() + SIMULATE_KEYPRESS_DELAY_TIME
|
|
ENDIF
|
|
|
|
IF IS_CURRENTLY_ON_MISSION_TO_TYPE()
|
|
//Update how long until the next J-skip.
|
|
m_txtAutoplayMessage = "Simulating J-skip in "
|
|
m_txtAutoplayMessage += CEIL(TO_FLOAT(m_iSimulateDebugPressTimer - GET_GAME_TIMER()) / 1000.0)
|
|
|
|
ELIF IS_CURRENTLY_ON_MISSION_OF_TYPE(MISSION_TYPE_RANDOM_EVENT)
|
|
// Update how long until the next S-skip
|
|
m_txtAutoplayMessage = "Simulating S-skip in "
|
|
m_txtAutoplayMessage += CEIL(TO_FLOAT(m_iSimulateDebugPressTimer - GET_GAME_TIMER()) / 1000.0)
|
|
ELSE
|
|
//Update how long until the next Off-skip.
|
|
m_txtAutoplayMessage = "Simulating Off-skip in "
|
|
m_txtAutoplayMessage += CEIL(TO_FLOAT(m_iSimulateDebugPressTimer - GET_GAME_TIMER()) / 1000.0)
|
|
ENDIF
|
|
ENDIF
|
|
/*
|
|
// Skip any missions that we know crash the autoplay script.
|
|
IF ARE_STRINGS_EQUAL(g_txtFlowAutoplayRunningMission, "M_FAM1")
|
|
OR ARE_STRINGS_EQUAL(g_txtFlowAutoplayRunningMission, "M_LS1b") // Skipping these because they always crash.
|
|
OR ARE_STRINGS_EQUAL(g_txtFlowAutoplayRunningMission, "M_ARM1")
|
|
IF NOT bShownCutMessage
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Skipping this mission because it always crashes - ", g_txtFlowAutoplayRunningMission)
|
|
ENDIF
|
|
FAKE_KEY_PRESS(KEY_S)
|
|
ELSE
|
|
IF bShownCutMessage
|
|
bShownCutMessage = FALSE
|
|
ENDIF
|
|
ENDIF
|
|
*/
|
|
|
|
|
|
//Have we reached our skip limit? Is the flow stuck?
|
|
IF m_iSkipWithoutChangeCounter >= SKIP_LIMIT
|
|
|
|
IF IS_CURRENTLY_ON_MISSION_TO_TYPE()
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Hit J-skip limit!")
|
|
|
|
//Too many J-skips. Log this problem and try and auto-pass the mission.
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("[J-skips stuck!][Attempting S-skip]",m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
|
|
//Simulate an S-skip to try and auto-pass this mission.
|
|
FAKE_KEY_PRESS(KEY_S)
|
|
WAIT(1000)
|
|
|
|
//Did the S-skip work?
|
|
IF ARE_STRINGS_EQUAL(m_txtLastRunningMissionName, g_txtFlowAutoplayRunningMission)
|
|
//No. Log this and reset the playthrough.
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("[S-skip failed]",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
m_bResetPlaythrough = TRUE
|
|
ELSE
|
|
//Yes, flow change noted. Reset counter.
|
|
m_iSkipWithoutChangeCounter = 0
|
|
ENDIF
|
|
ELSE
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Hit Off-mission skip limit!")
|
|
|
|
//Too many Off-mission skips. Log this problem and then reset the playthrough.
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("[Off-skips stuck!]",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
m_bResetPlaythrough = TRUE
|
|
ENDIF
|
|
ELSE
|
|
IF m_iSkipWithoutChangeCounter >= SKIP_LIMIT-10
|
|
IF IS_SCREEN_FADED_OUT() AND NOT IS_SCREEN_FADING_IN()
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Fading the screen in")
|
|
DO_SCREEN_FADE_IN(1000)
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
|
|
//Check if the current running mission has changed.
|
|
IF NOT ARE_STRINGS_EQUAL(m_txtLastRunningMissionName, g_txtFlowAutoplayRunningMission)
|
|
//The current running mission has changed. Log this.
|
|
IF ARE_STRINGS_EQUAL(g_txtFlowAutoplayRunningMission, "NO MISSION")
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Noted that mission ", m_txtLastRunningMissionName, " just ended.")
|
|
|
|
//Was the mission passed or failed?
|
|
IF g_bFlowAutoplayJustPassed
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("[Passed]",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
ELSE
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE("[Failed]",m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
ENDIF
|
|
|
|
//Flow change noted. Reset counter.
|
|
m_iSkipWithoutChangeCounter = 0
|
|
ELSE
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Noted that mission ", g_txtFlowAutoplayRunningMission, " just started.")
|
|
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
SAVE_NEWLINE_TO_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
m_txtLogString = "["
|
|
m_txtLogString += g_txtFlowAutoplayRunningMission
|
|
m_txtLogString += "]"
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE(m_txtLogString,m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
|
|
//Flow change noted. Reset counter.
|
|
m_iSkipWithoutChangeCounter = 0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//Check if the current character has changed.
|
|
enumCharacterList eCurrentChar = GET_CURRENT_PLAYER_PED_ENUM()
|
|
IF m_eLastChar <> eCurrentChar
|
|
//Character has changed. Log who we have switched to.
|
|
OPEN_NAMED_DEBUG_FILE(m_strPath, m_strFile)
|
|
m_txtLogString = "["
|
|
|
|
SWITCH(eCurrentChar)
|
|
CASE CHAR_MICHAEL
|
|
m_txtLogString += "M"
|
|
BREAK
|
|
CASE CHAR_FRANKLIN
|
|
m_txtLogString += "F"
|
|
BREAK
|
|
CASE CHAR_TREVOR
|
|
m_txtLogString += "T"
|
|
BREAK
|
|
DEFAULT
|
|
m_txtLogString += "Invalid Character Switch!"
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
m_txtLogString += "]"
|
|
SAVE_STRING_TO_NAMED_DEBUG_FILE(m_txtLogString,m_strPath, m_strFile)
|
|
CLOSE_DEBUG_FILE()
|
|
|
|
//Remember the new current character.
|
|
m_eLastChar = eCurrentChar
|
|
ENDIF
|
|
|
|
//Has a reset been requested?
|
|
IF m_bResetPlaythrough
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Restting the playthrough.")
|
|
|
|
m_iSkipWithoutChangeCounter = 0
|
|
m_eLastChar = CHAR_BLANK_ENTRY
|
|
m_bResetPlaythrough = FALSE
|
|
|
|
//End smoketest if one is running.
|
|
IF g_bFlowSmoketestEnabled
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Ending smoketest for this playthrough.")
|
|
SMOKETEST_END()
|
|
ENDIF
|
|
|
|
//Deactivate the game flow.
|
|
g_savedGlobals.sFlow.isGameflowActive = FALSE
|
|
|
|
//Trigger a singleplayer force cleanup as part of the reset procedure.
|
|
FORCE_CLEANUP(FORCE_CLEANUP_FLAG_DEBUG_MENU)
|
|
|
|
//Log the start of the new playthrough.
|
|
Log_New_Playthrough()
|
|
|
|
//Do we need to wait for the smoketest to be ready?
|
|
IF g_bFlowSmoketestEnabled
|
|
CPRINTLN(DEBUG_AUTOPLAY, "Waiting for smoketest to start.")
|
|
WHILE NOT SMOKETEST_STARTED()
|
|
WAIT(0)
|
|
ENDWHILE
|
|
CPRINTLN(DEBUG_AUTOPLAY, "New smoketest started.")
|
|
ENDIF
|
|
|
|
|
|
//Reactivate gameflow at the beginning.
|
|
Activate_Gameflow_At_First_Strand()
|
|
ENDIF
|
|
|
|
//CLEAN_UP_WIDGET()
|
|
|
|
//Store current running mission index as the last before stepping to the next frame.
|
|
m_txtLastRunningMissionName = g_txtFlowAutoplayRunningMission
|
|
|
|
//Draw the autoplay message box.
|
|
Draw_Autoplay_Message()
|
|
|
|
WAIT(0)
|
|
|
|
ENDWHILE
|
|
#ENDIF
|
|
|
|
//Will never be reached in debug mode.
|
|
//Clean up immediately in release mode.
|
|
TERMINATE_THIS_THREAD()
|
|
|
|
ENDSCRIPT
|
|
|