//╒═════════════════════════════════════════════════════════════════════════════╕ //│ Author: Ben Rollinson Date: 19/08/11 │ //╞═════════════════════════════════════════════════════════════════════════════╡ //│ │ //│ Finale Strand - Endgame Script │ //│ │ //│ Handles respawning the player as their most played character │ //│ after the final credits. │ //│ │ //╘═════════════════════════════════════════════════════════════════════════════╛ //Compile out Title Update changes to header functions. //Must be before includes. //CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R. // Includes USING "rage_builtins.sch" USING "globals.sch" USING "commands_stats.sch" USING "selector_public.sch" USING "player_ped_public.sch" USING "respawn_location_private.sch" USING "savegame_public.sch" USING "vehicle_gen_public.sch" USING "player_ped_scenes.sch" USING "Finale_Shrink.sch" USING "script_usecontext.sch" USING "social_public.sch" USING "mission_repeat_public.sch" // Enums ENUM STAGE_LETTER SS_INIT, SS_UPDATE, SS_CLEANUP ENDENUM // Psychology report STAGE_LETTER eLetterStage = SS_INIT SCALEFORM_INDEX siLetter STRUCT_PSYCH_DATA sUploadData INT iLoadStage BOOL bSuccess SIMPLE_USE_CONTEXT ucInstructions #IF IS_DEBUG_BUILD USING "flow_debug_game.sch" #ENDIF /// PURPOSE: /// Cancel all communications PROC Cancel_All_Comms_For_Player_Character(enumCharacterList paramPlayer) CPRINTLN(DEBUG_FLOW, " Cleaning out any communications being sent only to ", GET_CHARSHEET_DISPLAY_STRING_FROM_CHARSHEET(paramPlayer), ".") //Create a bitset with only this character's bit set. INT iTestBitset = 0 SET_BIT(iTestBitset, ENUM_TO_INT(paramPlayer)) //Remove calls. INT iCommIndex = 0 WHILE iCommIndex < g_savedGlobals.sCommsControlData.iNoQueuedCalls IF g_savedGlobals.sCommsControlData.sQueuedCalls[iCommIndex].sCommData.iPlayerCharBitset = iTestBitset CPRINTLN(DEBUG_FLOW, " Removing call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedCalls[iCommIndex].sCommData.eID), "..") CANCEL_COMMUNICATION(g_savedGlobals.sCommsControlData.sQueuedCalls[iCommIndex].sCommData.eID) iCommIndex = 0 ELSE iCommIndex++ ENDIF ENDWHILE //Remove chat calls. iCommIndex = 0 WHILE iCommIndex < g_savedGlobals.sCommsControlData.iNoChatCalls IF g_savedGlobals.sCommsControlData.sChatCalls[iCommIndex].sCommData.iPlayerCharBitset = iTestBitset CPRINTLN(DEBUG_FLOW, " Removing chat call ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sChatCalls[iCommIndex].sCommData.eID), ".") CANCEL_COMMUNICATION(g_savedGlobals.sCommsControlData.sChatCalls[iCommIndex].sCommData.eID) iCommIndex = 0 ELSE iCommIndex++ ENDIF ENDWHILE //Remove texts. iCommIndex = 0 WHILE iCommIndex < g_savedGlobals.sCommsControlData.iNoQueuedTexts IF g_savedGlobals.sCommsControlData.sQueuedTexts[iCommIndex].sCommData.iPlayerCharBitset = iTestBitset CPRINTLN(DEBUG_FLOW, " Removing text ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedTexts[iCommIndex].sCommData.eID), ".") CANCEL_COMMUNICATION(g_savedGlobals.sCommsControlData.sQueuedTexts[iCommIndex].sCommData.eID) iCommIndex = 0 ELSE iCommIndex++ ENDIF ENDWHILE //Remove emails. iCommIndex = 0 WHILE iCommIndex < g_savedGlobals.sCommsControlData.iNoQueuedEmails IF g_savedGlobals.sCommsControlData.sQueuedEmails[iCommIndex].sCommData.iPlayerCharBitset = iTestBitset CPRINTLN(DEBUG_FLOW, " Removing email ", GET_COMM_ID_DEBUG_STRING(g_savedGlobals.sCommsControlData.sQueuedEmails[iCommIndex].sCommData.eID), ".") CANCEL_COMMUNICATION(g_savedGlobals.sCommsControlData.sQueuedEmails[iCommIndex].sCommData.eID) iCommIndex = 0 ELSE iCommIndex++ ENDIF ENDWHILE ENDPROC /// PURPOSE: /// Disables access to pause menu and hides HUD elements /// whilst shrink letter is onscreen PROC HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() DISABLE_CONTROL_ACTION(FRONTEND_CONTROL, INPUT_FRONTEND_PAUSE) HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_AREA_NAME) HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_VEHICLE_NAME) HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_DISTRICT_NAME) HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_STREET_NAME) DISABLE_CELLPHONE_THIS_FRAME_ONLY() ENDPROC /// PURPOSE: /// Handles the creation and display the shrink letter after the main credits FUNC BOOL DO_LETTER_UPDATE SWITCH eLetterStage CASE SS_INIT // Fade out audio START_AUDIO_SCENE("END_CREDITS_SHRINKS_NOTE_SCENE") // Load shrink letter siLetter = REQUEST_SCALEFORM_MOVIE("PSYCHOLOGY_REPORT") WHILE (NOT HAS_SCALEFORM_MOVIE_LOADED(siLetter)) HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE // Load audio WHILE NOT LOAD_STREAM("Office_Background_Stream", "SHRINK_SOUNDS") HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE // Load shrink report text REQUEST_ADDITIONAL_TEXT("REPORT", MISSION_TEXT_SLOT) WHILE NOT HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT) HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE // Add gamertag BEGIN_SCALEFORM_MOVIE_METHOD(siLetter, "SET_PLAYER_NAME") // B*2023149 - seperate "patient:" from gamertag BEGIN_TEXT_COMMAND_SCALEFORM_STRING("STRING") ADD_TEXT_COMPONENT_SUBSTRING_TEXT_LABEL("PATIENT") CPRINTLN(DEBUG_FLOW, " shrink letter - set PATIENT string ") END_TEXT_COMMAND_SCALEFORM_STRING() // insert the gamertag BEGIN_TEXT_COMMAND_SCALEFORM_STRING("GAMERTAG") IF NETWORK_IS_SIGNED_IN() ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(GET_PLAYER_NAME(PLAYER_ID())) CPRINTLN(DEBUG_FLOW, " shrink letter - set GAMERTAG string using player gamertag") ELSE ADD_TEXT_COMPONENT_SUBSTRING_TEXT_LABEL("ACCNA_MIKE") CPRINTLN(DEBUG_FLOW, " shrink letter - set GAMERTAG string using ACCNA_MIKE for player name - not signed in") ENDIF END_TEXT_COMMAND_SCALEFORM_STRING() END_SCALEFORM_MOVIE_METHOD() // Holds individual line of shrink letter TEXT_LABEL_15 str // Build shrink letter BEGIN_SCALEFORM_MOVIE_METHOD(siLetter, "SET_LETTER_TEXT") // From the office of Dr Isiah Friedlander... SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("HEADER_1") SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING("HEADER_2") str = GET_SHRINK_INTRO(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_STORY_CHOICE(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_MOST_PLAYED_CHAR(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_MONEY_SPENT(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_VISITED_STRIP_CLUBS(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_USED_PROSTITUTES(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_FAMILY_ATTENTION(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_PLAYED_STOCKMARKET(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_KILLED_PEDS(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_STOLE_VEHICLES(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_PERFORMED_YOGA(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_FITNESS(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_RANDOM_CHARS(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_COLLECTABLES(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) str = GET_SHRINK_SUMMARY(sUploadData) SCALEFORM_MOVIE_METHOD_ADD_PARAM_STRING(str) END_SCALEFORM_MOVIE_METHOD() // Upload data to the cloud! CPRINTLN(DEBUG_FLOW, " Attempting psychology report upload to the cloud...") WHILE NOT SAVE_OUT_PSYCH_DATA(iLoadStage, bSuccess, sUploadData) HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE #IF IS_DEBUG_BUILD IF bSuccess CPRINTLN(DEBUG_FLOW, " Upload successful!") ELSE CPRINTLN(DEBUG_FLOW, " Upload failed!") ENDIF #ENDIF // Setup - Continue (X) CLEANUP_SIMPLE_USE_CONTEXT(ucInstructions) INIT_SIMPLE_USE_CONTEXT(ucInstructions, FALSE, FALSE, TRUE, TRUE) ADD_SIMPLE_USE_CONTEXT_INPUT(ucInstructions, "CONTINUE", FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) SET_SIMPLE_USE_CONTEXT_FULLSCREEN(ucInstructions) SET_SIMPLE_USE_CONTEXT_MINIGAME_ATTACHED(ucInstructions) // Play the audio stream PLAY_STREAM_FRONTEND() // Fade screen back in for letter IF IS_SCREEN_FADED_OUT() IF NOT IS_SCREEN_FADING_IN() DO_SCREEN_FADE_IN(DEFAULT_FADE_TIME) ENDIF WHILE NOT IS_SCREEN_FADED_IN() HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_BEFORE_HUD) DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLetter,255,255,255,255) WAIT(0) ENDWHILE ENDIF // Post game psychology report upload and display on the feed. // IF FACEBOOK_CAN_POST_TO_FACEBOOK() // IF NOT IS_BIT_SET(g_savedGlobals.sSocialData.iFacebookPostsMadeBitset, ENUM_TO_INT(FBPOST_PSYCH_REPORT)) // CPRINTLN(DEBUG_FLOW, " Posting FACEBOOK_MILESTONE_PSYCH facebook message.") // SHOW_FACEBOOK_MILESTONE_FEED_MESSAGE(FACEBOOK_MILESTONE_PSYCH) // FACEBOOK_POST_COMPLETED_MILESTONE(FACEBOOK_MILESTONE_PSYCH) // SET_BIT(g_savedGlobals.sSocialData.iFacebookPostsMadeBitset, ENUM_TO_INT(FBPOST_PSYCH_REPORT)) // ENDIF // ENDIF // Prevent flicker HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_BEFORE_HUD) DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLetter, 255,255,255,255) eLetterStage = SS_UPDATE BREAK CASE SS_UPDATE // Render shrink letter SET_SCRIPT_GFX_DRAW_ORDER(GFX_ORDER_BEFORE_HUD) DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLetter, 255,255,255,255) UPDATE_SIMPLE_USE_CONTEXT(ucInstructions) // Enable cursor IF IS_USING_KEYBOARD_AND_MOUSE(FRONTEND_CONTROL) SET_MOUSE_CURSOR_THIS_FRAME() ENDIF // Wait for user input IF IS_CONTROL_PRESSED(FRONTEND_CONTROL, INPUT_FRONTEND_ACCEPT) eLetterStage = SS_CLEANUP ENDIF BREAK CASE SS_CLEANUP // Remove continue button CLEANUP_SIMPLE_USE_CONTEXT(ucInstructions) // Fade back out DO_SCREEN_FADE_OUT(3000) WHILE IS_SCREEN_FADING_OUT() DRAW_SCALEFORM_MOVIE_FULLSCREEN(siLetter, 255,255,255,255) HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE // Stop shrink stream STOP_STREAM() // Fade audio back in STOP_AUDIO_SCENE("END_CREDITS_SHRINKS_NOTE_SCENE") // Cleanup SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(siLetter) RETURN FALSE BREAK ENDSWITCH RETURN TRUE ENDFUNC /// PURPOSE: /// Main script update SCRIPT CPRINTLN(DEBUG_FLOW, " Story flow completed. Checking which character was most played...") IF HAS_FORCE_CLEANUP_OCCURRED() SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(siLetter) STOP_STREAM() TERMINATE_THIS_THREAD() ENDIF #IF IS_DEBUG_BUILD IF g_flowUnsaved.bUpdatingGameflow CPRINTLN(DEBUG_FLOW, " Skipping past endgame. Aborting endgame routines.") SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_RESPAWNED_AFTER_FINALE, TRUE) SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(siLetter) TERMINATE_THIS_THREAD() ENDIF #ENDIF // Screen should already be faded out. But check here as a failsafe. IF NOT IS_SCREEN_FADED_OUT() IF NOT IS_SCREEN_FADING_OUT() DO_SCREEN_FADE_OUT(0) ENDIF WHILE NOT IS_SCREEN_FADED_OUT() WAIT(0) ENDWHILE ENDIF // Ensure player is alive before proceeding. CPRINTLN(DEBUG_FLOW, " Starting to wait for player to be alive...") WHILE IS_ENTITY_DEAD(PLAYER_PED_ID()) WAIT(0) ENDWHILE CPRINTLN(DEBUG_FLOW, "...Finished waiting for player to be alive.") // Prepare for letter SET_SCRIPTS_SAFE_FOR_CUTSCENE(TRUE) SET_PLAYER_CONTROL(PLAYER_ID(), FALSE) DISPLAY_RADAR(FALSE) DISPLAY_HUD(FALSE) // Create and display letter WHILE DO_LETTER_UPDATE() HIDE_UI_AND_DISABLE_CONTROLS_FOR_LETTER() WAIT(0) ENDWHILE // Add the other finales to the repeat play list ADD_ALL_FINALES_TO_REPEAT_PLAY() // Add boiler suits to the shops and wardrobes again SET_BOILER_SUIT_AVAILABILITY(TRUE) // Fix for 2227662. Ensure the radio station offset is corrected // after the credits have played. SKIP_RADIO_FORWARD() // Restore control SET_SCRIPTS_SAFE_FOR_CUTSCENE(FALSE) SET_PLAYER_CONTROL(PLAYER_ID(), TRUE) DISPLAY_RADAR(TRUE) DISPLAY_HUD(TRUE) // Trevor dead cleanup. IF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_TREVOR_KILLED) Cancel_All_Comms_For_Player_Character(CHAR_TREVOR) // Michael dead cleanup. ELIF GET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_MICHAEL_KILLED) Cancel_All_Comms_For_Player_Character(CHAR_MICHAEL) ENDIF // Clear last seen player data. CPRINTLN(DEBUG_FLOW, " Reset last known ped info.") ResetLastKnownPedInfo(g_savedGlobals.sPlayerData.sInfo, SP_MISSION_NONE) // Spawn as either Michael or Trevor. IF IS_SELECTOR_PED_AVAILABLE_IN_FLOW(SELECTOR_PED_TREVOR) IF IS_SELECTOR_PED_AVAILABLE_IN_FLOW(SELECTOR_PED_MICHAEL) CPRINTLN(DEBUG_FLOW, " Trevor and Michael are alive. Spawning as Trevor at the end of the game.") DO_PLAYER_WARP_WITH_LOAD_AND_PAUSE(g_sPedSceneData[PR_SCENE_Ta_FINALEC].vCreateCoords) Trigger_Specific_Switch_And_Wait(PR_SCENE_Ta_FINALEC, ENUM_TO_INT(SWITCH_FLAG_DESCENT_ONLY)) UpdatePostMissionInfo(g_savedGlobals.sPlayerData.sInfo, CHAR_MICHAEL, PR_SCENE_Ma_FINALEC) UpdatePostMissionInfo(g_savedGlobals.sPlayerData.sInfo, CHAR_FRANKLIN, PR_SCENE_Fa_FINALEC) ELSE CPRINTLN(DEBUG_FLOW, " Trevor is alive. Spawning as Trevor at the end of the game.") while not SET_CURRENT_SELECTOR_PED(SELECTOR_PED_TREVOR) wait(0) endwhile DO_PLAYER_WARP_WITH_LOAD_AND_PAUSE(g_sPedSceneData[PR_SCENE_T_CN_WAKEBARN].vCreateCoords) Trigger_Specific_Switch_And_Wait(PR_SCENE_T_CN_WAKEBARN, ENUM_TO_INT(SWITCH_FLAG_DESCENT_ONLY)) UpdatePostMissionInfo(g_savedGlobals.sPlayerData.sInfo, CHAR_FRANKLIN, PR_SCENE_Fa_FINALEC) ENDIF ELSE CPRINTLN(DEBUG_FLOW, " Trevor is dead. Spawning as Michael at the end of the game.") //B*:1764963 Swap char to Michael directly to keep the tennis minigame blip while not SET_CURRENT_SELECTOR_PED(SELECTOR_PED_MICHAEL) wait(0) endwhile DO_PLAYER_WARP_WITH_LOAD_AND_PAUSE(g_sPedSceneData[PR_SCENE_M4_WAKESUPSCARED].vCreateCoords) Trigger_Specific_Switch_And_Wait(PR_SCENE_M4_WAKESUPSCARED, ENUM_TO_INT(SWITCH_FLAG_DESCENT_ONLY)) UpdatePostMissionInfo(g_savedGlobals.sPlayerData.sInfo, CHAR_FRANKLIN, PR_SCENE_Fa_FINALEC) ENDIF // Delete ambient player characters. INT iQueue REPEAT NUM_OF_PLAYABLE_PEDS iQueue IF NOT IS_ENTITY_DEAD(g_sPlayerPedRequest.sSelectorPeds.pedID[iQueue]) IF (g_sPlayerPedRequest.sSelectorPeds.pedID[iQueue] <> PLAYER_PED_ID()) IF DOES_ENTITY_BELONG_TO_THIS_SCRIPT(g_sPlayerPedRequest.sSelectorPeds.pedID[iQueue]) SET_ENTITY_AS_MISSION_ENTITY(g_sPlayerPedRequest.sSelectorPeds.pedID[iQueue], TRUE, TRUE) ENDIF CPRINTLN(DEBUG_FLOW, " delete global selector ped [", iQueue, "].") DELETE_PED(g_sPlayerPedRequest.sSelectorPeds.pedID[iQueue]) ENDIF ENDIF ENDREPEAT REPEAT COUNT_OF(g_ambientSelectorPedDeleteQueue) iQueue IF NOT IS_ENTITY_DEAD(g_ambientSelectorPedDeleteQueue[iQueue]) IF (g_ambientSelectorPedDeleteQueue[iQueue] <> PLAYER_PED_ID()) IF DOES_ENTITY_BELONG_TO_THIS_SCRIPT(g_ambientSelectorPedDeleteQueue[iQueue]) SET_ENTITY_AS_MISSION_ENTITY(g_ambientSelectorPedDeleteQueue[iQueue], TRUE, TRUE) ENDIF CPRINTLN(DEBUG_FLOW, " delete ambient queue ped [", iQueue, "].") DELETE_PED(g_ambientSelectorPedDeleteQueue[iQueue]) ENDIF ENDIF ENDREPEAT // Slowly fade back in. IF NOT IS_SCREEN_FADED_IN() DO_SCREEN_FADE_IN(DEFAULT_FADE_TIME_LONG) ENDIF WHILE NOT IS_SCREEN_FADED_IN() WAIT(0) ENDWHILE // Post game complete facebook message and display on the feed. IF FACEBOOK_CAN_POST_TO_FACEBOOK() IF NOT IS_BIT_SET(g_savedGlobals.sSocialData.iFacebookPostsMadeBitset, ENUM_TO_INT(FBPOST_STORY_COMPLETE)) CPRINTLN(DEBUG_FLOW, " Posting FACEBOOK_MILESTONE_OVERVIEW facebook message.") SHOW_FACEBOOK_MILESTONE_FEED_MESSAGE(FACEBOOK_MILESTONE_OVERVIEW) FACEBOOK_POST_COMPLETED_MILESTONE(FACEBOOK_MILESTONE_OVERVIEW) SET_BIT(g_savedGlobals.sSocialData.iFacebookPostsMadeBitset, ENUM_TO_INT(FBPOST_STORY_COMPLETE)) ENDIF ENDIF // Allow mission passed results to display now. g_bMissionStatSystemBlocker = FALSE TRIGGER_MISSION_STATS_UI() IF GET_MISSION_FLOW_FLAG_STATE( FLOWFLAG_TREVOR_KILLED ) SET_DIRECTOR_STORY_CHARACTER_UNLOCKED( DU_STORY_MRS_T, FALSE ) SET_DIRECTOR_STORY_CHARACTER_UNLOCKED( DU_STORY_MAUDE, FALSE ) ELIF GET_MISSION_FLOW_FLAG_STATE( FLOWFLAG_MICHAEL_KILLED ) SET_DIRECTOR_STORY_CHARACTER_UNLOCKED( DU_STORY_CHRIS_F, FALSE ) SET_DIRECTOR_STORY_CHARACTER_UNLOCKED( DU_STORY_DR_F, FALSE ) ENDIF SET_MISSION_FLOW_FLAG_STATE(FLOWFLAG_RESPAWNED_AFTER_FINALE, TRUE) ADD_HELP_TO_FLOW_QUEUE("SHRINK_SOCIAL", FHP_VERY_HIGH) MAKE_AUTOSAVE_REQUEST() CPRINTLN(DEBUG_FLOW, " Finished.") TERMINATE_THIS_THREAD() ENDSCRIPT