1117 lines
41 KiB
Python
Executable File
1117 lines
41 KiB
Python
Executable File
//╒═════════════════════════════════════════════════════════════════════════════╕
|
|
//╞══════════════════╡ Murder Mystery ╞════════════════════╡
|
|
//╘═════════════════════════════════════════════════════════════════════════════╛
|
|
|
|
//╒═════════════════════════════════════════════════════════════════════════════╕
|
|
//│ Written by Simon Bramwell Date: 13/08/14 │
|
|
//╞═════════════════════════════════════════════════════════════════════════════╡
|
|
//│ EASTER EGG. The player must find seven clues around the map in │
|
|
//│ order to unlock a black and white, film noir filter. │
|
|
//╘═════════════════════════════════════════════════════════════════════════════╛
|
|
|
|
//-------------------- INCLUDES --------------------
|
|
USING "rage_builtins.sch"
|
|
USING "globals.sch"
|
|
USING "brains.sch"
|
|
USING "ambient_globals.sch"
|
|
USING "random_events_public.sch"
|
|
USING "rc_helper_functions.sch"
|
|
USING "building_control_private.sch"
|
|
USING "noirEffects.sch"
|
|
|
|
//-------------------- ENUMS --------------------
|
|
ENUM MURDER_MYSTERY_STAGE // murder mystery clues
|
|
STAGE_CARVING_1_WEST_VINEWOOD,
|
|
STAGE_CARVING_2_ALTA,
|
|
STAGE_CARVING_3_CHINESE_THEATRE,
|
|
STAGE_CARVING_4_OBSERVATORY,
|
|
STAGE_SEA,
|
|
STAGE_LETTER,
|
|
STAGE_MINE,
|
|
STAGE_UNSET
|
|
ENDENUM
|
|
|
|
ENUM WARP_STAGE // the stages for warping into Solomon's office
|
|
WS_NOT_INSIDE,
|
|
WS_INSIDE,
|
|
WS_WARPING_IN,
|
|
WS_WARPING_OUT
|
|
ENDENUM
|
|
|
|
ENUM FLAGS
|
|
F_ARE_PC_CONTROLS_SETUP,
|
|
F_DISPLAY_HELP_WHEN_LEAVING_MINE,
|
|
F_IS_MINE_DOOR_HIDDEN,
|
|
F_RESOLVE_TRIGGER,
|
|
F_HAS_FADE_BEEN_REQUESTED,
|
|
F_HAS_TIME_BEEN_PAUSED,
|
|
F_IS_PLAYER_CONTROL_DISABLED
|
|
ENDENUM
|
|
|
|
//-------------------- CONSTS --------------------
|
|
CONST_INT DO_DELAYED_CLEANUP 1
|
|
|
|
CONST_INT NUM_STAGES STAGE_UNSET
|
|
|
|
CONST_FLOAT CLEANUP_DIST 175.0 // brain activation range is 100 units
|
|
CONST_FLOAT CARVING_ACTIVATE_DIST 5.0
|
|
CONST_FLOAT SEA_ACTIVATE_DIST 5.0
|
|
CONST_FLOAT MINE_ACTIVATE_DIST 2.0
|
|
|
|
FLOAT CLEANUP_DIST2 = CLEANUP_DIST * CLEANUP_DIST
|
|
FLOAT CARVING_ACTIVATE_DIST2 = CARVING_ACTIVATE_DIST * CARVING_ACTIVATE_DIST
|
|
FLOAT SEA_ACTIVATE_DIST2 = SEA_ACTIVATE_DIST * SEA_ACTIVATE_DIST
|
|
FLOAT MINE_ACTIVATE_DIST2 = MINE_ACTIVATE_DIST * MINE_ACTIVATE_DIST
|
|
|
|
CONST_FLOAT HIDE_RADIUS 200.0
|
|
|
|
//-------------------- VECTORS AND HEADINGS --------------------
|
|
VECTOR vExtOfficeWarpPos = <<-1011.7365, -480.2540, 39.0734>>
|
|
VECTOR vIntOfficeWarpPos = <<-1003.0779, -477.9620, 49.1374>>
|
|
|
|
VECTOR vExtOfficePlayerPos = <<-1018.3756, -483.9436, 36.0964>>
|
|
FLOAT fExtOfficePlayerHeading = 114.7664
|
|
VECTOR vIntOfficePlayerPos = <<-1005.1911, -478.2104, 49.0262>>
|
|
FLOAT fIntOfficePlayerHeading = 80.6659
|
|
|
|
VECTOR vOnFootLocate = <<1.0, 1.0, LOCATE_SIZE_HEIGHT>>
|
|
VECTOR vMineDoorPos = <<-596.05000, 2088.5600, 130.590>>
|
|
|
|
//-------------------- MISC VARS --------------------
|
|
INTERIOR_INSTANCE_INDEX intOffice
|
|
WARP_STAGE eOfficeWarpStage = WS_NOT_INSIDE
|
|
INT iUpdateLetterCamStage = 0
|
|
CAMERA_INDEX camLetter
|
|
INT iDoor
|
|
PED_INDEX pedDeadBodyMine
|
|
OBJECT_INDEX objFilmCan
|
|
PED_INDEX pedDeadBodySea
|
|
STRING sNoirFoundClue = "FOUND_CLUE"
|
|
STRING sNoirSetName = "NOIR_FILTER_SOUNDS"
|
|
INT iNoirSFXSoundID
|
|
VECTOR vPlayerPos
|
|
MURDER_MYSTERY_STAGE eTriggerStage = STAGE_UNSET
|
|
INT iTimer
|
|
INT iTrackedPoint = 0
|
|
STRING sDeadBodySeaAnimDict = "missmurder"
|
|
STRING sDeadBodySeaAnim = "idle"
|
|
STRING sHelpTextReadLetter = "MM_LETREAD"
|
|
STRING sHelpTextStopReadLetter = "MM_LETCANC"
|
|
INT iFlags = 0
|
|
|
|
//-------------------- DEBUG VARS --------------------
|
|
#IF IS_DEBUG_BUILD
|
|
|
|
CONST_INT TOTAL_FLAGS COUNT_OF( FLAGS )
|
|
|
|
// Main
|
|
WIDGET_GROUP_ID widMain
|
|
TEXT_WIDGET_ID twidTriggerStage
|
|
TEXT_WIDGET_ID twidUnlockStage
|
|
BOOL bBlockCleanup
|
|
BOOL bDelayedCleanup = FALSE
|
|
INT iDelayTime
|
|
BOOL bToggleBlips
|
|
BLIP_INDEX blpUnlocks[ NUM_STAGES ]
|
|
BOOL bTerminate
|
|
BOOL bCycleFilter
|
|
BOOL bAddNoirPhoneContact
|
|
BOOL bIsPlayerInMine
|
|
|
|
// Clues
|
|
INT iUnlockStage = 0
|
|
INT iOldUnlockStage = -1
|
|
BOOL bIsUnlocked
|
|
BOOL bSetUnlocked
|
|
BOOL bSetNotUnlocked
|
|
|
|
// Flags
|
|
BOOL bFlags[ TOTAL_FLAGS ]
|
|
|
|
#ENDIF
|
|
//-------------------- FLAGS PROCS --------------------
|
|
PROC SET_FLAG( FLAGS flag, BOOL bEnable )
|
|
IF( bEnable )
|
|
SET_BIT( iFlags, ENUM_TO_INT( flag ) )
|
|
ELSE
|
|
CLEAR_BIT( iFlags, ENUM_TO_INT( flag ) )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_FLAG_SET( FLAGS flag )
|
|
RETURN IS_BIT_SET( iFlags, ENUM_TO_INT( flag ) )
|
|
ENDFUNC
|
|
|
|
//-------------------- PC CONTROL PROCS --------------------
|
|
PROC SETUP_PC_CONTROLS()
|
|
IF( IS_PC_VERSION() )
|
|
IF( NOT IS_FLAG_SET( F_ARE_PC_CONTROLS_SETUP ) )
|
|
INIT_PC_SCRIPTED_CONTROLS( "MYSTERY LETTER CAM" )
|
|
SET_FLAG( F_ARE_PC_CONTROLS_SETUP, TRUE )
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC CLEANUP_PC_CONTROLS()
|
|
IF( IS_PC_VERSION() )
|
|
IF( IS_FLAG_SET( F_ARE_PC_CONTROLS_SETUP ) )
|
|
SHUTDOWN_PC_SCRIPTED_CONTROLS()
|
|
SET_FLAG( F_ARE_PC_CONTROLS_SETUP, FALSE )
|
|
ENDIF
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
//-------------------- CLEANUP PROCS --------------------
|
|
PROC CLEANUP_TRIGGER_STAGE()
|
|
SWITCH( eTriggerStage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD
|
|
CASE STAGE_CARVING_2_ALTA
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE
|
|
CASE STAGE_CARVING_4_OBSERVATORY
|
|
DESTROY_TRACKED_POINT( iTrackedPoint )
|
|
iTrackedPoint = 0
|
|
BREAK
|
|
CASE STAGE_SEA
|
|
IF( DOES_ENTITY_EXIST( pedDeadBodySea ) )
|
|
SET_PED_AS_NO_LONGER_NEEDED( pedDeadBodySea )
|
|
ENDIF
|
|
REMOVE_ANIM_DICT( sDeadBodySeaAnimDict )
|
|
BREAK
|
|
CASE STAGE_LETTER
|
|
IF( IS_DOOR_REGISTERED_WITH_SYSTEM( iDoor ) )
|
|
REMOVE_DOOR_FROM_SYSTEM( iDoor )
|
|
ENDIF
|
|
IF( DOES_CAM_EXIST( camLetter ) )
|
|
DESTROY_CAM( camLetter )
|
|
ENDIF
|
|
IF( IS_FLAG_SET( F_HAS_FADE_BEEN_REQUESTED ) )
|
|
DO_SCREEN_FADE_IN( 0 )
|
|
ENDIF
|
|
IF( IS_FLAG_SET( F_HAS_TIME_BEEN_PAUSED ) )
|
|
PAUSE_CLOCK( FALSE )
|
|
ENDIF
|
|
IF( IS_FLAG_SET( F_IS_PLAYER_CONTROL_DISABLED ) )
|
|
SET_PLAYER_CONTROL( PLAYER_ID(), TRUE )
|
|
ENDIF
|
|
IF( IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( sHelpTextReadLetter )
|
|
OR IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( sHelpTextStopReadLetter ) )
|
|
CLEAR_HELP()
|
|
ENDIF
|
|
BREAK
|
|
CASE STAGE_MINE
|
|
IF( DOES_ENTITY_EXIST( pedDeadBodyMine ) )
|
|
SET_PED_AS_NO_LONGER_NEEDED( pedDeadBodyMine )
|
|
ENDIF
|
|
IF( DOES_ENTITY_EXIST( objFilmCan ) )
|
|
SET_OBJECT_AS_NO_LONGER_NEEDED( objFilmCan )
|
|
ENDIF
|
|
// Make sure the mine door reappears
|
|
IF( IS_FLAG_SET( F_IS_MINE_DOOR_HIDDEN ) )
|
|
REMOVE_MODEL_HIDE( vMineDoorPos, HIDE_RADIUS, PROP_MINESHAFT_DOOR, FALSE )
|
|
CPRINTLN( DEBUG_SIMON, "Unhiding mine door model" )
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
PROC SCRIPT_CLEANUP()
|
|
CPRINTLN( DEBUG_SIMON, "Cleaning up murderMystery.sc" )
|
|
|
|
CLEANUP_TRIGGER_STAGE()
|
|
CLEANUP_PC_CONTROLS()
|
|
|
|
TERMINATE_THIS_THREAD()
|
|
ENDPROC
|
|
|
|
//-------------------- UNLOCK PROCS --------------------
|
|
#IF IS_DEBUG_BUILD
|
|
|
|
FUNC STRING DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( MURDER_MYSTERY_STAGE stage )
|
|
SWITCH( stage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD RETURN "STAGE_CARVING_1_WEST_VINEWOOD" BREAK
|
|
CASE STAGE_CARVING_2_ALTA RETURN "STAGE_CARVING_2_ALTA" BREAK
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE RETURN "STAGE_CARVING_3_CHINESE_THEATRE" BREAK
|
|
CASE STAGE_CARVING_4_OBSERVATORY RETURN "STAGE_CARVING_4_OBSERVATORY" BREAK
|
|
CASE STAGE_SEA RETURN "STAGE_SEA" BREAK
|
|
CASE STAGE_LETTER RETURN "STAGE_LETTER" BREAK
|
|
CASE STAGE_MINE RETURN "STAGE_MINE" BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN "UNKNOWN"
|
|
ENDFUNC
|
|
|
|
#ENDIF
|
|
|
|
FUNC BOOL IS_STAGE_UNLOCKED( MURDER_MYSTERY_STAGE stage )
|
|
RETURN IS_BIT_SET( g_savedGlobals.sAmbient.iMurderMysteryFlags, ENUM_TO_INT( stage ) )
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Unlock/lock a stage, also play sfx and save
|
|
PROC SET_STAGE_UNLOCKED( MURDER_MYSTERY_STAGE stage, BOOL bUnlocked = TRUE, BOOL bSuppressSound = FALSE )
|
|
IF( bUnlocked )
|
|
SET_BIT( g_savedGlobals.sAmbient.iMurderMysteryFlags, ENUM_TO_INT( stage ) )
|
|
IF( NOT bSuppressSound )
|
|
PLAY_SOUND_FRONTEND( iNoirSFXSoundID, sNoirFoundClue, sNoirSetName, FALSE )
|
|
ENDIF
|
|
MAKE_AUTOSAVE_REQUEST()
|
|
CPRINTLN( DEBUG_SIMON, "Unlocking ", DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( stage ) )
|
|
ELSE
|
|
CLEAR_BIT( g_savedGlobals.sAmbient.iMurderMysteryFlags, ENUM_TO_INT( stage ) )
|
|
CPRINTLN( DEBUG_SIMON, "Locking ", DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( stage ) )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
FUNC INT IPOW( INT base, INT exponent )
|
|
IF( exponent = 0 )
|
|
RETURN 1
|
|
ELSE
|
|
RETURN base * IPOW( base, exponent - 1 )
|
|
ENDIF
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Are all the stages before the given stage unlocked
|
|
FUNC BOOL ARE_ALL_STAGES_PRECEDING_UNLOCKED( MURDER_MYSTERY_STAGE stage )
|
|
INT iStage = ENUM_TO_INT( stage )
|
|
IF( iStage = 0 )
|
|
RETURN TRUE
|
|
ELSE
|
|
INT iSelection = GET_BITS_IN_RANGE( g_savedGlobals.sAmbient.iMurderMysteryFlags, 0, iStage - 1 )
|
|
RETURN iSelection = IPOW( 2, iStage ) - 1
|
|
ENDIF
|
|
ENDFUNC
|
|
|
|
FUNC BOOL ARE_ALL_STAGES_UNLOCKED()
|
|
RETURN g_savedGlobals.sAmbient.iMurderMysteryFlags = 127
|
|
ENDFUNC
|
|
|
|
//-------------------- STAGE DATA PROCS --------------------
|
|
//PURPOSE: Gets the centre of the stage trigger area, should match the values in //depot/gta5/build/dev_ng/common/data/levels/gta5/ambient.ipl
|
|
FUNC VECTOR GET_WORLD_POINT_COORD_FOR_STAGE( MURDER_MYSTERY_STAGE stage )
|
|
SWITCH( stage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD RETURN <<1.8941, 309.6565, 111.0097>> BREAK
|
|
CASE STAGE_CARVING_2_ALTA RETURN <<190.1696, -431.7692, 42.1372>> BREAK
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE RETURN <<283.3024, 212.6587, 104.5986>> BREAK
|
|
CASE STAGE_CARVING_4_OBSERVATORY RETURN <<-425.1273, 1064.8011, 323.8097>> BREAK
|
|
CASE STAGE_SEA RETURN <<-3174.901, 3034.061, -35.645>> BREAK // not accurate to values in ipl
|
|
CASE STAGE_LETTER RETURN <<-1008.69, -476.4341, 49.9544>> BREAK
|
|
CASE STAGE_MINE RETURN <<-544.11, 1986.58, 127.03>> BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN <<0.0, 0.0, 0.0>>
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Gets the unlock position for the stage
|
|
FUNC VECTOR GET_UNLOCK_COORD_FOR_STAGE( MURDER_MYSTERY_STAGE stage )
|
|
SWITCH( stage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD RETURN <<1.8941, 309.6565, 111.0097>> BREAK
|
|
CASE STAGE_CARVING_2_ALTA RETURN <<190.1696, -431.7692, 42.1372>> BREAK
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE RETURN <<283.3024, 212.6587, 104.5986>> BREAK
|
|
CASE STAGE_CARVING_4_OBSERVATORY RETURN <<-425.1273, 1064.8011, 323.8097>> BREAK
|
|
CASE STAGE_SEA RETURN <<-3160.9604, 3005.6284, -39.9701>> BREAK
|
|
CASE STAGE_LETTER RETURN <<-1008.1416, -476.2818, 49.9633>> BREAK
|
|
CASE STAGE_MINE RETURN <<-544.11, 1986.58, 127.03>> BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN <<0.0, 0.0, 0.0>>
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Gets the range at which the stage should unlock from the position in GET_UNLOCK_COORD_FOR_STAGE
|
|
FUNC FLOAT GET_UNLOCK_DIST2_FOR_STAGE( MURDER_MYSTERY_STAGE stage )
|
|
SWITCH( stage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD RETURN CARVING_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_CARVING_2_ALTA RETURN CARVING_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE RETURN CARVING_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_CARVING_4_OBSERVATORY RETURN CARVING_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_SEA RETURN SEA_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_LETTER RETURN MINE_ACTIVATE_DIST2 BREAK
|
|
CASE STAGE_MINE RETURN 4.0 BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN 0.0
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Gets the range at which the stage should cleanup from the position in GET_WORLD_POINT_COORD_FOR_STAGE
|
|
FUNC FLOAT GET_ACTIVE_DIST2_FOR_STAGE( MURDER_MYSTERY_STAGE stage )
|
|
SWITCH( stage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_CARVING_2_ALTA RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_CARVING_4_OBSERVATORY RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_SEA RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_LETTER RETURN CLEANUP_DIST2 BREAK
|
|
CASE STAGE_MINE RETURN CLEANUP_DIST2 BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN 0.0
|
|
ENDFUNC
|
|
|
|
FUNC BOOL VECTOR_COMPARE( VECTOR a, VECTOR b, FLOAT fTolerance = 0.5 )
|
|
RETURN VDIST( a, b ) <= fTolerance
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Is the player inside the unlock range of the stage
|
|
FUNC BOOL IS_TRIGGER_STAGE_IN_UNLOCK_RANGE()
|
|
RETURN VDIST2( GET_UNLOCK_COORD_FOR_STAGE( eTriggerStage ), vPlayerPos ) < GET_UNLOCK_DIST2_FOR_STAGE( eTriggerStage )
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Is the player inside the active range of the stage
|
|
FUNC BOOL IS_TRIGGER_STAGE_IN_ACTIVE_RANGE()
|
|
RETURN VDIST2( GET_WORLD_POINT_COORD_FOR_STAGE( eTriggerStage ), vPlayerPos ) < GET_ACTIVE_DIST2_FOR_STAGE( eTriggerStage )
|
|
ENDFUNC
|
|
|
|
FUNC BOOL SAFE_IS_PLAYER_IN_ANY_VEHICLE()
|
|
IF( IS_ENTITY_ALIVE( PLAYER_PED_ID() ) )
|
|
RETURN IS_PED_IN_ANY_VEHICLE( PLAYER_PED_ID() )
|
|
ENDIF
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
PROC DO_WARP_FADE( BOOL bFadeIn, INT iFadeTime = DEFAULT_FADE_TIME )
|
|
SET_FLAG( F_HAS_FADE_BEEN_REQUESTED, NOT bFadeIn )
|
|
IF( bFadeIn )
|
|
DO_SCREEN_FADE_IN( iFadeTime )
|
|
ELSE
|
|
DO_SCREEN_FADE_OUT( iFadeTime )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC HALT_TIME( BOOL bHalt )
|
|
SET_FLAG( F_HAS_TIME_BEEN_PAUSED, bHalt )
|
|
PAUSE_CLOCK( bHalt )
|
|
ENDPROC
|
|
|
|
PROC ENABLE_PLAYER_CONTROL( BOOL bEnable )
|
|
SET_FLAG( F_IS_PLAYER_CONTROL_DISABLED, NOT bEnable )
|
|
SET_PLAYER_CONTROL( PLAYER_ID(), bEnable )
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_PLAYER_MICHAEL()
|
|
RETURN GET_ENTITY_MODEL( PLAYER_PED_ID() ) = PLAYER_ZERO
|
|
ENDFUNC
|
|
|
|
//-------------------- ASSET LOAD PROCS --------------------
|
|
//PURPOSE: Load a model with waits
|
|
PROC SCRIPT_LOAD_MODEL( MODEL_NAMES model )
|
|
REQUEST_MODEL( model )
|
|
#IF IS_DEBUG_BUILD
|
|
iTimer = GET_GAME_TIMER() + 8000
|
|
#ENDIF
|
|
WHILE( NOT HAS_MODEL_LOADED( model )
|
|
#IF IS_DEBUG_BUILD AND iTimer >= GET_GAME_TIMER() #ENDIF )
|
|
WAIT( 0 )
|
|
ENDWHILE
|
|
#IF IS_DEBUG_BUILD
|
|
IF( iTimer < GET_GAME_TIMER() )
|
|
ASSERTLN( "SCRIPT_LOAD_MODEL model took longer than 8s to load!" )
|
|
ENDIF
|
|
#ENDIF
|
|
ENDPROC
|
|
|
|
//PURPOSE: Load an anim with waits
|
|
PROC SCRIPT_LOAD_ANIM( STRING sAnimDict )
|
|
REQUEST_ANIM_DICT( sAnimDict )
|
|
#IF IS_DEBUG_BUILD
|
|
iTimer = GET_GAME_TIMER() + 8000
|
|
#ENDIF
|
|
WHILE( NOT HAS_ANIM_DICT_LOADED( sAnimDict )
|
|
#IF IS_DEBUG_BUILD AND iTimer >= GET_GAME_TIMER() #ENDIF )
|
|
WAIT( 0 )
|
|
ENDWHILE
|
|
#IF IS_DEBUG_BUILD
|
|
IF( iTimer < GET_GAME_TIMER() )
|
|
ASSERTLN( "SCRIPT_LOAD_ANIM anim:", sAnimDict, " took longer than 8s to load!" )
|
|
ENDIF
|
|
#ENDIF
|
|
ENDPROC
|
|
|
|
//-------------------- DEBUG --------------------
|
|
#IF IS_DEBUG_BUILD
|
|
|
|
FUNC STRING DEBUG_GET_FLAG_AS_STRING( FLAGS flag )
|
|
SWITCH( flag )
|
|
CASE F_ARE_PC_CONTROLS_SETUP RETURN "F_ARE_PC_CONTROLS_SETUP" BREAK
|
|
CASE F_DISPLAY_HELP_WHEN_LEAVING_MINE RETURN "F_DISPLAY_HELP_WHEN_LEAVING_MINE" BREAK
|
|
CASE F_IS_MINE_DOOR_HIDDEN RETURN "F_IS_MINE_DOOR_HIDDEN" BREAK
|
|
CASE F_RESOLVE_TRIGGER RETURN "F_RESOLVE_TRIGGER" BREAK
|
|
CASE F_HAS_FADE_BEEN_REQUESTED RETURN "F_HAS_FADE_BEEN_REQUESTED" BREAK
|
|
CASE F_HAS_TIME_BEEN_PAUSED RETURN "F_HAS_TIME_BEEN_PAUSED" BREAK
|
|
CASE F_IS_PLAYER_CONTROL_DISABLED RETURN "F_IS_PLAYER_CONTROL_DISABLED" BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN "UNKNOWN"
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Init the vars for a delayed cleanup
|
|
PROC DEBUG_CLEANUP_WITH_DELAY( INT iDelay = 10000 )
|
|
IF( NOT bDelayedCleanup )
|
|
bDelayedCleanup = TRUE
|
|
iDelayTime = GET_GAME_TIMER() + iDelay
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
//PURPOSE: Prints the unlock states of all the stages
|
|
PROC DEBUG_PRINT_UNLOCK_STATE()
|
|
INT i
|
|
STRING sStage, sUnlock
|
|
|
|
CPRINTLN( DEBUG_SIMON, "Unlock status" )
|
|
REPEAT NUM_STAGES i
|
|
MURDER_MYSTERY_STAGE stage = INT_TO_ENUM( MURDER_MYSTERY_STAGE, i )
|
|
sStage = DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( stage )
|
|
IF( IS_STAGE_UNLOCKED( stage ) )
|
|
sUnlock = "unlocked"
|
|
ELSE
|
|
sUnlock = "locked"
|
|
ENDIF
|
|
CPRINTLN( DEBUG_SIMON, " ", sStage, " is ", sUnlock )
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
//PURPOSE: Blips/unblips the clue positions
|
|
PROC DEBUG_TOGGLE_BLIPS( BOOL bEnable )
|
|
INT i
|
|
IF( bEnable )
|
|
REPEAT NUM_STAGES i
|
|
MURDER_MYSTERY_STAGE stage = INT_TO_ENUM( MURDER_MYSTERY_STAGE, i )
|
|
IF( NOT DOES_BLIP_EXIST( blpUnlocks[ i ] ) )
|
|
blpUnlocks[ i ] = CREATE_BLIP_FOR_COORD( GET_UNLOCK_COORD_FOR_STAGE( stage ) )
|
|
ENDIF
|
|
|
|
IF( IS_STAGE_UNLOCKED( stage ) )
|
|
SET_BLIP_COLOUR( blpUnlocks[ i ], BLIP_COLOUR_GREEN )
|
|
ELSE
|
|
SET_BLIP_COLOUR( blpUnlocks[ i ], BLIP_COLOUR_RED )
|
|
ENDIF
|
|
ENDREPEAT
|
|
ELSE
|
|
REPEAT NUM_STAGES i
|
|
IF( DOES_BLIP_EXIST( blpUnlocks[ i ] ) )
|
|
REMOVE_BLIP( blpUnlocks[ i ] )
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
PROC DEBUG_SCRIPT_INIT()
|
|
CPRINTLN( DEBUG_SIMON, "Trigger stage is ", DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( eTriggerStage ) )
|
|
DEBUG_PRINT_UNLOCK_STATE()
|
|
|
|
// Widget
|
|
IF( NOT DOES_WIDGET_GROUP_EXIST( widMain ) )
|
|
widMain = START_WIDGET_GROUP( "Murder Mystery" )
|
|
twidTriggerStage = ADD_TEXT_WIDGET( "Trigger stage" )
|
|
ADD_WIDGET_BOOL( "Block script clean up", bBlockCleanup )
|
|
ADD_WIDGET_BOOL( "Is script cleaning up", bDelayedCleanup )
|
|
ADD_WIDGET_BOOL( "Terminate", bTerminate )
|
|
ADD_WIDGET_BOOL( "Toggle blips", bToggleBlips )
|
|
ADD_WIDGET_BOOL( "Toggle filter", bCycleFilter )
|
|
ADD_WIDGET_BOOL( "Add Noir phone contact to all phonebooks", bAddNoirPhoneContact )
|
|
ADD_WIDGET_BOOL( "Is player in mine", bIsPlayerInMine )
|
|
STOP_WIDGET_GROUP()
|
|
|
|
SET_CURRENT_WIDGET_GROUP( widMain )
|
|
START_WIDGET_GROUP( "Clues" )
|
|
twidUnlockStage = ADD_TEXT_WIDGET( "Selected stage" )
|
|
ADD_WIDGET_INT_SLIDER( "Select unlock", iUnlockStage, 0, NUM_STAGES - 1, 1 )
|
|
ADD_WIDGET_BOOL( "Is unlocked", bIsUnlocked )
|
|
ADD_WIDGET_BOOL( "Set unlocked", bSetUnlocked )
|
|
ADD_WIDGET_BOOL( "Set locked", bSetNotUnlocked )
|
|
STOP_WIDGET_GROUP()
|
|
CLEAR_CURRENT_WIDGET_GROUP( widMain )
|
|
|
|
SET_CURRENT_WIDGET_GROUP( widMain )
|
|
START_WIDGET_GROUP( "Flags" )
|
|
INT i
|
|
REPEAT TOTAL_FLAGS i
|
|
ADD_WIDGET_BOOL( DEBUG_GET_FLAG_AS_STRING( INT_TO_ENUM( FLAGS, i ) ), bFlags[ i ] )
|
|
ENDREPEAT
|
|
STOP_WIDGET_GROUP()
|
|
CLEAR_CURRENT_WIDGET_GROUP( widMain )
|
|
ENDIF
|
|
|
|
// Set the trigger stage
|
|
SET_CONTENTS_OF_TEXT_WIDGET( twidTriggerStage, DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( eTriggerStage ) )
|
|
iUnlockStage = ENUM_TO_INT( eTriggerStage )
|
|
ENDPROC
|
|
|
|
PROC DEBUG_UPDATE()
|
|
// Widget update
|
|
MURDER_MYSTERY_STAGE stage = INT_TO_ENUM( MURDER_MYSTERY_STAGE, iUnlockStage )
|
|
bIsUnlocked = IS_STAGE_UNLOCKED( stage )
|
|
IF( iUnlockStage <> iOldUnlockStage ) // update the text displayed to the current selected stage
|
|
iOldUnlockStage = iUnlockStage
|
|
SET_CONTENTS_OF_TEXT_WIDGET( twidUnlockStage, DEBUG_GET_MURDER_MYSTERY_STAGE_AS_STRING( stage ) )
|
|
ENDIF
|
|
IF( bSetUnlocked ) // unlock the current selected stage
|
|
SET_STAGE_UNLOCKED( stage, TRUE )
|
|
iOldUnlockStage = -1
|
|
bSetUnlocked = FALSE
|
|
ENDIF
|
|
IF( bSetNotUnlocked ) // set the current selected stage locked
|
|
SET_STAGE_UNLOCKED( stage, FALSE )
|
|
iOldUnlockStage = -1
|
|
bSetNotUnlocked = FALSE
|
|
ENDIF
|
|
DEBUG_TOGGLE_BLIPS( bToggleBlips )
|
|
IF( bTerminate ) // terminate the script
|
|
SCRIPT_CLEANUP()
|
|
ENDIF
|
|
IF( bDelayedCleanup AND NOT bBlockCleanup ) // update the delayed cleanup of the script
|
|
IF( iDelayTime < GET_GAME_TIMER() )
|
|
SCRIPT_CLEANUP()
|
|
ENDIF
|
|
ENDIF
|
|
IF( bCycleFilter ) // cycle through the noir filters
|
|
NOIR_TOGGLE_EFFECTS()
|
|
bCycleFilter = FALSE
|
|
ENDIF
|
|
IF( bAddNoirPhoneContact ) // add Isaac to all the player character phone books
|
|
ADD_CONTACT_TO_PHONEBOOK( CHAR_ISAAC, ALL_OWNERS_BOOKS, TRUE )
|
|
bAddNoirPhoneContact = FALSE
|
|
ENDIF
|
|
IF( IS_ENTITY_ALIVE( PLAYER_PED_ID() ) )
|
|
bIsPlayerInMine = IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-415.436462, 2068.288574, 113.300171>>,
|
|
<<-564.951599, 1884.702515, 134.040344>>, 258.750000 )
|
|
OR IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-596.470581, 2089.920898, 125.412750>>,
|
|
<<-581.213440, 2036.256104, 136.283630>>, 9.500000 )
|
|
ENDIF
|
|
INT i // flags
|
|
REPEAT TOTAL_FLAGS i
|
|
bFlags[ i ] = IS_FLAG_SET( INT_TO_ENUM( FLAGS, i ) )
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
#ENDIF
|
|
|
|
//-------------------- MISC PROCS --------------------
|
|
PROC SET_ENTITY_COORD_AND_HEADING( ENTITY_INDEX entity, VECTOR vPos, FLOAT fHeading )
|
|
SET_ENTITY_COORDS( entity, vPos )
|
|
SET_ENTITY_HEADING( entity, fHeading )
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_PED_PERFORMING_TASK( PED_INDEX ped, SCRIPT_TASK_NAME scriptTask )
|
|
SCRIPTTASKSTATUS status = GET_SCRIPT_TASK_STATUS( ped, scriptTask )
|
|
RETURN status = PERFORMING_TASK OR status = WAITING_TO_START_TASK
|
|
ENDFUNC
|
|
|
|
FUNC BOOL IS_COORD_ON_SCREEN( VECTOR vec )
|
|
FLOAT fx, fy
|
|
RETURN GET_SCREEN_COORD_FROM_WORLD_COORD( vec, fx, fy )
|
|
ENDFUNC
|
|
|
|
PROC CREATE_TRACKED_POINT_WITH_INFO( INT &iTracked, VECTOR vPos, FLOAT fRadius )
|
|
iTracked = CREATE_TRACKED_POINT()
|
|
IF( iTracked = 0 )
|
|
ASSERTLN( "CREATE_TRACKED_POINT_WITH_INFO can't get free index from CREATE_TRACKED_POINT!" )
|
|
ELSE
|
|
SET_TRACKED_POINT_INFO( iTracked, vPos, fRadius )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
//-------------------- WARP PROCS --------------------
|
|
//PURPOSE: Checks to see if it's safe to allow the player to warp into Solomon's office interior
|
|
FUNC BOOL SHOULD_ALLOW_OFFICE_WARP()
|
|
// if player is in the office always allow warp
|
|
IF( eOfficeWarpStage = WS_INSIDE )
|
|
RETURN TRUE
|
|
ENDIF
|
|
// if the current player character isn't michael
|
|
IF( NOT IS_PLAYER_MICHAEL() )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if the solomon strand isn't complete then don't allow warp
|
|
IF( NOT GET_MISSION_COMPLETE_STATE( SP_MISSION_SOLOMON_3 ) )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if the player has a wanted level then don't allow warp
|
|
IF( GET_PLAYER_WANTED_LEVEL( PLAYER_ID() ) > 0 AND eOfficeWarpStage = WS_NOT_INSIDE ) // rob - only disabling warp on wanted if outside
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if repeat play is active then don't allow warp
|
|
IF( IS_REPEAT_PLAY_ACTIVE() )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if the player is with a prostitute then don't allow warp
|
|
IF( IS_PLAYER_WITH_A_PROSTITUTE() )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if there's a high priority phone call pending then don't allow warp
|
|
IF( IS_PLAYER_PED_PLAYABLE( GET_CURRENT_PLAYER_PED_ENUM() ) )
|
|
IF( GET_PLAYER_CHAR_COMMUNICATION_PRIORITY_LEVEL( GET_CURRENT_PLAYER_PED_ENUM() ) = CPR_HIGH
|
|
OR GET_PLAYER_CHAR_COMMUNICATION_PRIORITY_LEVEL( GET_CURRENT_PLAYER_PED_ENUM() ) = CPR_VERY_HIGH )
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDIF
|
|
// if the player is currently doing a random event then don't allow warp
|
|
IF( GET_RANDOM_EVENT_FLAG() )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// if player is interacting with Chop then don't allow warp
|
|
IF( g_bPlayerInteractingWithChop )
|
|
RETURN FALSE
|
|
ENDIF
|
|
// otherwise it's ok to warp
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Handles the camera letter logic
|
|
PROC UPDATE_LETTER_CAMERA()
|
|
VECTOR vVecCoors1 = <<-1007.013000,-478.366241,49.028175>>
|
|
VECTOR vVecCoors2 = <<-1007.850037,-476.957275,51.028072>>
|
|
FLOAT fWidth = 1.750000
|
|
|
|
SWITCH( iUpdateLetterCamStage )
|
|
CASE 0 // show help text when close to the desk "Press ~INPUT_SCRIPT_PAD_RIGHT~ to read the letter."
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), vVecCoors1, vVecCoors2, fWidth )
|
|
AND NOT IS_PHONE_ONSCREEN() )
|
|
PRINT_HELP_FOREVER( sHelpTextReadLetter )
|
|
iUpdateLetterCamStage++
|
|
ENDIF
|
|
BREAK
|
|
CASE 1 // if player is close to the desk handle player interaction
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), vVecCoors1, vVecCoors2, fWidth )
|
|
AND NOT IS_PHONE_ONSCREEN() )
|
|
IF( NOT IS_PED_PERFORMING_TASK( PLAYER_PED_ID(), SCRIPT_TASK_LOOK_AT_COORD ) )
|
|
TASK_LOOK_AT_COORD( PLAYER_PED_ID(), <<-1007.9945, -476.8016, 49.9117>>, -1 )
|
|
ENDIF
|
|
|
|
// if the player has pressed the interact button
|
|
IF( IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_CONTEXT ) )
|
|
// player walks close to letter and camera cuts
|
|
ENABLE_PLAYER_CONTROL( FALSE )
|
|
TASK_FOLLOW_NAV_MESH_TO_COORD( PLAYER_PED_ID(), <<-1007.3514, -477.5197, 49.0282>>, PEDMOVEBLENDRATIO_WALK,
|
|
DEFAULT_TIME_NEVER_WARP, DEFAULT_SEEK_RADIUS, ENAV_DEFAULT, 30.4025 )
|
|
PRINT_HELP_FOREVER( sHelpTextStopReadLetter )
|
|
DISPLAY_RADAR( FALSE )
|
|
SET_CAM_ACTIVE( camLetter, TRUE )
|
|
RENDER_SCRIPT_CAMS( TRUE, FALSE )
|
|
iUpdateLetterCamStage++
|
|
ENDIF
|
|
ELSE // clear help if the player moved away from the desk
|
|
CLEAR_HELP()
|
|
CLEAR_PED_TASKS( PLAYER_PED_ID() )
|
|
iUpdateLetterCamStage--
|
|
ENDIF
|
|
BREAK
|
|
CASE 2 // when the player quits the letter cam reset the gameplay cam and tasks etc.
|
|
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
|
|
ENABLE_PLAYER_CONTROL( FALSE )
|
|
DISPLAY_RADAR( FALSE )
|
|
IF( NOT IS_THIS_HELP_MESSAGE_BEING_DISPLAYED( sHelpTextStopReadLetter ) )
|
|
PRINT_HELP_FOREVER( sHelpTextStopReadLetter )
|
|
ENDIF
|
|
|
|
IF( IS_CONTROL_JUST_PRESSED( FRONTEND_CONTROL, INPUT_CONTEXT ) )
|
|
IF( GET_CAM_VIEW_MODE_FOR_CONTEXT( CAM_VIEW_MODE_CONTEXT_ON_FOOT ) = CAM_VIEW_MODE_FIRST_PERSON ) // if first person on foot
|
|
iTimer = GET_GAME_TIMER() + 300 // first person cut requires 300 m/s lead in
|
|
ANIMPOSTFX_PLAY( "CamPushInNeutral", 0, FALSE ) // flash
|
|
PLAY_SOUND_FRONTEND( -1, "1st_Person_Transition", "PLAYER_SWITCH_CUSTOM_SOUNDSET", FALSE )
|
|
ELSE
|
|
iTimer = 0
|
|
ENDIF
|
|
iUpdateLetterCamStage++
|
|
ENDIF
|
|
BREAK
|
|
CASE 3
|
|
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
|
|
IF( iTimer < GET_GAME_TIMER() )
|
|
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
|
|
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
|
|
DISPLAY_RADAR( TRUE )
|
|
ENABLE_PLAYER_CONTROL( TRUE )
|
|
CLEAR_PED_TASKS( PLAYER_PED_ID() )
|
|
RENDER_SCRIPT_CAMS( FALSE, FALSE )
|
|
SET_CAM_ACTIVE( camLetter, FALSE )
|
|
iUpdateLetterCamStage++
|
|
ENDIF
|
|
BREAK
|
|
CASE 4
|
|
iUpdateLetterCamStage = 0
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
FUNC BOOL IS_CORRECT_TOD()
|
|
INT iHour = GET_CLOCK_HOURS()
|
|
IF( iHour >= 21 OR iHour < 6 )
|
|
RETURN TRUE
|
|
ELSE
|
|
PRINT_HELP( "MM_SOLBUSY", 5000 )
|
|
RETURN FALSE
|
|
ENDIF
|
|
ENDFUNC
|
|
|
|
//PURPOSE: Handles the warp logic when entering/exiting Solomon's office interior
|
|
PROC UPDATE_SOLOMON_OFFICE_WARP()
|
|
SWITCH( eOfficeWarpStage )
|
|
CASE WS_NOT_INSIDE // waiting for player to touch the warp in locate
|
|
IF( NOT GET_MISSION_FLAG() ) // we check this here and not in ALLOW_SOLOMON_OFFICE_WARP because the player might start
|
|
// a mission in the office (via the phone), which would lock them inside (n.b. not checked for WS_INSIDE)
|
|
IF( IS_ENTITY_AT_COORD( PLAYER_PED_ID(), vExtOfficeWarpPos, vOnFootLocate, TRUE ) )
|
|
IF( IS_CORRECT_TOD() ) // check if the time at which the player touches the locate is late enough
|
|
eOfficeWarpStage = WS_WARPING_IN
|
|
DO_WARP_FADE( FALSE )
|
|
CPRINTLN( DEBUG_SIMON, " >>> Warping player into Solomon's office" )
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE WS_INSIDE // waiting for player to touch the warp out locate
|
|
DISABLE_SELECTOR_THIS_FRAME()
|
|
|
|
IF( NOT IS_CUTSCENE_PLAYING() ) // don't show the locate if a cutscene is playing
|
|
IF( IS_ENTITY_AT_COORD( PLAYER_PED_ID(), vIntOfficeWarpPos, vOnFootLocate, TRUE ) )
|
|
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
|
|
eOfficeWarpStage = WS_WARPING_OUT
|
|
DO_WARP_FADE( FALSE )
|
|
CPRINTLN( DEBUG_SIMON, " >>> Warping player out of Solomon's office" )
|
|
ENDIF
|
|
UPDATE_LETTER_CAMERA()
|
|
// force player to walk and disable weapon use while in the office
|
|
IF( IS_ENTITY_ALIVE( PLAYER_PED_ID() ) )
|
|
WEAPON_TYPE weapon
|
|
IF( GET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), weapon ) )
|
|
IF( weapon <> WEAPONTYPE_UNARMED )
|
|
SET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), WEAPONTYPE_UNARMED )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
SET_PED_MAX_MOVE_BLEND_RATIO( PLAYER_PED_ID(), PEDMOVEBLENDRATIO_WALK )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_SELECT_WEAPON, TRUE )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_ATTACK )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_JUMP )
|
|
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_MELEE_ATTACK_HEAVY )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_MELEE_ATTACK_LIGHT )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_MELEE_ATTACK_ALTERNATE )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_ATTACK2 )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_AIM )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_SELECT_WEAPON )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_COVER )
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE WS_WARPING_IN // handle warping the player into the office
|
|
DISABLE_SELECTOR_THIS_FRAME()
|
|
|
|
IF( IS_SCREEN_FADED_OUT() )
|
|
SET_INTERIOR_DISABLED( INTERIOR_V_58_SOL_OFFICE, FALSE )
|
|
SET_ENTITY_COORD_AND_HEADING( PLAYER_PED_ID(), vIntOfficePlayerPos, fIntOfficePlayerHeading )
|
|
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
|
|
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
|
|
SET_CURRENT_PED_WEAPON( PLAYER_PED_ID(), WEAPONTYPE_UNARMED, TRUE )
|
|
|
|
SET_PLAYER_WANTED_LEVEL( PLAYER_ID(), 0 )
|
|
SET_PLAYER_WANTED_LEVEL_NOW( PLAYER_ID() )
|
|
|
|
HALT_TIME( TRUE )
|
|
|
|
// resolve vehicles in the area where the player will end up when warping out of the office
|
|
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT( <<-1023.439148, -479.559204, 35.818062>>,
|
|
<<-1014.382874, -495.123932, 40.107964>>, 18.500, <<-1024.0964, -485.1923, 35.9779>>, 209.0203,
|
|
GET_DEFAULT_ALLOWABLE_VEHICLE_SIZE_VECTOR(), TRUE, FALSE, TRUE, TRUE )
|
|
|
|
// load the interior
|
|
NEW_LOAD_SCENE_START_SPHERE( vIntOfficePlayerPos, 20.0 )
|
|
GET_INTERIOR_INSTANCE_INDEX_FOR_INTERIOR( INTERIOR_V_58_SOL_OFFICE, intOffice )
|
|
PIN_INTERIOR_IN_MEMORY( intOffice )
|
|
iTimer = GET_GAME_TIMER() + 40000
|
|
WHILE( ( NOT IS_NEW_LOAD_SCENE_LOADED() OR NOT IS_INTERIOR_READY( intOffice ) ) AND iTimer > GET_GAME_TIMER() )
|
|
WAIT( 0 )
|
|
ENDWHILE
|
|
NEW_LOAD_SCENE_STOP()
|
|
IF( iTimer <= GET_GAME_TIMER() )
|
|
ASSERTLN( "UPDATE_SOLOMON_OFFICE_WARP took longer than 40s to load interior in!" )
|
|
UNPIN_INTERIOR( intOffice )
|
|
SET_ENTITY_COORD_AND_HEADING( PLAYER_PED_ID(), vExtOfficePlayerPos, fExtOfficePlayerHeading )
|
|
DO_WARP_FADE( TRUE )
|
|
eOfficeWarpStage = WS_NOT_INSIDE
|
|
ELSE
|
|
// load done
|
|
DO_WARP_FADE( TRUE )
|
|
eOfficeWarpStage = WS_INSIDE
|
|
SETUP_PC_CONTROLS()
|
|
CPRINTLN( DEBUG_SIMON, " >>> Warp into Solomon's office finished" )
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE WS_WARPING_OUT // handle warping the player out of the office
|
|
DISABLE_SELECTOR_THIS_FRAME()
|
|
DISABLE_CELLPHONE_THIS_FRAME_ONLY()
|
|
|
|
IF( IS_SCREEN_FADED_OUT() )
|
|
SET_ENTITY_COORD_AND_HEADING( PLAYER_PED_ID(), vExtOfficePlayerPos, fExtOfficePlayerHeading )
|
|
SET_INTERIOR_DISABLED( INTERIOR_V_58_SOL_OFFICE, TRUE )
|
|
UNPIN_INTERIOR( intOffice )
|
|
SET_GAMEPLAY_CAM_RELATIVE_HEADING()
|
|
SET_GAMEPLAY_CAM_RELATIVE_PITCH()
|
|
HALT_TIME( FALSE )
|
|
CLEANUP_PC_CONTROLS()
|
|
WAIT_FOR_WORLD_TO_LOAD( vExtOfficePlayerPos, 30.0 )
|
|
DO_WARP_FADE( TRUE )
|
|
eOfficeWarpStage = WS_NOT_INSIDE
|
|
CPRINTLN( DEBUG_SIMON, " >>> Warp out of Solomon's office finished" )
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
//-------------------- MAIN STAGE PROCS --------------------
|
|
FUNC BOOL SHOULD_TRIGGER_STAGE_RUN_THIS_FRAME()
|
|
SWITCH( eTriggerStage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD
|
|
CASE STAGE_CARVING_2_ALTA
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE
|
|
CASE STAGE_CARVING_4_OBSERVATORY
|
|
RETURN NOT IS_STAGE_UNLOCKED( eTriggerStage ) AND IS_TRIGGER_STAGE_IN_ACTIVE_RANGE()
|
|
CASE STAGE_SEA
|
|
RETURN IS_TRIGGER_STAGE_IN_ACTIVE_RANGE()
|
|
CASE STAGE_LETTER
|
|
RETURN ( ARE_ALL_STAGES_PRECEDING_UNLOCKED( eTriggerStage ) AND IS_TRIGGER_STAGE_IN_ACTIVE_RANGE() )
|
|
OR eOfficeWarpStage = WS_INSIDE OR eOfficeWarpStage = WS_WARPING_OUT OR eOfficeWarpStage = WS_WARPING_IN
|
|
CASE STAGE_MINE
|
|
RETURN IS_TRIGGER_STAGE_IN_ACTIVE_RANGE() OR ( IS_FLAG_SET( F_IS_MINE_DOOR_HIDDEN ) AND IS_COORD_ON_SCREEN( vMineDoorPos ) )
|
|
DEFAULT
|
|
RETURN FALSE
|
|
ENDSWITCH
|
|
ENDFUNC
|
|
|
|
PROC INIT_TRIGGER_STAGE()
|
|
SWITCH( eTriggerStage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD
|
|
CASE STAGE_CARVING_2_ALTA
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE
|
|
CASE STAGE_CARVING_4_OBSERVATORY
|
|
// used for checking occlusion of carving
|
|
CREATE_TRACKED_POINT_WITH_INFO( iTrackedPoint, GET_UNLOCK_COORD_FOR_STAGE( eTriggerStage ), 0.2 )
|
|
BREAK
|
|
CASE STAGE_SEA
|
|
SCRIPT_LOAD_MODEL( U_F_M_DROWNED_01 )
|
|
SCRIPT_LOAD_ANIM( sDeadBodySeaAnimDict )
|
|
|
|
// secretary spawn
|
|
pedDeadBodySea = CREATE_PED( PEDTYPE_MISSION, U_F_M_DROWNED_01, GET_UNLOCK_COORD_FOR_STAGE( STAGE_SEA ), 184.5548 )
|
|
SET_MODEL_AS_NO_LONGER_NEEDED( U_F_M_DROWNED_01 )
|
|
|
|
TASK_PLAY_ANIM( pedDeadBodySea, sDeadBodySeaAnimDict, sDeadBodySeaAnim, INSTANT_BLEND_IN, INSTANT_BLEND_OUT, -1,
|
|
AF_LOOPING | AF_NOT_INTERRUPTABLE )
|
|
|
|
SET_BLOCKING_OF_NON_TEMPORARY_EVENTS( pedDeadBodySea, TRUE )
|
|
SET_PED_KEEP_TASK( pedDeadBodySea, TRUE )
|
|
FREEZE_ENTITY_POSITION( pedDeadBodySea, TRUE )
|
|
STOP_PED_SPEAKING( pedDeadBodySea, TRUE )
|
|
DISABLE_PED_PAIN_AUDIO( pedDeadBodySea, TRUE )
|
|
SET_PED_CONFIG_FLAG( pedDeadBodySea, PCF_RunFromFiresAndExplosions, FALSE )
|
|
SET_PED_CONFIG_FLAG( pedDeadBodySea, PCF_DisableExplosionReactions, TRUE )
|
|
SET_ENTITY_INVINCIBLE( pedDeadBodySea, TRUE )
|
|
SET_PED_RELATIONSHIP_GROUP_HASH( pedDeadBodySea, RELGROUPHASH_PLAYER )
|
|
BREAK
|
|
CASE STAGE_LETTER
|
|
// lock office door
|
|
iDoor = HASH( "SOLOMON_OFFICE_DOOR" )
|
|
ADD_DOOR_TO_SYSTEM( iDoor, V_ILEV_SOL_OFF_DOOR01, << -1002.147,-478.064,50.117>> )
|
|
DOOR_SYSTEM_SET_DOOR_STATE( iDoor, DOORSTATE_LOCKED )
|
|
// create letter camera
|
|
camLetter = CREATE_CAMERA_WITH_PARAMS( CAMTYPE_SCRIPTED, <<-1008.0560, -476.7573, 50.2493>>,
|
|
<<-89.5003, -0.0000, 38.7952>>, 50.0, FALSE )
|
|
BREAK
|
|
CASE STAGE_MINE
|
|
SCRIPT_LOAD_MODEL( U_M_O_FILMNOIR )
|
|
|
|
// mine dead body spawn
|
|
pedDeadBodyMine = CREATE_PED( PEDTYPE_MISSION, U_M_O_FILMNOIR, GET_UNLOCK_COORD_FOR_STAGE( STAGE_MINE ), 22.9631 )
|
|
SET_PED_PROP_INDEX( pedDeadBodyMine, ANCHOR_HEAD, 0, 0 )
|
|
SET_MODEL_AS_NO_LONGER_NEEDED( U_M_O_FILMNOIR )
|
|
STOP_PED_SPEAKING( pedDeadBodyMine, TRUE )
|
|
DISABLE_PED_PAIN_AUDIO( pedDeadBodyMine, TRUE )
|
|
EXPLODE_PED_HEAD( pedDeadBodyMine )
|
|
SET_PED_RELATIONSHIP_GROUP_HASH( pedDeadBodyMine, RELGROUPHASH_PLAYER )
|
|
// film canister near dead body spawn
|
|
objFilmCan = CREATE_OBJECT_NO_OFFSET( PROP_VINTAGE_FILMCAN, <<-543.71, 1986.20, 126.05>> )
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
PROC UPDATE_TRIGGER_STAGE()
|
|
SWITCH( eTriggerStage )
|
|
CASE STAGE_CARVING_1_WEST_VINEWOOD
|
|
CASE STAGE_CARVING_2_ALTA
|
|
CASE STAGE_CARVING_3_CHINESE_THEATRE
|
|
CASE STAGE_CARVING_4_OBSERVATORY
|
|
// if the player is near the carving, it isn't occluded and the player isn't in a vehicle unlock it
|
|
IF( NOT IS_STAGE_UNLOCKED( eTriggerStage ) )
|
|
IF( IS_TRIGGER_STAGE_IN_UNLOCK_RANGE() AND NOT SAFE_IS_PLAYER_IN_ANY_VEHICLE() AND IS_PLAYER_MICHAEL()
|
|
AND NOT IS_REPEAT_PLAY_ACTIVE() )
|
|
IF( iTrackedPoint <> 0 )
|
|
IF( IS_TRACKED_POINT_VISIBLE( iTrackedPoint ) )
|
|
SET_STAGE_UNLOCKED( eTriggerStage )
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
CASE STAGE_SEA
|
|
// increase dead body capsule so that player's limbs don't clip through it
|
|
IF( IS_ENTITY_ALIVE( pedDeadBodySea ) )
|
|
SET_PED_CAPSULE( pedDeadBodySea, 0.75 )
|
|
ENDIF
|
|
|
|
// if the player is close to the clue then unlock
|
|
IF( NOT IS_STAGE_UNLOCKED( STAGE_SEA ) )
|
|
IF( IS_TRIGGER_STAGE_IN_UNLOCK_RANGE() AND IS_PLAYER_MICHAEL() AND NOT IS_REPEAT_PLAY_ACTIVE() )
|
|
SET_STAGE_UNLOCKED( STAGE_SEA )
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
|
|
CASE STAGE_LETTER
|
|
// handles warping in and out of the office
|
|
IF( SHOULD_ALLOW_OFFICE_WARP() )
|
|
UPDATE_SOLOMON_OFFICE_WARP()
|
|
ENDIF
|
|
|
|
// unlock clue when the player backs out of reading the letter
|
|
IF( NOT IS_STAGE_UNLOCKED( STAGE_LETTER ) AND iUpdateLetterCamStage = 4 AND IS_PLAYER_MICHAEL()
|
|
AND NOT IS_REPEAT_PLAY_ACTIVE() )
|
|
SET_STAGE_UNLOCKED( STAGE_LETTER )
|
|
ENDIF
|
|
BREAK
|
|
CASE STAGE_MINE
|
|
// trigger a vehicle resolve when the player enters the mine and can't see the mine door
|
|
IF( NOT IS_FLAG_SET( F_RESOLVE_TRIGGER ) )
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-580.891357, 2033.120117, 130.511261>>,
|
|
<<-578.478333, 2035.028687, 127.561455>>, 0.750000 ) )
|
|
SET_FLAG( F_RESOLVE_TRIGGER, TRUE )
|
|
ENDIF
|
|
ENDIF
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-580.230469, 2032.054077, 130.292755>>,
|
|
<<-577.666870, 2033.917480, 127.515732>>, 0.750000 ) )
|
|
IF( IS_FLAG_SET( F_RESOLVE_TRIGGER ) )
|
|
RESOLVE_VEHICLES_INSIDE_ANGLED_AREA_WITH_SIZE_LIMIT( <<-595.174561, 2085.767822, 136.881271>>,
|
|
<<-601.575439, 2106.161621, 125.461884>>, 20.500000, <<-602.8466, 2115.5112, 126.4209>>, 128.0735,
|
|
<<13.5, 22.2, 5.7>>, TRUE, FALSE, TRUE, TRUE )
|
|
SET_FLAG( F_RESOLVE_TRIGGER, FALSE )
|
|
CPRINTLN( DEBUG_SIMON, "Resolving area" )
|
|
ENDIF
|
|
ENDIF
|
|
// hide the mine door when the player's inside the mine and can't see the mine door
|
|
IF( NOT IS_FLAG_SET( F_IS_MINE_DOOR_HIDDEN ) )
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-580.230469, 2032.054077, 130.292755>>,
|
|
<<-577.666870, 2033.917480, 127.515732>>, 0.750000 )
|
|
OR IS_SCREEN_FADED_OUT() )
|
|
CREATE_MODEL_HIDE( vMineDoorPos, HIDE_RADIUS, PROP_MINESHAFT_DOOR, FALSE ) // large radius because debris can be scattered by explosion
|
|
CPRINTLN( DEBUG_SIMON, "Hiding mine door model" )
|
|
SET_FLAG( F_IS_MINE_DOOR_HIDDEN, TRUE )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// handle unlock and filter toggle
|
|
IF( IS_TRIGGER_STAGE_IN_UNLOCK_RANGE() AND NOT SAFE_IS_PLAYER_IN_ANY_VEHICLE() )
|
|
DISABLE_CONTROL_ACTION( PLAYER_CONTROL, INPUT_WEAPON_SPECIAL_TWO )
|
|
IF( ARE_ALL_STAGES_PRECEDING_UNLOCKED( STAGE_MINE ) )
|
|
IF( NOT IS_STAGE_UNLOCKED( STAGE_MINE ) AND IS_PLAYER_MICHAEL() AND NOT IS_REPEAT_PLAY_ACTIVE() )
|
|
ADD_CONTACT_TO_PHONEBOOK( CHAR_ISAAC, ALL_OWNERS_BOOKS, TRUE )
|
|
SET_STAGE_UNLOCKED( STAGE_MINE )
|
|
SET_FLAG( F_DISPLAY_HELP_WHEN_LEAVING_MINE, TRUE )
|
|
ENDIF
|
|
ENDIF
|
|
IF( ARE_ALL_STAGES_UNLOCKED() )
|
|
IF( NOT IS_PHONE_ONSCREEN() )
|
|
IF( IS_CONTROL_JUST_PRESSED( PLAYER_CONTROL, INPUT_CONTEXT ) )
|
|
NOIR_TOGGLE_EFFECTS()
|
|
ENDIF
|
|
PRINT_HELP( "MM_TOGGLE", 10 )
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// display help text when the player leaves the mine after unlocking the final clue, only displays once
|
|
IF( IS_FLAG_SET( F_DISPLAY_HELP_WHEN_LEAVING_MINE ) )
|
|
IF( IS_ENTITY_IN_ANGLED_AREA( PLAYER_PED_ID(), <<-594.997620, 2089.004639, 130.344940>>,
|
|
<<-597.112488, 2088.364502, 133.303513>>, 1.000000 ) )
|
|
PRINT_HELP( "MM_HELP", DEFAULT_HELP_TEXT_TIME )
|
|
SET_FLAG( F_DISPLAY_HELP_WHEN_LEAVING_MINE, FALSE )
|
|
ENDIF
|
|
ENDIF
|
|
BREAK
|
|
ENDSWITCH
|
|
ENDPROC
|
|
|
|
//-------------------- BACKEND PROCS --------------------
|
|
PROC SCRIPT_INIT( VECTOR vWorldPointCoord )
|
|
#IF IS_DEBUG_BUILD
|
|
CPRINTLN( DEBUG_SIMON, "" )
|
|
CPRINTLN( DEBUG_SIMON, "Starting murderMystery.sc" )
|
|
CPRINTLN( DEBUG_SIMON, "Activated world point: <<", vWorldPointCoord.x, ", ",
|
|
vWorldPointCoord.y, ", ", vWorldPointCoord.z, ">>" )
|
|
#ENDIF
|
|
|
|
// terminate script if not a CGtoNG player
|
|
IF( NOT IS_LAST_GEN_PLAYER() )
|
|
CPRINTLN( DEBUG_SIMON, "Terminating script because player isn't CG to NG" )
|
|
TERMINATE_THIS_THREAD()
|
|
ENDIF
|
|
// terminate script if an instance is already running
|
|
IF( GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH( HASH( "murderMystery" ) ) > 1 )
|
|
CPRINTLN( DEBUG_SIMON, "Terminating script because an instance of the script already exists" )
|
|
TERMINATE_THIS_THREAD()
|
|
ENDIF
|
|
|
|
// figure out which stage has triggered the script to start
|
|
INT i = 0
|
|
WHILE( i < NUM_STAGES AND eTriggerStage = STAGE_UNSET )
|
|
MURDER_MYSTERY_STAGE stage = INT_TO_ENUM( MURDER_MYSTERY_STAGE, i )
|
|
IF( VECTOR_COMPARE( vWorldPointCoord, GET_WORLD_POINT_COORD_FOR_STAGE( stage ) ) )
|
|
eTriggerStage = stage
|
|
ENDIF
|
|
i++
|
|
ENDWHILE
|
|
|
|
INIT_TRIGGER_STAGE()
|
|
ENDPROC
|
|
|
|
PROC SCRIPT_UPDATE()
|
|
// update player position for this frame
|
|
IF( IS_ENTITY_ALIVE( PLAYER_PED_ID() ) )
|
|
vPlayerPos = GET_ENTITY_COORDS( PLAYER_PED_ID(), FALSE )
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
//-------------------- MAIN LOOP --------------------
|
|
SCRIPT( coords_struct in_coords )
|
|
IF( HAS_FORCE_CLEANUP_OCCURRED( FORCE_CLEANUP_FLAG_SP_TO_MP | FORCE_CLEANUP_FLAG_REPEAT_PLAY | FORCE_CLEANUP_FLAG_DEBUG_MENU | FORCE_CLEANUP_FLAG_PLAYER_KILLED_OR_ARRESTED ) )
|
|
SCRIPT_CLEANUP()
|
|
ENDIF
|
|
|
|
SCRIPT_INIT( in_coords.vec_coord[ 0 ] )
|
|
#IF IS_DEBUG_BUILD
|
|
DEBUG_SCRIPT_INIT()
|
|
#ENDIF
|
|
|
|
WHILE( TRUE )
|
|
SCRIPT_UPDATE()
|
|
#IF IS_DEBUG_BUILD
|
|
DEBUG_UPDATE()
|
|
#ENDIF
|
|
|
|
// should the script run for the trigger stage this frame, if not then clean up
|
|
IF( SHOULD_TRIGGER_STAGE_RUN_THIS_FRAME() )
|
|
UPDATE_TRIGGER_STAGE()
|
|
ELSE
|
|
#IF IS_DEBUG_BUILD
|
|
#IF DO_DELAYED_CLEANUP
|
|
DEBUG_CLEANUP_WITH_DELAY()
|
|
#ENDIF
|
|
#IF NOT DO_DELAYED_CLEANUP
|
|
SCRIPT_CLEANUP()
|
|
#ENDIF
|
|
#ENDIF
|
|
#IF NOT IS_DEBUG_BUILD
|
|
SCRIPT_CLEANUP()
|
|
#ENDIF
|
|
ENDIF
|
|
|
|
WAIT( 0 )
|
|
ENDWHILE
|
|
ENDSCRIPT
|