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

4258 lines
143 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 "randomChar_public.sch"
USING "dialogue_public.sch"
USING "script_player.sch"
USING "shared_hud_displays.sch"
USING "CompletionPercentage_public.sch"
USING "randomChar_public.sch"
USING "RC_Helper_Functions.sch"
USING "RC_Threat_public.sch"
USING "RC_Area_public.sch"
USING "initial_scenes_epsilon.sch"
USING "commands_recording.sch"
#IF IS_DEBUG_BUILD
USING "select_mission_stage.sch"
#ENDIF
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//
// MISSION NAME : Epsilon4.sc
// AUTHOR : Sam Hackett (originally)/Ian Gander (July '12 onwards)
// DESCRIPTION : Track down a "space" rock using a detector
//
// *****************************************************************************************
// *****************************************************************************************
// *****************************************************************************************
//*******************************************************************************************************************
//******************************************************************************************************************* RC VARIABLES
// Scene entities from mission launcher
g_structRCScriptArgs sRCLauncherDataLocal
CONST_INT ID_MARNIE 0
CONST_INT ID_JIMMY 1
//*******************************************************************************************************************
//******************************************************************************************************************* POSITIONS
VECTOR vPos_WoodsCentre = << 1813.2936, 4698.7852, 38.9553 >>//<< 1812.0585, 4697.6284, 39.0981 >>
VECTOR vPos_PlayerReset = << 1827.1781, 4698.1138, 38.1653 >>
FLOAT fRot_PlayerReset = 187.4554
VECTOR vPos_Epsilonian1 = << 1811.9602, 4697.0708, 39.1076 >>
FLOAT fRot_Epsilonian1 = 330.5137
VECTOR vPos_Epsilonian2 = << 1814.0197, 4697.0508, 38.9678 >>
FLOAT fRot_Epsilonian2 = 24.0044
//VECTOR vPos_PlayerFinalScene = << 1860.4711, 4657.4482, 36.3283 >>
//FLOAT fRot_PlayerFinalScene = 177.3919
CONST_FLOAT fFindRange 6.2 //4.0//2.5
CONST_FLOAT fNearRange 9.0 //6.0//5.0//30.0//5.0//11.0//10.0//5.5
CONST_FLOAT fCloseDialogRange 20.0
CONST_FLOAT CAPSULE_SIZE 0.965
CONST_INT MAX_JGOOD_LINES 8
CONST_INT MAX_JBAD_LINES 8
CONST_INT MAX_MGOOD_LINES 8
CONST_INT MAX_MBAD_LINES 8
CONST_INT MAX_PGOOD_LINES 11
CONST_INT MAX_PBAD_LINES 12
WEAPON_TYPE weapon_Detector = WEAPONTYPE_DIGISCANNER
MODEL_NAMES model_Detector = GET_WEAPONTYPE_MODEL(weapon_Detector)
//STRING NO_RECENT_ANIM = "noAnim"
STRING EMPTY_STRING = "empty"
//1812.13, 4636.73, 37.78
//*******************************************************************************************************************
//******************************************************************************************************************* DATATYPES
//-- Rock
STRUCT ROCK_DATA
MODEL_NAMES model
OBJECT_INDEX hObject
VECTOR vPos
VECTOR vRot
VECTOR vCamPos
VECTOR vCamRot
FLOAT fCamFov
VECTOR vEpsPos
// FLOAT fEpsRot
FLOAT fMeanderFactor0
FLOAT fMeanderFactor1
FLOAT fMeanderAmplitude
FLOAT fStraightZone
FLOAT fHotAngle
FLOAT fMeterRange
FLOAT fPostSceneRot
VECTOR vAngledArea1
VECTOR vAngledArea2
FLOAT fAngledAreaWidth
VECTOR vWarpCarPos
FLOAT fWarpCarRot
STRING sChat1Dialogue
STRING sChat2Dialogue
STRING sReturn1Dialogue
STRING sReturn2Dialogue
STRING sHintGoodDialogue
STRING sHintBadDialogue
STRING SHintCloseDialogue
ENDSTRUCT
STRUCT DETECTOR
ENTITY_INDEX hObj
BOOL bIsOnTarget
INT hSndHum
INT hSndBeep
INT hSndFound
INT hSndScan
BOOL bIsFoundSoundOn
BOOL bIsScanSoundOn
FLOAT fMeanderFactor0
FLOAT fMeanderFactor1
FLOAT fMeanderAmplitude
FLOAT fStraightZone
FLOAT fHotAngle
BOOL bLockSettings
STRING sRecentAnim
ENDSTRUCT
//-- Anim markers
ENUM ANIM_MARKER_TYPE
ANIM_MARKER_FORAGE,
ANIM_MARKER_DUMMY_JIMMY,
ANIM_MARKER_DUMMY_PISS,
ANIM_MARKER_DUMMY_DANCE
ENDENUM
STRUCT ANIM_MARKER
VECTOR vPos
FLOAT fRot
ANIM_MARKER_TYPE type
BOOL bIsInUse
ENDSTRUCT
//-- Eps characters
ENUM EPS_STATE
EPS_ST_NULL = 0,
EPS_ST_MOVE,
EPS_ST_MARKER,
EPS_ST_IDLE,
EPS_ST_FOLLOW,
EPS_ST_CATCHUP
ENDENUM
ENUM STATE_MODE
SETUP_STATE,
UPDATE_STATE
ENDENUM
STRUCT EPS_DATA
PED_INDEX hPed
EPS_STATE state
STATE_MODE mode
INT iAnimMarker
VECTOR vPlayerStartPos
BOOL bNotUsingNavmeshMove = FALSE
ENDSTRUCT
//*******************************************************************************************************************
//******************************************************************************************************************* VARIABLES
SCENARIO_BLOCKING_INDEX mScenarioBlocker
SCENARIO_BLOCKING_INDEX mScenarioBlockerPicnic
BLIP_INDEX g_hBlip
SCALEFORM_INDEX si_DetectorScaleform
INT rt_ID
SEQUENCE_INDEX seq
structPedsForConversation pedsForConversation
BOOL bDonePushIn = FALSE
BOOL bLeadInPlayed = FALSE
BOOL bLeadInConvo = FALSE
BOOL bIsPlayerOnTarget = FALSE
BOOL bIsPlayerAtRock = FALSE
BOOL bHasPlayerFoundRock = FALSE
BOOL bIsPlayerInWoods = TRUE
BOOL bAudDoneChat1 = FALSE
BOOL bAudDoneChat2 = FALSE
BOOL bAudDoneChatAll = FALSE
BOOL bAudDoneClose = FALSE
BOOL bAudDoneReturn1 = FALSE
BOOL bAudDoneReturn2 = FALSE
BOOL bObjDoneHunt = FALSE
BOOL bObjDoneExamine = FALSE
BOOL bObjDoneReturnWoods = FALSE
//BOOL bPlayerSkippedScene = FALSE
//BOOL bCapsuleResized = FALSE
BOOL bPlayerUsedAim = FALSE
BOOL bFollowerDoingIdle = FALSE
BOOL bLockAimPitch = FALSE
BOOL bStillOnTarget = FALSE
INT iCurrentRock = 0
INT iPhaseTimer = 0
INT iBeepOffTimer = 0
INT iSupressHintAudioTimer = 0
INT iSupressPickupAudioTimer = 0
INT iHintTimer
INT iFoundWaitTimer
GRASS_CULL_SPHERE_HANDLE grassCull
CONST_FLOAT DIALOGUE_DIST 30.0
PED_INDEX hPrimaryBuddy
VEHICLE_INDEX Eps_Vehicle
CONST_INT ROCK_MAX 4
ROCK_DATA rockArray[ROCK_MAX]
INT iRockCount = 0
INT iMidtroDelay
CONST_INT ANIM_MARKER_MAX 11
ANIM_MARKER animMarkerArray[ANIM_MARKER_MAX]
INT iAnimMarkerCount = 0
CONST_INT EPSILONIAN_MAX 2
EPS_DATA epsilonianArray[EPSILONIAN_MAX]
BOOL epsKnockedOver = FALSE
PED_INDEX epsPedKnockedOver
DETECTOR gDetector
FLOAT fReading
CONST_INT LVL3_DISTANCE 80
CONST_INT LVL2_DISTANCE 50
OBJECT_INDEX DetectorCopy
TEST_POLY g_polyPlayArea
TEST_POLY g_polyFailArea
INT iTutorialLine = 0
INT iTutorialTimer = 0
INT iCurrentMaxGoodLines = 0
INT iCurrentMaxBadLines = 0
INT iSaidGoodLines = 0
INT iSaidBadLines = 0
INT iSaidOnTargetLines = 0
INT iNonFollowerCloseLines = 0
INT iNonFollowerCloseLines1 = 0 // Used when both characters are wandering around during the third object and I need to keep track of two sets of lines...
INT iNonFollowerCloseLinesTimer = 0
//INT g_hMarker_MarnieInitial
//INT g_hMarker_JimmyInitial
//INT g_hDummyMarker_Jimmy
INT iFollowIdleTimer
INT iFollowMessingAroundTimer
INT iAimPromptLines = 0
INT iAimPromptTimer
INT g_hDummyMarker_Piss
INT g_hDummyMarker_Dance
INT g_hDummyMarker_MarnieIntroForage
INT g_hMarker_MarnieAngry
INT iNavBlockerBush1 = -1
INT iNavBlockerBush2 = -1
INT iNavBlockerBush3 = -1
FLOAT fHintFov = 30.0
FLOAT fHintFollow = 0.35
FLOAT fHintPitchOrbit = 0.000
FLOAT fHintSide = 0.02
FLOAT fHintVert = -0.050
//*******************************************************************************************************************
//******************************************************************************************************************* WIDGETS
#IF IS_DEBUG_BUILD
USING "shared_debug.sch"
WIDGET_GROUP_ID widgetGroup
BOOL g_DEBUG_DisplayInfo = FALSE
BOOL bDebug_PrintToTTY = TRUE
BOOL bDebug_VerboseDetector = FALSE
PROC SETUP_EPS4_WIDGETS()
widgetGroup = START_WIDGET_GROUP("Epsilon 4 widgets")
ADD_WIDGET_FLOAT_SLIDER("Meander factor", gDetector.fMeanderFactor0, 0.0, 500.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Meander factor", gDetector.fMeanderFactor1, 0.0, 500.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Meander amplitude", gDetector.fMeanderAmplitude, -100.0, 100.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Striaght zone", gDetector.fStraightZone, 0.0, 100.0, 1.0)
ADD_WIDGET_FLOAT_SLIDER("Hot angle", gDetector.fHotAngle, 0.0, 1.0, 1.0)
ADD_WIDGET_BOOL("Show info", g_DEBUG_DisplayInfo)
ADD_WIDGET_BOOL("Lock detector meander settings", gDetector.bLockSettings)
ADD_WIDGET_BOOL("TTY Toggle - Print Mission Debug Info", bDebug_PrintToTTY)
ADD_WIDGET_BOOL("Verbose detector debug output (requires TTY Toggle to be on)", bDebug_VerboseDetector)
STOP_WIDGET_GROUP()
ENDPROC
PROC CLEANUP_EPS4_WIDGETS()
IF DOES_WIDGET_GROUP_EXIST(widgetGroup)
DELETE_WIDGET_GROUP(widgetGroup)
ENDIF
ENDPROC
#ENDIF
// ===========================================================================================================
// Debug prints
// ===========================================================================================================
/// PURPOSE: Print a string to the console
PROC DEBUG_PRINTSTRING(STRING s)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s)
ENDIF
#ENDIF
// Stop release compile error
s = s
ENDPROC
/// PURPOSE: Print a string with a float to the console
PROC DEBUG_PRINTSF(STRING s, FLOAT f)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, f)
ENDIF
#ENDIF
// Stop release compile error
s = s
f = f
ENDPROC
/// PURPOSE: Print a string with an int to the console
PROC DEBUG_PRINTSI(STRING s, INT i)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, i)
ENDIF
#ENDIF
// Stop release compile error
s = s
i = i
ENDPROC
/// PURPOSE: Print a string with an int to the console
PROC DEBUG_PRINTBOOL(BOOL b)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, b)
ENDIF
#ENDIF
// Stop release compile error
b = b
ENDPROC
/// PURPOSE: Print a string with an int to the console
PROC DEBUG_PRINTVECTOR(STRING s, VECTOR v)
#IF IS_DEBUG_BUILD
IF bDebug_PrintToTTY
CPRINTLN(DEBUG_MISSION, s, v)
ENDIF
#ENDIF
// Stop release compile error
s = S
v = v
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* ASSET FUNCTIONS
/// PURPOSE:
/// Request and check whether all text we want are loaded
/// RETURNS:
/// True when all the text has loaded, False otherwise
FUNC BOOL LOAD_TEXT()
// Request
REQUEST_ADDITIONAL_TEXT("EPS4", MISSION_TEXT_SLOT)
// Check
IF HAS_ADDITIONAL_TEXT_LOADED(MISSION_TEXT_SLOT)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Request and check whether all models we want are loaded
/// RETURNS:
/// True when all models are loaded, False otherwise
FUNC BOOL LOAD_MODELS()
// Request
INT i
REPEAT iRockCount i
REQUEST_MODEL(rockArray[i].model)
ENDREPEAT
REQUEST_MODEL(model_Detector)
REQUEST_MODEL(Bison)
// Check
REPEAT iRockCount i
IF NOT HAS_MODEL_LOADED(rockArray[i].model)
RETURN FALSE
ENDIF
ENDREPEAT
IF NOT HAS_MODEL_LOADED(model_Detector)
OR NOT HAS_MODEL_LOADED(Bison)
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNC
/// PURPOSE:
/// Request and check for the animations being loaded
/// RETURNS:
/// True when all anims are loaded, False otherwise
FUNC BOOL LOAD_ANIMS()
// Request
REQUEST_ANIM_DICT("rcm_epsilonism4")
REQUEST_ANIM_DICT("rcm_epsilonism4leadinout")
// Check
IF HAS_ANIM_DICT_LOADED("rcm_epsilonism4")
AND HAS_ANIM_DICT_LOADED("rcm_epsilonism4leadinout")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Request and check for all assets we wish to use for this mission
/// RETURNS:
/// True when all assets are loaded in, False otherwise
FUNC BOOL LOAD_ASSETS()
IF LOAD_TEXT()
AND LOAD_MODELS()
AND LOAD_ANIMS()
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Release all requested anims
PROC RELEASE_ANIMS()
REMOVE_ANIM_DICT("rcm_epsilonism4")
REMOVE_ANIM_DICT("rcm_epsilonism4leadinout")
ENDPROC
/// PURPOSE:
/// Set up basic fields for the rock data
/// PARAMS:
/// sSceneDialogue - The dialogue string for the scripted scene
/// model - The model to be used for the 'rock'
/// vPos - The coords of the rock
/// vRot - The rotation of the rock
PROC ADD_ROCK(MODEL_NAMES model, VECTOR vPos, VECTOR vRot)
IF iRockCount >= ROCK_MAX
SCRIPT_ASSERT("ADD_ROCK: Rock array full\n")
ENDIF
INT idx = iRockCount
iRockCount++
rockArray[idx].model = model
rockArray[idx].vPos = vPos
rockArray[idx].vRot = vRot
rockArray[idx].fMeterRange = 150.0
rockArray[idx].fPostSceneRot = -1.0
rockArray[idx].sChat1Dialogue = EMPTY_STRING
rockArray[idx].sChat2Dialogue = EMPTY_STRING
rockArray[idx].sReturn1Dialogue = EMPTY_STRING
rockArray[idx].sReturn2Dialogue = EMPTY_STRING
rockArray[idx].sHintGoodDialogue = EMPTY_STRING
rockArray[idx].sHintBadDialogue = EMPTY_STRING
ENDPROC
/// PURPOSE:
/// Set up camera values for the scripted cutscene for the current rock
/// PARAMS:
/// vCamPos - The camera position
/// vCamRot - The camera rotation
/// fCamFov - The camera FOV
PROC SETUP_ROCK_CAM(VECTOR vCamPos, VECTOR vCamRot, FLOAT fCamFov = 50.0)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_CAM: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].vCamPos = vCamPos
rockArray[idx].vCamRot = vCamRot
rockArray[idx].fCamFov = fCamFov
ENDPROC
/// PURPOSE:
/// Set up the position the Epsilonists will walk to during the scripted cutscene
/// PARAMS:
/// vEpsPos - The coords the Epsilonist will walk to
PROC SETUP_ROCK_EPS(VECTOR vEpsPos)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_EPS: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].vEpsPos = vEpsPos
ENDPROC
/// PURPOSE:
/// Set up the meander values for the detector
/// PARAMS:
/// fMeanderFactor0 - Meander factor value 1
/// fMeanderFactor1 - Meander factor value 2
/// fMeanderAmplitude - Meander factor amplitude
PROC SETUP_ROCK_MEANDER_PATH(FLOAT fMeanderFactor0, FLOAT fMeanderFactor1, FLOAT fMeanderAmplitude)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_MEANDER_PATH: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].fMeanderFactor0 = fMeanderFactor0
rockArray[idx].fMeanderFactor1 = fMeanderFactor1
rockArray[idx].fMeanderAmplitude = fMeanderAmplitude
ENDPROC
/// PURPOSE:
/// Set up various detector params for the given rock
/// PARAMS:
/// fStraightZone - The straight zone value
/// fMeterRange - The meter range value
/// fHotAngle - The hot angle for the detector
PROC SETUP_ROCK_DETECTION_PARAMS(FLOAT fStraightZone, FLOAT fMeterRange, FLOAT fHotAngle)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_DETECTION_PARAMS: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].fStraightZone = fStraightZone
rockArray[idx].fMeterRange = fMeterRange
rockArray[idx].fHotAngle = fHotAngle
ENDPROC
/// PURPOSE:
/// Sets the range for the meter
/// PARAMS:
/// fMeterRange - The range we wish to set
PROC SETUP_ROCK_METER_RANGE(FLOAT fMeterRange)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_METER_RANGE: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].fMeterRange = fMeterRange
ENDPROC
/// PURPOSE:
/// Set up the rotation to be used after the scripted rock cutscene
/// PARAMS:
/// fRot - The rotation we wish to set
PROC SETUP_ROCK_POST_SCENE_ROT(FLOAT fRot)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_POST_SCENE_ROT: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].fPostSceneRot = fRot
ENDPROC
PROC SETUP_ROCK_AREA(VECTOR vAngledArea1, VECTOR vAngledArea2, FLOAT fAreaWidth)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_AREA: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].vAngledArea1 = vAngledArea1
rockArray[idx].vAngledArea1 = vAngledArea2
rockArray[idx].fAngledAreaWidth = fAreaWidth
ENDPROC
/// PURPOSE:
/// Sets up the location for a car in case needed for the cutscene mode switch
/// PARAMS:
/// vPos - The pos of the theoretical car
/// fRot - The heading of the theoretical car
PROC SETUP_ROCK_WARP_CAR(VECTOR vPos, FLOAT fRot)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_WARP_CAR: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].vWarpCarPos = vPos
rockArray[idx].fWarpCarRot = fRot
ENDPROC
/// PURPOSE:
/// Adds dialogue for misc chat while trying to find a certain rock
/// PARAMS:
/// sChat1 - First dialogue branch
/// sChat2 - Second dialogue branch
PROC SETUP_ROCK_CHAT_DIALOGUE(STRING sChat1, STRING sChat2)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_CHAT_DIALOGUE: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].sChat1Dialogue = sChat1
rockArray[idx].sChat2Dialogue = sChat2
ENDPROC
/// PURPOSE:
/// Adds dialogue for coming back to the rock path
/// PARAMS:
/// sReturn1 - First dialogue branch
/// sReturn2 - Second dialogue branch
PROC SETUP_ROCK_RETURN_DIALOGUE(STRING sReturn1, STRING sReturn2)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_RETURN_DIALOGUE: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].sReturn1Dialogue = sReturn1
rockArray[idx].sReturn2Dialogue = sReturn2
ENDPROC
/// PURPOSE:
/// Adds hint dialogue for current rock being set up
/// PARAMS:
/// sGood - The dialogue string for being on track
/// sBad - The dialogue string for being off the track
PROC SETUP_ROCK_HINT_DIALOGUE(STRING sGood, STRING sBad)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_HINT_DIALOGUE: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].sHintGoodDialogue = sGood
rockArray[idx].sHintBadDialogue = sBad
ENDPROC
/// PURPOSE:
/// Adds 'player is close' dialogue for current rock being set up
/// PARAMS:
/// sClose - The dialogue string for being close
PROC SETUP_ROCK_CLOSE_DIALOGUE(STRING sClose)
INT idx = iRockCount - 1
IF idx < 0
SCRIPT_ASSERT("SETUP_ROCK_CLOSE_DIALOGUE: Can't setup rock before adding one\n")
ENDIF
rockArray[idx].SHintCloseDialogue = sClose
ENDPROC
/// PURPOSE:
/// Add an animation marker for the Epsilonists to use
/// PARAMS:
/// vPos - The coords of the marker
/// fRot - The heading for the marker (for alignment)
/// type - What type of marker it is, to set the correct anims
/// RETURNS:
/// The int index number of the new marker
FUNC INT ADD_ANIM_MARKER(VECTOR vPos, FLOAT fRot, ANIM_MARKER_TYPE type)
IF iAnimMarkerCount >= ANIM_MARKER_MAX
SCRIPT_ASSERT("ADD_ANIM_MARKER: Marker array full\n")
ENDIF
INT idx = iAnimMarkerCount
iAnimMarkerCount++
animMarkerArray[idx].vPos = vPos
animMarkerArray[idx].fRot = fRot
animMarkerArray[idx].type = type
animMarkerArray[idx].bIsInUse = FALSE
RETURN idx
ENDFUNC
/// PURPOSE:
/// Initialise the data for the rocks and cameras the mission will use
PROC INIT_DATA()
// TV set
ADD_ROCK(PROP_TV_TEST, << 1751.65, 4676.77, 43.03 >>, <<-2.33, 0.99, 91.36>>)//<< 1834.2987, 4760.5972, 37.9177 >>, 344.5698)
SETUP_ROCK_CAM(<< 1755.4631, 4678.6196, 44.1477 >>, << -9.5251, -0.0000, 122.2955 >>, 50.8320)
SETUP_ROCK_EPS(<<3,-4.5,0>>)
SETUP_ROCK_WARP_CAR(<< 1689.9510, 4762.6133, 40.9216 >>, 272.5499)
SETUP_ROCK_AREA(<<1779.514038,4691.447266,39.345768>>, <<1744.224976,4674.646484,46.848289>>, 16.5)
SETUP_ROCK_CHAT_DIALOGUE("EPS4_JCHAT1", EMPTY_STRING)//"EPS4_JCHAT2")
SETUP_ROCK_HINT_DIALOGUE("EPS4_JGOOD", "EPS4_JBAD")
SETUP_ROCK_RETURN_DIALOGUE("EPS4_JRET1", "EPS4_JRET2")
SETUP_ROCK_CLOSE_DIALOGUE("EPS4_JCLOSE")
//SETUP_ROCK_MEANDER_PATH(113.0, 0.0, 47.0) // Meander settings
SETUP_ROCK_MEANDER_PATH(0, 0, 0)
SETUP_ROCK_DETECTION_PARAMS(30.0, 115.0, 0.9)
// Old car battery
ADD_ROCK(PROP_BATTERY_01, << 1756.68, 4832.28, 39.43 >>, <<90.00, 13.21, 78.57>>)//<< 1773.8232, 4792.0288, 38.8912 >>, 127.1792)//178.0357)
SETUP_ROCK_CAM(<< 1758.0319, 4826.5605, 41.4590 >>, << -11.6785, -0.0000, 6.5381 >>, 34.3083)//<< 1773.5450, 4796.3384, 40.3945 >>, << -5.3621, -0.0000, -174.0904 >>, 34.3083)//<< 1773.4720, 4796.6479, 40.0057 >>, << -6.5347, 0.0000, -173.2800 >>, 45.0000)//<< 1770.4829, 4792.7202, 40.0238 >>, << -5.4930, 0.0000, -103.2162 >>, 50.8700)//<< 1755.5587, 4787.6787, 41.4211 >>, << -6.6573, 0.0000, -103.4049 >>, 30.2965)
SETUP_ROCK_EPS(<<2,4,0>>)
SETUP_ROCK_WARP_CAR(<< 1690.2666, 4769.9937, 40.9216 >>, 269.3043)
SETUP_ROCK_AREA(<<1750.065308,4833.117188,36.870258>>, <<1763.223755,4831.822266,43.542503>>, 13.75)
SETUP_ROCK_CHAT_DIALOGUE("EPS4_MCHAT1", "EPS4_MCHAT2")
SETUP_ROCK_HINT_DIALOGUE("EPS4_MGOOD", "EPS4_MBAD")
SETUP_ROCK_RETURN_DIALOGUE("EPS4_MRET1", "EPS4_MRET2")
SETUP_ROCK_CLOSE_DIALOGUE("EPS4_MCLOSE")
//SETUP_ROCK_MEANDER_PATH(307.5, 77.5, 24.0)
SETUP_ROCK_MEANDER_PATH(0, 0, 0)
SETUP_ROCK_DETECTION_PARAMS(30.0, 195.0, 0.9)
// Old boot
ADD_ROCK(PROP_OLD_BOOT, << 1847.8630, 4756.0591, 36.71 >>, <<-70.53, 75.48, 132.44>>)//<< 1874.7458, 4722.8452, 37.3642 >>, 76.8130)//<< 1869.2849, 4654.1274, 36.5388 >>, 304.6996)//<< 1876.32, 4725.66, 37.73 >>, -34.33)
SETUP_ROCK_CAM(<< 1829.3098, 4756.1582, 42.4876 >>, << -23.5614, -0.0000, -92.2873 >>, 50.0000)//<< 1851.8960, 4753.5889, 38.3750 >>, << -11.3477, -0.0000, 47.3156 >>, 59.2875)//<< 1841.6384, 4756.7441, 39.5189 >>, << -18.2638, -0.0000, -95.7327 >>, 59.2875)
SETUP_ROCK_EPS(<<7.5, -7.5, 0>>)//<<6.5, -2.4, 0>>)//(<<5.625, -1.875, 0>>)//(<<4.5, -1.5, 0>>)
SETUP_ROCK_WARP_CAR(<< 1689.7749, 4777.7695, 40.9216 >>, 267.4597)
SETUP_ROCK_AREA(<<1856.217773,4755.223145,34.671692>>, <<1841.114258,4755.488770,41.434017>>, 13.75)
SETUP_ROCK_CHAT_DIALOGUE("EPS4_PCHAT1", "EPS4_PCHAT2")
SETUP_ROCK_HINT_DIALOGUE("EPS4_PGOOD", "EPS4_PBAD")
SETUP_ROCK_RETURN_DIALOGUE(EMPTY_STRING, "EPS4_PRET2")
SETUP_ROCK_CLOSE_DIALOGUE("EPS4_PCLOSE")
//SETUP_ROCK_MEANDER_PATH(206.5, 58.5, 25.0)
SETUP_ROCK_MEANDER_PATH(0, 0, 0)
SETUP_ROCK_DETECTION_PARAMS(20.5, 155.0, 0.9)
// Add Jimmy + Marnie animation markers
ADD_ANIM_MARKER(<< 1820.1013, 4701.0986, 38.5450 >>, 280.7432, ANIM_MARKER_FORAGE)
ADD_ANIM_MARKER(<< 1803.0437, 4700.2441, 39.3123 >>, 72.1396, ANIM_MARKER_FORAGE) // Was originally Marnie initial marker
ADD_ANIM_MARKER(<< 1820.4816, 4672.5347, 35.6368 >>, 253.4126, ANIM_MARKER_FORAGE) // Was originally Jimmy initial marker
ADD_ANIM_MARKER(<< 1819.8701, 4694.0303, 38.4080 >>, 231.2265, ANIM_MARKER_FORAGE)
ADD_ANIM_MARKER(<< 1807.1217, 4684.4185, 38.5566 >>, 150.6129, ANIM_MARKER_FORAGE)
ADD_ANIM_MARKER(<< 1791.0580, 4689.4028, 40.5128 >>, 103.4073, ANIM_MARKER_FORAGE)
ADD_ANIM_MARKER(<< 1872.6261, 4718.8271, 37.2889 >>, 210.8288, ANIM_MARKER_DUMMY_JIMMY)
// g_hDummyMarker_Piss = ADD_ANIM_MARKER(<< 1875.7924, 4718.6582, 37.7000 >>, 179.1472, ANIM_MARKER_DUMMY_PISS)
g_hDummyMarker_Piss = ADD_ANIM_MARKER(<< 1764.0890, 4665.8794, 42.3031 >>, 281.6336, ANIM_MARKER_DUMMY_PISS)
g_hDummyMarker_MarnieIntroForage = ADD_ANIM_MARKER(<< 1814.27, 4651.32, 37.58 >>, 173.1089, ANIM_MARKER_FORAGE)
g_hDummyMarker_Dance = ADD_ANIM_MARKER(<< 1846.5121, 4705.6143, 38.1214 >>, 25.7591, ANIM_MARKER_DUMMY_DANCE)//<< 1877.3870, 4692.0205, 38.8601 >>, 62.9845, ANIM_MARKER_DUMMY_DANCE)
g_hMarker_MarnieAngry = ADD_ANIM_MARKER(<< 1790.4141, 4722.8970, 37.8533 >>, 221.4777, ANIM_MARKER_FORAGE)
OPEN_TEST_POLY(g_polyPlayArea)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1897.42, 4596.51, 36.40 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1912.20, 4676.93, 39.44 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1886.09, 4733.68, 39.48 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1800.24, 4820.64, 40.96 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1796.5560, 4893.5410, 40.4741 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1782.6514, 4916.3325, 41.4418 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1746.5521, 4942.3618, 42.8677 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1702.5366, 4893.8237, 36.7751 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1707.2734, 4814.8096, 40.9407 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1729.46, 4655.21, 42.61 >>)
ADD_TEST_POLY_VERT(g_polyPlayArea, << 1772.0504, 4602.1426, 36.4570 >>)
CLOSE_TEST_POLY(g_polyPlayArea)
COPY_EXPANDED_POLY(g_polyFailArea, g_polyPlayArea, 20)
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* MISSION STAGE DATATYPES
ENUM MISSION_STAGE
MS_NULL = -1,
MS_LEADIN,
MS_INTRO,
MS_FINDROCK,
MS_ROCKSCENE,
MS_WAITTOPASS,
MS_PASSED,
MS_FAILED
ENDENUM
CONST_INT CP_INTRO 0
CONST_INT CP_FINDROCKA 1
CONST_INT CP_ROCKSCENEA 2
CONST_INT CP_FINDROCKB 3
CONST_INT CP_ROCKSCENEB 4
CONST_INT CP_FINDROCKC 5
CONST_INT CP_ROCKSCENEC 6
CONST_INT MAX_CP 7
CONST_INT MAX_SKIP_OPTIONS 8
ENUM STAGE_SECTION
SECTION_SETUP = 0,
SECTION_RUNNING,
SECTION_FADEOUT,
SECTION_CLEANUP,
SECTION_SKIP
ENDENUM
ENUM FAIL_REASON
FAIL_REASON_DEFAULT,
FAIL_REASON_PLAYER_DEAD,
FAIL_REASON_MARNIE_DEAD,
FAIL_REASON_JIMMY_DEAD,
FAIL_REASON_MARNIE_INJURED,
FAIL_REASON_JIMMY_INJURED,
FAIL_REASON_MARNIE_THREATENED,
FAIL_REASON_JIMMY_THREATENED,
FAIL_REASON_LEFT_AREA
ENDENUM
STRUCT MISSION_DATA
MISSION_STAGE stage
STAGE_SECTION section
INT iEvent
// A stage can store what stage should be next, then run through it's exit section. At the end of the exit section it will switch to this stage.
BOOL bSyncForSkip
BOOL bRequestJSkip
BOOL bRequestPSkip
BOOL bRequestCpSkip
INT queueCpSkip
MISSION_STAGE queueNextStage
// When the mission goes to fail-state, it should set this so the right message can be displayed
FAIL_REASON failReason
ENDSTRUCT
MISSION_DATA g_mission
#IF IS_DEBUG_BUILD
MissionStageMenuTextStruct zSkipMenu[MAX_SKIP_OPTIONS]
#ENDIF
//*******************************************************************************************************************
//******************************************************************************************************************* MISSION STAGE FUNCTIONS
/// PURPOSE:
/// Initialise the mission data and bools
PROC INIT_MISSION_DATA()
g_mission.bRequestJSkip = FALSE
g_mission.bRequestPSkip = FALSE
g_mission.bRequestCpSkip = FALSE
g_mission.bSyncForSkip = FALSE
g_mission.queueNextStage = MS_NULL
#IF IS_DEBUG_BUILD
zSkipMenu[CP_INTRO].sTxtLabel = "Intro"
zSkipMenu[CP_FINDROCKA].sTxtLabel = "Find rock A"
zSkipMenu[CP_ROCKSCENEA].sTxtLabel = "Rock scene A"
zSkipMenu[CP_FINDROCKB].sTxtLabel = "Find rock B"
zSkipMenu[CP_ROCKSCENEB].sTxtLabel = "Rock scene B"
zSkipMenu[CP_FINDROCKC].sTxtLabel = "Find rock C"
zSkipMenu[CP_ROCKSCENEC].sTxtLabel = "Rock scene C"
zSkipMenu[7].sTxtLabel = "Toggle Aim Camera pitch lock"
INT i
REPEAT MAX_CP i
zSkipMenu[i].bSelectable = TRUE
ENDREPEAT
#ENDIF
ENDPROC
/// PURPOSE:
/// Queue a mission stage skip to be executed later
/// PARAMS:
/// newStage - The stage we want to skip to
PROC QUEUE_MISSION_STAGE(MISSION_STAGE newStage)
g_mission.queueNextStage = newStage
ENDPROC
/// PURPOSE:
/// Queue a skip to the given checkpoint to be executed later
/// PARAMS:
/// iCheckpoint - The checkpoint we want to skip to
PROC QUEUE_CP_SKIP(INT iCheckpoint)
g_mission.queueCpSkip = iCheckpoint
g_mission.bRequestCpSkip = TRUE
ENDPROC
/// PURPOSE:
/// Change the mission stage to the stored requested stage
PROC CHANGE_MISSION_STAGE()
// Handle skips
IF g_mission.bRequestJSkip OR g_mission.bRequestPSkip OR g_mission.bRequestCpSkip
g_mission.bSyncForSkip = TRUE
IF g_mission.queueNextStage = MS_INTRO
DEBUG_PRINTSTRING("Sync for skip is TRUE and Intro is queued!")
ENDIF
ELSE
g_mission.bSyncForSkip = FALSE
ENDIF
IF g_mission.bRequestCpSkip
SWITCH (g_mission.queueCpSkip)
CASE CP_INTRO
g_mission.queueNextStage = MS_INTRO
BREAK
CASE CP_FINDROCKA
g_mission.queueNextStage = MS_FINDROCK
iCurrentRock = 0
BREAK
CASE CP_ROCKSCENEA
g_mission.queueNextStage = MS_ROCKSCENE
iCurrentRock = 0
BREAK
CASE CP_FINDROCKB
g_mission.queueNextStage = MS_FINDROCK
iCurrentRock = 1
BREAK
CASE CP_ROCKSCENEB
g_mission.queueNextStage = MS_ROCKSCENE
iCurrentRock = 1
BREAK
CASE CP_FINDROCKC
g_mission.queueNextStage = MS_FINDROCK
iCurrentRock = 2
BREAK
CASE CP_ROCKSCENEC
g_mission.queueNextStage = MS_ROCKSCENE
iCurrentRock = 2
BREAK
ENDSWITCH
ENDIF
g_mission.bRequestJSkip = FALSE
g_mission.bRequestPSkip = FALSE
g_mission.bRequestCpSkip = FALSE
// Change stage
g_mission.stage = g_mission.queueNextStage
g_mission.section = SECTION_SETUP
g_mission.iEvent = 0
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* EPS FUNCTIONS
/// PURPOSE:
/// Create the Epsilonist we want and set default behaviours, or grab an existing ped index and reset their flags
/// PARAMS:
/// eps - The Epsilonist we want
/// vPos - The position we want to create the Epsilonist at
/// fRot - The heading of the Epsilonist
/// hPed - An existing ped index we want to cast as the Epsilonist, if desired
/// model - The model we want to use for the Epsilonist
/// RETURNS:
/// True if the ped exists and is uninjured, False if not
FUNC BOOL CREATE_EPS(EPS_DATA& eps, VECTOR vPos, FLOAT fRot, PED_INDEX hPed = NULL, MODEL_NAMES model = DUMMY_MODEL_FOR_SCRIPT)
IF hPed <> NULL
eps.hPed = hPed
DEBUG_PRINTSTRING("*** Epsilonist exists, grabbing ped index")
ELSE
eps.hPed = CREATE_PED(PEDTYPE_CIVFEMALE, model, vPos, fRot)
DEBUG_PRINTSTRING("*** Epsilonist does not exist, creating new")
ENDIF
IF IS_PED_UNINJURED(eps.hPed)
//SET_ENTITY_CAN_BE_DAMAGED(eps.hPed, FALSE)
SET_PED_CONFIG_FLAG(eps.hPed, PCF_KeepRelationshipGroupAfterCleanUp, TRUE)
SET_PED_RELATIONSHIP_GROUP_HASH(eps.hPed, RELGROUPHASH_PLAYER)
SET_ENTITY_ONLY_DAMAGED_BY_PLAYER(eps.hPed, TRUE)
SET_PED_CAN_BE_TARGETTED(eps.hPed, FALSE)
SET_PED_CAN_RAGDOLL_FROM_PLAYER_IMPACT(eps.hPed, TRUE)
//TASK_STAND_STILL(eps.hPed, -1)
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS(eps.hPed, TRUE)
SET_PED_KEEP_TASK(eps.hPed, TRUE)
eps.state = EPS_ST_IDLE
eps.mode = SETUP_STATE
eps.iAnimMarker = -1
//SET_ENTITY_COORDS(eps.hPed, vPos)
//SET_ENTITY_HEADING(eps.hPed, fRot)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Check for whether the given Epsilonist has been threatened by anyone
/// PARAMS:
/// eps - The Epsilonist we want to check
/// RETURNS:
/// True if threatened, False otherwise
FUNC BOOL IS_EPS_THREATENED(EPS_DATA& eps)
IF IS_ANYONE_SHOOTING_NEAR_PED(eps.hPed)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Remove the given Epsilonist from the world
/// PARAMS:
/// eps - The Epsilonist we want to delete
PROC DELETE_EPS(EPS_DATA& eps)
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
SAFE_DELETE_PED(eps.hPed)
ENDPROC
/// PURPOSE:
/// Set the passed-in Epsilonist to move around the area going to various destinations randomly, or to the passed in destination
/// PARAMS:
/// eps - The Epsilonist we want to move
/// hDestinationMarker - The (optional) destination we want the Epsilonist to move to
/// bNoNavmesh - Uses TASK_GO_TO_COORD instead which doesn't use navmesh - much faster, used for Marnie exiting the intro
PROC SET_EPS_MOVE(EPS_DATA& eps, INT hDestinationMarker = -1)
IF IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_MOVE
eps.mode = SETUP_STATE
//CLEAR_PED_TASKS(eps.hPed)
IF eps.iAnimMarker <> -1
animMarkerArray[eps.iAnimMarker].bIsInUse = FALSE
ENDIF
eps.iAnimMarker = hDestinationMarker
ELSE
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ENDIF
ENDPROC
/// PURPOSE:
/// Set the passed in Epsilonists as idle and remove them from the player's group
/// PARAMS:
/// eps - The Epsilonist ped
/// bClearTasksImmediately - Whether we want to clear tasks immediately rather than... not immediately
PROC SET_EPS_IDLE(EPS_DATA& eps, BOOL bClearTasksImmediately = TRUE)
IF IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_IDLE
eps.mode = SETUP_STATE
IF bClearTasksImmediately
CLEAR_PED_TASKS_IMMEDIATELY(eps.hPed)
ELSE
CLEAR_PED_TASKS(eps.hPed)
ENDIF
IF eps.iAnimMarker <> -1
animMarkerArray[eps.iAnimMarker].bIsInUse = FALSE
eps.iAnimMarker = -1
ENDIF
IF IS_PED_IN_GROUP(eps.hPed)
REMOVE_PED_FROM_GROUP(eps.hPed)
ENDIF
ELSE
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ENDIF
ENDPROC
/// PURPOSE:
/// Immediately warp the given Epsilonist to the given marker
/// PARAMS:
/// eps - The Epsilonist
/// hMarker - The marker ID we want to warp to
PROC SET_EPS_WARP_TO_MARKER(EPS_DATA& eps, INT hMarker)
IF IS_PED_UNINJURED(eps.hPed)
IF eps.state = EPS_ST_MARKER
animMarkerArray[hMarker].bIsInUse = FALSE
ENDIF
//CLEAR_PED_TASKS(eps.hPed)
eps.state = EPS_ST_MARKER
eps.mode = SETUP_STATE
animMarkerArray[hMarker].bIsInUse = TRUE
eps.iAnimMarker = hMarker
IF IS_PED_IN_GROUP(eps.hPed)
REMOVE_PED_FROM_GROUP(eps.hPed)
ENDIF
CLEAR_PED_TASKS_IMMEDIATELY(eps.hPed)
SET_ENTITY_COORDS(eps.hPed, animMarkerArray[hMarker].vPos)
SET_ENTITY_HEADING(eps.hPed, animMarkerArray[hMarker].fRot)
ELSE
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ENDIF
ENDPROC
/// PURPOSE:
/// Set the given Epsilonist to follow the player around
/// PARAMS:
/// eps - The Epsilonist
/// bTurnToFacePed - Whether want the ped to always try and face the player when they stop moving
PROC SET_EPS_FOLLOW(EPS_DATA& eps, BOOL bTurnToFacePed = TRUE)
IF IS_PED_UNINJURED(eps.hPed) AND IS_PED_UNINJURED(PLAYER_PED_ID())
eps.state = EPS_ST_FOLLOW
eps.mode = SETUP_STATE
//CLEAR_PED_TASKS(eps.hPed)
TASK_LOOK_AT_ENTITY(eps.hPed, PLAYER_PED_ID(), -1)
IF bTurnToFacePed
TASK_TURN_PED_TO_FACE_ENTITY(eps.hPed, PLAYER_PED_ID())
ENDIF
eps.vPlayerStartPos = GET_ENTITY_COORDS(PLAYER_PED_ID())
ELSE
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ENDIF
ENDPROC
PROC CHECK_FOR_KNOCKDOWN(PED_INDEX epsPed)
IF IS_PED_UNINJURED(epsPed)
AND IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF epsKnockedOver = FALSE
IF IS_ENTITY_TOUCHING_ENTITY(PLAYER_PED_ID(), epsPed)
AND IS_PED_RAGDOLL(epsPed)
DEBUG_PRINTSTRING("Player knocked Eps over!")
epsKnockedOver = TRUE
epsPedKnockedOver = epsPed // Store which ped got knocked over
CLEAR_PED_TASKS(epsPed)
ENDIF
ELSE
IF IS_PED_UNINJURED(epsPedKnockedOver)
IF IS_PED_GETTING_UP(epsPedKnockedOver)
OR IS_PED_ON_FOOT(epsPedKnockedOver)
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF epsPedKnockedOver = epsilonianArray[ID_JIMMY].hPed
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_JKNOCK", CONV_PRIORITY_MEDIUM)
epsKnockedOver = FALSE
epsPedKnockedOver = NULL
ENDIF
ELSE
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_MKNOCK", CONV_PRIORITY_MEDIUM)
epsKnockedOver = FALSE
epsPedKnockedOver = NULL
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
/// PURPOSE:
/// Continually update and check the given Epsilonists behaviour every frame
/// PARAMS:
/// eps - The Epsilonist
PROC UPDATE_EPS(EPS_DATA& eps)
IF IS_PED_UNINJURED(eps.hPed) AND IS_PED_IN_GROUP(eps.hPed)
IF eps.state <> EPS_ST_FOLLOW
AND eps.state <> EPS_ST_CATCHUP
REMOVE_PED_FROM_GROUP(eps.hPed)
ENDIF
ENDIF
CHECK_FOR_KNOCKDOWN(eps.hPed)
SWITCH (eps.state)
CASE EPS_ST_NULL
BREAK
CASE EPS_ST_IDLE
BREAK
CASE EPS_ST_MOVE
IF NOT IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ELIF eps.mode = SETUP_STATE
// Try to find a marker to go to (a different one to the previous one)
INT iRandMarker
iRandMarker = GET_RANDOM_INT_IN_RANGE(0, iAnimMarkerCount)
WHILE eps.iAnimMarker = -1
IF animMarkerArray[iRandMarker].bIsInUse = FALSE
IF animMarkerArray[iRandMarker].type = ANIM_MARKER_FORAGE
IF NOT IS_ENTITY_AT_COORD(eps.hPed, animMarkerArray[iRandMarker].vPos, <<3,3,3>>)
DEBUG_PRINTSI("Telling ped to go to marker: ", iRandMarker)
animMarkerArray[iRandMarker].bIsInUse = TRUE
eps.iAnimMarker = iRandMarker
ENDIF
ENDIF
ENDIF
iRandMarker = (iRandMarker + 1) % iAnimMarkerCount
ENDWHILE
// Go to new marker
TASK_FOLLOW_NAV_MESH_TO_COORD(eps.hPed, animMarkerArray[eps.iAnimMarker].vPos, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_NO_STOPPING|ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED)
eps.mode = UPDATE_STATE
ELIF eps.mode = UPDATE_STATE
IF NOT eps.bNotUsingNavmeshMove
IF GET_SCRIPT_TASK_STATUS(eps.hPed, SCRIPT_TASK_FOLLOW_NAV_MESH_TO_COORD) = FINISHED_TASK
DEBUG_PRINTSTRING("Eps reached marker! (follow nav to coord)")
eps.state = EPS_ST_MARKER
eps.mode = SETUP_STATE
ENDIF
ELSE
IF GET_SCRIPT_TASK_STATUS(eps.hPed, SCRIPT_TASK_GO_STRAIGHT_TO_COORD) = FINISHED_TASK
DEBUG_PRINTSTRING("Eps reached marker! (go straight to coord)")
eps.bNotUsingNavmeshMove = FALSE
eps.state = EPS_ST_MARKER
eps.mode = SETUP_STATE
ENDIF
ENDIF
ENDIF
BREAK
CASE EPS_ST_MARKER
IF NOT IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ELIF eps.mode = SETUP_STATE
DEBUG_PRINTSI("Telling ped do sequence for marker: ", eps.iAnimMarker)
OPEN_SEQUENCE_TASK(seq)
IF animMarkerArray[eps.iAnimMarker].type = ANIM_MARKER_FORAGE
IF eps.hPed = epsilonianArray[ID_JIMMY].hPed
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_entry_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_idle_a_jb", DEFAULT, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_exit_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
ELSE
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_entry_marnie", SLOW_BLEND_IN, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_idle_a_marnie", DEFAULT, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_exit_marnie", SLOW_BLEND_IN, SLOW_BLEND_OUT)
ENDIF
ELIF animMarkerArray[eps.iAnimMarker].type = ANIM_MARKER_DUMMY_PISS
TASK_ACHIEVE_HEADING(null, animMarkerArray[eps.iAnimMarker].fRot)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "peeing")
ELIF animMarkerArray[eps.iAnimMarker].type = ANIM_MARKER_DUMMY_DANCE
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "hippy_a", NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_LOOPING)
ELIF animMarkerArray[eps.iAnimMarker].type = ANIM_MARKER_DUMMY_JIMMY
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_entry_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_idle_a_jb", DEFAULT, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_exit_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
ENDIF
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(eps.hPed, seq)
CLEAR_SEQUENCE_TASK(seq)
eps.mode = UPDATE_STATE
ELIF eps.mode = UPDATE_STATE
IF GET_SCRIPT_TASK_STATUS(eps.hPed, SCRIPT_TASK_PERFORM_SEQUENCE) = FINISHED_TASK
animMarkerArray[eps.iAnimMarker].bIsInUse = FALSE
eps.iAnimMarker = -1
eps.state = EPS_ST_MOVE
eps.mode = SETUP_STATE
ENDIF
ENDIF
BREAK
CASE EPS_ST_FOLLOW
IF NOT IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ELIF eps.mode = SETUP_STATE
IF NOT IS_ENTITY_AT_COORD(PLAYER_PED_ID(), eps.vPlayerStartPos, <<1,1,1>>)//<<1.5,1.5,1.5>>)//<<3,3,3>>)//
OR iCurrentRock > 0
IF NOT IS_PED_IN_GROUP(eps.hPed)
CLEAR_PED_TASKS(eps.hPed)
SET_PED_AS_GROUP_MEMBER(eps.hPed, PLAYER_GROUP_ID())
SET_PED_CONFIG_FLAG(eps.hPed,PCF_DontEnterVehiclesInPlayersGroup, TRUE)
ENDIF
iFollowIdleTimer = GET_GAME_TIMER()
IF iCurrentRock = 0
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)//FORMATION_LINE_ABREAST)//FORMATION_LOOSE)//
ELSE
SET_GROUP_FORMATION(PLAYER_GROUP_ID(), FORMATION_LOOSE)
ENDIF
SET_GROUP_FORMATION_SPACING(PLAYER_GROUP_ID(), 4.0)//4.5)//5.0)//6.0//4.0)//3.0)//2.5)//2.2)//1.8) //1.375)//1.5)//2.2)//1.25)
eps.mode = UPDATE_STATE
ENDIF
ELIF eps.mode = UPDATE_STATE
IF NOT IS_PED_IN_GROUP(eps.hPed)
eps.state = EPS_ST_CATCHUP
eps.mode = SETUP_STATE
ENDIF
// If the follower isn't currently moving, wait a few seconds and then do an idle anim
IF IS_PED_STILL(eps.hPed)
// If the ped isn't doing the idle, keep checking if the time has passed and then do it
IF NOT bFollowerDoingIdle
IF GET_GAME_TIMER() - iFollowIdleTimer > 6000
OPEN_SEQUENCE_TASK(seq)
IF eps.hPed = epsilonianArray[ID_JIMMY].hPed
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_entry_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_idle_a_jb", DEFAULT, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_jimmy_lookaround_exit_jb", SLOW_BLEND_IN, SLOW_BLEND_OUT)
ELSE
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_entry_marnie", SLOW_BLEND_IN, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_idle_a_marnie", DEFAULT, SLOW_BLEND_OUT)
TASK_PLAY_ANIM(null, "rcm_epsilonism4", "eps_4_ig_1_marnie_lookaround_exit_marnie", SLOW_BLEND_IN, SLOW_BLEND_OUT)
ENDIF
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(eps.hPed, seq)
CLEAR_SEQUENCE_TASK(seq)
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF eps.hPed = epsilonianArray[ID_JIMMY].hPed
CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_DAWDJ", CONV_PRIORITY_MEDIUM)
ELSE
CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_DAWDM", CONV_PRIORITY_MEDIUM)
ENDIF
ENDIF
bFollowerDoingIdle = TRUE
ENDIF
ELSE
// Otherwise, if they're doing it, keep resetting the timer, and keep checking if they're not doing it to reset the bool
iFollowIdleTimer = GET_GAME_TIMER()
IF NOT IsPedPerformingTask(eps.hPed, SCRIPT_TASK_PERFORM_SEQUENCE)
bFollowerDoingIdle = FALSE
ENDIF
ENDIF
ELSE
iFollowIdleTimer = GET_GAME_TIMER()
bFollowerDoingIdle = FALSE
ENDIF
// Check for player "messing around" and make the following Eps comment on it
IF IS_PED_SPRINTING(PLAYER_PED_ID())
OR IS_PED_JUMPING(PLAYER_PED_ID())
IF GET_GAME_TIMER() - iFollowMessingAroundTimer > 7500
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
AND NOT bIsPlayerAtRock
IF eps.hPed = epsilonianArray[ID_JIMMY].hPed
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_MESSJ", CONV_PRIORITY_MEDIUM)
iFollowMessingAroundTimer = GET_GAME_TIMER()
ENDIF
ELSE
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_MESSM", CONV_PRIORITY_MEDIUM)
iFollowMessingAroundTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
// If the player hasn't aimed the detector for a while, make the follower comment on it
IF (GET_GAME_TIMER() - iAimPromptTimer) > 15000 // 15 secs?
IF iAimPromptLines < 4 // Both characters only have 4 lines, so we can hard-code this to a number
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
AND NOT bIsPlayerAtRock
AND NOT IS_PLAYER_IN_FIRST_PERSON_CAMERA()
IF eps.hPed = epsilonianArray[ID_JIMMY].hPed
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_PROMPTJ", CONV_PRIORITY_MEDIUM)
iAimPromptTimer = GET_GAME_TIMER()
iAimPromptLines++
ENDIF
ELSE
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_PROMPTM", CONV_PRIORITY_MEDIUM)
iAimPromptTimer = GET_GAME_TIMER()
iAimPromptLines++
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
BREAK
CASE EPS_ST_CATCHUP
IF NOT IS_PED_UNINJURED(eps.hPed)
eps.state = EPS_ST_NULL
eps.mode = SETUP_STATE
ELIF eps.mode = SETUP_STATE
TASK_GO_TO_ENTITY(eps.hPed, PLAYER_PED_ID(), DEFAULT_TIME_BEFORE_WARP, 4.5)
eps.mode = UPDATE_STATE
ELIF eps.mode = UPDATE_STATE
// DISPLAY_TEXT(0.1, 0.1, "CATCHUP")
SET_PED_AS_GROUP_MEMBER(eps.hPed, PLAYER_GROUP_ID())
IF IS_PED_IN_GROUP(eps.hPed)
eps.state = EPS_ST_FOLLOW
eps.mode = SETUP_STATE
ENDIF
ENDIF
BREAK
DEFAULT
SCRIPT_ASSERT("UPDATE_EPS(): State not supported\n")
BREAK
ENDSWITCH
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* ROCK FUNCTIONS
/// PURPOSE:
/// Create the given rock in the world
/// PARAMS:
/// rock - The rock we want to create
PROC CREATE_ROCK(ROCK_DATA& rock)
VECTOR vPos = rock.vPos
DEBUG_PRINTVECTOR("Rock created at: ", rock.vPos)
rock.hObject = CREATE_OBJECT_NO_OFFSET(rock.model, vPos)
IF DOES_ENTITY_EXIST(rock.hObject)
SET_ENTITY_ROTATION(rock.hObject, rock.vRot, EULER_XYZ)
DEBUG_PRINTVECTOR("Rock rot vector: ", GET_ENTITY_ROTATION(rock.hObject, EULER_XYZ))
DEBUG_PRINTVECTOR("Rock actual position: ", GET_ENTITY_COORDS(rock.hObject, FALSE))
SET_ENTITY_CAN_BE_DAMAGED(rock.hObject, FALSE)
FREEZE_ENTITY_POSITION(rock.hObject, TRUE)
ENDIF
ENDPROC
/// PURPOSE:
/// Delete all the rocks in the mission
PROC DELETE_ALL_ROCKS()
INT i
REPEAT iRockCount i
SAFE_DELETE_OBJECT(rockArray[i].hObject)
ENDREPEAT
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* DETECTOR FUNCTIONS
CONST_FLOAT CONST_fDefaultHotAngle 0.9200
/// PURPOSE:
/// Initialise various detector variables
PROC INIT_DETECTOR()
gDetector.hSndHum = GET_SOUND_ID()
gDetector.hSndBeep = GET_SOUND_ID()
gDetector.hSndFound = GET_SOUND_ID()
gDetector.hSndScan = GET_SOUND_ID()
gDetector.fHotAngle = CONST_fDefaultHotAngle
gDetector.bLockSettings = FALSE
gDetector.sRecentAnim = "NO_RECENT_ANIM"
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(model_Detector)
IF IS_NAMED_RENDERTARGET_REGISTERED("digiscanner")
rt_ID = GET_NAMED_RENDERTARGET_RENDER_ID("digiscanner")
ENDIF
ENDPROC
/// PURPOSE:
/// Turn the detector on
/// PARAMS:
/// fMeanderFactor0 - An override for the first meander factor
/// fMeanderFactor1 - An override for the second meander factor
/// fMeanderAmplitude - An override for the meader amplitude
/// fStraightZone - An override for the straight zone
/// fHotAngle - An override for the detector hot angle
PROC START_DETECTOR(FLOAT fMeanderFactor0 = 50.0, FLOAT fMeanderFactor1 = 70.0, FLOAT fMeanderAmplitude = 25.0, FLOAT fStraightZone = 30.0, FLOAT fHotAngle = CONST_fDefaultHotAngle)
// Play hum sound
PLAY_SOUND_FROM_ENTITY(gDetector.hSndHum, "DEVICE", PLAYER_PED_ID(), "EPSILONISM_04_SOUNDSET")
// Calculate meander factor
IF gDetector.bLockSettings = FALSE
gDetector.fMeanderFactor0 = fMeanderFactor0
gDetector.fMeanderFactor1 = fMeanderFactor1
gDetector.fMeanderAmplitude = fMeanderAmplitude
gDetector.fStraightZone = fStraightZone
gDetector.fHotAngle = fHotAngle
ENDIF
gDetector.bIsFoundSoundOn = FALSE
gDetector.bIsScanSoundOn = FALSE
gDetector.sRecentAnim = "NO_RECENT_ANIM"
ENDPROC
/// PURPOSE:
/// Turn off the detector and prevent it reacting to the rock
PROC STOP_DETECTOR()
// Stop hum sound
STOP_SOUND(gDetector.hSndHum)
// Stop other sounds
STOP_SOUND(gDetector.hSndBeep)
STOP_SOUND(gDetector.hSndFound)
STOP_SOUND(gDetector.hSndScan)
gDetector.bIsFoundSoundOn = FALSE
gDetector.bIsScanSoundOn = FALSE
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)
ENDPROC
PROC FORCE_FOUND_SCREEN_ON_DETECTOR()
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_COLOUR")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(67) //BarsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(200) //BarsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //BarsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //LightsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(209) //LightsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(67) //LightsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //WrongWayR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) //WrongWayG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) //WrongWayB
END_SCALEFORM_MOVIE_METHOD()
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_DISTANCE")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(100.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)
ENDPROC
/// PURPOSE:
/// Called every frame to update the detector while the player is searching for a rock
/// PARAMS:
/// rock - The rock the player is currently searching for
PROC UPDATE_DETECTOR(ROCK_DATA& rock)
CONST_FLOAT fBeepMinDist 6.5//3.0
CONST_FLOAT fBeepRange 40.0
//-- Calc dist, and if facing the target
// Calc dist
FLOAT fDist = VDIST(rock.vPos, GET_ENTITY_COORDS(PLAYER_PED_ID()))
// Get distorted-angle forward-vector
VECTOR vPlayerForward = GET_ENTITY_FORWARD_VECTOR(PLAYER_PED_ID())
VECTOR vDistortedForward
IF fDist > gDetector.fStraightZone
FLOAT fDistortionAngle = 0.0
IF gDetector.fMeanderFactor0 > 0.0
fDistortionAngle += SIN((fDist-gDetector.fStraightZone) * (360.0 / gDetector.fMeanderFactor0)) * gDetector.fMeanderAmplitude
ENDIF
IF gDetector.fMeanderFactor1 > 0.0
fDistortionAngle += SIN((fDist-gDetector.fStraightZone) * (360.0 / gDetector.fMeanderFactor1)) * (gDetector.fMeanderAmplitude * -0.7)
ENDIF
vDistortedForward.x = (vPlayerForward.x * COS(fDistortionAngle)) - (vPlayerForward.y * SIN(fDistortionAngle))
vDistortedForward.y = (vPlayerForward.y * COS(fDistortionAngle)) + (vPlayerForward.x * SIN(fDistortionAngle))
ELSE
vDistortedForward = vPlayerForward
ENDIF
// Get other useful vectors
VECTOR vPlayerToRock1 = rock.vPos - GET_ENTITY_COORDS(PLAYER_PED_ID()) // Is rock ahead of player? (180 degrees)
VECTOR vPlayerToRock2 = rock.vPos - GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(PLAYER_PED_ID(), <<0,-5,0>>) // Is rock in cone? (starting cone slightly behind player)
// Calc is-in-front
BOOL bIsInFrontOfPlayer = vPlayerToRock1.x*vDistortedForward.x + vPlayerToRock1.y*vDistortedForward.y > 0.0
FLOAT fAngle = 1.0 - (GET_ANGLE_BETWEEN_2D_VECTORS(vDistortedForward.x, vDistortedForward.y, vPlayerToRock2.x, vPlayerToRock2.y) / 180.0)
// Adjust the hot angle depending on distance to the artefact
if fDist >= 10
gDetector.fHotAngle = CONST_fDefaultHotAngle
ELSE
gDetector.fHotAngle = 0.95
ENDIF
BOOL bOnTarget = (fAngle > gDetector.fHotAngle) AND bIsInFrontOfPlayer
#IF IS_DEBUG_BUILD
IF g_DEBUG_DisplayInfo
DRAW_RECT_FROM_CORNER(0.03, 0.18, 0.3, (0.2 + (0.05*4)) - 0.18, 0,0,0, 100)
TEXT_LABEL_63 sDebugStr
// sDebugStr = "Meander phase dist 0: "
// sDebugStr += GET_STRING_FROM_FLOAT(gDetector.fMeanderFactor0)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*1)), "STRING", sDebugStr)
//
// sDebugStr = "Meander phase dist 1: "
// sDebugStr += GET_STRING_FROM_FLOAT(gDetector.fMeanderFactor1)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*2)), "STRING", sDebugStr)
//
// sDebugStr = "Meander amplitude: "
// sDebugStr += GET_STRING_FROM_FLOAT(gDetector.fMeanderAmplitude)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*0)), "STRING", sDebugStr)
sDebugStr = "Dist to target: "
sDebugStr += GET_STRING_FROM_FLOAT(VDIST(GET_ENTITY_COORDS(PLAYER_PED_ID()), rock.vPos))
SET_TEXT_SCALE(0.7, 0.6)
DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*3)), "STRING", sDebugStr)
sDebugStr = "Current angle: "
sDebugStr += GET_STRING_FROM_FLOAT(fAngle)
SET_TEXT_SCALE(0.7, 0.6)
DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*0)), "STRING", sDebugStr)
// VECTOR vRockPos
// vRockPos = GET_ENTITY_COORDS(rockArray[0].hObject, FALSE)
// sDebugStr = "rock 0 z: "
// sDebugStr += GET_STRING_FROM_FLOAT(vRockPos.z)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*3)), "STRING", sDebugStr)
//
// vRockPos = GET_ENTITY_COORDS(rockArray[1].hObject, FALSE)
// sDebugStr = "rock 1 z: "
// sDebugStr += GET_STRING_FROM_FLOAT(vRockPos.z)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*4)), "STRING", sDebugStr)
//
// vRockPos = GET_ENTITY_COORDS(rockArray[2].hObject, FALSE)
// sDebugStr = "rock 2 z: "
// sDebugStr += GET_STRING_FROM_FLOAT(vRockPos.z)
// SET_TEXT_SCALE(0.7, 0.6)
// DISPLAY_TEXT_WITH_LITERAL_STRING(0.05, (0.2 + (0.05*5)), "STRING", sDebugStr)
ENDIF
#ENDIF
gDetector.bIsOnTarget = bOnTarget
//-- Manage radar beep
IF gDetector.bIsFoundSoundOn = TRUE
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
IF fDist > fBeepMinDist
OR bOnTarget = FALSE
STOP_SOUND(gDetector.hSndFound)
gDetector.bIsFoundSoundOn = FALSE
iPhaseTimer = 0
ENDIF
ELIF iPhaseTimer < GET_GAME_TIMER()
IF fDist <= fBeepMinDist AND bOnTarget
STOP_SOUND(gDetector.hSndBeep)
PLAY_SOUND_FROM_ENTITY(gDetector.hSndFound, "CONTINUAL_BEEP", PLAYER_PED_ID(), "EPSILONISM_04_SOUNDSET")
gDetector.bIsFoundSoundOn = TRUE
ELSE
// Set cycle length
FLOAT fBeepDist = fDist - (fBeepMinDist + 2.5)
IF fBeepDist < 0
fBeepDist = 0
ENDIF
INT iInterval = 125 + ROUND( (fBeepDist / fBeepRange) * (1250.0 - 125.0) )
IF iInterval > 1250
iInterval = 1250
ENDIF
iPhaseTimer = GET_GAME_TIMER() + iInterval
iInterval /= 3
IF iInterval < 100
iInterval = 100
ENDIF
iBeepOffTimer = GET_GAME_TIMER() + iInterval
// Play beep + shake pad
PLAY_SOUND_FROM_ENTITY(gDetector.hSndBeep, "IDLE_BEEP", PLAYER_PED_ID(), "EPSILONISM_04_SOUNDSET")
IF bOnTarget
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
ELSE
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 100)
ENDIF
ENDIF
ENDIF
// Stop beep sound
IF iBeepOffTimer > 0
AND GET_GAME_TIMER() > iBeepOffTimer
STOP_SOUND(gDetector.hSndBeep)
iBeepOffTimer = 0
ENDIF
//-- Manage on-target sound
IF IS_AIM_CAM_ACTIVE()
IF gDetector.bIsScanSoundOn = FALSE
PLAY_SOUND_FROM_ENTITY(gDetector.hSndScan, "SCAN", PLAYER_PED_ID(), "EPSILONISM_04_SOUNDSET")
gDetector.bIsScanSoundOn = TRUE
ELSE
IF bOnTarget
SET_VARIABLE_ON_SOUND(gDetector.hSndScan, "IsOnTarget", 1.0)
ELSE
SET_VARIABLE_ON_SOUND(gDetector.hSndScan, "IsOnTarget", 0.0)
ENDIF
ENDIF
iAimPromptTimer = GET_GAME_TIMER() // Keep resetting this timer while the player is aiming
ELSE
IF gDetector.bIsScanSoundOn = TRUE
STOP_SOUND(gDetector.hSndScan)
gDetector.bIsScanSoundOn = FALSE
ENDIF
ENDIF
//-- Manage proximity meter
IF NOT DOES_ENTITY_EXIST(gDetector.hObj)
gDetector.hObj = GET_CURRENT_PED_WEAPON_ENTITY_INDEX(PLAYER_PED_ID())
ELSE
FLOAT fProx = (fDist - fBeepMinDist) / (rock.fMeterRange - fBeepMinDist) // Normalise for range
IF fProx < 0.0
fProx = 0.0
ELIF fProx > 1.0
fProx = 1.0
ENDIF
IF gDetector.bIsOnTarget
fReading = 100 - (fProx * 100.0)
ELSE
fReading = 100 - (fProx * 100.0)
fReading = fReading*-1.0
ENDIF
// IF IS_AIM_CAM_ACTIVE()
// DRAW_SCALEFORM_MOVIE_FULLSCREEN(si_DetectorScaleform, 100, 100, 100, 255)
// ENDIF
IF NOT gDetector.bIsOnTarget
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()
ELSE
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_COLOUR")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(67) //BarsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(200) //BarsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //BarsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //LightsR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(209) //LightsG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(67) //LightsB
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(255) //WrongWayR
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) //WrongWayG
SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0) //WrongWayB
END_SCALEFORM_MOVIE_METHOD()
ENDIF
// Cap the reading value so the last bar doesn't get filled until you're very close
IF fReading >= 95.0
AND fReading <= 99.8
fReading = 94.9
ELIF fReading <= -95.0
AND fReading >= -99.8
fReading = -94.9
ENDIF
// If the player is at the find range for the object, force the distance bar to full just in case it's not
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, << fFindRange,fFindRange,2.0 >>, FALSE, FALSE, TM_ON_FOOT)
fReading = 100.0
ENDIF
BEGIN_SCALEFORM_MOVIE_METHOD(si_DetectorScaleform, "SET_DISTANCE")
SCALEFORM_MOVIE_METHOD_ADD_PARAM_FLOAT(fReading)
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)
// This is the old meter in the corner of the screen, from before the scaleform for the detector was created
// Technically it's not needed anymore, but let's keep it around just in case it's handy for debug,
// or if the scaleform breaks in a future build or something
// IF IS_AIM_CAM_ACTIVE()
// //PRINTFLOAT(fReading) PRINTNL()
// IF bOnTarget
// DRAW_TIMER_HUD(100 + (900 - CEIL(fProx * 900.0)), 1000, "EPS4_B0")
// ELSE
// DRAW_TIMER_HUD(0, 1000, "EPS4_B0")
// ENDIF
// ENDIF
ENDIF
//-- Manage player body anims
IF IS_CONTROL_PRESSED(PLAYER_CONTROL, INPUT_AIM)
// Player is using device -> start body anim, and pause on first frame
SET_PED_MAX_MOVE_BLEND_RATIO(PLAYER_PED_ID(), PEDMOVEBLENDRATIO_WALK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_JUMP)
IF bLockAimPitch
SET_GAMEPLAY_CAM_RELATIVE_PITCH(15)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_LOOK_UD)
ENDIF
bPlayerUsedAim = TRUE
ELSE
IF IS_PLAYER_IN_FIRST_PERSON_CAMERA()
bPlayerUsedAim = TRUE
ENDIF
// Player not using device -> kill body anim
// IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop")
// STOP_ANIM_TASK(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop", WALK_BLEND_OUT)
// ENDIF
ENDIF
ENDPROC
//PROC ATTEMPT_GRAB_DETECTOR()
// gDetector.hObj = GET_CURRENT_PED_WEAPON_ENTITY_INDEX(PLAYER_PED_ID())
// gDetector.sRecentAnim = NO_RECENT_ANIM
//
//// IF DOES_ENTITY_EXIST(gDetector.hObj)
//// PLAY_ENTITY_ANIM(gDetector.hObj, "detector_level1_prop", "rcm_epsilonism4", INSTANT_BLEND_IN, TRUE, FALSE, FALSE)
//// gDetector.sRecentAnim = detector_level1_prop
//// ENDIF
//ENDPROC
/// PURPOSE:
/// Checks if the detector exists in the world
/// RETURNS:
/// True if the detector exists, False otherwise
FUNC BOOL DOES_DETECTOR_EXIST()
IF DOES_ENTITY_EXIST(gDetector.hObj)
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
FUNC BOOL CHECK_FAIL_CONDITIONS_DURING_CUTSCENE()
IF IS_ENTITY_DEAD(PLAYER_PED_ID())
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_PLAYER_DEAD
g_mission.section = SECTION_CLEANUP
RETURN TRUE
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_MARNIE].hPed)
IF iCurrentRock < 2 // Only check this if we're not on the final cutscene - otherwise when we delete the ped, this will trigger and fail the mission!
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_DEAD
g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Mission failed: Marnie dead")
RETURN TRUE
ENDIF
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_JIMMY].hPed)
IF iCurrentRock < 2 // Only check this if we're not on the final cutscene - otherwise when we delete the ped, this will trigger and fail the mission!
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_DEAD
g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Mission failed: Jimmy dead")
RETURN TRUE
ENDIF
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_MARNIE].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_MARNIE].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_INJURED
g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Mission failed: Marnie injured")
RETURN TRUE
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_JIMMY].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_JIMMY].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_INJURED
g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Mission failed: Jimmy injured")
RETURN TRUE
ENDIF
RETURN FALSE
ENDFUNC
/// PURPOSE:
/// Update the animations on the player and detector depending on the direction the player is currently facing
/// PARAMS:
/// bIsPlayerFacingTarget - Whether the player is facing the rock or not
PROC UPDATE_PLAYER_AND_DETECTOR_ANIMS(BOOL bIsPlayerFacingTarget)
//-- Player body anims
// IF IS_AIM_CAM_ACTIVE()
//
// // Player is using device -> start body anim, and pause on first frame
// IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop")
// TASK_PLAY_ANIM(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop", 2, -2, -1, AF_SECONDARY|AF_UPPERBODY|AF_LOOPING)//|AF_DELAY_BLEND_WHEN_FINISHED)
// ELSE
// SET_ENTITY_ANIM_CURRENT_TIME(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop", 0.0)
// SET_ENTITY_ANIM_SPEED(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop", 0.0)
// ENDIF
//
// ELSE
//
// // Player not using device -> kill body anim
// IF IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop")
// STOP_ANIM_TASK(PLAYER_PED_ID(), "rcm_epsilonism4", "detector_pulls_forwards_loop", WALK_BLEND_OUT)
// ENDIF
//
// ENDIF
// Stop player from being able to autovault things
//SET_PED_RESET_FLAG(PLAYER_PED_ID(), PRF_DisablePlayerAutoVaulting, TRUE)
//-- Detector anims
IF bIsPlayerFacingTarget = TRUE
// Player is facing target -> Keep running random anims on the detector
IF DOES_DETECTOR_EXIST()
// If there is no anim runnning on the detector, start one
IF ARE_STRINGS_EQUAL(gDetector.sRecentAnim, "NO_RECENT_ANIM")
OR NOT IS_ENTITY_PLAYING_ANIM(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim)
OR GET_ENTITY_ANIM_CURRENT_TIME(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim) >= 0.98
// Choose one of the detector reaction anims based on distance to the target
IF fReading > LVL3_DISTANCE
gDetector.sRecentAnim = "detector_level3_prop"
ELIF fReading > LVL2_DISTANCE
gDetector.sRecentAnim = "detector_level2_prop"
ELSE
gDetector.sRecentAnim = "detector_level1_prop"
ENDIF
// Play the anim (no looping)
#IF IS_DEBUG_BUILD
IF bDebug_VerboseDetector
DEBUG_PRINTSF("fReading: ", fReading)
DEBUG_PRINTSTRING("PLAY_ENTITY_ANIM: ")
DEBUG_PRINTSTRING(gDetector.sRecentAnim)
DEBUG_PRINTSI("Time: ", GET_GAME_TIMER())
ENDIF
#ENDIF
PLAY_ENTITY_ANIM(gDetector.hObj, gDetector.sRecentAnim, "rcm_epsilonism4", FAST_BLEND_IN, FALSE, FALSE, FALSE)
ENDIF
ENDIF
ELSE
// Player is facing away -> Stop any detector anims
IF DOES_DETECTOR_EXIST()
// Check if an animation is currently playing, it will need to be stopped
IF NOT ARE_STRINGS_EQUAL(gDetector.sRecentAnim, "NO_RECENT_ANIM")
IF IS_ENTITY_PLAYING_ANIM(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim, ANIM_SCRIPT)
IF GET_ENTITY_ANIM_CURRENT_TIME(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim) <= 0.05
// Stop the anim
#IF IS_DEBUG_BUILD
IF bDebug_VerboseDetector
DEBUG_PRINTSTRING("STOP_ENTITY_ANIM:")
DEBUG_PRINTSTRING(gDetector.sRecentAnim)
DEBUG_PRINTSI("Time: ", GET_GAME_TIMER())
DEBUG_PRINTSTRING("IS_ENTITY_PLAYING_ANIM: ")
DEBUG_PRINTBOOL(IS_ENTITY_PLAYING_ANIM(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim, ANIM_SCRIPT))
DEBUG_PRINTSTRING("HAS_ENTITY_ANIM_FINISHED: ")
DEBUG_PRINTBOOL(HAS_ENTITY_ANIM_FINISHED(gDetector.hObj, "rcm_epsilonism4", gDetector.sRecentAnim, ANIM_SCRIPT))
ENDIF
#ENDIF
STOP_ENTITY_ANIM(gDetector.hObj, gDetector.sRecentAnim, "rcm_epsilonism4", SLOW_BLEND_OUT)
gDetector.sRecentAnim = "NO_RECENT_ANIM"
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
FUNC BOOL DO_MICHAEL_EXIT()
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Michael")
IF iCurrentRock >= 2
DEBUG_PRINTSTRING("*** Forcing Michael's move state (end cutscene)")
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, FALSE, FAUS_CUTSCENE_EXIT)
RETURN TRUE
ELSE
DEBUG_PRINTSTRING("*** Forcing Michael's move state")
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) != weapon_Detector
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
ENDIF
FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, FALSE, FAUS_CUTSCENE_EXIT)
RETURN TRUE
ENDIF
ENDIF
ENDIF
RETURN FALSE
ENDFUNC
PROC DO_DETECTOR_EXIT()
IF IS_ENTITY_ALIVE(DetectorCopy)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Artefact_Detector")
IF iCurrentRock < 2
DEBUG_PRINTSTRING("*** Detector exit")
GIVE_WEAPON_OBJECT_TO_PED(DetectorCopy, PLAYER_PED_ID())
SAFE_DELETE_OBJECT(DetectorCopy)
IF NOT DOES_ENTITY_EXIST(gDetector.hObj)
DEBUG_PRINTSTRING("*** Recreating gDetector.hObj after cutscene...")
gDetector.hObj = GET_CURRENT_PED_WEAPON_ENTITY_INDEX(PLAYER_PED_ID())
ENDIF
ELSE
DEBUG_PRINTSTRING("*** Detector exit (end cutscene)")
SAFE_DELETE_OBJECT(DetectorCopy)
ENDIF
ENDIF
ENDIF
ENDPROC
SEQUENCE_INDEX seqExit
PROC DO_MARNIE_INTRO_EXIT()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Marnie")
SET_EPS_MOVE(epsilonianArray[ID_MARNIE], g_hDummyMarker_MarnieIntroForage)
epsilonianArray[ID_MARNIE].state = EPS_ST_MOVE
epsilonianArray[ID_MARNIE].mode = UPDATE_STATE
IF epsilonianArray[ID_MARNIE].iAnimMarker <> -1
animMarkerArray[epsilonianArray[ID_MARNIE].iAnimMarker].bIsInUse = FALSE
ENDIF
epsilonianArray[ID_MARNIE].iAnimMarkeR = g_hDummyMarker_MarnieIntroForage
TASK_GO_STRAIGHT_TO_COORD(epsilonianArray[ID_MARNIE].hPed, animMarkerArray[epsilonianArray[ID_MARNIE].iAnimMarker].vPos, PEDMOVE_WALK, DEFAULT_TIME_NEVER_WARP)
FORCE_PED_MOTION_STATE(epsilonianArray[ID_MARNIE].hPed, MS_ON_FOOT_WALK, FALSE, FAUS_CUTSCENE_EXIT, TRUE)
epsilonianArray[ID_MARNIE].bNotUsingNavmeshMove = TRUE
DEBUG_PRINTSTRING("Done Marnie intro exit state")
ENDIF
ENDIF
ENDPROC
PROC DO_MARNIE_EXIT()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Marnie")
IF iCurrentRock >= 2
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[ID_MARNIE])
AND IS_VEHICLE_OK(Eps_Vehicle)
OPEN_SEQUENCE_TASK(seqExit)
//TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sRCLauncherDataLocal.pedID[ID_MARNIE], <<0, 4, 0>>), PEDMOVEBLENDRATIO_WALK, DEFAULT, DEFAULT, ENAV_NO_STOPPING|ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED)
TASK_WARP_PED_INTO_VEHICLE(NULL, Eps_Vehicle, VS_DRIVER)
//TASK_ENTER_VEHICLE(NULL, Eps_Vehicle, DEFAULT, VS_DRIVER, PEDMOVEBLENDRATIO_WALK, ECF_WARP_IF_DOOR_IS_BLOCKED|ECF_RESUME_IF_INTERRUPTED)
//TASK_PAUSE(NULL, 4500)
TASK_VEHICLE_DRIVE_TO_COORD(NULL, Eps_Vehicle, <<1743.33, 4962.18, 45.16>>, 20, DRIVINGSTYLE_NORMAL, BISON, DRIVINGMODE_AVOIDCARS_STOPFORPEDS_OBEYLIGHTS, 5, -1)
TASK_VEHICLE_DRIVE_WANDER(NULL, Eps_Vehicle, 30, DRIVINGMODE_STOPFORCARS_STRICT)
CLOSE_SEQUENCE_TASK(seqExit)
TASK_PERFORM_SEQUENCE(sRCLauncherDataLocal.pedID[ID_MARNIE], seqExit)
CLEAR_SEQUENCE_TASK(seqExit)
DEBUG_PRINTSTRING("Did Marnie pass exit")
ENDIF
ELSE
TASK_FOLLOW_NAV_MESH_TO_COORD(sRCLauncherDataLocal.pedID[ID_MARNIE], GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sRCLauncherDataLocal.pedID[ID_MARNIE], <<0, 7, 0>>), PEDMOVEBLENDRATIO_WALK, DEFAULT, DEFAULT, ENAV_NO_STOPPING|ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED)
DEBUG_PRINTSTRING("Did Marnie regular exit")
ENDIF
FORCE_PED_MOTION_STATE(epsilonianArray[ID_MARNIE].hPed, MS_ON_FOOT_WALK, FALSE, FAUS_CUTSCENE_EXIT)
ENDIF
ENDIF
ENDPROC
PROC DO_JIMMY_INTRO_EXIT()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Jimmy_Boston")
FLOAT fZ
GET_GROUND_Z_FOR_3D_COORD(<<1829.80, 4693.48, 38.50>>, fZ)
SET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed, <<1829.80, 4693.48, fZ>>)
//FORCE_PED_MOTION_STATE(epsilonianArray[ID_MARNIE].hPed, MS_ON_FOOT_IDLE, FALSE, FAUS_CUTSCENE_EXIT, TRUE)
ENDIF
ENDIF
ENDPROC
PROC DO_JIMMY_EXIT()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Jimmy_Boston")
IF iCurrentRock >= 2
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[ID_JIMMY])
AND IS_VEHICLE_OK(Eps_Vehicle)
OPEN_SEQUENCE_TASK(seqExit)
//TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(sRCLauncherDataLocal.pedID[ID_JIMMY], <<0, 2, 0>>), PEDMOVEBLENDRATIO_WALK, DEFAULT, DEFAULT, ENAV_NO_STOPPING|ENAV_GO_FAR_AS_POSSIBLE_IF_TARGET_NAVMESH_NOT_LOADED)
TASK_WARP_PED_INTO_VEHICLE(NULL, Eps_Vehicle, VS_FRONT_RIGHT)
//TASK_ENTER_VEHICLE(NULL, Eps_Vehicle, DEFAULT, VS_FRONT_RIGHT, PEDMOVEBLENDRATIO_WALK, ECF_WARP_IF_DOOR_IS_BLOCKED|ECF_RESUME_IF_INTERRUPTED)
CLOSE_SEQUENCE_TASK(seqExit)
TASK_PERFORM_SEQUENCE(sRCLauncherDataLocal.pedID[ID_JIMMY], seqExit)
CLEAR_SEQUENCE_TASK(seqExit)
DEBUG_PRINTSTRING("Did Jimmy pass exit")
ENDIF
ELSE
TASK_GO_STRAIGHT_TO_COORD(sRCLauncherDataLocal.pedID[ID_JIMMY], <<1764.0890, 4665.8794, 42.3031>>, PEDMOVEBLENDRATIO_WALK)
DEBUG_PRINTSTRING("Did Jimmy regular exit")
ENDIF
FORCE_PED_MOTION_STATE(epsilonianArray[ID_JIMMY].hPed, MS_ON_FOOT_WALK, FALSE, FAUS_CUTSCENE_EXIT)
ENDIF
ENDIF
ENDPROC
// ===========================================================================================================
// Termination
// ===========================================================================================================
// -----------------------------------------------------------------------------------------------------------
// Script Cleanup
// -----------------------------------------------------------------------------------------------------------
/// PURPOSE:
/// Clean up text in the script
PROC Script_TextCleanup()
// Could this be included in normal clean up?
STOP_SCRIPTED_CONVERSATION(FALSE)
CLEAR_PRINTS()
IF IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("EPS4_T0")
OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED("EPS4_T1")
CLEAR_HELP(TRUE)
ENDIF
ENDPROC
/// PURPOSE:
/// General script cleanup function
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())
DEBUG_PRINTSTRING("...Random Character Script was triggered so additional cleanup required") PRINTNL()
ENDIF
// Cleanup scene entities created by the RC launcher
//RC_CleanupSceneEntities(sRCLauncherDataLocal, FALSE)
IF IS_PED_UNINJURED(PLAYER_PED_ID())
// Remove gadget
REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), weapon_Detector)
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
CLEAR_PED_TASKS(PLAYER_PED_ID())
SET_PED_CAPSULE(PLAYER_PED_ID(), 0)
ENDIF
IF IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_STOP()
ENDIF
REMOVE_GRASS_CULL_SPHERE(grassCull)
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
AND IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
IF IS_PED_IN_GROUP(epsilonianArray[ID_MARNIE].hPed)
REMOVE_PED_FROM_GROUP(epsilonianArray[ID_MARNIE].hPed)
ELIF IS_PED_IN_GROUP(epsilonianArray[ID_JIMMY].hPed)
REMOVE_PED_FROM_GROUP(epsilonianArray[ID_JIMMY].hPed)
ENDIF
ENDIF
SAFE_RELEASE_PED(epsilonianArray[ID_MARNIE].hPed, TRUE, TRUE)
SAFE_RELEASE_PED(epsilonianArray[ID_JIMMY].hPed, TRUE, TRUE)
RELEASE_NAMED_RENDERTARGET("digiscanner")
REMOVE_SCENARIO_BLOCKING_AREA(mScenarioBlocker)
REMOVE_SCENARIO_BLOCKING_AREA(mScenarioBlockerPicnic)
REMOVE_NAVMESH_BLOCKING_OBJECT(iNavBlockerBush1)
REMOVE_NAVMESH_BLOCKING_OBJECT(iNavBlockerBush2)
REMOVE_NAVMESH_BLOCKING_OBJECT(iNavBlockerBush3)
IF IS_AUDIO_SCENE_ACTIVE("EPSILONISM_04_MIX")
DEBUG_PRINTSTRING("Stopping dynamic mix EPSILONISM_04_MIX")
STOP_AUDIO_SCENE("EPSILONISM_04_MIX")
ENDIF
#IF IS_DEBUG_BUILD
CLEANUP_EPS4_WIDGETS()
#ENDIF
TERMINATE_THIS_THREAD()
ENDPROC
// -----------------------------------------------------------------------------------------------------------
// Script Pass
// -----------------------------------------------------------------------------------------------------------
PROC Script_Passed()
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
IF bPlayerUsedAim = FALSE
INFORM_STAT_SYSTEM_OF_BOOL_STAT_HAPPENED(EP4_ARTIFACT_DETECTOR_USED)
ENDIF
STOP_DETECTOR()
Script_TextCleanup()
DISABLE_CELLPHONE(FALSE)
ADD_CONTACT_TO_PHONEBOOK(CHAR_JIMMY_BOSTON, MICHAEL_BOOK)
Random_Character_Passed(CP_RAND_C_EPS4)
// Reset donations - pity the fool who has donated more than asked for before this point..
CPRINTLN(DEBUG_RANDOM_CHAR, "Resetting donation to Epsilon Program for new mission request.")
g_savedGlobals.sRandomChars.g_iCurrentEpsilonPayment = 0
IF NOT IS_REPEAT_PLAY_ACTIVE()
WHILE NOT REGISTER_EMAIL_FROM_CHARACTER_TO_PLAYER(EMAIL_EPSILON4_DONATE, CT_AMBIENT, BIT_MICHAEL, CHAR_MARNIE, 30000, 10000)
WAIT(0)
ENDWHILE
CPRINTLN(DEBUG_RANDOM_CHAR, "Queued $10,000 donation reminder email")
ENDIF
// Wait 1 second before doing the holster animation, then do it, then clean up the script
REQUEST_ANIM_DICT("weapons@holster_1h")
WHILE GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) = weapon_Detector
WAIT(0)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
IF HAS_ANIM_DICT_LOADED("weapons@holster_1h")
IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "weapons@holster_1h", "holster")
TASK_PLAY_ANIM(PLAYER_PED_ID(), "weapons@holster_1h", "holster")
ELSE
IF GET_ENTITY_ANIM_CURRENT_TIME(PLAYER_PED_ID(), "weapons@holster_1h", "holster") >= 0.5
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
ENDIF
ENDIF
ENDIF
ENDWHILE
//Set epsilon step stat
INT iCurrent
STAT_GET_INT(NUM_EPSILON_STEP,iCurrent)
IF iCurrent < 12
STAT_SET_INT(NUM_EPSILON_STEP,12)
SET_ACHIEVEMENT_PROGRESS_SAFE(ENUM_TO_INT(ACH20),12)
CPRINTLN(debug_dan,"Epsilon progress:",12)
ENDIF
Script_Cleanup()
ENDPROC
//*******************************************************************************************************************
//*******************************************************************************************************************
PROC STAGE_LEADIN()
// Disable controls and exit current vehicle
RC_PLAYER_TRIGGER_SCENE_LOCK_IN()
IF g_mission.bSyncForSkip = TRUE
RC_START_Z_SKIP()
DEBUG_PRINTSTRING("SKIP: Doing sync for leadin skip")
RC_END_Z_SKIP()
g_mission.bSyncForSkip = FALSE
ENDIF
IF g_mission.section = SECTION_SETUP
iPhaseTimer = GET_GAME_TIMER()
IF NOT IS_REPEAT_PLAY_ACTIVE()
AND IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<1826.621216,4698.734375,41.368622>>, <<1831.157593,4680.191406,32.426258>>, 16.50)
DEBUG_PRINTSTRING("Doing setup for leadin")
ADD_PED_FOR_DIALOGUE(pedsForConversation, 4, sRCLauncherDataLocal.pedID[ID_MARNIE], "MARNIE")
IF LOAD_ANIMS() // Loops here until anims are loaded
g_mission.section = SECTION_RUNNING
ENDIF
ELSE
DEBUG_PRINTSTRING("Skipping setup for leadin (repeat play/wrong area)")
g_mission.section = SECTION_RUNNING
ENDIF
ENDIF
IF g_mission.section = SECTION_RUNNING
IF (GET_GAME_TIMER() - iPhaseTimer) > 1250
PLAY_SOUND_FROM_COORD(-1, "IDLE_BEEP_NPC", <<1827.06, 4700.52, 39.16>>, "EPSILONISM_04_SOUNDSET")
iPhaseTimer = GET_GAME_TIMER()
ENDIF
IF NOT IS_REPEAT_PLAY_ACTIVE() // Don't do the leadin if we're on a repeat-play, just go into the cutscene
AND IS_ENTITY_IN_ANGLED_AREA(PLAYER_PED_ID(), <<1826.621216,4698.734375,41.368622>>, <<1831.157593,4680.191406,32.426258>>, 16.50)
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[ID_MARNIE]) >= 3.0
IF NOT IS_GAMEPLAY_HINT_ACTIVE()
IF NOT bDonePushIn
IF IS_ENTITY_ALIVE(sRCLauncherDataLocal.pedID[ID_MARNIE])
SET_GAMEPLAY_ENTITY_HINT(sRCLauncherDataLocal.pedID[ID_MARNIE], <<0,0,0.2>>, TRUE, 30000)
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)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
OPEN_SEQUENCE_TASK(seq)
TASK_LOOK_AT_ENTITY(NULL, sRCLauncherDataLocal.pedID[ID_MARNIE], 15000)
TASK_FOLLOW_NAV_MESH_TO_COORD(NULL, <<1827.34, 4697.22, 38.02>>, PEDMOVEBLENDRATIO_WALK, DEFAULT_TIME_BEFORE_WARP, DEFAULT_NAVMESH_RADIUS, ENAV_NO_STOPPING)
TASK_TURN_PED_TO_FACE_ENTITY(NULL, sRCLauncherDataLocal.pedID[ID_MARNIE])
CLOSE_SEQUENCE_TASK(seq)
TASK_PERFORM_SEQUENCE(PLAYER_PED_ID(), seq)
CLEAR_SEQUENCE_TASK(seq)
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
ENDIF
bDonePushIn = TRUE
ENDIF
ENDIF
ELSE
STOP_GAMEPLAY_HINT_BEING_CANCELLED_THIS_UPDATE(TRUE)
ENDIF
ELSE
bDonePushIn = TRUE // Stop trying to do the push in
ENDIF
IF NOT bLeadInPlayed
IF IS_PED_UNINJURED(sRCLauncherDataLocal.pedID[ID_MARNIE])
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
TASK_LOOK_AT_ENTITY(sRCLauncherDataLocal.pedID[ID_MARNIE], PLAYER_PED_ID(), -1, SLF_WIDEST_PITCH_LIMIT|SLF_WIDEST_YAW_LIMIT)
TASK_PLAY_ANIM(sRCLauncherDataLocal.pedID[ID_MARNIE], "rcm_epsilonism4leadinout", "ep_4_rcm_leadin_marnie",NORMAL_BLEND_IN, NORMAL_BLEND_OUT, -1, AF_HOLD_LAST_FRAME) // Marnie
REMOVE_CUTSCENE()
REQUEST_CUTSCENE_WITH_PLAYBACK_LIST("EP_4_RCM_CONCAT", CS_SECTION_2)
DEBUG_PRINTSTRING("Done Marnie leadin anim - request concat cutscene")
bLeadInPlayed = TRUE
ENDIF
ELSE
IF IS_PED_UNINJURED(sRCLauncherDataLocal.pedID[ID_MARNIE])
IF IS_ENTITY_PLAYING_ANIM(sRCLauncherDataLocal.pedID[ID_MARNIE], "rcm_epsilonism4leadinout", "ep_4_rcm_leadin_marnie")
IF GET_ENTITY_ANIM_CURRENT_TIME(sRCLauncherDataLocal.pedID[ID_MARNIE], "rcm_epsilonism4leadinout", "ep_4_rcm_leadin_marnie") > 0.25
IF NOT bLeadInConvo
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "ESP4_RCL", CONV_PRIORITY_HIGH)
DEBUG_PRINTSTRING("Leadin convo done")
bLeadInConvo = TRUE
ENDIF
ENDIF
ENDIF
IF GET_ENTITY_ANIM_CURRENT_TIME(sRCLauncherDataLocal.pedID[ID_MARNIE], "rcm_epsilonism4leadinout", "ep_4_rcm_leadin_marnie") > 0.95
DEBUG_PRINTSTRING("Leadin done, launch cutscene")
QUEUE_MISSION_STAGE(MS_INTRO)
g_mission.section = SECTION_CLEANUP
ENDIF
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), sRCLauncherDataLocal.pedID[ID_MARNIE]) <= 1.5
// Stop the player if they get too close
SET_PLAYER_CONTROL(PLAYER_ID(), FALSE)
CLEAR_PED_TASKS(PLAYER_PED_ID())
ENDIF
ENDIF
ENDIF
ENDIF
ELSE
DEBUG_PRINTSTRING("Replay in progress/wrong area, skipping leadin")
QUEUE_MISSION_STAGE(MS_INTRO)
g_mission.section = SECTION_CLEANUP
ENDIF
ENDIF
IF g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Doing leadin cleanup and progressing")
CHANGE_MISSION_STAGE()
ENDIF
ENDPROC
//STAGE: INTRO
/// PURPOSE:
/// Main loop for the intro stage
PROC STAGE_INTRO()
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
DEBUG_PRINTSTRING("Can request assets for cutscene entity in Eps 4")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_CUTSCENE_PED_COMPONENT_VARIATION_FROM_PED_SAFE("Michael", PLAYER_PED_ID())
ENDIF
ENDIF
IF g_mission.bSyncForSkip = TRUE
RC_START_Z_SKIP()
REMOVE_CUTSCENE()
DEBUG_PRINTSTRING("SKIP: Doing sync for intro skip")
IF NOT IS_REPEAT_PLAY_ACTIVE()
RC_END_Z_SKIP()
ENDIF
g_mission.bSyncForSkip = FALSE
ENDIF
IF g_mission.section = SECTION_SETUP
// b* 2363991 - moved to inside SECTION_SETUP
IF NOT IS_CUTSCENE_ACTIVE()
REQUEST_CUTSCENE("ep_4_rcm_concat")
ENDIF
// Load/start cutscene
DEBUG_PRINTSTRING("In Intro setup, waiting for cutscene to be ready...")
IF RC_IS_CUTSCENE_OK_TO_START()
DEBUG_PRINTSTRING("Starting intro cutscene...")
IF IS_PED_UNINJURED(PLAYER_PED_ID())
REGISTER_ENTITY_FOR_CUTSCENE(PLAYER_PED_ID(), "Michael", CU_ANIMATE_EXISTING_SCRIPT_ENTITY) // Player
ENDIF
IF IS_PED_UNINJURED(sRCLauncherDataLocal.pedID[ID_MARNIE])
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[ID_MARNIE], "Marnie", CU_ANIMATE_EXISTING_SCRIPT_ENTITY) // Marnie
ENDIF
IF IS_PED_UNINJURED(sRCLauncherDataLocal.pedID[ID_JIMMY])
FREEZE_ENTITY_POSITION(sRCLauncherDataLocal.pedID[ID_JIMMY], FALSE)
IF IS_ENTITY_ALIVE(GET_CURRENT_PED_WEAPON_ENTITY_INDEX(sRCLauncherDataLocal.pedID[ID_JIMMY]))
DetectorCopy = CREATE_WEAPON_OBJECT_FROM_PED_WEAPON_WITH_COMPONENTS(sRCLauncherDataLocal.pedID[ID_JIMMY], WEAPONTYPE_DIGISCANNER)
REGISTER_ENTITY_FOR_CUTSCENE(DetectorCopy, "Artefact_Detector", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
REGISTER_ENTITY_FOR_CUTSCENE(sRCLauncherDataLocal.pedID[ID_JIMMY], "Jimmy_Boston", CU_ANIMATE_EXISTING_SCRIPT_ENTITY) // Jimmy
ENDIF
IF IS_PED_UNINJURED(PLAYER_PED_ID())
REGISTER_ENTITY_FOR_CUTSCENE(PLAYER_PED_ID(), "Michael", CU_ANIMATE_EXISTING_SCRIPT_ENTITY) // Jimmy
ENDIF
TRIGGER_MUSIC_EVENT("EPS4_START")
// Ensure lead-in blip is cleaned up...
RC_CLEANUP_LAUNCHER()
REPLAY_START_EVENT(REPLAY_IMPORTANCE_LOW)
// Start cutscene
START_CUTSCENE()
WAIT(0)
STOP_GAMEPLAY_HINT()
RC_END_Z_SKIP(TRUE, TRUE, FALSE)
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT(<<1833.393188,4703.848633,32.502178>>, <<1819.368286,4693.412598,43.891628>>, 18.0,
<< 1816.55, 4683.33, 37.75 >>, 339.76, GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR())
RC_START_CUTSCENE_MODE(<<1812, 4697, 39.1>>, TRUE, FALSE, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT)
WHILE NOT LOAD_ASSETS()
WAIT(0)
ENDWHILE
DEBUG_PRINTSTRING("Loaded all assets! Moving to intro run loop...")
g_mission.section = SECTION_RUNNING
ENDIF
ENDIF
IF g_mission.section = SECTION_RUNNING
FORCE_NOT_FOUND_SCREEN_ON_DETECTOR()
IF g_mission.bRequestJSkip
STOP_CUTSCENE()
QUEUE_MISSION_STAGE(MS_FINDROCK)
g_mission.section = SECTION_CLEANUP
ELIF g_mission.bRequestCpSkip
STOP_CUTSCENE()
g_mission.section = SECTION_CLEANUP
// b* 2363991 - changed to is cutscene playing not ACTIVE
ELIF NOT IS_CUTSCENE_PLAYING() // IS_CUTSCENE_ACTIVE() // Wait for cutscene to end
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
QUEUE_MISSION_STAGE(MS_FINDROCK)
g_mission.section = SECTION_CLEANUP
ENDIF
IF WAS_CUTSCENE_SKIPPED()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Michael")
DEBUG_PRINTSTRING("*** Forcing Michael's move state")
SAFE_TELEPORT_ENTITY(PLAYER_PED_ID(), <<1827.1611, 4698.6445, 38.0940>>, 184.1384)
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
//FORCE_PED_MOTION_STATE(PLAYER_PED_ID(), MS_ON_FOOT_IDLE, FALSE, FAUS_DEFAULT)
//FORCE_PED_AI_AND_ANIMATION_UPDATE(PLAYER_PED_ID())
//SET_GAMEPLAY_CAM_RELATIVE_PITCH()
//SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
ENDIF
IF CAN_SET_EXIT_STATE_FOR_CAMERA()
REPLAY_STOP_EVENT()
DEBUG_PRINTSTRING("*** Teleport Mike")
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
SAFE_TELEPORT_ENTITY(PLAYER_PED_ID(), <<1827.1611, 4698.6445, 38.0940>>, 184.1384)
ENDIF
DO_MARNIE_INTRO_EXIT()
DO_JIMMY_INTRO_EXIT()
IF IS_ENTITY_ALIVE(DetectorCopy)
IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Artefact_Detector")
GIVE_WEAPON_OBJECT_TO_PED(DetectorCopy, PLAYER_PED_ID())
SAFE_DELETE_OBJECT(DetectorCopy)
ENDIF
ENDIF
// IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Jimmy_Boston")
// IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
// SET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed, << 1825.0122, 4697.2227, 38.17 >>)
// SET_ENTITY_HEADING(epsilonianArray[ID_JIMMY].hPed, 234.0331)
// ENDIF
// ENDIF
// IF CAN_SET_EXIT_STATE_FOR_REGISTERED_ENTITY("Marnie")
// IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
// SET_ENTITY_COORDS(epsilonianArray[ID_MARNIE].hPed, << 1825.0122, 4697.2227, 38.17 >>)
// SET_ENTITY_HEADING(epsilonianArray[ID_MARNIE].hPed, 234.0331)
// ENDIF
// ENDIF
ENDIF
IF g_mission.section = SECTION_CLEANUP
DEBUG_PRINTSTRING("Doing intro cleanup and progressing")
IF NOT IS_CUTSCENE_PLAYING()
iCurrentRock = 0
RC_END_CUTSCENE_MODE(TRUE, FALSE)
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, FALSE)
CHANGE_MISSION_STAGE()
ENDIF
ENDIF
ENDPROC
//*******************************************************************************************************************
//*******************************************************************************************************************
/// PURPOSE:
/// Main loop for the Find Rock stages of the mission
PROC STAGE_FINDROCK()
SET_ALL_RANDOM_PEDS_FLEE_THIS_FRAME(PLAYER_ID())
INT iEps
IF g_mission.bSyncForSkip = TRUE
RC_START_Z_SKIP()
WAIT(0)
WHILE NOT LOAD_ASSETS()
WAIT(0)
ENDWHILE
IF IS_CUTSCENE_ACTIVE()
STOP_CUTSCENE_IMMEDIATELY()
REMOVE_CUTSCENE()
ENDIF
WHILE IS_CUTSCENE_ACTIVE()
WAIT(0)
ENDWHILE
IF IS_REPLAY_BEING_SET_UP()
END_REPLAY_SETUP()
ENDIF
IF iCurrentRock = 0
IF NOT IS_REPLAY_BEING_SET_UP()
SET_ENTITY_COORDS(PLAYER_PED_ID(), vPos_PlayerReset)
SET_ENTITY_HEADING(PLAYER_PED_ID(), fRot_PlayerReset)
ENDIF
SET_EPS_IDLE(epsilonianArray[ID_JIMMY], TRUE)
SET_EPS_IDLE(epsilonianArray[ID_MARNIE], TRUE)
// Got to do this here for the skip in case we don't watch the intro
IF IS_PED_UNINJURED(epsilonianArray[ID_JIMMY].hPed)
FREEZE_ENTITY_POSITION(sRCLauncherDataLocal.pedID[ID_JIMMY], FALSE)
SET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed, << 1829.75, 4693.50, 38.51 >>)
SET_ENTITY_HEADING(epsilonianArray[ID_JIMMY].hPed, 27.46)
FLOAT groundZ
VECTOR vTemp = GET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed)
GET_GROUND_Z_FOR_3D_COORD(<< 1829.75, 4693.50, 38.51 >>, groundZ)
SET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed, <<vTemp.x, vTemp.y, groundZ>>)
DEBUG_PRINTSTRING("Setting Jimmy position (0)")
//TASK_FOLLOW_NAV_MESH_TO_COORD(epsilonianArray[ID_JIMMY].hPed, << 1826.2458, 4696.5059, 38.1187 >>, PEDMOVE_WALK, DEFAULT_TIME_BEFORE_WARP)
ENDIF
IF IS_PED_UNINJURED(epsilonianArray[ID_MARNIE].hPed)
SET_ENTITY_COORDS(epsilonianArray[ID_MARNIE].hPed, << 1827.32, 4692.59, 38.53 >>)
SET_ENTITY_HEADING(epsilonianArray[ID_MARNIE].hPed, 171.22)
DEBUG_PRINTSTRING("Setting Marnie position (0)")
ENDIF
ELIF iCurrentRock = 1
SET_ENTITY_COORDS(PLAYER_PED_ID(), <<1754.6337, 4675.7886, 42.9068>>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 293.2275)
IF IS_PED_UNINJURED(epsilonianArray[ID_JIMMY].hPed)
SET_ENTITY_COORDS(epsilonianArray[ID_JIMMY].hPed, <<1758.5857, 4670.0854, 42.6276 >>)
SET_ENTITY_HEADING(epsilonianArray[ID_JIMMY].hPed, 262.4368)
DEBUG_PRINTSTRING("Setting Jimmy position (1)")
ENDIF
IF IS_PED_UNINJURED(epsilonianArray[ID_MARNIE].hPed)
SET_ENTITY_COORDS(epsilonianArray[ID_MARNIE].hPed, << 1759.9169, 4683.5840, 42.7266 >>)
SET_ENTITY_HEADING(epsilonianArray[ID_MARNIE].hPed, 148.3211)
DEBUG_PRINTSTRING("Setting Marnie position (1)")
ENDIF
ELIF iCurrentRock = 2
SET_ENTITY_COORDS(PLAYER_PED_ID(), <<1758.4542, 4829.4307, 39.7290>>)
SET_ENTITY_HEADING(PLAYER_PED_ID(), 168.2012)
IF IS_PED_UNINJURED(epsilonianArray[ID_MARNIE].hPed)
SET_ENTITY_COORDS(epsilonianArray[ID_MARNIE].hPed, << 1755.0052, 4827.3291, 40.0736 >>)
SET_ENTITY_HEADING(epsilonianArray[ID_MARNIE].hPed, 169.6486)
DEBUG_PRINTSTRING("Setting Marnie position (2)")
ENDIF
ENDIF
WAIT(750)
RC_END_Z_SKIP()
g_mission.bSyncForSkip = FALSE
ENDIF
IF g_mission.section = SECTION_SETUP
DEBUG_PRINTSI("Doing setup for FindRock section:", iCurrentRock)
// Clear buddy tasks and state immediately
SET_EPS_IDLE(epsilonianArray[ID_JIMMY], FALSE)
//SET_EPS_IDLE(epsilonianArray[ID_MARNIE], FALSE)
bFollowerDoingIdle = FALSE
bStillOnTarget = FALSE
epsKnockedOver = FALSE
iFoundWaitTimer = -1
iNonFollowerCloseLines = 0
iNonFollowerCloseLines1 = 0
iNonFollowerCloseLinesTimer = GET_GAME_TIMER()
iFollowMessingAroundTimer = GET_GAME_TIMER()
iAimPromptLines = 0
// IF IS_PED_UNINJURED(PLAYER_PED_ID())
// // Reset the player capsule
// SET_PED_CAPSULE(PLAYER_PED_ID(), 0)
// bCapsuleResized = FALSE
// ENDIF
// Set initial positions/actions for player/buddies for each stage
IF iCurrentRock = 0
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) != weapon_Detector
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
ENDIF
DISABLE_CELLPHONE(TRUE)
ENDIF
IF IS_PED_UNINJURED(epsilonianArray[ID_JIMMY].hPed)
REMOVE_WEAPON_FROM_PED(epsilonianArray[ID_JIMMY].hPed, weapon_Detector) // Make sure Jimmy definitely doesn't have the detector
TASK_FOLLOW_NAV_MESH_TO_COORD(epsilonianArray[ID_JIMMY].hPed, << 1826.2458, 4696.5059, 38.1187 >>, PEDMOVE_WALK, DEFAULT_TIME_BEFORE_WARP, 0.1)
ENDIF
SET_EPS_FOLLOW(epsilonianArray[ID_JIMMY], TRUE)
//SET_EPS_MOVE(epsilonianArray[ID_MARNIE])
// SET_GAMEPLAY_CAM_RELATIVE_HEADING(45)
// SET_GAMEPLAY_CAM_RELATIVE_PITCH(-15)
iCurrentMaxGoodLines = MAX_JGOOD_LINES
iCurrentMaxBadLines = MAX_JBAD_LINES
iSaidBadLines = 0
iSaidGoodLines = 0
WHILE IS_CUTSCENE_ACTIVE()
WAIT(0)
// Need to wait for the cutscene to completely finish before requesting the next one
ENDWHILE
ELIF iCurrentRock = 1
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) != weapon_Detector
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
DISABLE_CELLPHONE(TRUE)
ENDIF
ENDIF
SET_EPS_FOLLOW(epsilonianArray[ID_MARNIE], FALSE)
SET_EPS_MOVE(epsilonianArray[ID_JIMMY], g_hDummyMarker_Piss)
iCurrentMaxGoodLines = MAX_MGOOD_LINES
iCurrentMaxBadLines = MAX_MBAD_LINES
iSaidBadLines = 0
iSaidGoodLines = 0
WHILE IS_CUTSCENE_ACTIVE()
WAIT(0)
// Need to wait for the cutscene to completely finish before requesting the next one
ENDWHILE
ELIF iCurrentRock = 2
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) != weapon_Detector
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
DISABLE_CELLPHONE(TRUE)
ENDIF
ENDIF
SET_EPS_MOVE(epsilonianArray[ID_MARNIE], g_hMarker_MarnieAngry)
SET_EPS_WARP_TO_MARKER(epsilonianArray[ID_JIMMY], g_hDummyMarker_Dance)
iCurrentMaxGoodLines = MAX_PGOOD_LINES
iCurrentMaxBadLines = MAX_PBAD_LINES
iSaidBadLines = 0
iSaidGoodLines = 0
WHILE IS_CUTSCENE_ACTIVE()
WAIT(0)
// Need to wait for the cutscene to completely finish before requesting the next one
ENDWHILE
ENDIF
// Setup dialogue participants
ADD_PED_FOR_DIALOGUE(pedsForConversation, 0, PLAYER_PED_ID(), "MICHAEL")
ADD_PED_FOR_DIALOGUE(pedsForConversation, 5, epsilonianArray[ID_JIMMY].hPed, "JIMMYBOSTON")
ADD_PED_FOR_DIALOGUE(pedsForConversation, 4, epsilonianArray[ID_MARNIE].hPed, "MARNIE")
IF iCurrentRock = 0
hPrimaryBuddy = epsilonianArray[ID_JIMMY].hPed
ELSE
hPrimaryBuddy = epsilonianArray[ID_MARNIE].hPed
ENDIF
// Switch on detector
START_DETECTOR(rockArray[iCurrentRock].fMeanderFactor0,
rockArray[iCurrentRock].fMeanderFactor1,
rockArray[iCurrentRock].fMeanderAmplitude,
rockArray[iCurrentRock].fStraightZone,
rockArray[iCurrentRock].fHotAngle)
// Reset all vars
bIsPlayerOnTarget = FALSE
bIsPlayerAtRock = FALSE
bHasPlayerFoundRock = FALSE
bIsPlayerInWoods = TRUE
bAudDoneChat1 = FALSE
bAudDoneChat2 = FALSE
bAudDoneChatAll = FALSE
bAudDoneClose = FALSE
bAudDoneReturn1 = FALSE
bAudDoneReturn2 = FALSE
bObjDoneHunt = FALSE
bObjDoneExamine = FALSE
bObjDoneReturnWoods = FALSE
iTutorialLine = 0
iTutorialTimer = 0
CLEAR_HELP(TRUE)
iHintTimer = GET_GAME_TIMER()
iTutorialTimer = GET_GAME_TIMER() + 1000
DEBUG_PRINTSI("Finished setup, moving to run loop for rock #:", iCurrentRock)
g_mission.section = SECTION_RUNNING
ENDIF
IF g_mission.section = SECTION_RUNNING
//-- Check for deaths
IF IS_ENTITY_DEAD(PLAYER_PED_ID())
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_PLAYER_DEAD
g_mission.section = SECTION_CLEANUP
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_MARNIE].hPed)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_DEAD
g_mission.section = SECTION_CLEANUP
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_JIMMY].hPed)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_DEAD
g_mission.section = SECTION_CLEANUP
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_MARNIE].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_MARNIE].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_INJURED
g_mission.section = SECTION_CLEANUP
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_JIMMY].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_JIMMY].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_INJURED
g_mission.section = SECTION_CLEANUP
ELIF IS_EPS_THREATENED(epsilonianArray[ID_MARNIE])
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_THREATENED
g_mission.section = SECTION_CLEANUP
ELIF IS_EPS_THREATENED(epsilonianArray[ID_JIMMY])
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_THREATENED
g_mission.section = SECTION_CLEANUP
ELIF NOT IS_POINT_IN_POLY_2D(g_polyFailArea, GET_ENTITY_COORDS(PLAYER_PED_ID()))
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_LEFT_AREA
g_mission.section = SECTION_CLEANUP
ELIF g_mission.bRequestCpSkip
g_mission.section = SECTION_CLEANUP
ELIF g_mission.bRequestJSkip
QUEUE_MISSION_STAGE(MS_ROCKSCENE)
g_mission.section = SECTION_CLEANUP
ELIF g_mission.bRequestPSkip
IF iCurrentRock = 0
QUEUE_MISSION_STAGE(MS_INTRO)
DEBUG_PRINTSTRING("P skipping to intro...")
ELSE
iCurrentRock--
QUEUE_MISSION_STAGE(MS_ROCKSCENE)
ENDIF
g_mission.section = SECTION_CLEANUP
ELSE
// Update the epsilonians
REPEAT EPSILONIAN_MAX iEps
UPDATE_EPS(epsilonianArray[iEps])
ENDREPEAT
// Start preloading the cutscene when < the default cutscene load distance
IF DOES_ENTITY_EXIST(rockArray[iCurrentRock].hObject)
IF iCurrentRock = 0
if GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) < DEFAULT_CUTSCENE_LOAD_DIST
IF NOT HAS_CUTSCENE_LOADED()
REQUEST_CUTSCENE("EPS_4_MCS_1")
DEBUG_PRINTSTRING("Requesting midtro now")
ENDIF
ELIF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) > DEFAULT_CUTSCENE_UNLOAD_DIST
IF HAS_CUTSCENE_LOADED()
DEBUG_PRINTSTRING("Player moved away - unloading midtro")
REMOVE_CUTSCENE()
ENDIF
ENDIF
ELIF iCurrentRock = 1
if GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) < DEFAULT_CUTSCENE_LOAD_DIST
IF NOT HAS_CUTSCENE_LOADED()
REQUEST_CUTSCENE("EPS_4_MCS_2")
DEBUG_PRINTSTRING("Requesting midtro now")
ENDIF
ELIF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) > DEFAULT_CUTSCENE_UNLOAD_DIST
IF HAS_CUTSCENE_LOADED()
DEBUG_PRINTSTRING("Player moved away - unloading midtro")
REMOVE_CUTSCENE()
ENDIF
ENDIF
ELSE
if GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) < DEFAULT_CUTSCENE_LOAD_DIST
IF NOT HAS_CUTSCENE_LOADED()
REQUEST_CUTSCENE("EPS_4_MCS_3")
DEBUG_PRINTSTRING("Requesting midtro now")
ENDIF
ELIF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), rockArray[iCurrentRock].hObject) > DEFAULT_CUTSCENE_UNLOAD_DIST
IF HAS_CUTSCENE_LOADED()
DEBUG_PRINTSTRING("Player moved away - unloading midtro")
REMOVE_CUTSCENE()
ENDIF
ENDIF
ENDIF
ENDIF
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
DEBUG_PRINTSTRING("Trying to set player component variation")
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_CUTSCENE_PED_COMPONENT_VARIATION_FROM_PED_SAFE("Michael", PLAYER_PED_ID())
ENDIF
IF iCurrentRock = 0
OR iCurrentRock = 2
DEBUG_PRINTSTRING("Trying to set Jimmy prop variation")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
ENDIF
ENDIF
// Hide the ammo counter, as the detector doesn't need it (#736243)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
// Disable the player from bringing up the weapon wheel so they're stuck with the detector
// May need to look into this again for the PC version to disable the shortcut keys!! (#1022647)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SELECT_WEAPON)
// Keep checking the Mike is holding the detector in case he puts it away when falling, etc
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) != weapon_Detector
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), weapon_Detector, INFINITE_AMMO, TRUE)
ENDIF
ENDIF
// Update the detector
UPDATE_DETECTOR(rockArray[iCurrentRock])
// Update help
IF iCurrentRock = 0
IF iTutorialLine = 0
IF iTutorialTimer < GET_GAME_TIMER()
IF NOT IS_PLAYER_IN_FIRST_PERSON_CAMERA()
PRINT_HELP_FOREVER("EPS4_T0") // "Hold ~INPUT_AIM~ to use the detector."
iTutorialTimer = GET_GAME_TIMER() + DEFAULT_GOD_TEXT_TIME
iTutorialLine++
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ELSE
// Player is in first person camera - skip the first bit of help text
iTutorialLine = 2
ENDIF
ENDIF
ELIF iTutorialLine = 1
IF IS_CONTROL_JUST_PRESSED(PLAYER_CONTROL, INPUT_AIM)
OR iTutorialTimer < GET_GAME_TIMER()
CLEAR_HELP(TRUE)
iTutorialTimer = GET_GAME_TIMER() + 1000
iTutorialLine++
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ENDIF
ELIF iTutorialLine = 2
IF iTutorialTimer < GET_GAME_TIMER()
PRINT_HELP_FOREVER("EPS4_T1") // "The detector's proximity meter shows how far away the artifact is."
iTutorialTimer = GET_GAME_TIMER() + DEFAULT_GOD_TEXT_TIME
iTutorialLine++
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ENDIF
ELIF iTutorialLine = 3
IF iTutorialTimer < GET_GAME_TIMER()
CLEAR_HELP(TRUE)
iTutorialTimer = GET_GAME_TIMER() + 1000
iTutorialLine++
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ENDIF
ELIF iTutorialLine = 4
IF iTutorialTimer < GET_GAME_TIMER()
PRINT_HELP_FOREVER("EPS4_T2") // "When facing toward the artifact, the detector's screen will turn blue."
iTutorialTimer = GET_GAME_TIMER() + DEFAULT_GOD_TEXT_TIME
iTutorialLine++
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ENDIF
ELIF iTutorialLine = 5
IF iTutorialTimer < GET_GAME_TIMER()
CLEAR_HELP(TRUE)
iTutorialTimer = GET_GAME_TIMER() + 1000
iTutorialLine++
ENDIF
ENDIF
ENDIF
// Update anims
UPDATE_PLAYER_AND_DETECTOR_ANIMS(gDetector.bIsOnTarget)
//-- Monitor objectives
// Player is in woods
IF bIsPlayerInWoods = TRUE
SAFE_REMOVE_BLIP(g_hBlip)
IF NOT IS_POINT_IN_POLY_2D(g_polyPlayArea, GET_ENTITY_COORDS(PLAYER_PED_ID()))
bIsPlayerInWoods = FALSE
STOP_SCRIPTED_CONVERSATION(FALSE)
CLEAR_PRINTS()
ELIF bObjDoneExamine = FALSE AND bHasPlayerFoundRock
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
iHintTimer = GET_GAME_TIMER()
bObjDoneExamine = TRUE
ENDIF
ELIF bAudDoneChat1 = FALSE
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sChat1Dialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sChat1Dialogue, CONV_PRIORITY_MEDIUM)
// We need the empty string check above to skip over the 1st chat in case it doesn't exist, but we don't want
// the ped to look at Mike if there's no conversation being played, hence this extra check
IF NOT ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sChat1Dialogue, EMPTY_STRING)
IF IS_ENTITY_ALIVE(hPrimaryBuddy)
TASK_LOOK_AT_ENTITY(hPrimaryBuddy, PLAYER_PED_ID(), 10000)
ENDIF
ENDIF
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
bAudDoneChat1 = TRUE
ENDIF
ELIF bObjDoneHunt = FALSE
IF iCurrentRock = 0
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
PRINT_NOW("EPS4_A2", DEFAULT_GOD_TEXT_TIME, 0) // Find the artefact
iHintTimer = GET_GAME_TIMER()
bObjDoneHunt = TRUE
ENDIF
ELSE
bObjDoneHunt = TRUE // Don't repeat goal if not on first artefact
ENDIF
ELIF bAudDoneChat2 = FALSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND (GET_GAME_TIMER() - iHintTimer) >= DEFAULT_GOD_TEXT_TIME
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sChat2Dialogue, EMPTY_STRING)
OR NOT IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), hPrimaryBuddy, <<DIALOGUE_DIST,DIALOGUE_DIST,DIALOGUE_DIST>>)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sChat2Dialogue, CONV_PRIORITY_MEDIUM)
// We need the empty string check above to skip over the 2nd chat in case it doesn't exist, but we don't want
// the ped to look at Mike if there's no conversation being played, hence this extra check
IF NOT ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sChat2Dialogue, EMPTY_STRING)
IF IS_ENTITY_ALIVE(hPrimaryBuddy)
TASK_LOOK_AT_ENTITY(hPrimaryBuddy, PLAYER_PED_ID(), 5000)
ENDIF
ENDIF
bAudDoneChat2 = TRUE
iAimPromptTimer = GET_GAME_TIMER() // Reset this again to stop it happening until the first prompts are over
ENDIF
ENDIF
ELIF bAudDoneChatAll = FALSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
bAudDoneChatAll = TRUE
iSupressHintAudioTimer = GET_GAME_TIMER()
iSupressPickupAudioTimer = 0
ENDIF
ELIF bHasPlayerFoundRock = FALSE
AND NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, fNearRange)
// If we're close enough to do the close dialogue, fire it once - otherwise, keep doing the Good/Bad dialogue
IF IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, fCloseDialogRange)
IF NOT bAudDoneClose
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].SHintCloseDialogue, CONV_PRIORITY_MEDIUM)
IF IS_ENTITY_ALIVE(hPrimaryBuddy)
TASK_LOOK_AT_ENTITY(hPrimaryBuddy, PLAYER_PED_ID(), 5000)
ENDIF
REPLAY_RECORD_BACK_FOR_TIME(3.0, 5.0, REPLAY_IMPORTANCE_LOWEST)
bAudDoneClose = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
// Tutorial dialogue
IF IS_AIM_CAM_ACTIVE()
IF IS_ENTITY_IN_RANGE_ENTITY(PLAYER_PED_ID(), hPrimaryBuddy, DIALOGUE_DIST)
OR iCurrentRock = 2
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED() AND ((GET_GAME_TIMER() - iSupressHintAudioTimer) > 15000)
IF bIsPlayerOnTarget
IF bStillOnTarget = FALSE
IF iSaidGoodLines < iCurrentMaxGoodLines
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sHintGoodDialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sHintGoodDialogue, CONV_PRIORITY_MEDIUM)
IF IS_PED_UNINJURED(hPrimaryBuddy)
TASK_LOOK_AT_ENTITY(hPrimaryBuddy, PLAYER_PED_ID(), 3000)
ENDIF
iSupressHintAudioTimer = GET_GAME_TIMER()
iSaidGoodLines++
// We want Michael to mumble to himself if he carries on being on target, but only for the last artefact
IF iCurrentRock = 2
bStillOnTarget = TRUE
ENDIF
ENDIF
ENDIF
ELSE
IF iSaidOnTargetLines < 12 // We can hard-code this since this will only be used for artefact 3
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sHintGoodDialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_HASSIG", CONV_PRIORITY_MEDIUM)
iSupressHintAudioTimer = GET_GAME_TIMER()
iSaidOnTargetLines++
ENDIF
ENDIF
ENDIF
ELSE
IF iSaidbadLines < iCurrentMaxBadLines
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sHintBadDialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sHintBadDialogue, CONV_PRIORITY_MEDIUM)
IF IS_PED_UNINJURED(hPrimaryBuddy)
TASK_LOOK_AT_ENTITY(hPrimaryBuddy, PLAYER_PED_ID(), 3000)
ENDIF
iSupressHintAudioTimer = GET_GAME_TIMER()
iSaidBadLines++
ENDIF
ENDIF
ENDIF
ELIF bIsPlayerOnTarget <> gDetector.bIsOnTarget
bIsPlayerOnTarget = gDetector.bIsOnTarget
// Don't reset bStillOnTarget to whatever gDetector.bIsOnTarget is at all times - we only set it true for rock 3,
// and only after we've had at least one "NOW you're on target" lines
IF gDetector.bIsOnTarget = FALSE
bStillOnTarget = FALSE
ENDIF
IF bIsPlayerOnTarget
IF iSupressPickupAudioTimer < GET_GAME_TIMER()
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
STOP_SCRIPTED_CONVERSATION(TRUE)
ENDIF
iSupressHintAudioTimer = GET_GAME_TIMER() - 7500
iSupressPickupAudioTimer = GET_GAME_TIMER()
ENDIF
ELSE
iSupressHintAudioTimer = GET_GAME_TIMER() - 7500
ENDIF
ENDIF
ENDIF
ELSE
iSupressHintAudioTimer = GET_GAME_TIMER() - 5000
ENDIF
ENDIF
//Handle dialogue from the non-buddy ped if the player walks towards them
IF iCurrentRock = 0
IF iNonFollowerCloseLines < 5
IF (GET_GAME_TIMER() - iNonFollowerCloseLinesTimer) > 7500
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
IF GET_DISTANCE_BETWEEN_ENTITIES(epsilonianArray[ID_MARNIE].hPed, PLAYER_PED_ID()) < 4
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_NEARM", CONV_PRIORITY_LOW)
iNonFollowerCloseLines++
iNonFollowerCloseLinesTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELIF iCurrentRock = 1
IF iNonFollowerCloseLines < 4
IF (GET_GAME_TIMER() - iNonFollowerCloseLinesTimer) > 7500
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
IF GET_DISTANCE_BETWEEN_ENTITIES(epsilonianArray[ID_JIMMY].hPed, PLAYER_PED_ID()) < 4
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_NEARJ", CONV_PRIORITY_LOW)
iNonFollowerCloseLines++
iNonFollowerCloseLinesTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ELSE // Must be the third rock
IF iNonFollowerCloseLines < 3 // Track Jimmy's near lines
IF (GET_GAME_TIMER() - iNonFollowerCloseLinesTimer) > 7500
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
IF GET_DISTANCE_BETWEEN_ENTITIES(epsilonianArray[ID_JIMMY].hPed, PLAYER_PED_ID()) < 4
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_NEARJP", CONV_PRIORITY_LOW)
iNonFollowerCloseLines++
iNonFollowerCloseLinesTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF iNonFollowerCloseLines1 < 4 // Track Marnie's near lines
IF (GET_GAME_TIMER() - iNonFollowerCloseLinesTimer) > 7500
AND NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
IF GET_DISTANCE_BETWEEN_ENTITIES(epsilonianArray[ID_MARNIE].hPed, PLAYER_PED_ID()) < 4
IF CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", "EPS4_NEARMP", CONV_PRIORITY_LOW)
iNonFollowerCloseLines1++
iNonFollowerCloseLinesTimer = GET_GAME_TIMER()
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
// Detect if found rock / near rock / far from rock
IF IS_ENTITY_AT_COORD(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, << fFindRange,fFindRange,2.0 >>, FALSE, FALSE, TM_ON_FOOT)
IF iFoundWaitTimer = -1
iFoundWaitTimer = GET_GAME_TIMER()
ELIF (GET_GAME_TIMER() - iFoundWaitTimer) >= 1500
//FORCE_FOUND_SCREEN_ON_DETECTOR()
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
KILL_ANY_CONVERSATION()
ENDIF
iMidtroDelay = GET_GAME_TIMER()
QUEUE_MISSION_STAGE(MS_ROCKSCENE)
g_mission.section = SECTION_CLEANUP
ENDIF
ELIF bIsPlayerAtRock = FALSE
IF gDetector.bIsFoundSoundOn //IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, fNearRange)
// SET_GAMEPLAY_COORD_HINT(rockArray[iCurrentRock].vPos + <<0,0,1>>, -1)
bIsPlayerAtRock = TRUE
bHasPlayerFoundRock = TRUE
ENDIF
ELSE
// If player moves away from rock after finding it, go back to previous state (but leave the blip)
IF NOT IS_ENTITY_IN_RANGE_COORDS(PLAYER_PED_ID(), rockArray[iCurrentRock].vPos, fNearRange+2)
// STOP_GAMEPLAY_HINT()
bIsPlayerAtRock = FALSE
ENDIF
ENDIF
// Player has strayed from woods
ELSE
IF NOT DOES_BLIP_EXIST(g_hBlip)
g_hBlip = CREATE_COORD_BLIP(vPos_WoodsCentre, BLIPPRIORITY_MED, FALSE)
ENDIF
bIsPlayerOnTarget = gDetector.bIsOnTarget
IF IS_POINT_IN_POLY_2D(g_polyPlayArea, GET_ENTITY_COORDS(PLAYER_PED_ID()))
bIsPlayerInWoods = TRUE
STOP_SCRIPTED_CONVERSATION(FALSE)
CLEAR_PRINTS()
ELIF bObjDoneReturnWoods = FALSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
PRINT_NOW("EPS4_A1", DEFAULT_GOD_TEXT_TIME, 0) // Go back to the woods
iHintTimer = GET_GAME_TIMER()
bObjDoneReturnWoods = TRUE
ENDIF
ELIF bAudDoneReturn1 = FALSE
IF iCurrentRock < 2
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), hPrimaryBuddy, <<DIALOGUE_DIST,DIALOGUE_DIST,DIALOGUE_DIST>>)
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sReturn1Dialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sReturn1Dialogue, CONV_PRIORITY_MEDIUM)
bAudDoneReturn1 = TRUE
ENDIF
ENDIF
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sReturn1Dialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sReturn1Dialogue, CONV_PRIORITY_MEDIUM)
bAudDoneReturn1 = TRUE
ENDIF
ENDIF
ENDIF
ELIF bAudDoneReturn2 = FALSE
IF iCurrentRock < 2
IF IS_ENTITY_AT_ENTITY(PLAYER_PED_ID(), hPrimaryBuddy, <<DIALOGUE_DIST,DIALOGUE_DIST,DIALOGUE_DIST>>)
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND (GET_GAME_TIMER() - iHintTimer) >= DEFAULT_GOD_TEXT_TIME
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sReturn2Dialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sReturn2Dialogue, CONV_PRIORITY_MEDIUM)
bAudDoneReturn2 = TRUE
ENDIF
ENDIF
ENDIF
ELSE
IF NOT IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
AND (GET_GAME_TIMER() - iHintTimer) >= DEFAULT_GOD_TEXT_TIME
AND NOT IS_MESSAGE_BEING_DISPLAYED()
IF ARE_STRINGS_EQUAL(rockArray[iCurrentRock].sReturn2Dialogue, EMPTY_STRING)
OR CREATE_CONVERSATION(pedsForConversation, "EPS4AUD", rockArray[iCurrentRock].sReturn2Dialogue, CONV_PRIORITY_MEDIUM)
bAudDoneReturn2 = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IF g_mission.section = SECTION_CLEANUP
// Hide the ammo counter, as the detector doesn't need it (#736243)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
DEBUG_PRINTSTRING("In cleanup for FindRock")
IF IS_ANY_CONVERSATION_ONGOING_OR_QUEUED()
STOP_SCRIPTED_CONVERSATION(TRUE)
ENDIF
UPDATE_PLAYER_AND_DETECTOR_ANIMS(TRUE)
FORCE_FOUND_SCREEN_ON_DETECTOR()
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
IF (GET_GAME_TIMER() - iMidtroDelay) > 750
// Disable detector
STOP_DETECTOR()
REPLAY_RECORD_BACK_FOR_TIME(5.0, 5.0, REPLAY_IMPORTANCE_LOWEST)
REPLAY_RECORD_BACK_FOR_TIME(3.0)
// Clear tasks
CLEAR_PED_TASKS(PLAYER_PED_ID())
SET_EPS_IDLE(epsilonianArray[ID_JIMMY], FALSE)
SET_EPS_IDLE(epsilonianArray[ID_MARNIE], FALSE)
CHANGE_MISSION_STAGE()
ENDIF
ENDIF
ENDPROC
//*******************************************************************************************************************
//*******************************************************************************************************************
/// PURPOSE:
/// Main loop for the rock scripted cutscenes during the mission
PROC STAGE_ROCKSCENE()
// Hide the ammo counter, as the detector doesn't need it (#736243)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
IF g_mission.bSyncForSkip = TRUE
RC_START_Z_SKIP()
REMOVE_CUTSCENE()
IF iCurrentRock = 0
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_1")
ELIF iCurrentRock = 1
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_2")
ELSE
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_3")
ENDIF
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
DEBUG_PRINTSTRING("Trying to set player component variation")
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_CUTSCENE_PED_COMPONENT_VARIATION_FROM_PED_SAFE("Michael", PLAYER_PED_ID())
ENDIF
IF iCurrentRock = 0
OR iCurrentRock = 2
DEBUG_PRINTSTRING("Trying to set Jimmy prop variation")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
ENDIF
ENDIF
DEBUG_PRINTSTRING("SKIP: Doing sync for cutscene skip")
RC_END_Z_SKIP()
g_mission.bSyncForSkip = FALSE
ENDIF
IF g_mission.section = SECTION_SETUP
DEBUG_PRINTSI("Doing setup for RockScene:", iCurrentRock)
UPDATE_PLAYER_AND_DETECTOR_ANIMS(TRUE)
FORCE_FOUND_SCREEN_ON_DETECTOR()
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
// IF IS_PED_UNINJURED(PLAYER_PED_ID())
// // Reset the capsule during the cutscenes so the Epsilonists aren't affected by it (#709181)
// SET_PED_CAPSULE(PLAYER_PED_ID(), 0)
// bCapsuleResized = FALSE
// ENDIF
IF CAN_REQUEST_ASSETS_FOR_CUTSCENE_ENTITY()
DEBUG_PRINTSTRING("Trying to set player component variation")
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
SET_CUTSCENE_PED_COMPONENT_VARIATION_FROM_PED_SAFE("Michael", PLAYER_PED_ID())
ENDIF
IF iCurrentRock = 0
OR iCurrentRock = 2
DEBUG_PRINTSTRING("Trying to set Jimmy prop variation")
SET_CUTSCENE_PED_PROP_VARIATION("Jimmy_Boston", ANCHOR_EYES, 0)
ENDIF
ENDIF
IF NOT IS_VEHICLE_OK(Eps_Vehicle)
Eps_Vehicle = CREATE_VEHICLE(Bison, <<1851.57, 4772.12, 39.80>>, 31.35)
SET_VEHICLE_COLOURS(Eps_Vehicle, 157, 157)
SET_VEHICLE_EXTRA_COLOURS(Eps_Vehicle, 5, 157)
SET_VEHICLE_ON_GROUND_PROPERLY(Eps_Vehicle)
ENDIF
// Clear buddy tasks and state immediately
SET_EPS_IDLE(epsilonianArray[ID_JIMMY])
SET_EPS_IDLE(epsilonianArray[ID_MARNIE])
IF IS_PED_UNINJURED(PLAYER_PED_ID())
// Final check to make sure the cutscene is ok to start
WHILE NOT RC_IS_CUTSCENE_OK_TO_START()
DEBUG_PRINTSTRING("Waiting for cutscene to be OK to start...")
// Hide the ammo counter, as the detector doesn't need it (#736243)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
UPDATE_PLAYER_AND_DETECTOR_ANIMS(TRUE)
FORCE_FOUND_SCREEN_ON_DETECTOR()
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
// Request cutscene again using the RC version to 1) make sure it definitely gets loaded, and 2) to stop the player moving
IF iCurrentRock = 0
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_1")
ELIF iCurrentRock = 1
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_2")
ELSE
RC_REQUEST_MID_MISSION_CUTSCENE("EPS_4_MCS_3")
ENDIF
WAIT(0)
ENDWHILE
SET_PLAYER_FORCED_AIM(PLAYER_ID(), TRUE)
INT iTimer = GET_GAME_TIMER()
WHILE (GET_GAME_TIMER() - iTimer) < 500
DEBUG_PRINTSTRING("Doing 500ms pause")
// Hide the ammo counter, as the detector doesn't need it (#736243)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
SET_PLAYER_FORCED_AIM(PLAYER_ID(), TRUE)
UPDATE_PLAYER_AND_DETECTOR_ANIMS(TRUE)
FORCE_FOUND_SCREEN_ON_DETECTOR()
SET_CONTROL_SHAKE(PLAYER_CONTROL, 200, 150)
WAIT(0)
ENDWHILE
// Setup cutscene gumph here
IF iCurrentRock = 0
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
REGISTER_ENTITY_FOR_CUTSCENE(epsilonianArray[ID_JIMMY].hPed, "Jimmy_Boston", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
REGISTER_ENTITY_FOR_CUTSCENE(epsilonianArray[ID_MARNIE].hPed, "Marnie", 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
IF IS_ENTITY_ALIVE(gDetector.hObj)
DetectorCopy = CREATE_WEAPON_OBJECT_FROM_PED_WEAPON_WITH_COMPONENTS(PLAYER_PED_ID(), WEAPONTYPE_DIGISCANNER)
REGISTER_ENTITY_FOR_CUTSCENE(DetectorCopy, "Artefact_Detector", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(rockArray[iCurrentRock].hObject)
REGISTER_ENTITY_FOR_CUTSCENE(rockArray[iCurrentRock].hObject, "EPS_TV", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
ELIF iCurrentRock = 1
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
epsilonianArray[ID_MARNIE].bNotUsingNavmeshMove = FALSE
REGISTER_ENTITY_FOR_CUTSCENE(epsilonianArray[ID_MARNIE].hPed, "Marnie", 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
IF IS_ENTITY_ALIVE(gDetector.hObj)
DetectorCopy = CREATE_WEAPON_OBJECT_FROM_PED_WEAPON_WITH_COMPONENTS(PLAYER_PED_ID(), WEAPONTYPE_DIGISCANNER)
REGISTER_ENTITY_FOR_CUTSCENE(DetectorCopy, "Artefact_Detector", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(rockArray[iCurrentRock].hObject)
REGISTER_ENTITY_FOR_CUTSCENE(rockArray[iCurrentRock].hObject, "EPS_Battery", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
ELSE
IF IS_ENTITY_ALIVE(epsilonianArray[ID_JIMMY].hPed)
REGISTER_ENTITY_FOR_CUTSCENE(epsilonianArray[ID_JIMMY].hPed, "Jimmy_Boston", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
REGISTER_ENTITY_FOR_CUTSCENE(epsilonianArray[ID_MARNIE].hPed, "Marnie", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
IF IS_ENTITY_ALIVE(gDetector.hObj)
DetectorCopy = CREATE_WEAPON_OBJECT_FROM_PED_WEAPON_WITH_COMPONENTS(PLAYER_PED_ID(), WEAPONTYPE_DIGISCANNER)
REGISTER_ENTITY_FOR_CUTSCENE(DetectorCopy, "Artefact_Detector", 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
IF IS_ENTITY_ALIVE(rockArray[iCurrentRock].hObject)
REGISTER_ENTITY_FOR_CUTSCENE(rockArray[iCurrentRock].hObject, "Old_Boot", CU_ANIMATE_EXISTING_SCRIPT_ENTITY)
ENDIF
ENDIF
// Start cutscene
START_CUTSCENE()
REPLAY_START_EVENT(REPLAY_IMPORTANCE_LOW)
// Got to do this instead of wait(0) like other missions so we can call HIDE_HUD_COMPONENT_THIS_FRAME
iTimer = GET_GAME_TIMER()
WHILE (GET_GAME_TIMER() - iTimer) < 1
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
WAIT(0)
REPLAY_CHECK_FOR_EVENT_THIS_FRAME("SF_Epsilon4")
ENDWHILE
// Don't want Mike to have the detector after the last cutscene
IF iCurrentRock >= 2
IF IS_ENTITY_ALIVE(PLAYER_PED_ID())
GIVE_WEAPON_TO_PED(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, INFINITE_AMMO, TRUE)
ENDIF
ENDIF
SET_PLAYER_FORCED_AIM(PLAYER_ID(), FALSE)
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT(rockArray[iCurrentRock].vAngledArea1, rockArray[iCurrentRock].vAngledArea2, rockArray[iCurrentRock].fAngledAreaWidth,
rockArray[iCurrentRock].vWarpCarPos, rockArray[iCurrentRock].fWarpCarRot, GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR())
RC_START_CUTSCENE_MODE(rockArray[iCurrentRock].vPos, TRUE, FALSE,
DEFAULT, DEFAULT, DEFAULT, DEFAULT, FALSE)
ENDIF
DEBUG_PRINTSI("Finished setup, moving to run loop for RockScene #:", iCurrentRock)
g_mission.section = SECTION_RUNNING
ENDIF
IF g_mission.section = SECTION_RUNNING
//-- Check for deaths
IF CHECK_FAIL_CONDITIONS_DURING_CUTSCENE()
ELIF g_mission.bRequestCpSkip
g_mission.section = SECTION_CLEANUP
ELIF g_mission.bRequestJSkip
IF (iCurrentRock < iRockCount-1)
QUEUE_MISSION_STAGE(MS_FINDROCK)
ELSE
QUEUE_MISSION_STAGE(MS_PASSED)
ENDIF
g_mission.section = SECTION_CLEANUP
iCurrentRock++
ELIF g_mission.bRequestPSkip
QUEUE_MISSION_STAGE(MS_FINDROCK)
g_mission.section = SECTION_CLEANUP
ELSE
// Timeout + skip checks
// IF IS_CUTSCENE_SKIP_BUTTON_JUST_PRESSED_WITH_DELAY()
//// bPlayerSkippedScene = TRUE
// g_mission.iEvent = -1
// ENDIF
IF iCurrentRock >= 2
IF IS_CUTSCENE_PLAYING()
IF GET_CUTSCENE_TIME() > 17000
IF NOT IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_START(<<1847.4722, 4756.1572, 36.6968>>, GET_HEADING_AS_VECTOR(271.4718), 145.0)
ENDIF
ENDIF
ENDIF
ENDIF
// Run events
IF g_mission.iEvent = 0
FORCE_FOUND_SCREEN_ON_DETECTOR()
// Keep spamming for the blend
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
IF WAS_CUTSCENE_SKIPPED()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
g_mission.iEvent = 1
ENDIF
DO_DETECTOR_EXIT()
IF iCurrentRock >= 2
DO_MARNIE_EXIT()
DO_JIMMY_EXIT()
ELIF iCurrentRock = 1
IF DO_MICHAEL_EXIT()
g_mission.iEvent = 1
ENDIF
DO_MARNIE_EXIT()
ELSE
IF DO_MICHAEL_EXIT()
g_mission.iEvent = 1
ENDIF
DO_MARNIE_EXIT()
DO_JIMMY_EXIT()
ENDIF
IF NOT IS_CUTSCENE_ACTIVE()
g_mission.iEvent = -1
DEBUG_PRINTSTRING("Cutscene not active, setting event -1")
ENDIF
ENDIF
IF g_mission.iEvent = 1
FORCE_NOT_FOUND_SCREEN_ON_DETECTOR()
DO_MICHAEL_EXIT()
DO_DETECTOR_EXIT()
IF iCurrentRock >= 2
DO_MARNIE_EXIT()
DO_JIMMY_EXIT()
ELIF iCurrentRock = 1
DO_MARNIE_EXIT()
ELSE
DO_MARNIE_EXIT()
DO_JIMMY_EXIT()
ENDIF
IF WAS_CUTSCENE_SKIPPED()
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
ENDIF
IF NOT IS_CUTSCENE_ACTIVE()
g_mission.iEvent = -1
DEBUG_PRINTSTRING("Cutscene not active, setting event -1")
ENDIF
ENDIF
// If complete...
IF g_mission.iEvent = -1
DEBUG_PRINTSTRING("Doing event -1...")
IF (iCurrentRock < iRockCount-1)
QUEUE_MISSION_STAGE(MS_FINDROCK)
ELSE
QUEUE_MISSION_STAGE(MS_WAITTOPASS)
ENDIF
IF iCurrentRock >= 2
TRIGGER_MUSIC_EVENT("EPS4_STOP")
SAFE_DELETE_OBJECT(rockArray[iCurrentRock].hObject)
ENDIF
g_mission.section = SECTION_CLEANUP
iCurrentRock++
DEBUG_PRINTSI("END CUTSCENE: iCurrentRock = ", iCurrentRock)
ENDIF
ENDIF
ENDIF
IF g_mission.section = SECTION_CLEANUP
REPLAY_STOP_EVENT()
DEBUG_PRINTSTRING("Doing cleanup for RockScene")
// IF IS_PED_UNINJURED(PLAYER_PED_ID())
// // Reset player in right direction
// IF (iCurrentRock < iRockCount)
// CLEAR_PED_TASKS_IMMEDIATELY(PLAYER_PED_ID())
// IF rockArray[iCurrentRock].fPostSceneRot >= 0.0
// SET_ENTITY_HEADING(PLAYER_PED_ID(), rockArray[iCurrentRock].fPostSceneRot)
// ENDIF
// ELSE
// CLEAR_PED_TASKS(PLAYER_PED_ID())
// ENDIF
//
// // Stop looking at the object
// TASK_CLEAR_LOOK_AT(PLAYER_PED_ID())
// ENDIF
// End custcene
// SET_GAMEPLAY_CAM_RELATIVE_HEADING()
RC_END_CUTSCENE_MODE(TRUE, FALSE)
// Change state
CHANGE_MISSION_STAGE()
ENDIF
ENDPROC
PROC STAGE_Passwait()
SWITCH g_mission.section
CASE SECTION_SETUP
REQUEST_ANIM_DICT("weapons@holster_1h")
WHILE GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) = weapon_Detector
WAIT(0)
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
IF HAS_ANIM_DICT_LOADED("weapons@holster_1h")
IF NOT IS_ENTITY_PLAYING_ANIM(PLAYER_PED_ID(), "weapons@holster_1h", "holster")
TASK_PLAY_ANIM(PLAYER_PED_ID(), "weapons@holster_1h", "holster")
ELSE
IF GET_ENTITY_ANIM_CURRENT_TIME(PLAYER_PED_ID(), "weapons@holster_1h", "holster") >= 0.5
SET_CURRENT_PED_WEAPON(PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE)
ENDIF
ENDIF
ENDIF
ENDWHILE
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
REMOVE_WEAPON_FROM_PED(PLAYER_PED_ID(), weapon_Detector)
g_mission.section = SECTION_RUNNING
BREAK
CASE SECTION_RUNNING
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
//-- Check for deaths
IF IS_ENTITY_DEAD(PLAYER_PED_ID())
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_PLAYER_DEAD
g_mission.section = SECTION_CLEANUP
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_MARNIE].hPed)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_DEAD
g_mission.section = SECTION_CLEANUP
ELIF IS_ENTITY_DEAD(epsilonianArray[ID_JIMMY].hPed)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_DEAD
g_mission.section = SECTION_CLEANUP
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_MARNIE].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_MARNIE].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_INJURED
g_mission.section = SECTION_CLEANUP
ELIF HAS_ENTITY_BEEN_DAMAGED_BY_ENTITY(epsilonianArray[ID_JIMMY].hPed, PLAYER_PED_ID(), TRUE)
AND HAS_ENTITY_BEEN_DAMAGED_BY_WEAPON(epsilonianArray[ID_JIMMY].hPed, WEAPONTYPE_INVALID, GENERALWEAPON_TYPE_ANYWEAPON)
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_INJURED
g_mission.section = SECTION_CLEANUP
ELIF IS_EPS_THREATENED(epsilonianArray[ID_MARNIE])
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_MARNIE_THREATENED
g_mission.section = SECTION_CLEANUP
ELIF IS_EPS_THREATENED(epsilonianArray[ID_JIMMY])
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_JIMMY_THREATENED
g_mission.section = SECTION_CLEANUP
ELIF IS_ENTITY_ALIVE(epsilonianArray[ID_MARNIE].hPed)
IF GET_DISTANCE_BETWEEN_ENTITIES(PLAYER_PED_ID(), epsilonianArray[ID_MARNIE].hPed) >= 50
IF IS_NEW_LOAD_SCENE_ACTIVE()
NEW_LOAD_SCENE_STOP()
ENDIF
QUEUE_MISSION_STAGE(MS_PASSED)
g_mission.section = SECTION_CLEANUP
ENDIF
ENDIF
BREAK
CASE SECTION_CLEANUP
HIDE_HUD_COMPONENT_THIS_FRAME(NEW_HUD_WEAPON_ICON)
CHANGE_MISSION_STAGE()
BREAK
ENDSWITCH
ENDPROC
//*******************************************************************************************************************
//******************************************************************************************************************* STAGE: FailFade
/// PURPOSE:
/// Main stage for mission failure
PROC STAGE_FailFade()
SWITCH g_mission.section
CASE SECTION_SETUP
Script_TextCleanup()
TRIGGER_MUSIC_EVENT("EPS_FAIL")
// convert reason to string
STRING sFailType
sFailType = EMPTY_STRING
SWITCH (g_mission.failReason)
CASE FAIL_REASON_LEFT_AREA
sFailType = "EPS4_X1"
BREAK
CASE FAIL_REASON_MARNIE_DEAD
sFailType = "EPS4_X2"
BREAK
CASE FAIL_REASON_JIMMY_DEAD
sFailType = "EPS4_X3"
BREAK
CASE FAIL_REASON_MARNIE_INJURED
sFailType = "EPS4_X4"
BREAK
CASE FAIL_REASON_JIMMY_INJURED
sFailType = "EPS4_X5"
BREAK
CASE FAIL_REASON_MARNIE_THREATENED
sFailType = "EPS4_X7"
BREAK
CASE FAIL_REASON_JIMMY_THREATENED
sFailType = "EPS4_X8"
BREAK
DEFAULT
// no fail reason
BREAK
ENDSWITCH
IF ARE_STRINGS_EQUAL(sFailType, EMPTY_STRING)
Random_Character_Failed()
ELSE
Random_Character_Failed_With_Reason(sFailType)
ENDIF
g_mission.section = SECTION_RUNNING
BREAK
CASE SECTION_RUNNING
IF GET_MISSION_FLOW_SAFE_TO_CLEANUP()
// Do a check here to see if we need to warp the player at all
// (only set the fail warp locations if we can't leave the player where he was)
//MISSION_FLOW_SET_FAIL_WARP_LOCATION(<< 1831.4000, 4663.7002, 33.3069 >>, 2.1870)
//SET_REPLAY_DECLINED_VEHICLE_WARP_LOCATION(<< 1826.57, 4665.27, 34.74 >>, 113.53)
// delete everything here!
DELETE_ALL_ROCKS()
DELETE_EPS(epsilonianArray[ID_MARNIE])
DELETE_EPS(epsilonianArray[ID_JIMMY])
Script_Cleanup()
ELSE
// not finished fading out
// you may want to handle dialogue etc here.
ENDIF
BREAK
ENDSWITCH
ENDPROC
// ===========================================================================================================
// DEBUG FUNCTIONS
// ===========================================================================================================
#IF IS_DEBUG_BUILD
/// PURPOSE: Check for Forced Pass or Fail
PROC DEBUG_Check_Debug_Keys()
IF g_mission.section = SECTION_RUNNING
INT iMenuSelection
// Mission is running, so reset sync-for-skip flag
g_mission.bSyncForSkip = FALSE
// Check for Pass
IF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_S))
WAIT_FOR_CUTSCENE_TO_STOP()
TRIGGER_MUSIC_EVENT("EPS4_STOP")
Script_Passed()
// Check for Fail
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_F))
WAIT_FOR_CUTSCENE_TO_STOP()
QUEUE_MISSION_STAGE(MS_FAILED)
g_mission.failReason = FAIL_REASON_DEFAULT
g_mission.section = SECTION_CLEANUP
// Check for J skip
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_J))
g_mission.bRequestJSkip = TRUE
// Check for P skip
ELIF (IS_KEYBOARD_KEY_JUST_PRESSED(KEY_P))
g_mission.bRequestPSkip = TRUE
// Check for Z skip
ELIF LAUNCH_MISSION_STAGE_MENU(zSkipMenu, iMenuSelection, iMenuSelection)
IF iMenuSelection < 7
g_mission.queueCpSkip = iMenuSelection
g_mission.bRequestCpSkip = TRUE
ELSE
IF bLockAimPitch
bLockAimPitch = FALSE
ELSE
bLockAimPitch = TRUE
ENDIF
ENDIF
ENDIF
ENDIF
ENDPROC
#ENDIF
// ===========================================================================================================
// 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()
ENDIF
IF Is_Replay_In_Progress() // Set up the initial scene for replays
OR IS_REPEAT_PLAY_ACTIVE()
g_bSceneAutoTrigger = TRUE
eInitialSceneStage = IS_REQUEST_SCENE
WHILE NOT SetupScene_EPSILON_4(sRCLauncherDataLocal)
WAIT(0)
ENDWHILE
g_bSceneAutoTrigger = FALSE
ENDIF
mScenarioBlocker = Eps4_Scenario_Blocker()
mScenarioBlockerPicnic = ADD_SCENARIO_BLOCKING_AREA_FROM_POSITION_AND_RADIUS(<<1855.08, 4755.85, 36.81>>, 25.0)
iNavBlockerBush1 = ADD_NAVMESH_BLOCKING_OBJECT(<<1815.39, 4698.00, 38.87>>, <<3.5,3.5,3>>, 0)
iNavBlockerBush2 = ADD_NAVMESH_BLOCKING_OBJECT(<<1824.12, 4701.39, 38.29>>, <<2.5, 2.5, 2.5>>, 0)
iNavBlockerBush3 = ADD_NAVMESH_BLOCKING_OBJECT(<<1801.28, 4700.25, 39.42>>, <<2,2,2>>, 0)
IF NOT IS_AUDIO_SCENE_ACTIVE("EPSILONISM_04_MIX")
DEBUG_PRINTSTRING("Starting dynamic mix EPSILONISM_04_MIX")
START_AUDIO_SCENE("EPSILONISM_04_MIX")
ENDIF
//** Mission initialisation ***************
#IF IS_DEBUG_BUILD
SETUP_EPS4_WIDGETS()
#ENDIF
REGISTER_SCRIPT_WITH_AUDIO()
SET_RELATIONSHIP_BETWEEN_GROUPS(ACQUAINTANCE_TYPE_PED_LIKE, RELGROUPHASH_PLAYER, RELGROUPHASH_PLAYER)
SET_WANTED_LEVEL_MULTIPLIER(0.5)
grassCull = SET_GRASS_CULL_SPHERE(<< 1751.65, 4676.77, 43.03 >>, 1.5)
// Disable controls and exit current vehicle
RC_PLAYER_TRIGGER_SCENE_LOCK_IN()
INIT_DATA()
INIT_MISSION_DATA()
g_mission.stage = MS_LEADIN
//-- Setup world
INIT_DETECTOR()
INT i
REPEAT iRockCount i
CREATE_ROCK(rockArray[i])
ENDREPEAT
CREATE_EPS(epsilonianArray[ID_MARNIE], vPos_Epsilonian1, fRot_Epsilonian1, sRCLauncherDataLocal.pedID[ID_MARNIE])
CREATE_EPS(epsilonianArray[ID_JIMMY], vPos_Epsilonian2, fRot_Epsilonian2, sRCLauncherDataLocal.pedID[ID_JIMMY])
//-- Z-Skips / Replay check points
IF Is_Replay_In_Progress()
IF GET_REPLAY_MID_MISSION_STAGE() = 0
START_REPLAY_SETUP(vPos_PlayerReset, fRot_PlayerReset)
QUEUE_CP_SKIP(CP_FINDROCKA)
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, FALSE)
CHANGE_MISSION_STAGE()
DEBUG_PRINTSTRING("Done replay setup")
ELSE
SCRIPT_ASSERT("Replay in progress: Unknown checkpoint selected")
ENDIF
ELIF IS_REPEAT_PLAY_ACTIVE()
START_REPLAY_SETUP(vPos_PlayerReset, fRot_PlayerReset)
QUEUE_CP_SKIP(CP_INTRO)
RC_SET_ENTITY_PROOFS_FOR_CUTSCENE(sRCLauncherDataLocal, TRUE)
CHANGE_MISSION_STAGE()
ENDIF
ADD_CONTACT_TO_PHONEBOOK(CHAR_MARNIE, MICHAEL_BOOK, FALSE)
//-- Mission loop *************************
WHILE(TRUE)
REPLAY_CHECK_FOR_EVENT_THIS_FRAME("SF_Epsilon4")
UPDATE_MISSION_NAME_DISPLAYING(sRCLauncherDataLocal.sIntroCutscene)
//DISPLAY_POLY2(g_polyPlayArea) // play area = red
//DISPLAY_POLY(g_polyFailArea, 100, 100, 255) // fail area = blue
SET_PLAYER_MAY_NOT_ENTER_ANY_VEHICLE(PLAYER_ID())
IF IS_PLAYER_IN_FIRST_PERSON_CAMERA()
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SPRINT)
ENDIF
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_SPECIAL_ABILITY)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_DUCK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_COVER)
IF IS_PED_UNINJURED(PLAYER_PED_ID())
IF GET_PEDS_CURRENT_WEAPON(PLAYER_PED_ID()) = weapon_Detector
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK)
DISABLE_CONTROL_ACTION(PLAYER_CONTROL, INPUT_ATTACK2)
ENDIF
ENDIF
SWITCH (g_mission.stage)
CASE MS_LEADIN
STAGE_LEADIN()
BREAK
CASE MS_INTRO
STAGE_INTRO()
BREAK
CASE MS_FINDROCK
STAGE_FINDROCK()
BREAK
CASE MS_ROCKSCENE
STAGE_ROCKSCENE()
BREAK
CASE MS_WAITTOPASS
STAGE_PASSWAIT()
BREAK
CASE MS_PASSED
Script_Passed()
BREAK
CASE MS_FAILED
STAGE_FailFade()
BREAK
ENDSWITCH
WAIT(0)
// 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