Files
gtav-src/script/dev_ng/singleplayer/include/public/noirEffects.sch
T
2025-09-29 00:52:08 +02:00

218 lines
8.8 KiB
Scheme
Executable File

//
// Noir Effects Header
//
//
// Written by Simon Bramwell Date: 04/09/14
//
// This header is used as a global toggle for the noir timecycles, audio
// scenes and looping audio associated with the murderMystery.sc easter egg.
//
USING "rage_builtins.sch"
USING "globals.sch"
USING "cellphone_public.sch"
USING "dialogue_public.sch"
USING "commands_graphics.sch"
USING "shared_hud_displays.sch"
//-------------------- ENUMS --------------------
ENUM NOIR_PHONECALL_STATE // state of a call to Isaac
NPS_IDLE,
NPS_RECEIVED_CALL
ENDENUM
//-------------------- STRUCTS --------------------
STRUCT NOIR_DATA
INT iNoirLoopingSoundID = -1
NOIR_PHONECALL_STATE eNoirPhonecallState
INT iTimer
ENDSTRUCT
//-------------------- AUDIO SCENE PROCS --------------------
//PURPOSE: Returns the audio scene for each eligible stage
FUNC STRING PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( NOIR_EFFECTS_STATUS state )
SWITCH( state )
CASE NOIR_FILTER_0 RETURN "FILM_NOIR_FILTER_SCENE"
CASE NOIR_FILTER_1 RETURN "FILM_NOIR_FILTER_2_SCENE"
DEFAULT RETURN ""
ENDSWITCH
ENDFUNC
//PURPOSE: Enables/disables an audio scene for a specified stage
PROC PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_EFFECTS_STATUS state, BOOL bEnable )
STRING sAudioScene = PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( state )
IF( bEnable )
IF( NOT IS_AUDIO_SCENE_ACTIVE( sAudioScene ) )
START_AUDIO_SCENE( sAudioScene )
ENDIF
ELSE
IF( IS_AUDIO_SCENE_ACTIVE( sAudioScene ) )
STOP_AUDIO_SCENE( sAudioScene )
ENDIF
ENDIF
ENDPROC
//PURPOSE: Sets the correct audio scenes for each stage
PROC PRIVATE_NOIR_UPDATE_AUDIO_SCENE()
IF( g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_0 )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_1, FALSE )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_0, TRUE )
ELIF( g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_1 )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_0, FALSE )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_1, TRUE )
ELIF( g_savedGlobals.sAmbient.eNoirEffectState = NOIR_OFF )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_0, FALSE )
PRIVATE_NOIR_AUDIO_SCENE_ENABLE( NOIR_FILTER_1, FALSE )
ENDIF
ENDPROC
//-------------------- EFFECTS PROCS --------------------
FUNC BOOL PRIVATE_NOIR_ARE_EFFECTS_ENABLED()
RETURN g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_0 OR g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_1
ENDFUNC
//PURPOSE: Returns the timecycle string for the current stage
FUNC STRING PRIVATE_NOIR_GET_CURRENT_FILTER()
SWITCH( g_savedGlobals.sAmbient.eNoirEffectState )
CASE NOIR_FILTER_0 RETURN "NG_filmnoir_BW02"
CASE NOIR_FILTER_1 RETURN "NG_filmnoir_BW01"
DEFAULT RETURN ""
ENDSWITCH
ENDFUNC
//PURPOSE: Enables/disables the current stage filter and plays sfx
PROC PRIVATE_NOIR_ENABLE( BOOL bEnable, INT &iNoirLoopingSoundID )
STRING sSetName = "NOIR_FILTER_SOUNDS"
IF( bEnable )
SET_EXTRA_TCMODIFIER( PRIVATE_NOIR_GET_CURRENT_FILTER() )
PLAY_SOUND_FRONTEND( -1, "ON", sSetName )
IF( iNoirLoopingSoundID = -1 )
iNoirLoopingSoundID = GET_SOUND_ID()
PLAY_SOUND_FRONTEND( iNoirLoopingSoundID, "LOOP", sSetName )
ENDIF
ELSE
CLEAR_EXTRA_TCMODIFIER()
PLAY_SOUND_FRONTEND( -1, "OFF", sSetName )
STOP_SOUND( iNoirLoopingSoundID )
RELEASE_SOUND_ID( iNoirLoopingSoundID )
iNoirLoopingSoundID = -1
ENDIF
ENDPROC
//PURPOSE: Called to toggle through each of the stages
PROC NOIR_TOGGLE_EFFECTS()
SWITCH( g_savedGlobals.sAmbient.eNoirEffectState )
CASE NOIR_OFF
g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_0
BREAK
CASE NOIR_FILTER_0
g_savedGlobals.sAmbient.eNoirEffectState = NOIR_FILTER_1
CPRINTLN( DEBUG_SIMON, "NOIR > NOIR_TOGGLE_EFFECTS > Switching from NOIR_FILTER_0 to NOIR_FILTER_1" )
SET_EXTRA_TCMODIFIER( PRIVATE_NOIR_GET_CURRENT_FILTER() )
PLAY_SOUND_FRONTEND( -1, "ON", "NOIR_FILTER_SOUNDS" )
BREAK
CASE NOIR_FILTER_1
g_savedGlobals.sAmbient.eNoirEffectState = NOIR_OFF
BREAK
ENDSWITCH
ENDPROC
//PURPOSE: Forces all noir effects off in one frame
PROC NOIR_FORCE_OFF( NOIR_DATA &data )
CPRINTLN( DEBUG_SIMON, "NOIR > NOIR_FORCE_OFF > Forcing noir effects off" )
// clear filter
IF( GET_EXTRA_TCMODIFIER() <> -1 )
CLEAR_EXTRA_TCMODIFIER()
ENDIF
// stop looping sound
IF( data.iNoirLoopingSoundID <> -1 )
STOP_SOUND( data.iNoirLoopingSoundID )
RELEASE_SOUND_ID( data.iNoirLoopingSoundID )
data.iNoirLoopingSoundID = -1
ENDIF
// clear audio scenes
IF( IS_AUDIO_SCENE_ACTIVE( PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( NOIR_FILTER_0 ) ) )
STOP_AUDIO_SCENE( PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( NOIR_FILTER_0 ) )
ENDIF
IF( IS_AUDIO_SCENE_ACTIVE( PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( NOIR_FILTER_1 ) ) )
STOP_AUDIO_SCENE( PRIVATE_NOIR_GET_AUDIO_SCENE_FOR_STATE( NOIR_FILTER_1 ) )
ENDIF
ENDPROC
//-------------------- PHONE CALL PROCS --------------------
FUNC enumPhoneBookPresence GET_CURRENT_PLAYER_CHARACTER_PHONEBOOK()
MODEL_NAMES model = GET_ENTITY_MODEL( PLAYER_PED_ID() )
SWITCH( model )
CASE PLAYER_ZERO RETURN MICHAEL_BOOK
CASE PLAYER_ONE RETURN FRANKLIN_BOOK
CASE PLAYER_TWO RETURN TREVOR_BOOK
DEFAULT RETURN MICHAEL_BOOK
ENDSWITCH
ENDFUNC
//PURPOSE: Waits for a phone call to Isaac and toggles filter in the right circumstances
PROC PROCESS_NOIR_PHONECALL( NOIR_PHONECALL_STATE &state, INT &iTimer )
SWITCH( state )
CASE NPS_IDLE
IF( IS_CALLING_CONTACT( CHAR_ISAAC ) )
IF( IS_CONTACT_IN_PHONEBOOK( CHAR_ISAAC, GET_CURRENT_PLAYER_CHARACTER_PHONEBOOK() ) )
state = NPS_RECEIVED_CALL
iTimer = GET_GAME_TIMER() + 3000
ENDIF
ENDIF
BREAK
CASE NPS_RECEIVED_CALL
IF( IS_CALLING_CONTACT( CHAR_ISAAC ) AND iTimer < GET_GAME_TIMER() )
HANG_UP_AND_PUT_AWAY_PHONE()
NOIR_TOGGLE_EFFECTS()
state = NPS_IDLE
ELIF( NOT IS_CALLING_CONTACT( CHAR_ISAAC ) )
state = NPS_IDLE
ENDIF
BREAK
ENDSWITCH
ENDPROC
//PURPOSE: Adds CHAR_ISAAC into the player's phonebook during repeat play, if the final clue is unlocked
PROC PROCESS_NOIR_CONTACT()
IF( IS_REPEAT_PLAY_ACTIVE() )
IF( IS_BIT_SET( g_savedGlobals.sAmbient.iMurderMysteryFlags, 6 ) ) // check if the player's finished STAGE_MINE
IF( NOT IS_CONTACT_IN_PHONEBOOK( CHAR_ISAAC, GET_CURRENT_PLAYER_CHARACTER_PHONEBOOK() ) )
ADD_CONTACT_TO_PHONEBOOK( CHAR_ISAAC, GET_CURRENT_PLAYER_CHARACTER_PHONEBOOK(), FALSE )
ENDIF
ENDIF
ENDIF
ENDPROC
//PURPOSE: Wrapper for REGISTER_NOIR_LENS_EFFECT
PROC UPDATE_NOIR_LENS_EFFECT()
IF( NOT IS_AIMING_THROUGH_SNIPER_SCOPE( PLAYER_PED_ID() ) AND NOT g_bDisableNoirLensEffect )
REGISTER_NOIR_LENS_EFFECT()
ENDIF
ENDPROC
//-------------------- MAIN UPDATE --------------------
PROC NOIR_UPDATE_EFFECTS( NOIR_DATA &data )
PRIVATE_NOIR_UPDATE_AUDIO_SCENE()
PROCESS_NOIR_CONTACT()
PROCESS_NOIR_PHONECALL( data.eNoirPhonecallState, data.iTimer )
// persistent checks for noir effects
IF( PRIVATE_NOIR_ARE_EFFECTS_ENABLED() )
IF( GET_EXTRA_TCMODIFIER() = -1 )
CPRINTLN( DEBUG_SIMON, "NOIR > NOIR_UPDATE_EFFECTS > Enabling effects because state is NOIR_ON" )
PRIVATE_NOIR_ENABLE( TRUE, data.iNoirLoopingSoundID )
UPDATE_NOIR_LENS_EFFECT()
ELSE
UPDATE_NOIR_LENS_EFFECT()
ENDIF
ELSE
IF( GET_EXTRA_TCMODIFIER() <> -1 )
CPRINTLN( DEBUG_SIMON, "NOIR > NOIR_UPDATE_EFFECTS > Disabling effects because NOIR_OFF" )
PRIVATE_NOIR_ENABLE( FALSE, data.iNoirLoopingSoundID )
ENDIF
ENDIF
ENDPROC