//╒═════════════════════════════════════════════════════════════════════════════╕ //╞══════════════════╡ 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