From 07b7eafd5c1845c70510b695446c23973fed1d4d Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 7 Jul 2021 22:25:59 +0100 Subject: add fra, featured modes and some private lobby v2 stuff --- .../scripts/vscripts/ui/menu_lobby.nut | 1628 ++++++++++++++++++++ .../scripts/vscripts/ui/menu_map_select.nut | 162 ++ .../scripts/vscripts/ui/menu_mode_select.nut | 135 ++ .../scripts/vscripts/ui/ui_utility.gnut | 634 ++++++++ 4 files changed, 2559 insertions(+) create mode 100644 Northstar.Client/scripts/vscripts/ui/menu_lobby.nut create mode 100644 Northstar.Client/scripts/vscripts/ui/menu_map_select.nut create mode 100644 Northstar.Client/scripts/vscripts/ui/menu_mode_select.nut create mode 100644 Northstar.Client/scripts/vscripts/ui/ui_utility.gnut (limited to 'Northstar.Client/scripts/vscripts/ui') diff --git a/Northstar.Client/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/scripts/vscripts/ui/menu_lobby.nut new file mode 100644 index 00000000..67036d48 --- /dev/null +++ b/Northstar.Client/scripts/vscripts/ui/menu_lobby.nut @@ -0,0 +1,1628 @@ +untyped + + +global function MenuLobby_Init + +global function InitLobbyMenu +global function UICodeCallback_SetupPlayerListGenElements +global function UpdateAnnouncementDialog +global function EnableButton +global function DisableButton + +global function UICodeCallback_CommunityUpdated +global function UICodeCallback_FactionUpdated +global function Lobby_UpdateInboxButtons + +global function GetTimeToRestartMatchMaking + +global function RefreshCreditsAvailable + +global function InviteFriendsIfAllowed +global function SetPutPlayerInMatchmakingAfterDelay + +global function DLCStoreShouldBeMarkedAsNew + +global function SetNextAutoMatchmakingPlaylist +global function GetNextAutoMatchmakingPlaylist + +global function OnDpadCommsButton_Activate + +global function GetActiveSearchingPlaylist + +global function Lobby_SetFDModeBasedOnSearching +global function Lobby_IsFDMode +global function Lobby_SetAutoFDOpen +global function Lobby_SetFDMode +global function Lobby_ToggleFDMode +global function Lobby_CallsignButton3EventHandler +global function Lobby_RefreshButtons + +global function OnStoreButton_Activate +global function OnStoreBundlesButton_Activate +global function OnStoreNewReleasesButton_Activate + +const string MATCHMAKING_AUDIO_CONNECTING = "menu_campaignsummary_titanunlocked" + +struct +{ + struct { + string playlistName = "" + int mapIdx = -1 + int modeIdx = -1 + } preCacheInfo + + array searchIconElems + array searchTextElems + array matchStartCountdownElems + array matchStatusRuis + + array creditsAvailableElems + + var chatroomMenu + var chatroomMenu_chatroomWidget + + var findGameButton + var inviteRoomButton + var inviteFriendsButton + var inviteFriendsToNetworkButton + var toggleMenuModeButton + + var networksMoreButton + + int inboxHeaderIndex + var inboxButton + + int customizeHeaderIndex + var pilotButton + var titanButton + var boostsButton + var storeButton + var storeNewReleasesButton + var storeBundlesButton + var factionButton + var bannerButton + var patchButton + var statsButton + var networksHeader + var settingsHeader + var storeHeader + var browseNetworkButton + var faqButton + var dpadCommsButton + + var genUpButton + + array lobbyButtons + var playHeader + var customizeHeader + var callsignHeader + + float timeToRestartMatchMaking = 0 + + string nextAutoMatchmakingPlaylist + + var callsignCard + + bool putPlayerInMatchmakingAfterDelay = false + float matchmakingStartTime = 0.0 + int etaTime = 0 + int etaMaxMinutes = 15 + string lastMixtapeMatchmakingStatus + + ComboStruct &lobbyComboStruct + + bool isFDMode = false + bool shouldAutoOpenFDMenu = false +} file + +void function MenuLobby_Init() +{ + PrecacheHUDMaterial( $"ui/menu/lobby/player_hover" ) + PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_player" ) + PrecacheHUDMaterial( $"ui/menu/lobby/chatroom_hover" ) + PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background" ) + PrecacheHUDMaterial( $"ui/menu/main_menu/motd_background_happyhour" ) + + AddUICallback_OnLevelInit( OnLobbyLevelInit ) +} + + +bool function ChatroomIsVisibleAndFocused() +{ + return Hud_IsVisible( file.chatroomMenu ) && Hud_IsFocused( file.chatroomMenu_chatroomWidget ); +} + +bool function ChatroomIsVisibleAndNotFocused() +{ + return Hud_IsVisible( file.chatroomMenu ) && !Hud_IsFocused( file.chatroomMenu_chatroomWidget ); +} + +void function Lobby_UpdateInboxButtons() +{ + var menu = GetMenu( "LobbyMenu" ) + if ( GetUIPlayer() == null || !IsPersistenceAvailable() ) + return + + bool hasNewMail = (Inbox_HasUnreadMessages() && Inbox_GetTotalMessageCount() > 0) || PlayerRandomUnlock_GetTotal( GetUIPlayer() ) > 0 + if ( hasNewMail ) + { + int messageCount = Inbox_GetTotalMessageCount() + int lootCount = PlayerRandomUnlock_GetTotal( GetUIPlayer() ) + int totalCount = messageCount + lootCount + + string countString + if ( totalCount >= MAX_MAIL_COUNT ) + countString = MAX_MAIL_COUNT + "+" + else + countString = string( totalCount ) + + SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS_NEW_MSGS", countString ) ) + ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_INBOX_NEW_MSGS", countString ) ) + } + else + { + SetComboButtonHeaderTitle( menu, file.inboxHeaderIndex, Localize( "#MENU_HEADER_NETWORKS" ) ) + ComboButton_SetText( file.inboxButton, Localize( "#MENU_TITLE_READ" ) ) + } + + ComboButton_SetNewMail( file.inboxButton, hasNewMail ) +} + +void function InitLobbyMenu() +{ + var menu = GetMenu( "LobbyMenu" ) + + InitOpenInvitesMenu() + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT", "", null, ChatroomIsVisibleAndNotFocused ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + AddMenuFooterOption( menu, BUTTON_BACK, "#BACK_BUTTON_POSTGAME_REPORT", "#POSTGAME_REPORT", OpenPostGameMenu, IsPostGameMenuValid ) + AddMenuFooterOption( menu, BUTTON_TRIGGER_RIGHT, "#R_TRIGGER_CHAT", "", null, IsVoiceChatPushToTalk ) + + InitChatroom( menu ) + + file.chatroomMenu = Hud_GetChild( menu, "ChatRoomPanel" ) + file.chatroomMenu_chatroomWidget = Hud_GetChild( file.chatroomMenu, "ChatRoom" ) + file.genUpButton = Hud_GetChild( menu, "GenUpButton" ) + + SetupComboButtonTest( menu ) + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnLobbyMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnLobbyMenu_Close ) + AddMenuEventHandler( menu, eUIEvent.MENU_NAVIGATE_BACK, OnLobbyMenu_NavigateBack ) + + RegisterUIVarChangeCallback( "gameStartTime", GameStartTime_Changed ) + + RegisterUIVarChangeCallback( "showGameSummary", ShowGameSummary_Changed ) + + file.searchIconElems = GetElementsByClassnameForMenus( "SearchIconClass", uiGlobal.allMenus ) + file.searchTextElems = GetElementsByClassnameForMenus( "SearchTextClass", uiGlobal.allMenus ) + file.matchStartCountdownElems = GetElementsByClassnameForMenus( "MatchStartCountdownClass", uiGlobal.allMenus ) + file.matchStatusRuis = GetElementsByClassnameForMenus( "MatchmakingStatusRui", uiGlobal.allMenus ) + file.creditsAvailableElems = GetElementsByClassnameForMenus( "CreditsAvailableClass", uiGlobal.allMenus ) + + file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) + + AddEventHandlerToButton( menu, "GenUpButton", UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "Generation_Respawn" ) ) ) + + AddMenuVarChangeHandler( "focus", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isFullyConnected", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isPartyLeader", UpdateFooterOptions ) + AddMenuVarChangeHandler( "isPrivateMatch", UpdateFooterOptions ) + #if DURANGO_PROG + AddMenuVarChangeHandler( "DURANGO_canInviteFriends", UpdateFooterOptions ) + AddMenuVarChangeHandler( "DURANGO_isJoinable", UpdateFooterOptions ) + AddMenuVarChangeHandler( "DURANGO_isGameFullyInstalled", UpdateFooterOptions ) + #elseif PS4_PROG + AddMenuVarChangeHandler( "PS4_canInviteFriends", UpdateFooterOptions ) + #elseif PC_PROG + AddMenuVarChangeHandler( "ORIGIN_isEnabled", UpdateFooterOptions ) + AddMenuVarChangeHandler( "ORIGIN_isJoinable", UpdateFooterOptions ) + #endif + + RegisterSignal( "BypassWaitBeforeRestartingMatchmaking" ) + RegisterSignal( "PutPlayerInMatchmakingAfterDelay" ) + RegisterSignal( "CancelRestartingMatchmaking" ) + RegisterSignal( "LeaveParty" ) +} + +void function SetupComboButtonTest( var menu ) +{ + ComboStruct comboStruct = ComboButtons_Create( menu ) + file.lobbyComboStruct = comboStruct + + int headerIndex = 0 + int buttonIndex = 0 + file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" ) + + bool isModded = IsNorthstarServer() + + + // this will be the server browser + if ( isModded ) + { + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_SetLocked( file.findGameButton, true ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser ) + } + else + { + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) + } + + // this is used for launching private matches now + if ( isModded ) + { + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) + } + else + { + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) + } + + file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) + Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed ) + + if ( isModded ) + { + Hud_SetEnabled( file.inviteFriendsButton, false ) + Hud_SetVisible( file.inviteFriendsButton, false ) + } + + // file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" ) + // Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode ) + + headerIndex++ + buttonIndex = 0 + file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" ) + file.customizeHeaderIndex = headerIndex + var pilotButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PILOT" ) + file.pilotButton = pilotButton + file.lobbyButtons.append( pilotButton ) + Hud_AddEventHandler( pilotButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditPilotLoadoutsMenu" ) ) ) + var titanButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_TITAN" ) + file.titanButton = titanButton + Hud_AddEventHandler( titanButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditTitanLoadoutsMenu" ) ) ) + file.boostsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BOOSTS" ) + Hud_AddEventHandler( file.boostsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "BurnCardMenu" ) ) ) + + headerIndex++ + buttonIndex = 0 + file.callsignHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_CALLSIGN" ) + file.bannerButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_BANNER" ) + file.lobbyButtons.append( file.bannerButton ) + Hud_AddEventHandler( file.bannerButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignCardSelectMenu" ) ) ) + file.patchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_PATCH" ) + Hud_AddEventHandler( file.patchButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "CallsignIconSelectMenu" ) ) ) + file.factionButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FACTION" ) + Hud_AddEventHandler( file.factionButton, UIE_CLICK, Lobby_CallsignButton3EventHandler ) + file.statsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STATS" ) + Hud_AddEventHandler( file.statsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ViewStatsMenu" ) ) ) + + file.callsignCard = Hud_GetChild( menu, "CallsignCard" ) + + headerIndex++ + buttonIndex = 0 + file.networksHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_NETWORKS" ) + file.inboxHeaderIndex = headerIndex + var networksInbox = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INBOX" ) + file.inboxButton = networksInbox + file.lobbyButtons.append( networksInbox ) + Hud_AddEventHandler( networksInbox, UIE_CLICK, OnInboxButton_Activate ) + var switchButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_SWITCHCOMMUNITY" ) + Hud_AddEventHandler( switchButton, UIE_CLICK, OnSwitchButton_Activate ) + var browseButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#COMMUNITY_BROWSE_NETWORKS" ) + file.lobbyButtons.append( browseButton ) + Hud_AddEventHandler( browseButton, UIE_CLICK, OnBrowseNetworksButton_Activate ) + file.browseNetworkButton = browseButton + #if NETWORK_INVITE + file.inviteFriendsToNetworkButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#INVITE_FRIENDS" ) + file.lobbyButtons.append( file.inviteFriendsToNetworkButton ) + Hud_AddEventHandler( file.inviteFriendsToNetworkButton, UIE_CLICK, OnInviteFriendsToNetworkButton_Activate ) + #endif + + headerIndex++ + buttonIndex = 0 + file.storeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_STORE" ) + SetComboButtonHeaderTint( GetMenu( "LobbyMenu" ), headerIndex, true ) + file.storeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BROWSE" ) + Hud_AddEventHandler( file.storeButton, UIE_CLICK, OnStoreButton_Activate ) + file.storeNewReleasesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_NEW_RELEASES" ) + Hud_AddEventHandler( file.storeNewReleasesButton, UIE_CLICK, OnStoreNewReleasesButton_Activate ) + file.storeBundlesButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_STORE_BUNDLES" ) + Hud_AddEventHandler( file.storeBundlesButton, UIE_CLICK, OnStoreBundlesButton_Activate ) + + headerIndex++ + buttonIndex = 0 + file.settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + file.lobbyButtons.append( controlsButton ) + #if CONSOLE_PROG + var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) + Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) + #elseif PC_PROG + var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) + Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) + var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) + Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) + #endif + file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) + Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) + + comboStruct.navUpButtonDisabled = true + comboStruct.navDownButton = file.genUpButton + + ComboButtons_Finalize( comboStruct ) +} + +bool function MatchResultsExist() +{ + return true // TODO +} + +void function StartPrivateMatch( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + ClientCommand( "StartPrivateMatchSearch" ) +} + +void function DoRoomInviteIfAllowed( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + if ( !DoesCurrentCommunitySupportInvites() ) + { + OnBrowseNetworksButton_Activate( button ) + return + } + + entity player = GetUIPlayer() + + if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) + { + DisplayMatchmakingPenaltyDialog( player ) + return + } + + SendOpenInvite( true ) + OpenSelectedPlaylistMenu() +} + +void function DisplayMatchmakingPenaltyDialog( entity player ) +{ + int minutesRemaining = int( ceil( Player_GetRemainingMatchmakingDelay( player ) / 60) ) + if ( minutesRemaining <= 1 ) + ServerCallback_GenericDialog( 30, 31, true ) + else if ( minutesRemaining == 2 ) + ServerCallback_GenericDialog( 30, 32, true ) + else if ( minutesRemaining == 3 ) + ServerCallback_GenericDialog( 30, 33, true ) + else if ( minutesRemaining == 4 ) + ServerCallback_GenericDialog( 30, 34, true ) + else if ( minutesRemaining == 5 ) + ServerCallback_GenericDialog( 30, 35, true ) + else + ServerCallback_GenericDialog( 30, 36, true ) +} + +void function CreatePartyAndInviteFriends() +{ + if ( CanInvite() ) + { + while ( !PartyHasMembers() && !AmIPartyLeader() ) + { + ClientCommand( "createparty" ) + WaitFrameOrUntilLevelLoaded() + } + InviteFriends( file.inviteFriendsButton ) + } + else + { + printt( "Not inviting friends - CanInvite() returned false" ); + } +} + +void function ToggleLobbyMode( var button ) +{ + Lobby_ToggleFDMode() +} + +void function Lobby_ToggleFDMode() +{ + Hud_SetFocused( file.findGameButton ) + ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) + file.isFDMode = !file.isFDMode + Lobby_RefreshButtons() +} + +void function Lobby_CallsignButton3EventHandler( var button ) +{ + if ( Lobby_IsFDMode() ) + { + AdvanceMenu( GetMenu( "ViewStatsMenu" ) ) + } + else + { + AdvanceMenu( GetMenu( "FactionChoiceMenu" ) ) + } +} + +void function InviteFriendsIfAllowed( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + entity player = GetUIPlayer() + if ( IsValid( player ) && Player_NextAvailableMatchmakingTime( player ) > 0 ) + { + DisplayMatchmakingPenaltyDialog( player ) + return + } + + #if PC_PROG + if ( !Origin_IsOverlayAvailable() ) + { + PopUpOriginOverlayDisabledDialog() + return + } + #endif + + thread CreatePartyAndInviteFriends() +} + +bool function CanInvite() +{ + if ( Player_NextAvailableMatchmakingTime( GetUIPlayer() ) > 0 ) + return false + +#if DURANGO_PROG + return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "DURANGO_canInviteFriends" ) && GetMenuVarBool( "DURANGO_isJoinable" ) && GetMenuVarBool( "DURANGO_isGameFullyInstalled" ) ) + #elseif PS4_PROG + return GetMenuVarBool( "PS4_canInviteFriends" ) + #elseif PC_PROG + return ( GetMenuVarBool( "isFullyConnected" ) && GetMenuVarBool( "ORIGIN_isEnabled" ) && GetMenuVarBool( "ORIGIN_isJoinable" ) && Origin_IsOverlayAvailable() ) + #endif +} + +void function Lobby_RefreshButtons() +{ + bool fdMode = Lobby_IsFDMode() + var menu = GetMenu( "LobbyMenu" ) + + if ( GetTopNonDialogMenu() == GetMenu( "LobbyMenu" ) ) + { + if ( fdMode ) + UI_SetPresentationType( ePresentationType.FD_MAIN ) + else + UI_SetPresentationType( ePresentationType.DEFAULT ) + } + + string buttonString = fdMode ? "#MENU_LOBBY_SWITCH_DEFAULT" : "#MENU_LOBBY_SWITCH_FD" + // ComboButton_SetText( file.toggleMenuModeButton, buttonString ) + + buttonString = fdMode ? "" : "#MENU_TITLE_BOOSTS" + Hud_SetEnabled( file.boostsButton, !fdMode ) + ComboButton_SetText( file.boostsButton, buttonString ) + + buttonString = fdMode ? "#MENU_TITLE_STATS" : "#MENU_TITLE_FACTION" + ComboButton_SetText( file.factionButton, buttonString ) + + buttonString = fdMode ? "" : "#MENU_TITLE_STATS" + Hud_SetEnabled( file.statsButton, !fdMode ) + ComboButton_SetText( file.statsButton, buttonString ) + + buttonString = fdMode ? "#MENU_HEADER_PLAY_FD" : "#MENU_HEADER_PLAY" + SetComboButtonHeaderTitle( menu, 0, buttonString ) + + if ( fdMode ) + Hud_Hide( Hud_GetChild( menu, "ImgTopBar" ) ) + else + Hud_Show( Hud_GetChild( menu, "ImgTopBar" ) ) + + ComboButtons_ResetColumnFocus( file.lobbyComboStruct ) + + if ( fdMode ) + { + Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "" ) + } + else + { + Hud_SetText( Hud_GetChild( menu, "MenuTitle" ), "#MULTIPLAYER" ) + } +} + +void function OnLobbyMenu_Open() +{ + Assert( IsConnected() ) + + // code will start loading DLC info from first party unless already done + InitDLCStore() + + thread UpdateCachedNewItems() + if ( file.putPlayerInMatchmakingAfterDelay ) + { + entity player = GetUIPlayer() + if (IsValid( player )) + { + string playlistToSearch = expect string( player.GetPersistentVar( "lastPlaylist" ) ) + string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() + if ( nextAutoPlaylist.len() > 0 ) + playlistToSearch = nextAutoPlaylist + + Lobby_SetFDModeBasedOnSearching( playlistToSearch ) + } + AdvanceMenu( GetMenu( "SearchMenu" ) ) + thread PutPlayerInMatchmakingAfterDelay() + file.putPlayerInMatchmakingAfterDelay = false + } + else if ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) ) + Lobby_SetFDMode( false ) + + thread UpdateLobbyUI() + thread LobbyMenuUpdate( GetMenu( "LobbyMenu" ) ) + + Hud_Show( file.chatroomMenu ) + + Lobby_RefreshButtons() + + if ( IsFullyConnected() ) + { + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + + while ( IsPersistenceAvailable() && (player.GetPersistentVarAsInt( "initializedVersion" ) < PERSISTENCE_INIT_VERSION) ) + { + WaitFrame() + } + if ( !IsPersistenceAvailable() ) + return + + // Clear hidden boosts + array boosts = GetAllItemsOfType( eItemTypes.BURN_METER_REWARD ) + foreach ( boost in boosts ) + { + if ( boost.hidden ) + { + ClearNewStatus( null, boost.ref ) + } + } + + UpdateCallsignElement( file.callsignCard ) + RefreshCreditsAvailable() + + bool emotesAreEnabled = EmotesEnabled() + // "Customize" + { + bool anyNewPilotItems = HasAnyNewPilotItems( player ) + bool anyNewTitanItems = HasAnyNewTitanItems( player ) + bool anyNewBoosts = HasAnyNewBoosts( player ) + bool anyNewCommsIcons = emotesAreEnabled ? HasAnyNewDpadCommsIcons( player ) : false + bool anyNewCustomizeHeader = (anyNewPilotItems || anyNewTitanItems || anyNewBoosts || anyNewCommsIcons) + + RuiSetBool( Hud_GetRui( file.customizeHeader ), "isNew", anyNewCustomizeHeader ) + ComboButton_SetNew( file.pilotButton, anyNewPilotItems ) + ComboButton_SetNew( file.titanButton, anyNewTitanItems ) + ComboButton_SetNew( file.boostsButton, anyNewBoosts ) + } + + // "Store" + { + bool storeIsNew = DLCStoreShouldBeMarkedAsNew() + RuiSetBool( Hud_GetRui( file.storeHeader ), "isNew", storeIsNew ) + ComboButton_SetNew( file.storeButton, storeIsNew ) + } + + // "Callsign" + { + bool anyNewBanners = HasAnyNewCallsignBanners( player ) + bool anyNewPatches = HasAnyNewCallsignPatches( player ) + bool anyNewFactions = HasAnyNewFactions( player ) && Lobby_IsFDMode() + bool anyNewCallsignHeader = (anyNewBanners || anyNewPatches || anyNewFactions) + + RuiSetBool( Hud_GetRui( file.callsignHeader ), "isNew", anyNewCallsignHeader ) + ComboButton_SetNew( file.bannerButton, anyNewBanners ) + ComboButton_SetNew( file.patchButton, anyNewPatches ) + ComboButton_SetNew( file.factionButton, anyNewFactions ) + } + + bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew ) + + TryUnlockSRSCallsign() + + Lobby_UpdateInboxButtons() + + if ( file.shouldAutoOpenFDMenu ) + { + file.shouldAutoOpenFDMenu = false + AdvanceMenu( GetMenu( GetPlaylistMenuName() ) ) + AdvanceMenu( GetMenu( "FDMenu" ) ) + } + } +} + +bool function DLCStoreShouldBeMarkedAsNew() +{ + if ( !IsFullyConnected() ) + return false + + if ( !IsPersistenceAvailable() ) + return false + + bool hasSeenStore = expect bool( GetPersistentVar( "hasSeenStore" ) ) + bool result = (!hasSeenStore) + return result +} + +void function LobbyMenuUpdate( var menu ) +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + while ( GetTopNonDialogMenu() == menu ) + { + bool inPendingOpenInvite = InPendingOpenInvite() + Hud_SetLocked( file.findGameButton, !IsPartyLeader() || inPendingOpenInvite ) + Hud_SetLocked( file.inviteRoomButton, IsOpenInviteVisible() || GetPartySize() > 1 || inPendingOpenInvite ) + Hud_SetLocked( file.inviteFriendsButton, inPendingOpenInvite ) + + bool canGenUp = false + if ( GetUIPlayer() ) + canGenUp = GetPersistentVarAsInt( "xp" ) == GetMaxPlayerXP() && GetGen() < MAX_GEN + + Hud_SetVisible( file.genUpButton, canGenUp ) + Hud_SetEnabled( file.genUpButton, canGenUp ) + + WaitFrame() + } +} + +void function SetNextAutoMatchmakingPlaylist( string playlistName ) +{ + file.nextAutoMatchmakingPlaylist = playlistName +} + +string function GetNextAutoMatchmakingPlaylist() +{ + return file.nextAutoMatchmakingPlaylist +} + +void function PutPlayerInMatchmakingAfterDelay() +{ + Signal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) + EndSignal( uiGlobal.signalDummy, "PutPlayerInMatchmakingAfterDelay" ) + EndSignal( uiGlobal.signalDummy, "CancelRestartingMatchmaking" ) + EndSignal( uiGlobal.signalDummy, "LeaveParty" ) + EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + if ( AreWeMatchmaking() ) //Party member, party leader is already searching + return + + entity player = GetUIPlayer() + if ( !player ) + return + + string lastPlaylist = expect string( player.GetPersistentVar( "lastPlaylist" ) ) + + //Bump player out of match making if they were playing coliseum and are out of tickets. + if ( ("coliseum" == lastPlaylist) && Player_GetColiseumTicketCount( GetLocalClientPlayer() ) <= 0 ) + { + SetNextAutoMatchmakingPlaylist( "" ) + return + } + + // Need to know if you were a party member before the countdown starts in case you leave + bool wasAPartyMemberThatIsNotLeader = AmIPartyMember() + waitthread WaitBeforeRestartingMatchmaking() + // Only the leader should proceed to start matchmaking + if ( wasAPartyMemberThatIsNotLeader ) + return + + if ( !Console_HasPermissionToPlayMultiplayer() ) + { + ClientCommand( "disconnect" ) + return + } + + string playlistToSearch = lastPlaylist + string nextAutoPlaylist = GetNextAutoMatchmakingPlaylist() + if ( nextAutoPlaylist.len() > 0 ) + playlistToSearch = nextAutoPlaylist + + StartMatchmakingPlaylists( playlistToSearch ) +} + +void function WaitBeforeRestartingMatchmaking() +{ + Signal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) + EndSignal( uiGlobal.signalDummy, "BypassWaitBeforeRestartingMatchmaking" ) + + float timeToWait + + bool isPartyMemberThatIsNotLeader = AmIPartyMember() + SetPutPlayerInMatchmakingAfterDelay( !isPartyMemberThatIsNotLeader ) + + if ( isPartyMemberThatIsNotLeader ) + timeToWait = 99999 //HACK, JFS + else + timeToWait = GetCurrentPlaylistVarFloat( "wait_before_restarting_matchmaking_time", 30.0 ) + + float timeToEnd = Time() + timeToWait + + UpdateTimeToRestartMatchmaking( timeToEnd ) + + OnThreadEnd( + function() : ( ) + { + UpdateTimeToRestartMatchmaking( 0.0 ) + UpdateFooterOptions() + } + ) + + if ( isPartyMemberThatIsNotLeader ) + { + while( Time() < timeToEnd ) //Hack hack, JFS. No appropriate signals for StartMatchmaking() being called. Replace when code gives us notifications about it + { + if ( isPartyMemberThatIsNotLeader != ( AmIPartyMember() ) ) //Party Status changed. Party leader probably left? + break + + if ( AreWeMatchmaking() ) //Need to break out if Party Leader brings us into matchmaking + break + + WaitFrame() + } + + } + else + { + wait timeToWait + } +} + +void function OnLobbyMenu_Close() +{ + Signal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) +} + +void function OnLobbyMenu_NavigateBack() +{ + if ( ChatroomIsVisibleAndFocused() ) + { + foreach ( button in file.lobbyButtons ) + { + if ( Hud_IsVisible( button ) && Hud_IsEnabled( button ) && !Hud_IsLocked( button ) ) + { + Hud_SetFocused( button ) + return + } + } + } + + if ( InPendingOpenInvite() ) + LeaveOpenInvite() + else + LeaveDialog() +} + +function GameStartTime_Changed() +{ + UpdateGameStartTimeCounter() +} + +function ShowGameSummary_Changed() +{ + if ( level.ui.showGameSummary ) + uiGlobal.EOGOpenInLobby = true +} + +function UpdateGameStartTimeCounter() +{ + if ( level.ui.gameStartTime == null ) + return + + MatchmakingSetSearchText( "#STARTING_IN_LOBBY" ) + MatchmakingSetCountdownTimer( expect float( level.ui.gameStartTime + 0.0 ), true ) + + HideMatchmakingStatusIcons() +} + +bool function MatchmakingStatusShouldShowAsActiveSearch( string matchmakingStatus ) +{ + if ( matchmakingStatus == "#MATCHMAKING_QUEUED" ) + return true + if ( matchmakingStatus == "#MATCHMAKING_ALLOCATING_SERVER" ) + return true + if ( matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" ) + return true + + return false +} + +string function GetActiveSearchingPlaylist() +{ + if ( !IsConnected() ) + return "" + if ( !AreWeMatchmaking() ) + return "" + + string matchmakingStatus = GetMyMatchmakingStatus() + if ( !MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) + return "" + + string param1 = GetMyMatchmakingStatusParam( 1 ) + return param1 +} + +float function CalcMatchmakingWaitTime() +{ + float result = ((file.matchmakingStartTime > 0.01) ? (Time() - file.matchmakingStartTime) : 0.0) + return result +} + +float function GetMixtapeWaitTimeForPlaylist( string playlistName ) +{ + float maxWaitTime = float( GetPlaylistVarOrUseValue( playlistName, "mixtape_timeout", "0" ) ) + return maxWaitTime +} + +void function UpdateRestartMatchmakingStatus( float time ) +{ + if ( AmIPartyMember() ) + { + MatchmakingSetSearchText( "#MATCHMAKING_WAIT_ON_PARTY_LEADER_RESTARTING_MATCHMAKING" ) + } + else + { + string statusText = "#MATCHMAKING_WAIT_BEFORE_RESTARTING_MATCHMAKING" + string matchmakeNowText = "" + if ( uiGlobal.activeMenu == GetMenu( "SearchMenu" ) ) + matchmakeNowText = Localize( "#MATCHMAKING_WAIT_MATCHMAKE_NOW" ) + MatchmakingSetSearchText( statusText, matchmakeNowText ) + MatchmakingSetCountdownTimer( time, false ) + } +} + +void function UpdateMatchmakingStatus() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + OnThreadEnd( + function() : () + { + printt( "Hiding all matchmaking elems due to UpdateMatchmakingStatus thread ending" ) + + HideMatchmakingStatusIcons() + + MatchmakingSetSearchText( "" ) + MatchmakingSetCountdownTimer( 0.0, true ) + + MatchmakingSetSearchVisible( false ) + MatchmakingSetCountdownVisible( false ) + } + ) + + MatchmakingSetSearchVisible( true ) + MatchmakingSetCountdownVisible( true ) + + var lobbyMenu = GetMenu( "LobbyMenu" ) + var searchMenu = GetMenu( "SearchMenu" ) + var postGameMenu = GetMenu( "PostGameMenu" ) + + string lastActiveSearchingPlaylist + file.matchmakingStartTime = 0.0 + file.etaTime = 0 + file.etaMaxMinutes = int( GetCurrentPlaylistVarOrUseValue( "etaMaxMinutes", file.etaMaxMinutes ) ) + file.lastMixtapeMatchmakingStatus = "" + + while ( true ) + { + int lobbyType = GetLobbyTypeScript() + string matchmakingStatus = GetMyMatchmakingStatus() + bool isConnectingToMatch = matchmakingStatus == "#MATCHMAKING_MATCH_CONNECTING" + + { + string activeSearchingPlaylist = GetActiveSearchingPlaylist() + if ( lastActiveSearchingPlaylist != activeSearchingPlaylist ) + { + if ( activeSearchingPlaylist.len() > 0 ) + { + lastActiveSearchingPlaylist = activeSearchingPlaylist + file.matchmakingStartTime = Time() + } + else + { + lastActiveSearchingPlaylist = "" + file.matchmakingStartTime = 0.0 + } + } + + if ( isConnectingToMatch && (matchmakingStatus != file.lastMixtapeMatchmakingStatus) ) + { + EmitUISound( MATCHMAKING_AUDIO_CONNECTING ) + + int mixtape_version = GetMixtapeMatchmakingVersion() + if ( IsMixtapeVersionNew() ) + LogMixtapeHasNew( mixtape_version ) + } + + file.lastMixtapeMatchmakingStatus = matchmakingStatus + } + + if ( level.ui.gameStartTime != null || lobbyType == eLobbyType.PRIVATE_MATCH ) + { + if ( level.ui.gameStartTimerComplete ) + { + MatchmakingSetSearchText( matchmakingStatus, GetMyMatchmakingStatusParam( 1 ), GetMyMatchmakingStatusParam( 2 ), GetMyMatchmakingStatusParam( 3 ), GetMyMatchmakingStatusParam( 4 ) ) + } + + if ( uiGlobal.activeMenu == searchMenu ) + CloseActiveMenu() + } + else if ( GetTimeToRestartMatchMaking() > 0 ) + { + UpdateRestartMatchmakingStatus( GetTimeToRestartMatchMaking() ) + } + else if ( level.ui.gameStartTime == null ) + { + MatchmakingSetCountdownTimer( 0.0, true ) + MatchmakingSetSearchText( "" ) + HideMatchmakingStatusIcons() + + if ( !IsConnected() || !AreWeMatchmaking() ) + { + if ( uiGlobal.activeMenu == searchMenu ) + CloseActiveMenu() + } + else + { + ShowMatchmakingStatusIcons() + + if ( GetActiveMenu() == lobbyMenu && !IsMenuInMenuStack( searchMenu ) ) + { + CloseAllDialogs() + AdvanceMenu( searchMenu ) + } + + var statusEl = Hud_GetChild( searchMenu, "MatchmakingStatusBig" ) + if ( matchmakingStatus == "#MATCH_NOTHING" ) + { + Hud_Hide( statusEl ) + } + else if ( MatchmakingStatusShouldShowAsActiveSearch( matchmakingStatus ) ) + { + string playlistName = GetMyMatchmakingStatusParam( 1 ) + int etaSeconds = int( GetMyMatchmakingStatusParam( 2 ) ) + int mapIdx = int( GetMyMatchmakingStatusParam( 3 ) ) + int modeIdx = int( GetMyMatchmakingStatusParam( 4 ) ) + string playlistList = GetMyMatchmakingStatusParam( 5 ) + + { + string statusText = Localize( "#MATCHMAKING_PLAYLISTS" ) + RuiSetString( Hud_GetRui( statusEl ), "statusText", statusText ) + for ( int idx = 1; idx <= 5; ++idx ) + RuiSetString( Hud_GetRui( statusEl ), ("bulletPointText" + idx), "" ) + + const int MAX_SHOWN_PLAYLISTS = 9 + array< string > searchingPlaylists = split( playlistList, "," ) + int searchingCount = minint( searchingPlaylists.len(), MAX_SHOWN_PLAYLISTS ) + RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", searchingCount ) + for( int idx = 0; idx < searchingCount; ++idx ) + { + asset playlistThumbnail = GetPlaylistThumbnailImage( searchingPlaylists[idx] ) + RuiSetImage( Hud_GetRui( statusEl ), format( "playlistIcon%d", idx ), playlistThumbnail ) + } + } + + Hud_Show( statusEl ) + + if ( mapIdx > -1 && modeIdx > -1 ) + { + if ( file.preCacheInfo.playlistName != playlistName || file.preCacheInfo.mapIdx != mapIdx || file.preCacheInfo.modeIdx != modeIdx ) + { + file.preCacheInfo.playlistName = playlistName + file.preCacheInfo.mapIdx = mapIdx + file.preCacheInfo.modeIdx = modeIdx + } + } + + string etaStr = "" + if ( !etaSeconds && !isConnectingToMatch ) + { + matchmakingStatus = "#MATCHMAKING_SEARCHING_FOR_MATCH" + } + else + { + int now = int( Time() ) + int etaTime = now + etaSeconds + if ( !file.etaTime || etaTime < file.etaTime ) + file.etaTime = etaTime + + int etaSeconds = file.etaTime - now + if ( etaSeconds <= 0 ) + file.etaTime = etaTime + + etaSeconds = file.etaTime - now + if ( etaSeconds <= 90 ) + { + etaStr = Localize( "#MATCHMAKING_ETA_SECONDS", etaSeconds ) + } + else + { + int etaMinutes = int( ceil( etaSeconds / 60.0 ) ) + if ( etaMinutes < file.etaMaxMinutes ) + etaStr = Localize( "#MATCHMAKING_ETA_MINUTES", etaMinutes ) + else + etaStr = Localize( "#MATCHMAKING_ETA_UNKNOWN", etaMinutes ) + } + } + + MatchmakingSetSearchText( matchmakingStatus, etaStr ) + } + else + { + Hud_Show( statusEl ) + RuiSetString( Hud_GetRui( statusEl ), "statusText", "" ) + RuiSetInt( Hud_GetRui( statusEl ), "playlistCount", 0 ) + } + } + } + + WaitFrameOrUntilLevelLoaded() + } +} + +void function UpdateAnnouncementDialog() +{ + while ( IsLobby() && IsFullyConnected() ) + { + // Only safe on these menus. Not safe if these variables are true because they indicate the search menu or postgame menu are going to be opened. + if ( ( uiGlobal.activeMenu == GetMenu( "LobbyMenu" ) || uiGlobal.activeMenu == GetMenu( "PrivateLobbyMenu" ) ) && !file.putPlayerInMatchmakingAfterDelay && !uiGlobal.EOGOpenInLobby ) + { + entity player = GetUIPlayer() + + // Only initialize here, CloseAnnouncementDialog() handles setting it when closing + if ( uiGlobal.announcementVersionSeen == -1 ) + uiGlobal.announcementVersionSeen = player.GetPersistentVarAsInt( "announcementVersionSeen" ) + + int announcementVersion = GetConVarInt( "announcementVersion" ) + if ( announcementVersion > uiGlobal.announcementVersionSeen ) + { + OpenAnnouncementDialog() + } + else if ( uiGlobal.activeMenu != "AnnouncementDialog" && ShouldShowEmotesAnnouncement( player ) ) + { + OpenCommsIntroDialog() + } + } + + WaitFrame() + } +} + +bool function CurrentMenuIsPVEMenu() +{ + var topMenu = GetTopNonDialogMenu() + if ( topMenu == null ) + return false + + return (uiGlobal.menuData[topMenu].isPVEMenu) +} + +void function RefreshCreditsAvailable( int creditsOverride = -1 ) +{ + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + if ( !IsPersistenceAvailable() ) + return + + int credits = creditsOverride >= 0 ? creditsOverride : GetAvailableCredits( GetLocalClientPlayer() ) + string pveTitle = "" + int pveCredits = 0 + bool isPVE = CurrentMenuIsPVEMenu() + if ( isPVE ) + { + TitanLoadoutDef loadout = GetCachedTitanLoadout( uiGlobal.editingLoadoutIndex ) + pveCredits = GetAvailableFDUnlockPoints( player, loadout.titanClass ) + pveTitle = GetTitanLoadoutName( loadout ) + } + + foreach ( elem in file.creditsAvailableElems ) + { + SetUIPlayerCreditsInfo( elem, credits, GetLocalClientPlayer().GetXP(), GetGen(), GetLevel(), GetNextLevel( GetLocalClientPlayer() ), isPVE, pveCredits, pveTitle ) + } +} + +void function SetUIPlayerCreditsInfo( var infoElement, int credits, int xp, int gen, int level, int nextLevel, bool isPVE, int pveCredits, string pveTitle ) +{ + var rui = Hud_GetRui( infoElement ) + RuiSetInt( rui, "credits", credits ) + RuiSetString( rui, "nameText", GetPlayerName() ) + + RuiSetBool( rui, "isPVE", isPVE ) + if ( isPVE ) + { + RuiSetInt( rui, "pveCredits", pveCredits ) + RuiSetString( rui, "pveTitle", pveTitle ) + } + + if ( xp == GetMaxPlayerXP() && gen < MAX_GEN ) + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", Localize( "#REGEN_AVAILABLE" ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) + RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) + } + else if ( xp == GetMaxPlayerXP() && gen == MAX_GEN ) + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", Localize( "#MAX_GEN" ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level - 1 ) ) + RuiSetInt( rui, "filledLevelPips", GetXPPipsForLevel( level - 1 ) ) + } + else + { + RuiSetString( rui, "levelText", PlayerXPDisplayGenAndLevel( gen, level ) ) + RuiSetString( rui, "nextLevelText", PlayerXPDisplayGenAndLevel( gen, nextLevel ) ) + RuiSetInt( rui, "numLevelPips", GetXPPipsForLevel( level ) ) + RuiSetInt( rui, "filledLevelPips", GetXPFilledPipsForXP( xp ) ) + } + + CallsignIcon callsignIcon = PlayerCallsignIcon_GetActive( GetLocalClientPlayer() ) + + RuiSetImage( rui, "callsignIcon", callsignIcon.image ) +} + +void function OpenServerBrowser( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + // nothing here yet lol + // look at OpenSelectedPlaylistMenu for advancing to server browser menu probably + // AdvanceMenu( GetMenu( "ServerBrowser ) ) i guess? idk +} + +void function BigPlayButton1_Activate( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + SendOpenInvite( false ) + OpenSelectedPlaylistMenu() +} + +function EnableButton( button ) +{ + Hud_SetEnabled( button, true ) + Hud_Show( button ) +} + +function DisableButton( button ) +{ + Hud_SetEnabled( button, false ) + Hud_Hide( button ) +} + +void function OpenSelectedPlaylistMenu() +{ + if ( Lobby_IsFDMode() ) + { + AdvanceMenu( GetMenu( "FDMenu" ) ) + } + else + { + string playlistMenuName = GetPlaylistMenuName() + AdvanceMenu( GetMenu( playlistMenuName ) ) + } +} + +function UpdateLobbyUI() +{ + if ( uiGlobal.updatingLobbyUI ) + return + uiGlobal.updatingLobbyUI = true + + thread UpdateLobbyType() + thread UpdateMatchmakingStatus() + thread UpdateChatroomThread() + //thread UpdateInviteJoinButton() + thread UpdateInviteFriendsToNetworkButton() + thread UpdatePlayerInfo() + + if ( uiGlobal.menuToOpenFromPromoButton != null ) + { + // Special case because this menu needs a few properties set before opening + + if ( IsStoreMenu( uiGlobal.menuToOpenFromPromoButton ) ) + { + string menuName = expect string( uiGlobal.menuToOpenFromPromoButton._name ) + + void functionref() preOpenfunc = null + if ( uiGlobal.menuToOpenFromPromoButton == GetMenu( "StoreMenu_WeaponSkins" ) ) // Hardcoded special case for now + preOpenfunc = DefaultToDLC11WeaponWarpaintBundle + + OpenStoreMenu( [ menuName ], preOpenfunc ) + } + else + { + AdvanceMenu( uiGlobal.menuToOpenFromPromoButton ) + } + + uiGlobal.menuToOpenFromPromoButton = null + } + else if ( uiGlobal.EOGOpenInLobby ) + { + EOGOpen() + } + + WaitSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + uiGlobal.updatingLobbyUI = false +} + +void function UpdateInviteJoinButton() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + var menu = GetMenu( "LobbyMenu" ) + + while ( true ) + { + if ( DoesCurrentCommunitySupportInvites() ) + ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_INVITE_ROOM" ) ) + else + ComboButton_SetText( file.inviteRoomButton, Localize( "#MENU_TITLE_JOIN_NETWORK" ) ) + + WaitFrame() + } +} + +void function UpdateInviteFriendsToNetworkButton() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + var menu = GetMenu( "LobbyMenu" ) + + while ( true ) + { + bool areInvitesToNetworkNotAllowed = !DoesCurrentCommunitySupportChat() + if ( areInvitesToNetworkNotAllowed || ( IsCurrentCommunityInviteOnly() && !AreWeAdminInCurrentCommunity() ) ) + DisableButton( file.inviteFriendsToNetworkButton ) + else + EnableButton( file.inviteFriendsToNetworkButton ) + + WaitFrame() + } +} + +function UpdateLobbyType() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + var menu = GetMenu( "LobbyMenu" ) + int lobbyType + local lastType + local partySize + local lastPartySize + local debugArray = [ "SOLO", "PARTY_LEADER", "PARTY_MEMBER", "MATCH", "PRIVATE_MATCH" ] // Must match enum + + WaitFrameOrUntilLevelLoaded() + + while ( true ) + { + lobbyType = GetLobbyTypeScript() + partySize = GetPartySize() + + if ( IsConnected() && ((lobbyType != lastType) || (partySize != lastPartySize)) ) + { + if ( lastType == null ) + printt( "Lobby lobbyType changing from:", lastType, "to:", debugArray[lobbyType] ) + else + printt( "Lobby lobbyType changing from:", debugArray[lastType], "to:", debugArray[lobbyType] ) + + local animation = null + + switch ( lobbyType ) + { + case eLobbyType.SOLO: + animation = "SoloLobby" + break + + case eLobbyType.PARTY_LEADER: + animation = "PartyLeaderLobby" + break + + case eLobbyType.PARTY_MEMBER: + animation = "PartyMemberLobby" + break + + case eLobbyType.MATCH: + animation = "MatchLobby" + break + + case eLobbyType.PRIVATE_MATCH: + animation = "PrivateMatchLobby" + break + } + + if ( animation != null ) + { + menu.RunAnimationScript( animation ) + } + + // Force the animation scripts (which have zero duration) to complete before anything can cancel them. + ForceUpdateHUDAnimations() + + lastType = lobbyType + lastPartySize = partySize + } + + WaitFrameOrUntilLevelLoaded() + } +} + +void function UICodeCallback_CommunityUpdated() +{ + Community_CommunityUpdated() + UpdateChatroomUI() +} + +void function UICodeCallback_FactionUpdated() +{ + printt( "Faction changed! to " + GetCurrentFaction() ); +} + +void function UICodeCallback_SetupPlayerListGenElements( table params, int gen, int rank, bool isPlayingRanked, int pilotClassIndex ) +{ + params.image = "" + params.label = "" + params.imageOverlay = "" +} + +float function GetTimeToRestartMatchMaking() +{ + return file.timeToRestartMatchMaking +} + +void function UpdateTimeToRestartMatchmaking( float time )//JFS: This uses UI time instead of server time, which leads to awkwardness in MatchmakingSetCountdownTimer() and the rui involved +{ + file.timeToRestartMatchMaking = time + + if ( time > 0 ) + { + UpdateRestartMatchmakingStatus( time ) + ShowMatchmakingStatusIcons() + } + else + { + MatchmakingSetSearchText( "" ) + MatchmakingSetCountdownTimer( 0.0, true ) + HideMatchmakingStatusIcons() + } +} + +void function HideMatchmakingStatusIcons() +{ + foreach ( element in file.searchIconElems ) + Hud_Hide( element ) + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "iconVisible", false ) +} + +void function ShowMatchmakingStatusIcons() +{ + //foreach ( element in file.searchIconElems ) + // Hud_Show( element ) + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "iconVisible", true ) +} + +void function MatchmakingSetSearchVisible( bool state ) +{ + foreach ( el in file.searchTextElems ) + { + //if ( state ) + // Hud_Show( el ) + //else + Hud_Hide( el ) + } + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "statusVisible", state ) +} + +void function MatchmakingSetSearchText( string searchText, var param1 = "", var param2 = "", var param3 = "", var param4 = "" ) +{ + foreach ( el in file.searchTextElems ) + { + Hud_SetText( el, searchText, param1, param2, param3, param4 ) + } + + foreach ( element in file.matchStatusRuis ) + { + RuiSetBool( Hud_GetRui( element ), "statusHasText", searchText != "" ) + + RuiSetString( Hud_GetRui( element ), "statusText", Localize( searchText, param1, param2, param3, param4 ) ) + } +} + + +void function MatchmakingSetCountdownVisible( bool state ) +{ + foreach ( el in file.matchStartCountdownElems ) + { + //if ( state ) + // Hud_Show( el ) + //else + Hud_Hide( el ) + } + + foreach ( element in file.matchStatusRuis ) + RuiSetBool( Hud_GetRui( element ), "timerVisible", state ) +} + +void function MatchmakingSetCountdownTimer( float time, bool useServerTime = true ) //JFS: useServerTime bool is awkward, comes from level.ui.gameStartTime using server time and UpdateTimeToRestartMatchmaking() uses UI time. +{ + foreach ( element in file.matchStatusRuis ) + { + RuiSetBool( Hud_GetRui( element ), "timerHasText", time != 0.0 ) + RuiSetGameTime( Hud_GetRui( element ), "startTime", Time() ) + RuiSetBool( Hud_GetRui( element ), "useServerTime", useServerTime ) + RuiSetGameTime( Hud_GetRui( element ), "timerEndTime", time ) + } +} + +void function OnLobbyLevelInit() +{ + UpdateCallsignElement( file.callsignCard ) + RefreshCreditsAvailable() +} + +function UpdatePlayerInfo() +{ + EndSignal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + var menu = GetMenu( "LobbyMenu" ) + + WaitFrameOrUntilLevelLoaded() + + while ( true ) + { + RefreshCreditsAvailable() + WaitFrame() + } +} + +void function TryUnlockSRSCallsign() +{ + if ( Script_IsRunningTrialVersion() ) + return + + int numCallsignsToUnlock = 0 + + if ( GetTotalLionsCollected() >= GetTotalLionsInGame() ) + numCallsignsToUnlock = 3 + else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_2_COUNT ) + numCallsignsToUnlock = 2 + else if ( GetTotalLionsCollected() >= ACHIEVEMENT_COLLECTIBLES_1_COUNT ) + numCallsignsToUnlock = 1 + else + numCallsignsToUnlock = 0 + + if ( numCallsignsToUnlock > 0 ) + ClientCommand( "UnlockSRSCallsign " + numCallsignsToUnlock ) +} + +void function SetPutPlayerInMatchmakingAfterDelay( bool value ) +{ + file.putPlayerInMatchmakingAfterDelay = value +} + +void function OnStoreButton_Activate( var button ) +{ + LaunchGamePurchaseOrDLCStore() +} + +void function OnStoreNewReleasesButton_Activate( var button ) +{ + //LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_NewReleases" ] ) + LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_WeaponSkins" ] ) +} + +void function OnStoreBundlesButton_Activate( var button ) +{ + LaunchGamePurchaseOrDLCStore( [ "StoreMenu", "StoreMenu_Sales" ] ) +} + +void function OnDpadCommsButton_Activate( var button ) +{ + AdvanceMenu( GetMenu( "EditDpadCommsMenu" ) ) +} + +void function OpenCommsIntroDialog() +{ + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#DPAD_COMMS_ANNOUNCEMENT_HEADER" + dialogData.ruiMessage.message = "#DPAD_COMMS_ANNOUNCEMENT" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B1" , OpenDpadCommsMenu ) + AddDialogButton( dialogData, "#DPAD_COMMS_ANNOUNCEMENT_B2" ) + + AddDialogPCBackButton( dialogData ) + AddDialogFooter( dialogData, "#A_BUTTON_ACCEPT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) + + ClientCommand( "SetCommsIntroSeen" ) +} + +void function OpenDpadCommsMenu() +{ + OnDpadCommsButton_Activate( null ) +} + +bool function ShouldShowEmotesAnnouncement( entity player ) +{ + if ( !EmotesEnabled() ) + return false + + if ( player.GetPersistentVarAsInt( "numTimesUsedComms" ) > 2 ) + return false + + if ( player.GetPersistentVar( "hasBeenIntroducedToComms" ) ) + return false + + #if !DEV + if ( PlayerGetRawLevel( player ) <= 2 ) + return false + #endif + + return true +} + +void function Lobby_SetFDMode( bool mode ) +{ + file.isFDMode = mode +} + +//Function returns whether lobby is currently in "Frontier Defense" lobby mode. +bool function Lobby_IsFDMode() +{ + return file.isFDMode +} + +void function Lobby_SetAutoFDOpen( bool autoFD ) +{ + Lobby_SetFDMode( autoFD ) + file.shouldAutoOpenFDMenu = autoFD +} + +void function Lobby_SetFDModeBasedOnSearching( string playlistToSearch ) +{ + array< string > searchingPlaylists = split( playlistToSearch, "," ) + + bool isFDMode = false + int searchingCount = searchingPlaylists.len() + for( int idx = 0; idx < searchingCount; ++idx ) + { + isFDMode = isFDMode || IsFDMode( searchingPlaylists[idx] ) + if ( isFDMode ) + break + } + + Lobby_SetFDMode( isFDMode ) +} \ No newline at end of file diff --git a/Northstar.Client/scripts/vscripts/ui/menu_map_select.nut b/Northstar.Client/scripts/vscripts/ui/menu_map_select.nut new file mode 100644 index 00000000..7ed0d177 --- /dev/null +++ b/Northstar.Client/scripts/vscripts/ui/menu_map_select.nut @@ -0,0 +1,162 @@ +untyped + + +global function MenuMapSelect_Init + +global function InitMapsMenu + +struct { + int mapsPerPage = 21 + int currentMapPage +} file + +// note: this does have a scrolling system in vanilla, but it's honestly really weird and jank and i don't like it +// so for parity with menu_mode_select i'm removing it in favour of a page system + +function MenuMapSelect_Init() +{ + RegisterSignal( "OnCloseMapsMenu" ) +} + +void function InitMapsMenu() +{ + var menu = GetMenu( "MapsMenu" ) + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnOpenMapsMenu ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnCloseMapsMenu ) + + AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_GET_FOCUS, MapButton_Focused ) + AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_LOSE_FOCUS, MapButton_LostFocus ) + AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_CLICK, MapButton_Activate ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + + AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack, IsNorthstarServer ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward, IsNorthstarServer ) +} + +void function OnOpenMapsMenu() +{ + if ( IsNorthstarServer() ) + file.mapsPerPage = 15 + else + file.mapsPerPage = 21 + + UpdateVisibleMaps() +} + +void function UpdateVisibleMaps() +{ + array buttons = GetElementsByClassname( GetMenu( "MapsMenu" ), "MapButtonClass" ) + array mapsArray = GetPrivateMatchMaps() + + foreach ( button in buttons ) + { + int buttonID = int( Hud_GetScriptID( button ) ) + int mapID = buttonID + ( file.currentMapPage * file.mapsPerPage ) + + if ( buttonID < file.mapsPerPage && mapID < GetPrivateMatchMaps().len() ) + { + string name = mapsArray[ mapID ] + SetButtonRuiText( button, GetMapDisplayName( name ) ) + Hud_SetEnabled( button, true ) + + if ( IsItemInEntitlementUnlock( name ) && IsValid( GetUIPlayer() ) ) + { + if ( IsItemLocked( GetUIPlayer(), name ) && GetCurrentPlaylistVarInt( name + "_available" , 0 ) == 0 ) + { + SetButtonRuiText( button, Localize( "#MAP_LOCKED", Localize( GetMapDisplayName( name ) ) ) ) + } + } + + bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( name, PrivateMatch_GetSelectedMode() ) + Hud_SetLocked( button, !mapSupportsMode ) + + if ( !mapSupportsMode ) + SetButtonRuiText( button, Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetMapDisplayName( name ) ) ) ) + } + else + { + SetButtonRuiText( button, "" ) + Hud_SetEnabled( button, false ) + } + + if ( mapID == level.ui.privatematch_map ) + { + printt( buttonID, mapsArray[buttonID] ) + Hud_SetFocused( button ) + } + } +} + +void function OnCloseMapsMenu() +{ + Signal( uiGlobal.signalDummy, "OnCloseMapsMenu" ) +} + +void function MapButton_Focused( var button ) +{ + int mapID = int( Hud_GetScriptID( button ) ) + ( file.currentMapPage * file.mapsPerPage ) + + var menu = GetMenu( "MapsMenu" ) + var nextMapImage = Hud_GetChild( menu, "NextMapImage" ) + var nextMapName = Hud_GetChild( menu, "NextMapName" ) + var nextMapDesc = Hud_GetChild( menu, "NextMapDesc" ) + + array mapsArray = GetPrivateMatchMaps() + string mapName = mapsArray[ mapID ] + + asset mapImage = GetMapImageForMapName( mapName ) + RuiSetImage( Hud_GetRui( nextMapImage ), "basicImage", mapImage ) + Hud_SetText( nextMapName, GetMapDisplayName( mapName ) ) + + string modeName = PrivateMatch_GetSelectedMode() + bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( mapName, modeName ) + if ( !mapSupportsMode ) + Hud_SetText( nextMapDesc, Localize( "#PRIVATE_MATCH_MAP_NO_MODE_SUPPORT", Localize( GetMapDisplayName( mapName ) ), Localize( GetGameModeDisplayName( modeName ) ) ) ) + else + Hud_SetText( nextMapDesc, GetMapDisplayDesc( mapName ) ) + +} + +void function MapButton_LostFocus( var button ) +{ + HandleLockedCustomMenuItem( GetMenu( "MapsMenu" ), button, [], true ) +} + +void function MapButton_Activate( var button ) +{ + if ( Hud_IsLocked( button ) ) + return + + if ( !AmIPartyLeader() && GetPartySize() > 1 ) + return + + array mapsArray = GetPrivateMatchMaps() + int mapID = int( Hud_GetScriptID( button ) ) + string mapName = mapsArray[ mapID + ( file.currentMapPage * file.mapsPerPage ) ] + + printt( mapName, mapID ) + + ClientCommand( "SetCustomMap " + mapName ) + CloseActiveMenu() +} + +void function CycleModesBack( var button ) +{ + if ( file.currentMapPage == 0 ) + return + + file.currentMapPage-- + UpdateVisibleMaps() +} + +void function CycleModesForward( var button ) +{ + if ( ( file.currentMapPage + 1 ) * file.mapsPerPage >= GetPrivateMatchMaps().len() ) + return + + file.currentMapPage++ + UpdateVisibleMaps() +} diff --git a/Northstar.Client/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/scripts/vscripts/ui/menu_mode_select.nut new file mode 100644 index 00000000..23376781 --- /dev/null +++ b/Northstar.Client/scripts/vscripts/ui/menu_mode_select.nut @@ -0,0 +1,135 @@ +global function InitModesMenu + +struct { + int currentModePage +} file + +const int MODES_PER_PAGE = 15 + +void function InitModesMenu() +{ + var menu = GetMenu( "ModesMenu" ) + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnOpenModesMenu ) + + AddEventHandlerToButtonClass( menu, "ModeButton", UIE_GET_FOCUS, ModeButton_GetFocus ) + AddEventHandlerToButtonClass( menu, "ModeButton", UIE_CLICK, ModeButton_Click ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + + AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack, IsNorthstarServer ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward, IsNorthstarServer ) +} + +void function OnOpenModesMenu() +{ + UpdateVisibleModes() + + if ( level.ui.privatematch_mode == 0 ) // set to the first mode if there's no mode focused + Hud_SetFocused( GetElementsByClassname( GetMenu( "ModesMenu" ), "ModeButton" )[ 0 ] ) +} + +void function UpdateVisibleModes() +{ + // ensures that we only ever show enough buttons for the number of modes we have + array buttons = GetElementsByClassname( GetMenu( "ModesMenu" ), "ModeButton" ) + foreach ( var button in buttons ) + { + Hud_SetEnabled( button, false ) + Hud_SetVisible( button, false ) + } + + array modesArray = GetPrivateMatchModes() + for ( int i = 0; i < MODES_PER_PAGE; i++ ) + { + if ( i + ( file.currentModePage * MODES_PER_PAGE ) >= modesArray.len() ) + break + + int modeIndex = i + ( file.currentModePage * MODES_PER_PAGE ) + SetButtonRuiText( buttons[ i ], GetGameModeDisplayName( modesArray[ modeIndex ] ) ) + Hud_SetEnabled( buttons[ i ], true ) + Hud_SetVisible( buttons[ i ], true ) + Hud_SetLocked( buttons[ i ], false ) + + if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeIndex ] ) && !IsNorthstarServer() ) + { + Hud_SetLocked( buttons[ i ], true ) + SetButtonRuiText( buttons[ i ], Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetGameModeDisplayName( modesArray[ modeIndex ] ) ) ) ) + } + } +} + +void function ModeButton_GetFocus( var button ) +{ + int modeId = int( Hud_GetScriptID( button ) ) + ( file.currentModePage * MODES_PER_PAGE ) + + var menu = GetMenu( "ModesMenu" ) + var nextModeImage = Hud_GetChild( menu, "NextModeImage" ) + var nextModeIcon = Hud_GetChild( menu, "ModeIconImage" ) + var nextModeName = Hud_GetChild( menu, "NextModeName" ) + var nextModeDesc = Hud_GetChild( menu, "NextModeDesc" ) + + array modesArray = GetPrivateMatchModes() + + if ( modeId > modesArray.len() ) + return + + string modeName = modesArray[modeId] + + asset playlistImage = GetPlaylistImage( modeName ) + RuiSetImage( Hud_GetRui( nextModeImage ), "basicImage", playlistImage ) + RuiSetImage( Hud_GetRui( nextModeIcon ), "basicImage", GetPlaylistThumbnailImage( modeName ) ) + Hud_SetText( nextModeName, GetGameModeDisplayName( modeName ) ) + + string mapName = PrivateMatch_GetSelectedMap() + bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( mapName, modeName ) + if ( !mapSupportsMode && !IsNorthstarServer() ) + Hud_SetText( nextModeDesc, Localize( "#PRIVATE_MATCH_MODE_NO_MAP_SUPPORT", Localize( GetGameModeDisplayName( modeName ) ), Localize( GetMapDisplayName( mapName ) ) ) ) + else if ( IsFDMode( modeName ) ) // HACK! + Hud_SetText( nextModeDesc, Localize( "#FD_PLAYERS_DESC", Localize( GetGameModeDisplayHint( modeName ) ) ) ) + else + Hud_SetText( nextModeDesc, GetGameModeDisplayHint( modeName ) ) +} + +void function ModeButton_Click( var button ) +{ + // this never activates on custom servers, but keeping it for parity with official + if ( !AmIPartyLeader() && GetPartySize() > 1 ) + return + + if ( Hud_IsLocked( button ) ) + return + + int modeID = int( Hud_GetScriptID( button ) ) + ( file.currentModePage * MODES_PER_PAGE ) + + array modesArray = GetPrivateMatchModes() + string modeName = modesArray[ modeID ] + + // on modded servers set us to the first map for that mode automatically + // need this for coliseum mainly which is literally impossible to select without this + if ( IsNorthstarServer() && !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) ) + ClientCommand( "SetCustomMap " + GetPrivateMatchMapsForMode( modeName )[ 0 ] ) + + // set it + ClientCommand( "PrivateMatchSetMode " + modeName ) + CloseActiveMenu() +} + +void function CycleModesBack( var button ) +{ + if ( file.currentModePage == 0 ) + return + + file.currentModePage-- + UpdateVisibleModes() +} + +void function CycleModesForward( var button ) +{ + if ( ( file.currentModePage + 1 ) * MODES_PER_PAGE >= GetPrivateMatchModes().len() ) + return + + file.currentModePage++ + UpdateVisibleModes() +} \ No newline at end of file diff --git a/Northstar.Client/scripts/vscripts/ui/ui_utility.gnut b/Northstar.Client/scripts/vscripts/ui/ui_utility.gnut new file mode 100644 index 00000000..02d77795 --- /dev/null +++ b/Northstar.Client/scripts/vscripts/ui/ui_utility.gnut @@ -0,0 +1,634 @@ +untyped + +globalize_all_functions + +global const NUM_EOG_CHALLENGE_BOXES = 6 + +global const WEBBROWSER_FLAG_NONE = 0 +global const WEBBROWSER_FLAG_MUTEGAME = 0x0001 + + +function UtilityUI_Init() +{ + level.getPersistentVarWrapper <- class + { + function GetPersistentVar( variable ) + { + // This looks up the code function GetPersistentVar + return GetPersistentVar( variable ) + } + + function GetPersistentVarAsInt( string variable ) + { + return GetPersistentVarAsInt( variable ) + } + } +} + +int[2] function GetScreenSize() +{ + var screenSize = Hud_GetSize( GetMenu( "MainMenu" ) ) + + int[2] returnSize + returnSize[0] = expect int( screenSize[0] ) + returnSize[1] = expect int( screenSize[1] ) + + return returnSize +} + +float[2] function GetContentScaleFactor( var menu ) +{ + local screenSize = menu.GetSize() + float screenSizeX = expect int( screenSize[0] ).tofloat() + float screenSizeY = expect int( screenSize[1] ).tofloat() + float aspectRatio = screenSizeX / screenSizeY + float[2] scaleFactor + scaleFactor[0] = screenSizeX / ( 1080.0 * aspectRatio ) + scaleFactor[1] = screenSizeY / 1080.0 + return scaleFactor +} + +float function ContentScaledX( int val ) +{ + return (val * GetContentScaleFactor( GetMenu( "MainMenu" ) )[0]) +} + +float function ContentScaledY( int val ) +{ + return (val * GetContentScaleFactor( GetMenu( "MainMenu" ) )[1]) +} + +int function ContentScaledXAsInt( int val ) +{ + float fVal = val * GetContentScaleFactor( GetMenu( "MainMenu" ) )[0] + return int( fVal + 0.5 ) +} + +int function ContentScaledYAsInt( int val ) +{ + float fVal = val * GetContentScaleFactor( GetMenu( "MainMenu" ) )[1] + return int( fVal + 0.5 ) +} + +// Returns string or null +function GetLobbyTeamImage( int team ) +{ + Assert( IsConnected() ) + + if ( !GetLobbyTeamsShowAsBalanced() ) + return null + + if ( GetLobbyTypeScript() == eLobbyType.MATCH || GetLobbyTypeScript() == eLobbyType.PRIVATE_MATCH ) + return GetTeamImage( team ) + + return null +} + +// Returns string or null +function GetLobbyTeamName( int team ) +{ + Assert( IsConnected() ) + + if ( !GetLobbyTeamsShowAsBalanced() ) + return null + + if ( GetLobbyTypeScript() == eLobbyType.MATCH || GetLobbyTypeScript() == eLobbyType.PRIVATE_MATCH ) + return GetTeamName( team ) + + return null +} + +asset function GetTeamImage( int team ) +{ + Assert( team == TEAM_IMC || team == TEAM_MILITIA ) + + if ( team == TEAM_IMC ) + return $"ui/scoreboard_imc_logo" + + return $"ui/scoreboard_mcorp_logo" +} + +function RefreshPersistentFunc( func ) +{ + for ( int i = 0; i < 5; i++ ) + { + // cause who knows when persistent data changes + delaythread( i * 0.1 ) RunFuncWithConnectedCheck( func ) + } +} + +function RunFuncWithConnectedCheck( func ) +{ + if ( !IsConnected() ) + return + func() +} + +string function GetActiveLevel() +{ + // The level load callbacks overlap with the level init/shutdown callbacks, so we track each one separately. + if ( uiGlobal.loadedLevel != "" ) + return uiGlobal.loadedLevel + return uiGlobal.loadingLevel +} + +function HandleLockedMenuItem( menu, button, hideTip = false ) +{ + /*array elements = GetElementsByClassname( menu, "HideWhenLocked" ) + var buttonTooltip = Hud_GetChild( menu, "ButtonTooltip" ) + //var buttonTooltip = GetElementsByClassname( menu, "ButtonTooltip" )[0] + var toolTipLabel = Hud_GetChild( buttonTooltip, "Label" ) + + entity player = GetUIPlayer() + if ( player == null ) + return + + if ( "ref" in button.s && button.s.ref != null && IsItemLocked( player, expect string( button.s.ref ) ) && !hideTip ) + { + foreach( elem in elements ) + Hud_Hide( elem ) + + Hud_SetText( toolTipLabel, "#UNLOCKED_AT_LEVEL", g_unlocks[ expect string( button.s.ref ) ].unlockLevel, "" ) + + local buttonPos = Hud_GetAbsPos( button ) + local buttonHeight = Hud_GetHeight( button ) + local tooltipHeight = Hud_GetHeight( buttonTooltip ) + local yOffset = ( tooltipHeight - buttonHeight ) / 2.0 + + Hud_SetPos( buttonTooltip, buttonPos[0] + Hud_GetWidth( button ) * 0.9, buttonPos[1] - yOffset ) + Hud_Show( buttonTooltip ) + + return true + } + else + { + foreach( elem in elements ) + Hud_Show( elem ) + Hud_Hide( buttonTooltip ) + } + return false*/ +} + +// No way to test a named element exists so this is a workaround +var function GetSingleElementByClassname( var menu, string classname ) +{ + array elems = GetElementsByClassname( menu, classname ) + + if ( elems.len() ) + { + Assert( elems.len() == 1 ) + return elems[0] + } + + return null +} + +array function GetElementsByClassnameForMenus( string classname, array menus ) +{ + array elements = [] + + foreach ( menu in menus ) + elements.extend( GetElementsByClassname( menu, classname ) ) + + return elements +} + +function WaitFrameOrUntilLevelLoaded() +{ + WaitFrame() + + while ( uiGlobal.loadedLevel == "" ) + WaitFrame() +} + +bool function IsPlayerAlone() +{ + int myTeam = GetTeam() + if ( GetTeamSize( myTeam ) <= 1 ) + return true + + return false +} + +bool function PartyHasMembers() +{ + if ( GetPartySize() > 1 ) + return true + + return false +} + +bool function AmIPartyMember() +{ + return ( PartyHasMembers() && !AmIPartyLeader() ) +} + +string function GetGameModeDisplayName( string mode ) +{ + string displayName = GetGamemodeVarOrUseValue( mode, "name", (mode in GAMETYPE_TEXT) ? GAMETYPE_TEXT[mode] : "" ) + + // modification to support playlists too + if ( displayName == "" ) + return GetPlaylistVarOrUseValue( mode, "name", "" ) + + return displayName +} + +string function GetGameModeDisplayDesc( string mode ) //TODO: Make this support attack/defend descriptions +{ + string displayDesc = GetGamemodeVarOrUseValue( mode, "description", (mode in GAMETYPE_DESC) ? GAMETYPE_DESC[mode] : "" ) + + // modification to support playlists too + if ( displayDesc == "" ) + { + displayDesc = Localize( GetPlaylistVarOrUseValue( mode, "description", "" ) ) + + if ( displayDesc.find( "^" ) != null ) + displayDesc = displayDesc.slice( 0, displayDesc.find( "^" ) ) + } + + return displayDesc +} + +string function GetGameModeDisplayHint( string mode ) //TODO: Make this support attack/defend descriptions +{ + string displayDesc = GetGamemodeVarOrUseValue( mode, "hint", GetGameModeDisplayDesc( mode ) ) + return displayDesc +} + +asset function GetGameModeDisplayImage( string mode ) +{ + return GAMETYPE_ICON[ mode ] +} + +array function ColorStringToArray( string colorString ) +{ + array tokens = split( colorString, " " ) + + Assert( tokens.len() >= 3 && tokens.len() <= 4 ) + + array colorArray + foreach ( token in tokens ) + colorArray.append( int( token ) ) + + return colorArray +} + +array function GetGameModeDisplayColor( string mode ) +{ + array displayColor = ColorStringToArray( GetGamemodeVarOrUseValue( mode, "color", "" ) ) + if ( displayColor.len() == 0 ) + displayColor = GameMode_GetColor( mode ) + + return displayColor +} + +float function GetCurrentPlaylistVarFloat( val, useVal ) +{ + expect string( val ) + expect float( useVal ) + + local result = GetCurrentPlaylistVarOrUseValue( val, useVal ) + if ( result == null ) + return 0.0 + + return float( result ) +} + +// ???: player not used +bool function PlayerProgressionAllowed( player = null ) +{ + if ( IsPrivateMatch() ) + return false + + return true +} + +entity function GetUIPlayer() +{ + if ( !IsFullyConnected() ) + return null + + return GetLocalClientPlayer() +} + + +int function GetLobbyTypeScript() +{ + if ( GetLobbyType() == "game" ) + { + if ( IsPrivateMatch() ) + return eLobbyType.PRIVATE_MATCH + else + return eLobbyType.MATCH + } + else + { + if ( AmIPartyLeader() ) + { + if ( IsPlayerAlone() ) // TODO: This function was changed to only check your team size, not the true player count, so you'll probably now have access to some menus you shouldn't be able to. + return eLobbyType.SOLO + else + return eLobbyType.PARTY_LEADER + } + else + { + return eLobbyType.PARTY_MEMBER + } + } + + unreachable +} + +function AddMenu( blockName, asset resourceFile, void functionref() initFunc = null, string displayName = "" ) +{ + local menu = CreateMenu( "menu_" + blockName, resourceFile ) + uiGlobal.menus[blockName] <- menu + menu.SetHudName( blockName ) + + if ( displayName != "" ) + menu.SetDisplayName( displayName ) + else + menu.SetDisplayName( blockName ) + + uiGlobal.allMenus.append( menu ) + + MenuDef defaultMenuData + uiGlobal.menuData[ menu ] <- defaultMenuData + + if ( initFunc != null ) + uiGlobal.menuData[ menu ].initFunc = initFunc + + return menu +} + +function AddMenu_WithCreateFunc( blockName, asset resourceFile, void functionref() initFunc, createMenuFunc ) +{ + local menu = createMenuFunc( "menu_" + blockName, resourceFile ) + uiGlobal.menus[blockName] <- menu + menu.SetHudName( blockName ) + + uiGlobal.allMenus.append( menu ) + + MenuDef defaultMenuData + uiGlobal.menuData[ menu ] <- defaultMenuData + + if ( initFunc != null ) + uiGlobal.menuData[ menu ].initFunc = initFunc + + return menu +} + +function AddPanel( var menu, string panelName, void functionref() initFunc = null ) +{ + //printt( "AddPanel called, panelName:", panelName ) + + var panel = Hud_GetChild( menu, panelName ) + uiGlobal.panels[ panelName ] <- panel + uiGlobal.allPanels.append( panel ) + + PanelDef defaultPanelData + uiGlobal.panelData[ panel ] <- defaultPanelData + + if ( initFunc != null ) + uiGlobal.panelData[ panel ].initFunc = initFunc + + return panel +} + +function AddSubmenu( blockName, asset resourceFile, void functionref() initFunc = null ) +{ + local menu = CreateMenu( "menu_" + blockName, resourceFile ) + uiGlobal.menus[blockName] <- menu + menu.SetHudName( blockName ) + menu.SetType( "submenu" ) + + menu.s.newFocusRef <- null + + uiGlobal.allMenus.append( menu ) + + MenuDef defaultMenuData + uiGlobal.menuData[ menu ] <- defaultMenuData + + if ( initFunc != null ) + uiGlobal.menuData[ menu ].initFunc = initFunc + + return menu +} + +function ClearButton( button ) +{ + Hud_SetText( button, "" ) + Hud_SetEnabled( button, false ) + Hud_SetLocked( button, false ) + Hud_SetNew( button, false ) + Hud_SetSelected( button, false ) +} + +void function HudElem_SetText( var hudelem, string text ) +{ + hudelem.SetText( text ) +} + +void function SetButtonRuiText( var elem, string text ) +{ + var rui = Hud_GetRui( elem ) + RuiSetString( rui, "buttonText", text ) +} + +void function SetLabelRuiText( var elem, string text ) +{ + var rui = Hud_GetRui( elem ) + RuiSetString( rui, "labelText", text ) +} + +void function SetNamedRuiText( var elem, string name, string text ) +{ + var rui = Hud_GetRui( elem ) + RuiSetString( rui, name, text ) +} + +void function SetNamedRuiBool( var elem, string name, bool state ) +{ + var rui = Hud_GetRui( elem ) + RuiSetBool( rui, name, state ) +} + +void function SetNamedRuiImage( var elem, string name, asset assetName ) +{ + var rui = Hud_GetRui( elem ) + RuiSetImage( rui, name, assetName ) +} + +// Should be using Hud_GetChild() instead of this +var function GetMenuChild( var elem, string name ) +{ + return elem.GetChild( name ) +} + +bool function IsWeaponButton( var button ) +{ + array weaponButtons = GetElementsByClassname( GetParentMenu( button ), "WeaponSelectClass" ) + + foreach ( weaponButton in weaponButtons ) + { + if ( button == weaponButton ) + return true + } + + return false +} + +void function SetPanelTabTitle( var panel, string title ) +{ + uiGlobal.panelData[ panel ].tabTitle = title +} + +string function GetPanelTabTitle( var panel ) +{ + return uiGlobal.panelData[ panel ].tabTitle +} + +void function ScriptCallback_UnlockAchievement( int achievementID ) +{ + Assert( achievementID > 0 && achievementID < achievements.MAX_ACHIVEMENTS, "Tried to unlock achievement with invalid enum value" ) + + #if DEV + string ref + foreach( string _ref, int val in achievements ) + { + if ( val != achievementID ) + continue + ref = _ref + break + } + printt( "#############################################" ) + printt( "UNLOCKED ACHIEVEMENT:", ref, "(" + achievementID + ")" ) + printt( "#############################################" ) + #endif //DEV + + if ( Script_IsRunningTrialVersion() ) + { + printt( "Achievements not awarded in trial version" ) + return + } + + + Plat_UnlockAchievementByID( achievementID ) +} + +void function TryUnlockCollectiblesAchievement() +{ + int totalLionsCollectedForGame = GetTotalLionsCollected() + + if ( totalLionsCollectedForGame >= GetTotalLionsInGame() ) + ScriptCallback_UnlockAchievement( achievements.COLLECTIBLES_3 ) + + if ( totalLionsCollectedForGame >= ACHIEVEMENT_COLLECTIBLES_2_COUNT ) + ScriptCallback_UnlockAchievement( achievements.COLLECTIBLES_2 ) + + if ( totalLionsCollectedForGame >= ACHIEVEMENT_COLLECTIBLES_1_COUNT ) + ScriptCallback_UnlockAchievement( achievements.COLLECTIBLES_1 ) +} + +void function TryUnlockCompletedGameAchievements() +{ + if ( Script_IsRunningTrialVersion() ) + return + + var dataTable = GetDataTable( $"datatable/sp_levels.rpak" ) + int numRows = GetDatatableRowCount( dataTable ) + + // Check Completed All Levels Achievement + int normalCompleted = 0 + int hardCompleted = 0 + int masterCompleted = 0 + for ( int i=0; i= numRows ) + ScriptCallback_UnlockAchievement( achievements.COMPLETE_NORMAL ) + + if ( hardCompleted >= numRows ) + ScriptCallback_UnlockAchievement( achievements.COMPLETE_HARD ) + + if ( masterCompleted >= numRows ) + ScriptCallback_UnlockAchievement( achievements.COMPLETE_MASTER ) +} + +void function PopUpOriginOverlayDisabledDialog() +{ + DialogData dialogData + dialogData.header = "#ORIGIN_OVERLAY_DISABLED" + AddDialogButton( dialogData, "#OK" ) + OpenDialog( dialogData ) +} + +void function PrintPartyData() +{ + Party partyData = GetParty() + + printt( "PARTY DATA:" ) + + if ( partyData.numSlots == 0 ) + { + printt( " INVALID, numSlots: 0" ) + return + } + + printt( " partyType: ", partyData.partyType ) + printt( " playlistName: ", partyData.playlistName ) + printt( " originatorName: ", partyData.originatorName ) + printt( " originatorUID: ", partyData.originatorUID ) + printt( " numSlots: ", partyData.numSlots ) + printt( " numClaimedSlots:", partyData.numClaimedSlots ) + printt( " numFreeSlots: ", partyData.numFreeSlots ) + printt( " timeLeft: ", partyData.timeLeft ) + printt( " amIInThis: ", partyData.amIInThis ) + printt( " amILeader: ", partyData.amILeader ) + printt( " searching: ", partyData.searching ) + print( " members: " ) + + foreach ( index, member in partyData.members ) + { + if ( index != 0 ) + print( " " ) + + printt( member.name, "uid:", member.uid, "callsignIdx:", member.callsignIdx, "skillMu:", member.skillMu ) + } +} + +void function PlayVideoFullScreen( string video, bool showCaptions = false ) +{ + PlayVideo( video, 0, 0, 0, 0, showCaptions ) +} + +void function PlayVideoUsingPanelRect( string video, var panel ) +{ + int xPos = Hud_GetX( panel ) + int yPos = Hud_GetY( panel ) + int width = Hud_GetWidth( panel ) + int height = Hud_GetHeight( panel ) + + PlayVideo( video, xPos, yPos, width, height, false ) +} + +void function Hud_SetNavUp( var buttonFrom, var buttonTo ) +{ + buttonFrom.SetNavUp( buttonTo ) +} + +void function Hud_SetNavDown( var buttonFrom, var buttonTo ) +{ + buttonFrom.SetNavDown( buttonTo ) +} \ No newline at end of file -- cgit v1.2.3