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

423 lines
14 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 "rage_builtins.sch"
USING "globals.sch"
USING "cutscene_public.sch"
USING "commands_cutscene.sch"
USING "commands_entity.sch"
USING "commands_script.sch"
USING "script_player.sch"
USING "email_public.sch"
USING "randomChar_public.sch"
USING "RC_Helper_Functions.sch"
USING "initial_scenes_Epsilon.sch"
USING "commands_recording.sch"
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : Epsilon5.sc
// AUTHOR : David Roberts
// DESCRIPTION : MICHAEL meets MARNIE in a weird part of Vinewood.
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
ENUM eRC_MainState
RC_LEADIN,
RC_INTRO
ENDENUM
ENUM eRC_SubState
SS_ASSET_REQUEST,
SS_SETUP,
SS_UPDATE,
SS_CLEANUP
ENDENUM
CONST_INT MARNIE 0
// Mission state
eRC_MainState m_eState = RC_LEADIN
eRC_SubState m_subState = SS_ASSET_REQUEST
STRING sSceneHandleMarnie = "Marnie"
g_structRCScriptArgs sRCLauncherDataLocal
structPedsForConversation ConvStruct
INT iCutsceneStage = 0
BOOL bDoneLeadinConv = FALSE
BOOL bLeadInCloseStop = FALSE
FLOAT fHintFov = 40.0
FLOAT fHintFollow = 0.35
FLOAT fHintPitchOrbit = 0.000
FLOAT fHintSide = 0.0
FLOAT fHintVert = 0.050
// ===========================================================================================================
// Termination
// ===========================================================================================================
// -----------------------------------------------------------------------------------------------------------
// Script Cleanup
// -----------------------------------------------------------------------------------------------------------
PROC Script_TextCleanup()
// Could this be included in normal clean up?
STOP_SCRIPTED_CONVERSATION(FALSE)
CLEAR_PRINTS()
ENDPROC
/// PURPOSE:
/// Safely cleans up the script
PROC Script_Cleanup()
// Ensure launcher is cleaned up
RC_CLEANUP_LAUNCHER()
// If the mission was triggered then additional mission cleanup will be required.
IF (Random_Character_Cleanup_If_Triggered())
CPRINTLN(DEBUG_MISSION, "...Random Character Script was triggered so additional cleanup required")
ENDIF
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARNIE])
SET_PED_CAN_BE_TARGETTED(sRCLauncherDataLocal.pedID[MARNIE], FALSE)
SET_PED_RELATIONSHIP_GROUP_HASH(sRCLauncherDataLocal.pedID[MARNIE], RELGROUPHASH_PLAYER)
ENDIF
//Cleanup the scene created by the launcher
RC_CleanupSceneEntities(sRCLauncherDataLocal, FALSE)
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------------------------
// Script Pass
// -----------------------------------------------------------------------------------------------------------
/// PURPOSE:
/// Adds needed contacts, completion %, cleans up and passes script.
PROC Script_Passed()
Script_TextCleanup()
ADD_HELP_TO_FLOW_QUEUE("EPSROBE_HE", FHP_MEDIUM, 0, FLOW_HELP_NEVER_EXPIRES, DEFAULT_HELP_TEXT_TIME, BIT_MICHAEL)
FIRE_EMAIL_INTO_DYNAMIC_THREAD(DYNAMIC_THREAD_EPSILON_ROBES, EMAIL_ORDER_REMINDER, FALSE)
//Set epsilon step stat
INT iCurrent
STAT_GET_INT(NUM_EPSILON_STEP,iCurrent)
IF iCurrent < 14
STAT_SET_INT(NUM_EPSILON_STEP,14)
SET_ACHIEVEMENT_PROGRESS_SAFE(ENUM_TO_INT(ACH20),14)
CPRINTLN(debug_dan,"Epsilon progress:",14)
ENDIF
Random_Character_Passed()
Script_Cleanup()
ENDPROC
// ===========================================================================================================
// DEBUG FUNCTIONS
// ===========================================================================================================
#IF IS_DEBUG_BUILD
/// PURPOSE:
/// Check for Forced Pass or Fail
PROC DEBUG_Check_Debug_Keys()
// Check for Pass
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S))
WAIT_FOR_CUTSCENE_TO_STOP()
Script_Passed()
ENDIF
// Check for Fail
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F))
WAIT_FOR_CUTSCENE_TO_STOP()
Script_TextCleanup()
Random_Character_Failed()
Script_Cleanup()
ENDIF
ENDPROC
#ENDIF
FUNC BOOL CHECK_TO_BLEND_MICHAEL()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Michael")
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, FALSE, FAUS_CUTSCENE_EXIT)
CPRINTLN(DEBUG_MISSION, "Force Michael motion state")
RETURN TRUE
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Keep checking to see if we can blend Marnie
PROC CHECK_TO_BLEND_MARNIE()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARNIE])
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Marnie")
CPRINTLN(DEBUG_MISSION, "Marnie exit state")
SAFE_DELETE_PED(sRCLauncherDataLocal.pedID[MARNIE])
ENDIF
ENDIF
ENDPROC
// ===========================================================================================================
// MISSION FUNCTIONS & PROCEDURES
// ===========================================================================================================
PROC STATE_Leadin()
RC_PLAYER_TRIGGER_SCENE_LOCK_IN()
SWITCH m_subState
CASE SS_ASSET_REQUEST
REQUEST_ANIM_DICT("rcmepsilonism5")
m_subState = SS_Setup
BREAK
CASE SS_SETUP
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARNIE]) >= 4.5
IF NOT IS_GAMEPLAY_HINT_ACTIVE()
IF IS_PLAYER_IN_FIRST_PERSON_CAMERA()
SET_GAMEPLAY_ENTITY_HINT(sRCLauncherDataLocal.pedID[MARNIE], <<0,0,0.5>>, TRUE, 30000)
ELSE
SET_GAMEPLAY_ENTITY_HINT(sRCLauncherDataLocal.pedID[MARNIE], <<-1.0,0,0>>, FALSE, 30000)
ENDIF
SET_GAMEPLAY_HINT_FOV(fHintFov)
SET_GAMEPLAY_HINT_FOLLOW_DISTANCE_SCALAR(fHintFollow)
SET_GAMEPLAY_HINT_BASE_ORBIT_PITCH_OFFSET(fHintPitchOrbit)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_SIDE_OFFSET(fHintSide)
SET_GAMEPLAY_HINT_CAMERA_RELATIVE_VERTICAL_OFFSET(fHintVert)
SET_GAMEPLAY_HINT_CAMERA_BLEND_TO_FOLLOW_PED_MEDIUM_VIEW_MODE(TRUE)
ELSE
STOP_GAMEPLAY_HINT_BEING_CANCELLED_THIS_UPDATE(TRUE)
ENDIF
ENDIF
IF bLeadInCloseStop = FALSE
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARNIE]) <= 2.5
// Turn player control off
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_LEAVE_CAMERA_CONTROL_ON)
TASK_TURN_PED_TO_FACE_ENTITY(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARNIE])
bLeadInCloseStop = TRUE
CPRINTLN(DEBUG_MISSION, "Player too close to Mary Ann, making him stop")
ENDIF
ENDIF
IF HAS_ANIM_DICT_LOADED("rcmepsilonism5")
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARNIE])
IF IS_ENTITY_PLAYING_ANIM(sRCLauncherDataLocal.pedID[MARNIE], "rcm_epsilonism5", "ep_5_rcm_marnie_strokes_wall")
IF GET_ENTITY_ANIM_CURRENT_TIME(sRCLauncherDataLocal.pedID[MARNIE], "rcm_epsilonism5", "ep_5_rcm_marnie_strokes_wall") <0.1
ADD_PED_FOR_DIALOGUE(ConvStruct, 4, sRCLauncherDataLocal.pedID[MARNIE], "MARNIE")
ADD_PED_FOR_DIALOGUE(ConvStruct, 0, PLAYER_PED_ID(), "MICHAEL")
TASK_LOOK_AT_ENTITY(sRCLauncherDataLocal.pedID[MARNIE], PLAYER_PED_ID(), -1, SLF_EXTEND_PITCH_LIMIT|SLF_EXTEND_YAW_LIMIT)
TASK_PLAY_ANIM(sRCLauncherDataLocal.pedID[MARNIE], "rcmepsilonism5", "leadin_action", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_HOLD_LAST_FRAME)
CPRINTLN(DEBUG_MISSION, "Do Marnie leadin")
m_subState = SS_UPDATE
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
CASE SS_UPDATE
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARNIE])
IF IS_ENTITY_PLAYING_ANIM(sRCLauncherDataLocal.pedID[MARNIE], "rcmepsilonism5", "leadin_action")
IF bDoneLeadinConv = FALSE
IF GET_ENTITY_ANIM_CURRENT_TIME(sRCLauncherDataLocal.pedID[MARNIE], "rcmepsilonism5", "leadin_action") >= 0.38
IF CREATE_CONVERSATION(ConvStruct, "EPS5AUD", "EP5_RCM_LI", CONV_PRIORITY_HIGH)
bDoneLeadinConv = TRUE
CPRINTLN(DEBUG_MISSION, "Leadin conv launched")
ENDIF
ENDIF
ENDIF
IF GET_ENTITY_ANIM_CURRENT_TIME(sRCLauncherDataLocal.pedID[MARNIE], "rcmepsilonism5", "leadin_action") >= 0.95
CPRINTLN(DEBUG_MISSION, "Completed Marnie leadin")
m_subState = SS_CLEANUP
ENDIF
IF bLeadInCloseStop = FALSE
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARNIE]) <= 2.5
// Turn player control off
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_LEAVE_CAMERA_CONTROL_ON)
TASK_TURN_PED_TO_FACE_ENTITY(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[MARNIE])
bLeadInCloseStop = TRUE
CPRINTLN(DEBUG_MISSION, "Player too close to Mary Ann, making him stop")
ENDIF
ENDIF
ELSE
CPRINTLN(DEBUG_MISSION, "Completed Marnie leadin")
m_subState = SS_CLEANUP
ENDIF
ENDIF
BREAK
CASE SS_CLEANUP
m_eState = RC_INTRO
m_subState = SS_ASSET_REQUEST
BREAK
ENDSWITCH
ENDPROC
/// PURPOSE:
/// Runs the intro cutscene state
PROC STATE_Intro()
SWITCH m_subState
CASE SS_ASSET_REQUEST
RC_REQUEST_CUTSCENE("ep_5_rcm")
m_subState = SS_Setup
BREAK
CASE SS_Setup
CPRINTLN(DEBUG_MISSION, "Init RC_INTRO")
IF RC_IS_CUTSCENE_OK_TO_START()
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[MARNIE])
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[MARNIE], sSceneHandleMarnie, CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
REGISTER_ENTITY_FOR_CUTSCENE(PLAYER_PED_ID(), "Michael", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
// Ensure lead-in blip is cleaned up...
RC_CLEANUP_LAUNCHER()
iCutsceneStage = 0
TRIGGER_MUSIC_EVENT("EPS5_START")
START_CUTSCENE()
REPLAY_START_EVENT(REPLAY_IMPORTANCE_LOW)
WAIT(0)
STOP_GAMEPLAY_HINT()
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT(<<638.724792,108.215866,87.003014>>, <<644.466736,124.222160,94.640419>>, 12.5,
<< 638.9150, 101.5370, 88.1472 >>, 331.3091, GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR())
//RC_CleanupSceneEntities(sRCLauncherDataLocal)
RC_START_CUTSCENE_MODE(<< 637.02, 119.7093, 89.50 >>, TRUE, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
m_subState = SS_Update
ENDIF
BREAK
CASE SS_Update
IF iCutsceneStage = 0
// Keep spamming this until Michael's exit state to get the camera to blend behind Michael
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
IF WAS_CUTSCENE_SKIPPED()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
iCutsceneStage = 1
ENDIF
IF CHECK_TO_BLEND_MICHAEL()
iCutsceneStage = 1
ENDIF
CHECK_TO_BLEND_MARNIE()
ELIF iCutsceneStage = 1
// Keep checking Marnie in case she hasn't blended yet
CHECK_TO_BLEND_MARNIE()
// Also check Michael in case the cutscene was skipped and the blend in stage 0 didn't fire
CHECK_TO_BLEND_MICHAEL()
IF WAS_CUTSCENE_SKIPPED()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
IF NOT IS_CUTSCENE_ACTIVE()
RC_END_CUTSCENE_MODE()
m_subState = SS_Cleanup
ENDIF
ENDIF
BREAK
CASE SS_Cleanup
REPLAY_STOP_EVENT()
CPRINTLN(DEBUG_MISSION, "Cleaning up RC_INTRO")
TRIGGER_MUSIC_EVENT("EPS5_STOP")
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, FALSE)
Script_Passed()
BREAK
ENDSWITCH
ENDPROC
// ===========================================================================================================
// Script Loop
// ===========================================================================================================
SCRIPT(g_structRCScriptArgs sRCLauncherDataIn)
sRCLauncherDataLocal = sRCLauncherDataIn
RC_TakeEntityOwnership(sRCLauncherDataLocal)
SET_MISSION_FLAG(TRUE)
// 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))
PRINT_LAUNCHER_DEBUG("Force cleanup [TERMINATING]")
Random_Character_Failed()
Script_Cleanup()
TRIGGER_MUSIC_EVENT("EPS_FAIL")
ENDIF
IF Is_Replay_In_Progress() // Set up the initial scene for replays
g_bSceneAutoTrigger = TRUE
eInitialSceneStage = IS_REQUEST_SCENE
WHILE NOT SetupScene_EPSILON_5(sRCLauncherDataLocal)
WAIT(0)
ENDWHILE
g_bSceneAutoTrigger = FALSE
ENDIF
ADD_CONTACT_TO_PHONEBOOK(CHAR_MARNIE, MICHAEL_BOOK, FALSE)
ADD_CONTACT_TO_PHONEBOOK(CHAR_JIMMY_BOSTON, MICHAEL_BOOK, FALSE)
// Loop within here until the mission passes or fails
WHILE(TRUE)
REPLAY_CHECK_FOR_EVENT_THIS_FRAME("SF_BTT")
WAIT(0)
UPDATE_MISSION_NAME_DISPLAYING(sRCLauncherDataLocal.sIntroCutscene)
SWITCH(m_eState)
CASE RC_LEADIN
STATE_Leadin()
BREAK
CASE RC_INTRO
STATE_Intro()
BREAK
ENDSWITCH
// Check debug completion/failure
#IF IS_DEBUG_BUILD
DEBUG_Check_Debug_Keys()
#ENDIF
ENDWHILE
SCRIPT_ASSERT("Script should never reach here. Always terminate with cleanup function.")
ENDSCRIPT