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 ++++++++ Northstar.Custom/mod.json | 2 +- .../scripts/vscripts/gamemodes/_gamemode_gg.gnut | 2 + .../vscripts/gamemodes/sh_gamemode_ctf_comp.gnut | 5 + .../vscripts/gamemodes/sh_gamemode_fastball.gnut | 2 + .../scripts/vscripts/gamemodes/sh_gamemode_gg.gnut | 1 + .../vscripts/gamemodes/sh_gamemode_inf.gnut | 2 + .../scripts/vscripts/gamemodes/sh_gamemode_kr.gnut | 2 + .../scripts/vscripts/gamemodes/sh_gamemode_tt.gnut | 2 + .../lobby/sh_private_lobby_custom_modes_init.gnut | 11 + Northstar.CustomServers/mod.json | 21 +- .../scripts/vscripts/_powerup.gnut | 2 +- .../gamemodes/_featured_mode_settings.gnut | 121 ++ .../vscripts/gamemodes/_gamemode_coliseum.nut | 87 +- .../scripts/vscripts/gamemodes/_gamemode_fra.nut | 25 + .../scripts/vscripts/gamemodes/sh_gamemodes.gnut | 5 +- .../scripts/vscripts/lobby/_private_lobby.gnut | 6 +- .../scripts/vscripts/lobby/sh_lobby.gnut | 356 +++++ .../lobby/sh_private_lobby_modes_init.gnut | 21 + .../scripts/vscripts/sh_northstar_utils.gnut | 49 + bobthebob.testing/mod.json | 6 - .../scripts/vscripts/lobby/sh_lobby.gnut | 356 ----- .../vscripts/sh_bobtestingfunctions_mp.gnut | 6 + .../scripts/vscripts/ui/menu_map_select.nut | 108 +- .../scripts/vscripts/ui/menu_mode_select.nut | 3 +- 28 files changed, 3316 insertions(+), 444 deletions(-) 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 create mode 100644 Northstar.Custom/scripts/vscripts/lobby/sh_private_lobby_custom_modes_init.gnut create mode 100644 Northstar.CustomServers/scripts/vscripts/gamemodes/_featured_mode_settings.gnut create mode 100644 Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_fra.nut create mode 100644 Northstar.CustomServers/scripts/vscripts/lobby/sh_lobby.gnut create mode 100644 Northstar.CustomServers/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut create mode 100644 Northstar.CustomServers/scripts/vscripts/sh_northstar_utils.gnut delete mode 100644 bobthebob.testing/scripts/vscripts/lobby/sh_lobby.gnut 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 000000000..67036d48d --- /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 000000000..7ed0d1773 --- /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 000000000..233767816 --- /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 000000000..02d77795a --- /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 diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 75a142915..8d7c17523 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,4 +1,4 @@ -{ +disabled{ "ApiId" : "Northstar.Custom", "Name" : "Northstar.Custom", "Description" : "Additional content for coop and custom multiplayer servers", diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/_gamemode_gg.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/_gamemode_gg.gnut index fd41236c4..99a5ccf77 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/_gamemode_gg.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/_gamemode_gg.gnut @@ -73,6 +73,8 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) void function UpdateLoadout( entity player ) { + // todo: honestly, this should be reworked to use PilotLoadoutDefs instead of directly modifying weapons and shit + int currentWeaponIndex = GameRules_GetTeamScore( player.GetTeam() ) array weapons = GetGunGameWeapons() diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut index aff693c7d..1a1ce6451 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_ctf_comp.gnut @@ -25,6 +25,8 @@ void function CreateGamemodeCTFComp() GameMode_AddScoreboardColumnData( GAMEMODE_CTF_COMP, "#SCOREBOARD_TITAN_DAMAGE", PGS_DISTANCE_SCORE, 6 ) // gotta use a weird pgs here since we're running out of them lol GameMode_SetColor( GAMEMODE_CTF_COMP, [61, 117, 193, 255] ) + AddPrivateMatchMode( GAMEMODE_CTF_COMP ) // add to private lobby modes + // this gamemode is literally just normal ctf + a few extra settings // as such we do all the inits in this file, not enough logic to be worth splitting it up @@ -46,6 +48,9 @@ void function CreateGamemodeCTFComp() void function CTFCompRegisterNetworkVars() { + if ( GAMETYPE != GAMEMODE_CTF_COMP ) + return + // copied from the vanilla ctf remote functions RegisterNetworkedVariable( "imcFlag", SNDC_GLOBAL, SNVT_ENTITY ) RegisterNetworkedVariable( "milFlag", SNDC_GLOBAL, SNVT_ENTITY ) diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_fastball.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_fastball.gnut index 734e24ce5..2462d5376 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_fastball.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_fastball.gnut @@ -22,6 +22,8 @@ void function CreateGamemodeFastball() GameMode_AddScoreboardColumnData( GAMEMODE_FASTBALL, "#SCOREBOARD_DEATHS", PGS_DEATHS, 2 ) GameMode_SetColor( GAMEMODE_FASTBALL, [147, 204, 57, 255] ) + AddPrivateMatchMode( GAMEMODE_FASTBALL ) // add to private lobby modes + #if SERVER GameMode_AddServerInit( GAMEMODE_FASTBALL, GamemodeFastball_Init ) GameMode_SetPilotSpawnpointsRatingFunc( GAMEMODE_FASTBALL, RateSpawnpoints_Generic ) diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_gg.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_gg.gnut index 4ea9ac207..c4021a3cc 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_gg.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_gg.gnut @@ -31,6 +31,7 @@ void function CreateGamemodeGG() GameMode_AddScoreboardColumnData( GAMEMODE_GG, "#SCOREBOARD_PILOT_KILLS", PGS_PILOT_KILLS, 2 ) GameMode_SetColor( GAMEMODE_GG, [147, 204, 57, 255] ) + AddPrivateMatchMode( GAMEMODE_GG ) // add to private lobby modes // setup guns diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_inf.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_inf.gnut index b73dc1940..bcd863786 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_inf.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_inf.gnut @@ -21,6 +21,8 @@ void function CreateGamemodeInfection() GameMode_AddScoreboardColumnData( GAMEMODE_INFECTION, "#SCOREBOARD_KILLS", PGS_ASSAULT_SCORE, 2 ) GameMode_SetColor( GAMEMODE_INFECTION, [147, 204, 57, 255] ) + AddPrivateMatchMode( GAMEMODE_INFECTION ) // add to private lobby modes + #if SERVER GameMode_AddServerInit( GAMEMODE_INFECTION, GamemodeInfection_Init ) GameMode_SetPilotSpawnpointsRatingFunc( GAMEMODE_INFECTION, RateSpawnpoints_Generic ) diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_kr.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_kr.gnut index 2a320077f..7cd91de9d 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_kr.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_kr.gnut @@ -19,6 +19,8 @@ void function CreateGamemodeKR() GameMode_AddScoreboardColumnData( GAMEMODE_KR, "#SCOREBOARD_KR_RECORD", PGS_ASSAULT_SCORE, 2 ) GameMode_AddScoreboardColumnData( GAMEMODE_KR, "#SCOREBOARD_PILOT_KILLS", PGS_PILOT_KILLS, 2 ) GameMode_SetColor( GAMEMODE_KR, [147, 204, 57, 255] ) + + AddPrivateMatchMode( GAMEMODE_KR ) // add to private lobby modes #if SERVER GameMode_AddServerInit( GAMEMODE_KR, GamemodeKR_Init ) diff --git a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_tt.gnut b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_tt.gnut index 9e8798430..f3fbff28f 100644 --- a/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_tt.gnut +++ b/Northstar.Custom/scripts/vscripts/gamemodes/sh_gamemode_tt.gnut @@ -21,6 +21,8 @@ void function CreateGamemodeTT() GameMode_AddScoreboardColumnData( GAMEMODE_TT, "#SCOREBOARD_PILOT_KILLS", PGS_PILOT_KILLS, 2 ) GameMode_SetColor( GAMEMODE_TT, [200, 40, 40, 255] ) + AddPrivateMatchMode( GAMEMODE_TT ) // add to private lobby modes + #if SERVER GameMode_AddServerInit( GAMEMODE_TT, GamemodeTT_Init ) GameMode_SetPilotSpawnpointsRatingFunc( GAMEMODE_TT, RateSpawnpoints_Generic ) diff --git a/Northstar.Custom/scripts/vscripts/lobby/sh_private_lobby_custom_modes_init.gnut b/Northstar.Custom/scripts/vscripts/lobby/sh_private_lobby_custom_modes_init.gnut new file mode 100644 index 000000000..81c08f225 --- /dev/null +++ b/Northstar.Custom/scripts/vscripts/lobby/sh_private_lobby_custom_modes_init.gnut @@ -0,0 +1,11 @@ +global function CustomPrivateMatchModesInit + +void function CustomPrivateMatchModesInit() +{ + // modes + AddPrivateMatchMode( "gg" ) + AddPrivateMatchMode( "inf" ) + AddPrivateMatchMode( "kr" ) + AddPrivateMatchMode( "tt" ) + AddPrivateMatchMode( "ctf_comp" ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index a9e4f36d3..6e4d2d58f 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -23,6 +23,11 @@ "RunOn": "SERVER && MP", }, + { + "Path": "sh_northstar_utils.gnut", + "RunOn": "CLIENT || SERVER || UI", + }, + { "Path": "mp/levels/_lf_maps_shared.gnut", "RunOn": "SERVER && MP" @@ -32,11 +37,20 @@ "Path": "gamemodes/sh_gamemodes_custom.gnut", "RunOn": "(CLIENT || SERVER) && MP" }, - { "Path": "sh_remote_functions_mp_custom.gnut", "RunOn": "(CLIENT || SERVER) && MP" }, + { + "Path": "gamemodes/_gamemode_fra.nut", + "RunOn": "SERVER && MP", + "ServerPreCallback": "GamemodeFRA_AddAdditionalInitCallback" + }, + { + "Path": "gamemodes/_featured_mode_settings.gnut", + "RunOn": "SERVER && MP", + "ServerCallback": "FeaturedModeSettings_Init" + }, { "Path": "mp/_classic_mp_dropship_intro.gnut", @@ -52,5 +66,10 @@ "RunOn": "SERVER && MP", "ServerCallback": "SvLoadoutsMP_Init" }, + + { + "Path": "lobby/sh_private_lobby_modes_init.gnut", + "RunOn": "( SERVER || CLIENT ) && MP", + }, ] } \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/_powerup.gnut b/Northstar.CustomServers/scripts/vscripts/_powerup.gnut index a6a117afb..03b9fcfc7 100644 --- a/Northstar.CustomServers/scripts/vscripts/_powerup.gnut +++ b/Northstar.CustomServers/scripts/vscripts/_powerup.gnut @@ -81,7 +81,7 @@ bool function OnPowerupCollected( entity player, entity healthpack ) { // hack because i couldn't figure out any other way to do this without modifying sh_powerup // ensure we don't kill the powerup if it's a battery the player can't pickup - if ( ( powerup.index == ePowerUps.titanTimeReduction || powerup.index == ePowerUps.LTS_TitanTimeReduction ) && PlayerHasBattery( player ) ) + if ( ( powerup.index == ePowerUps.titanTimeReduction || powerup.index == ePowerUps.LTS_TitanTimeReduction ) && ( player.IsTitan() || PlayerHasMaxBatteryCount( player ) ) ) return false // idk why the powerup.destroyFunc doesn't just return a bool? would mean they could just handle stuff like this in powerup code diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_featured_mode_settings.gnut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_featured_mode_settings.gnut new file mode 100644 index 000000000..272043804 --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_featured_mode_settings.gnut @@ -0,0 +1,121 @@ +untyped +global function FeaturedModeSettings_Init + +void function FeaturedModeSettings_Init() +{ + // if it's not super obvious at a glance this script is used for playlist vars with the prefix "featured_mode_" + // these often set loadouts and shit so they need a script + // note: for turbo_titans, the core multiplier is set in playlist + + AddCallback_OnPlayerRespawned( FeaturedModeSettingsSetupPilotLoadouts ) + AddCallback_OnPilotBecomesTitan( FeaturedModeSettingsSetupTitanLoadouts ) +} + +bool function IsFeaturedMode( string modeName ) +{ + return GetCurrentPlaylistVar( "featured_mode_" + modeName ) == "1" +} + +void function FeaturedModeSettingsSetupPilotLoadouts( entity player ) +{ + bool shouldChangeLoadout = false + + // create loadout struct + PilotLoadoutDef modifiedLoadout = clone GetActivePilotLoadout( player ) + + if ( IsFeaturedMode( "all_holopilot" ) ) + { + shouldChangeLoadout = true + + modifiedLoadout.special = "mp_ability_holopilot" + } + + if ( IsFeaturedMode( "all_grapple" ) ) + { + shouldChangeLoadout = true + + modifiedLoadout.special = "mp_ability_grapple" + modifiedLoadout.specialMods = [ "all_grapple" ] + } + + if ( IsFeaturedMode( "all_phase" ) ) + { + shouldChangeLoadout = true + + modifiedLoadout.special = "mp_ability_shifter" + modifiedLoadout.specialMods = [ "all_phase" ] + } + + if ( IsFeaturedMode( "all_ticks" ) ) + { + shouldChangeLoadout = true + + modifiedLoadout.ordnance = "mp_weapon_frag_drone" + modifiedLoadout.ordnanceMods = [ "all_ticks" ] + } + + if ( IsFeaturedMode( "rocket_arena" ) ) + { + shouldChangeLoadout = true + + modifiedLoadout.primary = "mp_weapon_epg" + modifiedLoadout.primaryMods = [ "rocket_arena" ] + + // set secondary to whatever one is pistol + if ( GetWeaponInfoFileKeyField_Global( player.GetMainWeapons()[ 1 ].GetWeaponClassName(), "menu_category" ) == "at" ) + { + modifiedLoadout.weapon3 = "mp_weapon_autopistol" + modifiedLoadout.weapon3Mods = [ "rocket_arena" ] + } + else + { + modifiedLoadout.secondary = "mp_weapon_autopistol" + modifiedLoadout.secondaryMods = [ "rocket_arena" ] + } + } + + if ( IsFeaturedMode( "shotguns_snipers" ) ) + { + + shouldChangeLoadout = true + + // this one was never released, assuming it just gives you a mastiff and a kraber with quick swap + modifiedLoadout.primary = "mp_weapon_sniper" + modifiedLoadout.primaryMods = [ "pas_fast_swap", "pas_fast_ads" ] + + // set secondary to whatever one is pistol + if ( GetWeaponInfoFileKeyField_Global( player.GetMainWeapons()[ 1 ].GetWeaponClassName(), "menu_category" ) == "at" ) + { + modifiedLoadout.weapon3 = "mp_weapon_mastiff" + modifiedLoadout.weapon3Mods = [ "pas_fast_swap", "pas_run_and_gun" ] + } + else + { + modifiedLoadout.secondary = "mp_weapon_mastiff" + modifiedLoadout.secondaryMods = [ "pas_fast_swap", "pas_run_and_gun" ] + } + } + + // dont wanna give a new loadout if it's not necessary, could break other callbacks + if ( shouldChangeLoadout ) + GivePilotLoadout( player, modifiedLoadout ) + + if ( IsFeaturedMode( "tactikill" ) ) + player.GiveExtraWeaponMod( "tactical_cdr_on_kill" ) + + if ( IsFeaturedMode( "amped_tacticals" ) ) + player.GiveExtraWeaponMod( "amped_tacticals" ) +} + +void function FeaturedModeSettingsSetupTitanLoadouts( entity player, entity titan ) +{ + // this doesn't work atm, figure out how it should work and fix at some point + entity soul = player.GetTitanSoul() + if ( IsFeaturedMode( "turbo_titans" ) ) + { + if ( GetSoulTitanSubClass( soul ) == "stryder" || GetSoulTitanSubClass( soul ) == "atlas" ) + GivePassive( player, ePassives.PAS_MOBILITY_DASH_CAPACITY ) + else + GivePassive( player, ePassives.PAS_DASH_RECHARGE ) + } +} \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_coliseum.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_coliseum.nut index d8ccfc424..b358cfe82 100644 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_coliseum.nut +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_coliseum.nut @@ -1,12 +1,95 @@ +untyped + global function GamemodeColiseum_Init global function GamemodeColiseum_CustomIntro +bool hasShownIntroScreen = false + void function GamemodeColiseum_Init() { + // gamemode settings + SetRoundBased( true ) + SetRespawnsEnabled( false ) + SetShouldUseRoundWinningKillReplay( true ) + Riff_ForceTitanAvailability( eTitanAvailability.Never ) + Riff_ForceBoostAvailability( eBoostAvailability.Disabled ) + Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) + SetLoadoutGracePeriodEnabled( false ) // prevent modifying loadouts with grace period + SetWeaponDropsEnabled( false ) + + ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) + AddCallback_GameStateEnter( eGameState.Prematch, ShowColiseumIntroScreen ) + AddCallback_OnPlayerRespawned( GivePlayerColiseumLoadout ) +} + +// stub function referenced in sh_gamemodes_mp +void function GamemodeColiseum_CustomIntro( entity player ) +{} +void function ShowColiseumIntroScreen() +{ + if ( !hasShownIntroScreen ) + thread ShowColiseumIntroScreenThreaded() + + hasShownIntroScreen = true } -void function GamemodeColiseum_CustomIntro(entity _0) +void function ShowColiseumIntroScreenThreaded() { + wait 5 + + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_ColiseumIntro", 1, 1, 1 ) // stub numbers atm because lazy +} + +void function GivePlayerColiseumLoadout( entity player ) +{ + // create loadout struct + PilotLoadoutDef coliseumLoadout = clone GetActivePilotLoadout( player ) + + /* from playlists.txt + coliseum_primary "mp_weapon_lstar" + coliseum_primary_attachment "" + coliseum_primary_mod1 "" + coliseum_primary_mod2 "" + coliseum_primary_mod3 "" + coliseum_secondary "mp_weapon_softball" + coliseum_secondary_mod1 "" + coliseum_secondary_mod2 "" + coliseum_secondary_mod3 "" + coliseum_weapon3 "" + coliseum_weapon3_mod1 "" + coliseum_weapon3_mod2 "" + coliseum_weapon3_mod3 "" + coliseum_melee "melee_pilot_emptyhanded" + coliseum_special "mp_ability_heal" + coliseum_ordnance "mp_weapon_frag_drone" + coliseum_passive1 "pas_fast_health_regen" + coliseum_passive2 "pas_wallhang"*/ + + coliseumLoadout.primary = GetColiseumItem( "primary" ) + coliseumLoadout.primaryMods = [ GetColiseumItem( "primary_attachment" ), GetColiseumItem( "primary_mod1" ), GetColiseumItem( "primary_mod2" ), GetColiseumItem( "primary_mod3" ) ] + + coliseumLoadout.secondary = GetColiseumItem( "secondary" ) + coliseumLoadout.secondaryMods = [ GetColiseumItem( "secondary_mod1" ), GetColiseumItem( "secondary_mod2" ), GetColiseumItem( "secondary_mod3" ) ] + + coliseumLoadout.weapon3 = GetColiseumItem( "weapon3" ) + coliseumLoadout.weapon3Mods = [ GetColiseumItem( "weapon3_mod1" ), GetColiseumItem( "weapon3_mod2" ), GetColiseumItem( "weapon3_mod3" ) ] + + coliseumLoadout.melee = GetColiseumItem( "melee" ) + coliseumLoadout.special = GetColiseumItem( "special" ) + coliseumLoadout.ordnance = GetColiseumItem( "ordnance" ) + coliseumLoadout.passive1 = GetColiseumItem( "passive1" ) + coliseumLoadout.passive2 = GetColiseumItem( "passive2" ) + + coliseumLoadout.setFile = GetSuitAndGenderBasedSetFile( "coliseum", coliseumLoadout.race == RACE_HUMAN_FEMALE ? "female" : "male" ) + + GivePilotLoadout( player, coliseumLoadout ) +} + +string function GetColiseumItem( string name ) +{ + return expect string ( GetCurrentPlaylistVar( "coliseum_" + name ) ) +} -} \ No newline at end of file +// todo this needs the outro: unsure what anims it uses \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_fra.nut b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_fra.nut new file mode 100644 index 000000000..15f749ac7 --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/_gamemode_fra.nut @@ -0,0 +1,25 @@ +global function GamemodeFRA_AddAdditionalInitCallback + +// fra doesn't register a gamemode init by default, adding one just so we can set stuff up for it +void function GamemodeFRA_AddAdditionalInitCallback() +{ + AddCallback_OnCustomGamemodesInit( GamemodeFRA_AddAdditionalInit ) +} + +void function GamemodeFRA_AddAdditionalInit() +{ + GameMode_AddServerInit( FREE_AGENCY, GamemodeFRA_Init ) +} + +void function GamemodeFRA_Init() +{ + // need a way to disable passive earnmeter gain + ScoreEvent_SetEarnMeterValues( "PilotBatteryPickup", 0.0, 0.34 ) + + AddCallback_OnPlayerKilled( FRARemoveEarnMeter ) +} + +void function FRARemoveEarnMeter( entity victim, entity attacker, var damageInfo ) +{ + PlayerEarnMeter_Reset( victim ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemodes.gnut b/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemodes.gnut index df7acb78e..9114fcadd 100644 --- a/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemodes.gnut +++ b/Northstar.CustomServers/scripts/vscripts/gamemodes/sh_gamemodes.gnut @@ -415,7 +415,10 @@ void function GameModes_Init() #endif #if SERVER || CLIENT - InitCustomGamemodes() + // add modes/maps/playlists to private lobby that aren't there by default + PrivateMatchModesInit() + + InitCustomGamemodes() // do custom gamemode callbacks GameModes_Init_SV_CL() #endif diff --git a/Northstar.CustomServers/scripts/vscripts/lobby/_private_lobby.gnut b/Northstar.CustomServers/scripts/vscripts/lobby/_private_lobby.gnut index c428d3095..8d803da1d 100644 --- a/Northstar.CustomServers/scripts/vscripts/lobby/_private_lobby.gnut +++ b/Northstar.CustomServers/scripts/vscripts/lobby/_private_lobby.gnut @@ -102,7 +102,11 @@ void function StartMatch() WaitFrame() } - GameRules_SetGameMode( file.mode ) + if ( file.mode in GAMETYPE_TEXT ) + GameRules_SetGameMode( file.mode ) + else + GameRules_SetGameMode( GetPlaylistGamemodeByIndex( file.mode, 0 ) ) + try { // todo: not every gamemode uses the same playlist as their name! need some code to resolve these manually diff --git a/Northstar.CustomServers/scripts/vscripts/lobby/sh_lobby.gnut b/Northstar.CustomServers/scripts/vscripts/lobby/sh_lobby.gnut new file mode 100644 index 000000000..24436017f --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/lobby/sh_lobby.gnut @@ -0,0 +1,356 @@ +globalize_all_functions + +const string PRIVATE_MATCH_PLAYLIST = "private_match" + +struct { + array modes = [ // default modes in vanilla + "aitdm", + "tdm", + "cp", + "at", + "ctf", + "lts", + "ps", + "speedball", + "mfd", + "ttdm", + "fd_easy", + "fd_normal", + "fd_hard", + "fd_master", + "fd_insane" + ] + + array maps = [ // default maps in vanilla + "mp_forwardbase_kodai", + "mp_grave", + "mp_homestead", + "mp_thaw", + "mp_black_water_canal", + "mp_eden", + "mp_drydock", + "mp_crashsite3", + "mp_complex3", + "mp_angel_city", + "mp_colony02", + "mp_glitch", + "mp_relic02", + "mp_wargames", + "mp_rise", + "mp_lf_stacks", + "mp_lf_deck", + "mp_lf_meadow", + "mp_lf_traffic", + "mp_lf_township", + "mp_lf_uma" + ] +} file + +void function AddPrivateMatchMode( string mode ) +{ + if ( !file.modes.contains( mode ) ) + file.modes.append( mode ) + + #if CLIENT + // call this on ui too so the client and ui states are the same + RunUIScript( "AddPrivateMatchMode", mode ) + #endif +} + +void function AddPrivateMatchMap( string map ) +{ + if ( !file.maps.contains( map ) ) + file.maps.append( map ) + + #if CLIENT + // call this on ui too so the client and ui states are the same + RunUIScript( "AddPrivateMatchMap", map ) + #endif +} + +array function GetPrivateMatchModes() +{ + //array modesArray + // + //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) + //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) + //{ + // modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) ) + //} + + //return modesArray + + return file.modes +} + +int function GetPrivateMatchModeIndex( string modeName ) +{ + //int indexForName = 0 + // + //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) + //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) + //{ + // if ( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) != modeName ) + // continue + // + // indexForName = modeIndex; + // break + //} + // + //return indexForName + + return file.modes.find( modeName ) +} + + +array function GetPrivateMatchMapsForMode( string modeName ) +{ + //array mapsArray + // + //int modeIndex = GetPrivateMatchModeIndex( modeName ) + //int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) + //for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) + //{ + // mapsArray.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) ) + //} + // + //return mapsArray + + array maps + + // use the private match playlist for this if the gamemode is in it already + int privatePlaylistModeIndex = GetPrivateMatchModeIndex( modeName ) + if ( privatePlaylistModeIndex < GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) ) + { + for ( int i = 0; i < GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex ); i++ ) + maps.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex, i ) ) + } + else + { + int numMaps = GetPlaylistGamemodeByIndexMapsCount( modeName, 0 ) + for ( int i = 0; i < numMaps; i++ ) + maps.append( GetPlaylistGamemodeByIndexMapByIndex( modeName, 0, i ) ) + } + + return maps +} + +// never called +/*array function GetPrivateMatchModesForMap( string mapName ) +{ + array modesArray + + int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) + for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) + { + int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) + for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) + { + if ( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) != mapName ) + continue + + modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) ) + } + } + + return modesArray +}*/ + + +string function GetPrivateMatchMapForIndex( int index ) +{ + array mapsArray = GetPrivateMatchMaps() + + if ( index >= mapsArray.len() ) + return "" + + return mapsArray[index] +} + +string function GetPrivateMatchModeForIndex( int index ) +{ + array modesArray = GetPrivateMatchModes() + + if ( index >= modesArray.len() ) + return "" + + return modesArray[index] +} + +int function GetPrivateMatchMapIndex( string mapName ) +{ + array mapsArray = GetPrivateMatchMaps() + for ( int index = 0; index < mapsArray.len(); index++ ) + { + if ( mapsArray[index] == mapName ) + return index + } + + return 0 +} +/* +int function GetPrivateMatchModeIndex( string modeName ) +{ + array modesArray = GetPrivateMatchModes() + for ( int index = 0; index < modesArray.len(); index++ ) + { + if ( modesArray[index] == modeName ) + return index + } + + return 0 +} +*/ + +array function GetPrivateMatchMaps() +{ + //array mapsArray + // + //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) + //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) + //{ + // int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) + // for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) + // { + // string mapName = GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) + // if ( mapsArray.contains( mapName ) ) + // continue + // + // mapsArray.append( mapName ) + // } + //} + // + //return mapsArray + + return file.maps +} + + + +array function GetPlaylistMaps( string playlistName ) +{ + array mapsArray + + int numModes = GetPlaylistGamemodesCount( playlistName ) + for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) + { + int numMaps = GetPlaylistGamemodeByIndexMapsCount( playlistName, modeIndex ) + for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) + { + string mapName = GetPlaylistGamemodeByIndexMapByIndex( playlistName, modeIndex, mapIndex ) + if ( mapsArray.contains( mapName ) ) + continue + + mapsArray.append( mapName ) + } + } + + return mapsArray +} + + +bool function MapSettings_SupportsTitans( string mapName ) +{ + if ( mapName.find( "mp_lf_") != null ) + return false + + if ( mapName.find( "coliseum" ) != null ) + return false; + + return true +} + +bool function MapSettings_SupportsAI( string mapName ) +{ + if ( mapName.find( "mp_lf_") != null ) + return false + + if ( mapName.find( "coliseum" ) != null ) + return false; + + return true +} + + +bool function ModeSettings_RequiresTitans( string modeName ) +{ + switch ( modeName ) + { + case "lts": + return true + } + + return false +} + +bool function ModeSettings_RequiresAI( string modeName ) +{ + switch ( modeName ) + { + case "aitdm": + case "at": + return true + } + + return false +} + +#if !CLIENT +string function PrivateMatch_GetSelectedMap() +{ + var mapIndex = level.ui.privatematch_map + string mapName = GetPrivateMatchMapForIndex( expect int(mapIndex) ) + + return mapName +} + + +string function PrivateMatch_GetSelectedMode() +{ + var modeIndex = level.ui.privatematch_mode + string modeName = GetPrivateMatchModeForIndex( expect int(modeIndex) ) + + return modeName +} +#endif + +bool function PrivateMatch_IsValidMapModeCombo( string mapName, string modeName ) +{ + array mapsForMode = GetPrivateMatchMapsForMode( modeName ) + + return mapsForMode.contains( mapName ) +} + +// end private match stuff + +int function Player_GetMaxMatchmakingDelay( entity player ) +{ + // return GetCurrentPlaylistVarInt( "matchmaking_delay", 0 ) + return 300 +} + +int function Player_GetRemainingMatchmakingDelay( entity player ) +{ + int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME ) + + return Player_GetMaxMatchmakingDelay( player ) - (GetCurrentTimeForPersistence() - lastLeaveTime) +} + +int function Player_NextAvailableMatchmakingTime( entity player ) +{ + #if MP + int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME ) + if ( GetCurrentTimeForPersistence() - lastLeaveTime < Player_GetMaxMatchmakingDelay( player ) ) + { + return Player_GetRemainingMatchmakingDelay( player ) + } + #endif + + return 0 +} + +int function GetCurrentTimeForPersistence() +{ + // Returns the unix timestap offset to the timezone we want to use + return GetUnixTimestamp() + DAILY_RESET_TIME_ZONE_OFFSET * SECONDS_PER_HOUR +} diff --git a/Northstar.CustomServers/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut b/Northstar.CustomServers/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut new file mode 100644 index 000000000..b1474a15a --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut @@ -0,0 +1,21 @@ +global function PrivateMatchModesInit + +void function PrivateMatchModesInit() +{ + // modes + AddPrivateMatchMode( "ffa" ) + AddPrivateMatchMode( "fra" ) + AddPrivateMatchMode( "coliseum" ) + + // playlists + AddPrivateMatchMode( "attdm" ) + AddPrivateMatchMode( "turbo_ttdm" ) + AddPrivateMatchMode( "alts" ) + AddPrivateMatchMode( "turbo_lts" ) + AddPrivateMatchMode( "rocket_lf" ) + AddPrivateMatchMode( "holopilot_lf" ) + + // maps + AddPrivateMatchMap( "mp_coliseum" ) + AddPrivateMatchMap( "mp_coliseum_column" ) +} \ No newline at end of file diff --git a/Northstar.CustomServers/scripts/vscripts/sh_northstar_utils.gnut b/Northstar.CustomServers/scripts/vscripts/sh_northstar_utils.gnut new file mode 100644 index 000000000..15eed9b21 --- /dev/null +++ b/Northstar.CustomServers/scripts/vscripts/sh_northstar_utils.gnut @@ -0,0 +1,49 @@ +globalize_all_functions + +enum eNorthstarLobbyType +{ + PrivateMatchLobby, // normal vanilla private lobby + IntermissionLobby, // similar to tf1's intermission lobby, chooses next map automatically + CompetitiveLobby // similar to vanilla privates, but with ready up system +} + +// whether the server is a modded, northstar server +bool function IsNorthstarServer() +{ + bool isModded = true // TEMP for testing + try + { + // need this in a trycatch because the var might not exist atm + isModded = GetConVarInt( "northstar_is_modded_server" ) == 1 + } catch ( ex ) {} + + return isModded +} + +// whether the game should return to the lobby on GameRules_EndMatch() +bool function ShouldReturnToLobby() +{ + bool shouldReturnToLobby = false + try + { + // need this in a trycatch because the var might not exist atm + shouldReturnToLobby = GetConVarInt( "northstar_should_return_to_lobby" ) == 1 + } catch ( ex ) {} + + return shouldReturnToLobby +} + +int function GetNorthstarLobbyType() +{ + if ( !IsNorthstarServer() ) + return eNorthstarLobbyType.PrivateMatchLobby + + int lobbyType = eNorthstarLobbyType.PrivateMatchLobby + try + { + // need this in a trycatch because the var might not exist atm + lobbyType = GetConVarInt( "northstar_lobby_type" ) + } catch ( ex ) {} + + return lobbyType +} \ No newline at end of file diff --git a/bobthebob.testing/mod.json b/bobthebob.testing/mod.json index f79cb091c..b0da73e56 100644 --- a/bobthebob.testing/mod.json +++ b/bobthebob.testing/mod.json @@ -30,11 +30,5 @@ "ServerPreCallback": "BleedoutTest_Init", "ClientPreCallback": "BleedoutTest_Init", }, - - { - "Path": "sh_northstar_utils.gnut", - "RunOn": "CLIENT || SERVER || UI", - } - ] } \ No newline at end of file diff --git a/bobthebob.testing/scripts/vscripts/lobby/sh_lobby.gnut b/bobthebob.testing/scripts/vscripts/lobby/sh_lobby.gnut deleted file mode 100644 index 24436017f..000000000 --- a/bobthebob.testing/scripts/vscripts/lobby/sh_lobby.gnut +++ /dev/null @@ -1,356 +0,0 @@ -globalize_all_functions - -const string PRIVATE_MATCH_PLAYLIST = "private_match" - -struct { - array modes = [ // default modes in vanilla - "aitdm", - "tdm", - "cp", - "at", - "ctf", - "lts", - "ps", - "speedball", - "mfd", - "ttdm", - "fd_easy", - "fd_normal", - "fd_hard", - "fd_master", - "fd_insane" - ] - - array maps = [ // default maps in vanilla - "mp_forwardbase_kodai", - "mp_grave", - "mp_homestead", - "mp_thaw", - "mp_black_water_canal", - "mp_eden", - "mp_drydock", - "mp_crashsite3", - "mp_complex3", - "mp_angel_city", - "mp_colony02", - "mp_glitch", - "mp_relic02", - "mp_wargames", - "mp_rise", - "mp_lf_stacks", - "mp_lf_deck", - "mp_lf_meadow", - "mp_lf_traffic", - "mp_lf_township", - "mp_lf_uma" - ] -} file - -void function AddPrivateMatchMode( string mode ) -{ - if ( !file.modes.contains( mode ) ) - file.modes.append( mode ) - - #if CLIENT - // call this on ui too so the client and ui states are the same - RunUIScript( "AddPrivateMatchMode", mode ) - #endif -} - -void function AddPrivateMatchMap( string map ) -{ - if ( !file.maps.contains( map ) ) - file.maps.append( map ) - - #if CLIENT - // call this on ui too so the client and ui states are the same - RunUIScript( "AddPrivateMatchMap", map ) - #endif -} - -array function GetPrivateMatchModes() -{ - //array modesArray - // - //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) - //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) - //{ - // modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) ) - //} - - //return modesArray - - return file.modes -} - -int function GetPrivateMatchModeIndex( string modeName ) -{ - //int indexForName = 0 - // - //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) - //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) - //{ - // if ( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) != modeName ) - // continue - // - // indexForName = modeIndex; - // break - //} - // - //return indexForName - - return file.modes.find( modeName ) -} - - -array function GetPrivateMatchMapsForMode( string modeName ) -{ - //array mapsArray - // - //int modeIndex = GetPrivateMatchModeIndex( modeName ) - //int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) - //for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) - //{ - // mapsArray.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) ) - //} - // - //return mapsArray - - array maps - - // use the private match playlist for this if the gamemode is in it already - int privatePlaylistModeIndex = GetPrivateMatchModeIndex( modeName ) - if ( privatePlaylistModeIndex < GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) ) - { - for ( int i = 0; i < GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex ); i++ ) - maps.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex, i ) ) - } - else - { - int numMaps = GetPlaylistGamemodeByIndexMapsCount( modeName, 0 ) - for ( int i = 0; i < numMaps; i++ ) - maps.append( GetPlaylistGamemodeByIndexMapByIndex( modeName, 0, i ) ) - } - - return maps -} - -// never called -/*array function GetPrivateMatchModesForMap( string mapName ) -{ - array modesArray - - int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) - for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) - { - int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) - for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) - { - if ( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) != mapName ) - continue - - modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) ) - } - } - - return modesArray -}*/ - - -string function GetPrivateMatchMapForIndex( int index ) -{ - array mapsArray = GetPrivateMatchMaps() - - if ( index >= mapsArray.len() ) - return "" - - return mapsArray[index] -} - -string function GetPrivateMatchModeForIndex( int index ) -{ - array modesArray = GetPrivateMatchModes() - - if ( index >= modesArray.len() ) - return "" - - return modesArray[index] -} - -int function GetPrivateMatchMapIndex( string mapName ) -{ - array mapsArray = GetPrivateMatchMaps() - for ( int index = 0; index < mapsArray.len(); index++ ) - { - if ( mapsArray[index] == mapName ) - return index - } - - return 0 -} -/* -int function GetPrivateMatchModeIndex( string modeName ) -{ - array modesArray = GetPrivateMatchModes() - for ( int index = 0; index < modesArray.len(); index++ ) - { - if ( modesArray[index] == modeName ) - return index - } - - return 0 -} -*/ - -array function GetPrivateMatchMaps() -{ - //array mapsArray - // - //int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) - //for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) - //{ - // int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex ) - // for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) - // { - // string mapName = GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) - // if ( mapsArray.contains( mapName ) ) - // continue - // - // mapsArray.append( mapName ) - // } - //} - // - //return mapsArray - - return file.maps -} - - - -array function GetPlaylistMaps( string playlistName ) -{ - array mapsArray - - int numModes = GetPlaylistGamemodesCount( playlistName ) - for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ ) - { - int numMaps = GetPlaylistGamemodeByIndexMapsCount( playlistName, modeIndex ) - for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ ) - { - string mapName = GetPlaylistGamemodeByIndexMapByIndex( playlistName, modeIndex, mapIndex ) - if ( mapsArray.contains( mapName ) ) - continue - - mapsArray.append( mapName ) - } - } - - return mapsArray -} - - -bool function MapSettings_SupportsTitans( string mapName ) -{ - if ( mapName.find( "mp_lf_") != null ) - return false - - if ( mapName.find( "coliseum" ) != null ) - return false; - - return true -} - -bool function MapSettings_SupportsAI( string mapName ) -{ - if ( mapName.find( "mp_lf_") != null ) - return false - - if ( mapName.find( "coliseum" ) != null ) - return false; - - return true -} - - -bool function ModeSettings_RequiresTitans( string modeName ) -{ - switch ( modeName ) - { - case "lts": - return true - } - - return false -} - -bool function ModeSettings_RequiresAI( string modeName ) -{ - switch ( modeName ) - { - case "aitdm": - case "at": - return true - } - - return false -} - -#if !CLIENT -string function PrivateMatch_GetSelectedMap() -{ - var mapIndex = level.ui.privatematch_map - string mapName = GetPrivateMatchMapForIndex( expect int(mapIndex) ) - - return mapName -} - - -string function PrivateMatch_GetSelectedMode() -{ - var modeIndex = level.ui.privatematch_mode - string modeName = GetPrivateMatchModeForIndex( expect int(modeIndex) ) - - return modeName -} -#endif - -bool function PrivateMatch_IsValidMapModeCombo( string mapName, string modeName ) -{ - array mapsForMode = GetPrivateMatchMapsForMode( modeName ) - - return mapsForMode.contains( mapName ) -} - -// end private match stuff - -int function Player_GetMaxMatchmakingDelay( entity player ) -{ - // return GetCurrentPlaylistVarInt( "matchmaking_delay", 0 ) - return 300 -} - -int function Player_GetRemainingMatchmakingDelay( entity player ) -{ - int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME ) - - return Player_GetMaxMatchmakingDelay( player ) - (GetCurrentTimeForPersistence() - lastLeaveTime) -} - -int function Player_NextAvailableMatchmakingTime( entity player ) -{ - #if MP - int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME ) - if ( GetCurrentTimeForPersistence() - lastLeaveTime < Player_GetMaxMatchmakingDelay( player ) ) - { - return Player_GetRemainingMatchmakingDelay( player ) - } - #endif - - return 0 -} - -int function GetCurrentTimeForPersistence() -{ - // Returns the unix timestap offset to the timezone we want to use - return GetUnixTimestamp() + DAILY_RESET_TIME_ZONE_OFFSET * SECONDS_PER_HOUR -} diff --git a/bobthebob.testing/scripts/vscripts/sh_bobtestingfunctions_mp.gnut b/bobthebob.testing/scripts/vscripts/sh_bobtestingfunctions_mp.gnut index 124c7a541..70bc5165b 100644 --- a/bobthebob.testing/scripts/vscripts/sh_bobtestingfunctions_mp.gnut +++ b/bobthebob.testing/scripts/vscripts/sh_bobtestingfunctions_mp.gnut @@ -125,4 +125,10 @@ void function TestObjectiveRUIFW() RuiDestroy( rui ) } + +void function RespawnWhy() +{ + for ( int i = 0; i < 500; i++ ) // this only works in lobby, luckily + GetLocalViewPlayer().ClientCommand( "test_clientsetplaylistvaroverride " + i + " whyyyyy" ) +} #endif \ No newline at end of file diff --git a/bobthebob.testing/scripts/vscripts/ui/menu_map_select.nut b/bobthebob.testing/scripts/vscripts/ui/menu_map_select.nut index 7263a9faf..7ed0d1773 100644 --- a/bobthebob.testing/scripts/vscripts/ui/menu_map_select.nut +++ b/bobthebob.testing/scripts/vscripts/ui/menu_map_select.nut @@ -5,16 +5,9 @@ global function MenuMapSelect_Init global function InitMapsMenu -const int MAPS_PER_PAGE = 21 - -const MAP_LIST_VISIBLE_ROWS = 21 -const MAP_LIST_SCROLL_SPEED = 0 - struct { - var menu = null - array buttons - int numMapButtonsOffScreen - int mapListScrollState = 0 + 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 @@ -27,8 +20,7 @@ function MenuMapSelect_Init() void function InitMapsMenu() { - file.menu = GetMenu( "MapsMenu" ) - var menu = file.menu + var menu = GetMenu( "MapsMenu" ) AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnOpenMapsMenu ) AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnCloseMapsMenu ) @@ -36,13 +28,9 @@ void function InitMapsMenu() AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_GET_FOCUS, MapButton_Focused ) AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_LOSE_FOCUS, MapButton_LostFocus ) AddEventHandlerToButtonClass( menu, "MapButtonClass", UIE_CLICK, MapButton_Activate ) - //AddEventHandlerToButtonClass( menu, "MapListScrollUpClass", UIE_CLICK, OnMapListScrollUp_Activate ) - //AddEventHandlerToButtonClass( menu, "MapListScrollDownClass", UIE_CLICK, OnMapListScrollDown_Activate ) AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) - - file.buttons = GetElementsByClassname( menu, "MapButtonClass" ) 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 ) @@ -50,19 +38,27 @@ void function InitMapsMenu() void function OnOpenMapsMenu() { - array buttons = file.buttons - array mapsArray = GetPrivateMatchMaps() + if ( IsNorthstarServer() ) + file.mapsPerPage = 15 + else + file.mapsPerPage = 21 + + UpdateVisibleMaps() +} - file.numMapButtonsOffScreen = int( max( mapsArray.len() - MAP_LIST_VISIBLE_ROWS, 0 ) ) -// Assert( file.numMapButtonsOffScreen >= 0 ) +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 >= 0 && buttonID < mapsArray.len() ) + if ( buttonID < file.mapsPerPage && mapID < GetPrivateMatchMaps().len() ) { - string name = mapsArray[buttonID] + string name = mapsArray[ mapID ] SetButtonRuiText( button, GetMapDisplayName( name ) ) Hud_SetEnabled( button, true ) @@ -86,36 +82,30 @@ void function OnOpenMapsMenu() Hud_SetEnabled( button, false ) } - if ( buttonID == level.ui.privatematch_map ) + if ( mapID == level.ui.privatematch_map ) { printt( buttonID, mapsArray[buttonID] ) Hud_SetFocused( button ) } } - - //RegisterButtonPressedCallback( MOUSE_WHEEL_UP, OnMapListScrollUp_Activate ) - //RegisterButtonPressedCallback( MOUSE_WHEEL_DOWN, OnMapListScrollDown_Activate ) } void function OnCloseMapsMenu() { - //DeregisterButtonPressedCallback( MOUSE_WHEEL_UP, OnMapListScrollUp_Activate ) - //DeregisterButtonPressedCallback( MOUSE_WHEEL_DOWN, OnMapListScrollDown_Activate ) - Signal( uiGlobal.signalDummy, "OnCloseMapsMenu" ) } void function MapButton_Focused( var button ) { - int buttonID = int( Hud_GetScriptID( button ) ) + int mapID = int( Hud_GetScriptID( button ) ) + ( file.currentMapPage * file.mapsPerPage ) - var menu = file.menu + 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[buttonID] + string mapName = mapsArray[ mapID ] asset mapImage = GetMapImageForMapName( mapName ) RuiSetImage( Hud_GetRui( nextMapImage ), "basicImage", mapImage ) @@ -128,36 +118,24 @@ void function MapButton_Focused( var button ) else Hud_SetText( nextMapDesc, GetMapDisplayDesc( mapName ) ) - // Update window scrolling if we highlight a map not in view - int minScrollState = int( clamp( buttonID - (MAP_LIST_VISIBLE_ROWS - 1), 0, file.numMapButtonsOffScreen ) ) - int maxScrollState = int( clamp( buttonID, 0, file.numMapButtonsOffScreen ) ) - - if ( file.mapListScrollState < minScrollState ) - file.mapListScrollState = minScrollState - if ( file.mapListScrollState > maxScrollState ) - file.mapListScrollState = maxScrollState - - UpdateMapListScroll() } void function MapButton_LostFocus( var button ) { - HandleLockedCustomMenuItem( file.menu, button, [], true ) + 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] + string mapName = mapsArray[ mapID + ( file.currentMapPage * file.mapsPerPage ) ] printt( mapName, mapID ) @@ -165,36 +143,20 @@ void function MapButton_Activate( var button ) CloseActiveMenu() } - -void function OnMapListScrollUp_Activate( var button ) -{ - file.mapListScrollState-- - if ( file.mapListScrollState < 0 ) - file.mapListScrollState = 0 - - UpdateMapListScroll() -} - -void function OnMapListScrollDown_Activate( var button ) +void function CycleModesBack( var button ) { - file.mapListScrollState++ - if ( file.mapListScrollState > file.numMapButtonsOffScreen ) - file.mapListScrollState = file.numMapButtonsOffScreen - - UpdateMapListScroll() + if ( file.currentMapPage == 0 ) + return + + file.currentMapPage-- + UpdateVisibleMaps() } -function UpdateMapListScroll() +void function CycleModesForward( var button ) { - array buttons = file.buttons - local basePos = buttons[0].GetBasePos() - local offset = buttons[0].GetHeight() * file.mapListScrollState - - buttons[0].SetPos( basePos[0], basePos[1] - offset ) + if ( ( file.currentMapPage + 1 ) * file.mapsPerPage >= GetPrivateMatchMaps().len() ) + return + + file.currentMapPage++ + UpdateVisibleMaps() } - -void function CycleModesBack( var button ) -{} - -void function CycleModesForward( var button ) -{} diff --git a/bobthebob.testing/scripts/vscripts/ui/menu_mode_select.nut b/bobthebob.testing/scripts/vscripts/ui/menu_mode_select.nut index b6bd6d386..233767816 100644 --- a/bobthebob.testing/scripts/vscripts/ui/menu_mode_select.nut +++ b/bobthebob.testing/scripts/vscripts/ui/menu_mode_select.nut @@ -2,7 +2,6 @@ global function InitModesMenu struct { int currentModePage - } file const int MODES_PER_PAGE = 15 @@ -105,7 +104,7 @@ void function ModeButton_Click( var button ) int modeID = int( Hud_GetScriptID( button ) ) + ( file.currentModePage * MODES_PER_PAGE ) array modesArray = GetPrivateMatchModes() - string modeName = modesArray[mapID] + 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 -- cgit v1.2.3