Files
2025-09-29 00:52:08 +02:00

1100 lines
39 KiB
Python
Executable File

//
// Mission Repeat Controller
//
//
// AUTHOR: Ben Rollinson / Andrew Minghella
// DATE: 13/09/11
// DESCRIPTION: A system used to trigger mission scripts
// that the player has chosen to replay after
// having already completed them.
//
//
USING "rage_builtins.sch"
USING "globals.sch"
USING "snapshot_private.sch"
USING "flow_processing_game.sch"
USING "mission_repeat_private.sch"
USING "savegame_private.sch"
USING "RC_launcher_public.sch"
USING "flow_processing_missions_game.sch"
USING "script_heist.sch"
USING "mission_repeat_public.sch"
ENUM RP_STATE
RP_SETUP,
RP_HEIST_PLANNING_BOARD,
RP_LAUNCH,
RP_RUNNING,
RP_PASSED,
RP_FAILED
ENDENUM
// repeat play variables
RP_STATE eRPState
RP_HEIST_STATE eRPHeistState
TEXT_LABEL_31 tScriptName
INT iTriggerCharBitset
INT iCandidateID = NO_CANDIDATE_ID
INT iHeistCrewUnlockBackup // Used for remembering which crew memebers had been unlocked before resetting the flow state.
// --------------------------functions ----------------------------------------------------------
/// PURPOSE:
/// Moves the player into position and loads the world in
/// PARAMS:
/// vPos - where we are moving the player
/// fHeading - heading the player should use
/// bRepopulate - do we want to repropulate the world here?
/// RETURNS:
/// TRUE if everything loaded ok
FUNC BOOL RepeatPlay_Warp_Player(VECTOR vPos, FLOAT fHeading, BOOL bRepopulate)
IF IS_PLAYER_PLAYING(PLAYER_ID())
// start the teleport
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player started")
SET_GAME_PAUSED(FALSE)
// turn off emergency streaming (pausing game will ensure player doesnt fall through floor)
//SET_GAME_PAUSES_FOR_STREAMING(FALSE)
// move player now
CLEAR_AREA(vPos, 5.0, TRUE)
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos)
SET_ENTITY_HEADING(PLAYER_PED_ID(), fHeading)
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
ENDIF
ENDIF
NEW_LOAD_SCENE_START_SPHERE(vPos, 600)
WAIT(0) // wait a frame for the camera to catch up before pausing
// clear wanted level again (in case repeat play triggered in restricted area)
IF IS_PLAYER_PLAYING(PLAYER_ID())
CPRINTLN(DEBUG_REPEAT,"Repeat play clearing wanted level now (after warp).")
CLEAR_PLAYER_WANTED_LEVEL(PLAYER_ID())
ENDIF
// clear the area
CLEAR_AREA(vPos, 5000, TRUE, FALSE)
DELETE_VEHICLE_GEN_VEHICLES_IN_AREA(vPos, 5000)
CLEAR_AREA_OF_OBJECTS(vPos, 5000)
REMOVE_PARTICLE_FX_IN_RANGE(vPos, 5000)
REMOVE_DECALS_IN_RANGE(vPos, 5000)
CLEAR_ALL_MUST_LEAVE_AREA_VEHICLE_GEN_FLAGS()
RESET_VEHICLE_GEN_LOADED_CHECKS()
// start timer + pause game
SETTIMERA(0)
SET_GAME_PAUSED(TRUE)
// try to create the new load scene
IF NOT IS_NEW_LOAD_SCENE_ACTIVE()
WHILE NOT NEW_LOAD_SCENE_START_SPHERE(vPos, REPLAY_LOAD_SCENE_SIZE)
WAIT(0)
IF TIMERA() > 2000
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player failed to create load scene- exit.")
//SET_GAME_PAUSES_FOR_STREAMING(TRUE) // allow emergency streaming again
SET_GAME_PAUSED(FALSE)
RETURN FALSE
ENDIF
ENDWHILE
ENDIF
// wait for scene to load
CPRINTLN(DEBUG_REPEAT, "REPLAY_WARP_PLAYER new load scene succesfully started.")
SETTIMERA(0)
WHILE NOT IS_NEW_LOAD_SCENE_LOADED()
WAIT(0)
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player new load scene still loading: ", TIMERA())
// check for early out
IF TIMERA() > REPLAY_LOAD_SCENE_TIMEOUT
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player took too long: early out")
SET_GAME_PAUSED(FALSE)
// get rid of the stream vol
IF IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_STOP()
ENDIF
//SET_GAME_PAUSES_FOR_STREAMING(TRUE) // allow emergency streaming again
RETURN FALSE
ENDIF
// check for debug skip
#IF IS_DEBUG_BUILD
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_V))
CPRINTLN(DEBUG_REPLAY, "RepeatPlay_Warp_Player debug skipping streaming.")
SET_GAME_PAUSED(FALSE)
// get rid of the stream vol
IF IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_STOP()
ENDIF
//SET_GAME_PAUSES_FOR_STREAMING(TRUE) // allow emergency streaming again
RETURN FALSE
ENDIF
#ENDIF
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player warp finished")
// post warp cleanup- then start repopulation
// clear and repopulate the area
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
// get rid of the stream vol
IF IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_STOP()
ENDIF
//SET_GAME_PAUSES_FOR_STREAMING(TRUE) // allow emergency streaming again
// need to unpause for repopulate stuff to work
SET_GAME_PAUSED(FALSE)
SETTIMERA(0)
// refill population
INSTANTLY_FILL_PED_POPULATION()
IF bRepopulate = TRUE
INSTANTLY_FILL_VEHICLE_POPULATION()
ELSE
// if not doing vehicle repop, set the early out
SETTIMERA(REPOP_EARLY_OUT - REPOP_MIN_WAIT)
ENDIF
POPULATE_NOW()
ENDIF
ENDIF
// wait for repopulation to finish
WHILE (NOT HAS_INSTANT_FILL_VEHICLE_POPULATION_FINISHED()
OR NOT HAVE_ALL_VEHICLE_GENS_LOADED_NEAR_PLAYER()
OR TIMERA() < REPOP_MIN_WAIT)
AND TIMERA() < REPOP_EARLY_OUT
WAIT(0)
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player waiting for vehicle repopulation.")
ENDWHILE
IF TIMERA() > REPOP_EARLY_OUT
IF bRepopulate = TRUE
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player repopulation took too long, early out.")
ELSE
CPRINTLN(DEBUG_REPEAT, "RepeatPlay_Warp_Player skipping vehicle repopulation.")
ENDIF
ENDIF
// reset camera behind player
SET_GAMEPLAY_CAM_RELATIVE_PITCH(0.0)
SET_GAMEPLAY_CAM_RELATIVE_HEADING(0.0)
// finished
CPRINTLN(DEBUG_REPLAY, "RepeatPlay_Warp_Player: repopulation finished")
SET_GAME_PAUSED(FALSE)
RETURN TRUE
ENDIF
CPRINTLN(DEBUG_REPLAY, "RepeatPlay_Warp_Player: player not playing")
SET_GAME_PAUSED(FALSE)
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// (Un)Freezes the player
/// PARAMS:
/// bFreeze- are we freezing or unfreezing?
PROC RepeatPlay_Freeze_Player(BOOL bFreeze)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF bFreeze = TRUE
// freeze
SET_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_PLAYER))
CPRINTLN(DEBUG_REPEAT, "Repeat Play is freezing the player.")
// disable player control
IF IS_PLAYER_PLAYING(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
CLEAR_PED_TASKS(PLAYER_PED_ID())
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
FREEZE_ENTITY_POSITION(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), TRUE)
ELSE
IF NOT IS_PED_GETTING_INTO_A_VEHICLE(PLAYER_PED_ID())
IF IS_ENTITY_ATTACHED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT, "Repeat Play is detaching entity.")
DETACH_ENTITY(PLAYER_PED_ID())
ENDIF
ENDIF
IF NOT IS_ENTITY_ATTACHED(PLAYER_PED_ID())
FREEZE_ENTITY_POSITION(PLAYER_PED_ID(), TRUE)
ENDIF
ENDIF
SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), TRUE)
SET_ENTITY_PROOFS(PLAYER_PED_ID(), TRUE, TRUE, TRUE, TRUE, TRUE)
ELSE
// unfreeze
IF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_PLAYER))
CPRINTLN(DEBUG_REPEAT, "Repeat Play is unfreezing the player.")
// disable player control
IF IS_PLAYER_PLAYING(PLAYER_ID())
SET_PLAYER_CONTROL(PLAYER_ID(), TRUE)
ENDIF
IF IS_ENTITY_ATTACHED(PLAYER_PED_ID()) // unfreeze player
FREEZE_ENTITY_POSITION(GET_ENTITY_ATTACHED_TO(PLAYER_PED_ID()), FALSE)
ELSE
FREEZE_ENTITY_POSITION(PLAYER_PED_ID(), FALSE)
ENDIF
IF IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
FREEZE_ENTITY_POSITION(GET_VEHICLE_PED_IS_IN(PLAYER_PED_ID()), FALSE)
ENDIF
SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), FALSE)
SET_ENTITY_PROOFS(PLAYER_PED_ID(), FALSE, FALSE, FALSE, FALSE, FALSE)
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_PLAYER))
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Reactivates game flow and comm queues
PROC Exit_Repeat_Play(BOOL bFadeIn)
g_savedGlobals.sFlow.isGameflowActive = TRUE
g_bPauseCommsQueues = FALSE
CPRINTLN(DEBUG_REPEAT, "Unpaused Flow + communication queue.")
SET_GAME_PAUSED(FALSE)
IF bFadeIn = TRUE
DO_SCREEN_FADE_IN(DEFAULT_FADE_TIME)
ENDIF
// stop the player being invinvible
// this was set on by the repeat play menu
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
SET_ENTITY_INVINCIBLE(PLAYER_PED_ID(), FALSE)
ENDIF
// reset the bitset - we don't clear the bits after as they are used for putting the player back after things like the rollercoaster
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_ACTIVE))
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_FROZEN_PLAYER))
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PAUSED_GAME))
SET_PLAYER_IS_REPEATING_A_MISSION(FALSE)
TERMINATE_THIS_THREAD()
ENDPROC
/// PURPOSE:
/// This is called after repeat play is passed, or repeat play replay is rejected (or if player quits via pause menu)
/// Calls mission termination commands, loads the autosave and calls exit repeat play
PROC Repeat_Play_Completed()
CPRINTLN(DEBUG_REPEAT,"Mission repeat ended for mission script ", tScriptName)
// End of mission cleanup
IF g_RepeatPlayData.eMissionType = CP_GROUP_MISSIONS
MISSION_PROCESSING_MISSION_OVER(INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex))
//Inform the mission candidate system that the mission is over
Mission_Over(iCandidateID)
ELSE
// nothing needs to be done here as the RCs run as normal via world points and launchers
ENDIF
// Load the auto-save here
QUEUE_MISSION_REPEAT_LOAD()
Exit_Repeat_Play(FALSE)
ENDPROC
/// PURPOSE:
/// Returns the position we want to warp the player to for this story mission.
/// Uses static blip position for normal missions.
/// Uses custom vectors for moving prep missions.
/// RETURNS:
/// VECTOR position to warp the player to
FUNC VECTOR GET_STORY_MISSION_WARP_POS()
VECTOR vPos = <<0.0,0.0,0.0>>
SP_MISSIONS eMissionID = INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex)
SWITCH eMissionID
// moving prep missions
CASE SP_HEIST_AGENCY_PREP_1
vPos = <<354.3055, -1722.2062, 28.2590>>
BREAK
CASE SP_MISSION_FBI_4_PREP_1
vPos = <<1062.2830, -357.3208, 66.1474>>
BREAK
CASE SP_HEIST_JEWELRY_PREP_1B
g_iForcePrepMissionRoute = GET_RANDOM_INT_IN_RANGE(1,4)
SWITCH g_iForcePrepMissionRoute
CASE 1
vPos = <<-745.47900, -1118.11047, 9.67980>>
BREAK
CASE 2
vPos = <<895.8368, -788.0649, 41.9022>>
BREAK
CASE 3
vPos = <<-964.6421, -336.7097, 36.8155>>
BREAK
ENDSWITCH
BREAK
CASE SP_HEIST_JEWELRY_PREP_2A
g_iForcePrepMissionRoute = 1
vPos = <<1261.4415, 589.6306, 80.5991>>
BREAK
CASE SP_HEIST_RURAL_PREP_1
vPos = <<45.7300, 3064.2739, 39.9430>>
BREAK
CASE SP_HEIST_DOCKS_PREP_1
vPos = <<1219.1857, -2977.8999, 4.8653>>
BREAK
// other special cases
CASE SP_MISSION_CHINESE_1
vPos = <<1991.0757, 3054.2473, 46.2147>>
BREAK
// normal missions
DEFAULT
IF g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].blip != STATIC_BLIP_NAME_DUMMY_FINAL
vPos = GET_STATIC_BLIP_POSITION(g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].blip)
ENDIF
BREAK
ENDSWITCH
RETURN vPos
ENDFUNC
/// PURPOSE:
/// Sets up the flow ready for the chosen repeat play mission
PROC Setup_Repeat_Play()
CPRINTLN(DEBUG_REPEAT,"Setup_Repeat_Play called")
// pause game
CPRINTLN(DEBUG_REPEAT, "Pausing game in mission repeat controller.")
SET_GAME_PAUSED(TRUE)
//Check the mission repeat index to trigger is valid.
IF g_RepeatPlayData.iMissionIndex < 0 OR g_RepeatPlayData.iMissionIndex >= ENUM_TO_INT(SP_MISSION_MAX)
SCRIPT_ASSERT("mission_repeat_controller.sc: The controller was asked to trigger a repeatable mission with an invalid index.")
Exit_Repeat_Play(TRUE)
ENDIF
// ------------Set initial mission details--------------------------
g_structRCMissionsStatic sRCMissionDetails
IF g_RepeatPlayData.eMissionType = CP_GROUP_RANDOMCHARS
g_bSceneAutoTrigger = TRUE // set scene auto trigger on for RCs
Retrieve_Random_Character_Static_Mission_Details(INT_TO_ENUM(g_eRC_MissionIDs ,g_RepeatPlayData.iMissionIndex), sRCMissionDetails)
ENDIF
// Some are different for story and RC missions
SWITCH g_RepeatPlayData.eMissionType
CASE CP_GROUP_MISSIONS
tScriptName = g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].scriptName
iTriggerCharBitset = g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].triggerCharBitset
BREAK
CASE CP_GROUP_RANDOMCHARS
tScriptName = sRCMissionDetails.rcScriptName
iTriggerCharBitset = sRCMissionDetails.rcPlayableChars
BREAK
DEFAULT
CPRINTLN(DEBUG_REPEAT,"Run_Mission_Repeat passed a mission type that isn't repeat playable: ", g_RepeatPlayData.eMissionType)
BREAK
ENDSWITCH
SET_PLAYER_IS_REPEATING_A_MISSION(TRUE)
// ------------------set up the player ready for the mission-------------------------
WHILE NOT IS_SCREEN_FADED_OUT()
IF NOT IS_SCREEN_FADING_OUT()
DO_SCREEN_FADE_OUT(500)
ENDIF
WAIT(0)
ENDWHILE
// Perform the repeat play autosave
Store_RepeatPlay_Snapshot()
// overwrite the vehicle's velocity- as we've already stored it
// and it is now frozen so velocity is 0
g_savedGlobals.sRepeatPlayData.mVehicleStruct.vVehicleVelocity = g_vRPVelocity
CPRINTLN(DEBUG_REPEAT, "Overwriting velocity as g_vRPVelocity x= ", g_vRPVelocity.x, " y= ", g_vRPVelocity.y, " z= ", g_vRPVelocity.z)
PERFORM_PRE_SAVEGAME_ROUTINE(FALSE, TRUE)
QUEUE_MISSION_REPEAT_SAVE()
WHILE GET_STATUS_OF_MISSION_REPEAT_SAVE() = SAVEGAME_OPERATION_IN_PROGRESS
WAIT(0)
CPRINTLN(DEBUG_REPEAT,"Waiting for repeat play to save the game.")
ENDWHILE
// Exit if we failed to save the game
IF GET_STATUS_OF_MISSION_REPEAT_SAVE() = SAVEGAME_OPERATION_FAILED
CPRINTLN(DEBUG_REPEAT,"Repeat play save failed. exit repeat play.")
Exit_Repeat_Play(TRUE)
EXIT
ELSE
CPRINTLN(DEBUG_REPEAT,"Repeat play save was successful.")
ENDIF
// stop player being on fire, ground him etc
VECTOR vPos
IF DOES_ENTITY_EXIST(PLAYER_PED_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT,"Doing new safety checks: not injured.")
// get player out of car and ground him
CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID())
vPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
GET_GROUND_Z_FOR_3D_COORD(vPos, vPos.z)
SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos)
IF IS_ENTITY_ON_FIRE(PLAYER_PED_ID())
STOP_ENTITY_FIRE(PLAYER_PED_ID())
ENDIF
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
STOP_FIRE_IN_RANGE(vPos, 50.0)
ENDIF
CLEAR_AREA_OF_PROJECTILES(vPos, 50.0)
SET_ENTITY_HEALTH(PLAYER_PED_ID(),GET_PED_MAX_HEALTH(PLAYER_PED_ID())) //Always set the player to full health.
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
ELSE
CPRINTLN(DEBUG_REPEAT,"Doing new safety checks: Player already injured.")
ENDIF
ENDIF
// Repeat play is initialising, force clean-up any scripts we need to terminate
RepeatPlay_Freeze_Player(TRUE)
RUN_GENERAL_SCRIPT_CLEANUP()
// #1542560: Backup old crew unlock bitset before reset so we can use them on
// any heist planning board that supports them later.
iHeistCrewUnlockBackup = g_savedGlobals.sHeistData.iCrewUnlockedBitset
// set up building swaps, available characters etc
REPEAT_PLAY_UNLOCKING(g_RepeatPlayData.iMissionIndex, g_RepeatPlayData.eMissionType)
#if use_CLF_dlc
//always remove the spy vehicle for a repeat play
spy_vehicle_system_struct temp_spy_veh_system
spy_vehicle_remove_all_system_assets(temp_spy_veh_system)
#endif
IF g_RepeatPlayData.eMissionType = CP_GROUP_MISSIONS // (heists are in mission group at the moment for repeat play)
AND IS_BIT_SET(g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].settingsBitset, MF_INDEX_IS_HEIST)
eRPState = RP_HEIST_PLANNING_BOARD // need to do planning board
ELSE
eRPState = RP_LAUNCH // no planning board needed, go to the mission
ENDIF
ENDPROC
/// PURPOSE:
/// Lets the player choose which crew / approach etc to use for this repeat play heist
PROC Do_Heist_Planning_Board()
CPRINTLN(DEBUG_REPEAT, "Do_Heist_Planning_Board called.")
// heist only variables
INT iHeist = GET_HEIST_FROM_MISSION_ID(INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex))
TEXT_LABEL_31 tHeistController = GET_HEIST_CONTROLLER_SCRIPT(INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex))
VECTOR vHeistPos = GET_HEIST_PLANNING_BOARD_LOCATION(iHeist)
//#1542560: Unlock previously unlocked heist crew members who are valid for this heist.
SWITCH iHeist
CASE HEIST_FINALE
CASE HEIST_AGENCY
IF IS_BIT_SET(iHeistCrewUnlockBackup, ENUM_TO_INT(CM_DRIVER_G_TALINA_UNLOCK))
SET_HEIST_CREW_MEMBER_UNLOCKED(CM_DRIVER_G_TALINA_UNLOCK)
ENDIF
FALLTHRU
CASE HEIST_RURAL_BANK
IF IS_BIT_SET(iHeistCrewUnlockBackup, ENUM_TO_INT(CM_GUNMAN_G_CHEF_UNLOCK))
SET_HEIST_CREW_MEMBER_UNLOCKED(CM_GUNMAN_G_CHEF_UNLOCK)
ENDIF
FALLTHRU
CASE HEIST_JEWEL
IF IS_BIT_SET(iHeistCrewUnlockBackup, ENUM_TO_INT(CM_GUNMAN_G_PACKIE_UNLOCK))
SET_HEIST_CREW_MEMBER_UNLOCKED(CM_GUNMAN_G_PACKIE_UNLOCK)
ENDIF
IF IS_BIT_SET(iHeistCrewUnlockBackup, ENUM_TO_INT(CM_HACKER_B_RICKIE_UNLOCK))
SET_HEIST_CREW_MEMBER_UNLOCKED(CM_HACKER_B_RICKIE_UNLOCK)
ENDIF
BREAK
ENDSWITCH
// load the heist controller
REQUEST_SCRIPT(tHeistController)
WHILE NOT (HAS_SCRIPT_LOADED(tHeistController))
CPRINTLN(DEBUG_REPEAT, "RepeatPlay: Waiting for script to load: ", tHeistController)
WAIT(0)
ENDWHILE
// Script has loaded, so launch it
START_NEW_SCRIPT(tHeistController, FRIEND_STACK_SIZE) //Fix for 1219287: This stack size must match the ones defined in Define_Restore_Launched_ScriptNames()
SET_SCRIPT_AS_NO_LONGER_NEEDED(tHeistController)
CPRINTLN(DEBUG_REPEAT, "RepeatPlay: script launched: ", tHeistController)
// Warp the player to the planning board
CPRINTLN(DEBUG_REPEAT, "iHeist = ", iHeist)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
CPRINTLN(DEBUG_REPEAT, "RepeatPlay: warping player to heist board pos: ", vHeistPos)
RepeatPlay_Warp_Player(vHeistPos, GET_ENTITY_HEADING(PLAYER_PED_ID()), FALSE)
ENDIF
// set up any board display groups that should be on
SET_HEIST_BOARD_DISPLAY_GROUPS_ON(iHeist)
// any other special case setup
IF iHeist = HEIST_DOCKS
SET_BUILDING_STATE(BUILDINGNAME_ES_FLOYDS_APPARTMENT_SHIT, BUILDINGSTATE_DESTROYED)
SET_BUILDING_STATE(BUILDINGNAME_ES_FLOYDS_APPARTMENT_SHIT_SOFA, BUILDINGSTATE_DESTROYED)
ELIF iHeist = HEIST_AGENCY
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_WITH_INTERIOR, BUILDINGSTATE_DESTROYED)
ENDIF
// set flow flag to activate the planning board
REPEAT_PLAY_SET_HEIST_FLOW_FLAG(iHeist, RPH_START_BOARD_INTERACTIONS, TRUE)
// fade in when the board is ready to be displayed
WHILE g_bHeistBoardViewActive = FALSE
CPRINTLN(DEBUG_REPEAT, "Waiting for heist board to set up..")
WAIT(0)
ENDWHILE
RepeatPlay_Freeze_Player(FALSE) // un freeze + no longer invincible
// slight wait so we don't see stuff fade in
WAIT(500)
CPRINTLN(DEBUG_REPEAT, "Heist board has been setup, fading in.")
DO_SCREEN_FADE_IN(500)
// ---------------------------HEIST PLANNING BOARD FLOW-------------------------------------------------
eRPHeistState = RPHS_POI_OVERVIEW
WHILE eRPHeistState <> RPHS_FINISHED
WAIT(0)
SWITCH eRPHeistState
CASE RPHS_POI_OVERVIEW
eRPHeistState = REPEAT_PLAY_DO_BOARD_INTERACTION(iHeist, INTERACT_POI_OVERVIEW, REPEAT_PLAY_GET_HEIST_CHOICE_DISPLAY_GROUP(iHeist, TRUE), eRPHeistState)
BREAK
CASE RPHS_POI_OVERVIEW_DONE
CPRINTLN(DEBUG_REPEAT, "Point of interest overview done.")
WAIT(REPEAT_PLAY_GET_HEIST_CHOICE_DONE_WAIT(iHeist, eRPHeistState))
IF iHeist = HEIST_RURAL_BANK // bank heist doesn't have a gameplay choice
CPRINTLN(DEBUG_REPEAT, "Bank heist skipping gameplay choice.")
Set_Mission_Flow_Int_Value(FLOWINT_HEIST_CHOICE_RURAL, HEIST_CHOICE_RURAL_NO_TANK)
REPEAT_PLAY_SET_HEIST_FLOW_FLAG(iHeist, RPH_LOAD_EXIT_CUTSCENE, TRUE)
eRPHeistState = RPHS_CREW_CHOICE
ELSE
eRPHeistState = RPHS_GAMEPLAY_CHOICE
ENDIF
BREAK
CASE RPHS_GAMEPLAY_CHOICE
eRPHeistState = REPEAT_PLAY_DO_BOARD_INTERACTION(iHeist, INTERACT_GAMEPLAY_CHOICE, REPEAT_PLAY_GET_HEIST_CHOICE_DISPLAY_GROUP(iHeist, TRUE), eRPHeistState)
IF eRPHeistState <> RPHS_GAMEPLAY_CHOICE
REPEAT_PLAY_SET_HEIST_FLOW_FLAG(iHeist, RPH_LOAD_EXIT_CUTSCENE, TRUE)
ENDIF
BREAK
CASE RPHS_GAMEPLAY_CHOICE_DONE
CPRINTLN(DEBUG_REPEAT, "Gameplay choice done.")
WAIT(REPEAT_PLAY_GET_HEIST_CHOICE_DONE_WAIT(iHeist, eRPHeistState))
eRPHeistState = RPHS_CREW_CHOICE
BREAK
CASE RPHS_CREW_CHOICE
eRPHeistState = REPEAT_PLAY_DO_BOARD_INTERACTION(iHeist, INTERACT_CREW, REPEAT_PLAY_GET_HEIST_CHOICE_DISPLAY_GROUP(iHeist, FALSE), eRPHeistState)
BREAK
CASE RPHS_CREW_CHOICE_DONE
CPRINTLN(DEBUG_REPEAT, "Crew choice done.")
WAIT(REPEAT_PLAY_GET_HEIST_CHOICE_DONE_WAIT(iHeist, eRPHeistState))
REPEAT_PLAY_TOGGLE_BOARD_VIEWING(iHeist, FALSE)
eRPHeistState = RPHS_EXIT_CUTSCENE
BREAK
CASE RPHS_EXIT_CUTSCENE
CPRINTLN(DEBUG_REPEAT, "Waiting for heist board exit cut-scene to finish...")
WHILE NOT REPEAT_PLAY_HAS_HEIST_CUTSCENE_FINISHED(iHeist)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Finished.")
DO_SCREEN_FADE_OUT(0)
CPRINTLN(DEBUG_REPEAT, "Waiting for heist board cut-scene to unload...")
WHILE IS_CUTSCENE_ACTIVE()
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Unloaded.")
eRPHeistState = RPHS_FINISHED
BREAK
DEFAULT
CPRINTLN(DEBUG_REPEAT, "Heist planning board in unknown state.")
BREAK
ENDSWITCH
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Heist planning board finished.")
//--------------------------------------------------------------------------------------------
// wait for the heist board to cleanup
CPRINTLN(DEBUG_REPEAT, "Waiting for heist board to cleanup.")
WHILE IS_CURRENTLY_ON_MISSION_TO_TYPE()
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Heist board has finished clean up.")
// any special case clean-up
IF iHeist = HEIST_AGENCY
// Switch to empty sweatshop interior
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_NO_INTERIOR, BUILDINGSTATE_DESTROYED)
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_WITH_INTERIOR, BUILDINGSTATE_CLEANUP)
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_LOD_DOOR, BUILDINGSTATE_DESTROYED)
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_BURNT, BUILDINGSTATE_NORMAL)
SET_BUILDING_STATE(BUILDINGNAME_IPL_SWEATSHOP_WINDOW_LIGHTS, BUILDINGSTATE_NORMAL)
ELIF iHeist = HEIST_DOCKS
SET_BUILDING_STATE(BUILDINGNAME_ES_FLOYDS_APPARTMENT_SHIT, BUILDINGSTATE_NORMAL)
SET_BUILDING_STATE(BUILDINGNAME_ES_FLOYDS_APPARTMENT_SHIT_SOFA, BUILDINGSTATE_NORMAL)
ENDIF
// do the actual heist mission
g_RepeatPlayData.iMissionIndex = REPEAT_PLAY_GET_SELECTED_HEIST_MISSION_ID(iHeist)
tScriptName = g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].scriptName
iTriggerCharBitset = g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].triggerCharBitset
RepeatPlay_Freeze_Player(TRUE) // re freeze + invincible
eRPState = RP_LAUNCH
ENDPROC
/// PURPOSE:
/// Launches the repeat play mission script
PROC Launch_Repeat_Play()
CPRINTLN(DEBUG_REPEAT, "Launch_Repeat_Play called.")
INT iHour, iMinute // used to set time of day to something suitable
// RC variables
g_structRCMissionsStatic sRCMissionDetails
// ----------------------load and launch the mission -------------------------------------
//Reset mission passed flag.
CLEAR_BIT(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
//Wait for the player character to be switched to the correct character for this mission.
REPEAT_PLAY_SWITCH_TO_SUITABLE_CHARACTER(iTriggerCharBitset)
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
//---------- warp the player into position + set time of day-------------
SWITCH g_RepeatPlayData.eMissionType
CASE CP_GROUP_MISSIONS
// warp
VECTOR vPos
vPos = GET_STORY_MISSION_WARP_POS()
IF NOT ARE_VECTORS_EQUAL(vPos, <<0.0,0.0,0.0>>)
CPRINTLN(DEBUG_REPEAT,"Moving player to blip pos")
RepeatPlay_Warp_Player(vPos, GET_ENTITY_HEADING(PLAYER_PED_ID()), TRUE)
CPRINTLN(DEBUG_REPEAT,"Moved player to blip pos")
ELSE
CPRINTLN(DEBUG_REPEAT,"Move to vector was 0,0,0. Leave player where he was.")
ENDIF
// set time to be suitable
SP_MISSIONS eMissionID
eMissionID = INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex)
IF (g_sMissionStaticData[eMissionID].startHour != NULL_HOUR) AND (g_sMissionStaticData[eMissionID].endHour != NULL_HOUR)
AND NOT IS_BIT_SET(g_sMissionStaticData[eMissionID].settingsBitset, MF_INDEX_MID_MISSION_TOD)
// ignore if the TOD skip is done mid mission
INT iCurrentHour
INT iStartHour
INT iEndHour
iCurrentHour = GET_TIMEOFDAY_HOUR(GET_CURRENT_TIMEOFDAY())
iStartHour = g_sMissionStaticData[eMissionID].startHour
iEndHour = g_sMissionStaticData[eMissionID].endHour
IF NOT IS_HOUR_BETWEEN_THESE_HOURS(iCurrentHour, iStartHour, iEndHour)
CPRINTLN(DEBUG_REPEAT, "Current hour is ", iCurrentHour, " which is not in the valid mission triggering hours of ", iStartHour, "->", iEndHour, ".")
CPRINTLN(DEBUG_REPEAT, "Overriding time hour to be ", iStartHour, ".")
SET_CLOCK_TIME(iStartHour, 00, 00)
ENDIF
ENDIF
BREAK
CASE CP_GROUP_RANDOMCHARS
g_eRC_MissionIDs eRCMissionID
// Warp
Retrieve_Random_Character_Static_Mission_Details(INT_TO_ENUM(g_eRC_MissionIDs ,g_RepeatPlayData.iMissionIndex), sRCMissionDetails)
CPRINTLN(DEBUG_REPEAT,"Moving player to blip pos")
// Get mission ID
eRCMissionID = Get_RC_MissionID_For_Script(tScriptName)
IF ARE_VECTORS_EQUAL(sRCMissionDetails.rcCoords, <<0,0,0>>)
IF eRCMissionID = RC_TONYA_3
OR eRCMissionID = RC_TONYA_4
sRCMissionDetails.rcCoords = <<-3.2349, -1469.9525, 29.5503>>
// Heading should be... 265.8950
ELSE
CERRORLN(DEBUG_REPEAT,"Launch_Repeat_Play: rcCoords are <<0,0,0 with no associated mission! Bug for Andy Minghella")
SCRIPT_ASSERT("Launch_Repeat_Play: rcCoords are <<0,0,0>> with no associated mission! Bug for Andy Minghella")
ENDIF
ENDIF
// other special cases where we need to spawn player away from blip pos
IF eRCMissionID = RC_BARRY_1
OR eRCMissionID = RC_BARRY_2
sRCMissionDetails.rcCoords = <<188.51234, -954.81543, 29.09192>>
CPRINTLN(DEBUG_REPEAT,"Using special case pos for Barry 1/2 RC.")
ELIF eRCMissionID = RC_BARRY_3A
sRCMissionDetails.rcCoords = <<1205.7874, -1289.2284, 34.2264>>
ELIF eRCMissionID = RC_BARRY_3C
sRCMissionDetails.rcCoords = <<-447.0243, -1704.6481, 17.9004>>
ENDIF
RepeatPlay_Warp_Player(sRCMissionDetails.rcCoords, GET_ENTITY_HEADING(PLAYER_PED_ID()), TRUE)
CPRINTLN(DEBUG_REPEAT,"Moved player to blip pos")
// Time
IF sRCMissionDetails.rcStartTime != 0000 OR sRCMissionDetails.rcEndTime != 2359
iHour = (sRCMissionDetails.rcStartTime/100)
iMinute = (sRCMissionDetails.rcStartTime%100)
SET_CLOCK_TIME(iHour, iMinute, 0)
CPRINTLN(DEBUG_REPEAT,"REPEAT_PLAY_SET_SUITABLE_TIME_OF_DAY set time to : ", iHour, iMinute)
ENDIF
// Activate the RC so we can launch it
Activate_RC_Mission(eRCMissionID, FALSE)
// Special case for Tonya phone call missions
IF eRCMissionID = RC_TONYA_3
OR eRCMissionID = RC_TONYA_4
// Load script
REQUEST_SCRIPT("ambient_Tonya")
WHILE NOT HAS_SCRIPT_LOADED("ambient_Tonya")
REQUEST_SCRIPT("ambient_Tonya")
WAIT(0)
ENDWHILE
// Launch script
START_NEW_SCRIPT("ambient_Tonya", DEFAULT_STACK_SIZE)
SET_SCRIPT_AS_NO_LONGER_NEEDED("ambient_Tonya")
CPRINTLN(DEBUG_REPEAT, "Launched ambient script for Tonya 3 or 4.")
ELSE
CPRINTLN(DEBUG_REPEAT, "Reactivating all world brains.")
REACTIVATE_ALL_WORLD_BRAINS_THAT_ARE_WAITING_TILL_OUT_OF_RANGE()
ENDIF
g_RandomChars[eRCMissionID].rcLeaveAreaCheck = FALSE
g_bSceneAutoTrigger = TRUE //Flag launchers to setup their RC scene to automatically trigger.
//Delay until rc is flagged as running.
CPRINTLN(DEBUG_REPEAT, "Waiting for RC mission to trigger.")
WHILE NOT g_RandomChars[eRCMissionID].rcIsRunning
g_RandomChars[eRCMissionID].rcLeaveAreaCheck = FALSE
WAIT(0)
ENDWHILE
g_bSceneAutoTrigger = FALSE
BREAK
DEFAULT
CPRINTLN(DEBUG_REPEAT,"Launch_Repeat_Play passed a mission type that isn't repeat playable: ", g_RepeatPlayData.eMissionType)
BREAK
ENDSWITCH
ELSE
CERRORLN(DEBUG_REPEAT,"Launch_Repeat_Play: player is injured. Abort!. bug for Andy Minghella.")
SCRIPT_ASSERT("Launch_Repeat_Play: player is injured. Abort!. bug for Andy Minghella")
Exit_Repeat_Play(TRUE)
EXIT
ENDIF
RepeatPlay_Freeze_Player(FALSE) // un freeze + no longer invincible
eRPState = RP_RUNNING
ENDPROC
/// PURPOSE:
/// Waits for the repeat play thread to terminate
PROC Run_Repeat_Play()
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play called.")
SWITCH g_RepeatPlayData.eMissionType
CASE CP_GROUP_MISSIONS
INT iCoreVarsArrayPos
iCoreVarsArrayPos = g_sMissionStaticData[g_RepeatPlayData.iMissionIndex].coreVariablesIndex
CPRINTLN(DEBUG_MISSION, "CoreVarsIndex in static data set to ", iCoreVarsArrayPos)
WHILE PERFORM_DO_MISSION_NOW(iCoreVarsArrayPos) = STAY_ON_THIS_COMMAND
WAIT(0)
// Story mission repeat play still running.
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play story mission passed or failed +rejected.")
// handle 2 part mission
SP_MISSIONS eMissionID
eMissionID= INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex)
//Handle Finale A and B
IF eMissionID = SP_MISSION_FINALE_A
OR eMissionID = SP_MISSION_FINALE_B
IF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
//Wait until the Finale Credits is passed as well
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play launching finale credits.")
// passed 2nd part, do credits
iCoreVarsArrayPos = g_sMissionStaticData[SP_MISSION_FINALE_CREDITS].coreVariablesIndex
WHILE PERFORM_DO_MISSION_NOW(iCoreVarsArrayPos) = STAY_ON_THIS_COMMAND
WAIT(0)
// Story mission repeat play still running
ENDWHILE
ENDIF
//Handle Finale C1
ELIF eMissionID = SP_MISSION_FINALE_C1
IF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play launching finale c2.")
// passed 1st part, do 2nd part of mission
iCoreVarsArrayPos = g_sMissionStaticData[SP_MISSION_FINALE_C2].coreVariablesIndex
WHILE PERFORM_DO_MISSION_NOW(iCoreVarsArrayPos) = STAY_ON_THIS_COMMAND
WAIT(0)
// Story mission repeat play still running
ENDWHILE
//Wait until the Finale Credits is passed as well
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play launching finale credits.")
// passed 2nd part, do credits
iCoreVarsArrayPos = g_sMissionStaticData[SP_MISSION_FINALE_CREDITS].coreVariablesIndex
WHILE PERFORM_DO_MISSION_NOW(iCoreVarsArrayPos) = STAY_ON_THIS_COMMAND
WAIT(0)
// Story mission repeat play still running
ENDWHILE
ENDIF
ENDIF
// if we're not staying on this command, repeat play was either passed or failed + rejected
IF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
eRPState = RP_PASSED
ELSE
eRPState = RP_FAILED
ENDIF
BREAK
CASE CP_GROUP_RANDOMCHARS
// wait for the mission thread to actually start
WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY(tScriptName)) =0
WAIT(0)
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play waiting for mission thread to start.")
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play mission thread started.")
//--------------------Wait for the mission script to terminate----------------------------
WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY(tScriptName)) >0
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Run_Repeat_Play mission thread terminated.")
/// ----------Pass / Fail-------------------------------
IF IS_BIT_SET(g_iRepeatPlayBits, ENUM_TO_INT(RPB_PASSED))
eRPState = RP_PASSED
ELSE
eRPState = RP_FAILED
ENDIF
BREAK
DEFAULT
CPRINTLN(DEBUG_REPEAT,"Run_Repeat_Play passed a mission type that isn't repeat playable: ", g_RepeatPlayData.eMissionType)
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Waits for pass stats to display then calls repeat play completed
PROC Repeat_Play_Passed()
INT iEarlyExitTimer = 0
INT iEarlyOutLimit = 20000
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Passed called.")
BOOL bWaitForPassedScreen = TRUE
IF g_RepeatPlayData.eMissionType = CP_GROUP_MISSIONS
SP_MISSIONS eMissionID = INT_TO_ENUM(SP_MISSIONS, g_RepeatPlayData.iMissionIndex)
// Some missions do their passed screens during the mission.
IF eMissionID = SP_MISSION_FAMILY_3
OR eMissionID = SP_MISSION_FAMILY_5
OR eMissionID = SP_MISSION_FAMILY_6
OR eMissionID = SP_HEIST_FINALE_2A
OR eMissionID = SP_HEIST_FINALE_2B
//OR eMissionID = SP_MISSION_FINALE_C1 //C1 IS c2, c1 seamless passes into C2, fix for last comment on 1593783
OR eMissionID = SP_HEIST_JEWELRY_2
bWaitForPassedScreen = FALSE
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Passed: This mission does passed screen on mission: Don't wait for passed screen.")
ENDIF
ENDIF
IF bWaitForPassedScreen = TRUE
//Wait for the mission pass stats to start displaying
iEarlyExitTimer = GET_GAME_TIMER() + iEarlyOutLimit
WHILE g_bResultScreenDisplaying = FALSE
AND GET_GAME_TIMER() < iEarlyExitTimer
AND (NOT g_MissionStatSystemSuppressVisual)
WAIT(0)
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Passed: Waiting for stats to start displaying.")
ENDWHILE
//Wait for the mission pass stats to finish displaying
iEarlyExitTimer = GET_GAME_TIMER() + 30000
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Passed: Starting to wait for stats to finish displaying...")
WHILE (g_bResultScreenDisplaying OR g_bMissionStatSystemUploadPending)
AND GET_GAME_TIMER() < iEarlyExitTimer
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Passed: Stats finished displaying.")
ENDIF
// fade out and exit
WHILE NOT IS_SCREEN_FADED_OUT()
IF NOT IS_SCREEN_FADING_OUT()
DO_SCREEN_FADE_OUT(DEFAULT_FADE_TIME)
ENDIF
WAIT(0)
ENDWHILE
Repeat_Play_Completed()
ENDPROC
/// PURPOSE:
/// Handles setting up, accepting and rejecting replays
PROC Repeat_Play_Failed()
CPRINTLN(DEBUG_REPEAT, "Repeat_Play_Failed called.")
// End of mission cleanup
SWITCH g_RepeatPlayData.eMissionType
CASE CP_GROUP_MISSIONS
// Story missions only enter the failed state after replay rejection
// so can go stright to the exit
CPRINTLN(DEBUG_REPEAT,"Story Mission repeat rejected.")
Repeat_Play_Completed()
BREAK
CASE CP_GROUP_RANDOMCHARS
// RC replays should work ok since they don't rely on flow commands
WHILE IS_REPLAY_BEING_PROCESSED()
WAIT(0)
CPRINTLN(DEBUG_REPEAT,"Mission repeat RC waiting to be set up for a replay.")
ENDWHILE
// Handle accepting / rejecting of replay
IF IS_REPLAY_IN_PROGRESS()
CPRINTLN(DEBUG_REPEAT,"Mission repeat RC accepted.")
// replay accepted, wait for script to be running and go back into running state
WHILE GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(GET_HASH_KEY(tScriptName)) =0
WAIT(0)
CPRINTLN(DEBUG_REPEAT,"Waiting for RC replay to launch.")
ENDWHILE
eRPState = RP_RUNNING
ELSE
CPRINTLN(DEBUG_REPEAT,"Mission repeat RC rejected.")
Repeat_Play_Completed() // replay rejected, this repeat play is complete
ENDIF
BREAK
DEFAULT
CPRINTLN(DEBUG_REPEAT,"Repeat_Play_Failed passed a mission type that isn't repeat playable: ", g_RepeatPlayData.eMissionType)
Repeat_Play_Completed()
BREAK
ENDSWITCH
ENDPROC
// ----------------Main Loop-------------------------------------------------------------
SCRIPT
CPRINTLN(DEBUG_REPEAT,"Starting mission repeat controller.")
// This script needs to cleanup only when the game moves from SP to MP
IF (HAS_FORCE_CLEANUP_OCCURRED(FORCE_CLEANUP_FLAG_SP_TO_MP|FORCE_CLEANUP_FLAG_MAGDEMO))
CPRINTLN(DEBUG_REPEAT,"Mission_repeat_controller.sc has been forced to cleanup.")
IF GET_CAUSE_OF_MOST_RECENT_FORCE_CLEANUP() = FORCE_CLEANUP_FLAG_SP_TO_MP
CPRINTLN(DEBUG_REPEAT,"Mission_repeat_controller.sc has been forced to cleanup (SP to MP)")
SET_FRONTEND_ACTIVE(FALSE)
LOBBY_SET_AUTO_MULTIPLAYER(TRUE)
SHUTDOWN_SESSION_CLEARS_AUTO_MULTIPLAYER(FALSE)
QUEUE_MISSION_REPEAT_LOAD()
ENDIF
SET_PLAYER_IS_REPEATING_A_MISSION(FALSE)
TERMINATE_THIS_THREAD()
ENDIF
WHILE TRUE
IF IS_REPEAT_PLAY_ACTIVE()
SWITCH eRPState
CASE RP_SETUP
Setup_Repeat_Play()
BREAK
CASE RP_HEIST_PLANNING_BOARD
Do_Heist_Planning_Board()
BREAK
CASE RP_LAUNCH
Launch_Repeat_Play()
BREAK
CASE RP_RUNNING
Run_Repeat_Play()
BREAK
CASE RP_PASSED
Repeat_Play_Passed()
BREAK
CASE RP_FAILED
Repeat_Play_Failed()
BREAK
ENDSWITCH
ENDIF
WAIT(0)
ENDWHILE
ENDSCRIPT