untyped global function CLEventNotification_Init global function ServerCallback_EventNotification global function EventNotification global function SetEventNotificationHATT global function SetTimedEventNotificationHATT global function SetEventNotification global function SetTimedEventNotification global function HideEventNotification global function AddEventNotificationCallback global function AddPermanentEventNotification global function RestorePermanentEventNotification global function EmitCountdownSound global function SetEventNotificationEndingOnSignals //Should go away once we make gamemodes/etc register their own EventNotifications as opposed to adding to EventNotification() const EN_SHOW_OVER_SCREENFADE = 0x00000001 void function CLEventNotification_Init() { RegisterSignal( "SetEventNotification" ) RegisterEntityVarChangeCallback( "player", "permanentEventNotification", PermanentEventNotificationChanged ) AddCreatePilotCockpitCallback( CockpitCreate_RestorePermanentEventNotification ) AddCreateTitanCockpitCallback( CockpitCreate_RestorePermanentEventNotification ) } function ServerCallback_EventNotification( int eventID, int eHandle, eventVal ) { entity ent if ( eHandle ) ent = GetEntityFromEncodedEHandle( eHandle ) EventNotification( eventID, ent, eventVal ) } void function EventNotification( int eventID, entity ent, var eventVal ) { entity player = GetLocalClientPlayer() switch ( eventID ) { //TODO: One day, go back and move all these into specific scripts, e.g. MFD EventNotifications should go into cl_gamemode_mfd case eEventNotifications.BurnCardRematch: if ( ent ) SetTimedEventNotification( 3.0, "#BURNCARD_REMATCH_WARNING", ent.GetPlayerName() ) break case eEventNotifications.YouveBeenSpotted: SetTimedEventNotification( 3.0, "#YOUVE_BEEN_SPOTTED" ) break case eEventNotifications.MarkedForDeathWaitingForMarkedToSpawn: //Not used atm SetEventNotification( "#MARKED_FOR_DEATH_WAITING_FOR_MARKED_TO_SPAWN" ) break case eEventNotifications.MarkedForDeathMarkedDisconnected: AnnouncementMessageSweep( GetLocalClientPlayer(), "#MARKED_FOR_DEATH_MARKED_DISCONNECTED", "#MARKED_FOR_DEATH_MARKED_DISCONNECTED_SUB", <1,0,0> ) break case eEventNotifications.MarkedForDeathYouWillBeMarkedNext: //Not used atm. expect float( eventVal ) if ( eventVal - Time() > 2.0 ) { thread EmitCountdownSound( eventVal, "UI_InGame_MarkedForDeath_CountdownToYouAreMarked" ) AnnouncementData announcement = Announcement_Create( "#MARKED_FOR_DEATH_YOU_ARE_THE_NEXT_TARGET" ) Announcement_SetPurge( announcement, true ) Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc AnnouncementFromClass( player, announcement ) SetTimedEventNotificationHATT( (eventVal - Time()) - 1.0, "#MARKED_FOR_DEATH_YOU_WILL_BE_MARKED_NEXT", HATT_GAME_COUNTDOWN_SECONDS, eventVal ) } break case eEventNotifications.MarkedForDeathCountdownToNextMarked: //Not used atm. expect float( eventVal ) if ( eventVal - Time() > 2.0 ) { SetTimedEventNotificationHATT( (eventVal - Time()) - 1.0, "#MARKED_FOR_DEATH_COUNTDOWN_TO_NEXT_MARKED", HATT_GAME_COUNTDOWN_SECONDS, eventVal ) thread EmitCountdownSound( eventVal, "UI_InGame_MarkedForDeath_CountdownToMarked" ) } break #if MP case eEventNotifications.MarkedForDeathKill: if ( !ent ) return entity attacker if ( eventVal != null ) { expect int( eventVal ) attacker = GetHeavyWeightEntityFromEncodedEHandle( eventVal ) } if ( !IsValid( attacker ) ) break entity clientPlayer = GetLocalClientPlayer() bool friendlyDeath = ent.GetTeam() == clientPlayer.GetTeam() string msg = GetMarkedName( attacker ) + " " + Localize( "#DEATH_GENERIC_KILLED_LOWER_CASE" ) + " " + GetMarkedName( ent ) if ( friendlyDeath ) AnnouncementMessageSweep( GetLocalClientPlayer(), "#MARKED_FOR_DEATH_MARK_ELIMINATED" , msg, TEAM_COLOR_ENEMY ) else AnnouncementMessageSweep( GetLocalClientPlayer(), "#MARKED_FOR_DEATH_MARK_ELIMINATED" , msg, TEAM_COLOR_FRIENDLY ) break #endif case eEventNotifications.SST_ScoreChange: if ( IsLocalViewPlayer( ent ) ) { SetTimedEventNotification( 3.0, "#GAMEMODE_SST_NOTIFY_SELF_TITANSLEFT_INFINITE" ) } else { AnnouncementData announcement = Announcement_Create( "#GAMEMODE_SST_ENEMY_TITAN_DOWN" ) entity attacker = eventVal ? GetHeavyWeightEntityFromEncodedEHandle( expect int( eventVal ) ) : null if ( IsValid( ent ) && IsValid( attacker ) && attacker.IsPlayer() ) { if ( IsLocalViewPlayer( attacker ) ) { Announcement_SetSubText( announcement, "#GAMEMODE_SST_NOTIFY_DESTROYED_BY_YOU" ) Announcement_SetOptionalSubTextArgsArray( announcement, [ent.GetPlayerName()] ) } else { Announcement_SetSubText( announcement, "#GAMEMODE_SST_NOTIFY_DESTROYED_BY" ) Announcement_SetOptionalSubTextArgsArray( announcement, [attacker.GetPlayerName(), ent.GetPlayerName()] ) } } Announcement_SetPurge( announcement, false ) Announcement_SetDuration( announcement, 3.0 ) Announcement_SetSoundAlias( announcement, "UI_LH_1P_Friendly_CappingLhp" ) AnnouncementFromClass( player, announcement ) } break case eEventNotifications.BeingRevived: SetTimedEventNotificationHATT( 0.0, "Revived in %s1", HATT_GAME_COUNTDOWN_SECONDS_MILLISECONDS, eventVal ) break case eEventNotifications.TurretAvailable: AnnouncementData announcement = Announcement_Create( "#SENTRY_TURRET_AVAILABLE_SPLASH" ) if ( player.IsTitan() ) Announcement_SetSubText( announcement, "#SENTRY_TURRET_AVAILABLE_SPLASH_HINT_TITAN" ) else Announcement_SetSubText( announcement, "#SENTRY_TURRET_AVAILABLE_SPLASH_HINT" ) Announcement_SetPurge( announcement, false ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetSoundAlias( announcement, "UI_InGame_CoOp_SentryGunAvailable" ) AnnouncementFromClass( player, announcement ) break case eEventNotifications.MaxTurretsPlaced: AnnouncementData announcement = Announcement_Create( "" ) Announcement_SetSubText( announcement, "#SENTRY_TURRET_MAX_PLACED_SPLASH_HINT" ) Announcement_SetPurge( announcement, true ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetSoundAlias( announcement, "coop_sentrygun_deploymentdeniedbeep" ) AnnouncementFromClass( player, announcement ) break case eEventNotifications.RoundWinningKillReplayCancelled: SetTimedEventNotification( 5.0, "#ROUND_WINNING_KILL_REPLAY_CANCELLED", null, null, EN_SHOW_OVER_SCREENFADE ) break case eEventNotifications.FriendlyPlayerSpawnedOnYou: if ( IsValid( ent ) ) { SetTimedEventNotification( 5.0, "#FRIENDLY_PLAYER_SPAWNED_ON_YOU", ent.GetPlayerName(), string( eventVal ) ) EmitSoundOnEntity( ent, "UI_Spawn_FriendlyPilot" ) EmitSoundOnEntity( ent, "diag_neut_friendlySpawnOnPlayer" ) } break case eEventNotifications.SpawnedOnFriendlyPlayer: if ( IsValid( ent ) ) { SetTimedEventNotification( 5.0, "#SPAWNED_ON_FRIENDLY_PLAYER", ent.GetPlayerName(), string( eventVal ) ) EmitSoundOnEntity( ent, "UI_Spawn_FriendlyPilot" ) EmitSoundOnEntity( ent, "diag_neut_friendlySpawn_PlayerReact" ) } break case eEventNotifications.HarvesterTitanDamageOnly: SetTimedEventNotification( 5.0, "#HARVESTER_TITAN_DAMAGE_ONLY" ) break case eEventNotifications.HarvesterBombDamageOnly: SetTimedEventNotification( 5.0, "#HARVESTER_BOMB_DAMAGE_ONLY" ) break case eEventNotifications.TurretTitanDamageOnly: SetTimedEventNotification( 5.0, "#FW_TITAN_REQUIRED_TURRET" ) break case eEventNotifications.Grapple_WasGrappled_ByPilot: case eEventNotifications.Grapple_WasGrappled_ByTitan: SmartAmmo_SetStatusWarning( "#GRAPPLED_WARNING", 3.0 ) //AnnouncementData announcement = Announcement_Create( "#GRAPPLED_WARNING" ) // //if ( eventID == eEventNotifications.Grapple_WasGrappled_ByPilot ) // Announcement_SetSubText( announcement, "#GRAPPLED_WARNING_HINT_PILOT" ) //else // Announcement_SetSubText( announcement, "#GRAPPLED_WARNING_HINT_TITAN" ) // //Announcement_SetPurge( announcement, true ) //Announcement_SetDuration( announcement, 2.0 ) //Announcement_SetSoundAlias( announcement, "Weapon_TetherGun_Attach_1P" ) //Announcement_SetHideOnDeath( announcement, false ) //AnnouncementFromClass( player, announcement ) break case eEventNotifications.EnemyTeamEliminated: SetTimedEventNotification( 3.0, "#EVENTNOTIFY_ENEMY_TEAM_ELIMINATED" ) break case eEventNotifications.TDay_ActivatedBeacon: string message = "Enemy activated the beacon" if ( ent == GetLocalViewPlayer() ) message = "Beacon Activated" else if ( ent.GetTeam() == GetLocalViewPlayer().GetTeam() ) message = "Teammate activated the beacon" AnnouncementData announcement = Announcement_Create( message ) Announcement_SetSubText( announcement, "Titan meter awarded" ) Announcement_SetPurge( announcement, true ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetSoundAlias( announcement, "UI_InGame_CoOp_WaveSurvived" ) Announcement_SetHideOnDeath( announcement, false ) AnnouncementFromClass( player, announcement ) break case eEventNotifications.TDay_TDayIncoming: expect float( eventVal ) if ( eventVal - Time() > 2.0 ) { SetTimedEventNotificationHATT( (eventVal - Time()) - 1.0, "T-Day coming in: ^FFC83200 %s1", HATT_GAME_COUNTDOWN_SECONDS, eventVal ) thread EmitCountdownSound( eventVal, "UI_InGame_MarkedForDeath_CountdownToMarked" ) } break case eEventNotifications.TDay_Arrived: string message = "T-Day has arrived" AnnouncementData announcement = Announcement_Create( message ) Announcement_SetSubText( announcement, "All Titans available" ) Announcement_SetPurge( announcement, true ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetSoundAlias( announcement, "UI_LH_1P_Enemy_CappingLhp" ) Announcement_SetHideOnDeath( announcement, false ) AnnouncementFromClass( player, announcement ) break case eEventNotifications.TDay_KnockedOff: SetTimedEventNotification( 5.0, "Hacking interrupted - took too much damage" ) break case eEventNotifications.AT_BlackBoxDied: SetTimedEventNotification( 5.0, "Black box self destructed" ) break case eEventNotifications.AT_SupplyDropIncomingIn: SetTimedEventNotificationHATT( (eventVal - Time()) - 1.0, "#AT_SUPPLY_DROP_INCOMING_IN", HATT_GAME_COUNTDOWN_SECONDS, eventVal ) thread EmitCountdownSound( eventVal, "UI_InGame_MarkedForDeath_CountdownToMarked" ) break case eEventNotifications.AT_SupplyDropIncoming: AnnouncementData announcement = Announcement_Create( "#AT_SUPPLY_DROP_INCOMING" ) Announcement_SetSubText( announcement, "#AT_SUPPLY_DROP_INCOMING_HINT" ) Announcement_SetPurge( announcement, true ) Announcement_SetSoundAlias( announcement, "UI_InGame_CoOp_WaveIncoming" ) Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc AnnouncementFromClass( player, announcement ) break case eEventNotifications.AT_SupplyDropCaptured: string msg = "#AT_SUPPLY_DROP_CAPTURED" if ( eventVal != GetLocalViewPlayer().GetTeam() ) msg = "#AT_SUPPLY_DROP_CAPTURED_BY_ENEMY" AnnouncementData announcement = Announcement_Create( msg ) Announcement_SetSubText( announcement, "#AT_SUPPLY_DROP_CAPTURED_HINT" ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetPurge( announcement, true ) Announcement_SetSoundAlias( announcement, "UI_InGame_LevelUp" ) Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc AnnouncementFromClass( player, announcement ) break case eEventNotifications.AT_SupplyDropExpired: AnnouncementData announcement = Announcement_Create( "#AT_SUPPLY_DROP_EXPIRED" ) Announcement_SetSubText( announcement, "#AT_SUPPLY_DROP_EXPIRED_HINT" ) Announcement_SetDuration( announcement, 4.0 ) Announcement_SetPurge( announcement, true ) Announcement_SetSoundAlias( announcement, "UI_InGame_CoOp_TryAgain" ) Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc AnnouncementFromClass( player, announcement ) break case eEventNotifications.BLEEDOUT_SelfHealPrompt: //By default notification messages will not display if the new message is the same as the last message. if ( player.cv.hud.s.lastEventNotificationText == "#BLEEDOUT_USE_TEAMMATE_RES" ) player.cv.hud.s.lastEventNotificationText = "" SetTimedEventNotification( 1.0, "#BLEEDOUT_USE_TEAMMATE_RES" ) break case eEventNotifications.Clear: HideEventNotification() break default: clGlobal.eventNotificationCallbacks[ eventID ]( ent, eventVal ) break } } function SetEventNotificationHATT( eventText, eventHATT = null, eventVal = 0, flags = 0 ) { SetTimedEventNotification( 0, eventText, eventHATT, eventVal ) } function SetTimedEventNotificationHATT( duration, eventText, eventHATT, eventVal = 0, flags = 0 ) { expect float( duration ) entity player = GetLocalClientPlayer() if ( eventText != player.cv.hud.s.lastEventNotificationText ) { player.cv.hud.s.eventNotification.SetAlpha( 0 ) player.cv.hud.s.eventNotification.FadeOverTime( 255, 1.0 ) } else { player.cv.hud.s.eventNotification.SetAlpha( 255 ) } player.cv.hud.s.eventNotification.Show() player.cv.hud.s.eventNotification.SetAutoText( eventText, eventHATT, eventVal ) player.cv.hud.s.lastEventNotificationText = eventText if ( !player.cv.hud.s.eventNotification.IsAutoText() ) player.cv.hud.s.eventNotification.EnableAutoText() player.Signal( "SetEventNotification" ) local zPos = 1000 // there is no base Z in code, this value should match the default in HudScripted_mp.res if ( flags & EN_SHOW_OVER_SCREENFADE ) zPos = 3501 player.cv.hud.s.eventNotification.SetZ( zPos ) if ( duration ) thread HideEventNotificationWithDelay( duration ) } function SetEventNotification( eventText, eventArg1 = null, eventArg2 = null, flags = 0 ) { SetTimedEventNotification( 9999.0, eventText, eventArg1, eventArg2, flags ) } function SetTimedEventNotification( duration, eventText, eventArg1 = null, eventArg2 = null, flags = 0 ) { expect float( duration ) entity player = GetLocalClientPlayer() printt( "SetTimedEventNotification", duration, eventText, player.cv.hud.s.lastEventNotificationText ) if ( eventText == player.cv.hud.s.lastEventNotificationText ) { //player.cv.hud.s.eventNotification.SetAlpha( 0 ) //player.cv.hud.s.eventNotification.FadeOverTime( 255, 1.0 ) HidePlayerHint( eventText ) } else { //player.cv.hud.s.eventNotification.SetAlpha( 255 ) AddPlayerHint( duration, 0.25, $"", eventText, eventArg1, eventArg2 ) } //player.cv.hud.s.eventNotification.Show() //if ( player.cv.hud.s.eventNotification.IsAutoText() ) // player.cv.hud.s.eventNotification.DisableAutoText() //player.cv.hud.s.eventNotification.SetText( eventText, eventArg1, eventArg2 ) player.cv.hud.s.lastEventNotificationText = eventText player.Signal( "SetEventNotification" ) //local zPos = 1000 // there is no base Z in code, this value should match the default in HudScripted_mp.res //if ( flags & EN_SHOW_OVER_SCREENFADE ) // zPos = 3501 //player.cv.hud.s.eventNotification.SetZ( zPos ) if ( duration && duration < 9999 ) thread HideEventNotificationWithDelay( duration ) } function SetEventNotificationEndingOnSignals( eventText, signalArray, eventArg1 = null, eventArg2 = null, flags = 0 ) { SetEventNotification( eventText, eventArg1, eventArg2, flags ) thread HideEventNotificationOnSignals( signalArray ) } void function HideEventNotification() { ClearEventNotification() RestorePermanentEventNotification() } void function HideEventNotificationWithDelay( float delay ) { Assert( delay > 0.0 ) entity player = GetLocalClientPlayer() player.Signal( "SetEventNotification" ) player.EndSignal( "SetEventNotification" ) wait delay HideEventNotification() } function HideEventNotificationOnSignals( signalArray ) { entity player = GetLocalClientPlayer() foreach( signal in signalArray ) player.EndSignal( signal ) OnThreadEnd( function() : () { HideEventNotification() } ) WaitForever() } void function RestorePermanentEventNotification() { if ( IsWatchingReplay() ) return entity player = GetLocalClientPlayer() int permanentEventNotificationID = expect int ( player.nv.permanentEventNotification ) //printt( "HideEventNotification. PermEventNotificationID: " + permanentEventNotificationID ) if ( permanentEventNotificationID != ePermanentEventNotifications.Empty ) { Assert( permanentEventNotificationID in clGlobal.permanentEventNotifications ) SetEventNotification( clGlobal.permanentEventNotifications[ permanentEventNotificationID ] ) } } void function CockpitCreate_RestorePermanentEventNotification( entity cockpit, entity player ) { RestorePermanentEventNotification() } function ClearEventNotification() //Does not restore PermanentEventNotifications! { entity player = GetLocalClientPlayer() if ( !player.p.playerScriptsInitialized ) return HidePlayerHint( player.cv.hud.s.lastEventNotificationText ) //player.cv.hud.s.eventNotification.FadeOverTime( 0, 1.0 ) } function EmitCountdownSound( endCountdownTime, soundAlias = "UI_InGame_MarkedForDeath_CountdownToMarked" ) { //player.EndSignal( "OnDestroy" ) //Don't end signal on destroy because if you are watching kill replay while counting down to marked, we don't want this thread to end var remainingTime = endCountdownTime - Time() while( remainingTime > 0 ) { entity player = GetLocalClientPlayer() //Keep getting handle to local player because we want to keep playing this sound throughout kill replay EmitSoundOnEntity( player, soundAlias ) wait 1.0 remainingTime -= 1.0 } } void function AddEventNotificationCallback( int eventNotificationID, void functionref( entity, var ) callbackFunc ) { Assert( !(eventNotificationID in clGlobal.eventNotificationCallbacks), "Already have callbackFunc : " + string( clGlobal.eventNotificationCallbacks[ eventNotificationID ] ) + " associated with eEventNotificationID: " + eventNotificationID ) clGlobal.eventNotificationCallbacks[ eventNotificationID ] <- callbackFunc } void function AddPermanentEventNotification( int enumValue, string displayString ) { clGlobal.permanentEventNotifications[ enumValue ] <- displayString } function PermanentEventNotificationChanged( player, newValue, oldValue ) //Not typed since RegisterEntityVarChangeCallback is untyped { Assert( player == GetLocalClientPlayer() ) expect int( newValue ) expect int( oldValue ) if ( newValue == ePermanentEventNotifications.Empty ) { if ( !IsValid( player ) || !player.cv ) return if ( newValue == oldValue ) //Tried to clear PermanentEventNotifications twice. Just exit return Assert( oldValue in clGlobal.permanentEventNotifications ) string eventNotificationText = clGlobal.permanentEventNotifications[ oldValue ] if ( player.cv.hud.s.lastEventNotificationText != eventNotificationText ) return ClearEventNotification() } else { Assert( newValue in clGlobal.permanentEventNotifications ) string eventNotificationText = clGlobal.permanentEventNotifications[ newValue ] SetEventNotification( eventNotificationText ) } }