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

881 lines
29 KiB
Python
Executable File

//Compile out Title Update changes to header functions.
//Must be before includes.
//CONST_INT USE_TU_CHANGES 0 // Removed by Kenneth R.
USING "cutscene_public.sch"
USING "RC_launcher_public.sch"
USING "RC_Setup_public.sch"
USING "initial_scenes_Epsilon.sch"
// *****************************************************************************************
// SCRIPT NAME : launcher_Epsilon.sc
//
// AUTHOR : David Roberts / Andrew Minghella
//
// DESCRIPTION : Launcher script that determines which RC mission scene to setup.
// This launcher script should be attached to appropriate world point.
//
// If multiple missions share same coord or are within close proximity,
// we should just add one world point, and adjust the tolerance float.
// *****************************************************************************************
ENUM EPS_CONV_STATE
EPS_CONV_WAITING,
EPS_CONV_DOLINE,
EPS_CONV_SPEAKING
ENDENUM
ENUM EPS6_WANDER_STATE
WANDER_INIT,
WANDER_GOTO,
WANDER_NOWGOINGTO,
WANDER_IDLEANIM,
WANDER_IDLEFINISH
ENDENUM
// ------------Variables----------------------
// Constants
CONST_FLOAT WORLD_POINT_COORD_TOLERANCE 5.0
CONST_FLOAT HELP_TEXT_RESET_DISTANCE 25.0
SCENARIO_BLOCKING_INDEX mScenarioBlocker
INT iCutsceneLoadRequestID = NULL_OFFMISSION_CUTSCENE_REQUEST
EPS_CONV_STATE EpsConv = EPS_CONV_WAITING
structPedsForConversation ConvStruct
INT iConvTimer
BOOL bDoConv = FALSE // Prevent Epsilon 4 conversation from looping
BOOL bStorageRoomLocked = FALSE // Epsilon 2 storage room blocked when in a vehicle
BLIP_INDEX biLeadIn // Blip for lead-in sequence
SEQUENCE_INDEX siEps3Flee
// Epsilon 4 detector things
SCALEFORM_INDEX si_DetectorScaleform
INT rt_ID
INT iPhaseTimer
INT iDetectorSndID
EPS6_WANDER_STATE Eps6Wander = WANDER_INIT
INT iWanderStage = 0
VECTOR vTomCoords[3]
//-------------------Debug Functions------------------------
#IF IS_DEBUG_BUILD
USING "shared_debug.sch"
WIDGET_GROUP_ID m_WidgetGroup
BOOL m_bGivePlayerCash = FALSE
/// PURPOSE:
/// Creates debug widgets for this mission
/// PARAMS:
/// eRCMissionToLaunch - which mission we want the widgets for
PROC SETUP_DEBUG_WIDGETS(g_eRC_MissionIDs& eRCMissionToLaunch)
TEXT_LABEL_63 money = "Give Player $"
SWITCH eRCMissionToLaunch
// Deliver $500
CASE RC_EPSILON_2
START_WIDGET_GROUP("Random Character: Epsilon 2")
money += EPSILON_2_CASH_AMOUNT
ADD_WIDGET_BOOL(money, m_bGivePlayerCash)
STOP_WIDGET_GROUP()
BREAK
// Deliver $5000
CASE RC_EPSILON_3
START_WIDGET_GROUP("Random Character: Epsilon 3")
money += EPSILON_3_CASH_AMOUNT
ADD_WIDGET_BOOL(money, m_bGivePlayerCash)
STOP_WIDGET_GROUP()
BREAK
// Deliver $10000
CASE RC_EPSILON_8
START_WIDGET_GROUP("Random Character: Epsilon 8")
money += EPSILON_8_CASH_AMOUNT
ADD_WIDGET_BOOL(money, m_bGivePlayerCash)
STOP_WIDGET_GROUP()
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Monitors for widgets being used to give player cash.
/// PARAMS:
/// eRCMissionToLaunch - which mission's widgets to monitor
PROC UPDATE_DEBUG_WIDGETS(g_eRC_MissionIDs& eRCMissionToLaunch)
IF m_bGivePlayerCash
SWITCH eRCMissionToLaunch
CASE RC_EPSILON_2
CREDIT_BANK_ACCOUNT(CHAR_MICHAEL, BAAC_DEFAULT_DEBUG, EPSILON_2_CASH_AMOUNT)
BREAK
CASE RC_EPSILON_3
CREDIT_BANK_ACCOUNT(CHAR_MICHAEL, BAAC_DEFAULT_DEBUG, EPSILON_3_CASH_AMOUNT)
BREAK
CASE RC_EPSILON_8
CREDIT_BANK_ACCOUNT(CHAR_MICHAEL, BAAC_DEFAULT_DEBUG, EPSILON_8_CASH_AMOUNT)
BREAK
ENDSWITCH
m_bGivePlayerCash = FALSE
ENDIF
ENDPROC
/// PURPOSE:
/// Removes the debug widgets
PROC CLEANUP_DEBUG_WIDGETS()
IF DOES_WIDGET_GROUP_EXIST(m_WidgetGroup)
DELETE_WIDGET_GROUP(m_WidgetGroup)
ENDIF
ENDPROC
/// PURPOSE: Helper function that determines whether mission needs cash in order to launch
FUNC BOOL Does_Mission_Require_Cash(g_eRC_MissionIDs& eRCMissionToLaunch)
// Epsilon 2&3 require cash donations
IF (eRCMissionToLaunch = RC_EPSILON_2)
OR (eRCMissionToLaunch = RC_EPSILON_3)
OR (eRCMissionToLaunch = RC_EPSILON_8)
RETURN TRUE
ELSE
RETURN FALSE
ENDIF
ENDFUNC
/// PURPOSE: Put player into outfit or give money if on autoplay
PROC HANDLE_RC_RESTRICTIONS_ON_AUTOPLAY(g_eRC_MissionIDs& eRCMissionToLaunch)
IF g_bFlowAutoplayInProgress
SWITCH eRCMissionToLaunch
// Michael needs to wear the Epsilon robes
CASE RC_EPSILON_7
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_OUTFIT, OUTFIT_P0_EPSILON)
BREAK
// Michael needs $
CASE RC_EPSILON_8
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_OUTFIT, OUTFIT_P0_EPSILON)
CREDIT_BANK_ACCOUNT(CHAR_MICHAEL, BAAC_UNLOGGED_SMALL_ACTION, EPSILON_8_CASH_AMOUNT)
BREAK
ENDSWITCH
ENDIF
ENDPROC
#ENDIF
// ----------Functions -------------------------
/// PURPOSE:
/// Does any necessary cleanup and terminates the launcher's thread.
/// PARAMS:
/// sData - launcher data struct
/// bCleanupEntities - do we want to cleanup the entities in the launcher struct
PROC Script_Cleanup(g_structRCScriptArgs& sData, BOOL bCleanupEntities=TRUE)
// Clear scene entities created by RC launcher
IF bCleanupEntities
PRINT_LAUNCHER_DEBUG("Cleaning up launcher script entities [TERMINATING]")
RC_CleanupSceneEntities(sData, FALSE)
ENDIF
// Remove lead-in blip
IF DOES_BLIP_EXIST(biLeadIn)
REMOVE_BLIP(biLeadIn)
ENDIF
// Clear any cutscene requests with controller.
IF iCutsceneLoadRequestID != NULL_OFFMISSION_CUTSCENE_REQUEST
PRINT_LAUNCHER_DEBUG("SCRIPT TERMINATING: Ending off-mission cutscene request")
END_OFFMISSION_CUTSCENE_REQUEST(iCutsceneLoadRequestID)
ENDIF
// Remove scenario blocking areas
IF sData.eMissionID = RC_EPSILON_4
OR sData.eMissionID = RC_EPSILON_7
OR sData.eMissionID = RC_EPSILON_8
REMOVE_SCENARIO_BLOCKING_AREA(mScenarioBlocker)
ENDIF
// Cleanup debug functions
#IF IS_DEBUG_BUILD CLEANUP_DEBUG_WIDGETS() #ENDIF
// Unload launcher animation dictionary
REMOVE_LAUNCHER_ANIM_DICT(sData.sAnims)
// mission specific cleanup
SWITCH sData.eMissionID
CASE RC_EPSILON_1
//cleanup hill sfx (ocurs when player is far enough away to not hear the cleanup)
SET_AMBIENT_ZONE_STATE("AZ_EPSILONISM_01_HILLS", FALSE)
BREAK
CASE RC_EPSILON_6
// this is the detector anim set used by the cultist in Epsilon 6
REMOVE_ANIM_DICT("rcmepsilonism6")
BREAK
ENDSWITCH
// Stop launcher conversation
STRING sConversationRoot
SWITCH sData.eMissionID
CASE RC_EPSILON_3
sConversationRoot = "EP3_RCM_L2"
BREAK
CASE RC_EPSILON_4
// this mission uses 2 conversations, so cleanup both
RC_STOP_LAUNCHER_DIALOGUE("EPS4_AMBM")
sConversationRoot = "EPS4_AMBJ"
BREAK
CASE RC_EPSILON_8
// this mission uses 2 conversations, so cleanup both
RC_STOP_LAUNCHER_DIALOGUE("EPS8_AMB1")
sConversationRoot = "EPS8_AMB2"
BREAK
ENDSWITCH
RC_STOP_LAUNCHER_DIALOGUE(sConversationRoot)
//B*1574385 - Force update to blip in RandChar Controller if mission wasn't launched
IF bCleanupEntities
SET_RC_AWAITING_TRIGGER(sData.eMissionID)
ENDIF
//B* 2089222 - Unblock quicksaving
g_QuickSaveDisabledByScript = FALSE
RC_LAUNCHER_END()
// Kill the thread
PRINT_LAUNCHER_DEBUG("SCRIPT TERMINATED")
TERMINATE_THIS_THREAD()
ENDPROC
/// PURPOSE: Display relevant help text for specified Epsilon mission
PROC Display_Help_Text(g_eRC_MissionIDs& eRCMissionToLaunch, BOOL& bDisplayHelp)
IF bDisplayHelp
SWITCH eRCMissionToLaunch
CASE RC_EPSILON_7
PRINT_LAUNCHER_DEBUG("Need to wear robes to launch Epsilon 7...")
PRINT_HELP_WITH_STRING("BADSUIT_HELP", "OUTFIT_P0_11")
bDisplayHelp = FALSE
BREAK
CASE RC_EPSILON_8
PRINT_LAUNCHER_DEBUG("Need robes and $ to launch Epsilon 8...")
PRINT_HELP_WITH_STRING_AND_NUMBER("NOCASH_HELP", "OUTFIT_P0_11", EPSILON_8_CASH_AMOUNT)
bDisplayHelp = FALSE
BREAK
DEFAULT
PRINT_LAUNCHER_DEBUG("Tried to show help text for invalid mission")
BREAK
ENDSWITCH
ENDIF
ENDPROC
/// PURPOSE: Check to see whether we need to display the help text again...
PROC Monitor_Help_Text(g_structRCScriptArgs& sData, BOOL& bDisplayHelp)
// Help text has been recently displayed
IF NOT bDisplayHelp
// Reset call to display help text when player walks out of activation range
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF NOT IS_PED_INJURED(PLAYER_PED_ID())
IF (GET_DISTANCE_BETWEEN_COORDS(GET_ENTITY_COORDS(PLAYER_PED_ID()), sData.triggerLocate[0]) > HELP_TEXT_RESET_DISTANCE)
PRINT_LAUNCHER_DEBUG("Resetting help text flag as player has moved out of range...")
bDisplayHelp = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Manages locking and unlocking the storage room for Epsilon 2
/// Also blocks quicksaving when in front of it
PROC DO_EPS2_DOOR_UPDATE()
IF IS_PLAYER_PLAYING(PLAYER_ID())
IF IS_PED_ON_FOOT(PLAYER_PED_ID())
IF bStorageRoomLocked
SET_DOOR_STATE(DOORNAME_EPSILON2_STORAGE_ROOM, DOORSTATE_UNLOCKED)
bStorageRoomLocked = FALSE
ENDIF
ELSE
IF NOT bStorageRoomLocked
SET_DOOR_STATE(DOORNAME_EPSILON2_STORAGE_ROOM, DOORSTATE_LOCKED)
bStorageRoomLocked = TRUE
ENDIF
ENDIF
ENDIF
//Block quicksaving
IF IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<244.966919,374.669586,104.457909>>, <<239.611908,360.304504,107.752342>>, 9.062500)
g_QuickSaveDisabledByScript = TRUE
ELSE
g_QuickSaveDisabledByScript = FALSE
ENDIF
ENDPROC
PROC SET_UP_EPS4_DETECTOR_SCREEN()
si_DetectorScaleform = REQUEST_SCALEFORM_MOVIE("digiscanner")
WHILE NOT HAS_SCALEFORM_MOVIE_LOADED(si_DetectorScaleform)
WAIT(0)
ENDWHILE
IF NOT IS_NAMED_RENDERTARGET_REGISTERED("digiscanner")
REGISTER_NAMED_RENDERTARGET("digiscanner")
ENDIF
LINK_NAMED_RENDERTARGET(GET_WEAPONTYPE_MODEL(WEAPONTYPE_DIGISCANNER))
IF IS_NAMED_RENDERTARGET_REGISTERED("digiscanner")
rt_ID = GET_NAMED_RENDERTARGET_RENDER_ID("digiscanner")
ENDIF
iDetectorSndID = GET_SOUND_ID()
iPhaseTimer = GET_GAME_TIMER()
ENDPROC
PROC FORCE_NOT_FOUND_SCREEN_ON_DETECTOR()
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_COLOUR")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //BarsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //BarsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //BarsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //LightsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //LightsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //LightsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //WrongWayR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //WrongWayG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(10) //WrongWayB
END_SCALEFORM_MOVIE_METHOD()
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_DISTANCE")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(10.0)
END_SCALEFORM_MOVIE_METHOD()
SET_TEXT_RENDER_ID(rt_ID)
DRAW_SCALEFORM_MOVIE(si_DetectorScaleform, 0.100, 0.24000, 0.2100,0.51000, 100,100,100,255)
IF (GET_GAME_TIMER() - iPhaseTimer) > 1250
PLAY_SOUND_FROM_COORD(iDetectorSndID, "IDLE_BEEP_NPC", <<1827.06, 4700.52, 39.16>>, "EPSILONISM_04_SOUNDSET")
iPhaseTimer = GET_GAME_TIMER()
ENDIF
ENDPROC
/// PURPOSE:
/// Does the initial scene conversation for Epsilon 4
PROC DO_EPS4_AMB()
SWITCH EpsConv
CASE EPS_CONV_WAITING
EpsConv = EPS_CONV_DOLINE
BREAK
CASE EPS_CONV_DOLINE
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), <<1826.45, 4699.58, 38.15>>) <= 25.0
AND bDoConv = FALSE
IF CREATE_CONVERSATION(ConvStruct, "EPS4AUD", "EPS4_AMBJ", CONV_PRIORITY_HIGH)
EpsConv = EPS_CONV_SPEAKING
bDoConv = TRUE
ENDIF
ENDIF
BREAK
CASE EPS_CONV_SPEAKING
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
EpsConv = EPS_CONV_WAITING
ELIF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), <<1826.45, 4699.58, 38.15>>) >= 28.0
KILL_ANY_CONVERSATION()
EpsConv = EPS_CONV_WAITING
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// State machine to handle Tom wandering around at the start of Eps 6
PROC DO_EPS6_TOM(g_structRCScriptArgs &sData)
IF IS_ENTITY_ALIVE(sData.pedID[0])
SWITCH Eps6Wander
CASE WANDER_INIT
iWanderStage = 0
vTomCoords[0] = <<-2887.15, 3197.88, 10.17>>
vTomCoords[1] = <<-2888.92, 3203.76, 10.60>>
vTomCoords[2] = <<-2895.37, 3199.37, 10.03>>
REQUEST_ANIM_DICT("rcmepsilonism6")
IF HAS_ANIM_DICT_LOADED("rcmepsilonism6")
TASK_PLAY_ANIM(sData.pedID[0], "rcmepsilonism6", "cultist_upperstatic", DEFAULT, DEFAULT, -1, AF_UPPERBODY|AF_SECONDARY|AF_LOOPING)
Eps6Wander = WANDER_GOTO
PRINT_LAUNCHER_DEBUG("Initialised Eps 6 Tom state machine")
ENDIF
BREAK
CASE WANDER_GOTO
IF NOT IsPedPerformingTask(sData.pedID[0], SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD)
TASK_FOLLOW_NAV_MESH_TO_COORD(sData.pedID[0], vTomCoords[iWanderStage], PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_BEFORE_WARP)
PRINT_LAUNCHER_DEBUG("Eps 6: Nav tasking Tom...")
Eps6Wander = WANDER_NOWGOINGTO
ENDIF
BREAK
CASE WANDER_NOWGOINGTO
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(sData.pedID[0], vTomCoords[iWanderStage]) <= 1.2
Eps6Wander = WANDER_IDLEANIM
PRINT_LAUNCHER_DEBUG("Eps 6: Tom at coord; do idle anim")
ENDIF
BREAK
CASE WANDER_IDLEANIM
CLEAR_PED_TASKS(sData.pedID[0])
TASK_PLAY_ANIM(sData.pedID[0], "rcmepsilonism6", "cultist_idle_a", FAST_BLEND_IN, REALLY_SLOW_BLEND_OUT, -1, AF_FORCE_START)
FORCE_PED_AI_AND_ANIMATION_UPDATE(sData.pedID[0])
Eps6Wander = WANDER_IDLEFINISH
PRINT_LAUNCHER_DEBUG("Eps 6: Done Tom idle anim")
BREAK
CASE WANDER_IDLEFINISH
IF IS_ENTITY_PLAYING_ANIM(sData.pedID[0], "rcmepsilonism6", "cultist_idle_a")
IF GET_ENTITY_ANIM_CURRENT_TIME(sData.pedID[0], "rcmepsilonism6", "cultist_idle_a") >=0.98
IF iWanderStage >= 2
iWanderStage = 0
ELSE
iWanderStage++
ENDIF
TASK_PLAY_ANIM(sData.pedID[0], "rcmepsilonism6", "cultist_upperstatic", FAST_BLEND_IN, DEFAULT, -1, AF_UPPERBODY|AF_SECONDARY|AF_LOOPING)
FORCE_PED_AI_AND_ANIMATION_UPDATE(sData.pedID[0])
Eps6Wander = WANDER_GOTO
PRINT_LAUNCHER_DEBUG("Eps 6: Tom idle anim >0.98")
ENDIF
ELSE
IF iWanderStage >= 2
iWanderStage = 0
ELSE
iWanderStage++
ENDIF
TASK_PLAY_ANIM(sData.pedID[0], "rcmepsilonism6", "cultist_upperstatic", DEFAULT, DEFAULT, -1, AF_UPPERBODY|AF_SECONDARY|AF_LOOPING)
Eps6Wander = WANDER_GOTO
PRINT_LAUNCHER_DEBUG("Eps 6: Tom idle anim not playing")
ENDIF
BREAK
ENDSWITCH
ENDIF
ENDPROC
/// PURPOSE:
/// Guards say Kifflom to Michael at the mansion - Epsilon 8
PROC DO_EPS8_KIFFLOM()
SWITCH EpsConv
CASE EPS_CONV_WAITING
IF (GET_GAME_TIMER() - iConvTimer) > 20000 //1 min delay between each Kifflom
EpsConv = EPS_CONV_DOLINE
ENDIF
BREAK
CASE EPS_CONV_DOLINE
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), <<-726.45, 33.33, 43.23>>) < 9 //Guy at the East entrance
IF CREATE_CONVERSATION(ConvStruct, "EPS8AU", "EPS8_AMB1", CONV_PRIORITY_MEDIUM) //Kifflom.
EpsConv = EPS_CONV_SPEAKING
ENDIF
ENDIF
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(), <<-666.55, 49.19, 42.08>>) < 9 //Guy at the West entrance
IF CREATE_CONVERSATION(ConvStruct, "EPS8AU", "EPS8_AMB2", CONV_PRIORITY_MEDIUM) //Kifflom Zondar.
EpsConv = EPS_CONV_SPEAKING
ENDIF
ENDIF
BREAK
CASE EPS_CONV_SPEAKING
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
iConvTimer = GET_GAME_TIMER()
EpsConv = EPS_CONV_WAITING
ENDIF
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Guards kick off if player interferes with the initial scene - Epsilon 8
PROC DO_EPS8_KICK_OFF()
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_HATE,relgroupEpsilon8,RELGROUPHASH_PLAYER)
IF GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(),<<-726.45, 33.33, 43.23>>) <= GET_DISTANCE_BETWEEN_ENTITY_AND_COORD(PLAYER_PED_ID(),<<-666.55, 49.19, 42.08>>)
CREATE_CONVERSATION(ConvStruct, "EPS8AU", "EPS8_AMA1", CONV_PRIORITY_HIGH) //Protect the apocalype funds!
ELSE
CREATE_CONVERSATION(ConvStruct, "EPS8AU", "EPS8_AMA2", CONV_PRIORITY_HIGH) //Cleanse the unbeliever!
ENDIF
ENDPROC
/// PURPOSE:
/// Creates the initial scene
FUNC BOOL LOAD_INITIAL_SCENE(g_structRCScriptArgs& sData)
// Setup the correct initial scene
SWITCH sData.eMissionID
CASE RC_EPSILON_1
IF NOT SetupScene_EPSILON_1(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_2
IF NOT SetupScene_EPSILON_2(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_3
IF NOT SetupScene_EPSILON_3(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_4
IF NOT SetupScene_EPSILON_4(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_5
IF NOT SetupScene_EPSILON_5(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_6
IF NOT SetupScene_EPSILON_6(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_7
IF NOT SetupScene_EPSILON_7(sData)
RETURN FALSE
ENDIF
BREAK
CASE RC_EPSILON_8
IF NOT SetupScene_EPSILON_8(sData)
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
// Setup scenario blockers
IF sData.eMissionID = RC_EPSILON_4
mScenarioBlocker = Eps4_Scenario_Blocker()
ELIF sData.eMissionID = RC_EPSILON_7
mScenarioBlocker = Eps7_Scenario_Blocker()
CLEAR_AREA_OF_PEDS(<<538.45, 3079.61, 39.27>>, 75.0)
ELIF sData.eMissionID = RC_EPSILON_8
mScenarioBlocker = Eps8_Scenario_Blocker()
ENDIF
// Scene creation successful
PRINT_LAUNCHER_DEBUG("Created initial scene")
RETURN TRUE
ENDFUNC
/// PURPOSE: Does the player meet the requirements of this specific RCM
FUNC BOOL IS_RC_SPECIFIC_RESTRICTION_MET(g_eRC_MissionIDs& eRCMissionToLaunch)
SWITCH eRCMissionToLaunch
// Michael needs to wear the Epsilon robes
CASE RC_EPSILON_7
RETURN IS_PLAYER_IN_CORRECT_OUTFIT(eRCMissionToLaunch)
BREAK
// Michael needs $
CASE RC_EPSILON_8
IF IS_REPEAT_PLAY_ACTIVE()
SET_PED_COMP_ITEM_AVAILABLE_SP(PLAYER_ZERO, COMP_TYPE_OUTFIT, OUTFIT_P0_EPSILON_WITH_MEDAL,TRUE)
SET_PED_COMP_ITEM_ACQUIRED_SP(PLAYER_ZERO, COMP_TYPE_OUTFIT, OUTFIT_P0_EPSILON_WITH_MEDAL,TRUE)
SET_PED_COMP_ITEM_CURRENT_SP(PLAYER_PED_ID(), COMP_TYPE_OUTFIT, OUTFIT_P0_EPSILON_WITH_MEDAL,FALSE)
CREDIT_BANK_ACCOUNT(CHAR_MICHAEL, BAAC_UNLOGGED_SMALL_ACTION, EPSILON_8_CASH_AMOUNT)
ENDIF
IF (GET_TOTAL_CASH(CHAR_MICHAEL) >= EPSILON_8_CASH_AMOUNT)
OR (g_savedGlobals.sRandomChars.g_bFinalEpsilonPayment = TRUE)
RETURN IS_PLAYER_IN_CORRECT_OUTFIT(eRCMissionToLaunch)
ELSE
RETURN FALSE
ENDIF
BREAK
ENDSWITCH
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Main script loops
/// PARAMS:
/// in_coords - world point co-ords
SCRIPT(coords_struct in_coords)
// Launcher priority for streaming requests
SET_THIS_IS_A_TRIGGER_SCRIPT(TRUE)
RC_LAUNCHER_START()
g_structRCScriptArgs sRCLauncherData // Scene information to pass to mission script
VECTOR vInCoords = <<0,0,0>> // Stores world point location
BOOL bDisplayHelp = TRUE // Whether we need to prompt help text
//Reset all basic values of the data, so each scene has to set them up correctly
RC_Reset_LauncherData(sRCLauncherData)
// Update world point
vInCoords = in_coords.vec_coord[0]
// Determine which RC mission we are attempting to launch (currently done on a launcher by launcher basis)
g_eRC_MissionIDs eRCMissions[8]
eRCMissions[0] = RC_EPSILON_1
eRCMissions[1] = RC_EPSILON_2
eRCMissions[2] = RC_EPSILON_3
eRCMissions[3] = RC_EPSILON_4
eRCMissions[4] = RC_EPSILON_5
eRCMissions[5] = RC_EPSILON_6
eRCMissions[6] = RC_EPSILON_7
eRCMissions[7] = RC_EPSILON_8
// Setup callback when player is killed, arrested or goes to multiplayer
IF (HAS_FORCE_CLEANUP_OCCURRED(DEFAULT_FORCE_CLEANUP_FLAGS|FORCE_CLEANUP_FLAG_DEBUG_MENU|FORCE_CLEANUP_FLAG_REPEAT_PLAY))
PRINT_LAUNCHER_DEBUG("Force cleanup [TERMINATING]")
// Ensure candidate id is released in the event that the player has died
// or been arrested prior to mission launch
IF sRCLauncherData.eMissionID <> NO_RC_MISSION
IF (g_RandomChars[sRCLauncherData.eMissionID].rcMissionCandidateID <> NO_CANDIDATE_ID)
PRINT_LAUNCHER_DEBUG("Relinquishing candidate id...")
Mission_Over(g_RandomChars[sRCLauncherData.eMissionID].rcMissionCandidateID)
ENDIF
ENDIF
// Standard cleanup
Script_Cleanup(sRCLauncherData)
ENDIF
// Pick which mission activated us
IF NOT (DETERMINE_RC_TO_LAUNCH(eRCMissions, sRCLauncherData, vInCoords, WORLD_POINT_COORD_TOLERANCE))
RC_LAUNCHER_END()
PRINT_LAUNCHER_DEBUG("SCRIPT TERMINATED")
TERMINATE_THIS_THREAD() // B* 1510945 - don't call cleanup if nothing has been setup yet
ENDIF
// Check with the Random Character Controller to see if this script is allowed to launch
IF NOT CAN_RC_LAUNCH(sRCLauncherData.eMissionID)
RC_LAUNCHER_END()
PRINT_LAUNCHER_DEBUG("SCRIPT TERMINATED")
TERMINATE_THIS_THREAD() // B* 1510945 - don't call cleanup if nothing has been setup yet
ENDIF
// Halt launcher as we are incorrect character
IF Random_Character_Blocked_Due_To_Character(sRCLauncherData.eMissionID)
RC_LAUNCHER_END()
PRINT_LAUNCHER_DEBUG("SCRIPT TERMINATED")
TERMINATE_THIS_THREAD() // B* 1510945 - don't call cleanup if nothing has been setup yet
ENDIF
// The script is allowed to launch so set up the initial scene
WHILE NOT LOAD_INITIAL_SCENE(sRCLauncherData)
WAIT(0)
IF NOT IS_WORLD_POINT_WITHIN_BRAIN_ACTIVATION_RANGE()
PRINT_LAUNCHER_DEBUG("Player out of range [TERMINATING]")
Script_Cleanup(sRCLauncherData)
ENDIF
ENDWHILE
// Clears area of non-mission entities and blood decals
CLEAR_AREA(vInCoords, sRCLauncherData.activationRange, TRUE)
IF sRCLauncherData.eMissionID = RC_EPSILON_3
ADD_PED_FOR_DIALOGUE(ConvStruct, 3, sRCLauncherData.pedID[0], "MARNIE")
ENDIF
IF sRCLauncherData.eMissionID = RC_EPSILON_4
ADD_PED_FOR_DIALOGUE(ConvStruct, 4, sRCLauncherData.pedID[0], "MARNIE")
ADD_PED_FOR_DIALOGUE(ConvStruct, 5, sRCLauncherData.pedID[1], "JIMMYBOSTON")
iConvTimer = GET_GAME_TIMER()
SET_UP_EPS4_DETECTOR_SCREEN()
ENDIF
IF sRCLauncherData.eMissionID = RC_EPSILON_5
ADD_PED_FOR_DIALOGUE(ConvStruct, 4, sRCLauncherData.pedID[0], "MARNIE")
ENDIF
IF sRCLauncherData.eMissionID = RC_EPSILON_8
ADD_PED_FOR_DIALOGUE(ConvStruct, 4, sRCLauncherData.pedID[0], "EPSGUARD5")
ADD_PED_FOR_DIALOGUE(ConvStruct, 5, sRCLauncherData.pedID[1], "EPSGUARD6")
ENDIF
#IF IS_DEBUG_BUILD
// Setup debug cash functions for Epsilon 2,3&8
IF Does_Mission_Require_Cash(sRCLauncherData.eMissionID)
SETUP_DEBUG_WIDGETS(sRCLauncherData.eMissionID)
ENDIF
// Handle outfit/cash on autoplay
HANDLE_RC_RESTRICTIONS_ON_AUTOPLAY(sRCLauncherData.eMissionID)
#ENDIF
// Loop to check conditions - should script terminate? or is player close enough to trigger mission?
WHILE (TRUE)
WAIT(0)
// Is the player still in activation range?
IF NOT IS_RC_FINE_AND_IN_RANGE(sRCLauncherData)
// For B*900468: Security attack player if he interferes with Epsilon 8 initial scene
IF sRCLauncherData.eMissionID = RC_EPSILON_8
AND (IS_WORLD_POINT_WITHIN_BRAIN_ACTIVATION_RANGE())
PRINT_LAUNCHER_DEBUG("Epsilon 8 kicking off! [TERMINATING]")
MAKE_ALL_INITIAL_SCENE_PEDS_ATTACK_PLAYER(sRCLauncherData)
DO_EPS8_KICK_OFF()
ENDIF
IF sRCLauncherData.eMissionID = RC_EPSILON_6
SET_VEHICLE_GEN_AVAILABLE(VEHGEN_EPSILON6_PLANE, TRUE) // Reenable the vehicle gen
ENDIF
Script_Cleanup(sRCLauncherData)
ENDIF
// Mission specific updates
IF sRCLauncherData.eMissionID = RC_EPSILON_2
DO_EPS2_DOOR_UPDATE()
IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<237.925980,360.299164,103.651520>>, <<244.689896,357.827728,107.322365>>, 4.75)
SET_PED_MAX_MOVE_BLEND_RATIO(PLAYER_PED_ID(), PEDMOVEBLENDRATIO_WALK)
ENDIF
ELIF sRCLauncherData.eMissionID = RC_EPSILON_3
IF IS_ENTITY_ALIVE(sRCLauncherData.pedID[0])
IF NOT IS_PED_FLEEING(sRCLauncherData.pedID[0])
AND NOT IS_PED_RAGDOLL(sRCLauncherData.pedID[0])
PLAY_LAUNCHER_AMBIENT_DIALOGUE(sRCLauncherData, vInCoords, "EPS3AUD", "EP3_AMB", 3, "MARNIE", 500)
ENDIF
IF HAS_PLAYER_THREATENED_PED(sRCLauncherData.pedID[0])
IF HAS_ANIM_DICT_LOADED("rcmepsilonism3")
OPEN_SEQUENCE_TASK(siEps3Flee)
TASK_PLAY_ANIM(NULL, "rcmepsilonism3", "outro")
TASK_SMART_FLEE_PED(NULL, PLAYER_PED_ID(), 200, -1)
CLOSE_SEQUENCE_TASK(siEps3Flee)
TASK_PERFORM_SEQUENCE(sRCLauncherData.pedID[0], siEps3Flee)
ELSE
TASK_SMART_FLEE_PED(sRCLauncherData.pedID[0], PLAYER_PED_ID(), 200, -1)
ENDIF
SET_PED_KEEP_TASK(sRCLauncherData.pedID[0], TRUE)
SET_PED_AS_NO_LONGER_NEEDED(sRCLauncherData.pedID[0])
Script_Cleanup(sRCLauncherData)
ENDIF
ENDIF
ELIF sRCLauncherData.eMissionID = RC_EPSILON_4
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
PRINT_LAUNCHER_DEBUG("Can request assets for cutscene entity in Eps 4")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
ENDIF
FORCE_NOT_FOUND_SCREEN_ON_DETECTOR()
IF IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<1826.621216,4698.734375,41.368622>>, <<1831.157593,4680.191406,32.426258>>, 16.50)
IF NOT IS_PED_IN_ANY_VEHICLE(PLAYER_PED_ID())
IF NOT IsPedPerformingTask(PLAYER_PED_ID(), SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD)
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_LEAVE_CAMERA_CONTROL_ON)
TASK_FOLLOW_NAV_MESH_TO_COORD(PLAYER_PED_ID(), <<1827.34, 4697.22, 38.02>>, PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_BEFORE_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_NO_STOPPING)
ENDIF
ENDIF
ENDIF
DO_EPS4_AMB()
ELIF sRCLauncherData.eMissionID = RC_EPSILON_5
IF IS_ENTITY_ALIVE(sRCLauncherData.pedID[0])
IF NOT IS_PED_FLEEING(sRCLauncherData.pedID[0])
AND NOT IS_PED_RAGDOLL(sRCLauncherData.pedID[0])
IF PLAY_LAUNCHER_FULL_CONVERSATION(sRCLauncherData, vInCoords, "EPS5AUD", "EP5_AMB", 4, "MARNIE", 1500)
PRINT_LAUNCHER_DEBUG("Triggered Mary Ann Eps 5 conv")
ENDIF
ENDIF
IF HAS_PLAYER_THREATENED_PED(sRCLauncherData.pedID[0])
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
PRINT_LAUNCHER_DEBUG("Killed Eps 5 conversation (threat)")
KILL_ANY_CONVERSATION()
ENDIF
TASK_SMART_FLEE_PED(sRCLauncherData.pedID[0], PLAYER_PED_ID(), 200, -1)
SET_PED_KEEP_TASK(sRCLauncherData.pedID[0], TRUE)
SET_PED_AS_NO_LONGER_NEEDED(sRCLauncherData.pedID[0])
Script_Cleanup(sRCLauncherData)
ENDIF
ENDIF
ELIF sRCLauncherData.eMissionID = RC_EPSILON_6
DO_EPS6_TOM(sRCLauncherData)
ELIF sRCLauncherData.eMissionID = RC_EPSILON_7
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
PRINT_LAUNCHER_DEBUG("Can request assets for cutscene entity in Eps 7")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
ENDIF
ELIF sRCLauncherData.eMissionID = RC_EPSILON_8
DO_EPS8_KIFFLOM()
ENDIF
//Update launcher blip + preload intro
SET_RC_AWAITING_TRIGGER(sRCLauncherData.eMissionID)
MANAGE_PRELOADING_RC_CUTSCENE(iCutsceneLoadRequestID, sRCLauncherData.sIntroCutscene, vInCoords)
// Check whether help text needs to be reset
Monitor_Help_Text(sRCLauncherData, bDisplayHelp)
// Monitor debug functions for Epsilon 2,3&8
#IF IS_DEBUG_BUILD
IF Does_Mission_Require_Cash(sRCLauncherData.eMissionID)
UPDATE_DEBUG_WIDGETS(sRCLauncherData.eMissionID)
ENDIF
#ENDIF
// Is the player close enough to start the mission off
IF ARE_RC_TRIGGER_CONDITIONS_MET(sRCLauncherData)
IF NOT IS_RC_SPECIFIC_RESTRICTION_MET(sRCLauncherData.eMissionID)
Display_Help_Text(sRCLauncherData.eMissionID, bDisplayHelp)
ELSE
// Create mission blip that persists for lead-in scene
// Original will be removed when RC controller shuts down
IF DOES_RC_MISSION_HAVE_LEAD_IN(sRCLauncherData.eMissionID)
CREATE_BLIP_FOR_LEAD_IN(sRCLauncherData.eMissionID, biLeadIn)
ENDIF
// Launch the mission script
IF NOT LAUNCH_RC_MISSION(sRCLauncherData)
Script_Cleanup(sRCLauncherData)
ENDIF
// Waits in a loop until we can terminate the launcher - flagged from mission at the moment
IF IS_RC_LAUNCHER_SAFE_TO_TERMINATE(sRCLauncherData.eMissionID)
// No need to clean up entities as these should be owned by the mission script
Script_Cleanup(sRCLauncherData, FALSE)
ENDIF
ENDIF
ENDIF
ENDWHILE
// Script should never reach here. Always terminate with cleanup function.
ENDSCRIPT