From fdc38f3867a3727edf097ec0241efc0b59d75395 Mon Sep 17 00:00:00 2001 From: Kyle Gospodnetich Date: Thu, 21 Jul 2022 15:38:16 -0700 Subject: Fix missing fonts under Linux (#437) * Replace Arial and Lucidia fonts with Lato and Fira Code respectively, this fixes Linux users needing to install proprietary fonts to use the in-game console. * Clean up gitattributes and encoding.yml to be more specific about the txt files it checks against. UTF-16LE-BOM will crash the game with a division by zero error if it's not expecting the file to be encoded as such. * Replace Fira Code with Northstar Mono (Modified Fira Mono Regular) --- Northstar.Client/mod/resource/Lato-Regular.ttf | Bin 0 -> 657212 bytes Northstar.Client/mod/resource/NorthstarMono.ttf | Bin 0 -> 170600 bytes Northstar.Client/mod/resource/fontfiletable.txt | 40 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 Northstar.Client/mod/resource/Lato-Regular.ttf create mode 100644 Northstar.Client/mod/resource/NorthstarMono.ttf create mode 100644 Northstar.Client/mod/resource/fontfiletable.txt (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/Lato-Regular.ttf b/Northstar.Client/mod/resource/Lato-Regular.ttf new file mode 100644 index 00000000..adbfc467 Binary files /dev/null and b/Northstar.Client/mod/resource/Lato-Regular.ttf differ diff --git a/Northstar.Client/mod/resource/NorthstarMono.ttf b/Northstar.Client/mod/resource/NorthstarMono.ttf new file mode 100644 index 00000000..2814eee6 Binary files /dev/null and b/Northstar.Client/mod/resource/NorthstarMono.ttf differ diff --git a/Northstar.Client/mod/resource/fontfiletable.txt b/Northstar.Client/mod/resource/fontfiletable.txt new file mode 100644 index 00000000..b4238134 --- /dev/null +++ b/Northstar.Client/mod/resource/fontfiletable.txt @@ -0,0 +1,40 @@ +FontFileTable +{ + "Default" "resource/MetronicPro-Regular.vfont" [!$JAPANESE && !$TCHINESE] + "Default" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "Default" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + + "DefaultBold" "resource/MetronicPro-SemiBold.vfont" [!$JAPANESE && !$TCHINESE] + "DefaultBold" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "DefaultBold" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + + "Titanfall" "resource/Titanfall-Regular.vfont" [!$JAPANESE && !$TCHINESE && !$RUSSIAN] + "Titanfall" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "Titanfall" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + "Titanfall" "resource/MetronicPro-SemiBold.vfont" [$RUSSIAN] + + "marlett" "vgui/fonts/marlett.ttf" + + // Everything below is DONOTSHIP / Dev only + + "arial unicode ms" "resource/Lato-Regular.ttf" + + "lucida console" "resource/NorthstarMono.ttf" [$PC] + "lucida console" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] + + "tahoma" "fonts\\tahoma.ttf" [$PC] + "tahoma" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] + + "tahoma bold" "fonts\\tahomabd.ttf" [$PC] + "tahoma bold" "resource/MetronicPro-SemiBold.vfont" [$GAMECONSOLE] + + "courier new" "fonts\\cour.ttf" [$PC] + "courier new" "vgui/fonts/cour.ttf" [$GAMECONSOLE] + + "times new roman" "fonts\\times.ttf" [$PC] + "times new roman" "vgui/fonts/times.ttf" [$GAMECONSOLE] + + "arial" "resource/Lato-Regular.ttf" + "arial bold" "resource/Lato-Regular.ttf" + "arial narrow" "resource/Lato-Regular.ttf" +} -- cgit v1.2.3 From e591885e0336f33facbcf2b15c9cd99f9b217e70 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Tue, 26 Jul 2022 17:16:32 +0200 Subject: Serverside RUI, but it doesn't stink ( hopefully ) (#435) * Serverside polls * reset table so mods can wait for response * large message * popup message * announcement * info * status * fix uniboi crash * no need to return id * among * typo * Formatting * bruh * takyon doesn't know how to finish a review * Formatting * Do you not know how to finish a review or what * You should look at gamemode_aitdm for some funky formatting :) * Formatting * Formatting * Finally a good suggestion * fix client misinterpreting assets --- Northstar.Client/mod/scripts/kb_act.lst | 11 +- Northstar.Custom/mod.json | 10 + .../mod/scripts/vscripts/sh_message_utils.gnut | 505 +++++++++++++++++++++ 3 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/kb_act.lst b/Northstar.Client/mod/scripts/kb_act.lst index ace98222..238d7eef 100644 --- a/Northstar.Client/mod/scripts/kb_act.lst +++ b/Northstar.Client/mod/scripts/kb_act.lst @@ -1,7 +1,16 @@ "blank" "==========================" "blank" "NORTHSTAR" "blank" "==========================" -"toggleconsole" "Toggle Developer Console" +"toggleconsole" "Toggle Developer Console" +"vote 1" "Vote 1" +"vote 2" "Vote 2" +"vote 3" "Vote 3" +"vote 4" "Vote 4" +"vote 5" "Vote 5" +"vote 6" "Vote 6" +"vote 7" "Vote 7" +"vote 8" "Vote 8" +"vote 9" "Vote 9" "blank" "==========================" "blank" "#KEY_BINDINGS_HEADER_ACTIONS" "blank" "==========================" diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 46b5ab7f..28825a58 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -407,6 +407,16 @@ "ServerCallback": { "After": "CustomPilotCollision_InitPlaylistVars" } + }, + { + "Path": "sh_message_utils.gnut", + "RunOn": "( CLIENT || SERVER ) && MP", + "ClientCallback": { + "Before": "MessageUtils_ClientInit" + }, + "ServerCallback": { + "Before": "MessageUtils_ServerInit" + } } ], diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut new file mode 100644 index 00000000..6bbf77bd --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut @@ -0,0 +1,505 @@ +#if SERVER +global function MessageUtils_ServerInit + +global function NSCreatePollOnPlayer +global function NSGetPlayerResponse + +global function NSSendLargeMessageToPlayer +global function NSSendPopUpMessageToPlayer +global function NSSendAnnouncementMessageToPlayer +global function NSSendInfoMessageToPlayer + +global function NSCreateStatusMessageOnPlayer +global function NSEditStatusMessageOnPlayer +global function NSDeleteStatusMessageOnPlayer + +struct +{ + table playerPollResponses +} server +#endif // SERVER + + +#if CLIENT +global function MessageUtils_ClientInit + +vector ColorSelected = < 0.9, 0.8, 0.5 > +vector ColorBase = < 0.9, 0.5, 0.1 > + +struct tempMessage +{ + string title + string description + float duration + string image + int priority + int style + vector color +} + + +// Nested structs look funny, but are pretty helpful when reading code so I'm keeping them :) +struct +{ + struct + { + string header + array options + float duration + bool pollActive + array ruis + } poll + + string id + tempMessage temp + + array largeMessageQueue + array popupMessageQueue + array announcementQueue + array infoMessageQueue + + // table + table statusMessageList +} client +#endif // CLIENT + + +const int STATUS_MESSAGES_MAX = 4 + + +enum eMessageType +{ + POLL, + LARGE, + POPUP, + ANNOUNCEMENT, + INFO, + CREATE_STATUS, + EDIT_STATUS, + DELETE_STATUS +} + +enum eDataType +{ + POLL_HEADER, + POLL_OPTION, + POLL_DURATION, + POLL_SELECT, + TITLE, + DESC, + DURATION, + ASSET, + COLOR, + PRIORITY, + STYLE, + ID +} + +#if SERVER +void function MessageUtils_ServerInit() +{ + AddClientCommandCallback( "vote", ClientCommand_Vote ) + AddClientCommandCallback( "poll_respond", ClientCommand_PollRespond ) +} + +bool function ClientCommand_Vote( entity player, array args ) +{ + if( args.len() == 0 ) + return false + + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_SELECT + " " + args[0] ) + return true +} + +bool function ClientCommand_PollRespond( entity player, array args ) +{ + if( args.len() == 0 ) + return false + + server.playerPollResponses[player] <- args[0].tointeger() + return true +} + +void function NSCreateStatusMessageOnPlayer( entity player, string title, string description, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.CREATE_STATUS ) +} + +void function NSEditStatusMessageOnPlayer( entity player, string title, string description, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.EDIT_STATUS ) +} + +void function NSDeleteStatusMessageOnPlayer( entity player, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.DELETE_STATUS ) +} + +void function NSCreatePollOnPlayer( entity player, string header, array options, float duration ) +{ + foreach ( string option in options ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_OPTION + " " + option ) + + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_DURATION + " " + duration ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_HEADER + " " + header ) + + server.playerPollResponses[player] <- -1 // Reset poll response table + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.POLL ) +} + +int function NSGetPlayerResponse( entity player ) +{ + if( !( player in server.playerPollResponses ) ) + return -1 + + if( server.playerPollResponses[ player ] == -1 ) + return -1 + + return server.playerPollResponses[ player ] - 1 +} + +void function NSSendLargeMessageToPlayer( entity player, string title, string description, float duration, string image ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DURATION + " " + duration ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ASSET + " " + image ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.LARGE ) +} + +void function NSSendPopUpMessageToPlayer( entity player, string text ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + text ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.POPUP ) +} + +void function NSSendAnnouncementMessageToPlayer( entity player, string title, string description, vector color, int priority, int style ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.COLOR + " " + color.x + " " + color.y + " " + color.z ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.PRIORITY + " " + priority ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.STYLE + " " + style ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.ANNOUNCEMENT ) +} + +void function NSSendInfoMessageToPlayer( entity player, string text ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + text ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.INFO ) +} + +#endif // SERVER + +#if CLIENT +void function MessageUtils_ClientInit() +{ + // ServerHUDMessageRequest + AddServerToClientStringCommandCallback( "ServerHUDMessageShow", ServerCallback_CreateServerHUDMessage ) + // ServerHUDMessageRequest + AddServerToClientStringCommandCallback( "ServerHUDMessagePut", ServerCallback_UpdateServerHUDMessage ) + + thread LargeMessageHandler_Threaded() + thread PopUpMessageHandler_Threaded() + thread AnnouncementMessageHandler_Threaded() + thread InfoMessageHandler_Threaded() +} + +string function CombineArgsIntoString( array args ) +{ + string result + + // Ignore the first argument + for( int i = 1; i < args.len(); i++ ) + result += args[i] + " " + + return result +} + +void function ServerCallback_UpdateServerHUDMessage ( array args ) +{ + switch ( args[0].tointeger() ) + { + case eDataType.POLL_HEADER: + client.poll.header = CombineArgsIntoString( args ) + break + case eDataType.POLL_OPTION: + client.poll.options.append( CombineArgsIntoString( args ) ) + break + case eDataType.POLL_DURATION: + client.poll.duration = args[1].tofloat() + break + case eDataType.POLL_SELECT: + thread SelectPollOption_Threaded( args[1].tointeger() ) + break + case eDataType.TITLE: + client.temp.title = CombineArgsIntoString( args ) + break + case eDataType.DESC: + client.temp.description = CombineArgsIntoString( args ) + break + case eDataType.DURATION: + client.temp.duration = args[1].tofloat() + break + case eDataType.ASSET: + client.temp.image = CombineArgsIntoString( args ) + break + case eDataType.COLOR: + client.temp.color = Vector( args[1].tofloat(), args[2].tofloat(), args[3].tofloat()) + break + case eDataType.PRIORITY: + client.temp.priority = args[1].tointeger() + break + case eDataType.STYLE: + client.temp.style = args[1].tointeger() + break + case eDataType.ID: + client.id = args[1] + break + } +} + +void function ServerCallback_CreateServerHUDMessage ( array args ) +{ + switch ( args[0].tointeger() ) + { + case eMessageType.POLL: + thread ShowPollMessage_Threaded() + break + case eMessageType.LARGE: + client.largeMessageQueue.append( client.temp ) + break + case eMessageType.POPUP: + client.popupMessageQueue.append( client.temp ) + break + case eMessageType.ANNOUNCEMENT: + client.announcementQueue.append( client.temp ) + break + case eMessageType.INFO: + client.infoMessageQueue.append( client.temp ) + break + case eMessageType.CREATE_STATUS: + CreateStatusMessage( client.id ) + break + case eMessageType.EDIT_STATUS: + EditStatusMessage( client.id ) + break + case eMessageType.DELETE_STATUS: + thread DeleteStatusMessage( client.id ) + break + } +} + +void function DeleteStatusMessage( string id ) +{ + if ( id in client.statusMessageList ) + { + var rui = client.statusMessageList[ id ] + RuiSetGameTime( rui, "startFadeOutTime", Time() ) + + // Remove it from table + delete client.statusMessageList[ id ] + + // Wait for animation + wait 0.6 + + RuiDestroyIfAlive( rui ) + + int i = 0 + foreach( _id, _rui in client.statusMessageList ) + { + RuiSetInt( _rui, "listPos", i ) + i++ + } + } +} + +void function EditStatusMessage( string id ) +{ + if( id in client.statusMessageList ) + { + var rui = client.statusMessageList[ id ] + RuiSetString( rui, "titleText", client.temp.title ) + RuiSetString( rui, "itemText", client.temp.description ) + } +} + +void function CreateStatusMessage( string id ) +{ + // Cap at 4 messages at a time + if( client.statusMessageList.len() == STATUS_MESSAGES_MAX ) + return + + var rui = CreatePermanentCockpitRui( $"ui/at_wave_intro.rpak" ) + RuiSetInt( rui, "listPos", client.statusMessageList.len() ) + RuiSetGameTime( rui, "startFadeInTime", Time() ) + RuiSetString( rui, "titleText", client.temp.title ) + RuiSetString( rui, "itemText", client.temp.description ) + RuiSetFloat2( rui, "offset", < 0, -250, 0 > ) + + client.statusMessageList[ id ] <- rui +} + +void function SelectPollOption_Threaded( int index ) +{ + if ( index >= client.poll.ruis.len() || index <= 0 ) + return + + RuiSetFloat3( client.poll.ruis[ index ], "msgColor", ColorSelected ) + EmitSoundOnEntity( GetLocalClientPlayer(), "menu_accept" ) + + float endTime = 1 + client.poll.duration + while( endTime > Time() && client.poll.pollActive ) + WaitFrame() + + GetLocalClientPlayer().ClientCommand( "poll_respond " + index ) + + foreach( var rui in client.poll.ruis ) + RuiDestroyIfAlive( rui ) + + client.poll.ruis.clear() + client.poll.pollActive = false +} + +void function ShowPollMessage_Threaded() +{ + if( client.poll.pollActive ) + return + + client.poll.pollActive = true + + for( int i = 0; i < client.poll.options.len() + 1; i++ ) + { + var rui = CreateCockpitRui( $"ui/cockpit_console_text_top_left.rpak" ) + // This makes it fade and me no likey >:( + RuiSetFloat2( rui, "msgPos", < 0, 0.4 + i * 0.025, 0 > ) + if( i == 0 ) + { + RuiSetFloat3( rui, "msgColor", ColorSelected ) + RuiSetString( rui, "msgText", client.poll.header ) + } + else + { + RuiSetFloat3( rui, "msgColor", ColorBase ) + RuiSetString( rui, "msgText", i + ". " + client.poll.options[i - 1] ) + } + + RuiSetFloat( rui, "msgFontSize", 30.0 ) + RuiSetFloat( rui, "msgAlpha", 0.9 ) + RuiSetFloat( rui, "thicken", 0.0 ) + + client.poll.ruis.append( rui ) + } + + client.poll.options.clear() + + float endTime = Time() + client.poll.duration + while( endTime > Time() && client.poll.pollActive ) + WaitFrame() + + + foreach( var rui in client.poll.ruis ) + RuiDestroyIfAlive( rui ) + + client.poll.ruis.clear() + client.poll.pollActive = false +} + +void function InfoMessageHandler_Threaded() +{ + while( true ) + { + while( client.infoMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreatePermanentCockpitRui( $"ui/death_hint_mp.rpak" ) + RuiSetString( rui, "hintText", client.infoMessageQueue[0].description ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat3( rui, "bgColor", < 0, 0, 0 > ) + RuiSetFloat( rui, "bgAlpha", 0.5 ) + + wait 7 + + client.infoMessageQueue.remove( 0 ) + RuiDestroyIfAlive( rui ) + } +} + +void function AnnouncementMessageHandler_Threaded() +{ + while( true ) + { + while( client.announcementQueue.len() == 0 ) + WaitFrame() + + AnnouncementData announcement = Announcement_Create( client.announcementQueue[0].title ) + Announcement_SetSubText( announcement, client.announcementQueue[0].description ) + Announcement_SetTitleColor( announcement, client.announcementQueue[0].color ) + Announcement_SetPurge( announcement, true ) + Announcement_SetPriority( announcement, client.announcementQueue[0].priority ) + Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK ) + Announcement_SetStyle( announcement, client.announcementQueue[0].style ) + AnnouncementFromClass( GetLocalViewPlayer(), announcement ) + + wait 5 + + client.announcementQueue.remove(0) + } +} + +void function LargeMessageHandler_Threaded() +{ + while( true ) + { + while( client.largeMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreatePermanentCockpitRui( $"ui/fd_tutorial_tip.rpak" ) + RuiSetImage( rui, "backgroundImage", StringToAsset( strip( client.largeMessageQueue[0].image ) ) ) + RuiSetString( rui, "titleText", client.largeMessageQueue[0].title ) + RuiSetString( rui, "descriptionText", client.largeMessageQueue[0].description ) + RuiSetGameTime( rui, "updateTime", Time() ) + RuiSetFloat( rui, "duration", client.largeMessageQueue[0].duration ) + + wait client.largeMessageQueue[0].duration + + client.largeMessageQueue.remove(0) + RuiDestroyIfAlive( rui ) + } +} + +void function PopUpMessageHandler_Threaded() +{ + while( true ) + { + while( client.popupMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreateCockpitRui( $"ui/killdeath_info.rpak" ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat( rui, "duration", 20 ) // It has a weird end animation + RuiSetString( rui, "messageText", client.popupMessageQueue[0].description ) + RuiSetBool( rui, "isBigText", true ) + + wait 2.4 + + client.popupMessageQueue.remove(0) + RuiDestroyIfAlive( rui ) + } +} + +#endif // CLIENT \ No newline at end of file -- cgit v1.2.3 From 4a316c5c0055ffcf407dc2411b76438723187290 Mon Sep 17 00:00:00 2001 From: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Date: Mon, 8 Aug 2022 01:22:47 +0800 Subject: Support to input other languages in the search box (#477) Support to input other languages in the search box --- Northstar.Client/mod/resource/ui/menus/server_browser.menu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index 89fb951d..d25d1219 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -2197,7 +2197,7 @@ resource/ui/menus/mods_browse.menu font Default_21 allowRightClickMenu 0 allowSpecialCharacters 0 - unicode 0 + unicode 1 pin_to_sibling BtnSearchLabel pin_corner_to_sibling TOP_LEFT -- cgit v1.2.3 From ecd37edc3f833526518cf6a6abb2bd128fd0a51c Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:44:20 +0000 Subject: Change modlist interface (#401) * Change modlist interface * add the settings file * new current mod enabled indicator * Only show requiredOnClient warning when required * filter by required on client status * fix ONLY_REQUIRED instead of ONLY_NOT_REQUIRED * update list slider position when reopening * colorblind colors * convar for reversed list and allow unicode search * better colors for the blind * Update filtered modlist after changing mod status * fix some things * mod enabled color blind icon * move enabled icon --- Northstar.Client/mod.json | 10 + .../northstar_client_localisation_english.txt | 2 + .../mod/resource/ui/menus/modlist.menu | 1003 +++++++++++--------- .../resource/ui/menus/panels/modlist_settings.res | 79 ++ .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 679 ++++++++----- 5 files changed, 1110 insertions(+), 663 deletions(-) create mode 100644 Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 17b01543..7dcfcd21 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -31,6 +31,16 @@ { "Name": "filter_map_hide_locked", "DefaultValue": "0" + }, + { + "Name": "modlist_show_convars", + "DefaultValue": "0", + "Flags": 16777216 + }, + { + "Name": "modlist_reverse", + "DefaultValue": "0", + "Flags": 16777216 } ], "Scripts": [ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 8c6cadcf..3382e5b1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -301,6 +301,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "SHOW_ALL" "All" "SHOW_ONLY_ENABLED" "Only Enabled" "SHOW_ONLY_DISABLED" "Only Disabled" + "SHOW_ONLY_NOT_REQUIRED" "Only Optional Mods" + "SHOW_ONLY_REQUIRED" "Only Required Mods" // Maps menu "HIDE_LOCKED" "Hide locked" diff --git a/Northstar.Client/mod/resource/ui/menus/modlist.menu b/Northstar.Client/mod/resource/ui/menus/modlist.menu index ffe9a257..da59bcdd 100644 --- a/Northstar.Client/mod/resource/ui/menus/modlist.menu +++ b/Northstar.Client/mod/resource/ui/menus/modlist.menu @@ -1,4 +1,4 @@ -resource/ui/menus/mods_browse.menu +resource/ui/menus/modlist.menu { menu { @@ -18,497 +18,654 @@ resource/ui/menus/mods_browse.menu Vignette { - ControlName ImagePanel - InheritProperties MenuVignette + ControlName ImagePanel + InheritProperties MenuVignette } Title { - ControlName Label - InheritProperties MenuTitle - labelText "#MENU_TITLE_MODS" + ControlName Label + InheritProperties MenuTitle + labelText "#MENU_TITLE_MODS" } ImgTopBar { - ControlName ImagePanel - InheritProperties MenuTopBar + ControlName ImagePanel + InheritProperties MenuTopBar } - + ButtonRowAnchor { - ControlName Label - labelText "" + ControlName Label + labelText "" - xpos 120 - ypos 160 + xpos 120 + ypos 160 } - + FilterButtonsRowAnchor { - ControlName Label - labelText "" + ControlName Label + labelText "" - xpos 90 - ypos 848 + xpos 90 + ypos 848 } - + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PANELS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BtnMod1 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 0 - navUp BtnMod15 - navDown BtnMod2 - - pin_to_sibling ButtonRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - BtnMod2 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 1 - pin_to_sibling BtnMod1 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod1 - navDown BtnMod3 - } - BtnMod3 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 2 - pin_to_sibling BtnMod2 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod2 - navDown BtnMod4 - } - BtnMod4 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 3 - pin_to_sibling BtnMod3 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - //ypos 11 - navUp BtnMod3 - navDown BtnMod5 - } - BtnMod5 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 4 - pin_to_sibling BtnMod4 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod4 - navDown BtnMod6 - } - BtnMod6 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 5 - pin_to_sibling BtnMod5 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod5 - navDown BtnMod7 - } - BtnMod7 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 6 - pin_to_sibling BtnMod6 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod6 - navDown BtnMod8 - } - BtnMod8 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 7 - pin_to_sibling BtnMod7 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod7 - navDown BtnMod9 - } - BtnMod9 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 8 - pin_to_sibling BtnMod8 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod8 - navDown BtnMod10 - } - BtnMod10 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 9 - pin_to_sibling BtnMod9 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod9 - navDown BtnMod11 - } - BtnMod11 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 10 - pin_to_sibling BtnMod10 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod10 - navDown BtnMod12 - } - BtnMod12 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 11 - pin_to_sibling BtnMod11 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod11 - navDown BtnMod13 - } - BtnMod13 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 12 - pin_to_sibling BtnMod12 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod12 - navDown BtnMod14 - } - BtnMod14 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 13 - pin_to_sibling BtnMod13 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod13 - navDown BtnMod15 - } - BtnMod15 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 14 - pin_to_sibling BtnMod14 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod14 - navDown BtnMod1 - } - BtnMod16 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 15 - pin_to_sibling BtnMod15 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod15 - navDown BtnMod17 - } - BtnMod17 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 16 - pin_to_sibling BtnMod16 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod16 - navDown BtnMod18 + Panel1 + { + ControlName CNestedPanel + classname ModSelectorPanel + scriptID 1 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling ButtonRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel2 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 2 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel1 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel3 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 3 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel2 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel4 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 4 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel3 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel5 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 5 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel4 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel6 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 6 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel5 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel7 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 7 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel6 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel8 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 8 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel7 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel9 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 9 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel8 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel10 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 10 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel9 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel11 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 11 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel10 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel12 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 12 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel11 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT } + Panel13 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 13 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel12 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel14 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 14 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel13 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel15 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 15 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel14 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +// FILTERS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + FilterPanel { - ControlName RuiPanel - wide 800 - tall 112 - xpos -8 - classname FilterPanelChild - - rui "ui/knowledgebase_panel.rpak" + ControlName RuiPanel + classname FilterPanelChild + + wide 800 + tall 112 + xpos -8 + zpos -1 - visible 1 - zpos -1 + rui "ui/knowledgebase_panel.rpak" + visible 1 - pin_to_sibling FilterButtonsRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT + pin_to_sibling FilterButtonsRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT } - + BtnSearchLabel { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#SEARCHBAR_LABEL" - textAlignment west - classname FilterPanelChild - - wide 500 - xpos -23 - ypos -16 - - wrap 1 - visible 1 - zpos 0 - - pin_to_sibling FilterButtonsRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + classname FilterPanelChild + + labelText #SEARCHBAR_LABEL + textAlignment west + + wide 500 + xpos -23 + ypos -16 + zpos 0 + wrap 1 + visible 1 + + + + pin_to_sibling FilterButtonsRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + BtnModsSearch { - ControlName TextEntry - classname FilterPanelChild - zpos 100 // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. - xpos -400 - ypos -5 - wide 390 - tall 30 - textHidden 0 - editable 1 - font Default_21 - allowRightClickMenu 0 - allowSpecialCharacters 0 - unicode 0 - - pin_to_sibling BtnSearchLabel - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_RIGHT + ControlName TextEntry + classname FilterPanelChild + + zpos 100 // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + xpos -400 + ypos -5 + wide 390 + tall 30 + + textHidden 0 // Why? + editable 1 + font Default_21 + + allowRightClickMenu 0 + allowSpecialCharacters 0 + unicode 1 + + pin_to_sibling BtnSearchLabel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_RIGHT } - + SwtBtnShowFilter { - ControlName RuiButton - InheritProperties SwitchButton - labelText "#SHOW" - ConVar "filter_mods" - classname FilterPanelChild + ControlName RuiButton + InheritProperties SwitchButton + classname FilterPanelChild + + labelText "#SHOW" + ConVar "filter_mods" wide 500 - + list { - "#SHOW_ALL" 0 - "#SHOW_ONLY_ENABLED" 1 - "#SHOW_ONLY_DISABLED" 2 + "#SHOW_ALL" 0 + "#SHOW_ONLY_ENABLED" 1 + "#SHOW_ONLY_DISABLED" 2 + "#SHOW_ONLY_NOT_REQUIRED" 3 + "#SHOW_ONLY_REQUIRED" 4 } - - pin_to_sibling BtnSearchLabel - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + + pin_to_sibling BtnSearchLabel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT } - + + BtnListReverse + { + ControlName RuiButton + InheritProperties SwitchButton + classname FilterPanelChild + + xpos -15 + ypos -15 + + labelText "Reverse" + ConVar "modlist_reverse" + wide 260 + + list + { + "low first" 0 + "high first" 1 + } + + pin_to_sibling FilterPanel + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_RIGHT + } + BtnFiltersClear { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#CLEAR_FILTERS" - classname FilterPanelChild - wide 100 - xpos -15 - ypos -55 - zpos 90 - - scriptID 999 - - pin_to_sibling FilterPanel - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner BOTTOM_RIGHT + ControlName RuiButton + InheritProperties RuiSmallButton + classname FilterPanelChild + + labelText "#CLEAR_FILTERS" + wide 100 + xpos -15 + ypos -55 + zpos 90 + + pin_to_sibling FilterPanel + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner BOTTOM_RIGHT } - + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MOD INFO +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ModButtonsPanel + { + ControlName RuiPanel + classname FilterPanelChild + + wide 950 + tall 112 + + rui "ui/knowledgebase_panel.rpak" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP + pin_to_sibling_corner BOTTOM + } + + HideCVButton + { + ControlName RuiButton + InheritProperties SwitchButton + + labelText "ConVars" + ConVar "modlist_show_convars" + wide 300 + + list + { + "Hidden" 0 + "Shown" 1 + } + + pin_to_sibling ModButtonsPanel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + + ModPageButton + { + ControlName RuiButton + InheritProperties RuiSmallButton + + textAlignment west + visible 0 + + pin_to_sibling HideCVButton + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningLegendImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + xpos -10 + ypos -5 + visible 0 + + pin_to_sibling ModButtonsPanel + pin_corner_to_sibling BOTTOM_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningLegendLabel + { + ControlName Label + + labelText " : This mod gets (un)loaded automatically" + wide 500 + tall 50 + visible 0 + + pin_to_sibling WarningLegendImage + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + LabelDetails { - ControlName RuiPanel - xpos 900 - ypos 160 - tall 800 - wide 950 - rui "ui/knowledgebase_panel.rpak" - wrap 1 - visible 1 - zpos 1 + ControlName RuiPanel + + xpos 900 + ypos 160 + zpos 1 + + tall 688 + wide 950 + rui "ui/knowledgebase_panel.rpak" + wrap 1 + visible 1 } - + + ModEnabledBar + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 950 + tall 7 + zpos 2 + visible 0 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SLIDER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + BtnModListUpArrow { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "A" - wide 40 - tall 40 - xpos 2 - ypos 2 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 40 + xpos 2 + ypos 2 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListUpArrowPanel { - ControlName RuiPanel - wide 40 - tall 40 - xpos 2 - ypos 2 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 40 + xpos 2 + ypos 2 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + zpos -1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListDownArrow { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "V" - wide 40 - tall 40 - xpos 2 - ypos -646 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 40 + xpos 2 + ypos -646 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListDownArrowPanel { - ControlName RuiPanel - wide 40 - tall 40 - xpos 2 - ypos -646 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 40 + xpos 2 + ypos -646 + zpos -1 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListSlider { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "V" - wide 40 - tall 604 - xpos 2 - ypos -40 - zpos 0 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos 0 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListSliderPanel { - ControlName RuiPanel - wide 40 - tall 604 - xpos 2 - ypos -40 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos -1 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + // sh_menu_models.gnut has a global function which gets called when // left mouse button gets called while hovering and has mouse // deltaX; deltaY which we can yoink for ourselfes MouseMovementCapture { - ControlName CMouseMovementCapturePanel - wide 40 - tall 604 - xpos 2 - ypos -40 - zpos 1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT + ControlName CMouseMovementCapturePanel + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos 1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FooterButtons { - ControlName CNestedPanel - InheritProperties FooterButtons + ControlName CNestedPanel + InheritProperties FooterButtons } } } diff --git a/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res b/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res new file mode 100644 index 00000000..cd596238 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res @@ -0,0 +1,79 @@ +resource/ui/menus/panels/modlist_setting.res +{ + BtnMod + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModButton + labelText "please show up" + + pin_to_sibling ControlBox + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + Header + { + ControlName Label + wide 400 + labelText "labelText" + + pin_to_sibling ControlBox + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + ControlBox + { + ControlName RuiPanel + classname ControlBox + + tall 30 + wide 5 + ypos 5 + rui "ui/basic_image.rpak" + + pin_corner_to_sibling LEFT + pin_to_sibling_corner LEFT + } + + BottomLine + { + ControlName ImagePanel + InheritProperties MenuTopBar + ypos 0 + wide %50 + + pin_to_sibling BtnMod + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + visible 0 + + pin_to_sibling BtnMod + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + EnabledImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + visible 0 + + pin_to_sibling BtnMod + pin_corner_to_sibling RIGHT + pin_to_sibling_corner LEFT + } +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 15d78025..01149bb0 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -5,18 +5,26 @@ global function AddNorthstarModMenu_MainMenuFooter global function ReloadMods -const int BUTTONS_PER_PAGE = 17 - +struct modData { + string name = "" + string version = "" + string link = "" + int loadPriority = 0 + bool enabled = false + array conVars = [] +} -struct modStruct { - int modIndex - string modName +struct panelContent { + modData& mod + bool isHeader = false } enum filterShow { ALL = 0, ONLY_ENABLED = 1, ONLY_DISABLED = 2 + ONLY_NOT_REQUIRED = 3, + ONLY_REQUIRED = 4 } struct { @@ -25,16 +33,19 @@ struct { } mouseDeltaBuffer struct { - bool shouldReloadModsOnEnd - string currentMod - var currentButton - int scrollOffset = 0 - - array modsArrayFiltered - + array mods var menu + array panels + int scrollOffset = 0 + array enabledMods + var currentButton + string searchTerm + modData& lastMod } file +const int PANELS_LEN = 15 +const string[3] CORE_MODS = ["Northstar.Client", "Northstar.Coop", "Northstar.CustomServers"] // Shows a warning if you try to disable these + void function AddNorthstarModMenu() { AddMenu( "ModListMenu", $"resource/ui/menus/modlist.menu", InitModMenu ) @@ -54,11 +65,46 @@ void function AdvanceToModListMenu( var button ) void function InitModMenu() { file.menu = GetMenu( "ModListMenu" ) - + file.panels = GetElementsByClassname( file.menu, "ModSelectorPanel" ) + + var rui = Hud_GetRui( Hud_GetChild( file.menu, "WarningLegendImage" ) ) + RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) + + RuiSetFloat( Hud_GetRui( Hud_GetChild( file.menu, "ModEnabledBar" ) ), "basicImageAlpha", 0.8 ) + + // Mod buttons + foreach ( var panel in file.panels ) + { + var button = Hud_GetChild( panel, "BtnMod" ) + AddButtonEventHandler( button, UIE_GET_FOCUS, OnModButtonFocused ) + AddButtonEventHandler( button, UIE_CLICK, OnModButtonPressed ) + + var rui = Hud_GetRui( Hud_GetChild( panel, "WarningImage" ) ) + RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) + } + AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + // UI Events AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnModMenuClosed ) + + // up / down buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListUpArrow" ), UIE_CLICK, OnUpArrowSelected ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListDownArrow" ), UIE_CLICK, OnDownArrowSelected ) + + // Mod info buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "ModPageButton" ), UIE_CLICK, OnModLinkButtonPressed ) + + // Filter buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnShowFilter"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModsSearch"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnListReverse"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear"), UIE_CLICK, OnBtnFiltersClear_Activate ) + + AddButtonEventHandler( Hud_GetChild( file.menu, "HideCVButton"), UIE_CHANGE, OnHideConVarsChange ) + + // Footers AddMenuFooterOption( file.menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) AddMenuFooterOption( file.menu, @@ -74,37 +120,25 @@ void function InitModMenu() "#AUTHENTICATION_AGREEMENT", OnAuthenticationAgreementButtonPressed ) - - foreach ( var button in GetElementsByClassname( file.menu, "ModButton" ) ) - { - AddButtonEventHandler( button, UIE_GET_FOCUS, OnModMenuButtonFocused ) - AddButtonEventHandler( button, UIE_CLICK, OnModMenuButtonPressed ) - } - - AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnShowFilter"), UIE_CHANGE, OnFiltersChange ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModsSearch"), UIE_CHANGE, OnFiltersChange ) - - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListUpArrow"), UIE_CLICK, OnUpArrowSelected ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListDownArrow"), UIE_CLICK, OnDownArrowSelected ) - - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear"), UIE_CLICK, OnBtnFiltersClear_Activate ) - + // Nuke weird rui on filter switch RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnShowFilter")), "buttonText", "") + RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "HideCVButton")), "buttonText", "") + RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "BtnListReverse")), "buttonText", "") } +// EVENTS + void function OnModMenuOpened() { - file.shouldReloadModsOnEnd = false - file.scrollOffset = 0 - - RegisterButtonPressedCallback(MOUSE_WHEEL_UP , OnScrollUp) - RegisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) + file.enabledMods = GetEnabledModsArray() // used to check if mods should be reloaded - Hud_SetText( Hud_GetChild( file.menu, "Title" ), "#MENU_TITLE_MODS" ) + UpdateList() + UpdateListSliderHeight() + UpdateListSliderPosition() - - OnFiltersChange(0) + RegisterButtonPressedCallback(MOUSE_WHEEL_UP , OnScrollUp) + RegisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) } void function OnModMenuClosed() @@ -115,120 +149,118 @@ void function OnModMenuClosed() DeregisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) } catch ( ex ) {} - - if ( file.shouldReloadModsOnEnd ) - ReloadMods() -} - -void function OnFiltersChange( var n ) -{ - file.scrollOffset = 0 - - HideAllButtons() - - RefreshModsArray() - - UpdateList() - - UpdateListSliderHeight() -} -void function RefreshModsArray() -{ - string searchTerm = Hud_GetUTF8Text( Hud_GetChild( file.menu, "BtnModsSearch" ) ).tolower() - - file.modsArrayFiltered.clear() - - - bool useSearch = searchTerm != "" - - - array modNames = NSGetModNames() - int modCount = modNames.len() - - foreach ( int index_, mod in modNames ) { - modStruct tempMod - tempMod.modIndex = index_ - tempMod.modName = mod - - int filter = GetConVarInt( "filter_mods" ) - bool enabled = NSIsModEnabled( tempMod.modName ) - - bool containsTerm = tempMod.modName.tolower().find(searchTerm) != null - - if ( filter == filterShow.ALL && (useSearch == true ? containsTerm : true ) ) - { - file.modsArrayFiltered.append( tempMod ) - } - else if ( filter == filterShow.ONLY_ENABLED && enabled && (useSearch == true ? containsTerm : true )) - { - file.modsArrayFiltered.append( tempMod ) - } - else if ( filter == filterShow.ONLY_DISABLED && !enabled && (useSearch == true ? containsTerm : true )) + array current = GetEnabledModsArray() + bool reload + foreach ( string mod in current ) + { + if ( file.enabledMods.find(mod) == -1 ) { - file.modsArrayFiltered.append( tempMod ) + reload = true + break } } + if ( current.len() != file.enabledMods.len() || reload ) // Only reload if we have to + ReloadMods() } -void function HideAllButtons() +void function OnModButtonFocused( var button ) { - array buttons = GetElementsByClassname( file.menu, "ModButton" ) - - // disable all buttons, we'll enable the ones we need later - foreach ( var button in buttons ) + file.currentButton = button + file.lastMod = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod + string modName = file.lastMod.name + var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) + + RuiSetGameTime( rui, "startTime", -99999.99 ) // make sure it skips the whole animation for showing this + RuiSetString( rui, "headerText", modName ) + RuiSetString( rui, "messageText", FormatModDescription( modName ) ) + + // Add a button to open the link with if required + string link = NSGetModDownloadLinkByModName( modName ) + var linkButton = Hud_GetChild( file.menu, "ModPageButton" ) + if ( link.len() ) { - Hud_SetEnabled( button, false ) - Hud_SetVisible( button, false ) + Hud_SetEnabled( linkButton, true ) + Hud_SetVisible( linkButton, true ) + Hud_SetText( linkButton, link ) } + else + { + Hud_SetEnabled( linkButton, false ) + Hud_SetVisible( linkButton, false ) + } + + SetControlBarColor( modName ) + + bool required = NSIsModRequiredOnClient( modName ) + Hud_SetVisible( Hud_GetChild( file.menu, "WarningLegendLabel" ), required ) + Hud_SetVisible( Hud_GetChild( file.menu, "WarningLegendImage" ), required ) } -void function UpdateList() +void function OnModButtonPressed( var button ) { - array buttons = GetElementsByClassname( file.menu, "ModButton" ) - - - int j = file.modsArrayFiltered.len() > 17 ? 17 : file.modsArrayFiltered.len() - - for ( int i = 0; i < j; i++ ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod.name + if ( StaticFind( modName ) && NSIsModEnabled( modName ) ) + CoreModToggleDialog( modName ) + else { - Hud_SetEnabled( buttons[ i ], true ) - Hud_SetVisible( buttons[ i ], true ) - - SetModMenuNameText( buttons[ i ] ) + NSSetModEnabled( modName, !NSIsModEnabled( modName ) ) + var panel = file.panels[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) - 1 ] + SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) + SetControlBarColor( modName ) + SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) + RefreshMods() } } -void function SetModMenuNameText( var button ) +void function OnReloadModsButtonPressed( var button ) { - modStruct mod = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ] + ReloadMods() +} - // should be localisation at some point - if ( NSIsModEnabled( mod.modName ) ) - SetButtonRuiText( button, mod.modName + " v" + NSGetModVersionByModName( mod.modName ) ) - else - SetButtonRuiText( button, mod.modName + " (DISABLED)" ) +void function OnAuthenticationAgreementButtonPressed( var button ) +{ + NorthstarMasterServerAuthDialog() } -void function OnModMenuButtonPressed( var button ) +void function OnModLinkButtonPressed( var button ) { - string modName = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ].modName - if ( ( modName == "Northstar.Client" || modName == "Northstar.Coop" || modName == "Northstar.CustomServers") && NSIsModEnabled( modName ) ) - { - file.currentMod = modName - file.currentButton = button - CoreModToggleDialog( modName ) - } - else - { - NSSetModEnabled( modName, !NSIsModEnabled( modName ) ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) + file.scrollOffset - 1 ].mod.name + string link = NSGetModDownloadLinkByModName( modName ) + if ( link.find("http://") != 0 && link.find("https://") != 0 ) + link = "http://" + link // links without the http or https protocol get opened in the internal browser + LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL ) +} + +void function OnFiltersChange( var n ) +{ + file.scrollOffset = 0 - SetModMenuNameText( button ) + UpdateList() + UpdateListSliderHeight() + UpdateListSliderPosition() +} - file.shouldReloadModsOnEnd = true - } +void function OnBtnFiltersClear_Activate( var button ) +{ + Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) + + SetConVarInt( "filter_mods", 0 ) + + OnFiltersChange( null ) +} + +void function OnHideConVarsChange( var n ) +{ + string modName = file.lastMod.name + if ( modName == "" ) + return + var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) + RuiSetString( rui, "messageText", FormatModDescription( modName ) ) } +// LIST LOGIC + void function CoreModToggleDialog( string mod ) { DialogData dialogData @@ -247,46 +279,235 @@ void function CoreModToggleDialog( string mod ) void function DisableMod() { - NSSetModEnabled( file.currentMod, false ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) + file.scrollOffset - 1 ].mod.name + NSSetModEnabled( modName, false ) - SetModMenuNameText( file.currentButton ) + var panel = file.panels[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) - 1] + SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) + SetControlBarColor( modName ) + SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) - file.shouldReloadModsOnEnd = true + RefreshMods() } -void function OnModMenuButtonFocused( var button ) +array function GetEnabledModsArray() { - string modName = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ].modName + array enabledMods + foreach ( string mod in NSGetModNames() ) + { + if ( NSIsModEnabled( mod ) ) + enabledMods.append( mod ) + } + return enabledMods +} - var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) - - RuiSetGameTime( rui, "startTime", -99999.99 ) // make sure it skips the whole animation for showing this - RuiSetString( rui, "headerText", modName ) - RuiSetString( rui, "messageText", FormatModDescription( modName ) ) +void function HideAllPanels() +{ + foreach ( var panel in file.panels ) + { + Hud_SetEnabled( panel, false ) + Hud_SetVisible( panel, false ) + } +} + +void function UpdateList() +{ + HideAllPanels() + RefreshMods() + DisplayModPanels() +} + +void function RefreshMods() +{ + array modNames = NSGetModNames() + file.mods.clear() + + bool reverse = GetConVarBool( "modlist_reverse" ) + + int lastLoadPriority = reverse ? NSGetModLoadPriority( modNames[ modNames.len() - 1 ] ) + 1 : -1 + string searchTerm = Hud_GetUTF8Text( Hud_GetChild( file.menu, "BtnModsSearch" ) ).tolower() + + for ( int i = reverse ? modNames.len() - 1 : 0; + reverse ? ( i >= 0 ) : ( i < modNames.len() ); + i += ( reverse ? -1 : 1) ) + { + string mod = modNames[i] + + if ( searchTerm.len() && mod.tolower().find( searchTerm ) == null ) + continue + + bool enabled = NSIsModEnabled( mod ) + bool required = NSIsModRequiredOnClient( mod ) + switch ( GetConVarInt( "filter_mods" ) ) + { + case filterShow.ONLY_ENABLED: + if ( !enabled ) + continue + break + case filterShow.ONLY_DISABLED: + if ( enabled ) + continue + break + case filterShow.ONLY_REQUIRED: + if ( !required ) + continue + break + case filterShow.ONLY_NOT_REQUIRED: + if( required ) + continue + break + } + + int pr = NSGetModLoadPriority( mod ) + + if ( reverse ? pr < lastLoadPriority : pr > lastLoadPriority ) + { + modData m + m.name = pr.tostring() + + panelContent c + c.mod = m + c.isHeader = true + file.mods.append( c ) + lastLoadPriority = pr + } + + modData m + m.name = mod + m.version = NSGetModVersionByModName( mod ) + m.link = NSGetModDownloadLinkByModName( mod ) + m.loadPriority = NSGetModLoadPriority( mod ) + m.enabled = enabled + m.conVars = NSGetModConvarsByModName( mod ) + + panelContent c + c.mod = m + + file.mods.append( c ) + } +} + +void function DisplayModPanels() +{ + foreach ( int i, var panel in file.panels) + { + if ( i >= file.mods.len() ) // don't try to show more panels than needed + break + + panelContent c = file.mods[ file.scrollOffset + i ] + modData mod = c.mod + var btn = Hud_GetChild( panel, "BtnMod" ) + var headerLabel = Hud_GetChild( panel, "Header" ) + var box = Hud_GetChild( panel, "ControlBox" ) + var line = Hud_GetChild( panel, "BottomLine" ) + var warning = Hud_GetChild( panel, "WarningImage" ) + var enabledImage = Hud_GetChild( panel, "EnabledImage" ) + + if ( c.isHeader ) + { + Hud_SetEnabled( btn, false ) + Hud_SetVisible( btn, false ) + + Hud_SetText( headerLabel, "Load Priority: " + mod.name ) + Hud_SetVisible( headerLabel, true ) + + Hud_SetVisible( box, false ) + Hud_SetVisible( line, true ) + + Hud_SetVisible( warning, false ) + Hud_SetVisible( enabledImage, false ) + } + else + { + Hud_SetEnabled( btn, true ) + Hud_SetVisible( btn, true ) + Hud_SetText( btn, mod.name ) + + Hud_SetVisible( headerLabel, false ) + + SetControlBoxColor( box, mod.name ) + Hud_SetVisible( box, true ) + Hud_SetVisible( line, false ) + + Hud_SetVisible( warning, NSIsModRequiredOnClient( c.mod.name ) ) + + SetModEnabledHelperImageAsset( enabledImage, c.mod.name ) + } + Hud_SetVisible( panel, true ) + } +} + +void function SetModEnabledHelperImageAsset( var panel, string modName ) +{ + if( NSIsModEnabled( modName ) ) + RuiSetImage( Hud_GetRui( panel ), "basicImage", $"rui/menu/common/merit_state_success" ) + else + RuiSetImage( Hud_GetRui( panel ), "basicImage", $"rui/menu/common/merit_state_failure" ) + RuiSetFloat3(Hud_GetRui( panel ), "basicImageColor", GetControlColorForMod( modName ) ) + Hud_SetVisible( panel, true ) +} + +void function SetControlBoxColor( var box, string modName ) +{ + var rui = Hud_GetRui( box ) + // if ( NSIsModEnabled( modName ) ) + // RuiSetFloat3(rui, "basicImageColor", <0,1,0>) + // else + // RuiSetFloat3(rui, "basicImageColor", <1,0,0>) + RuiSetFloat3(rui, "basicImageColor", GetControlColorForMod( modName ) ) +} + +void function SetControlBarColor( string modName ) +{ + var bar_element = Hud_GetChild( file.menu, "ModEnabledBar" ) + var bar = Hud_GetRui( bar_element ) + // if ( NSIsModEnabled( modName ) ) + // RuiSetFloat3(bar, "basicImageColor", <0,1,0>) + // else + // RuiSetFloat3(bar, "basicImageColor", <1,0,0>) + RuiSetFloat3(bar, "basicImageColor", GetControlColorForMod( modName ) ) + Hud_SetVisible( bar_element, true ) +} + +vector function GetControlColorForMod( string modName ) +{ + if ( NSIsModEnabled( modName ) ) + switch ( GetConVarInt( "colorblind_mode" ) ) + { + case 1: + case 2: + case 3: + default: + return <0,1,0> + } + else + switch ( GetConVarInt( "colorblind_mode" ) ) + { + case 1: + case 2: + return <0.29,0,0.57> + case 3: + default: + return <1,0,0> + } + unreachable } string function FormatModDescription( string modName ) { string ret // version - ret += format( "Version %s\n", NSGetModVersionByModName( modName ) ) - - // download link - string modLink = NSGetModDownloadLinkByModName( modName ) - if ( modLink.len() != 0 ) - ret += format( "Download link: \"%s\"\n", modLink ) - + ret += format( "Version %s\n", NSGetModVersionByModName( modName ) ) + // load priority ret += format( "Load Priority: %i\n", NSGetModLoadPriority( modName ) ) - - // todo: add ClientRequired here - + // convars array modCvars = NSGetModConvarsByModName( modName ) - if ( modCvars.len() != 0 ) + if ( modCvars.len() != 0 && GetConVarBool( "modlist_show_convars" ) ) { ret += "ConVars: " - + for ( int i = 0; i < modCvars.len(); i++ ) { if ( i != modCvars.len() - 1 ) @@ -294,76 +515,33 @@ string function FormatModDescription( string modName ) else ret += format( "\"%s\"", modCvars[ i ] ) } - + ret += "\n" } - + // description ret += format( "\n%s\n", NSGetModDescriptionByModName( modName ) ) - - return ret -} - -void function OnReloadModsButtonPressed( var button ) -{ - ReloadMods() -} - -void function ReloadMods() -{ - NSReloadMods() - ClientCommand( "reload_localization" ) - ClientCommand( "loadPlaylists" ) - - bool svCheatsOriginal = GetConVarBool( "sv_cheats" ) - SetConVarBool( "sv_cheats", true ) - ClientCommand( "weapon_reparse" ) // weapon_reparse only works if a server is running and sv_cheats is 1, gotta figure this out eventually - SetConVarBool( "sv_cheats", svCheatsOriginal ) - - // note: the logic for this seems really odd, unsure why it doesn't seem to update, since the same code seems to get run irregardless of whether we've read weapon data before - ClientCommand( "uiscript_reset" ) -} -void function OnAuthenticationAgreementButtonPressed( var button ) -{ - NorthstarMasterServerAuthDialog() + return ret } +//////////// +// SLIDER +//////////// -void function OnBtnFiltersClear_Activate( var button ) -{ - Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) - - SetConVarInt( "filter_mods", 0 ) - - OnFiltersChange(0) -} - -////////////////////////////// -// Slider -////////////////////////////// void function UpdateMouseDeltaBuffer(int x, int y) { - mouseDeltaBuffer.deltaX += x - mouseDeltaBuffer.deltaY += y + mouseDeltaBuffer.deltaX = x + mouseDeltaBuffer.deltaY = y SliderBarUpdate() } -void function FlushMouseDeltaBuffer() -{ - mouseDeltaBuffer.deltaX = 0 - mouseDeltaBuffer.deltaY = 0 -} - void function SliderBarUpdate() { - if ( file.modsArrayFiltered.len() <= 17 ) - { - FlushMouseDeltaBuffer() + if ( file.mods.len() <= 15 ) return - } var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) @@ -376,12 +554,11 @@ void function SliderBarUpdate() float maxYPos = minYPos - (maxHeight - Hud_GetHeight( sliderPanel )) float useableSpace = (maxHeight - Hud_GetHeight( sliderPanel )) - float jump = minYPos - (useableSpace / ( float( file.modsArrayFiltered.len()))) + float jump = minYPos - (useableSpace / ( float( file.mods.len()))) // got local from official respaw scripts, without untyped throws an error local pos = Hud_GetPos(sliderButton)[1] local newPos = pos - mouseDeltaBuffer.deltaY - FlushMouseDeltaBuffer() if ( newPos < maxYPos ) newPos = maxYPos if ( newPos > minYPos ) newPos = minYPos @@ -390,69 +567,65 @@ void function SliderBarUpdate() Hud_SetPos( sliderPanel , 2, newPos ) Hud_SetPos( movementCapture , 2, newPos ) - file.scrollOffset = -int( ( (newPos - minYPos) / useableSpace ) * ( file.modsArrayFiltered.len() - BUTTONS_PER_PAGE) ) + file.scrollOffset = -int( ( (newPos - minYPos) / useableSpace ) * ( file.mods.len() - PANELS_LEN) ) UpdateList() } -void function UpdateListSliderHeight() +void function UpdateListSliderPosition() { var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) - - float mods = float ( file.modsArrayFiltered.len() ) - float maxHeight = 604.0 * (GetScreenSize()[1] / 1080.0) - float minHeight = 80.0 * (GetScreenSize()[1] / 1080.0) + float mods = float ( file.mods.len() ) - float height = maxHeight * ( float( BUTTONS_PER_PAGE ) / mods ) + float minYPos = -40.0 * (GetScreenSize()[1] / 1080.0) + float useableSpace = (604.0 * (GetScreenSize()[1] / 1080.0) - Hud_GetHeight( sliderPanel )) - if ( height > maxHeight ) height = maxHeight - if ( height < minHeight ) height = minHeight + float jump = minYPos - (useableSpace / ( mods - float( PANELS_LEN ) ) * file.scrollOffset) - Hud_SetHeight( sliderButton , height ) - Hud_SetHeight( sliderPanel , height ) - Hud_SetHeight( movementCapture , height ) -} + if ( jump > minYPos ) jump = minYPos + Hud_SetPos( sliderButton , 2, jump ) + Hud_SetPos( sliderPanel , 2, jump ) + Hud_SetPos( movementCapture , 2, jump ) +} -void function UpdateListSliderPosition() +void function UpdateListSliderHeight() { var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) - - float mods = float ( file.modsArrayFiltered.len() ) - float minYPos = -40.0 * (GetScreenSize()[1] / 1080.0) - float useableSpace = (604.0 * (GetScreenSize()[1] / 1080.0) - Hud_GetHeight( sliderPanel )) + float mods = float ( file.mods.len() ) - float jump = minYPos - (useableSpace / ( mods - float( BUTTONS_PER_PAGE ) ) * file.scrollOffset) + float maxHeight = 604.0 * (GetScreenSize()[1] / 1080.0) + float minHeight = 80.0 * (GetScreenSize()[1] / 1080.0) - //jump = jump * (GetScreenSize()[1] / 1080.0) + float height = maxHeight * ( float( PANELS_LEN ) / mods ) - if ( jump > minYPos ) jump = minYPos + if ( height > maxHeight ) height = maxHeight + if ( height < minHeight ) height = minHeight - Hud_SetPos( sliderButton , 2, jump ) - Hud_SetPos( sliderPanel , 2, jump ) - Hud_SetPos( movementCapture , 2, jump ) + Hud_SetHeight( sliderButton , height ) + Hud_SetHeight( sliderPanel , height ) + Hud_SetHeight( movementCapture , height ) } -void function OnDownArrowSelected( var button ) +void function OnScrollDown( var button ) { - if ( file.modsArrayFiltered.len() <= BUTTONS_PER_PAGE ) return - file.scrollOffset += 1 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.modsArrayFiltered.len()) { - file.scrollOffset = file.modsArrayFiltered.len() - BUTTONS_PER_PAGE + if ( file.mods.len() <= PANELS_LEN ) return + file.scrollOffset += 5 + if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + file.scrollOffset = file.mods.len() - PANELS_LEN } UpdateList() UpdateListSliderPosition() } - -void function OnUpArrowSelected( var button ) +void function OnScrollUp( var button ) { - file.scrollOffset -= 1 + file.scrollOffset -= 5 if (file.scrollOffset < 0) { file.scrollOffset = 0 } @@ -460,23 +633,49 @@ void function OnUpArrowSelected( var button ) UpdateListSliderPosition() } -void function OnScrollDown( var button ) +void function OnDownArrowSelected( var button ) { - if ( file.modsArrayFiltered.len() <= BUTTONS_PER_PAGE ) return - file.scrollOffset += 5 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.modsArrayFiltered.len()) { - file.scrollOffset = file.modsArrayFiltered.len() - BUTTONS_PER_PAGE + if ( file.mods.len() <= PANELS_LEN ) return + file.scrollOffset += 1 + if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + file.scrollOffset = file.mods.len() - PANELS_LEN } UpdateList() UpdateListSliderPosition() } -void function OnScrollUp( var button ) +void function OnUpArrowSelected( var button ) { - file.scrollOffset -= 5 + file.scrollOffset -= 1 if (file.scrollOffset < 0) { file.scrollOffset = 0 } UpdateList() UpdateListSliderPosition() +} + +// + +// Static arrays don't have the .find method for some reason +bool function StaticFind( string mod ) +{ + foreach( string smod in CORE_MODS ) + if ( mod == smod ) + return true + return false +} + +void function ReloadMods() +{ + NSReloadMods() + ClientCommand( "reload_localization" ) + ClientCommand( "loadPlaylists" ) + + bool svCheatsOriginal = GetConVarBool( "sv_cheats" ) + SetConVarBool( "sv_cheats", true ) + ClientCommand( "weapon_reparse" ) // weapon_reparse only works if a server is running and sv_cheats is 1, gotta figure this out eventually + SetConVarBool( "sv_cheats", svCheatsOriginal ) + + // note: the logic for this seems really odd, unsure why it doesn't seem to update, since the same code seems to get run irregardless of whether we've read weapon data before + ClientCommand( "uiscript_reset" ) } \ No newline at end of file -- cgit v1.2.3 From 6c2b576ce8379163d812f364079f761734815917 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Mon, 26 Sep 2022 13:31:57 +0200 Subject: Add some missing translations (#508) * feat: add missing spanish entries * feat: add missing french entry * feat: add missing chinese entry * feat: add missing italian entries * feat: add missing german entries --- .../northstar_client_localisation_french.txt | 2 + .../northstar_client_localisation_german.txt | 30 ++++++++++++++ .../northstar_client_localisation_italian.txt | 48 ++++++++++++++++++++++ .../northstar_client_localisation_mspanish.txt | 2 + .../northstar_client_localisation_spanish.txt | 2 + .../northstar_client_localisation_tchinese.txt | 2 + 6 files changed, 86 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 0d4786a0..276698a0 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -82,6 +82,8 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "cp_amped_capture_points" "Points de capture améliorés" "coliseum_loadouts_enabled" "Equipements du Colisée" + "aitdm_archer_grunts" "Soldats (Archer)" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Bac à sable" "PL_sbox_lobby" "Lobby: Bac à sable" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 0eded5bc..9077fac0 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -8,6 +8,9 @@ "MENU_LAUNCH_NORTHSTAR" "Northstar starten" "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Mods neu laden" + "WARNING" "Warnung" + "CORE_MOD_DISABLE_WARNING" "Das Deaktivieren von essentiellen Mods kann die Funktion deines Clients beeinträchtigen!" + "DISABLE" "Deaktiviere" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Danke, dass du Northstar installiert hast!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Damit Northstar funktionieren kann, muss es mithilfe des Northstar Masterservers authentifizieren. Dies setzt ein Weitergeben deines Origin Tokens an den Masterserver voraus, er wird nicht gespeichert oder für andere Zwecke verwendet. @@ -16,6 +19,9 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "AUTHENTICATION_AGREEMENT" "Authentifizierungs-Einwilligung" "AUTHENTICATION_AGREEMENT_RESTART" "Ein Neustart ist notwendig, um diese Änderung zu übernehmen" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Authentifizierung mit Master Server" + "AUTHENTICATIONAGREEMENT_NO" "Du hast dich gegen die Authentifizierung mit Northstar entschieden. Du kannst die Authentifizierungs-Einwilligung im Modmenü ansehen." + "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Keine Server gefunden" "NS_SERVERBROWSER_UNKNOWNMODE" "Unbekannter Modus" @@ -75,6 +81,8 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "cp_amped_capture_points" "Verstärkte Hardpoints" "coliseum_loadouts_enabled" "Coliseum Loadouts" + "aitdm_archer_grunts" "Archer Frontsoldaten" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" @@ -88,6 +96,8 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "PL_gg_hint" "Erhalte einen Kill mit jeder Waffe um zu siegen." "PL_gg_abbr" "GG" "GAMEMODE_GG" "Gun Game" + "gg_kill_reward" "Killprozentbelohnung" + "gg_execution_reward" "Exekutierungsprozentbelohnung" "PL_tt" "Titan Tag" "PL_tt_lobby" "Titan Tag Lobby" @@ -113,6 +123,17 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "HIDDEN_KILL_SURVIVORS" "Töte alle Überlebenden" "HIDDEN_FIRST_HIDDEN" "%s1 ist the The Hidden." + "PL_sns" "Stock und Stein" + "PL_sns_lobby" "Stock und Stein Lobby" + "PL_sns_desc" "Frei für Alle. Erziele Kills mit Impulsklingen und Exekutierungen um die Punktzahl des Gegners zurückzusetzen" + "PL_sns_abbr" "SuS" + "GAMEMODE_SNS" "Stock und Stein" + "sns_wme_kill_value" "Wingman Elite Killwert" + "sns_softball_kill_value" "Softball Killwert" + "sns_reset_kill_value" "Pulseklinge/Exekutierung Killwert" + "sns_melee_kill_value" "Nahkampfkill Killwert" + "sns_softball_enabled" "Softball aktiviert" + "PL_inf" "Infektion" "PL_inf_lobby" "Infektion-Lobby" "PL_inf_desc" "Überlebe die Infektion. Überlebende werden nach dem Tod infiziert." @@ -266,6 +287,15 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "INGAME_PLAYERS" "Spieler: ^6BA6C400%s1" "TOTAL_SERVERS" "Server: ^C46C6C00%s1" + // Mods menu + "SHOW" "Anzeigen" + "SHOW_ALL" "Alle anzeigen" + "SHOW_ONLY_ENABLED" "Nur aktivierte" + "SHOW_ONLY_DISABLED" "Nur deaktivierte" + + // Maps menu + "HIDE_LOCKED" "Verstecke gesperrte" + // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index b8253ad9..b0bc348f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -6,6 +6,9 @@ "MENU_LAUNCH_NORTHSTAR" "Avvia Northstar" "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Ricarica Mods" + "WARNING", "Attenzione" + "CORE_MOD_DISABLE_WARNING", "Disattivare Mods Principali può rompere il tuo Client!" + "DISABLE", "Disattiva" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Grazie per aver installato Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Affinché Northstar funzioni, è necessario autenticarsi utilizzando il server principale di Northstar. Ciò richiederà l'invio del tuo token di Origin al server principale, non verrà archiviato o utilizzato per altri scopi. @@ -14,8 +17,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT_RESTART" "Dovrai riavviare Titanfall 2 affinché questa scelta abbia effetto." + "DIALOG_AUTHENTICATING_MASTERSERVER", "Autenticazione Sul Master Server in corso" + "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu Mods" + "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Nessun server trovato" + "NS_SERVERBROWSER_UNKNOWNMODE", "Modalità Sconosciuta" "NS_SERVERBROWSER_WAITINGFORSERVERS" "In attesa dei server..." "NS_SERVERBROWSER_CONNECTIONFAILED" "Connessione fallita!" "REFRESH_SERVERS" "Aggiorna" @@ -46,6 +53,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "roundscorelimit" "Limite Punteggio (per round)" "timelimit" "Limite di Tempo" "roundtimelimit" "Limite di Tempo (per round)" + "respawnprotection", "Tempo Protezione di Respawn" "pilot_health_multiplier" "Moltiplicatore di Salute" "respawn_delay" "Tempo di Respawn" @@ -72,6 +80,8 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "cp_amped_capture_points" "Hardpoints Amplificati" "coliseum_loadouts_enabled" "Equipaggiamento Colosseo" + "aitdm_archer_grunts", "Schagniozzi Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" @@ -85,6 +95,10 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_gg_hint" "Ottieni una nuova arma ogni uccisione." "PL_gg_abbr" "GG" "GAMEMODE_GG" "Gioco d'Armi" + "aitdm_archer_grunts", "Schagniozzi Archer" + "gg_kill_reward", "Punteggio Riconpensa Uccisione" + "gg_assist_reward", "Punteggio Ricompensa Assist" + "gg_execution_reward", "Punteggio Ricompensa Esecuzione" "PL_tt" "Titan Tag" "PL_tt_lobby" "Lobby: Titan Tag" @@ -110,6 +124,24 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDDEN_KILL_SURVIVORS" "Uccidi tutti i giocatori." "HIDDEN_FIRST_HIDDEN" "%s1 è il Cacciatore." + "PL_sns", "Sticks and Stones" + "PL_sns_lobby", "Sticks and Stones Lobby" + "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e Esecuzioni per Resettare il Puntegio Nemico" + "PL_sns_abbr", "SNS" + "GAMEMODE_SNS", "Sticks and Stones" + "SCOREBOARD_BANKRUPTS", "Uccisioni Bancarotta" + "SNS_LEADER_BANKRUPT", "Leader Punteggio andato in Bancarotta!" + "SNS_LEADER_BANKRUPT_SUB", "%s1 è stato Resettato da %s2" + "SNS_BANKRUPT", "Bancarotta!" + "SNS_BANKRUPT_SUB", "Il Tuo Punteggio è stato Resettato da %s1" + "sns_wme_kill_value", "Valore Uccisione Wingman d'Elite" + "sns_softball_kill_value", "Valore Uccisione Softball" + "sns_offhand_kill_value", "Valore Uccisione Improvvisa" + "sns_reset_kill_value", "Valore Uccisione Pulse/Esecuzione" + "sns_melee_kill_value", "Valore Uccisione Corpo a Corpo" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill", "Reset Cooldown Uccisione" + "sns_softball_enabled", "Softball Attivato" + "PL_inf" "Infetto" "PL_inf_lobby" "Lobby: Infetto" "PL_inf_desc" "Sopravvivi all'infezione. I sopravvissuti vengono infettati quando uccisi." @@ -124,6 +156,13 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INFECTION_YOU_ARE_LAST_SURVIVOR" "Sei l'Ultimo Sopravvissuto!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sopravvivi." + "PL_tffa", "Titan Free for All" + "PL_tffa_lobby", "Titan Free for All Lobby" + "PL_tffa_desc", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." + "PL_tffa_hint", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." + "PL_tffa_abbr", "TFFA" + "GAMEMODE_TFFA", "Titan Free for All" + "PL_hs" "Nascondino" "PL_hs_lobby" "Lobby: Nascondino" "PL_hs_desc" "Nasconditi oppure trova gli avversari." @@ -257,6 +296,15 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INGAME_PLAYERS" "Players: ^6BA6C400%s1" "TOTAL_SERVERS" "Server: ^C46C6C00%s1" + // Mods menu + "SHOW", "Mostra" + "SHOW_ALL", "Mostra Tutti" + "SHOW_ONLY_ENABLED", "Mostra solo Attivi" + "SHOW_ONLY_DISABLED", "Mostra solo Inattivi" + + // Maps menu + "HIDE_LOCKED" "Nascondi bloccati" + // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index ea62415e..208747f9 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -82,6 +82,8 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "cp_amped_capture_points" "Fortalezas amplificadas" "coliseum_loadouts_enabled" "Equipamientos de coliseo" + "aitdm_archer_grunts" "Soldado Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Lobby sandbox" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 8d2df53b..fa732b63 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -82,6 +82,8 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "cp_amped_capture_points" "Fortines cargados" "coliseum_loadouts_enabled" "Arsenales de coliseo" + "aitdm_archer_grunts" "Soldado Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Vestíbulo de Sandbox" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 5e6721a9..276a192d 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -82,6 +82,8 @@ "cp_amped_capture_points" "強化據點" "coliseum_loadouts_enabled" "競技場裝備" + "aitdm_archer_grunts" "射手飛彈步兵" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "沙盒" "PL_sbox_lobby" "沙盒大廳" -- cgit v1.2.3 From 189a7cd05caa65cfde716e2c8e39da0635735cb2 Mon Sep 17 00:00:00 2001 From: CYakigasi <65476384+castella-cake@users.noreply.github.com> Date: Tue, 27 Sep 2022 08:39:57 +0900 Subject: Update Japanese Translation (#499) Translated the untranslated text (game modes, UI, error messages, etc.) --- .../northstar_client_localisation_japanese.txt | 105 +++++++++++++++++++-- 1 file changed, 96 insertions(+), 9 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index 08772933..b35c9fb8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -3,9 +3,15 @@ "Language" "japanese" "Tokens" { + // ファイルはUTF-16 LEでエンコードしてください、メモ帳なら"名前を付けて保存"から + "MENU_LAUNCH_NORTHSTAR" "Northstarを起動" "MENU_TITLE_MODS" "Modの管理" "RELOAD_MODS" "Modをリロード" + "WARNING" "警告" + "CORE_MOD_DISABLE_WARNING" "コアModを無効化すると、クライアントが破損する可能性があります!" + // 多分ボタンに使われると思うので「無効化」としたが、今後変更する必要があるかもしれない + "DISABLE" "無効化" "MENU_MAIN_AUTHENTICATING" "認証中..." "MENU_MAIN_CONNECTING" "ローカルサーバーへの接続" @@ -17,8 +23,12 @@ "AUTHENTICATION_AGREEMENT" "認証への同意" "AUTHENTICATION_AGREEMENT_RESTART" "変更を適用するには、一度Titanfall 2を再起動する必要があります。" + "DIALOG_AUTHENTICATING_MASTERSERVER" "マスターサーバーへ認証中..." + "AUTHENTICATIONAGREEMENT_NO" "Northstarの認証を行わないことを選択しました。Modメニューから再度このダイアログを開くことができます。" + "MENU_TITLE_SERVER_BROWSER" "サーバーブラウザー" "NS_SERVERBROWSER_NOSERVERS" "サーバーが見つかりませんでした。" + "NS_SERVERBROWSER_UNKNOWNMODE" "不明なモード" "NS_SERVERBROWSER_WAITINGFORSERVERS" "サーバーを待っています..." "NS_SERVERBROWSER_CONNECTIONFAILED" "接続に失敗しました!" // 要議論 @@ -60,6 +70,7 @@ // 要議論: "時間制限"のままか、"マッチ時間"、"タイム上限"、それ以外への差し替え "timelimit" "時間制限" "roundtimelimit" "時間制限 (ラウンドベース)" + "respawnprotection" "リスポーン保護時間" "pilot_health_multiplier" "ヘルス倍率" // 要議論: "リスポーン遅延" のままか、"リスポーンまでの時間"、それ以外への差し替え @@ -89,29 +100,76 @@ "cp_amped_capture_points" "拠点増幅" "coliseum_loadouts_enabled" "コロシアムロードアウト" + // そのまま「グラント」よりも、Respawn翻訳で使われている + //「ミニオン」のほうが伝わりやすいかもしれないのでこっちにする + // 「アーチャーを持ったミニオン」とかだと流石によくなさそうなのでとりあえずそのまま日本語に。 + "aitdm_archer_grunts" "アーチャー持ちミニオン" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "サンドボックス" - "PL_sbox_lobby" "サンドボックスロビー" + "PL_sbox_lobby" "サンドボックス ロビー" "PL_sbox_desc" "サンドボックス" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" "PL_gg" "ガン・ゲーム" - "PL_gg_lobby" "ガン・ゲームロビー" + "PL_gg_lobby" "ガン・ゲーム ロビー" "PL_gg_desc" "全ての銃でキルを取って勝利しろ。" "PL_gg_hint" "全ての銃でキルを取って勝利しろ。" "PL_gg_abbr" "GG" "GAMEMODE_GG" "ガン・ゲーム" + "gg_kill_reward" "キルリワード倍率" + "gg_assist_reward" "アシストリワード倍率" + "gg_execution_reward" "処刑リワード倍率" "PL_tt" "タイタン・タグ" - "PL_tt_lobby" "タイタン・タグロビー" + "PL_tt_lobby" "タイタン・タグ ロビー" "PL_tt_desc" "タイタンとしてポイントを稼げ。敵のタイタンを破壊し自分のタイタンを確保しろ。" "PL_tt_hint" "タイタンとしてポイントを稼げ。敵のタイタンを破壊し自分のタイタンを確保しろ。" "PL_tt_abbr" "TT" "GAMEMODE_TT" "タイタン・タグ" + "PL_chamber" "ワン・イン・ザ・チャンバー" + "PL_chamber_lobby" "ワン・イン・ザ・チャンバー ロビー" + "PL_chamber_desc" "ワンショット・ワンキル。敵をキルして、弾倉に新たな弾丸を込めろ。" + "PL_chamber_hint" "ワンショット・ワンキル。敵をキルして、弾倉に新たな弾丸を込めろ。" + "PL_chamber_abbr" "CHAMBER" + "GAMEMODE_CHAMBER" "ワン・イン・ザ・チャンバー" + + "PL_hidden" "ザ・ヒデゥン" + "PL_hidden_lobby" "ザ・ヒデゥン ロビー" + "PL_hidden_desc" "透明化しているプレイヤーが一人潜んでいる。ヒデゥンを撃破せよ。" + "PL_hidden_hint" "透明化しているプレイヤーが一人潜んでいる。ヒデゥンを撃破せよ。" + "PL_hidden_abbr" "HIDDEN" + "GAMEMODE_HIDDEN" "ザ・ヒデゥン" + "HIDDEN_YOU_ARE_HIDDEN" "ヒデゥンになった!" + "HIDDEN_KILL_SURVIVORS" "すべてのサバイバーを撃破せよ。" + "HIDDEN_FIRST_HIDDEN" "%s1 はヒデゥンになった。" + + "PL_sns" "スティック・アンド・ストーン" + "PL_sns_lobby" "スティック・アンド・ストーン ロビー" + "PL_sns_desc" "フリー・フォー・オール。パルスブレードか、処刑を使用して敵のスコアをリセットできる。" + "PL_sns_abbr" "SNS" + "GAMEMODE_SNS" "スティック・アンド・ストーン" + // 要変更: 破産以外の言葉に置き換える + "SCOREBOARD_BANKRUPTS" "破産キル" + "SNS_LEADER_BANKRUPT" "スコアリーダーが破産した!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 は %s2 にスコアをリセットされた" + "SNS_BANKRUPT" "破産!" + "SNS_BANKRUPT_SUB" "あなたのスコアは %s1 によってリセットされた" + // 要議論: value -> "数"?それとも"値"? + "sns_wme_kill_value" "ウィングマン・エリートキル数" + "sns_softball_kill_value" "ソフトボールキル数" + "sns_offhand_kill_value" "オフハンドキル数" + "sns_reset_kill_value" "パルスブレード/処刑キル数" + "sns_melee_kill_value" "格闘キル数" + // 要変更: 「キルリセットまでのクールダウンを有効化するかどうか」なのか、「キルによってクールダウンをリセットするかどうか」なのか。 + // ひとまずそのまま日本語に直したが、わかりにくいので変更するべき。 + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "キルクールダウンリセット" + "sns_softball_enabled" "ソフトボールを有効化" + "PL_inf" "インフェクション" - "PL_inf_lobby" "インフェクションロビー" + "PL_inf_lobby" "インフェクション ロビー" "PL_inf_desc" "生き残りは死亡するとインフェクターになる。" "PL_inf_hint" "生き残りは死亡するとインフェクターになる。" "PL_inf_abbr" "INF" @@ -125,8 +183,15 @@ "INFECTION_YOU_ARE_LAST_SURVIVOR" "お前が最後の生き残りだ!" "INFECTION_SURVIVE_LAST_SURVIVOR" "生きろ" + "PL_tffa" "タイタン フリー・フォー・オール" + "PL_tffa_lobby" "タイタン フリー・フォー・オール ロビー" + "PL_tffa_desc" "すべてのパイロットはタイタンに搭乗している。すべての敵タイタンを撃破せよ。" + "PL_tffa_hint" "すべてのパイロットはタイタンに搭乗している。すべての敵タイタンを撃破せよ。" + "PL_tffa_abbr" "TFFA" + "GAMEMODE_TFFA" "タイタン フリー・フォー・オール" + "PL_hs" "ハイド・アンド・シーク" - "PL_hs_lobby" "ハイド・アンド・シークロビー" + "PL_hs_lobby" "ハイド・アンド・シーク ロビー" "PL_hs_desc" "ハイダーは隠れ、シーカーはハイダーを探せ!" "PL_hs_hint" "ハイダーは隠れ、シーカーはハイダーを探せ!" "PL_hs_abbr" "HS" @@ -145,13 +210,13 @@ "GAMEMODE_fw" "フロンティア戦争" "PL_fw" "フロンティア戦争" - "PL_fw_lobby" "フロンティア戦争ロビー" + "PL_fw_lobby" "フロンティア戦争 ロビー" "PL_fw_desc" "敵のハーベスターを破壊し、自分のを守れ!" "PL_fw_abbr" "FW" "GAMEMODE_kr" "強化キルレース" "PL_kr" "強化キルレース" - "PL_kr_lobby" "強化キルレースロビー" + "PL_kr_lobby" "強化キルレース ロビー" "PL_kr_desc" "旗を拾い、キルレースを開始しろ。キルでポイントを上げ、キルレースの時間を延ばせ。最高ポイント記録が一番高い者が勝利する" "PL_kr_hint" "旗を拾い、キルレースを開始しろ。キルでポイントを上げ、キルレースの時間を延ばせ。最高ポイント記録が一番高い者が勝利する" "PL_kr_abbr" "KR" @@ -167,7 +232,7 @@ "GAMEMODE_fastball" "ファストボール" "PL_fastball" "ファストボール" - "PL_fastball_lobby" "ファストボールロビー" + "PL_fastball_lobby" "ファストボール ロビー" "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる" "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる" "PL_fastball_abbr" "FB" @@ -182,6 +247,7 @@ "MODE_SETTING_CATEGORY_BLEEDOUT" "パイロットのダウン" "custom_air_accel_pilot" "空中加速度" + "no_pilot_collision" "パイロット同士の当たり判定" "promode_enable" "Proモードの武器" "fp_embark_enabled" "搭乗と処刑の一人称視点" "classic_rodeo" "クラシックロデオ" @@ -257,10 +323,31 @@ "CONNECTING" "接続中..." "INGAME_PLAYERS" "プレイヤー数: ^6BA6C400%s1" "TOTAL_SERVERS" "サーバー数: ^C46C6C00%s1" - // Translation done by Zetryox and CYakigasi + + // Mods menu + "SHOW" "表示" + "SHOW_ALL" "全て" + "SHOW_ONLY_ENABLED" "有効のみ" + "SHOW_ONLY_DISABLED" "無効のみ" + + // Maps menu + "HIDE_LOCKED" "ロック中を隠す" // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + + "NO_GAMESERVER_RESPONSE" "ゲームサーバーに接続できません\n(Couldn't reach game server)" + "BAD_GAMESERVER_RESPONSE" "ゲームサーバーが不明なレスポンスを返しました\n(Game server gave an invalid response)" + "UNAUTHORIZED_GAMESERVER" "ゲームサーバーにそのリクエストを作成する許可がありません\n(Game server is not authorized to make that request)" + "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\nStryder couldn't confirm that this account owns Titanfall 2" + "UNAUTHORIZED_PWD" "パスワードが間違っています\n(Wrong password)" + "STRYDER_RESPONSE" "Stryderからのレスポンスの処理に失敗しました\n(Couldn't parse stryder response)" + "PLAYER_NOT_FOUND" "プレイヤーのアカウントが見つかりません\n(Couldn't find player account)" + "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです\n(Invalid or expired masterserver token)" + "JSON_PARSE_ERROR" "JSONレスポンスの処理に失敗しました\n(Error parsing json response)" + "UNSUPPORTED_VERSION" "現在使用しているバージョンはサポートされていません\n(The version you are using is no longer supported)" + + // Translation done by Zetryox and CYakigasi } } -- cgit v1.2.3 From 1804b784eee053a1031a9f095955de88b0179e1e Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Sat, 8 Oct 2022 10:30:22 +0000 Subject: Modlist Hotfixes (#510) * fix mod list overflow * better offset validation --- .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 49 +++++++++++++--------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 01149bb0..329ea73f 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -166,6 +166,9 @@ void function OnModMenuClosed() void function OnModButtonFocused( var button ) { + if( int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) > file.mods.len() ) + return + file.currentButton = button file.lastMod = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod string modName = file.lastMod.name @@ -209,7 +212,9 @@ void function OnModButtonPressed( var button ) SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) SetControlBarColor( modName ) SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) - RefreshMods() + // RefreshMods() + UpdateListSliderPosition() + UpdateListSliderHeight() } } @@ -391,7 +396,7 @@ void function DisplayModPanels() { foreach ( int i, var panel in file.panels) { - if ( i >= file.mods.len() ) // don't try to show more panels than needed + if ( i >= file.mods.len() || file.scrollOffset + i >= file.mods.len() ) // don't try to show more panels than needed break panelContent c = file.mods[ file.scrollOffset + i ] @@ -534,6 +539,7 @@ void function UpdateMouseDeltaBuffer(int x, int y) mouseDeltaBuffer.deltaX = x mouseDeltaBuffer.deltaY = y + UpdateListSliderHeight() SliderBarUpdate() } @@ -616,45 +622,50 @@ void function OnScrollDown( var button ) { if ( file.mods.len() <= PANELS_LEN ) return file.scrollOffset += 5 - if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + if (file.scrollOffset + PANELS_LEN > file.mods.len()) file.scrollOffset = file.mods.len() - PANELS_LEN - } - UpdateList() - UpdateListSliderPosition() + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModListSlider" ) ) + ValidateScrollOffset() } void function OnScrollUp( var button ) { file.scrollOffset -= 5 - if (file.scrollOffset < 0) { + if (file.scrollOffset < 0) file.scrollOffset = 0 - } - UpdateList() - UpdateListSliderPosition() + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModListSlider" ) ) + ValidateScrollOffset() } void function OnDownArrowSelected( var button ) { if ( file.mods.len() <= PANELS_LEN ) return file.scrollOffset += 1 - if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + if (file.scrollOffset + PANELS_LEN > file.mods.len()) file.scrollOffset = file.mods.len() - PANELS_LEN - } - UpdateList() - UpdateListSliderPosition() + ValidateScrollOffset() } void function OnUpArrowSelected( var button ) { file.scrollOffset -= 1 - if (file.scrollOffset < 0) { + if (file.scrollOffset < 0) file.scrollOffset = 0 - } - UpdateList() - UpdateListSliderPosition() + ValidateScrollOffset() } -// +void function ValidateScrollOffset() +{ + RefreshMods() + if( file.scrollOffset + 15 > file.mods.len() ) + file.scrollOffset = file.mods.len() - 15 + if( file.scrollOffset < 0 ) + file.scrollOffset = 0 + HideAllPanels() + DisplayModPanels() + UpdateListSliderHeight() + UpdateListSliderPosition() +} // Static arrays don't have the .find method for some reason bool function StaticFind( string mod ) -- cgit v1.2.3 From dae4a32f1c4b0f04a50fa462d00ce6ebee92b2ee Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Sat, 22 Oct 2022 03:43:16 +0100 Subject: Halfway decent fix to allow changing of minimap size and zoom midgame (#265) * Add files via upload * Added Getter functions * typo lol * Update cl_minimap.gnut * Mode select updated RegisterPlaylistBannerImage and GetPlaylistBannerImage had initially been in another file but that file is not present in r2northstar/client, not much point adding the entirety of menu_playlist here since for a few lines, this also wont modify mixtape but i don't think mixtape menu is used anywhere in northstar * Added rui since basic image cant handle callsigns added ``` NextModeImageCallsign //For calling card icons { ControlName RuiPanel // xpos -12 ypos -12 wide 480 tall 240 visible 1 scaleImage 1 zpos 2 pin_to_sibling NextModeImageFrame pin_corner_to_sibling BOTTOM pin_to_sibling_corner BOTTOM rui "ui/callsign_icon_button.rpak" //For callsign mode images } ``` * Revert "Added rui since basic image cant handle callsigns" This reverts commit b2623ec41ca944fc0ac3386ae0346464da07a8b3. * Revert "Mode select updated" This reverts commit 2c6f430775c84ef252402b6b447b01fd394459a9. --- .../mod/scripts/vscripts/client/cl_minimap.gnut | 942 +++++++++++++++++++++ 1 file changed, 942 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut new file mode 100644 index 00000000..4237a0be --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut @@ -0,0 +1,942 @@ +global function ClMinimap_Init + +global function ClientCodeCallback_MinimapEntitySpawned + +global function Minimap_AddLayer +global function Minimap_AddCustomLayer + +global function RegisterMinimapPackage + +global function Minimap_SetZoomScale +global function Minimap_SetSizeScale +global function Minimap_GetZoomScale +global function Minimap_GetSizeScale +global function Minimap_IsUsingLargeMinimap + +global function Minimap_Ping +global function ServerCallback_PingMinimap + +global function Minimap_EnableDraw +global function Minimap_DisableDraw + +#if DEV +global function DumpMinimapHandles +#endif + +struct { + var minimap_base + var minimap_wedges + + int activeMinimapObjectCount + + var minimap_you + var minimap_jammed_layer + + var minimap_indicator + + #if DEV + table< int, entity > minimapHandles + #endif + + array minimapOtherRuis + + float threatMaxDist + + float minimapZoomScale = 1 + float minimapSizeScale = 1 + + bool minimapEnabled = true +} file + + +struct MinmapPackage +{ + asset minimapAsset = $"" + void functionref( entity, var ) initFunction +} + +table< string, array > minimapAssetMap = {} + +const int OF_IS_VISIBLE = 1 << 0 +const int OF_TEAM_SAME = 1 << 1 +const int OF_TEAM_ENEMY = 1 << 2 +const int OF_IN_OUR_PARTY = 1 << 3 +const int OF_IS_OWNED_BY_US = 1 << 4 +const int OF_IS_PLAYER = 1 << 5 +const int OF_IS_NPC = 1 << 6 +const int OF_IS_TITAN = 1 << 7 +const int OF_ORIENT_UP = 1 << 8 +const int OF_NO_TEAM_COLOR = 1 << 9 + + +void function RegisterMinimapPackage( string entityClassname, int customStateIndex, asset minimapAsset, void functionref( entity, var ) initFunction ) +{ + Assert ( (entityClassname in minimapAssetMap), "minimap is not currently setup to handle this type of entity: " + entityClassname ) + + MinmapPackage minimapPackage + minimapPackage.minimapAsset = minimapAsset + minimapPackage.initFunction = initFunction + + switch ( entityClassname ) + { + case "npc_soldier": + case "npc_spectre": + case "npc_stalker": + case "npc_drone": + case "npc_frag_drone": + case "npc_super_spectre": + case "npc_turret_sentry": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_npc.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_npc.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + case "npc_titan": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_npc_titan.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_npc_titan.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + case "prop_script": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_prop_script.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_prop_script.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + case "info_hardpoint": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_info_hardpoint.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_info_hardpoint.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + default: + Assert( false, "minimap is not currently setup to handle this type of entity: " + entityClassname ) + } +} + +void function RegisterDefaultMinimapPackage( string entityClassname, asset minimapAsset, void functionref( entity, var ) initFunction ) +{ + Assert ( !(entityClassname in minimapAssetMap) ) + + MinmapPackage minimapPackage + minimapPackage.minimapAsset = minimapAsset + minimapPackage.initFunction = initFunction + + minimapAssetMap[entityClassname] <- [minimapPackage] +} + +void function ClMinimap_Init() +{ + RegisterDefaultMinimapPackage( "player", $"ui/minimap_player.rpak", MinimapPackage_PlayerInit ) + RegisterDefaultMinimapPackage( "npc_titan", $"ui/minimap_object.rpak", MinimapPackage_NPCTitanInit ) + RegisterDefaultMinimapPackage( "npc_soldier", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_spectre", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_stalker", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_super_spectre", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_drone_rocket", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_frag_drone", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_drone", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_dropship", $"ui/minimap_object.rpak", MinimapPackage_NPCDropShipInit ) + RegisterDefaultMinimapPackage( "npc_turret_sentry", $"ui/minimap_object.rpak", MinimapPackage_NPCSentryTurretInit ) + RegisterDefaultMinimapPackage( "prop_script", $"", MinimapPackage_DummyInit ) + RegisterDefaultMinimapPackage( "item_titan_battery", $"ui/minimap_fw_battery.rpak", MinimapPackage_BatteryInit ) + RegisterDefaultMinimapPackage( "item_flag", $"ui/minimap_object.rpak", MinimapPackage_FlagInit ) + RegisterDefaultMinimapPackage( "item_bomb", $"ui/minimap_object.rpak", MinimapPackage_LTSBomb ) + RegisterDefaultMinimapPackage( "info_hardpoint", $"", MinimapPackage_DummyInit ) + RegisterDefaultMinimapPackage( "item_powerup", $"ui/minimap_object.rpak", MinimapPackage_PowerUp ) + + RegisterMinimapPackage( "npc_titan", eMinimapObject_npc_titan.AT_BOUNTY_BOSS, $"ui/minimap_object.rpak", MinimapPackage_BossTitanInit ) + + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_A, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_B, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_C, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_BANK, $"ui/minimap_object.rpak", MinimapPackage_ATBank ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE_TURRET, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE_SHIELDED, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_HARVESTER, $"ui/minimap_obj_area.rpak", MinimapPackage_FDHarvester ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_LOADOUT_CHEST, $"ui/minimap_obj_area.rpak", MinimapPackage_FDLoadoutChest ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_BATTERY_EXCHANGE, $"ui/minimap_obj_area.rpak", MinimapPackage_FDBatteryExchange ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.BOOST_STORE, $"ui/minimap_obj_area.rpak", MinimapPackage_BoostStore ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_MORTAR_POSITION, $"ui/minimap_mortar_spectre.rpak", MinimapPackage_MortarPosition ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.ARC_TRAP, $"ui/minimap_obj_area.rpak", MinimapPackage_ArcTrap ) + + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_A, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampA ) + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_B, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampB ) + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_C, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampC ) + + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_A, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointA ) + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_B, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointB ) + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_C, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointC ) + + //if ( IsPlayingDemo() ) + { + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_IMC, $"ui/minimap_obj_area.rpak", MinimapPackage_SpawnZoneAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_MIL, $"ui/minimap_obj_area.rpak", MinimapPackage_SpawnZoneAreaInit ) + } + //else + //{ + // RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_IMC, $"", MinimapPackage_SpawnZoneAreaInit ) + // RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_MIL, $"", MinimapPackage_SpawnZoneAreaInit ) + //} + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.LTS_SITE_A, $"ui/minimap_object.rpak", MinimapPackage_LTSBombSiteA ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.LTS_SITE_B, $"ui/minimap_object.rpak", MinimapPackage_LTSBombSiteB ) + /* + { + MinmapPackage atAreaPacakage + atAreaPacakage.minimapAsset = $"ui/minimap_obj_area.rpak" + atAreaPacakage.initFunction = MinimapPackage_ATAreaInit + MinmapPackage spawnZonePacakage + spawnZonePacakage.minimapAsset = $"ui/minimap_obj_area.rpak" + spawnZonePacakage.initFunction = MinimapPackage_SpawnZoneAreaInit + MinmapPackage fwBuildSitePackage + fwBuildSitePackage.minimapAsset = $"ui/minimap_fw_build_site.rpak" + fwBuildSitePackage.initFunction = MinimapPackage_FWBuildSite + MinmapPackage fwCampAPackage + fwCampAPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampAPackage.initFunction = MinimapPackage_FWCampA + MinmapPackage fwCampBPackage + fwCampBPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampBPackage.initFunction = MinimapPackage_FWCampB + MinmapPackage fwCampCPackage + fwCampCPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampCPackage.initFunction = MinimapPackage_FWCampC + minimapAssetMap["prop_script"] <-[blankPackage, atAreaPacakage, atAreaPacakage, atAreaPacakage, spawnZonePacakage, spawnZonePacakage, + fwCampAPackage, fwCampBPackage, fwCampCPackage, + fwBuildSitePackage, fwBuildSitePackage, fwBuildSitePackage ] + } +*/ + + AddCreateCallback( "player", OnPlayerCreate ) + + float threatMaxDist = Minimap_GetFloatForKey( "threatMaxDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + if ( GameRules_GetGameMode() == FORT_WAR ) + file.threatMaxDist = max( threatMaxDist, 2200 ) + else + file.threatMaxDist = max( threatMaxDist, 1800 ) + + file.minimap_base = CreateCockpitRui( $"ui/minimap_base.rpak", MINIMAP_Z_BASE ) + + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + + file.minimap_wedges = CreateCockpitRui( $"ui/minimap_wedges.rpak", MINIMAP_Z_THREAT_WEDGES ) + + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + + file.minimap_you = CreateCockpitRui( $"ui/minimap_you.rpak", MINIMAP_Z_YOU ) + + RuiSetFloat( file.minimap_you, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_you, "minimapSizeScale", file.minimapSizeScale ) + + file.minimap_jammed_layer = null + + file.minimap_indicator = CreateCockpitRui( $"ui/minimap_indicator.rpak", -1 ) + + RuiSetFloat( file.minimap_indicator, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_indicator, "minimapSizeScale", file.minimapSizeScale ) + + StatusEffect_RegisterEnabledCallback( eStatusEffect.minimap_jammed, MinimapJammed_Enabled ) + StatusEffect_RegisterDisabledCallback( eStatusEffect.minimap_jammed, MinimapJammed_Disabled ) + RegisterSignal( "LoopRadarJammerSounds" ) +} + +#if DEV +void function DumpMinimapHandles() +{ + int index = 0 + foreach ( handle, ent in file.minimapHandles ) + { + printt( index, handle, ent ) + ++index + } +} +#endif + + +void function Minimap_DisableDraw() +{ + file.minimapEnabled = false + + RuiSetDrawGroup( file.minimap_base, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_wedges, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_you, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_indicator, RUI_DRAW_NONE ) + + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetDrawGroup( rui, RUI_DRAW_NONE ) + } +} + +void function Minimap_EnableDraw() +{ + file.minimapEnabled = true + + RuiSetDrawGroup( file.minimap_base, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_wedges, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_you, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_indicator, RUI_DRAW_COCKPIT ) + + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetDrawGroup( rui, RUI_DRAW_COCKPIT ) + } +} + + +void function ClientCodeCallback_MinimapEntitySpawned( entity ent ) +{ + foreach ( callbackFunc in clGlobal.onMinimapEntSpawnedCallbacks ) + { + callbackFunc( ent ) + } + + if ( ent == GetLocalViewPlayer() ) + return + + thread AddMinimapObject( ent ) +} + + +asset function GetMinimapAsset( string className, int customState ) +{ + if ( !(className in minimapAssetMap) ) + return $"" + + if ( customState > minimapAssetMap[className].len() - 1 ) + return $"" + + return minimapAssetMap[className][customState].minimapAsset +} + + +void function AddMinimapObject( entity ent ) //TODO: If we want radar jammer boost to hide friendly players we need to be able to get the rui handles back. +{ + Assert( IsValid( ent ) ) + + string className = expect string( ent.GetSignifierName() ) + int customState = ent.Minimap_GetCustomState() + + asset minimapAsset = GetMinimapAsset( className, customState ) + if ( minimapAsset == $"" ) + { + return + } + + int zOrder = ent.Minimap_GetZOrder() + entity viewPlayer = GetLocalViewPlayer() + + ent.SetDoDestroyCallback( true ) + + #if DEV + int eHandle = ent.Dev_GetEncodedEHandle() + + { + array< int > eHandlesToRemove + foreach ( eHandleIter, entIter in file.minimapHandles ) + { + if ( !IsValid( entIter ) ) + { + eHandlesToRemove.append( eHandleIter ) + } + } + + foreach ( eHandleIter in eHandlesToRemove ) + { + delete file.minimapHandles[eHandleIter] + } + } + + if ( eHandle in file.minimapHandles ) + { + // Should have been removed in above loop + Assert( IsValid( file.minimapHandles[eHandle] ) ) + + DumpMinimapHandles() + Assert( false, "Duplicate minimap entity added - " + ent ) + } + + file.minimapHandles[eHandle] <- ent + #endif + + var rui = CreateCockpitRui( minimapAsset, MINIMAP_Z_BASE + zOrder ) + + //RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + + RuiTrackFloat3( rui, "playerPos", viewPlayer, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", viewPlayer, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiTrackFloat3( rui, "objectPos", ent, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "objectAngles", ent, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackInt( rui, "objectFlags", ent, RUI_TRACK_MINIMAP_FLAGS ) + RuiTrackInt( rui, "customState", ent, RUI_TRACK_MINIMAP_CUSTOM_STATE ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + minimapAssetMap[className][customState].initFunction( ent, rui ) + + file.minimapOtherRuis.append( rui ) + + RuiSetDrawGroup( rui, file.minimapEnabled ? RUI_DRAW_COCKPIT : RUI_DRAW_NONE ) + OnThreadEnd( + function() : ( rui ) + { + file.minimapOtherRuis.removebyvalue( rui ) + RuiDestroy( rui ) + } + ) + + ent.EndSignal( "OnDestroy" ) + + if ( ent.IsPlayer() ) + { + while ( IsValid( ent ) ) + { + WaitSignal( ent, "SettingsChanged", "OnDeath" ) + } + } + else + { + ent.WaitSignal( "OnDestroy" ) + } +} + + +void function Minimap_PingCount( vector origin, float radius, float duration, vector color, int count, bool reverse = false ) +{ + float delay = duration / count + + while ( count ) + { + count-- + + Minimap_Ping( origin, radius, delay + (delay * 0.25), color, reverse ) + wait delay + } +} + + +void function Minimap_Ping( vector origin, float radius, float duration, vector color, bool reverse = false ) +{ + entity viewPlayer = GetLocalViewPlayer() + int zOrder = viewPlayer.Minimap_GetZOrder() + + if ( !file.minimapEnabled ) + return + + var rui = CreateCockpitRui( $"ui/minimap_ping.rpak", MINIMAP_Z_BASE + zOrder ) + + RuiTrackFloat3( rui, "playerPos", viewPlayer, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", viewPlayer, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiSetFloat3( rui, "objColor", color ) + RuiSetFloat3( rui, "objectPos", origin ) + RuiSetFloat3( rui, "objectAngles", <0,0,0> ) + + RuiSetFloat( rui, "objectRadius", radius / ( file.threatMaxDist * file.minimapZoomScale ) ) + + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetGameTime( rui, "endTime", Time() + duration ) + + RuiSetBool( rui, "reverse", reverse ) +} + + + +var function Minimap_AddLayer( asset layerImage, bool isFriendly ) +{ + entity player = GetLocalViewPlayer() + + var rui = CreateCockpitRui( $"ui/minimap_layer.rpak", MINIMAP_Z_LAYER ) + + RuiTrackFloat3( rui, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetImage( rui, "layerImage", layerImage ) + RuiSetFloat3( rui, "mapCorner", ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "mapScale", mapScale ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetBool( rui, "isFriendly", isFriendly ) + + return rui +} + +var function Minimap_AddCustomLayer( asset ruiAsset, int sortKey = MINIMAP_Z_LAYER ) +{ + entity player = GetLocalViewPlayer() + + var rui = CreateCockpitRui( ruiAsset, sortKey ) + + RuiTrackFloat3( rui, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetFloat3( rui, "mapCorner", ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "mapScale", mapScale ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + return rui +} + + +void function OnPlayerCreate( entity player ) +{ + if ( player != GetLocalViewPlayer() ) + return + + RuiTrackFloat3( file.minimap_base, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.minimap_base, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiTrackInt( file.minimap_indicator, "indicatorId", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "indicatorId" ) ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetImage( file.minimap_base, "mapImage", mapImage ) + RuiSetFloat3( file.minimap_base, "mapCorner", ) + RuiSetFloat( file.minimap_base, "displayDist", file.threatMaxDist ) + RuiSetFloat( file.minimap_base, "mapScale", mapScale ) + + RuiTrackFloat3( file.minimap_wedges, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.minimap_wedges, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiSetFloat3( file.minimap_wedges, "distances", ) + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeCenter", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_CENTER ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid0", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_N ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid1", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_NE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid2", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_E ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid3", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_SE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid4", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_S ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid5", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_SW ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid6", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_W ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid7", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_NW ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter0", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_N ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter1", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_NE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter2", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_E ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter3", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_SE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter4", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_S ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter5", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_SW ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter6", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_W ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter7", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_NW ) + + + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + + RuiTrackInt( file.minimap_you, "objectFlags", player, RUI_TRACK_MINIMAP_FLAGS ) + RuiTrackInt( file.minimap_you, "customState", player, RUI_TRACK_MINIMAP_CUSTOM_STATE ) + +} + + +void function MinimapPackage_DummyInit( entity ent, var rui ) +{ + +} + +void function MinimapPackage_PlayerInit( entity ent, var rui ) +{ + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + { + RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) + RuiTrackFloat( rui, "maphackDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.maphack_detected ) + } +} + +void function MinimapPackage_NPCTitanInit( entity ent, var rui ) +{ + entity player = GetLocalClientPlayer() + + RuiSetBool( rui, "useTeamColor", false ) + + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) +} + +void function MinimapPackage_NPCHumanSizedInit( entity ent, var rui ) +{ + entity player = GetLocalClientPlayer() + + RuiSetImage( rui, "defaultIcon", $"rui/hud/minimap/compass_icon_small_dot" ) + RuiSetImage( rui, "clampedDefaultIcon", $"" ) + + //if ( ent == GetLocalClientPlayer().GetPetTitan() ) + //{ + // RuiSetBool( rui, "useTeamColor", false ) + // RuiSetFloat3( rui, "iconColor", TEAM_COLOR_YOU / 255.0 ) + //} + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + //if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + // RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) +} + +void function MinimapPackage_NPCDropShipInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/scoreboard/status_evac" ) +} + +void function MinimapPackage_NPCSentryTurretInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"" ) + RuiSetImage( rui, "clampedDefaultIcon", $"" ) +} + +void function MinimapPackage_BossTitanInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_titan" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_titan" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_BatteryInit( entity ent, var rui ) +{ + entity player = GetLocalViewPlayer() + RuiTrackInt( rui, "batteryCount", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "batteryCount" ) ) + RuiSetBool( rui, "useTeamColor", false ) + RuiTrackFloat( rui, "batteryCarried", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.battery_carried ) +} + +void function MinimapPackage_ATAreaInit( entity ent, var rui ) +{ + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_ATBank( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_SpawnZoneAreaInit( entity ent, var rui ) +{ + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) + if ( !IsPlayingDemo() ) + { + RuiSetImage( rui, "centerImage", $"" ) // hide diamond + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/obj_foreground_diamond" ) + } +} + +void function MinimapPackage_FWBuildSite( entity ent, var rui ) +{ + entity player = GetLocalViewPlayer() + RuiTrackInt( rui, "batteryCount", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "batteryCount" ) ) + //RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_HardpointA( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_HardpointB( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_HardpointC( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_FDHarvester( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/coop_harvester" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/coop_harvester" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_FDLoadoutChest( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/coop_ammo_locker_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/coop_ammo_locker_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_FDBatteryExchange( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_BoostStore( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bonus_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bonus_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_MortarPosition( entity ent, var rui ) +{ + RuiSetImage( rui, "bgImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar_bg" ) + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar" ) + RuiTrackFloat( rui, "arcPercent", ent, RUI_TRACK_SHIELD_FRACTION ) +} + +void function MinimapPackage_ArcTrap( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/minimap/compass_icon_arc_trap" ) + RuiSetImage( rui, "clampedImage", $"" ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampA( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertA" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampB( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertB" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampC( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertC" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_LTSBombSiteA( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_a_attacking" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_a_attacking" ) +} + +void function MinimapPackage_LTSBombSiteB( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_b_attacking" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_b_attacking" ) +} + +void function MinimapPackage_LTSBomb( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_neutral" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_neutral" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_FlagInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/ctf/ctf_flag_neutral" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/ctf/ctf_flag_neutral" ) + RuiSetBool( rui, "useTeamColor", true ) +} + +void function MinimapPackage_PowerUp( entity ent, var rui ) +{ + //Battery spawners are the only power ups in use atm. This would need to be updated if we use them differently. + RuiSetImage( rui, "defaultIcon", $"rui/hud/battery/battery_capture_friendly" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/battery/battery_capture_friendly" ) + RuiSetBool( rui, "useTeamColor", false ) +} + + +void function MinimapJammed_Enabled( entity ent, int statusEffect, bool actuallyChanged ) +{ + if ( !actuallyChanged ) + return + + if ( ent != GetLocalClientPlayer() ) + return + + thread LoopRadarJammerSounds( ent ) + thread FadeOutStaticSoundAfterDelay( ent, BURN_METER_RADAR_JAMMER_PULSE_DURATION - BURN_METER_RADAR_JAMMER_EASE_OFF_TIME ) + + if ( file.minimap_jammed_layer != null ) + RuiDestroy( file.minimap_jammed_layer ) + + file.minimap_jammed_layer = Minimap_AddCustomLayer( $"ui/minimap_jammer_layer.rpak", MINIMAP_Z_YOU + 1 ) + if ( actuallyChanged ) + RuiSetGameTime( file.minimap_jammed_layer, "startTime", Time() ) + + RuiSetFloat( file.minimap_jammed_layer, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_jammed_layer, "minimapSizeScale", file.minimapSizeScale ) + RuiTrackFloat( file.minimap_jammed_layer, "scriptAlphaVar", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, statusEffect ) + + RuiTrackFloat( file.minimap_wedges, "scriptInverseAlphaVar", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, statusEffect ) + +} + +void function MinimapJammed_Disabled( entity ent, int statusEffect, bool actuallyChanged ) +{ + if ( !actuallyChanged ) + return + + if ( ent != GetLocalClientPlayer() ) + return + + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) + + if ( file.minimap_jammed_layer != null ) + { + RuiDestroy( file.minimap_jammed_layer ) + file.minimap_jammed_layer = null + } +} + +void function LoopRadarJammerSounds( entity ent ) +{ + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) + clGlobal.levelEnt.EndSignal( "LoopRadarJammerSounds" ) + ent.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( ent ) + { + StopSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_RedTextBeep_1P" ) + } + ) + + float currentTime = Time() + float fractionalComponent = currentTime - floor( currentTime ) + float timeToWait + if ( fractionalComponent <= 0.5 ) + timeToWait = 0.5 - fractionalComponent + else + timeToWait = 1.5 - fractionalComponent + + wait ( timeToWait ) //Red text flashes in with regards to game time, so we need to wait till the appropriate time (0.5) to play the next sound + + while( true ) + { + if ( IsValid( ent ) ) + EmitSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_RedTextBeep_1P" ) + + wait 1.0 //This is dependent on the rui logic, and will need to be changed if the rui logic changes + } +} + +void function FadeOutStaticSoundAfterDelay( entity ent, float delay ) +{ + EmitSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_Signal_Static_1P" ) + + ent.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( ent ) + { + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) //stop red text beeping sounds + if ( IsValid( ent ) ) + StopSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_Signal_Static_1P" ) + + } + ) + wait delay +} +void function Minimap_SetZoomScale( float scale ) +{ + file.minimapZoomScale = scale + if(file.minimap_you != null) + RuiSetFloat( file.minimap_you, "minimapZoomScale", file.minimapZoomScale ) + if(file.minimap_indicator != null) + RuiSetFloat( file.minimap_indicator, "minimapZoomScale", file.minimapZoomScale ) + if(file.minimap_base != null) + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + + if ( file.minimap_wedges != null ) + { + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + } + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + } +} + +void function Minimap_SetSizeScale( float scale ) +{ + file.minimapSizeScale = scale + if(file.minimap_base != null) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_indicator != null) + RuiSetFloat( file.minimap_indicator, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_you != null) + RuiSetFloat( file.minimap_you, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_wedges != null) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + } + +} +float function Minimap_GetZoomScale() +{ + return file.minimapZoomScale +} +float function Minimap_GetSizeScale() +{ + return file.minimapSizeScale +} +bool function Minimap_IsUsingLargeMinimap() +{ + return file.minimapSizeScale > 1.0 +} + +void function ServerCallback_PingMinimap( float originX, float originY, float originZ, float radius, float duration, float colorR, float colorG, float colorB, int count, bool reverse ) +{ + if ( count > 1 ) + thread Minimap_PingCount( , radius, duration, , count, reverse ) + else + Minimap_Ping( , radius, duration, , reverse ) +} -- cgit v1.2.3 From ef8a419edea010f39c35b913626c35900f052e2b Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:16:58 +0000 Subject: restore hud_takesshots functionality to automatically take screenshots of scoreboard (#522) * restore hud_takesshots functionality to take screenshots of scoreboard automatically * fixup some formatting --- Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut b/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut index 93be01ea..1baeae9f 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut @@ -1105,8 +1105,16 @@ void function DisplayPostMatchTop3() RuiSetBool( rui, "isFriendly" + i, localTeam == players[i].GetTeam() ) } } + + if ( GetConVarBool( "hud_takesshots" ) ) + thread TakeScoreboardScreenshot_Delayed() } +void function TakeScoreboardScreenshot_Delayed() +{ + wait 1.5 + GetLocalClientPlayer().ClientCommand( "jpeg" ) +} float function GetGameStartTime() { -- cgit v1.2.3 From 0a5c705f662773ecb97a9b06d2c92e023307b441 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 6 Nov 2022 02:17:53 +0100 Subject: Bump version number (#526) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7dcfcd21..7ca8dd5e 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 0, "ConVars": [ { diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 28825a58..1a08f0d4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 79663feb..2ed89910 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From f5e4a7be5b6d48006e5f3b9ac218993aa4ee284e Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 10 Nov 2022 00:05:18 +0000 Subject: Improve mouse capture handling in menus (#520) * rework mouse capture handling * small improvement to comment * move to new script file * refactor to use only the capturePanel * refactor part 2 * github please commit everything * remove non-implemented global function * cleanup * rename variable * formatting and a comment * run callbacks for menus * update comment accordingly * small formatting change * slight refactor to avoid duplicate code * improve comment * pass correct parameters * newline at end of file :) --- Northstar.Client/mod.json | 4 ++ .../mod/scripts/vscripts/sh_menu_models.gnut | 36 ------------- .../mod/scripts/vscripts/ui/menu_map_select.nut | 2 +- .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 2 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- .../mod/scripts/vscripts/ui/ui_mouse_capture.nut | 60 ++++++++++++++++++++++ 6 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7ca8dd5e..15853be7 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -115,6 +115,10 @@ { "Path": "ui/controller_prompts.nut", "RunOn": "UI" + }, + { + "Path": "ui/ui_mouse_capture.nut", + "RunOn": "UI" } ], "Localisation": [ diff --git a/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut b/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut index 6d446654..0bcb7864 100644 --- a/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut +++ b/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut @@ -207,19 +207,9 @@ #endif // CLIENT && MP #if UI - struct - { - table MouseMovementCaptureFunctionsTable = {} - } file - - const MOUSE_ROTATE_MULTIPLIER = 25.0 - global function UpdateUIMapSupportsMenuModels global function RunMenuClientFunction global function UI_SetPresentationType - - global function AddMouseMovementCaptureHandler - global function UICodeCallback_MouseMovementCapture #endif // UI global const STORE_BG_DEFAULT = 0 @@ -2897,30 +2887,4 @@ RunClientScript( "UpdateMenuToHarvester" ) } } - - void function AddMouseMovementCaptureHandler( var menu, void functionref( int, int ) func ) - { - file.MouseMovementCaptureFunctionsTable.rawset( menu, func ) - } - - void function UpdateMouseMovementCaptureFunctions( int deltaX, int deltaY ) - { - var activeMenu = GetActiveMenu() - if ( file.MouseMovementCaptureFunctionsTable.rawin( activeMenu ) ) - file.MouseMovementCaptureFunctionsTable.rawget( activeMenu )(deltaX, deltaY) - } - - void function UICodeCallback_MouseMovementCapture( var capturePanel, int deltaX, int deltaY ) - { - float screenScaleXModifier = 1920.0 / GetScreenSize()[0] // 1920 is base screen width - float mouseXRotateDelta = deltaX * screenScaleXModifier * MOUSE_ROTATE_MULTIPLIER - //printt( "deltaX:", deltaX, "deltaY:", deltaY ) - - float screenScaleYModifier = 1080.0 / GetScreenSize()[1] // 1920 is base screen width - float mouseYRotationDelta = deltaY * screenScaleYModifier * MOUSE_ROTATE_MULTIPLIER - - UpdateMouseMovementCaptureFunctions( deltaX, deltaY ) - - RunMenuClientFunction( "UpdateMouseRotateDelta", mouseXRotateDelta, mouseYRotationDelta ) - } #endif // UI diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut index 930e472b..8e8071f5 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut @@ -43,7 +43,7 @@ void function InitMapsMenu() { file.menu = GetMenu( "MapsMenu" ) - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnCloseMapsMenu ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 329ea73f..3f643aa3 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -83,7 +83,7 @@ void function InitModMenu() RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) } - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) // UI Events AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index eb068374..d9b11ccc 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -142,7 +142,7 @@ void function InitServerBrowserMenu() { file.menu = GetMenu( "ServerBrowserMenu" ) - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) // Get menu stuff file.serverButtons = GetElementsByClassname( file.menu, "ServerButton" ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut b/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut new file mode 100644 index 00000000..fa5c9217 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut @@ -0,0 +1,60 @@ +untyped // untyped purely so I can index into a table with var + +global function AddMouseMovementCaptureHandler +global function UICodeCallback_MouseMovementCapture + +struct +{ + // a table of capturePanels and menus, each of which contains an array of callbacks + table< var, array< void functionref( int deltaX, int deltaY ) > > mouseMovementCaptureCallbacks = {} +} file + +// this function registers a callback (or "handler") function for a MouseMovementCapture menu panel +// use this for scrollbars, sliders, etc. +void function AddMouseMovementCaptureHandler( var capturePanelOrMenu, void functionref( int deltaX, int deltaY ) func ) +{ + // if the capturePanel or menu already has an array in the table, we append to the array + // if not, we should create the array, [func] just turns func into an array + if ( capturePanelOrMenu in file.mouseMovementCaptureCallbacks ) + file.mouseMovementCaptureCallbacks[capturePanelOrMenu].append( func ) + else + file.mouseMovementCaptureCallbacks[capturePanelOrMenu] <- [func] +} + +void function RunMouseMovementCallbacks( var capturePanelOrMenu, int deltaX, int deltaY ) +{ + // check that the capturePanelOrMenu is in the table before trying anything stupid + if ( capturePanelOrMenu in file.mouseMovementCaptureCallbacks ) + { + // iterate through the different callback functions + foreach ( void functionref( int deltaX, int deltaY ) callback in file.mouseMovementCaptureCallbacks[capturePanelOrMenu] ) + { + // run the callback function + callback( deltaX, deltaY ) + } + } +} + +void function UICodeCallback_MouseMovementCapture( var capturePanel, int deltaX, int deltaY ) +{ + // run callbacks for the capturePanel + RunMouseMovementCallbacks( capturePanel, deltaX, deltaY ) + + // get the current menu and run callbacks, this preserves backwards compatibility + RunMouseMovementCallbacks( GetActiveMenu(), deltaX, deltaY ) + + // everything below here originally existed in vanilla sh_menu_models.gnut and is meant to be used for like all of their rotation stuff + // its easier to move this here than to add a shared callback for all of the vanilla capture handlers (there are like >20) + + // this const was moved instead of made global because it was literally only used in the code below + const MOUSE_ROTATE_MULTIPLIER = 25.0 + + float screenScaleXModifier = 1920.0 / GetScreenSize()[0] // 1920 is base screen width + float mouseXRotateDelta = deltaX * screenScaleXModifier * MOUSE_ROTATE_MULTIPLIER + //printt( "deltaX:", deltaX, "screenScaleModifier:", screenScaleModifier, "mouseRotateDelta:", mouseRotateDelta ) + + float screenScaleYModifier = 1080.0 / GetScreenSize()[1] // 1080 is base screen height + float mouseYRotationDelta = deltaY * screenScaleYModifier * MOUSE_ROTATE_MULTIPLIER + + RunMenuClientFunction( "UpdateMouseRotateDelta", mouseXRotateDelta, mouseYRotationDelta ) +} -- cgit v1.2.3 From 3b02ecd43c2c1efd6e2d966b9659e4268dc1bbc5 Mon Sep 17 00:00:00 2001 From: Erlite Date: Sat, 12 Nov 2022 15:09:43 +0100 Subject: Add support for hiding the [SERVER] tag in server messages (#506) --- .../vscripts/_custom_codecallbacks_client.gnut | 29 ++++++++++++++++------ .../mod/scripts/vscripts/_chat.gnut | 8 +++--- 2 files changed, 26 insertions(+), 11 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 66a40cb0..3caf4336 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -11,6 +11,7 @@ global struct ClClient_MessageStruct { bool isDead bool isWhisper bool shouldBlock + bool noServerTag } struct { @@ -29,6 +30,7 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { localMessage.isDead = returnStruct.isDead localMessage.isWhisper = returnStruct.isWhisper localMessage.shouldBlock = localMessage.shouldBlock || returnStruct.shouldBlock + localMessage.noServerTag = returnStruct.noServerTag } } @@ -39,7 +41,13 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { NSChatWriteRaw(1, "\n") - if (localMessage.player == null) NSChatWrite(1, "\x1b[95m") + if (localMessage.player == null) + { + if (!localMessage.noServerTag || localMessage.isWhisper) + { + NSChatWrite(1, "\x1b[95m") + } + } else { bool isFriendly = localMessage.player.GetTeam() == GetLocalClientPlayer().GetTeam() @@ -54,15 +62,18 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { if (localMessage.player == null) { - NSChatWriteRaw(1, Localize("#HUD_CHAT_SERVER_PREFIX") + " ") + if (!localMessage.noServerTag) + { + NSChatWriteRaw(1, Localize("#HUD_CHAT_SERVER_PREFIX") + " ") + } } - else { + else + { NSChatWriteRaw(1, localMessage.playerName) NSChatWriteRaw(1, ": ") } - NSChatWrite(1, "\x1b[0m") - + if (localMessage.player != null || !localMessage.noServerTag || localMessage.isWhisper) NSChatWrite(1, "\x1b[0m") NSChatWrite(1, localMessage.message) } @@ -87,16 +98,19 @@ void function CHudChat_OnReceivedSayTextMessageCallback(int fromPlayerIndex, str fromPlayerName = fromPlayer.GetPlayerNameWithClanTag() } + // Null player + isTeam == true: Server with no tag. + if (messageType == 0 || messageType == 1) { ClClient_MessageStruct localMessage localMessage.message = message localMessage.player = fromPlayer localMessage.playerName = fromPlayerName - localMessage.isTeam = isTeam + localMessage.isTeam = fromPlayer != null && isTeam localMessage.isDead = isDead localMessage.isWhisper = false localMessage.shouldBlock = false + localMessage.noServerTag = fromPlayer == null && isTeam OnReceivedMessage(localMessage) return } @@ -107,10 +121,11 @@ void function CHudChat_OnReceivedSayTextMessageCallback(int fromPlayerIndex, str localMessage.message = message localMessage.player = fromPlayer localMessage.playerName = fromPlayerName - localMessage.isTeam = isTeam + localMessage.isTeam = fromPlayer != null && isTeam localMessage.isDead = isDead localMessage.isWhisper = true localMessage.shouldBlock = false + localMessage.noServerTag = fromPlayer == null && isTeam OnReceivedMessage(localMessage) return } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut index 97ed959c..44836bc9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut @@ -25,26 +25,26 @@ void function Chat_PrivateMessage(entity fromPlayer, entity toPlayer, string tex } // Broadcasts a message from the server to all players. -void function Chat_ServerBroadcast(string text) +void function Chat_ServerBroadcast(string text, bool withServerTag = true) { NSBroadcastMessage( -1, -1, text, - false, + !withServerTag, false, eChatMessageType.CHAT ) } // Sends a message from the server to one player. Will be shown as a whisper if whisper is set. -void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper) +void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper, bool withServerTag = true) { NSBroadcastMessage( -1, toPlayer.GetPlayerIndex(), text, - false, + !withServerTag, false, whisper ? eChatMessageType.WHISPER : eChatMessageType.CHAT ) -- cgit v1.2.3 From 7c30c44d2bfea9cf64a374f690a23a6e6eb1165b Mon Sep 17 00:00:00 2001 From: Respawn Date: Sat, 12 Nov 2022 23:08:24 +0100 Subject: Add cl_titan_cockpit.nut from englishclient_mp_common --- .../scripts/vscripts/client/cl_titan_cockpit.nut | 1652 ++++++++++++++++++++ 1 file changed, 1652 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut new file mode 100644 index 00000000..828f3056 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -0,0 +1,1652 @@ +untyped + +global function ClTitanCockpit_Init + +global function ServerCallback_TitanEMP +global function ServerCallback_TitanCockpitBoot +global function TitanCockpit_DamageFeedback +global function TitanCockpit_AddPlayer +global function RegisterTitanBindings +global function GetTitanBindings +global function DeregisterTitanBindings +global function ServerCallback_TitanEmbark +global function ServerCallback_TitanDisembark +global function PlayerPressed_EjectEnable // so can be called directly for debugging +global function PlayerPressed_Eject // so can be called directly for debugging +global function TitanCockpit_IsBooting +global function ServerCallback_TitanCockpitEMP +global function TitanCockpit_EMPFadeScale +global function TitanCockpit_DoEMP +global function TitanEMP_Internal +global function ServerCallback_EjectConfirmed +global function LinkCoreHint + +global function AddTitanCockpitManagedRUI +global function UpdateTitanCockpitVisibility +global function TitanCockpitDestroyRui +global function TitanCockpitDoomedThink +global function PlayerEjects +global function IsDisplayingEjectInterface +global function FlashCockpitLight +global function PlayCockpitSparkFX + +global function FlashCockpitHealth + +global function UpdateEjectHud_SetButtonPressTime +global function UpdateEjectHud_SetButtonPressCount + +global function SetUnlimitedDash +#if MP +global function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus +global function DisplayFrontierRank +#endif +struct TitanCockpitManagedRUI +{ + bool exists = false + var functionref() create + void functionref() destroy + bool functionref() shouldCreate + int drawGroup = RUI_DRAW_COCKPIT +} + +const TITAN_ALARM_SOUND = "titan_alarm" +const TITAN_NUCLEAR_DEATH_ALARM = "titan_nuclear_death_alarm" +const TITAN_EJECT_BOOST = "titan_eject_boost" +const TITAN_EJECT_ASCENT = "player_eject_windrush" +const TITAN_EJECT_APEX = "player_eject_apex_wind" +const TITAN_EJECT_DESCENT = "player_fallingdescent_windrush" + +const EJECT_MIN_VELOCITY = 200.0 +const EJECT_MAX_VELOCITY = 1000.0 + +struct +{ + var coreHintRui + var cockpitRui + var cockpitLowerRui + var cockpitAdditionalRui + array titanCockpitManagedRUIs + + string lastPilotSettings + + bool isFirstBoot = true + var scorchHotstreakRui +} file + +function ClTitanCockpit_Init() +{ + if ( reloadingScripts ) + return + + RegisterSignal( "DisembarkCheck" ) + RegisterSignal( "Rumble_Forward_End" ) + RegisterSignal( "Rumble_Back_End" ) + RegisterSignal( "Rumble_Left_End" ) + RegisterSignal( "Rumble_Right_End" ) + RegisterSignal( "EMP" ) + RegisterSignal( "Ejecting" ) + RegisterSignal( "TitanEMP_Internal" ) + RegisterSignal( "TitanUnDoomed" ) + RegisterSignal( "MonitorPlayerEjectAnimBeingStuck" ) + RegisterSignal( "DisplayFrontierRank" ) + + PrecacheParticleSystem( $"xo_cockpit_spark_01" ) + + if ( !IsModelViewer() && !IsLobby() ) + { + AddCreateCallback( "titan_cockpit", TitanCockpitInit ) + } + + if ( !reloadingScripts ) + { + level.cockpitGeoRef <- null + } + + AddPlayerFunc( TitanCockpit_AddPlayer ) + + AddCinematicEventFlagChangedCallback( CE_FLAG_TITAN_3P_CAM, CinematicEventFlagChanged ) + AddCinematicEventFlagChangedCallback( CE_FLAG_INTRO, CinematicEventFlagChanged ) + + AddCallback_PlayerClassChanged( UpdateLastPlayerSettings ) + + AddTitanCockpitManagedRUI( Scorch_CreateHotstreakBar, Scorch_DestroyHotstreakBar, Scorch_ShouldCreateHotstreakBar, RUI_DRAW_COCKPIT ) //RUI_DRAW_HUD +} + +void function UpdateLastPlayerSettings( entity player ) +{ + if ( IsPilot( player ) ) + file.lastPilotSettings = player.GetPlayerSettings() +} + +TitanBindings function GetTitanBindings() +{ + TitanBindings Table + Table.PlayerPressed_Eject = PlayerPressed_Eject + Table.PlayerPressed_EjectEnable = PlayerPressed_EjectEnable + return Table +} + +bool function RegisterTitanBindings( entity player, TitanBindings bind ) +{ + if ( player != GetLocalViewPlayer() ) + return false + + if ( player != GetLocalClientPlayer() ) + return false + + RegisterConCommandTriggeredCallback( "+useAndReload", bind.PlayerPressed_Eject ) + RegisterConCommandTriggeredCallback( "+use", bind.PlayerPressed_Eject ) + + RegisterConCommandTriggeredCallback( "+scriptCommand1", bind.PlayerPressed_EjectEnable ) + + return true +} + +void function DeregisterTitanBindings( TitanBindings bind ) +{ + DeregisterConCommandTriggeredCallback( "+useAndReload", bind.PlayerPressed_Eject ) + DeregisterConCommandTriggeredCallback( "+use", bind.PlayerPressed_Eject ) + + if ( GetMapName() != "" ) + { + DeregisterConCommandTriggeredCallback( "+scriptCommand1", bind.PlayerPressed_EjectEnable ) + } +} + + +void function TitanCockpit_AddPlayer( entity player ) +{ + if ( IsModelViewer() ) + return + + player.s.lastCockpitDamageSoundTime <- 0 + player.s.inTitanCockpit <- false + player.s.lastDialogTime <- 0 + player.s.titanCockpitDialogActive <- false + player.s.titanCockpitDialogAliasList <- [] + + player.s.hitVectors <- [] +} + +void function TitanCockpitInit( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + Assert( player.GetCockpit() == cockpit ) + + cockpit.s.ejectStartTime <- 0 // placed here to fix http://bugzilla.respawn.net/show_bug.cgi?id=156786 + + if ( !IsAlive( player ) ) + return + + if ( !IsTitanCockpitModelName( cockpit.GetModelName() ) || IsWatchingThirdPersonKillReplay() ) + { + player.s.inTitanCockpit = false + return + } + + if ( !player.s.inTitanCockpit ) + TitanEmbarkDSP( 0.5 ) + + player.s.inTitanCockpit = true + + // code aint callin this currently + CodeCallback_PlayerInTitanCockpit( GetLocalViewPlayer(), GetLocalViewPlayer() ) + + // move this + array targets = GetClientEntArrayBySignifier( "info_target" ) + foreach ( target in targets ) + { + if ( target.GetTargetName() != "cockpit_geo_ref" ) + continue + + level.cockpitGeoRef = target + } + + entity cockpitParent = expect entity( level.cockpitGeoRef ) + + if ( !IsValid( cockpitParent ) ) + cockpitParent = GetLocalViewPlayer() + + cockpit.s.empInfo <- {} + cockpit.s.empInfo["xOffset"] <- 0 + cockpit.s.empInfo["yOffset"] <- 0 + cockpit.s.empInfo["startTime"] <- 0 + cockpit.s.empInfo["duration"] <- 0 + cockpit.s.empInfo["sub_count"] <- 0 + cockpit.s.empInfo["sub_start"] <- 0 + cockpit.s.empInfo["sub_duration"] <- 0 + cockpit.s.empInfo["sub_pause"] <- 0 + cockpit.s.empInfo["sub_alpha"] <- 0 + + cockpit.s.cockpitType <- 1 + cockpit.s.FOV <- 70 + + cockpit.e.body = CreateCockpitBody( cockpit, player, cockpitParent ) + + thread TitanCockpitAnimThink( cockpit, cockpit.e.body ) + + if ( player.IsTitan() && IsAlive( player ) ) // pilot with titan cockpit gets thrown from titan + thread TitanCockpitDoomedThink( cockpit, player ) + + SetCockpitLightingEnabled( 0, true ) + ShowRUIHUD( cockpit ) +} + +//bind r "script_client ReloadScripts();script_client GetLocalViewPlayer().GetCockpit().Destroy()" +void function ShowRUIHUD( entity cockpit ) +{ + // update topo positions + int cameraAttachId = cockpit.LookupAttachment( "CAMERA" ) + vector cameraOrigin = cockpit.GetAttachmentOrigin( cameraAttachId ) + + int lowerScreenAttachId = cockpit.LookupAttachment( "COCKPIT_HUD_BOTTOM" ) + vector lowerScreenOrigin = cockpit.GetAttachmentOrigin( lowerScreenAttachId ) + vector lowerScreenAngles = cockpit.GetAttachmentAngles( lowerScreenAttachId ) + + int instrument1AttachId = cockpit.LookupAttachment( "COCKPIT_OBJ_1" ) + vector instrument1Origin = cockpit.GetAttachmentOrigin( instrument1AttachId ) + vector instrument1Angles = cockpit.GetAttachmentAngles( instrument1AttachId ) + + lowerScreenOrigin = lowerScreenOrigin - cameraOrigin + vector lowerScreenPosition = + + instrument1Origin = instrument1Origin - cameraOrigin + vector instrument1Position = + vector instrument1RightVector = AnglesToRight( instrument1Angles ) * -1 + vector instrument1DownVector = AnglesToUp( instrument1Angles ) * -1 + + RuiTopology_UpdatePos( clGlobal.topoTitanCockpitLowerHud, lowerScreenPosition, <0, -TITAN_COCKPIT_LOWER_RUI_SCREEN_SQUARE_SIZE, 0>, <0, 0, -(TITAN_COCKPIT_LOWER_RUI_SCREEN_SQUARE_SIZE * TITAN_COCKPIT_LOWER_RUI_SCREEN_HEIGHT_SCALE)> ) + RuiTopology_UpdatePos( clGlobal.topoTitanCockpitInstrument1, instrument1Position - (instrument1RightVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE * 0.5) - (instrument1DownVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE * 0.5), instrument1RightVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE, instrument1DownVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE ) + + // create ruis + entity player = GetLocalViewPlayer() + + #if SP + file.coreHintRui = CreateTitanCockpitRui( $"ui/core_hint.rpak" ) + #endif + + file.cockpitRui = CreateTitanCockpitRui( $"ui/ajax_cockpit_base.rpak" ) + RuiTrackFloat3( file.cockpitRui, "playerOrigin", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.cockpitRui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackFloat( file.cockpitRui, "healthFrac", player, RUI_TRACK_HEALTH ) + RuiTrackFloat( file.cockpitRui, "shieldFrac", player, RUI_TRACK_SHIELD_FRACTION ) + RuiTrackFloat( file.cockpitRui, "dashFrac", player, RUI_TRACK_PLAYER_SUIT_POWER ) + RuiSetFloat( file.cockpitRui, "ejectManualTimeOut", EJECT_FADE_TIME ) + RuiSetFloat( file.cockpitRui, "ejectButtonTimeOut", TITAN_EJECT_MAX_PRESS_DELAY ) + RuiSetGameTime( file.cockpitRui, "ejectManualStartTime", -60.0 ) + RuiSetGameTime( file.cockpitRui, "ejectButtonPressTime", -60.0 ) + #if MP + string titanName = GetTitanCharacterName( player ) + if ( titanName == "vanguard" ) + { + RuiSetString( file.cockpitRui, "titanInfo1", GetVanguardCoreString( player, 1 ) ) + RuiSetString( file.cockpitRui, "titanInfo2", GetVanguardCoreString( player, 2 ) ) + RuiSetString( file.cockpitRui, "titanInfo3", GetVanguardCoreString( player, 3 ) ) + RuiSetString( file.cockpitRui, "titanInfo4", GetVanguardCoreString( player, 4 ) ) + } + + file.cockpitAdditionalRui = CreateTitanCockpitRui( $"ui/ajax_cockpit_fd.rpak" ) + RuiSetFloat( file.cockpitAdditionalRui, "ejectManualTimeOut", EJECT_FADE_TIME ) + RuiSetFloat( file.cockpitAdditionalRui, "ejectButtonTimeOut", TITAN_EJECT_MAX_PRESS_DELAY ) + RuiSetGameTime( file.cockpitAdditionalRui, "ejectManualStartTime", -60.0 ) + + RuiSetDrawGroup( file.cockpitAdditionalRui, RUI_DRAW_NONE ) + #endif + +#if SP + bool ejectIsAllowed = false +#else + bool ejectIsAllowed = !TitanEjectIsDisabled() +#endif + RuiSetBool( file.cockpitRui, "ejectIsAllowed", ejectIsAllowed ) + + string playerSettings = GetLocalViewPlayer().GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( file.cockpitRui, "numHealthSegments", int( health / healthPerSegment ) ) + RuiTrackFloat( file.cockpitRui, "cockpitColor", player, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.cockpitColor ) + + file.cockpitLowerRui = CreateTitanCockpitLowerRui( $"ui/ajax_cockpit_lower.rpak" ) + RuiTrackFloat( file.cockpitLowerRui, "dashFrac", player, RUI_TRACK_PLAYER_SUIT_POWER ) + RuiTrackFloat3( file.cockpitLowerRui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackFloat( file.cockpitLowerRui, "cockpitColor", player, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.cockpitColor ) + + var instrument1Rui = CreateTitanCockpitInstrument1Rui( $"ui/ajax_cockpit_insturment1.rpak" ) + RuiTrackFloat3( instrument1Rui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + int numDashPips = int( floor( 100 / GetSettingsForPlayer_DodgeTable( GetLocalViewPlayer() )["dodgePowerDrain"] ) ) + RuiSetInt( file.cockpitRui, "numDashSegments", numDashPips ) + RuiSetInt( file.cockpitLowerRui, "numDashSegments", numDashPips ) + + thread CockpitDoomedThink( cockpit ) + thread TitanCockpitDestroyRuisOnDeath( cockpit ) + thread TitanCockpitHealthChangedThink( cockpit, player ) + + #if MP + if ( GetCurrentPlaylistVarInt( "aegis_upgrades", 0 ) == 1 && !IsSpectating() && !IsWatchingKillReplay() ) + thread DisplayFrontierRank( file.isFirstBoot ) + #endif + file.isFirstBoot = false + + UpdateTitanCockpitVisibility() +} + +#if MP +void function DisplayFrontierRank( bool isFirstBoot = true ) +{ + GetLocalClientPlayer().Signal( "DisplayFrontierRank" ) + GetLocalClientPlayer().EndSignal( "DisplayFrontierRank" ) + + wait 2.0 + + TitanLoadoutDef titanLoadout = GetTitanLoadoutFromPersistentData( GetLocalClientPlayer(), GetPersistentSpawnLoadoutIndex( GetLocalClientPlayer(), "titan" ) ) + string titanClass = titanLoadout.titanClass + + array titanUpgrades = FD_GetUpgradesForTitanClass( titanClass ) + int maxActiveIndex + foreach ( index, item in titanUpgrades ) + { + RuiSetImage( file.cockpitAdditionalRui, "upgradeIcon" + (index + 1), item.image ) + RuiSetString( file.cockpitAdditionalRui, "upgradeName" + (index + 1), item.name ) + + if ( !IsSubItemLocked( GetLocalClientPlayer(), item.ref, item.parentRef ) ) + maxActiveIndex++ + } + + RuiSetDrawGroup( file.cockpitAdditionalRui, RUI_DRAW_COCKPIT ) + + bool firstBootDisplay + if ( GameRules_GetGameMode() == FD ) + firstBootDisplay = isFirstBoot || !GetGlobalNetBool( "FD_waveActive" ) + else + firstBootDisplay = isFirstBoot + + RuiSetBool( file.cockpitAdditionalRui, "isFirstBoot", firstBootDisplay ) + RuiSetImage( file.cockpitAdditionalRui, "titanIcon", GetIconForTitanClass( titanClass ) ) + RuiSetInt( file.cockpitAdditionalRui, "titanRank", FD_TitanGetLevel( GetLocalClientPlayer(), titanClass ) ) + RuiSetInt( file.cockpitAdditionalRui, "maxActiveIndex", maxActiveIndex ) + RuiSetGameTime( file.cockpitAdditionalRui, "updateTime", Time() ) + + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeAnnouncement" ) + + if ( firstBootDisplay ) + { + wait 2.0 + + for ( int index = 0; index < maxActiveIndex; index++ ) + { + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeTextAppear" ) + + wait 0.85 + + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeBarFill" ) + + wait 0.15 + } + } + else + { + wait 0.5 + + for ( int index = 0; index < maxActiveIndex; index++ ) + { + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeBarFill" ) + wait 0.05 + } + } +} + +string function GetVanguardCoreString( entity player, int index ) +{ + Assert( player.IsTitan() ) + + if ( !IsConnected() ) //Persistence isn't available when we disconnect + return "" + + if ( player != GetLocalClientPlayer() ) //Client Persistence doesn't know about other players. + return "" + + TitanLoadoutDef loadout = GetActiveTitanLoadout( player ) + + entity soul = player.GetTitanSoul() + if ( !IsValid( soul ) ) + return "" + + if ( index == 1 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 1 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE1_TITLE" ), Localize( GetItemName( loadout.passive4 ) ) ) + } + else + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE1_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + } + } + if ( index == 2 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 2 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( GetItemName( loadout.passive5 ) ) ) + } + else + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 1 ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + else + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( "#UPGRADE_NOT_INSTALLED" ) ) + } + } + if ( index == 3 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 3 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( GetItemName( loadout.passive6 ) ) ) + } + else + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 2 ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + else + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( "#UPGRADE_NOT_INSTALLED" ) ) + } + } + if ( index == 4 ) + { + printt( loadout.passive4 ) + if ( loadout.passive4 == "pas_vanguard_core1" ) // Arc Rounds + { + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_RIGHT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "missile_racks" ) || offhandWeapon.HasMod( "upgradeCore_MissileRack_Vanguard" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE2" ) ) + offhandWeapon = player.GetOffhandWeapon( OFFHAND_LEFT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "energy_transfer" ) || offhandWeapon.HasMod( "energy_field_energy_transfer" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE3" ) ) + } + else if ( loadout.passive4 == "pas_vanguard_core2" ) // Missile Racks + { + entity weapon = player.GetMainWeapons()[0] + if ( IsValid( weapon ) && ( weapon.HasMod( "arc_rounds" ) || weapon.HasMod( "arc_rounds_with_battle_rifle" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE1" ) ) + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_LEFT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "energy_transfer" ) || offhandWeapon.HasMod( "energy_field_energy_transfer" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE3" ) ) + } + else if ( loadout.passive4 == "pas_vanguard_core3" ) // Energy Transfer + { + entity weapon = player.GetMainWeapons()[0] + if ( IsValid( weapon ) && ( weapon.HasMod( "arc_rounds" ) || weapon.HasMod( "arc_rounds_with_battle_rifle" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE1" ) ) + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_RIGHT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "missile_racks" ) || offhandWeapon.HasMod( "upgradeCore_MissileRack_Vanguard" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE2" ) ) + } + return "" + } + + unreachable +} +#endif + +void function SetUnlimitedDash( bool active ) +{ + if ( file.cockpitLowerRui == null ) + return + + RuiSetBool( file.cockpitLowerRui, "hasUnlimitedDash", active ) +} + +void function UpdateEjectHud_SetManualEjectStartTime( entity player ) +{ + float timeNow = Time() + player.p.ejectEnableTime = timeNow + + if ( file.cockpitRui != null ) + RuiSetGameTime( file.cockpitRui, "ejectManualStartTime", timeNow ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetGameTime( file.cockpitAdditionalRui, "ejectManualStartTime", timeNow ) +} + +void function UpdateEjectHud_SetButtonPressTime( entity player ) +{ + float timeNow = Time() + player.p.ejectPressTime = timeNow + + if ( file.cockpitRui != null ) + RuiSetGameTime( file.cockpitRui, "ejectButtonPressTime", timeNow ) + + //if ( file.cockpitAdditionalRui != null ) + // RuiSetGameTime( file.cockpitAdditionalRui, "ejectButtonPressTime", timeNow ) +} + +void function UpdateEjectHud_SetButtonPressCount( entity player, int buttonCount ) +{ + player.p.ejectPressCount = buttonCount + + if ( file.cockpitRui != null ) + RuiSetInt( file.cockpitRui, "ejectButtonCount", buttonCount ) + + //if ( file.cockpitAdditionalRui != null ) + // RuiSetInt( file.cockpitAdditionalRui, "ejectButtonCount", buttonCount ) +} + +void function UpdateTitanCockpitVisibility() +{ + entity player = GetLocalViewPlayer() + if ( !IsValid( player ) ) + return + + if ( Tone_ShouldCreateTrackerHud( player ) ) + thread Tone_HudThink( player ) + else + player.Signal( "StopToneHud" ) + + foreach ( managedRUI in file.titanCockpitManagedRUIs ) + { + bool shouldCreate = managedRUI.shouldCreate() + if ( !managedRUI.exists && shouldCreate ) + { + var rui = managedRUI.create() + + bool found = false + foreach ( cockpitRui in player.p.titanCockpitRUIs ) + { + if ( cockpitRui.rui == rui ) + found = true + } + if ( !found ) + { + TitanCockpitRUI tcRUI + tcRUI.rui = rui + tcRUI.drawGroup = managedRUI.drawGroup + player.p.titanCockpitRUIs.append( tcRUI ) + } + + managedRUI.exists = true + } + else if ( managedRUI.exists && !shouldCreate ) + { + managedRUI.destroy() + managedRUI.exists = false + } + } + + bool isVisible = true + + int ceFlags = player.GetCinematicEventFlags() + if ( (ceFlags & CE_FLAG_INTRO) || (ceFlags & CE_FLAG_TITAN_3P_CAM) ) + isVisible = false + if ( clGlobal.isSoloDialogMenuOpen ) + isVisible = false + + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + TitanCockpitRUI tcRUI = player.p.titanCockpitRUIs[ i ] + RuiSetDrawGroup( tcRUI.rui, isVisible ? tcRUI.drawGroup : RUI_DRAW_NONE ) + } +} + +void function AddTitanCockpitManagedRUI( var functionref() createFunc, void functionref() destroyFunc, bool functionref() shouldCreateFunc, int drawGroup ) +{ + TitanCockpitManagedRUI managedRUI + managedRUI.create = createFunc + managedRUI.destroy = destroyFunc + managedRUI.shouldCreate = shouldCreateFunc + managedRUI.drawGroup = drawGroup + + file.titanCockpitManagedRUIs.append( managedRUI ) +} + +void function CinematicEventFlagChanged( entity player ) +{ + UpdateTitanCockpitVisibility() +} + +void function CockpitDoomedThink( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + cockpit.EndSignal( "OnDestroy" ) + + while ( IsAlive( player ) ) + { + entity soul = player.GetTitanSoul() + if ( !IsValid( soul ) ) //Defensive fix for bug 227087. Assumption is that the cockpit is likely to be destroyed soon if the soul is invalid. + return + if ( !soul.IsDoomed() ) + player.WaitSignal( "Doomed" ) + + SetCockpitUIDoomedState( true ) + + if ( !IsValid( soul ) ) //Defensive fix for bug 227087. Assumption is that the cockpit is likely to be destroyed soon if the soul is invalid. + return + if ( soul.IsDoomed() ) + player.WaitSignal( "TitanUnDoomed" ) + + SetCockpitUIDoomedState( false ) + } +} + +void function SetCockpitUIEjectingState( bool state ) +{ + if ( file.cockpitRui != null ) + RuiSetBool( file.cockpitRui, "isEjecting", state ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetBool( file.cockpitAdditionalRui, "isEjecting", state ) + + if ( file.cockpitLowerRui != null ) + { + RuiSetBool( file.cockpitLowerRui, "isEjecting", state ) + if ( state ) + RuiSetString( file.cockpitLowerRui, "ejectPrompt", Localize( RollRandomEjectString() ) ) + else + RuiSetString( file.cockpitLowerRui, "ejectPrompt", "" ) + } +} + +void function SetCockpitUIDoomedState( bool state ) +{ + if ( file.cockpitRui != null ) + RuiSetBool( file.cockpitRui, "isDoomed", state ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetBool( file.cockpitAdditionalRui, "isDoomed", state ) +} + +void function TitanCockpitDestroyRui( var ruiToDestroy ) +{ + if ( ruiToDestroy == null ) + return + + entity player = GetLocalViewPlayer() + + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + TitanCockpitRUI tcRUI = player.p.titanCockpitRUIs[ i ] + if ( tcRUI.rui == ruiToDestroy ) + { + RuiDestroy( tcRUI.rui ) + player.p.titanCockpitRUIs.remove( i ) + } + } +} + +void function TitanCockpitDestroyRuisOnDeath( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + + OnThreadEnd( + function() : ( cockpit ) + { + foreach ( managedRUI in file.titanCockpitManagedRUIs ) + { + if ( managedRUI.exists ) + { + managedRUI.destroy() + managedRUI.exists = false + } + } + + entity player = GetLocalViewPlayer() + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + RuiDestroy( player.p.titanCockpitRUIs[ i ].rui ) + player.p.titanCockpitRUIs.remove( i ) + } + + player = GetLocalClientPlayer() + if ( IsValid( player ) ) + player.Signal( "DisplayFrontierRank" ) + file.cockpitAdditionalRui = null + file.cockpitRui = null + file.cockpitLowerRui = null + file.coreHintRui = null + } + ) + + player.EndSignal( "OnDeath" ) + cockpit.EndSignal( "OnDestroy" ) + WaitForever() +} + +function CockpitBodyThink( cockpit, cockpitBody ) +{ + cockpitBody.EndSignal( "OnDestroy" ) + + cockpit.WaitSignal( "OnDestroy" ) + + cockpitBody.Destroy() +} + + +entity function CreateCockpitBody( entity cockpit, entity player, entity cockpitParent ) +{ + #if SP + string bodySettings = DEFAULT_PILOT_SETTINGS + #else + string bodySettings = file.lastPilotSettings + if ( bodySettings == "" || bodySettings == "spectator" ) + bodySettings = Loadouts_GetSetFileForRequestedClass( player ) + if ( bodySettings == "" ) + bodySettings = "pilot_base" + #endif + + asset bodyModelName = GetPlayerSettingsAssetForClassName( bodySettings, "armsmodel" ) + #if DEV + if ( bodySettings == "" ) + { + CodeWarning( "Couldn't find armsmodel for set file: " + bodySettings ) + } + #endif + + entity cockpitBody = CreateClientSidePropDynamic( cockpitParent.GetOrigin(), Vector( 0, 0, 0 ), bodyModelName ) + cockpitBody.EnableRenderWithCockpit() + cockpitBody.SetOrigin( cockpit.GetOrigin() ) + cockpitBody.SetParent( cockpit ) + + thread CockpitBodyThink( cockpit, cockpitBody ) + + return cockpitBody +} + +function TitanEmbarkDSP( transitionTime ) +{ +} + +function TitanDisembarkDSP( transitionTime ) +{ +} + +function TitanCockpit_EMPFadeScale( entity cockpit, elapsedMod = 0 ) +{ + local fadeInTime = 0.0 + local fadeOutTime = 1.5 + local elapsedTime = Time() - cockpit.s.empInfo.startTime + elapsedTime += elapsedMod + + // ToDo: + // Fade in/out from last frames amount so it doesnt pop + // Make strength var to control max fade ( less strength returns max of like 0.5 ) + + //------------------------ + // EMP effect is finished + //------------------------ + + //printt( "elapsedTime:" + elapsedTime + " cockpit.s.empInfo.duration:" + cockpit.s.empInfo.duration + " fadeOutTime:" + fadeOutTime ) + if ( elapsedTime < cockpit.s.empInfo.duration - fadeOutTime ) + { + return 1.0 + } + + + if ( elapsedTime >= fadeInTime + cockpit.s.empInfo.duration + fadeOutTime ) + { + cockpit.s.empInfo.startTime = 0 + return 0.0 + } + + //------------------------ + // EMP effect is starting + //------------------------ + + if ( elapsedTime < fadeInTime ) + { + return GraphCapped( elapsedTime, 0.0, fadeInTime, 0.0, 1.0 ) + } + + //---------------------- + // EMP effect is ending + //---------------------- + + if ( elapsedTime > fadeInTime + cockpit.s.empInfo.duration ) + { + cockpit.s.empInfo["sub_count"] = 0 + return GraphCapped( elapsedTime, fadeInTime + cockpit.s.empInfo.duration, fadeInTime + cockpit.s.empInfo.duration + fadeOutTime, 1.0, 0.0 ) + } + + //--------------------- + // EMP flicker effect + //--------------------- + + // Time to start a new flicker + if ( cockpit.s.empInfo["sub_start"] == 0 ) + { + cockpit.s.empInfo["sub_start"] <- Time() + if ( cockpit.s.empInfo["sub_count"] == 0 ) + cockpit.s.empInfo["sub_pause"] <- RandomFloatRange( 0.5, 1.5 ) + else + cockpit.s.empInfo["sub_pause"] <- RandomFloat( 0.5 ) + cockpit.s.empInfo["sub_duration"] <- RandomFloatRange( 0.1, 0.4 ) + cockpit.s.empInfo["sub_alpha"] <- RandomFloatRange( 0.4, 0.9 ) + cockpit.s.empInfo["sub_count"]++; + } + local flickerElapsedTime = Time() - cockpit.s.empInfo["sub_start"] + + // Start a new flicker if the current one is finished + if ( flickerElapsedTime > cockpit.s.empInfo["sub_pause"] + cockpit.s.empInfo["sub_duration"] ) + cockpit.s.empInfo["sub_start"] = 0 + + if ( flickerElapsedTime < cockpit.s.empInfo["sub_pause"] ) + { + // Pause before the flicker + return 1.0 + } + else if ( flickerElapsedTime < cockpit.s.empInfo["sub_pause"] + ( cockpit.s.empInfo["sub_duration"] / 2.0 ) ) + { + // First half of the flicker + return GraphCapped( flickerElapsedTime, 0.0, cockpit.s.empInfo["sub_duration"] / 2.0, 1.0, cockpit.s.empInfo["sub_alpha"] ) + } + else + { + // Second half of the flicker + return GraphCapped( flickerElapsedTime, cockpit.s.empInfo["sub_duration"] / 2.0, cockpit.s.empInfo["sub_duration"], cockpit.s.empInfo["sub_alpha"], 1.0 ) + } +} + +function ServerCallback_TitanCockpitEMP( duration ) +{ + thread TitanCockpit_DoEMP( duration / 4 ) +} + +function TitanCockpit_DoEMP( duration ) +{ + entity player = GetLocalViewPlayer() + entity cockpit = player.GetCockpit() + + if ( !IsValid( cockpit ) ) + return + + if ( !player.IsTitan() ) + return + + if ( !player.s.inTitanCockpit ) + return + + Signal( player, "EMP" ) + EndSignal( player, "EMP" ) + player.EndSignal( "OnDestroy" ) + + // this needs tweaking... looks a bit artificial + ClientCockpitShake( 0.25, 3, 1.0, Vector( 0, 0, 1 ) ) // amplitude, frequency, duration, direction + + thread PlayCockpitEMPLights( cockpit, duration ) + + // Start the screens and vdu power outages + cockpit.s.empInfo.xOffset = RandomFloatRange( 0.5, 0.75 ) + cockpit.s.empInfo.yOffset = RandomFloatRange( 0.5, 0.75 ) + if ( CoinFlip() ) + cockpit.s.empInfo.xOffset *= -1 + if ( CoinFlip() ) + cockpit.s.empInfo.yOffset *= -1 + + cockpit.s.empInfo.startTime = Time() + cockpit.s.empInfo.duration = duration + + EmitSoundOnEntity( player, EMP_IMPARED_SOUND ) + wait duration + FadeOutSoundOnEntity( player, EMP_IMPARED_SOUND, 1.5 ) +} + +function PlayCockpitEMPLights( cockpit, duration ) +{ + duration += 1.5 // blend out + local attachID + local origin + local angles + local fxLights = [] + + string tagName = "COCKPIT" // SCR_CL_BL" + attachID = cockpit.LookupAttachment( tagName ) + origin = cockpit.GetAttachmentOrigin( attachID ) + origin.z -= 25 + angles = Vector( 0, 0, 0 ) + local lightTable = {} + lightTable.light <- CreateClientSideDynamicLight( origin, angles, Vector( 0.0, 0.0, 0.0 ), 80.0 ) + lightTable.modulate <- true + fxLights.append( lightTable ) + + wait 0.5 + + foreach ( fxLight in fxLights ) + { + fxLight.light.SetCockpitLight( true ) + } + + local startTime = Time() + local rate = 1.2 + + local endTime = Time() + duration + + while ( IsValid( cockpit ) ) + { + if ( Time() > endTime ) + break + + float subtractColor = GraphCapped( Time(), endTime - 0.25, endTime, 1.0, 0.0 ) + local pulseFrac = GetPulseFrac( rate, startTime ) + pulseFrac *= subtractColor + //pulseFrac -= fadeInColor + + foreach ( index, fxLight in fxLights ) + { + Assert( fxLight.modulate ) + fxLight.light.SetLightColor( Vector( pulseFrac, 0, 0 ) ) + + // the case where fxLight.modulate == false used to be handled by this script, which used undefined variable fadeInColor: + // fxLight.light.SetLightColor( Vector( fadeInColor, fadeInColor, fadeInColor ) ) + } + + WaitFrame() + } + + foreach ( fxLight in fxLights ) + { + fxLight.light.Destroy() + } +} + + +function TitanCockpit_IsBooting( cockpit ) +{ + return cockpit.GetTimeInCockpit() < 1.3 +} + +function TitanCockpitAnimThink( cockpit, body ) +{ + cockpit.SetOpenViewmodelOffset( 20.0, 0.0, 10.0 ) + cockpit.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + + if ( body ) + body.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) +} + + +bool function IsDisplayingEjectInterface( entity player ) +{ + if ( !player.IsTitan() ) + return false + + if ( player.ContextAction_IsMeleeExecution() ) //Could just check for ContextAction_IsActive() if we need to be more general + return false + + if ( !GetDoomedState( player ) && Time() - player.p.ejectEnableTime > EJECT_FADE_TIME ) + return false + + if ( Riff_TitanExitEnabled() == eTitanExitEnabled.Never || Riff_TitanExitEnabled() == eTitanExitEnabled.DisembarkOnly ) + return false + + //if ( !CanDisembark( player ) ) + // return false + + return true +} + +void function PlayerPressed_Eject( entity player ) +{ + if ( !IsDisplayingEjectInterface( player ) ) + return + + if ( Time() - player.p.ejectPressTime > TITAN_EJECT_MAX_PRESS_DELAY ) + UpdateEjectHud_SetButtonPressCount( player, 0 ) + + if ( !IsAlive( player ) ) + return + + EmitSoundOnEntity( player, "titan_eject_xbutton" ) + EmitSoundOnEntity( player, "hud_boost_card_radar_jammer_redtextbeep_1p" ) + UpdateEjectHud_SetButtonPressTime( player ) + UpdateEjectHud_SetButtonPressCount( player, (player.p.ejectPressCount + 1) ) + + player.ClientCommand( "TitanEject " + player.p.ejectPressCount ) + + entity cockpit = player.GetCockpit() + if ( player.p.ejectPressCount < 3 || cockpit.s.ejectStartTime ) + return + + PlayerEjects( player, cockpit ) +} + +string function RollRandomEjectString() +{ + const int COCKPIT_EJECT_COMMON_COUNT = 6 + const int COCKPIT_EJECT_RARE_COUNT = 36 + const float CHANCE_FOR_RARE = 0.15 + + float randForType = RandomFloat( 1.0 ) + if ( randForType < CHANCE_FOR_RARE ) + { + int index = RandomInt( COCKPIT_EJECT_RARE_COUNT ) + string result = "#COCKPIT_EJECT_RARE_" + index + return result + } + + int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT ) + string result = "#COCKPIT_EJECT_COMMON_" + index + return result +} + +void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal +{ + // prevent animation from playing if player is in the middle of execution + if ( player.ContextAction_IsActive() && !player.ContextAction_IsBusy() ) + return + + player.Signal( "Ejecting" ) + + SetCockpitUIEjectingState( true ) + + local ejectAlarmSound + cockpit.s.ejectStartTime = Time() + string animationName + if ( GetNuclearPayload( player ) > 0 ) + { + animationName = "atpov_cockpit_eject_nuclear" + cockpit.Anim_NonScriptedPlay( animationName ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_eject_nuclear" ) + ejectAlarmSound = TITAN_NUCLEAR_DEATH_ALARM + } + else + { + animationName = "atpov_cockpit_eject" + cockpit.Anim_NonScriptedPlay( animationName ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_eject" ) + + ejectAlarmSound = TITAN_ALARM_SOUND + } + + thread LightingUpdateAfterOpeningCockpit() + thread EjectAudioThink( player, ejectAlarmSound ) + + float animDuration = cockpit.GetSequenceDuration( animationName ) + + thread MonitorPlayerEjectAnimBeingStuck( player, animDuration ) +} + +void function MonitorPlayerEjectAnimBeingStuck( entity player, float duration ) +{ + player.Signal( "MonitorPlayerEjectAnimBeingStuck" ) + player.EndSignal( "MonitorPlayerEjectAnimBeingStuck" ) + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "SettingsChanged" ) + + + wait duration + 2.0 // 1s as a buffer + + if ( player.IsTitan() ) + { + entity cockpit = player.GetCockpit() + cockpit.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + + SetCockpitUIEjectingState( false ) + } +} + +function ServerCallback_EjectConfirmed() +{ + if ( !IsWatchingReplay() ) + return + + entity player = GetLocalViewPlayer() + entity cockpit = player.GetCockpit() + + if ( !cockpit || !IsTitanCockpitModelName( cockpit.GetModelName() ) ) + return + + PlayerEjects( player, cockpit ) +} + +function EjectAudioThink( entity player, ejectAlarmSound = TITAN_ALARM_SOUND ) +{ + EmitSoundOnEntity( player, ejectAlarmSound ) + TitanCockpit_PlayDialog( player, "manualEjectNotice" ) + + player.EndSignal( "OnDeath" ) + + player.WaitSignal( "SettingsChanged" ) + + if ( player.GetPlayerClass() != "pilot" ) + return + + OnThreadEnd( + function() : ( player ) + { + if ( !IsAlive( player ) ) + { + StopSoundOnEntity( player, TITAN_EJECT_ASCENT ) + StopSoundOnEntity( player, TITAN_EJECT_DESCENT ) + } + else + { + FadeOutSoundOnEntity( player, TITAN_EJECT_ASCENT, 0.25 ) + FadeOutSoundOnEntity( player, TITAN_EJECT_DESCENT, 0.25 ) + } + + StopSoundOnEntity( player, TITAN_EJECT_APEX ) + } + ) + + EmitSoundOnEntity( player, TITAN_EJECT_BOOST ) + + float startTime = Time() + float duration = GetSoundDuration( TITAN_EJECT_ASCENT ) + EmitSoundOnEntity( player, TITAN_EJECT_ASCENT ) + float timeOut = duration - 0.25 + vector velocity + float diff = 0.0 + + const int STAGE_ASCENT = 1 + const int STAGE_APEX = 2 + const int STAGE_DESCENT = 3 + + int ejectStage = STAGE_ASCENT + + string currentSound = TITAN_EJECT_ASCENT + + while ( diff < timeOut ) + { + PerfStart( 127 ) + + diff = (Time() - startTime) + + velocity = player.GetVelocity() + float length = Length( velocity ) + + if ( diff > 0.5 ) + { + if ( player.IsOnGround() ) + { + PerfEnd( 127 ) + break + } + } + + if ( ejectStage != STAGE_DESCENT && velocity.z < 0 ) + { + FadeOutSoundOnEntity( player, TITAN_EJECT_ASCENT, 0.25 ) + timeOut = GetSoundDuration( TITAN_EJECT_DESCENT ) + EmitSoundOnEntity( player, TITAN_EJECT_DESCENT ) + currentSound = TITAN_EJECT_DESCENT + ejectStage = STAGE_DESCENT + } + else if ( ejectStage == STAGE_ASCENT && length < 400 ) + { + EmitSoundOnEntity( player, TITAN_EJECT_APEX ) + ejectStage = STAGE_APEX + } + + PerfEnd( 127 ) + + WaitFrame() + } +} + +function LightingUpdateAfterOpeningCockpit() +{ + while ( true ) + { + if ( !GetLocalViewPlayer().s.inTitanCockpit ) + break + WaitFrame() + } + + SetCockpitLightingEnabled( 0, false ) +} + + +function TonemappingUpdateAfterOpeningCockpit() //Deprecated, no longer used +{ + local duration = 3 + local tonemapMin = 2 + local tonemapMax = 5 + + while ( true ) + { + if ( !GetLocalViewPlayer().s.inTitanCockpit ) + break + WaitFrame() + } + + SetCockpitLightingEnabled( 0, false ) + + AutoExposureSetExposureCompensationBias( tonemapMax ) + AutoExposureSnap() + wait( 0.1 ) + + TitanDisembarkDSP( 0.5 ) + + local startTime = Time() + while ( true ) + { + local time = Time() - startTime + float factor = GraphCapped( time, 0, duration, 1, 0 ) + factor = factor * factor * factor + local toneMapScale = tonemapMin + (tonemapMax - tonemapMin) * factor + AutoExposureSetExposureCompensationBias( toneMapScale ) + AutoExposureSnap() + wait 0 + if ( factor == 0 ) + break + } + + AutoExposureSetExposureCompensationBias( 0 ) +} + +function ServerCallback_TitanEmbark() +{ + TitanCockpit_PlayDialog( GetLocalViewPlayer(), "embark" ) +} + +function ServerCallback_TitanDisembark() +{ + entity player = GetLocalViewPlayer() + + thread LightingUpdateAfterOpeningCockpit() + + //HideFriendlyIndicatorAndCrosshairNames() + + //PlayMusic( "Music_FR_Militia_PilotAction2" ) +} + + +function PlayerPressed_QuickDisembark( player ) +{ + player.ClientCommand( "TitanDisembark" ) +} + +void function PlayerPressed_EjectEnable( entity player ) +{ + if ( !player.IsTitan() ) + return + + if ( !IsAlive( player ) ) + return + + if ( IsValid( player.GetParent() ) ) + return + + if ( TitanEjectIsDisabled() ) + { + EmitSoundOnEntity( player, "CoOp_SentryGun_DeploymentDeniedBeep" ) + SetTimedEventNotification( 1.5, "" ) + SetTimedEventNotification( 1.5, "#NOTIFY_EJECT_DISABLED" ) + return + } + + if ( Riff_TitanExitEnabled() == eTitanExitEnabled.Never || Riff_TitanExitEnabled() == eTitanExitEnabled.DisembarkOnly ) + return + + //if ( !CanDisembark( player ) ) + // return + + if ( player.ContextAction_IsMeleeExecution() ) //Could just check for ContextAction_IsActive() if we need to be more general + return + + if ( player.GetHealth() == 1 ) + { + #if MP + if ( !FD_ReadyUpEnabled() ) + #endif + { + player.ClientCommand( "TitanEject " + 3 ) + return + } + } + + EmitSoundOnEntity( player, "titan_eject_dpad" ) + UpdateEjectHud_SetManualEjectStartTime( player ) + player.Signal( "UpdateRodeoAlert" ) // need this to hide titan stomp hint +} + +float function CalcJoltMagnitude( player, cockpit, joltDir, float damageAmount, damageType, int damageSourceID ) +{ + const float COCKPIT_MAX_JOLT_DAMAGE = 2000.0 + + float resultRaw = damageAmount / COCKPIT_MAX_JOLT_DAMAGE + return clamp( resultRaw, 0.0, 1.0 ) +} + +function JoltCockpit( cockpit, player, joltDir, float damageAmount, damageType, damageSourceId ) +{ + float severity = CalcJoltMagnitude( player, cockpit, joltDir, damageAmount, damageType, expect int( damageSourceId ) ) + player.CockpitJolt( joltDir, severity ) +} + +function RandomizeDir( dir, randPitch = 0, randYaw = 0, basePitch = 0, baseYaw = 0 ) +{ + local pitch = RandomFloatRange( -randPitch, randPitch ) + local yaw = RandomFloatRange( -randYaw, randYaw ) + local angles = VectorToAngles( dir ) + angles = AnglesCompose( angles, Vector( pitch, yaw, 0 ) ) + angles = AnglesCompose( angles, Vector( basePitch, baseYaw, 0 ) ) + return AnglesToForward( angles ) +} + +function TitanCockpitDoomedThink( cockpit, player ) +{ + cockpit.EndSignal( "OnDestroy" ) + + local titanSoul = player.GetTitanSoul() + + if ( titanSoul == null || !titanSoul.IsDoomed() ) + WaitSignal( player, "Doomed", "Ejecting" ) + + local color = Vector( 0.6, 0.06, 0 ) + local radius = 70.0 + + FlashCockpitLight( cockpit, color, radius, -1 ) +} + +void function TitanCockpitHealthChangedThink( cockpit, entity player ) +{ + cockpit.EndSignal( "OnDestroy" ) + + while ( true ) + { + table results = WaitSignal( player, "HealthChanged" ) + + if ( !IsAlive( player ) ) + continue + + float oldHealthFrac = float( results.oldHealth ) / float( player.GetMaxHealth() ) + float newHealthFrac = float( results.newHealth ) / float( player.GetMaxHealth() ) + + if ( oldHealthFrac > newHealthFrac ) + { + var rui = RuiCreate( $"ui/ajax_cockpit_lost_health_segment.rpak", clGlobal.topoTitanCockpitHud, RUI_DRAW_COCKPIT, 10 ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat( rui, "oldHealthFrac", oldHealthFrac ) + RuiSetFloat( rui, "newHealthFrac", newHealthFrac ) + + string playerSettings = GetLocalViewPlayer().GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( rui, "numHealthSegments", int( health / healthPerSegment ) ) + } + } +} + + +function FlashCockpitLight( cockpit, color, radius, duration, tag = "SCR_CL_BL" ) +{ + cockpit.EndSignal( "TitanUnDoomed" ) + cockpit.EndSignal( "OnDestroy" ) + + local attachID = cockpit.LookupAttachment( tag ) + local origin = cockpit.GetAttachmentOrigin( attachID ) + local angles = Vector( 0, 0, 0 ) + + local fxLight = CreateClientSideDynamicLight( origin, angles, color, radius ) + fxLight.SetCockpitLight( true ) + fxLight.SetParent( cockpit ) + + OnThreadEnd( + function() : ( fxLight ) + { + fxLight.Destroy() + } + ) + + local startTime = Time() + local rate = 3.0 + + while ( IsValid( cockpit ) && (Time() < startTime + duration || duration == -1 ) ) + { + local pulseFrac = GetPulseFrac( rate, startTime ) + pulseFrac += 0.5 + fxLight.SetLightColor( Vector( color.x * pulseFrac, color.y * pulseFrac, color.z * pulseFrac ) ) + + WaitFrame() + } +} + +function PlayCockpitSparkFX_Internal( cockpit, string tagName ) +{ + expect entity( cockpit ) + + // this is called from a delaythread so needs valid check + if ( !IsValid( cockpit ) ) + return + + int attachID = cockpit.LookupAttachment( tagName ) + if ( attachID == 0 ) + { + tagName = CoinFlip() ? "FX_TL_PANEL" : "FX_TR_PANEL" + attachID = cockpit.LookupAttachment( tagName ) + Assert( attachID, "Could not find fallback attachment index " + attachID + " for '" + tagName + "'' in model " + GetLocalViewPlayer().GetCockpit().GetModelName() ) + } + + int fxID = GetParticleSystemIndex( $"xo_cockpit_spark_01" ) + int fxInstID = PlayFXOnTag( cockpit, fxID, attachID ) + + EffectSetIsWithCockpit( fxInstID, true ) +} + +function PlayCockpitSparkFX( cockpit, int sparkCount ) +{ + const int TAG_COUNT = 6 + const string[TAG_COUNT] cockpitFXEmitTags = [ "FX_TL_PANEL", "FX_TR_PANEL", "FX_TC_PANELA", "FX_TC_PANELB", "FX_BL_PANEL", "FX_BR_PANEL" ] + array playlist = [0,1,2,3,4,5] + playlist.randomize() + + for ( int idx = 0; idx < sparkCount; idx++ ) + { + int lookup = (idx % TAG_COUNT) + int tagIndex = playlist[lookup] + string tagName = cockpitFXEmitTags[tagIndex] + PlayCockpitSparkFX_Internal( cockpit, tagName ) + } +} + +const int DAMAGE_PER_SPARK = 1000 +const int SPARK_MULTIPLIER = 3 + +int function CalSparkCountForHit( entity player, float damageAmount, bool becameDoomed ) +{ + if ( becameDoomed ) + return 20 + if ( damageAmount <= 0 ) + return 0 + + int healthNow = player.GetHealth() + int healthPrev = healthNow + int( damageAmount ) + int healthMax = player.GetMaxHealth() + + bool isDoomed = GetDoomedState( player ) + int sparksNow = (healthNow / DAMAGE_PER_SPARK) + int sparksPrev = (healthPrev / DAMAGE_PER_SPARK) + if ( (healthPrev == healthMax) && !isDoomed ) + --sparksPrev // no spark on first damage + + int delta = (sparksPrev - sparksNow) + if ( delta < 0 ) + return 0 + + return (delta * SPARK_MULTIPLIER) +} + +function TitanCockpit_DamageFeedback( entity player, cockpit, float damageAmount, damageType, damageOrigin, damageSourceId, bool doomedNow, int doomedDamage ) +{ + RumbleForTitanDamage( damageAmount ) + + vector joltDir = Normalize( player.CameraPosition() - damageOrigin ) + float joltDamage = doomedNow ? float( doomedDamage ) : damageAmount + JoltCockpit( cockpit, player, joltDir, joltDamage, damageType, damageSourceId ) + + bool isShieldHit = (damageType & DF_SHIELD_DAMAGE) ? true : false + if ( isShieldHit ) + return + + int sparkCount = CalSparkCountForHit( player, damageAmount, doomedNow ); + //printt( "sparks: " + sparkCount + " dmg: " + damageAmount + " - " + player.GetHealth() + " / " + player.GetMaxHealth() ) + PlayCockpitSparkFX( cockpit, sparkCount ) +} + +function ServerCallback_TitanCockpitBoot() +{ + thread ServerCallback_TitanCockpitBoot_Internal() +} + +function ServerCallback_TitanCockpitBoot_Internal() +{ + AutoExposureSetExposureCompensationBias( -6 ) + AutoExposureSnap() + wait 0.1 + AutoExposureSetExposureCompensationBias( 0 ) +} + +function ServerCallback_TitanEMP( maxValue, duration, fadeTime, doFlash = true, doSound = true ) +{ + thread TitanEMP_Internal( maxValue, duration, fadeTime, doFlash, doSound ) +} + +function TitanEMP_Internal( maxValue, duration, fadeTime, doFlash = true, doSound = true ) +{ + entity player = GetLocalViewPlayer() + + player.Signal( "TitanEMP_Internal" ) + player.EndSignal( "TitanEMP_Internal" ) + + player.EndSignal( "OnDeath" ) + player.EndSignal( "SettingsChanged" ) + + local angles = Vector( 0, -90, 90 ) + + local wide = 16 + local tall = 9 + + float fovOffset = Graph( player.GetFOV(), 75, 120, 4, 2.5 ) + + local empVgui = CreateClientsideVGuiScreen( "vgui_titan_emp", VGUI_SCREEN_PASS_VIEWMODEL, Vector(0,0,0), Vector(0,0,0), wide, tall ); + + //empVgui.SetParent( player.GetViewModelEntity(), "CAMERA_BASE" ) + empVgui.SetRefract( true ) // Force refract resolve before drawing vgui. (This can cost GPU!) + empVgui.SetParent( player ) + empVgui.SetAttachOffsetOrigin( < fovOffset, wide / 2, -tall / 2 > ) + empVgui.SetAttachOffsetAngles( angles ) + + empVgui.GetPanel().WarpEnable() + + local EMPScreenFX = HudElement( "EMPScreenFX", empVgui.GetPanel() ) + local EMPScreenFlash = HudElement( "EMPScreenFlash", empVgui.GetPanel() ) + + OnThreadEnd( + function() : ( player, empVgui ) + { + empVgui.Destroy() + } + ) + + EMPScreenFX.Show() + EMPScreenFX.SetAlpha( maxValue * 255 ) + EMPScreenFX.FadeOverTimeDelayed( 0, fadeTime, duration ) + + if ( doFlash ) + { + EMPScreenFlash.Show() + EMPScreenFlash.SetAlpha( 255 ) + EMPScreenFlash.FadeOverTimeDelayed( 0, fadeTime + duration, 0 ) + } + + if ( doSound ) + { + EmitSoundOnEntity( player, EMP_IMPARED_SOUND ) + wait duration + FadeOutSoundOnEntity( player, EMP_IMPARED_SOUND, fadeTime ) + } + + wait fadeTime +} + + +void function LinkCoreHint( entity soul ) +{ + if ( file.coreHintRui == null ) + return + + RuiTrackFloat( file.coreHintRui, "coreFrac", soul, RUI_TRACK_SCRIPT_NETWORK_VAR, GetNetworkedVariableIndex( "coreAvailableFrac" ) ) +} + + +void function FlashCockpitHealth( vector color ) +{ + if ( file.cockpitRui == null ) + return + + RuiSetGameTime( file.cockpitRui, "startFlashTime", Time() ) + RuiSetFloat3( file.cockpitRui, "flashColor", color ) +} + +void function UpdateHealthSegmentCount() +{ + if ( file.cockpitRui == null ) + return + + entity player = GetLocalViewPlayer() + string playerSettings = player.GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( file.cockpitRui, "numHealthSegments", int( health / healthPerSegment ) ) +} +#if MP +void function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus( entity soul, int oldValue, int newValue, bool actuallyChanged ) +{ + if ( file.cockpitRui == null ) + return + + if ( actuallyChanged == false ) + return + + entity player = GetLocalViewPlayer() + if ( !IsValid( player ) || !player.IsTitan() ) + return + + UpdateHealthSegmentCount() + + string titanName = GetTitanCharacterName( player ) + if ( titanName == "vanguard" ) + { + RuiSetString( file.cockpitRui, "titanInfo1", GetVanguardCoreString( player, 1 ) ) + RuiSetString( file.cockpitRui, "titanInfo2", GetVanguardCoreString( player, 2 ) ) + RuiSetString( file.cockpitRui, "titanInfo3", GetVanguardCoreString( player, 3 ) ) + RuiSetString( file.cockpitRui, "titanInfo4", GetVanguardCoreString( player, 4 ) ) + } +} +#endif + +var function Scorch_CreateHotstreakBar() +{ + Assert( file.scorchHotstreakRui == null ) + + file.scorchHotstreakRui = CreateFixedTitanCockpitRui( $"ui/scorch_hotstreak_bar.rpak" ) + + RuiTrackFloat( file.scorchHotstreakRui, "coreMeterMultiplier", GetLocalViewPlayer(), RUI_TRACK_SCRIPT_NETWORK_VAR, GetNetworkedVariableIndex( "coreMeterModifier" ) ) + + return file.scorchHotstreakRui +} + +void function Scorch_DestroyHotstreakBar() +{ + TitanCockpitDestroyRui( file.scorchHotstreakRui ) + file.scorchHotstreakRui = null +} + +bool function Scorch_ShouldCreateHotstreakBar() +{ + entity player = GetLocalViewPlayer() + + if ( !IsAlive( player ) ) + return false + + array mainWeapons = player.GetMainWeapons() + if ( mainWeapons.len() == 0 ) + return false + + entity primaryWeapon = mainWeapons[0] + return primaryWeapon.HasMod( "fd_hot_streak" ) +} -- cgit v1.2.3 From 74f0ee8b5807e2c46541cdbc3460165200051b07 Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Sat, 12 Nov 2022 14:15:03 +0000 Subject: Add eject quotes (#527) * Upload cl_titan_cockpit.nut * Add eject string in script * Moved to client * index issue + removed else so always returns * Apply suggestions from code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Rest of the suggestions because github makes me want to cry * Commit suggestions from review GitHub really hates batching suggestions Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../scripts/vscripts/client/cl_titan_cockpit.nut | 35 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut index 828f3056..4df1af42 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -36,6 +36,11 @@ global function UpdateEjectHud_SetButtonPressTime global function UpdateEjectHud_SetButtonPressCount global function SetUnlimitedDash + +// Added by northstar +global function AddCommonEjectMessage +global function AddRareEjectMessage + #if MP global function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus global function DisplayFrontierRank @@ -71,6 +76,9 @@ struct bool isFirstBoot = true var scorchHotstreakRui + // Added by northstar + array moddedRareEjectMessages + array moddedCommonEjectMessages } file function ClTitanCockpit_Init() @@ -1007,6 +1015,16 @@ void function PlayerPressed_Eject( entity player ) PlayerEjects( player, cockpit ) } +void function AddCommonEjectMessage( string message ) +{ + file.moddedCommonEjectMessages.append( message ) +} + +void function AddRareEjectMessage( string message ) +{ + file.moddedRareEjectMessages.append( message ) +} + string function RollRandomEjectString() { const int COCKPIT_EJECT_COMMON_COUNT = 6 @@ -1016,14 +1034,19 @@ string function RollRandomEjectString() float randForType = RandomFloat( 1.0 ) if ( randForType < CHANCE_FOR_RARE ) { - int index = RandomInt( COCKPIT_EJECT_RARE_COUNT ) - string result = "#COCKPIT_EJECT_RARE_" + index - return result + int index = RandomInt( COCKPIT_EJECT_RARE_COUNT + file.moddedRareEjectMessages.len() ) + if ( index < COCKPIT_EJECT_RARE_COUNT ) + return "#COCKPIT_EJECT_RARE_" + index + else + return file.moddedRareEjectMessages[index - COCKPIT_EJECT_RARE_COUNT] } - int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT ) - string result = "#COCKPIT_EJECT_COMMON_" + index - return result + int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT + file.moddedCommonEjectMessages.len() ) + if ( index < COCKPIT_EJECT_COMMON_COUNT ) + return "#COCKPIT_EJECT_COMMON_" + index + else + return file.moddedCommonEjectMessages[index - COCKPIT_EJECT_COMMON_COUNT] + } void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal -- cgit v1.2.3 From 17d8f97607f51e75497ed413d0d80f8416a2b3e6 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 14 Nov 2022 22:22:52 +0000 Subject: Add missing `unreachable` to stop compile error (#528) --- Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut | 1 + 1 file changed, 1 insertion(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut index 4df1af42..8261b3fd 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -1047,6 +1047,7 @@ string function RollRandomEjectString() else return file.moddedCommonEjectMessages[index - COCKPIT_EJECT_COMMON_COUNT] + unreachable } void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal -- cgit v1.2.3 From 3f80f07ac14dc210261601e7c59968b5d2c38e2c Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 16 Nov 2022 00:58:23 +0000 Subject: Use new system for adding keybinds to `kb_act.lst` (#529) --- Northstar.Client/kb_act.lst | 13 +++++++ Northstar.Client/mod/scripts/kb_act.lst | 63 --------------------------------- 2 files changed, 13 insertions(+), 63 deletions(-) create mode 100644 Northstar.Client/kb_act.lst delete mode 100644 Northstar.Client/mod/scripts/kb_act.lst (limited to 'Northstar.Client') diff --git a/Northstar.Client/kb_act.lst b/Northstar.Client/kb_act.lst new file mode 100644 index 00000000..1a4f7129 --- /dev/null +++ b/Northstar.Client/kb_act.lst @@ -0,0 +1,13 @@ +"blank" "==========================" +"blank" "NORTHSTAR" +"blank" "==========================" +"toggleconsole" "Toggle Developer Console" +"vote 1" "Vote 1" +"vote 2" "Vote 2" +"vote 3" "Vote 3" +"vote 4" "Vote 4" +"vote 5" "Vote 5" +"vote 6" "Vote 6" +"vote 7" "Vote 7" +"vote 8" "Vote 8" +"vote 9" "Vote 9" diff --git a/Northstar.Client/mod/scripts/kb_act.lst b/Northstar.Client/mod/scripts/kb_act.lst deleted file mode 100644 index 238d7eef..00000000 --- a/Northstar.Client/mod/scripts/kb_act.lst +++ /dev/null @@ -1,63 +0,0 @@ -"blank" "==========================" -"blank" "NORTHSTAR" -"blank" "==========================" -"toggleconsole" "Toggle Developer Console" -"vote 1" "Vote 1" -"vote 2" "Vote 2" -"vote 3" "Vote 3" -"vote 4" "Vote 4" -"vote 5" "Vote 5" -"vote 6" "Vote 6" -"vote 7" "Vote 7" -"vote 8" "Vote 8" -"vote 9" "Vote 9" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_ACTIONS" -"blank" "==========================" -"+attack" "#FIRE" -"+zoom" "#AIM_MODIFIER" -"+toggle_zoom" "#TOGGLE_AIM_MODIFIER" -"+reload" "#RELOAD" -"+weaponCycle" "#SWITCH_WEAPONS_PILOT" -"weaponSelectPrimary0" "#SWITCH_TO_WEAPON1" -"weaponSelectPrimary1" "#SWITCH_TO_WEAPON2" -"weaponSelectPrimary2" "#SWITCH_TO_WEAPON3" -"+melee" "#MELEE" -"+offhand0" "#ORDNANCE_GRENADE" -"+offhand1" "#TACTICAL_ABILITY" -"+offhand2" "#TITAN_UTILITY_BIND" -"+use" "#USE_DISEMBARK" -"+scriptCommand1" "#DISABLE_EJECT_SAFETY_TITAN" -"+ability 1" "#SWITCH_TITAN_AI_MODE_PILOT" -"+ability 6" "#KEYBINDING_MENU_BURN_CARD" -"titan_loadout_select" "#TITAN_LOADOUT_SELECT" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_MOVEMENT" -"blank" "==========================" -"+forward" "#MOVE_FORWARD" -"+back" "#MOVE_BACK" -"+moveleft" "#MOVE_LEFT" -"+moveright" "#MOVE_RIGHT" -"+speed" "#SPRINT" -"+ability 3" "#JUMP_PILOT_DASH_TITAN" -"+duck" "#CROUCH" -"+toggle_duck" "#TOGGLE_CROUCH" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_COMMUNICATION" -"blank" "==========================" -"+pushtotalk" "#PUSH_TO_TALK_KEY" -"say" "#CHAT_MESSAGE" -"say_team" "#TEAM_CHAT_MESSAGE" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_SCOREBOARD" -"blank" "==========================" -"+showscores" "#TOGGLE_SCOREBOARD" -"scoreboard_toggle_focus" "#SCOREBOARD_FOCUS" -"scoreboard_up" "#SCOREBOARD_SCROLL_UP" -"scoreboard_down" "#SCOREBOARD_SCROLL_DOWN" -"scoreboard_profile" "#SCOREBOARD_VIEW_PROFILE" -"scoreboard_mute" "#SCOREBOARD_MUTE" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_MISCELLANEOUS" -"blank" "==========================" -"jpeg" "#SCREENSHOT" -- cgit v1.2.3 From 891c2afe222930d9bd5a0edb6471c9f7d8da2d42 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 1 Dec 2022 20:25:12 +0000 Subject: Remove unnecessary root table setting and make functions global (#534) * fix for CHudChat_ProcessMessageStartThread not working in native * remove unneeded NSSetupChathooksClient callback * fix for CServerGameDLL_ProcessMessageStartThread not working in native * remove unneeded NSSetupChathooksServer callback * remove root table setting for ServerToClientStringCommands_Init * remove unneeded ServerToClientStringCommands_Init callback * remove global function --- Northstar.Client/mod.json | 5 +---- .../mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 9 ++++----- Northstar.CustomServers/mod.json | 10 ++-------- .../mod/scripts/vscripts/_custom_codecallbacks.gnut | 9 ++++----- .../scripts/vscripts/sh_server_to_client_stringcommands.gnut | 7 ------- 5 files changed, 11 insertions(+), 29 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 15853be7..3b236980 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -46,10 +46,7 @@ "Scripts": [ { "Path": "_custom_codecallbacks_client.gnut", - "RunOn": "CLIENT", - "ClientCallback": { - "Before": "NSSetupChathooksClient" - } + "RunOn": "CLIENT" }, { "Path": "client/cl_chat.gnut", diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 3caf4336..811874c5 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -1,7 +1,10 @@ untyped global function AddCallback_OnReceivedSayTextMessage -global function NSSetupChathooksClient + +// this is global due to squirrel bridge v3 making native not be able to find non-global funcs properly +// temp fix (surely it will get replaced), do not use this function please (although there isnt rly a downside to it?) +global function CHudChat_ProcessMessageStartThread global struct ClClient_MessageStruct { string message @@ -135,7 +138,3 @@ void function AddCallback_OnReceivedSayTextMessage( ClClient_MessageStruct funct { NsCustomCallbacksClient.OnReceivedSayTextMessageCallbacks.append(callbackFunc) } - -void function NSSetupChathooksClient() { - getroottable().rawset("CHudChat_ProcessMessageStartThread", CHudChat_ProcessMessageStartThread) -} diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 2ed89910..f67aeb19 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -58,10 +58,7 @@ "Scripts": [ { "Path": "_custom_codecallbacks.gnut", - "RunOn": "SERVER", - "ServerCallback": { - "Before": "NSSetupChathooksServer" - } + "RunOn": "SERVER" }, { "Path": "_northstar_cheatcommands.nut", @@ -104,10 +101,7 @@ }, { "Path": "sh_server_to_client_stringcommands.gnut", - "RunOn": "CLIENT || SERVER", - "ClientCallback": { - "After": "ServerToClientStringCommands_Init" - } + "RunOn": "CLIENT || SERVER" }, { "Path": "gamemodes/_gamemode_fra.nut", diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut index 4a7f8189..ee21116d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut @@ -1,7 +1,10 @@ untyped global function AddCallback_OnReceivedSayTextMessage -global function NSSetupChathooksServer + +// this is global due to squirrel bridge v3 making native not be able to find non-global funcs properly +// temp fix (surely it will get replaced), do not use this function please +global function CServerGameDLL_ProcessMessageStartThread global struct ClServer_MessageStruct { string message @@ -53,7 +56,3 @@ void function AddCallback_OnReceivedSayTextMessage( ClServer_MessageStruct funct { NsCustomCallbacks.OnReceivedSayTextMessageCallbacks.append(callbackFunc) } - -void function NSSetupChathooksServer() { - getroottable().rawset("CServerGameDLL_ProcessMessageStartThread", CServerGameDLL_ProcessMessageStartThread) -} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut index a51e528f..18df6a6f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut @@ -1,6 +1,4 @@ #if CLIENT -global function ServerToClientStringCommands_Init - global function AddServerToClientStringCommandCallback global function NSClientCodeCallback_RecievedServerToClientStringCommand #endif @@ -14,11 +12,6 @@ struct { table< string, array< void functionref( array args ) > > callbacks } file -void function ServerToClientStringCommands_Init() -{ - getroottable().rawset( "NSClientCodeCallback_RecievedServerToClientStringCommand", NSClientCodeCallback_RecievedServerToClientStringCommand ) -} - void function AddServerToClientStringCommandCallback( string command, void functionref( array args ) callback ) { if ( !( command in file.callbacks ) ) -- cgit v1.2.3 From a4606ba8c3c6d816499ab73b6633dd1f33728adb Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 4 Dec 2022 23:04:45 +0100 Subject: Display server region in serverbrowser (#479) * Replace latency column with region in serverbrowser * Add English and German localisation * Mark remaining localisations as TODOs * Enable filtering by region using search field * Update tchinese translation for display server region in serverbrowser (#484) * Add French translation * Add Japanese translation * Add Portuguese translation * Add Russian translation * Add Spanish translation * Add Italian translation * Add Mexican Spanish translation --- .../northstar_client_localisation_english.txt | 2 +- .../northstar_client_localisation_french.txt | 2 +- .../northstar_client_localisation_german.txt | 2 +- .../northstar_client_localisation_italian.txt | 2 +- .../northstar_client_localisation_japanese.txt | 2 +- .../northstar_client_localisation_mspanish.txt | 2 +- .../northstar_client_localisation_portuguese.txt | 2 +- .../northstar_client_localisation_russian.txt | 2 +- .../northstar_client_localisation_spanish.txt | 2 +- .../northstar_client_localisation_tchinese.txt | 2 +- .../mod/resource/ui/menus/server_browser.menu | 70 +++++++++++----------- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 43 ++++++------- 12 files changed, 67 insertions(+), 66 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 3382e5b1..c25708a6 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -276,7 +276,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "PLAYERS_COLUMN" "Players" "MAP_COLUMN" "Map" "GAMEMODE_COLUMN" "Gamemode" - "LATENCY_COLUMN" "Latency" + "REGION_COLUMN" "Region" "SEARCHBAR_LABEL" "Search:" "MAP_FILTER" "Map" "GAMEMODE_FILTER" "Gamemode" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 276698a0..2a199186 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -276,7 +276,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PLAYERS_COLUMN" "Joueurs" "MAP_COLUMN" "Carte" "GAMEMODE_COLUMN" "Mode de jeu" - "LATENCY_COLUMN" "Latence" + "REGION_COLUMN" "Région" "SEARCHBAR_LABEL" "Recherche :" "MAP_FILTER" "Carte" "GAMEMODE_FILTER" "Mode de jeu" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 9077fac0..0316bbcf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -267,7 +267,7 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "PLAYERS_COLUMN" "Spieler" "MAP_COLUMN" "Karte" "GAMEMODE_COLUMN" "Modus" - "LATENCY_COLUMN" "Ping" + "REGION_COLUMN" "Region" "SEARCHBAR_LABEL" "Suche:" "MAP_FILTER" "Karte" "GAMEMODE_FILTER" "Modus" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index b0bc348f..72bf7030 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -275,7 +275,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PLAYERS_COLUMN" "Players" "MAP_COLUMN" "Mappa" "GAMEMODE_COLUMN" "Modalità" - "LATENCY_COLUMN" "Latenza" + "REGION_COLUMN" "Regione" "SEARCHBAR_LABEL" "Cerca:" "MAP_FILTER" "Mappa" "GAMEMODE_FILTER" "Modalità" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index b35c9fb8..b7fadeaf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -303,7 +303,7 @@ "PLAYERS_COLUMN" "プレイヤー" "MAP_COLUMN" "マップ" "GAMEMODE_COLUMN" "ゲームモード" - "LATENCY_COLUMN" "レイテンシー" + "REGION_COLUMN" "領域" "SEARCHBAR_LABEL" "検索:" "MAP_FILTER" "マップ" "GAMEMODE_FILTER" "ゲームモード" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index 208747f9..18634668 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -276,7 +276,7 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "PLAYERS_COLUMN" "Jugadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo de juego" - "LATENCY_COLUMN" "Latencia" + "REGION_COLUMN" "Región" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo de juego" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index d398e557..51854726 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -274,7 +274,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PLAYERS_COLUMN" "Jogadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo" - "LATENCY_COLUMN" "Latência" + "REGION_COLUMN" "Região" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index af9eb0ff..9ce0c2e3 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -219,7 +219,7 @@ "PLAYERS_COLUMN" "Игроки" "MAP_COLUMN" "Карта" "GAMEMODE_COLUMN" "Режим игры" - "LATENCY_COLUMN" "Задержка" + "REGION_COLUMN" "Регион" "SEARCHBAR_LABEL" "Поиск:" "MAP_FILTER" "Карта" "GAMEMODE_FILTER" "Режим игры" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index fa732b63..0dc82570 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -276,7 +276,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PLAYERS_COLUMN" "Jugadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo de juego" - "LATENCY_COLUMN" "Latencia" + "REGION_COLUMN" "Región" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo de juego" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 276a192d..12b6cad1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -276,7 +276,7 @@ "PLAYERS_COLUMN" "玩家" "MAP_COLUMN" "地圖" "GAMEMODE_COLUMN" "遊戲模式" - "LATENCY_COLUMN" "延遲" + "REGION_COLUMN" "地區" "SEARCHBAR_LABEL" "搜尋:" "MAP_FILTER" "地圖" "GAMEMODE_FILTER" "遊戲模式" diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index d25d1219..b66fb8a6 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -1178,7 +1178,7 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner TOP_RIGHT navDown BtnServer1 navLeft BtnServerMapTab - navRight BtnServerLatencyTab + navRight BtnServerRegionTab navUp BtnFiltersClear } @@ -1408,12 +1408,12 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner BOTTOM_LEFT } - // Latency - BtnServerLatencyTab + // Region + BtnServerRegionTab { ControlName RuiButton InheritProperties RuiSmallButton - labelText "#LATENCY_COLUMN" + labelText "#REGION_COLUMN" wide 110 xpos 4 @@ -1428,11 +1428,11 @@ resource/ui/menus/mods_browse.menu navUp BtnFiltersClear } - BtnServerLatency1 + BtnServerRegion1 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1443,11 +1443,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency2 + BtnServerRegion2 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1458,11 +1458,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency3 + BtnServerRegion3 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1473,11 +1473,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency4 + BtnServerRegion4 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1488,11 +1488,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency5 + BtnServerRegion5 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1503,11 +1503,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency6 + BtnServerRegion6 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1518,11 +1518,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency7 + BtnServerRegion7 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1533,11 +1533,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency8 + BtnServerRegion8 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1548,11 +1548,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency9 + BtnServerRegion9 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1563,11 +1563,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency10 + BtnServerRegion10 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1578,11 +1578,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency11 + BtnServerRegion11 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1593,11 +1593,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency12 + BtnServerRegion12 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1608,11 +1608,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency13 + BtnServerRegion13 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1623,11 +1623,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency14 + BtnServerRegion14 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1638,11 +1638,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency15 + BtnServerRegion15 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1737,7 +1737,7 @@ resource/ui/menus/mods_browse.menu xpos 3 ypos -1 - pin_to_sibling BtnServerLatencyTab + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner TOP_LEFT } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index d9b11ccc..03028255 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -38,7 +38,7 @@ enum sortingBy PLAYERS, MAP, GAMEMODE, - LATENCY + REGION } // Column sort direction, only one of these can be aplied at once @@ -48,8 +48,8 @@ struct { bool serverPlayers = true bool serverMap = true bool serverGamemode = true - bool serverLatency = true - // 0 = none; 1 = default; 2 = name; 3 = players; 4 = map; 5 = gamemode; 6 = latency + bool serverRegion = true + // 0 = none; 1 = default; 2 = name; 3 = players; 4 = map; 5 = gamemode; 6 = region int sortingBy = 1 } filterDirection @@ -61,7 +61,7 @@ struct serverStruct { int serverPlayersMax string serverMap string serverGamemode - int serverLatency + string serverRegion } struct { @@ -87,7 +87,7 @@ struct { array serversProtected array serversMap array serversGamemode - array serversLatency + array serversRegion } file @@ -151,7 +151,7 @@ void function InitServerBrowserMenu() file.serversProtected = GetElementsByClassname( file.menu, "ServerLock" ) file.serversMap = GetElementsByClassname( file.menu, "ServerMap" ) file.serversGamemode = GetElementsByClassname( file.menu, "ServerGamemode" ) - file.serversLatency = GetElementsByClassname( file.menu, "ServerLatency" ) + file.serversRegion = GetElementsByClassname( file.menu, "Serverregion" ) filterArguments.filterMaps = [ "SWITCH_ANY" ] Hud_DialogList_AddListItem( Hud_GetChild( file.menu, "SwtBtnSelectMap" ), "SWITCH_ANY", "0" ) @@ -194,7 +194,7 @@ void function InitServerBrowserMenu() AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerPlayersTab"), UIE_CLICK, SortServerListByPlayers_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerMapTab"), UIE_CLICK, SortServerListByMap_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerGamemodeTab"), UIE_CLICK, SortServerListByGamemode_Activate ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerLatencyTab"), UIE_CLICK, SortServerListByLatency_Activate ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerRegionTab"), UIE_CLICK, SortServerListByRegion_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnSelectMap"), UIE_CHANGE, FilterAndUpdateList ) @@ -218,8 +218,6 @@ void function InitServerBrowserMenu() Hud_SetText( Hud_GetChild( file.menu, "BtnServerDescription"), "" ) Hud_SetText( Hud_GetChild( file.menu, "BtnServerMods"), "" ) - // Unfinished features - Hud_SetLocked( Hud_GetChild( file.menu, "BtnServerLatencyTab" ), true ) // Rui is a pain RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnHideFull") ), "buttonText", "" ) @@ -675,9 +673,9 @@ void function FilterAndUpdateList( var n ) filterDirection.serverGamemode = !filterDirection.serverGamemode SortServerListByGamemode_Activate(0) break - case sortingBy.LATENCY: - filterDirection.serverLatency = !filterDirection.serverLatency - SortServerListByLatency_Activate(0) + case sortingBy.REGION: + filterDirection.serverRegion = !filterDirection.serverRegion + SortServerListByRegion_Activate(0) break default: printt( "How the f did you get here" ) @@ -715,7 +713,7 @@ void function WaitForServerListRequest() Hud_SetText( file.playerCountLabels[ i ], "" ) Hud_SetText( file.serversMap[ i ], "" ) Hud_SetText( file.serversGamemode[ i ], "" ) - Hud_SetText( file.serversLatency[ i ], "" ) + Hud_SetText( file.serversRegion[ i ], "" ) } HideServerInfo() @@ -756,6 +754,7 @@ void function FilterServerList() tempServer.serverPlayersMax = NSGetServerMaxPlayerCount( i ) tempServer.serverMap = NSGetServerMap( i ) tempServer.serverGamemode = GetGameModeDisplayName( NSGetServerPlaylist ( i ) ) + tempServer.serverRegion = NSGetServerRegion( i ) totalPlayers += tempServer.serverPlayers @@ -786,6 +785,7 @@ void function FilterServerList() sName.append( tempServer.serverGamemode.tolower() ) sName.append( Localize( tempServer.serverGamemode ).tolower() ) sName.append( NSGetServerDescription( i ).tolower() ) + sName.append( NSGetServerRegion( i ).tolower() ) string sTerm = filterArguments.searchTerm.tolower() @@ -821,7 +821,7 @@ void function UpdateShownPage() Hud_SetText( file.playerCountLabels[ i ], "" ) Hud_SetText( file.serversMap[ i ], "" ) Hud_SetText( file.serversGamemode[ i ], "" ) - Hud_SetText( file.serversLatency[ i ], "" ) + Hud_SetText( file.serversRegion[ i ], "" ) } int j = file.serversArrayFiltered.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.serversArrayFiltered.len() @@ -840,6 +840,7 @@ void function UpdateShownPage() Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", file.serversArrayFiltered[ buttonIndex ].serverPlayers, file.serversArrayFiltered[ buttonIndex ].serverPlayersMax ) ) Hud_SetText( file.serversMap[ i ], GetMapDisplayName( file.serversArrayFiltered[ buttonIndex ].serverMap ) ) Hud_SetText( file.serversGamemode[ i ], file.serversArrayFiltered[ buttonIndex ].serverGamemode ) + Hud_SetText( file.serversRegion[ i ], file.serversArrayFiltered[ buttonIndex ].serverRegion ) } @@ -1161,10 +1162,10 @@ int function ServerSortLogic ( serverStruct a, serverStruct b ) bTemp = Localize( b.serverGamemode ).tolower() direction = filterDirection.serverGamemode break; - case sortingBy.LATENCY: - aTemp = a.serverLatency - bTemp = b.serverLatency - direction = filterDirection.serverLatency + case sortingBy.REGION: + aTemp = a.serverRegion + bTemp = b.serverRegion + direction = filterDirection.serverRegion break; default: return 0 @@ -1238,13 +1239,13 @@ void function SortServerListByGamemode_Activate( var button ) UpdateShownPage() } -void function SortServerListByLatency_Activate( var button ) +void function SortServerListByRegion_Activate( var button ) { - filterDirection.sortingBy = sortingBy.LATENCY + filterDirection.sortingBy = sortingBy.REGION file.serversArrayFiltered.sort( ServerSortLogic ) - filterDirection.serverLatency = !filterDirection.serverLatency + filterDirection.serverRegion = !filterDirection.serverRegion UpdateShownPage() } -- cgit v1.2.3 From 27e000e3feb3741c91708ea47c92ec95d9f3d4d1 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Tue, 3 Jan 2023 00:27:15 +0100 Subject: Move region column to the left (#553) --- .../mod/resource/ui/menus/server_browser.menu | 900 ++++++++++----------- 1 file changed, 450 insertions(+), 450 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index b66fb8a6..48cddd73 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -143,7 +143,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -462 + xpos -422 zpos 101 //fgcolor_override "107 166 196 255" @@ -159,7 +159,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -462 + xpos -422 zpos 100 rui "ui/control_options_description.rpak" @@ -419,6 +419,252 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } + + // Region + BtnServerRegionTab + { + ControlName RuiButton + InheritProperties RuiSmallButton + labelText "#REGION_COLUMN" + wide 110 + xpos -4 + ypos -1 + + scriptID 999 + + pin_to_sibling BtnServerPasswordProtectedTab + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_RIGHT + navDown BtnServer1 + navRight BtnServerNameTab + navUp BtnFiltersClear + } + + BtnServerRegion1 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer1 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion2 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer2 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion3 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer3 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion4 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer4 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion5 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer5 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion6 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer6 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion7 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer7 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion8 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer8 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion9 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer9 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion10 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer10 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion11 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer11 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion12 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer12 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion13 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer13 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion14 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer14 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion15 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer15 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } // Name BtnServerNameTab @@ -427,16 +673,16 @@ resource/ui/menus/mods_browse.menu InheritProperties RuiSmallButton labelText "#SERVERS_COLUMN" wide 600 - xpos -4 - ypos -1 + xpos 4 scriptID 999 - pin_to_sibling BtnServerPasswordProtectedTab + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner TOP_RIGHT navUp BtnFiltersClear navDown BtnServer1 + navLeft BtnServerRegionTab navRight BtnServerPlayersTab } @@ -448,8 +694,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 interactive false @@ -465,8 +711,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -480,8 +726,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -495,8 +741,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -510,8 +756,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -525,8 +771,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -540,8 +786,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -555,8 +801,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -570,8 +816,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -585,8 +831,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -600,8 +846,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -615,8 +861,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -630,8 +876,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -645,8 +891,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -660,8 +906,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -697,8 +943,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -712,8 +958,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -727,8 +973,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -742,8 +988,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -757,8 +1003,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -772,8 +1018,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -787,8 +1033,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -802,8 +1048,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -817,8 +1063,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -832,8 +1078,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -847,8 +1093,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -862,8 +1108,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -877,8 +1123,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -892,8 +1138,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -907,8 +1153,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -944,8 +1190,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -959,8 +1205,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -974,8 +1220,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -989,8 +1235,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -1004,8 +1250,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -1019,8 +1265,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -1034,8 +1280,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -1049,8 +1295,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -1064,8 +1310,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -1079,8 +1325,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -1094,8 +1340,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -1109,8 +1355,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -1124,8 +1370,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -1139,8 +1385,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -1154,8 +1400,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -1178,7 +1424,7 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner TOP_RIGHT navDown BtnServer1 navLeft BtnServerMapTab - navRight BtnServerRegionTab + navRight BtnServerJoin navUp BtnFiltersClear } @@ -1190,8 +1436,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -1205,8 +1451,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -1220,8 +1466,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -1235,8 +1481,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -1250,8 +1496,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -1265,8 +1511,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -1280,8 +1526,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -1295,8 +1541,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -1310,8 +1556,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -1325,8 +1571,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -1340,8 +1586,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -1355,8 +1601,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -1370,8 +1616,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -1385,8 +1631,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -1400,366 +1646,120 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - // Region - BtnServerRegionTab - { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#REGION_COLUMN" - wide 110 - xpos 4 - - scriptID 999 - - pin_to_sibling BtnServerGamemodeTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_RIGHT - navDown BtnServer1 - navLeft BtnServerGamemodeTab - navRight BtnServerJoin - navUp BtnFiltersClear - } - - BtnServerRegion1 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer1 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion2 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer2 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion3 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer3 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion4 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + // Dividers: - pin_to_sibling BtnServer4 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion5 + // Y + YDivider0 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer5 + pin_to_sibling BtnServerNameTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion6 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer6 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion7 + YDivider1 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer7 + pin_to_sibling BtnServerPlayersTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion8 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer8 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion9 + YDivider2 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer9 + pin_to_sibling BtnServerMapTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion10 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer10 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion11 + YDivider3 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer11 + pin_to_sibling BtnServerGamemodeTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion12 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer12 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion13 + YDivider4 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer13 + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion14 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer14 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion15 + // X + XDivider0 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 1150 + tall 2 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + ypos 3 + xpos 37 - pin_to_sibling BtnServer15 - pin_corner_to_sibling TOP_LEFT + pin_to_sibling BtnServerRegionTab + pin_corner_to_sibling BOTTOM_LEFT pin_to_sibling_corner BOTTOM_LEFT } - // Dividers: - - // Y - YDivider0 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerNameTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider1 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerPlayersTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider2 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerMapTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider3 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerGamemodeTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider4 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerRegionTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - // X - XDivider0 - { - ControlName ImagePanel - wide 1150 - tall 2 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - ypos 3 - xpos 37 - - pin_to_sibling BtnServerNameTab - pin_corner_to_sibling BOTTOM_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - // List: BtnServerDummmyTop { ControlName RuiButton @@ -2082,7 +2082,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 zpos 0 image "vgui/hud/white" @@ -2099,7 +2099,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 rui "ui/control_options_description.rpak" @@ -2120,7 +2120,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 zpos 1 pin_to_sibling ServerDetailsPanel -- cgit v1.2.3 From 92a3d6c0d00e2d4cb8a320ee47870beb407110b3 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Wed, 4 Jan 2023 02:50:11 +0100 Subject: Fix connecting UI (#560) Fixes misaligned buttons when showing server connecting pop up --- Northstar.Client/mod/resource/ui/menus/server_browser.menu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index 48cddd73..4a84a714 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -143,7 +143,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -422 + xpos -462 zpos 101 //fgcolor_override "107 166 196 255" @@ -159,7 +159,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -422 + xpos -462 zpos 100 rui "ui/control_options_description.rpak" -- cgit v1.2.3 From 26e49bdf49689f64453a398a3a76f7e44946e20c Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Sun, 8 Jan 2023 02:40:10 +0100 Subject: Fix server chat messages being send twice when watching a replay (#555) * fixes chat messages being send twice * OCD is a real issue --- .../mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 811874c5..277ed030 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -22,6 +22,10 @@ struct { } NsCustomCallbacksClient void function OnReceivedMessage(ClClient_MessageStruct localMessage) { + + if ( IsWatchingReplay() ) + return + if (localMessage.player != null) { foreach (callbackFunc in NsCustomCallbacksClient.OnReceivedSayTextMessageCallbacks) -- cgit v1.2.3 From 554761ab629418048e367c7ba1504acd87b5b6e1 Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Sat, 25 Feb 2023 22:52:08 +0100 Subject: Fix chat messages when dead (#574) * Fix chat messages when dead * Spoons fix was better Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 277ed030..db4865ee 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -23,7 +23,7 @@ struct { void function OnReceivedMessage(ClClient_MessageStruct localMessage) { - if ( IsWatchingReplay() ) + if ( IsWatchingReplay() && localMessage.player == null ) return if (localMessage.player != null) -- cgit v1.2.3 From 2376c5339776d8ef6cb6e0f60d8fcf5a61ef2885 Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 8 Mar 2023 02:08:35 +0100 Subject: Add _menus.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/_menus.nut | 2002 ++++++++++++++++++++ 1 file changed, 2002 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/_menus.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut new file mode 100644 index 00000000..90a535ee --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut @@ -0,0 +1,2002 @@ +untyped + +global const bool EDIT_LOADOUT_SELECTS = true +global const string PURCHASE_SUCCESS_SOUND = "UI_Menu_Store_Purchase_Success" + +global function UICodeCallback_CloseAllMenus +global function UICodeCallback_ActivateMenus +global function UICodeCallback_LevelInit +global function UICodeCallback_LevelLoadingStarted +global function UICodeCallback_LevelLoadingFinished +global function UICodeCallback_LevelShutdown +global function UICodeCallback_OnConnected +global function UICodeCallback_OnFocusChanged +global function UICodeCallback_NavigateBack +global function UICodeCallback_ToggleInGameMenu +global function UICodeCallback_TryCloseDialog +global function UICodeCallback_UpdateLoadingLevelName +global function UICodeCallback_ConsoleKeyboardClosed +global function UICodeCallback_ErrorDialog +global function UICodeCallback_AcceptInvite +global function UICodeCallback_OnDetenteDisplayed +global function UICodeCallback_OnSpLogDisplayed +global function UICodeCallback_EntitlementsChanged +global function UICodeCallback_StoreTransactionCompleted +global function UICodeCallback_GamePurchased +global function UICodeCallback_PartyUpdated +global function UICodeCallback_KeyBindOverwritten + +global function AdvanceMenu +global function OpenSubmenu // REMOVE +global function CloseSubmenu // REMOVE +global function CloseActiveMenu +global function CloseActiveMenuNoParms +global function CloseAllMenus +global function CloseAllInGameMenus +global function CloseAllDialogs +global function CloseAllToTargetMenu +global function PrintMenuStack +global function CleanupInGameMenus +global function GetActiveMenu +global function GetMenu +global function GetPanel +global function GetAllMenuPanels +global function InitGamepadConfigs +global function InitMenus +global function AdvanceMenuEventHandler +global function PCSwitchTeamsButton_Activate +global function PCToggleSpectateButton_Activate +global function AddMenuElementsByClassname +global function FocusDefault +global function SetPanelDefaultFocus +global function PanelFocusDefault +global function OpenMenuWrapper +global function CloseMenuWrapper +global function IsLevelMultiplayer +global function AddMenuEventHandler +global function AddPanelEventHandler +global function AddButtonEventHandler +global function AddEventHandlerToButton +global function AddEventHandlerToButtonClass +global function DisableMusic +global function EnableMusic +global function PlayMusic +global function StopMusic +global function IsMenuInMenuStack +global function GetTopNonDialogMenu +global function IsDialog +global function IsDialogActive +global function IsDialogOnlyActiveMenu +global function SetNavUpDown +global function SetNavLeftRight +global function IsTrialPeriodActive +global function LaunchGamePurchaseOrDLCStore +global function SetMenuThinkFunc + +global function PCBackButton_Activate + +global function RegisterMenuVarInt +global function GetMenuVarInt +global function SetMenuVarInt +global function RegisterMenuVarBool +global function GetMenuVarBool +global function SetMenuVarBool +global function RegisterMenuVarVar +global function GetMenuVarVar +global function SetMenuVarVar +global function AddMenuVarChangeHandler + +global function InviteFriends + +global function HACK_DelayedSetFocus_BecauseWhy + +#if DURANGO_PROG + global function OpenXboxPartyApp + global function OpenXboxHelp +#endif // DURANGO_PROG + +global function OpenReviewTermsDialog +global function ClassicMusic_OnChange +global function IsClassicMusicAvailable + + +void function UICodeCallback_CloseAllMenus() +{ + printt( "UICodeCallback_CloseAllMenus" ) + CloseAllMenus() + // This is usually followed by a call to UICodeCallback_ActivateMenus(). +} + +// Bringing up the console will cause this, and it probably shouldn't +void function UICodeCallback_ActivateMenus() +{ + if ( IsConnected() ) + return + + printt( "UICodeCallback_ActivateMenus:", uiGlobal.activeMenu && Hud_GetHudName( uiGlobal.activeMenu ) ) + + if ( uiGlobal.menuStack.len() == 0 ) + { + AdvanceMenu( GetMenu( "MainMenu" ) ) + } + + if ( uiGlobal.activeMenu == GetMenu( "MainMenu" ) ) + Signal( uiGlobal.signalDummy, "OpenErrorDialog" ) + + PlayMusic() + + #if DURANGO_PROG + Durango_LeaveParty() + #endif // DURANGO_PROG +} + +void function UICodeCallback_ToggleInGameMenu() +{ + if ( !IsFullyConnected() ) + return + + var activeMenu = uiGlobal.activeMenu + bool isMP = IsLevelMultiplayer( GetActiveLevel() ) + bool isLobby = IsLobby() + + var ingameMenu + if ( isMP ) + { + ingameMenu = GetMenu( "InGameMPMenu" ) + } + else + { + // Disable this callback for this special case menu so players can't skip it. + var spTitanTutorialMenu = GetMenu( "SPTitanLoadoutTutorialMenu" ) + if ( activeMenu == spTitanTutorialMenu ) + return + + ingameMenu = GetMenu( "InGameSPMenu" ) + } + + if ( IsDialog( uiGlobal.activeMenu ) ) + { + // Do nothing if a dialog is showing + } + else if ( TeamTitanSelectMenuIsOpen() ) + { + if ( uiGlobal.activeMenu == GetMenu( "TeamTitanSelectMenu" ) ) + { + // Do nothing here either + } + else + { + CloseActiveMenu() + } + } + else if ( ( isMP && !isLobby ) || !isMP ) + { + if ( !activeMenu ) + AdvanceMenu( ingameMenu ) + else + CloseAllInGameMenus() + } +} + +// Return true to show load screen, false to not show load screen. +// levelname can be "" because the level to load isn't always known when the load screen starts +bool function UICodeCallback_LevelLoadingStarted( string levelname ) +{ + printt( "UICodeCallback_LevelLoadingStarted: " + levelname ) + + CloseAllDialogs() + + uiGlobal.loadingLevel = levelname + + StopMusic() + + if ( uiGlobal.playingVideo ) + Signal( uiGlobal.signalDummy, "PlayVideoEnded" ) + + if ( uiGlobal.playingCredits ) + Signal( uiGlobal.signalDummy, "PlayingCreditsDone" ) + + // kill lingering postgame summary since persistent data may not be available at this point + Signal( uiGlobal.signalDummy, "PGDisplay" ) + +#if CONSOLE_PROG + if ( !Console_IsSignedIn() ) + return false +#endif + + return true +} + +// Return true to show load screen, false to not show load screen. +bool function UICodeCallback_UpdateLoadingLevelName( string levelname ) +{ + printt( "UICodeCallback_UpdateLoadingLevelName: " + levelname ) + +#if CONSOLE_PROG + if ( !Console_IsSignedIn() ) + return false +#endif + + return true +} + +void function UICodeCallback_LevelLoadingFinished( bool error ) +{ + printt( "UICodeCallback_LevelLoadingFinished: " + uiGlobal.loadingLevel + " (" + error + ")" ) + + if ( !IsLobby() ) + { + HudChat_ClearTextFromAllChatPanels() + ResetActiveChatroomLastModified() + } + else + { + uiGlobal.lobbyFromLoadingScreen = true + } + + uiGlobal.loadingLevel = "" + Signal( uiGlobal.signalDummy, "LevelFinishedLoading" ) +} + +void function UICodeCallback_LevelInit( string levelname ) +{ + Assert( IsConnected() ) + + StopVideo() + + uiGlobal.loadedLevel = levelname + + printt( "UICodeCallback_LevelInit: " + uiGlobal.loadedLevel ) + + if ( !uiGlobal.loadoutsInitialized ) + { + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString != "solo" ) + { + InitStatsTables() + } + } + + InitItems() + + if ( IsMultiplayer() ) + { + ShWeaponXP_Init() + ShTitanXP_Init() + ShFactionXP_Init() + } + else + { + SPObjectiveStringsInit() + } + + #if DEV + UpdatePrecachedSPWeapons() + #endif + + + if ( !uiGlobal.loadoutsInitialized ) + { + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString != "solo" ) + { + DeathHints_Init() + InitDefaultLoadouts() + CreateChallenges() + uiGlobal.loadoutsInitialized = true + } + } + + if ( IsLevelMultiplayer( levelname ) || IsLobbyMapName( levelname ) ) + { + thread UpdateCachedLoadouts() + thread UpdateCachedNewItems() + thread InitUISpawnLoadoutIndexes() + + if ( !uiGlobal.eventHandlersAdded ) + { + uiGlobal.eventHandlersAdded = true + } + + UI_GetAllChallengesProgress() + + bool isLobby = IsLobbyMapName( levelname ) + + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString == "" ) + gameModeString = "" + + Assert( gameModeString == GetConVarString( "mp_gamemode" ) ) + Assert( gameModeString != "" ) + + int gameModeId = GameMode_GetGameModeId( gameModeString ) + + int mapId = eMaps.invalid + if ( levelname in getconsttable().eMaps ) + { + mapId = expect int( getconsttable().eMaps[ levelname ] ) + } + else + { + // Don't worry about this until we have to consider R2 Durango TCRs (10/2015) + //if ( !IsTestMap() ) + // CodeWarning( "No map named '" + levelname + "' exists in eMaps, all shipping maps should be in this enum" ) + } + + int difficultyLevelId = 0 + int roundId = 0 + + if ( isLobby ) + Durango_OnLobbySessionStart( gameModeId, difficultyLevelId ) + else + Durango_OnMultiplayerRoundStart( gameModeId, mapId, difficultyLevelId, roundId, 0 ) + } + else + { + // SP loadout stuff + UI_GetAllChallengesProgress() // TODO: Can this be moved so we don't call it twice? It's called above. + + SP_ResetObjectiveStringIndex() // Since this persists thru level load, we need to explicitely clear it. + } + + if ( IsMultiplayer() ) + { + foreach ( callbackFunc in uiGlobal.onLevelInitCallbacks ) + { + thread callbackFunc() + } + + } + thread UpdateMenusOnConnect( levelname ) + + uiGlobal.previousLevel = uiGlobal.loadedLevel + uiGlobal.previousPlaylist = GetCurrentPlaylistName() +} + +void function UICodeCallback_LevelShutdown() +{ + Signal( uiGlobal.signalDummy, "LevelShutdown" ) + + printt( "UICodeCallback_LevelShutdown: " + uiGlobal.loadedLevel ) + + StopVideo() + + if ( uiGlobal.loadedLevel != "" ) + CleanupInGameMenus() + + uiGlobal.loadedLevel = "" + uiGlobal.mapSupportsMenuModelsUpdated = false + uiGlobal.sp_showAlternateMissionLog = false +} + +void function UICodeCallback_NavigateBack() +{ + if ( uiGlobal.activeMenu == null ) + return + + if ( IsDialog( uiGlobal.activeMenu ) ) + { + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.noChoice || + uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.forceChoice || + Time() < uiGlobal.dialogInputEnableTime ) + return + } + + Assert( uiGlobal.activeMenu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].navBackFunc != null ) + { + thread uiGlobal.menuData[ uiGlobal.activeMenu ].navBackFunc() + return + } + + if ( uiGlobal.activeMenu.GetType() == "submenu" ) // REMOVE + { + CloseSubmenu() + return + } + + CloseActiveMenu( true ) +} + +// Called when IsConnected() will start returning true. +void function UICodeCallback_OnConnected() +{ + +} + +void function UICodeCallback_OnFocusChanged( var oldFocusedPanel, var newFocusedPanel ) +{ + +} + +// Accepting an origin invite closes dialogs, or aborts if they can't be closed +bool function UICodeCallback_TryCloseDialog() +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return true + + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.forceChoice ) + return false + + CloseAllDialogs() + Assert( !IsDialog( uiGlobal.activeMenu ) ) + return true +} + +void function UICodeCallback_ConsoleKeyboardClosed() +{ + switch ( uiGlobal.activeMenu ) + { + case GetMenu( "EditPilotLoadoutMenu" ): + string oldName = GetPilotLoadoutName( GetCachedPilotLoadout( uiGlobal.editingLoadoutIndex ) ) + string newName = GetPilotLoadoutRenameText() + + // strip doesn't work on UTF-8 strings + // newName = strip( newName ) // Remove leading/trailing whitespace + if ( newName == "" ) // If all whitespace entered reset to previous name + newName = oldName + + SetPilotLoadoutName( newName ) + SelectPilotLoadoutRenameText() + if ( newName != oldName ) + EmitUISound( "Menu.Accept" ) // No callback when cancelled so for now assume name was changed + break + + default: + break + } +} + +void function UICodeCallback_OnDetenteDisplayed() +{ +// thread PlayDetentSound() +//} +// +//void function PlayDetentSound() +//{ +// WaitFrame() // otherwise gets killed off by code pause +// WaitFrame() // otherwise gets killed off by code pause +// EmitUISound( "Pilot_Killed_Indicator" ) +} + +void function UICodeCallback_OnSpLogDisplayed() +{ +} + +void function UICodeCallback_ErrorDialog( string errorDetails ) +{ + printt( "UICodeCallback_ErrorDialog: " + errorDetails ) + thread OpenErrorDialog( errorDetails ) +} + +void function UICodeCallback_AcceptInviteThread( string accesstoken ) +{ + printt( "UICodeCallback_AcceptInviteThread '" + accesstoken + "'") + + #if PS4_PROG + if ( !Ps4_PSN_Is_Loggedin() ) + { + Ps4_LoginDialog_Schedule(); + while( Ps4_LoginDialog_Running() ) + WaitFrame() + if ( !Ps4_PSN_Is_Loggedin() ) + return; + } + + if( Ps4_CheckPlus_Schedule() ) + { + while( Ps4_CheckPlus_Running() ) + WaitFrame() + if( !Ps4_CheckPlus_Allowed() ) + { + if( Ps4_CheckPlus_GetLastRequestResults() != 0 ) + { + return + } + + if( Ps4_ScreenPlusDialog_Schedule() ) + { + while( Ps4_ScreenPlusDialog_Running() ) + WaitFrame() + if( !Ps4_ScreenPlusDialog_Allowed() ) + return; + } + else + { + return; + } + } + } + + #endif // #if PS4_PROG + + SubscribeToChatroomPartyChannel( accesstoken ); + +} + + +void function UICodeCallback_AcceptInvite( string accesstoken ) +{ + printt( "UICodeCallback_AcceptInvite '" + accesstoken + "'") + thread UICodeCallback_AcceptInviteThread( accesstoken ) +} + +// TODO: replaceCurrent should not be an option. It should be a different function. +void function AdvanceMenu( var menu, bool replaceCurrent = false ) +{ + //foreach ( index, menu in uiGlobal.menuStack ) + //{ + // if ( menu != null ) + // printt( "menu index " + index + " is named " + menu.GetDisplayName() ) + //} + + if ( uiGlobal.activeMenu ) + { + // Don't open the same menu again if it's already open + if ( uiGlobal.activeMenu == menu ) + return + + // Opening a normal menu while a dialog is open + Assert( !IsDialog( uiGlobal.activeMenu ), "Tried opening menu: " + Hud_GetHudName( menu ) + " when uiGlobal.activeMenu was: " + Hud_GetHudName( uiGlobal.activeMenu ) ) + } + + if ( uiGlobal.activeMenu && !IsDialog( menu ) ) // Dialogs show on top so don't close existing menu when opening them + { + SetBlurEnabled( false ) + + if ( replaceCurrent ) + { + CloseMenuWrapper( uiGlobal.activeMenu ) + uiGlobal.menuStack.pop() + } + else + { + CloseMenu( uiGlobal.activeMenu ) + printt( Hud_GetHudName( uiGlobal.activeMenu ), "menu closed" ) + } + } + + if ( IsDialog( menu ) && uiGlobal.activeMenu ) + SetFooterPanelVisibility( uiGlobal.activeMenu, false ) + + uiGlobal.menuStack.push( menu ) + uiGlobal.activeMenu = menu + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + if ( uiGlobal.activeMenu ) + { + if ( !IsLobby() && !uiGlobal.mapSupportsMenuModels ) + SetBlurEnabled( true ) + + OpenMenuWrapper( uiGlobal.activeMenu, true ) + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function SetFooterPanelVisibility( var menu, bool visible ) +{ + if ( !Hud_HasChild( menu, "FooterButtons" ) ) + return + + var panel = Hud_GetChild( menu, "FooterButtons" ) + Hud_SetVisible( panel, visible ) +} + +void function OpenSubmenu( var menu, bool updateMenuPos = true ) +{ + Assert( menu ) + Assert( menu.GetType() == "submenu" ) + + if ( uiGlobal.activeMenu ) + { + // Don't open the same menu again if it's already open + if ( uiGlobal.activeMenu == menu ) + return + } + + local submenuPos = Hud_GetAbsPos( GetFocus() ) + + uiGlobal.menuStack.push( menu ) + uiGlobal.activeMenu = menu + + OpenMenuWrapper( uiGlobal.activeMenu, true ) + + if ( updateMenuPos ) + { + var vguiButtonFrame = Hud_GetChild( uiGlobal.activeMenu, "ButtonFrame" ) + Hud_SetPos( vguiButtonFrame, submenuPos[0], submenuPos[1] ) + } + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseSubmenu( bool openStackMenu = true ) +{ + if ( !uiGlobal.activeMenu ) + return + + if ( uiGlobal.activeMenu.GetType() != "submenu" ) + return + + CloseMenuWrapper( uiGlobal.activeMenu ) + uiGlobal.menuStack.pop() + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + if ( uiGlobal.menuStack.len() ) + { + uiGlobal.activeMenu = uiGlobal.menuStack.top() + + // This runs any OnOpen function for the menu and sets focus, but doesn't actually open the menu because it is already open + if ( openStackMenu ) + OpenMenuWrapper( uiGlobal.activeMenu, false ) + } + else + { + uiGlobal.activeMenu = null + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseActiveMenuNoParms() +{ + CloseActiveMenu() +} + +void function CloseActiveMenu( bool cancelled = false, bool openStackMenu = true ) +{ + bool updateBlur = true + bool wasDialog = false + + if ( uiGlobal.activeMenu ) + { + if ( IsDialog( uiGlobal.activeMenu ) ) + { + updateBlur = false + wasDialog = true + uiGlobal.dialogInputEnableTime = 0.0 + + if ( uiGlobal.dialogCloseCallback ) + { + uiGlobal.dialogCloseCallback( cancelled ) + uiGlobal.dialogCloseCallback = null + } + } + + if ( updateBlur ) + SetBlurEnabled( false ) + + CloseMenuWrapper( uiGlobal.activeMenu ) + } + + uiGlobal.menuStack.pop() + if ( uiGlobal.menuStack.len() ) + uiGlobal.activeMenu = uiGlobal.menuStack.top() + else + uiGlobal.activeMenu = null + + uiGlobal.lastMenuNavDirection = MENU_NAV_BACK + + if ( wasDialog ) + { + if ( uiGlobal.activeMenu ) + SetFooterPanelVisibility( uiGlobal.activeMenu, true ) + + if ( IsDialog( uiGlobal.activeMenu ) ) + openStackMenu = true + else + openStackMenu = false + } + + if ( uiGlobal.activeMenu ) + { + if ( uiGlobal.activeMenu.GetType() == "submenu" ) + { + Hud_SetFocused( uiGlobal.menuData[ uiGlobal.activeMenu ].lastFocus ) + } + else if ( openStackMenu ) + { + OpenMenuWrapper( uiGlobal.activeMenu, false ) + + if ( updateBlur && !IsLobby() && !uiGlobal.mapSupportsMenuModels ) + SetBlurEnabled( true ) + } + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseAllMenus() +{ + if ( IsDialog( uiGlobal.activeMenu ) ) + CloseActiveMenu( true ) + + if ( uiGlobal.activeMenu && uiGlobal.activeMenu.GetType() == "submenu" ) + CloseSubmenu( false ) + + if ( uiGlobal.activeMenu ) + { + SetBlurEnabled( false ) + CloseMenuWrapper( uiGlobal.activeMenu ) + } + + uiGlobal.menuStack = [] + uiGlobal.activeMenu = null + + uiGlobal.lastMenuNavDirection = MENU_NAV_BACK + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseAllInGameMenus() +{ + while ( uiGlobal.activeMenu ) + { + if ( uiGlobal.activeMenu.GetType() == "submenu" ) + CloseSubmenu( false ) + + CloseActiveMenu( true, false ) + } +} + +void function CloseAllDialogs() +{ + while ( IsDialog( uiGlobal.activeMenu ) ) + CloseActiveMenu( true ) +} + +void function CloseAllToTargetMenu( var targetMenu ) +{ + while ( uiGlobal.activeMenu != targetMenu ) + CloseActiveMenu( true, false ) +} + +void function PrintMenuStack() +{ + array stack = clone uiGlobal.menuStack + stack.reverse() + + printt( "MENU STACK:" ) + + foreach ( menu in stack ) + { + if ( menu ) + printt( " ", Hud_GetHudName( menu ) ) + else + printt( " null" ) + } +} + +// Happens on any level load +void function UpdateMenusOnConnect( string levelname ) +{ + EndSignal( uiGlobal.signalDummy, "LevelShutdown" ) // HACK fix because UICodeCallback_LevelInit() incorrectly runs when disconnected by client error. Test with "script_error_client" while a level is loaded. + + CloseAllDialogs() + + var mainMenu = GetMenu( "MainMenu" ) + if ( IsMenuInMenuStack( mainMenu ) && !IsMenuInMenuStack( null ) ) + CloseAllToTargetMenu( mainMenu ) + + Assert( uiGlobal.activeMenu != null || uiGlobal.menuStack.len() == 0 ) + + AdvanceMenu( null ) + + // TODO: The order things are called in should be predictable so this isn't needed + while ( !uiGlobal.mapSupportsMenuModelsUpdated ) + { + //printt( Time(), "beginning waitframe, uiGlobal.mapSupportsMenuModelsUpdated is:", uiGlobal.mapSupportsMenuModelsUpdated ) + WaitFrame() + //printt( Time(), "ended waitframe, uiGlobal.mapSupportsMenuModelsUpdated is:", uiGlobal.mapSupportsMenuModelsUpdated ) + } + + if ( IsLevelMultiplayer( levelname ) ) + { + bool isLobby = IsLobbyMapName( levelname ) + + if ( isLobby ) + { + if ( IsPrivateMatch() ) + { + AdvanceMenu( GetMenu( "PrivateLobbyMenu" ) ) + } + else + { + AdvanceMenu( GetMenu( "LobbyMenu" ) ) + } + + thread UpdateAnnouncementDialog() + } + else + { + UI_SetPresentationType( ePresentationType.INACTIVE ) + } + } +} + +bool function IsMenuInMenuStack( var searchMenu ) +{ + foreach ( menu in uiGlobal.menuStack ) + { + // loading a map pushes a null sentinel onto the menu stack + if ( !menu ) + continue + + if ( menu == searchMenu ) + return true + } + + return false +} + +var function GetTopNonDialogMenu() +{ + array menuArray = clone uiGlobal.menuStack + menuArray.reverse() + + foreach ( menu in menuArray ) + { + if ( menu == null || IsDialog( menu ) ) + continue + + return menu + } + + return null +} + +void function CleanupInGameMenus() +{ + Signal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + CloseAllInGameMenus() + Assert( uiGlobal.activeMenu == null ) + if ( uiGlobal.menuStack.len() ) + { + if ( uiGlobal.loadingLevel == "" ) + CloseActiveMenu() // Disconnected. Remove stack null and open main menu. + else + CloseActiveMenu( true, false ) // Level to level transition. Remove stack null and DON'T open main menu. + } +} + +var function GetActiveMenu() +{ + return uiGlobal.activeMenu +} + +var function GetMenu( string menuName ) +{ + return uiGlobal.menus[ menuName ] +} + +var function GetPanel( string panelName ) +{ + return uiGlobal.panels[ panelName ] +} + +array function GetAllMenuPanels( var menu ) +{ + array menuPanels + + foreach ( panel in uiGlobal.allPanels ) + { + if ( Hud_GetParent( panel ) == menu ) + menuPanels.append( panel ) + } + + return menuPanels +} + +void function InitGamepadConfigs() +{ + uiGlobal.buttonConfigs = [ { orthodox = "gamepad_button_layout_default.cfg", southpaw = "gamepad_button_layout_default_southpaw.cfg" } ] + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_bumper_jumper.cfg", southpaw = "gamepad_button_layout_bumper_jumper_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_bumper_jumper_alt.cfg", southpaw = "gamepad_button_layout_bumper_jumper_alt_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_pogo_stick.cfg", southpaw = "gamepad_button_layout_pogo_stick_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_button_kicker.cfg", southpaw = "gamepad_button_layout_button_kicker_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_circle.cfg", southpaw = "gamepad_button_layout_circle_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_ninja.cfg", southpaw = "gamepad_button_layout_ninja_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_custom.cfg", southpaw = "gamepad_button_layout_custom.cfg" } ) + + uiGlobal.stickConfigs = [] + uiGlobal.stickConfigs.append( "gamepad_stick_layout_default.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_southpaw.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_legacy.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_legacy_southpaw.cfg" ) + + foreach ( key, val in uiGlobal.buttonConfigs ) + { + VPKNotifyFile( "cfg/" + val.orthodox ) + VPKNotifyFile( "cfg/" + val.southpaw ) + } + + foreach ( key, val in uiGlobal.stickConfigs ) + VPKNotifyFile( "cfg/" + val ) + + ExecCurrentGamepadButtonConfig() + ExecCurrentGamepadStickConfig() + + SetStandardAbilityBindingsForPilot( GetLocalClientPlayer() ) +} + +void function InitMenus() +{ + InitGlobalMenuVars() + SpShWeaponsInit() + + AddMenu( "MainMenu", $"resource/ui/menus/main.menu", InitMainMenu, "#MAIN" ) + AddPanel( GetMenu( "MainMenu" ), "EstablishUserPanel", InitEstablishUserPanel ) + AddPanel( GetMenu( "MainMenu" ), "MainMenuPanel", InitMainMenuPanel ) + + AddMenu( "PlayVideoMenu", $"resource/ui/menus/play_video.menu", InitPlayVideoMenu ) + AddMenu( "LobbyMenu", $"resource/ui/menus/lobby.menu", InitLobbyMenu, "#LOBBY" ) + + AddMenu( "FDMenu", $"resource/ui/menus/playlist_fd.menu", InitFDPlaylistMenu ) + AddMenu( "TeamTitanSelectMenu", $"resource/ui/menus/team_titan_select.menu", InitTeamTitanSelectMenu ) + AddMenu( "PlaylistMenu", $"resource/ui/menus/playlist.menu", InitPlaylistMenu ) + AddMenu( "PlaylistMixtapeMenu", $"resource/ui/menus/playlist_mixtape.menu", InitPlaylistMixtapeMenu ) + AddMenu( "PlaylistMixtapeChecklistMenu", $"resource/ui/menus/playlist_mixtape_checklist.menu", InitPlaylistMixtapeChecklistMenu ) + + AddMenu( "SinglePlayerDevMenu", $"resource/ui/menus/singleplayer_dev.menu", InitSinglePlayerDevMenu, "SINGLE PLAYER DEV" ) + AddMenu( "SinglePlayerMenu", $"resource/ui/menus/singleplayer.menu", InitSinglePlayerMenu, "SINGLE PLAYER" ) + + AddMenu( "SearchMenu", $"resource/ui/menus/search.menu", InitSearchMenu ) + + AddMenu( "GammaMenu", $"resource/ui/menus/gamma.menu", InitGammaMenu, "#BRIGHTNESS" ) + + AddMenu( "CommunitiesMenu", $"resource/ui/menus/community.menu", InitCommunitiesMenu ) + AddMenu( "Notifications", $"resource/ui/menus/notifications.menu", InitNotificationsMenu ) + AddMenu( "MyNetworks", $"resource/ui/menus/communities_mine.menu", InitMyNetworksMenu ) + AddMenu( "InboxFrontMenu", $"resource/ui/menus/inbox_front.menu", InitInboxFrontMenu ) + AddMenu( "Inbox", $"resource/ui/menus/inbox.menu", InitInboxMenu ) + AddMenu( "BrowseCommunities", $"resource/ui/menus/communities_browse.menu" ) + AddMenu( "CommunityEditMenu", $"resource/ui/menus/community_edit.menu" ) + AddMenu( "CommunityAdminSendMessage", $"resource/ui/menus/community_sendMessage.menu" ) + AddMenu( "CommunityAdminInviteRequestMenu", $"resource/ui/menus/community_inviteRequest.menu" ) +#if NETWORK_INVITE + AddMenu( "InviteFriendsToNetworkMenu", $"resource/ui/menus/invite_friends.menu", InitInviteFriendsToNetworkMenu ) +#endif + + AddMenu( "InGameMPMenu", $"resource/ui/menus/ingame_mp.menu", InitInGameMPMenu ) + AddMenu( "InGameSPMenu", $"resource/ui/menus/ingame_sp.menu", InitInGameSPMenu ) + + AddMenu( "Dialog", $"resource/ui/menus/dialog.menu", InitDialogMenu ) + AddMenu( "AnnouncementDialog", $"resource/ui/menus/dialog_announcement.menu", InitAnnouncementDialog ) + AddMenu( "ConnectingDialog", $"resource/ui/menus/dialog_connecting.menu", InitConnectingDialog ) + AddMenu( "DataCenterDialog", $"resource/ui/menus/dialog_datacenter.menu", InitDataCenterDialogMenu ) + AddMenu( "EULADialog", $"resource/ui/menus/dialog_eula.menu", InitEULADialog ) + AddMenu( "ReviewTermsDialog", $"resource/ui/menus/dialog_review_terms.menu", InitReviewTermsDialog ) + AddMenu( "RegistrationDialog", $"resource/ui/menus/dialog_registration.menu", InitRegistrationDialog ) + AddMenu( "AdvocateGiftDialog", $"resource/ui/menus/dialog_advocate_gift.menu", InitAdvocateGiftDialog ) + + AddMenu( "ControlsMenu", $"resource/ui/menus/controls.menu", InitControlsMenu, "#CONTROLS" ) + AddMenu( "ControlsAdvancedLookMenu", $"resource/ui/menus/controls_advanced_look.menu", InitControlsAdvancedLookMenu, "#CONTROLS_ADVANCED_LOOK" ) + AddMenu( "GamepadLayoutMenu", $"resource/ui/menus/gamepadlayout.menu", InitGamepadLayoutMenu ) +#if PC_PROG + AddMenu_WithCreateFunc( "MouseKeyboardBindingsMenu", $"resource/ui/menus/mousekeyboardbindings.menu", InitMouseKeyboardMenu, CreateKeyBindingMenu ) + AddMenu( "AudioMenu", $"resource/ui/menus/audio.menu", InitAudioMenu, "#AUDIO" ) + AddMenu_WithCreateFunc( "VideoMenu", $"resource/ui/menus/video.menu", InitVideoMenu, CreateVideoOptionsMenu ) +#elseif CONSOLE_PROG + AddMenu( "AudioVideoMenu", $"resource/ui/menus/audio_video.menu", InitAudioVideoMenu, "#AUDIO_VIDEO" ) +#endif + + AddMenu( "AdvancedHudMenu", $"resource/ui/menus/advanced_hud.menu", InitAdvancedHudMenu, "#ADVANCED_HUD" ) + + AddMenu( "PilotLoadoutsMenu", $"resource/ui/menus/pilotloadouts.menu", InitPilotLoadoutsMenu ) + AddMenu( "TitanLoadoutsMenu", $"resource/ui/menus/titanloadouts.menu", InitTitanLoadoutsMenu ) + AddMenu( "EditPilotLoadoutsMenu", $"resource/ui/menus/pilotloadouts.menu", InitEditPilotLoadoutsMenu ) + AddMenu( "EditTitanLoadoutsMenu", $"resource/ui/menus/titanloadouts.menu", InitEditTitanLoadoutsMenu ) + AddMenu( "EditPilotLoadoutMenu", $"resource/ui/menus/editpilotloadout.menu", InitEditPilotLoadoutMenu ) + AddMenu( "EditTitanLoadoutMenu", $"resource/ui/menus/edittitanloadout.menu", InitEditTitanLoadoutMenu ) + + AddMenu( "SPTitanLoadoutMenu", $"resource/ui/menus/sptitanloadout.menu", InitSPTitanLoadoutMenu ) + AddMenu( "SPTitanLoadoutTutorialMenu", $"resource/ui/menus/sptitanloadout_tutorial.menu", InitSPTitanLoadoutTutorialMenu ) + + AddMenu( "SuitSelectMenu", $"resource/ui/menus/suitselect.menu", InitSuitSelectMenu ) + AddMenu( "WeaponSelectMenu", $"resource/ui/menus/weaponselect.menu", InitWeaponSelectMenu ) + AddMenu( "CategorySelectMenu", $"resource/ui/menus/categoryselect.menu", InitCategorySelectMenu ) + AddMenu( "AbilitySelectMenu", $"resource/ui/menus/abilityselect.menu", InitAbilitySelectMenu ) + AddMenu( "PassiveSelectMenu", $"resource/ui/menus/passiveselect.menu", InitPassiveSelectMenu ) + AddSubmenu( "ModSelectMenu", $"resource/ui/menus/modselect.menu", InitModSelectMenu ) + AddMenu( "CamoSelectMenu", $"resource/ui/menus/camoselect.menu", InitCamoSelectMenu ) + AddMenu( "NoseArtSelectMenu", $"resource/ui/menus/noseartselect.menu", InitNoseArtSelectMenu ) + AddMenu( "CallsignCardSelectMenu", $"resource/ui/menus/callsigncardselect.menu", InitCallsignCardSelectMenu ) + AddMenu( "CallsignIconSelectMenu", $"resource/ui/menus/callsigniconselect.menu", InitCallsignIconSelectMenu ) + AddMenu( "BoostStoreMenu", $"resource/ui/menus/booststore.menu", InitBoostStoreMenu ) + + AddMenu( "PrivateLobbyMenu", $"resource/ui/menus/private_lobby.menu", InitPrivateMatchMenu, "#PRIVATE_MATCH" ) + AddMenu( "MapsMenu", $"resource/ui/menus/map_select.menu", InitMapsMenu ) + AddMenu( "ModesMenu", $"resource/ui/menus/mode_select.menu", InitModesMenu ) + AddMenu( "MatchSettingsMenu", $"resource/ui/menus/match_settings.menu", InitMatchSettingsMenu ) + + AddMenu( "Advocate_Letter", $"resource/ui/menus/advocate_letter.menu", InitAdvocateLetterMenu ) + AddMenu( "Generation_Respawn", $"resource/ui/menus/generation_respawn.menu", InitGenerationRespawnMenu ) + AddMenu( "ChallengesMenu", $"resource/ui/menus/challenges.menu", InitChallengesMenu ) + + AddMenu( "ViewStatsMenu", $"resource/ui/menus/viewstats.menu", InitViewStatsMenu, "#PERSONAL_STATS" ) + AddMenu( "ViewStats_Overview_Menu", $"resource/ui/menus/viewstats_overview.menu", InitViewStatsOverviewMenu ) + //AddMenu( "ViewStats_Kills_Menu", $"resource/ui/menus/viewstats_kills.menu", InitViewStatsKillsMenu ) + AddMenu( "ViewStats_Time_Menu", $"resource/ui/menus/viewstats_time.menu", InitViewStatsTimeMenu ) + //AddMenu( "ViewStats_Distance_Menu", $"resource/ui/menus/viewstats_distance.menu", InitViewStatsDistanceMenu ) + AddMenu( "ViewStats_Weapons_Menu", $"resource/ui/menus/viewstats_weapons.menu", InitViewStatsWeaponsMenu ) + AddMenu( "ViewStats_Titans_Menu", $"resource/ui/menus/viewstats_titans.menu", InitViewStatsTitansMenu ) + AddMenu( "ViewStats_Misc_Menu", $"resource/ui/menus/viewstats_misc.menu", InitViewStatsMiscMenu ) + AddMenu( "ViewStats_Maps_Menu", $"resource/ui/menus/viewstats_maps.menu", InitViewStatsMapsMenu ) + + AddMenu( "PostGameMenu", $"resource/ui/menus/postgame.menu", InitPostGameMenu ) + AddMenu( "EOG_XP", $"resource/ui/menus/eog_xp.menu", InitEOG_XPMenu ) + AddMenu( "EOG_Coins", $"resource/ui/menus/eog_coins.menu", InitEOG_CoinsMenu ) + AddMenu( "EOG_Challenges", $"resource/ui/menus/eog_challenges.menu", InitEOG_ChallengesMenu ) + AddMenu( "EOG_Unlocks", $"resource/ui/menus/eog_unlocks.menu", InitEOG_UnlocksMenu ) + AddMenu( "EOG_Scoreboard", $"resource/ui/menus/eog_scoreboard.menu", InitEOG_ScoreboardMenu ) + + AddMenu( "CreditsMenu", $"resource/ui/menus/credits.menu", InitCreditsMenu, "#CREDITS" ) + + AddMenu( "BurnCardMenu", $"resource/ui/menus/burn_cards.menu", InitBurnCardMenu, "#MENU_BURNCARD_MENU" ) + AddMenu( "FactionChoiceMenu", $"resource/ui/menus/faction_choice.menu", InitFactionChoiceMenu, "#FACTION_CHOICE_MENU" ) + AddMenu( "ArmoryMenu", $"resource/ui/menus/armory.menu", InitArmoryMenu, "#ARMORY_MENU" ) + + AddMenu( "StoreMenu", $"resource/ui/menus/store.menu", InitStoreMenu, "#STORE_MENU" ) + AddMenu( "StoreMenu_NewReleases", $"resource/ui/menus/store_new_releases.menu", InitStoreMenuNewReleases, "#STORE_NEW_RELEASES" ) + AddMenu( "StoreMenu_Limited", $"resource/ui/menus/store_limited.menu", InitStoreMenuLimited, "#STORE_LIMITED" ) + AddMenu( "StoreMenu_Sales", $"resource/ui/menus/store_bundles.menu", InitStoreMenuSales, "#STORE_BUNDLES" ) + AddMenu( "StoreMenu_Titans", $"resource/ui/menus/store_prime_titans.menu", InitStoreMenuTitans, "#STORE_TITANS" ) // reusing store_prime_titans.menu + AddMenu( "StoreMenu_PrimeTitans", $"resource/ui/menus/store_prime_titans.menu", InitStoreMenuPrimeTitans, "#STORE_PRIME_TITANS" ) + //AddMenu( "StoreMenu_WeaponSelect", $"resource/ui/menus/store_weapon_select.menu", InitStoreMenuWeaponSelect ) + //AddMenu( "StoreMenu_WeaponSkinPreview", $"resource/ui/menus/store_weapon_skin_preview.menu", InitStoreMenuWeaponSkinPreview ) + AddMenu( "StoreMenu_WeaponSkinBundles", $"resource/ui/menus/store_weapon_skin_bundles.menu", InitStoreMenuWeaponSkinBundles ) + AddMenu( "StoreMenu_WeaponSkins", $"resource/ui/menus/store_weapons.menu", InitStoreMenuWeaponSkins ) + AddMenu( "StoreMenu_Customization", $"resource/ui/menus/store_customization.menu", InitStoreMenuCustomization, "#STORE_CUSTOMIZATION_PACKS" ) + AddMenu( "StoreMenu_CustomizationPreview", $"resource/ui/menus/store_customization_preview.menu", InitStoreMenuCustomizationPreview, "#STORE_CUSTOMIZATION_PACKS" ) + AddMenu( "StoreMenu_Camo", $"resource/ui/menus/store_camo.menu", InitStoreMenuCamo, "#STORE_CAMO_PACKS" ) + AddMenu( "StoreMenu_CamoPreview", $"resource/ui/menus/store_camo_preview.menu", InitStoreMenuCamoPreview, "#STORE_CAMO_PACKS" ) + AddMenu( "StoreMenu_Callsign", $"resource/ui/menus/store_callsign.menu", InitStoreMenuCallsign, "#STORE_CALLSIGN_PACKS" ) + AddMenu( "StoreMenu_CallsignPreview", $"resource/ui/menus/store_callsign_preview.menu", InitStoreMenuCallsignPreview, "#STORE_CALLSIGN_PACKS" ) + + AddMenu( "KnowledgeBaseMenu", $"resource/ui/menus/knowledgebase.menu", InitKnowledgeBaseMenu ) + AddMenu( "KnowledgeBaseMenuSubMenu", $"resource/ui/menus/knowledgebase_submenu.menu", InitKnowledgeBaseMenuSubMenu ) + + AddMenu( "DevMenu", $"resource/ui/menus/dev.menu", InitDevMenu, "Dev" ) + InitSharedStartPoints() + + foreach ( menu in uiGlobal.allMenus ) + { + if ( uiGlobal.menuData[ menu ].initFunc != null ) + uiGlobal.menuData[ menu ].initFunc() + + array elems = GetElementsByClassname( menu, "TabsCommonClass" ) + if ( elems.len() ) + uiGlobal.menuData[ menu ].hasTabs = true + + elems = GetElementsByClassname( menu, "EnableKeyBindingIcons" ) + foreach ( elem in elems ) + Hud_EnableKeyBindingIcons( elem ) + } + + InitTabs() + + var tabbedMenu = GetMenu( "PostGameMenu" ) + AddPanel( tabbedMenu, "PVEPanel", InitPVEPanel ) + AddPanel( tabbedMenu, "SummaryPanel", InitSummaryPanel ) + AddPanel( tabbedMenu, "FDAwardsPanel", InitFDAwardsPanel ) + + AddPanel( tabbedMenu, "ScoreboardPanel", InitScoreboardPanel ) + + foreach ( panel in uiGlobal.allPanels ) + { + if ( uiGlobal.panelData[ panel ].initFunc != null ) + uiGlobal.panelData[ panel ].initFunc() + } + + // A little weird, but GetElementsByClassname() uses menu scope rather than parent scope. + foreach ( menu in uiGlobal.allMenus ) + { + array buttons = GetElementsByClassname( menu, "DefaultFocus" ) + foreach ( button in buttons ) + { + var panel = Hud_GetParent( button ) + + //Assert( elems.len() == 1, "More than 1 panel element set as DefaultFocus!" ) + Assert( panel != null, "no parent panel found for button " + Hud_GetHudName( button ) ) + Assert( panel in uiGlobal.panelData, "panel " + Hud_GetHudName( panel ) + " isn't in uiGlobal.panelData, but button " + Hud_GetHudName( button ) + " has defaultFocus set!" ) + uiGlobal.panelData[ panel ].defaultFocus = button + //printt( "Found DefaultFocus, button was:", Hud_GetHudName( button ), "panel was:", Hud_GetHudName( panel ) ) + } + } + + InitFooterOptions() + + #if DEV + if ( Dev_CommandLineHasParm( "-autoprecache_all" ) ) + { + // repreache all levels + ExecuteLoadingClientCommands_SetStartPoint( "sp_training" ) + ClientCommand( "map sp_training" ) + CloseAllMenus() + } + #endif +} + +void functionref( var ) function AdvanceMenuEventHandler( var menu ) +{ + return void function( var item ) : ( menu ) + { + if ( Hud_IsLocked( item ) ) + return + + AdvanceMenu( menu ) + } +} + +void function PCBackButton_Activate( var button ) +{ + UICodeCallback_NavigateBack() +} + +void function PCSwitchTeamsButton_Activate( var button ) +{ + ClientCommand( "PrivateMatchSwitchTeams" ) +} + +void function PCToggleSpectateButton_Activate( var button ) +{ + ClientCommand( "PrivateMatchToggleSpectate" ) +} + +void function ToggleButtonStates( var button ) +{ + for ( ;; ) + { + Hud_SetEnabled( button, true ) + wait 1 + Hud_SetSelected( button, true ) + wait 1 + Hud_SetLocked( button, true ) + wait 1 + Hud_SetNew( button, true ) + wait 1 + Hud_SetNew( button, false ) + wait 1 + Hud_SetLocked( button, false ) + wait 1 + Hud_SetSelected( button, false ) + wait 1 + Hud_SetEnabled( button, false ) + wait 1 + } +} + +void function AddMenuElementsByClassname( var menu, string classname ) +{ + array elements = GetElementsByClassname( menu, classname ) + + if ( !(classname in menu.classElements) ) + menu.classElements[classname] <- [] + + menu.classElements[classname].extend( elements ) +} + +void function FocusDefault( var menu ) +{ + if ( + menu == GetMenu( "MainMenu" ) || + menu == GetMenu( "CategorySelectMenu" ) || + menu == GetMenu( "AbilitySelectMenu" ) || + menu == GetMenu( "PassiveSelectMenu" ) || + menu == GetMenu( "WeaponSelectMenu" ) || + menu == GetMenu( "SuitSelectMenu" ) || + menu == GetMenu( "CamoSelectMenu" ) || + menu == GetMenu( "NoseArtSelectMenu" ) || + menu == GetMenu( "FactionChoiceMenu" ) || + menu == GetMenu( "BurnCardMenu" ) || + menu == GetMenu( "CallsignCardSelectMenu" ) || + menu == GetMenu( "CallsignIconSelectMenu" ) ) + { + } + else + { + //printt( "FocusDefaultMenuItem() called" ) + FocusDefaultMenuItem( menu ) + } +} + +void function SetPanelDefaultFocus( var panel, var button ) +{ + uiGlobal.panelData[ panel ].defaultFocus = button +} + +void function PanelFocusDefault( var panel ) +{ + //printt( "PanelFocusDefault called" ) + if ( uiGlobal.panelData[ panel ].defaultFocus ) + { + Hud_SetFocused( uiGlobal.panelData[ panel ].defaultFocus ) + //printt( "PanelFocusDefault if passed,", Hud_GetHudName( uiGlobal.panelData[ panel ].defaultFocus ), "focused" ) + } +} + +void function SetMenuThinkFunc( var menu, void functionref() func ) +{ + Assert( uiGlobal.menuData[ menu ].thinkFunc == null ) + uiGlobal.menuData[ menu ].thinkFunc = func +} + +void function AddMenuEventHandler( var menu, int event, void functionref() func ) +{ + if ( event == eUIEvent.MENU_OPEN ) + { + Assert( uiGlobal.menuData[ menu ].openFunc == null ) + uiGlobal.menuData[ menu ].openFunc = func + } + else if ( event == eUIEvent.MENU_CLOSE ) + { + Assert( uiGlobal.menuData[ menu ].closeFunc == null ) + uiGlobal.menuData[ menu ].closeFunc = func + } + else if ( event == eUIEvent.MENU_SHOW ) + { + Assert( uiGlobal.menuData[ menu ].showFunc == null ) + uiGlobal.menuData[ menu ].showFunc = func + } + else if ( event == eUIEvent.MENU_HIDE ) + { + Assert( uiGlobal.menuData[ menu ].hideFunc == null ) + uiGlobal.menuData[ menu ].hideFunc = func + } + else if ( event == eUIEvent.MENU_NAVIGATE_BACK ) + { + Assert( uiGlobal.menuData[ menu ].navBackFunc == null ) + uiGlobal.menuData[ menu ].navBackFunc = func + } + else if ( event == eUIEvent.MENU_TAB_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].tabChangedFunc == null ) + uiGlobal.menuData[ menu ].tabChangedFunc = func + } + else if ( event == eUIEvent.MENU_ENTITLEMENTS_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].entitlementsChangedFunc == null ) + uiGlobal.menuData[ menu ].entitlementsChangedFunc = func + } + else if ( event == eUIEvent.MENU_INPUT_MODE_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].inputModeChangedFunc == null ) + uiGlobal.menuData[ menu ].inputModeChangedFunc = func + } +} + +void function AddPanelEventHandler( var panel, int event, void functionref() func ) +{ + if ( event == eUIEvent.PANEL_SHOW ) + uiGlobal.panelData[ panel ].showFunc = func + else if ( event == eUIEvent.PANEL_HIDE ) + uiGlobal.panelData[ panel ].hideFunc = func +} + +// TODO: Get a real on open event from code? +void function OpenMenuWrapper( var menu, bool focusDefault ) +{ + OpenMenu( menu ) + printt( Hud_GetHudName( menu ), "menu opened" ) + + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].openFunc != null ) + { + thread uiGlobal.menuData[ menu ].openFunc() + //printt( "Called openFunc for:", menu.GetHudName() ) + } + + if ( focusDefault ) + FocusDefault( menu ) + + //UpdateMenuTabs() + UpdateFooterOptions() +} + +void function CloseMenuWrapper( var menu ) +{ + CloseMenu( menu ) + printt( Hud_GetHudName( menu ), "menu closed" ) + + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].closeFunc != null ) + { + thread uiGlobal.menuData[ menu ].closeFunc() + //printt( "Called closeFunc for:", Hud_GetHudName( menu ) ) + } +} + +bool function IsLevelMultiplayer( string levelname ) +{ + return levelname.find( "mp_" ) == 0 +} + +void function AddButtonEventHandler( var button, int event, void functionref( var ) func ) +{ + Hud_AddEventHandler( button, event, func ) +} + +void function AddEventHandlerToButton( var menu, string buttonName, int event, void functionref( var ) func ) +{ + var button = Hud_GetChild( menu, buttonName ) + Hud_AddEventHandler( button, event, func ) +} + +void function AddEventHandlerToButtonClass( var menu, string classname, int event, void functionref( var ) func ) +{ + array buttons = GetElementsByClassname( menu, classname ) + + foreach ( button in buttons ) + { + //printt( "button name:", Hud_GetHudName( button ) ) + Hud_AddEventHandler( button, event, func ) + } +} + +// Added slight delay to main menu music to work around a hitch caused when the game first starts up +void function PlayMusicAfterDelay() +{ + wait MAINMENU_MUSIC_DELAY + if ( uiGlobal.playingMusic ) + EmitUISound( "MainMenu_Music" ) +} + +void function DisableMusic() +{ + EmitUISound( "Movie_MuteAllGameSound" ) +} + +void function EnableMusic() +{ + StopUISoundByName( "Movie_MuteAllGameSound" ) +} + +void function PlayMusic() +{ + if ( !uiGlobal.playingMusic && !uiGlobal.playingVideo && !uiGlobal.playingCredits ) + { + //printt( "PlayMusic() called. Playing: MainMenu_Music. uiGlobal.playingMusic:", uiGlobal.playingMusic, "uiGlobal.playingVideo:", uiGlobal.playingVideo, "uiGlobal.playingCredits:", uiGlobal.playingCredits ) + uiGlobal.playingMusic = true + thread PlayMusicAfterDelay() + } + else + { + //printt( "PlayMusic() called, but doing nothing. uiGlobal.playingMusic:", uiGlobal.playingMusic, "uiGlobal.playingVideo:", uiGlobal.playingVideo, "uiGlobal.playingCredits:", uiGlobal.playingCredits ) + } +} + +void function StopMusic() +{ + //printt( "StopMusic() called. Stopping: MainMenu_Music" ) + StopUISound( "MainMenu_Music" ) + uiGlobal.playingMusic = false +} + +void function RegisterMenuVarInt( string varName, int value ) +{ + table intVars = uiGlobal.intVars + + Assert( !( varName in intVars ) ) + + intVars[varName] <- value +} + +void function RegisterMenuVarBool( string varName, bool value ) +{ + table boolVars = uiGlobal.boolVars + + Assert( !( varName in boolVars ) ) + + boolVars[varName] <- value +} + +void function RegisterMenuVarVar( string varName, var value ) +{ + table varVars = uiGlobal.varVars + + Assert( !( varName in varVars ) ) + + varVars[varName] <- value +} + +int function GetMenuVarInt( string varName ) +{ + table intVars = uiGlobal.intVars + + Assert( varName in intVars ) + + return intVars[varName] +} + +bool function GetMenuVarBool( string varName ) +{ + table boolVars = uiGlobal.boolVars + + Assert( varName in boolVars ) + + return boolVars[varName] +} + +var function GetMenuVarVar( string varName ) +{ + table varVars = uiGlobal.varVars + + Assert( varName in varVars ) + + return varVars[varName] +} + +void function SetMenuVarInt( string varName, int value ) +{ + table intVars = uiGlobal.intVars + + Assert( varName in intVars ) + + if ( intVars[varName] == value ) + return + + intVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function SetMenuVarBool( string varName, bool value ) +{ + table boolVars = uiGlobal.boolVars + + Assert( varName in boolVars ) + + if ( boolVars[varName] == value ) + return + + boolVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function SetMenuVarVar( string varName, var value ) +{ + table varVars = uiGlobal.varVars + + Assert( varName in varVars ) + + if ( varVars[varName] == value ) + return + + varVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function AddMenuVarChangeHandler( string varName, void functionref() func ) +{ + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( !( varName in varChangeFuncs ) ) + varChangeFuncs[varName] <- [] + + // TODO: Verify we're not duplicating an existing func + varChangeFuncs[varName].append( func ) +} + +// These are common menu statuses that trigger menu logic any time they change +// They should become code callbacks, so script doesn't poll +void function InitGlobalMenuVars() +{ + RegisterMenuVarVar( "focus", null ) + RegisterMenuVarBool( "isConnected", false ) + RegisterMenuVarBool( "isFullyConnected", false ) + RegisterMenuVarBool( "isPartyLeader", false ) + RegisterMenuVarBool( "isPrivateMatch", false ) + RegisterMenuVarBool( "isGamepadActive", IsControllerModeActive() ) + + #if CONSOLE_PROG + RegisterMenuVarBool( "CONSOLE_isOnline", false ) + RegisterMenuVarBool( "CONSOLE_isSignedIn", false ) + #endif // CONSOLE_PROG + + #if DURANGO_PROG + RegisterMenuVarBool( "DURANGO_isGameFullyInstalled", false ) + RegisterMenuVarBool( "DURANGO_canInviteFriends", false ) + RegisterMenuVarBool( "DURANGO_isJoinable", false ) + #elseif PS4_PROG + RegisterMenuVarBool( "PS4_canInviteFriends", false) + #elseif PC_PROG + RegisterMenuVarBool( "ORIGIN_isEnabled", false ) + RegisterMenuVarBool( "ORIGIN_isJoinable", false ) + #endif + + thread UpdateFocus() + thread UpdateIsConnected() + thread UpdateIsFullyConnected() + thread UpdateAmIPartyLeader() + thread UpdateIsPrivateMatch() + thread UpdateActiveMenuThink() + + #if CONSOLE_PROG + thread UpdateConsole_IsOnline() + thread UpdateConsole_IsSignedIn() + #endif // CONSOLE_PROG + + #if DURANGO_PROG + thread UpdateDurango_IsGameFullyInstalled() + thread UpdateDurango_CanInviteFriends() + thread UpdateDurango_IsJoinable() + #elseif PS4_PROG + thread UpdatePS4_CanInviteFriends() + #elseif PC_PROG + thread UpdateOrigin_IsEnabled() + thread UpdateOrigin_IsJoinable() + thread UpdateIsGamepadActive() + #endif +} + +void function UpdateFocus() +{ + while ( true ) + { + SetMenuVarVar( "focus", GetFocus() ) + WaitFrame() + } +} + +void function UpdateActiveMenuThink() +{ + while ( true ) + { + var menu = GetActiveMenu() + if ( menu ) + { + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].thinkFunc != null ) + uiGlobal.menuData[ menu ].thinkFunc() + } + + WaitFrame() + } +} + +void function UpdateIsConnected() +{ + while ( true ) + { + SetMenuVarBool( "isConnected", IsConnected() ) + WaitFrame() + } +} + +void function UpdateIsFullyConnected() +{ + while ( true ) + { + SetMenuVarBool( "isFullyConnected", IsFullyConnected() ) + WaitFrame() + } +} + +void function UpdateAmIPartyLeader() +{ + while ( true ) + { + SetMenuVarBool( "isPartyLeader", AmIPartyLeader() ) + WaitFrame() + } +} + +void function UpdateIsPrivateMatch() +{ + while ( true ) + { + SetMenuVarBool( "isPrivateMatch", IsPrivateMatch() ) + WaitFrame() + } +} + +#if CONSOLE_PROG + void function UpdateConsole_IsOnline() + { + while ( true ) + { + SetMenuVarBool( "CONSOLE_isOnline", Console_IsOnline() ) + WaitFrame() + } + } + + void function UpdateConsole_IsSignedIn() + { + while ( true ) + { + SetMenuVarBool( "CONSOLE_isSignedIn", Console_IsSignedIn() ) + WaitFrame() + } + } +#endif // CONSOLE_PROG + + +#if PS4_PROG + void function UpdatePS4_CanInviteFriends() + { + while ( true ) + { + SetMenuVarBool( "PS4_canInviteFriends", PS4_canInviteFriends() ) + WaitFrame() + } + } +#endif // PS4_PROG + + + +#if DURANGO_PROG + void function UpdateDurango_IsGameFullyInstalled() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_isGameFullyInstalled", IsGameFullyInstalled() ) + wait 1 // Poll less frequent + } + } + + void function UpdateDurango_CanInviteFriends() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_canInviteFriends", Durango_CanInviteFriends() ) + WaitFrame() + } + } + + void function UpdateDurango_IsJoinable() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_isJoinable", Durango_IsJoinable() ) + WaitFrame() + } + } +#endif // DURANGO_PROG + +#if PC_PROG + void function UpdateOrigin_IsEnabled() + { + while ( true ) + { + SetMenuVarBool( "ORIGIN_isEnabled", Origin_IsEnabled() ) + WaitFrame() + } + } + + void function UpdateOrigin_IsJoinable() + { + while ( true ) + { + SetMenuVarBool( "ORIGIN_isJoinable", Origin_IsJoinable() ) + WaitFrame() + } + } + + void function UpdateIsGamepadActive() + { + while ( true ) + { + SetMenuVarBool( "isGamepadActive", IsControllerModeActive() ) + WaitFrame() + } + } +#endif // PC_PROG + +void function InviteFriends( var button ) +{ + //AdvanceMenu( GetMenu( "InviteFriendsToPartyMenu" ) ) + + #if DURANGO_PROG + Durango_InviteFriends() + #elseif PS4_PROG + ClientCommand("session_debug_invite"); + #elseif PC_PROG + Assert( Origin_IsEnabled() ) + Assert( Origin_IsJoinable() ) + + Origin_ShowInviteFriendsDialog() + #endif +} + +#if DURANGO_PROG +void function OpenXboxPartyApp( var button ) +{ + Durango_OpenPartyApp() +} + +void function OpenXboxHelp( var button ) +{ + Durango_ShowHelpWindow() +} +#endif // DURANGO_PROG + +void function OpenReviewTermsDialog( var button ) +{ + AdvanceMenu( GetMenu( "ReviewTermsDialog" ) ) +} + +void function OpenErrorDialog( string errorDetails ) +{ + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = errorDetails + dialogData.image = $"ui/menu/common/dialog_error" + +#if PC_PROG + AddDialogButton( dialogData, "#DISMISS" ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) +#endif // PC_PROG + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + while ( uiGlobal.activeMenu != GetMenu( "MainMenu" ) ) + { + WaitSignal( uiGlobal.signalDummy, "OpenErrorDialog", "ActiveMenuChanged" ) + } + + OpenDialog( dialogData ) +} + +bool function IsDialog( var menu ) +{ + if ( menu == null ) + return false + + return uiGlobal.menuData[ menu ].isDialog +} + +bool function IsDialogActive( DialogData dialogData ) +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return false + + return uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData == dialogData +} + +bool function IsDialogOnlyActiveMenu() +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return false + + int stackLen = uiGlobal.menuStack.len() + if ( stackLen < 1 ) + return false + + if ( uiGlobal.menuStack[stackLen - 1] != uiGlobal.activeMenu ) + return false + + if ( stackLen == 1 ) + return true + + if ( uiGlobal.menuStack[stackLen - 2] == null ) + return true + + return false +} + +void function SetNavUpDown( array buttons, var wrap = true ) +{ + Assert( buttons.len() > 0 ) + + var first = buttons[0] + var last = buttons[buttons.len() - 1] + var prev + var next + var button + + for ( int i = 0; i < buttons.len(); i++ ) + { + button = buttons[i] + + if ( button == first ) + prev = last + else + prev = buttons[i - 1] + + if ( button == last ) + next = first + else + next = buttons[i + 1] + + button.SetNavUp( prev ) + button.SetNavDown( next ) + + //printt( "SetNavUP for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( prev ) ) + //printt( "SetNavDown for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( next ) ) + } +} + +void function SetNavLeftRight( array buttons, var wrap = true ) +{ + Assert( buttons.len() > 0 ) + + var first = buttons[0] + var last = buttons[buttons.len() - 1] + var prev + var next + var button + + for ( int i = 0; i < buttons.len(); i++ ) + { + button = buttons[i] + + if ( button == first ) + prev = last + else + prev = buttons[i - 1] + + if ( button == last ) + next = first + else + next = buttons[i + 1] + + button.SetNavLeft( prev ) + button.SetNavRight( next ) + + //printt( "SetNavUP for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( prev ) ) + //printt( "SetNavDown for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( next ) ) + } +} + +void function UICodeCallback_EntitlementsChanged() +{ + if ( uiGlobal.activeMenu == null ) + return + + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].entitlementsChangedFunc != null ) + thread uiGlobal.menuData[ uiGlobal.activeMenu ].entitlementsChangedFunc() +} + +#if PC_PROG +void function QuitGame() +{ + ClientCommand( "quit" ) +} +#endif + +void function UICodeCallback_StoreTransactionCompleted() +{ + // this callback is only supported and needed on PS4 currently +#if PS4_PROG + if ( InStoreMenu() ) + OnOpenDLCStore() +#endif +} + +void function UICodeCallback_GamePurchased() +{ + // this callback is only supported and needed on PC currently +#if PC_PROG + DialogData dialogData + dialogData.header = "#PURCHASE_GAME_COMPLETE" + dialogData.message = "#PURCHASE_GAME_RESTART" + AddDialogButton( dialogData, "#QUIT", QuitGame ) + + OpenDialog( dialogData ) +#endif +} + +bool function IsTrialPeriodActive() +{ + return GetConVarBool( "trialPeriodIsActive" ) +} + +void function LaunchGamePurchaseOrDLCStore( array menuNames = [ "StoreMenu" ] ) +{ + if ( Script_IsRunningTrialVersion() ) + { + LaunchGamePurchase() + } + else + { + void functionref() preOpenFunc = null + + foreach ( menuName in menuNames ) + { + // Special case because this menu needs a few properties set before opening + if ( menuName == "StoreMenu_WeaponSkins" ) + { + preOpenFunc = DefaultToDLC11WeaponWarpaintBundle + break + } + } + + OpenStoreMenu( menuNames, preOpenFunc ) + } +} + +void function UICodeCallback_PartyUpdated() +{ + if ( AmIPartyLeader() ) + { + string activeSearchingPlaylist = GetActiveSearchingPlaylist() + if ( activeSearchingPlaylist != "" && !CanPlaylistFitMyParty( activeSearchingPlaylist ) ) + { + CancelMatchSearch() + + DialogData dialogData + dialogData.header = "#MATCHMAKING_CANCELED" + dialogData.message = "#MATCHMAKING_CANCELED_REASON_PARTY_SIZE" + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) + } + } +} + + +void function HACK_DelayedSetFocus_BecauseWhy( var item ) +{ + wait 0.1 + if ( IsValid( item ) ) + Hud_SetFocused( item ) +} + +void function ClassicMusic_OnChange( var button ) +{ + bool isEnabled = GetConVarBool( "sound_classic_music" ) + + if ( IsFullyConnected() && IsMultiplayer() && GetUIPlayer() ) + { + if ( IsItemLocked( GetUIPlayer(), "classic_music" ) ) + SetConVarBool( "sound_classic_music", false ) + + if ( IsLobby() ) + thread RunClientScript( "OnSoundClassicMusicChanged" ) + } +} + +bool function IsClassicMusicAvailable() +{ + bool classicMusicAvailable = false + if ( IsFullyConnected() && IsMultiplayer() && GetUIPlayer() ) + classicMusicAvailable = !IsItemLocked( GetUIPlayer(), "classic_music" ) + + return classicMusicAvailable +} + +void function UICodeCallback_KeyBindOverwritten( string key, string oldbinding, string newbinding ) +{ + DialogData dialogData + dialogData.header = Localize( "#MENU_KEYBIND_WAS_BEING_USED", key ) + dialogData.message = Localize( "#MENU_KEYBIND_WAS_BEING_USED_SUB", key, Localize( oldbinding ) ) + + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) +} -- cgit v1.2.3 From 4d8e3698102d545b7d2bbd3f41506362a7cddc28 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 12 Mar 2023 19:35:29 +0100 Subject: Bump version number (#602) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 3b236980..d52f95fc 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 0, "ConVars": [ { diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 1f672ee4..374e13e4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index f67aeb19..657854da 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 80ceb2b317336c454d83392028501a31da89e77e Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 5 Apr 2023 01:25:35 +0200 Subject: Add menu_ingame.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/menu_ingame.nut | 693 +++++++++++++++++++++ 1 file changed, 693 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut new file mode 100644 index 00000000..03bd8959 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut @@ -0,0 +1,693 @@ +//global function InitLobbyStartMenu +global function InitInGameMPMenu +global function InitInGameSPMenu +global function ServerCallback_UI_ObjectiveUpdated +global function ServerCallback_UI_UpdateMissionLog +global function SP_ResetObjectiveStringIndex +global function SCB_SetDoubleXPStatus + +global function SCB_SetCompleteMeritState +global function SCB_SetEvacMeritState +global function SCB_SetMeritCount +global function SCB_SetScoreMeritState +global function SCB_SetWinMeritState +global function SCB_SetWeaponMeritCount +global function SCB_SetTitanMeritCount + +const DATA_TABLE = $"datatable/sp_difficulty.rpak" + +struct +{ + var menuMP + var menuSP + var BtnTrackedChallengeBackground + var BtnTrackedChallengeTitle + array trackedChallengeButtons + var BtnLastCheckpoint + int objectiveStringIndex + bool SP_displayObjectiveOnClose + var settingsHeader + var faqButton + int titanHeaderIndex + var titanHeader + var titanSelectButton + var titanEditButton + + ComboStruct &comboStruct + + array loadoutButtons + array loadoutHeaders +} file + +void function InitInGameMPMenu() +{ + var menu = GetMenu( "InGameMPMenu" ) + file.menuMP = menu + + SP_ResetObjectiveStringIndex() + file.SP_displayObjectiveOnClose = true + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnInGameMPMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnInGameMPMenu_Close ) + + AddUICallback_OnLevelInit( OnInGameLevelInit ) + + ComboStruct comboStruct = ComboButtons_Create( menu ) + + int headerIndex = 0 + int buttonIndex = 0 + var pilotHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PILOT" ) + file.loadoutHeaders.append( pilotHeader ) + var pilotSelectButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#SELECT" ) + Hud_AddEventHandler( pilotSelectButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "PilotLoadoutsMenu" ) ) ) + file.loadoutButtons.append( pilotSelectButton ) + var pilotEditButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#EDIT" ) + Hud_AddEventHandler( pilotEditButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditPilotLoadoutsMenu" ) ) ) + file.loadoutButtons.append( pilotEditButton ) + + headerIndex++ + buttonIndex = 0 + var titanHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_TITAN" ) + file.titanHeader = titanHeader + file.titanHeaderIndex = headerIndex + file.loadoutHeaders.append( titanHeader ) + var titanSelectButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#SELECT" ) + file.titanSelectButton = titanSelectButton + file.loadoutButtons.append( titanSelectButton ) + Hud_AddEventHandler( titanSelectButton, UIE_CLICK, TitanSelectButtonHandler ) + var titanEditButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#EDIT" ) + Hud_AddEventHandler( titanEditButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditTitanLoadoutsMenu" ) ) ) + file.titanEditButton = titanEditButton + file.loadoutButtons.append( titanEditButton ) + + headerIndex++ + buttonIndex = 0 + var gameHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_GAME" ) + var leaveButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#LEAVE_MATCH" ) + Hud_AddEventHandler( leaveButton, UIE_CLICK, OnLeaveButton_Activate ) + #if DEV + var devButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Dev" ) + Hud_AddEventHandler( devButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "DevMenu" ) ) ) + #endif + + headerIndex++ + buttonIndex = 0 + var dummyHeader = AddComboButtonHeader( comboStruct, headerIndex, "" ) + var dummyButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "" ) + Hud_SetVisible( dummyHeader, false ) + Hud_SetVisible( dummyButton, false ) + + headerIndex++ + buttonIndex = 0 + file.settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + #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" ) ) ) + + //var dataCenterButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#DATA_CENTER" ) + //Hud_AddEventHandler( dataCenterButton, UIE_CLICK, OpenDataCenterDialog ) + + ComboButtons_Finalize( comboStruct ) + + file.comboStruct = comboStruct + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_CLOSE", "#CLOSE" ) +} + +void function OnInGameMPMenu_Open() +{ + Lobby_SetFDMode( GetCurrentPlaylistVarInt( "ingame_menu_fd_mode", 0 ) == 1 ) + UI_SetPresentationType( ePresentationType.DEFAULT ) + + bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew ) + + UpdateLoadoutButtons() + RefreshCreditsAvailable() + thread UpdateCachedNewItems() +} + +void function OnInGameMPMenu_Close() +{ + UI_SetPresentationType( ePresentationType.INACTIVE ) + + if ( IsConnected() && !IsLobby() && IsLevelMultiplayer( GetActiveLevel() ) ) + { + //printt( "OnInGameMPMenu_Close() uiGlobal.updatePilotSpawnLoadout is:", uiGlobal.updatePilotSpawnLoadout ) + //printt( "OnInGameMPMenu_Close() uiGlobal.updateTitanSpawnLoadout is:", uiGlobal.updateTitanSpawnLoadout ) + + string updatePilotSpawnLoadout = uiGlobal.updatePilotSpawnLoadout ? "1" : "0" + string updateTitanSpawnLoadout = uiGlobal.updateTitanSpawnLoadout ? "1" : "0" + + ClientCommand( "InGameMPMenuClosed " + updatePilotSpawnLoadout + " " + updateTitanSpawnLoadout ) + + uiGlobal.updatePilotSpawnLoadout = false + uiGlobal.updateTitanSpawnLoadout = false + + RunClientScript( "RefreshIntroLoadoutDisplay", GetLocalClientPlayer(), uiGlobal.pilotSpawnLoadoutIndex, uiGlobal.titanSpawnLoadoutIndex ) + } +} + +void function UpdateLoadoutButtons() +{ + bool loadoutSelectionEnabled = (GetCurrentPlaylistVarInt( "loadout_selection_enabled", 1 ) == 1) + + SetTitanSelectButtonVisibleState( true ) + + foreach ( button in file.loadoutButtons ) + { + Hud_SetEnabled( button, loadoutSelectionEnabled ) + } + + foreach ( header in file.loadoutHeaders ) + { + if ( loadoutSelectionEnabled ) + Hud_Show( header ) + else + Hud_Hide( header ) + } + + entity player = GetUIPlayer() + + if ( GetAvailableTitanRefs( player ).len() > 1 ) + { + SetComboButtonHeaderTitle( file.menuMP, file.titanHeaderIndex, "#MENU_HEADER_TITAN" ) + ComboButton_SetText( file.titanSelectButton, "#SELECT" ) + Hud_Show( file.titanEditButton ) + } + else if ( GetAvailableTitanRefs( player ).len() == 1 ) + { + TitanLoadoutDef loadout = GetCachedTitanLoadout( uiGlobal.titanSpawnLoadoutIndex ) + + SetComboButtonHeaderTitle( file.menuMP, file.titanHeaderIndex, GetTitanLoadoutName( loadout ) ) + ComboButton_SetText( file.titanSelectButton, "#EDIT" ) + + Hud_Hide( file.titanEditButton ) + ComboButtons_ResetColumnFocus( file.comboStruct ) + } + else + { + SetTitanSelectButtonVisibleState( true ) + } +} + +////////// + +////////// + +void function InitInGameSPMenu() +{ + var menu = GetMenu( "InGameSPMenu" ) + file.menuSP = menu + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnOpenInGameSPMenu ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnCloseInGameSPMenu ) + + ComboStruct comboStruct = ComboButtons_Create( menu ) + + int headerIndex = 0 + int buttonIndex = 0 + + // MISSION Menu + var missionHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_MISSION" ) + var resumeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#RESUME_GAME_SHORT" ) + Hud_AddEventHandler( resumeButton, UIE_CLICK, OnResumeGame_Activate ) + var lastCheckpointButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#LAST_CHECKPOINT" ) + Hud_AddEventHandler( lastCheckpointButton, UIE_CLICK, OnReloadCheckpoint_Activate ) + file.BtnLastCheckpoint = lastCheckpointButton + var restartButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#RESTART_LEVEL_SHORT" ) + Hud_AddEventHandler( restartButton, UIE_CLICK, OnRestartLevel_Activate ) + + // GAME Menu + // headerIndex++ + // buttonIndex = 0 + // var gameHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_GAME" ) + // var difficultyButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CHANGE_DIFFICULTY" ) + // Hud_AddEventHandler( difficultyButton, UIE_CLICK, OnChangeDifficulty_Activate ) + // var leaveButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#QUIT" ) + // Hud_AddEventHandler( leaveButton, UIE_CLICK, OnLeaveButton_Activate ) + + // SETTINGS Menu + headerIndex++ + buttonIndex = 0 + var settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + #if CONSOLE_PROG + var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) + Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) + #elseif PC_PROG + var audioButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) + Hud_AddEventHandler( audioButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) + var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) + Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) + #endif + + array orderedButtons + + var changeDifficultyBtn = Hud_GetChild( menu, "BtnChangeDifficulty" ) + + AddButtonEventHandler( changeDifficultyBtn, UIE_CLICK, OnChangeDifficulty_Activate ) + Hud_Show( changeDifficultyBtn ) + orderedButtons.append( changeDifficultyBtn ) + + var quitBtn = Hud_GetChild( menu, "BtnQuit" ) + SetButtonRuiText( quitBtn, "#QUIT" ) + AddButtonEventHandler( quitBtn, UIE_CLICK, OnLeaveButton_Activate ) + Hud_Show( quitBtn ) + orderedButtons.append( quitBtn ) + + // DEV button + var devButton = Hud_GetChild( menu, "BtnDev" ) + #if DEV + SetButtonRuiText( devButton, "--- Dev" ) + AddButtonEventHandler( devButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "DevMenu" ) ) ) + Hud_Show( devButton ) + orderedButtons.append( devButton ) + comboStruct.navUpButton = devButton + #else + Hud_Hide( devButton ) + comboStruct.navUpButton = quitBtn + #endif // DEV + + SetNavUpDown( orderedButtons ) + comboStruct.navDownButton = changeDifficultyBtn + + ComboButtons_Finalize( comboStruct ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_CLOSE", "#CLOSE" ) +} + + +void function OnOpenInGameSPMenu() +{ + var collectiblesFoundDesc = Hud_GetChild( file.menuSP, "CollectiblesFoundDesc" ) + var missionLogDesc = Hud_GetChild( file.menuSP, "MissionLogDesc" ) + var changeDifficultyBtn = Hud_GetChild( file.menuSP, "BtnChangeDifficulty" ) + + Hud_SetEnabled( file.BtnLastCheckpoint, HasValidSaveGame() ) + + int currentDifficulty = GetConVarInt( "sp_difficulty" ) + string newDifficultyString + + switch ( currentDifficulty ) + { + case 0: + newDifficultyString = "#CHANGE_DIFFICULTY_EASY" + break + + case 1: + newDifficultyString = "#CHANGE_DIFFICULTY_REGULAR" + break + + case 2: + newDifficultyString = "#CHANGE_DIFFICULTY_HARD" + break + + case 3: + newDifficultyString = "#CHANGE_DIFFICULTY_MASTER" + break + + default: + Assert( 0, "Unknown difficulty " + currentDifficulty ) + break + } + SetButtonRuiText( changeDifficultyBtn, newDifficultyString ) + + string activeLevelName = GetActiveLevel() + if ( activeLevelName != "" ) + { + var dataTable = GetDataTable( $"datatable/sp_levels_data.rpak" ) + + // Make sure this level actually has data to display. + bool levelHasData = false + int numRows = GetDatatableRowCount( dataTable ) + for ( int i = 0; i < numRows; i++ ) + { + string levelName = GetDataTableString( dataTable, i, GetDataTableColumnByName( dataTable, "level" ) ) + if ( activeLevelName == levelName ) + { + levelHasData = true + break + } + } + + if ( levelHasData ) + { + // Mission Log + int row = GetDataTableRowMatchingStringValue( dataTable, GetDataTableColumnByName( dataTable, "level" ), activeLevelName ) + string missionLog = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "missionLog" ) ) + + if ( uiGlobal.sp_showAlternateMissionLog ) + { + string alternateMissionLog = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "alternateMissionLog" ) ) + missionLog = alternateMissionLog + } + + Hud_SetText( missionLogDesc, missionLog ) + + // Collectibles + int foundLions = GetCollectiblesFoundForLevel( activeLevelName ) + int maxLions = GetMaxLionsInLevel( activeLevelName ) + Hud_SetText( collectiblesFoundDesc, "#MENU_SP_COLLECTIBLE_DESC", foundLions, maxLions ) + } + else + { + Hud_SetText( missionLogDesc, "#MENU_SP_OBJECTIVES_NO_ENTRY" ) + Hud_SetText( collectiblesFoundDesc, "#MENU_SP_COLLECTIBLE_DESC", 0, 0 ) + } + + // Make sure trial mode doesn't reveal any spoilers! + if ( Script_IsRunningTrialVersion() ) + Hud_SetText( missionLogDesc, "#MENU_SP_OBJECTIVES_NO_ENTRY" ) + } + + SPMenu_UpdateReloadCheckpointButton() +} + + +void function OnCloseInGameSPMenu() +{ + if ( file.SP_displayObjectiveOnClose ) + ClientCommand( "ShowObjective closedSPMenu" ) +} + +void function SPMenu_UpdateReloadCheckpointButton() +{ + if ( level.ui.playerRunningGauntlet ) + ComboButton_SetText( file.BtnLastCheckpoint, "#GAUNTLET_RESTART" ) + else + ComboButton_SetText( file.BtnLastCheckpoint, "#LAST_CHECKPOINT" ) +} + +void function MobilityDifficultyButton_Activate( var button ) +{ + OpenMobilityDifficultyMenu() +} + +void function OnLeaveButton_Activate( var button ) +{ + file.SP_displayObjectiveOnClose = false + LeaveDialog() +} + +void function OnRestartLevel_Activate( var button ) +{ + ShowAreYouSureDialog( "#MENU_RESTART_MISSION_CONFIRM", RestartMission, "#WARNING_LOSE_PROGRESS" ) +} + +void function OnChangeDifficulty_Activate( var button ) +{ + SPDifficultyButton_Click( button ) +} + +void function OnResumeGame_Activate( var button ) +{ + CloseActiveMenu() +} + +void function OnReloadCheckpoint_Activate( var button ) +{ + if ( level.ui.playerRunningGauntlet ) + { + CloseActiveMenu() + ClientCommand( "Gauntlet_PlayerRestartedFromMenu" ) + } + else + { + ShowAreYouSureDialog( "#MENU_RESTART_CHECKPOINT_CONFIRM", ReloadLastCheckpoint, "#EMPTY_STRING" ) + } +} + +void function ShowAreYouSureDialog( string header, void functionref() func, string details ) +{ + DialogData dialogData + dialogData.header = header + dialogData.message = details + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", func ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) +} + +void function RestartMission() +{ + file.SP_displayObjectiveOnClose = false + ClientCommand( "RestartMission" ) +} + +void function ReloadLastCheckpoint() +{ + file.SP_displayObjectiveOnClose = false + + printt( "SAVEGAME: Trying to load saveName" ) + if ( HasValidSaveGame() ) + { + printt( "SAVEGAME: Trying to load checkpoint from menu_ingame" ) + SaveGame_LoadWithStartPointFallback() + return + } + + ClientCommand( "RestartFromLevelTransition" ) +} + +void function SP_ResetObjectiveStringIndex() +{ + file.objectiveStringIndex = -1 +} + +void function ServerCallback_UI_ObjectiveUpdated( int stringIndex ) +{ + file.objectiveStringIndex = stringIndex +} + +void function ServerCallback_UI_UpdateMissionLog( bool showAltLog ) +{ + uiGlobal.sp_showAlternateMissionLog = showAltLog +} + +void function SPDifficultyButton_Click( var button ) +{ + DialogData dialogData + dialogData.header = "#SP_DIFFICULTY_MISSION_SELECT_TITLE" + + int currentDifficulty = GetConVarInt( "sp_difficulty" ) + dialogData.coloredButton[ currentDifficulty ] <- true + + if ( currentDifficulty == DIFFICULTY_EASY ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_EASY_TITLE", SPPickEasy, "#SP_DIFFICULTY_EASY_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_EASY_TITLE", SPPickEasy, "#SP_DIFFICULTY_EASY_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_NORMAL ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_NORMAL_TITLE", SPPickNormal, "#SP_DIFFICULTY_NORMAL_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_NORMAL_TITLE", SPPickNormal, "#SP_DIFFICULTY_NORMAL_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_HARD ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_HARD_TITLE", SPPickHard, "#SP_DIFFICULTY_HARD_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_HARD_TITLE", SPPickHard, "#SP_DIFFICULTY_HARD_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_MASTER ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_MASTER_TITLE", SPPickMaster, "#SP_DIFFICULTY_MASTER_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_MASTER_TITLE", SPPickMaster, "#SP_DIFFICULTY_MASTER_DESCRIPTION", false ) + + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + AddDialogPCBackButton( dialogData ) + + OpenDialog( dialogData ) +} + +void function SPPickEasy() +{ + RequestSPDifficultyChange( DIFFICULTY_EASY ) + CloseAllMenus() +} + +void function SPPickNormal() +{ + RequestSPDifficultyChange( DIFFICULTY_NORMAL ) + CloseAllMenus() +} + +void function SPPickHard() +{ + RequestSPDifficultyChange( DIFFICULTY_HARD ) + CloseAllMenus() +} + +void function SPPickMaster() +{ + RequestSPDifficultyChange( DIFFICULTY_MASTER ) + CloseAllMenus() +} + +void function RequestSPDifficultyChange( int selectedDifficulty ) +{ + var dataTable = GetDataTable( DATA_TABLE ) + int difficulty = GetDataTableInt( dataTable, selectedDifficulty, GetDataTableColumnByName( dataTable, "index" ) ) + + ClientCommand( "ClientCommand_RequestSPDifficultyChange " + difficulty ) +} + +void function SCB_SetDoubleXPStatus( int status ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + RuiSetInt( Hud_GetRui( doubleXPWidget ), "doubleXPStatus", status ) + + // update this menu too + TTSUpdateDoubleXPStatus( status ) +} + +void function OnInGameLevelInit() +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + RuiSetInt( rui, "doubleXPStatus", 0 ) + RuiSetBool( rui, "isVisible", false ) + + string gameModeScoreHint = expect string( GetCurrentPlaylistVar( "gamemode_score_hint" ) ) + if ( gameModeScoreHint != "" ) + { + RuiSetString( rui, "scoreMeritText", Localize( gameModeScoreHint ) ) + RuiSetInt( rui, "matchScoreMerit", MERIT_STATE_AVAILABLE ) + } + else + { + RuiSetString( rui, "scoreMeritText", "" ) + RuiSetInt( rui, "matchScoreMerit", MERIT_STATE_HIDDEN ) + } + + Hud_SetVisible( doubleXPWidget, !IsPrivateMatch() ) +} +/* +int matchScoreMerit = MERIT_STATE_AVAILABLE +int matchCompleteMerit = MERIT_STATE_AVAILABLE +int matchWinMerit = MERIT_STATE_AVAILABLE +int matchEvacMerit = MERIT_STATE_HIDDEN +int happyHourMerits = MERIT_STATE_HIDDEN + +int meritCount = 0 +*/ + +void function SCB_SetScoreMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchScoreMerit", meritState ) +} + +void function SCB_SetCompleteMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchCompleteMerit", meritState ) +} + +void function SCB_SetWinMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchWinMerit", meritState ) +} + +void function SCB_SetEvacMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchEvacMerit", meritState ) +} + +void function SCB_SetMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "meritCount", meritCount ) +} + +void function SCB_SetWeaponMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "weaponMeritCount", meritCount ) +} + +void function SCB_SetTitanMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "titanMeritCount", meritCount ) +} + +void function TitanSelectButtonHandler( var button ) +{ + if ( !IsFullyConnected() ) + return + + entity player = GetUIPlayer() + if ( GetAvailableTitanRefs( player ).len() > 1 ) + { + AdvanceMenu( GetMenu( "TitanLoadoutsMenu" ) ) + } + else if ( GetAvailableTitanRefs( player ).len() == 1 ) + { + uiGlobal.updateTitanSpawnLoadout = false + SetEditLoadout( "titan", uiGlobal.titanSpawnLoadoutIndex ) + + RunMenuClientFunction( "SetEditingTitanLoadoutIndex", uiGlobal.titanSpawnLoadoutIndex ) + AdvanceMenu( GetMenu( "EditTitanLoadoutMenu" ) ) + } + else + { + // HIDE + } +} + +void function SetTitanSelectButtonVisibleState( bool state ) +{ + if ( state ) + { + Hud_Show( file.titanHeader ) + Hud_Show( file.titanEditButton ) + Hud_Show( file.titanSelectButton ) + } + else + { + ComboButtons_ResetColumnFocus( file.comboStruct ) + Hud_Hide( file.titanHeader ) + Hud_Hide( file.titanEditButton ) + Hud_Hide( file.titanSelectButton ) + } +} -- cgit v1.2.3 From db2434b524c284913c91556c75ff1ebd4226c96e Mon Sep 17 00:00:00 2001 From: Emma Miler Date: Tue, 11 Apr 2023 20:49:35 +0200 Subject: New presence code for plugins v2 (#532) * test * Update cl_presence.nut * Update Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut * Apply suggestions from code review * New scripts * fix playlist and add native funcs to build * remove snake cases from GameStateStruct * I forgor --------- Co-authored-by: cat_or_not <41955154+catornot@users.noreply.github.com> --- .github/nativefuncs.json | 12 +++ Northstar.Client/mod.json | 1 + .../scripts/vscripts/cl_northstar_client_init.nut | 22 +++++ .../mod/scripts/vscripts/presence/cl_presence.nut | 95 +++++++++------------- .../mod/scripts/vscripts/presence/ui_presence.nut | 42 ++-------- .../mod/scripts/vscripts/ui/_menus.nut | 2 + .../mod/scripts/vscripts/ui/menu_lobby.nut | 2 - .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 12 --- 8 files changed, 85 insertions(+), 103 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 50bba0e5..f52a969c 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -325,6 +325,12 @@ "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", "returnTypeString":"bool", "argTypes":"" + }, + { + "name":"NSPushGameStateData", + "helpText":"", + "returnTypeString":"void", + "argTypes":"struct gamestate" } ], "UI":[ @@ -639,6 +645,12 @@ "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", "returnTypeString":"bool", "argTypes":"" + }, + { + "name":"NSPushUIPresence", + "helpText":"", + "returnTypeString":"void", + "argTypes":"struct presence" } ] } \ No newline at end of file diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index d52f95fc..f0f45e67 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -3,6 +3,7 @@ "Description": "Various ui and client changes to fix bugs and add better support for mods", "Version": "1.12.0", "LoadPriority": 0, + "InitScript": "cl_northstar_client_init.nut", "ConVars": [ { "Name": "filter_hide_empty", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut new file mode 100644 index 00000000..212568d0 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -0,0 +1,22 @@ +global struct GameStateStruct { + + string map + string mapDisplayname + + string playlist + string playlistDisplayname + + int currentPlayers + int maxPlayers + int ownScore + int otherHighestScore + int maxScore + float timeEnd +} + +global struct UIPresenceStruct { + bool isLoading + bool isLobby + string loadingLevel + string loadedLevel +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut index 755396e3..c8a8274a 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut @@ -1,60 +1,45 @@ untyped globalize_all_functions -struct { - int highestScore = 0 - int secondHighestScore = 0 -} file - -void function OnPrematchStart() -{ - if ( GetServerVar( "roundBased" ) ) - NSUpdateTimeInfo( level.nv.roundEndTime - Time() ) - else - NSUpdateTimeInfo( level.nv.gameEndTime - Time() ) -} - -void function NSUpdateGameStateClientStart() -{ - #if MP - AddCallback_GameStateEnter( eGameState.Prematch, OnPrematchStart ) - #endif - - thread NSUpdateGameStateLoopClient() - OnPrematchStart() -} - -void function NSUpdateGameStateLoopClient() -{ - while ( true ) +void function NorthstarCodeCallback_GenerateGameState() { + + GameStateStruct gs + + int highestScore = 0 + int secondHighest = 0 + + foreach ( player in GetPlayerArray() ) { - if ( IsSingleplayer() ) - { - NSUpdateGameStateClient( GetPlayerArray().len(), GetCurrentPlaylistVarInt( "max_players", 65535 ), 1, 1, 1, GetServerVar( "roundBased" ), 1 ) - wait 1.0 - } - else - { - foreach ( player in GetPlayerArray() ) - { - if ( GameRules_GetTeamScore( player.GetTeam() ) >= file.highestScore ) - { - file.highestScore = GameRules_GetTeamScore( player.GetTeam() ) - } - else if ( GameRules_GetTeamScore( player.GetTeam() ) > file.secondHighestScore ) - { - file.secondHighestScore = GameRules_GetTeamScore( player.GetTeam() ) - } - } - - int ourScore = 0 - if ( IsValid( GetLocalClientPlayer() ) ) - ourScore = GameRules_GetTeamScore( GetLocalClientPlayer().GetTeam() ) - - int limit = IsRoundBased() ? GetCurrentPlaylistVarInt( "roundscorelimit", 0 ) : GetCurrentPlaylistVarInt( "scorelimit", 0 ) - NSUpdateGameStateClient( GetPlayerArray().len(), GetCurrentPlaylistVarInt( "max_players", 65535 ), ourScore, file.secondHighestScore, file.highestScore, GetServerVar( "roundBased" ), limit ) - OnPrematchStart() - wait 1.0 - } + if ( GameRules_GetTeamScore( player.GetTeam() ) >= highestScore ) + { + highestScore = GameRules_GetTeamScore( player.GetTeam() ) + } + else if ( GameRules_GetTeamScore( player.GetTeam() ) > secondHighest ) + { + secondHighest = GameRules_GetTeamScore( player.GetTeam() ) + } } -} + + gs.map = GetMapName() + gs.mapDisplayname = Localize(GetMapDisplayName(GetMapName())) + + gs.playlist = GetCurrentPlaylistName() + gs.playlistDisplayname = Localize(GetCurrentPlaylistVarString("name", GetCurrentPlaylistName())) + + gs.currentPlayers = GetPlayerArray().len() + gs.maxPlayers = GetCurrentPlaylistVarInt( "maxPlayers", -1 ) + + if ( IsValid( GetLocalClientPlayer() ) ) + gs.ownScore = GameRules_GetTeamScore( GetLocalClientPlayer().GetTeam() ) + + gs.otherHighestScore = gs.ownScore == highestScore ? secondHighest : highestScore + + gs.maxScore = IsRoundBased() ? GetCurrentPlaylistVarInt( "roundscorelimit", 0 ) : GetCurrentPlaylistVarInt( "scorelimit", 0 ) + + if ( GetServerVar( "roundBased" ) ) + gs.timeEnd = expect float(level.nv.roundEndTime - Time()) + else + gs.timeEnd = expect float(level.nv.gameEndTime - Time()) + + NSPushGameStateData(gs) +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut index 1e381989..cdf1c981 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut @@ -1,38 +1,12 @@ untyped globalize_all_functions -void function NSUpdateGameStateUIStart() -{ - thread NSUpdateGameStateLoopUI() -} +void function NorthstarCodeCallback_GenerateUIPresence() { + UIPresenceStruct uis -void function NSUpdateGameStateLoopUI() -{ - while ( true ) - { - wait 1.0 - - if ( uiGlobal.loadedLevel == "" ) - { - if ( uiGlobal.isLoading ) - NSSetLoading( true ) - else - { - NSSetLoading( false ) - NSUpdateGameStateUI( "", "", "", "", true, false ) - } - - continue - } - - NSSetLoading( false ) - if( GetConVarString( "mp_gamemode" ) == "solo" ) - { - NSUpdateGameStateUI( GetActiveLevel(), Localize( GetMapDisplayName( GetActiveLevel() + "_CAMPAIGN_NAME" ) ), "Campaign", "Campaign", IsFullyConnected(), false ) - } - else - { - NSUpdateGameStateUI( GetActiveLevel(), Localize( GetMapDisplayName( GetActiveLevel() ) ), GetConVarString( "mp_gamemode" ), Localize( GetPlaylistDisplayName( GetConVarString( "mp_gamemode" ) ) ), IsFullyConnected(), false ) - } - } -} + uis.isLoading = uiGlobal.isLoading + uis.isLobby = IsLobby() + uis.loadingLevel = uiGlobal.loadingLevel + uis.loadedLevel = uiGlobal.loadedLevel + NSPushUIPresence(uis) +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut index 90a535ee..c83381fd 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut @@ -187,6 +187,7 @@ bool function UICodeCallback_LevelLoadingStarted( string levelname ) CloseAllDialogs() uiGlobal.loadingLevel = levelname + uiGlobal.isLoading = true StopMusic() @@ -235,6 +236,7 @@ void function UICodeCallback_LevelLoadingFinished( bool error ) } uiGlobal.loadingLevel = "" + uiGlobal.isLoading = false Signal( uiGlobal.signalDummy, "LevelFinishedLoading" ) } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 938e0d3f..3c868aab 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -372,8 +372,6 @@ void function StartPrivateMatch( var button ) return ClientCommand( "StartPrivateMatchSearch" ) - NSSetLoading(true) - NSUpdateListenServer() } void function DoRoomInviteIfAllowed( var button ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 03028255..b2e2a8b6 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1058,18 +1058,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) } file.cancelConnection = false - NSSetLoading( true ) - NSUpdateServerInfo( - NSGetServerID( file.lastSelectedServer ), - NSGetServerName( file.lastSelectedServer ), - password, - NSGetServerPlayerCount( file.lastSelectedServer ), - NSGetServerMaxPlayerCount( file.lastSelectedServer ), - NSGetServerMap( file.lastSelectedServer ), - Localize( GetMapDisplayName( NSGetServerMap( file.lastSelectedServer ) ) ), - NSGetServerPlaylist( file.lastSelectedServer ), - Localize( GetPlaylistDisplayName( NSGetServerPlaylist( file.lastSelectedServer ) ) ) - ) if ( NSWasAuthSuccessful() ) { -- cgit v1.2.3 From ecfdf4a47beb94f90a91e0ccac25d95b5c5f3cbb Mon Sep 17 00:00:00 2001 From: pg9182 <96569817+pg9182@users.noreply.github.com> Date: Thu, 20 Apr 2023 18:22:54 -0400 Subject: Improve server connection error messages (#598) * Also show masterserver error for server connections It's already used for self auth and is available for both, but we currently only show it for the former. * Don't localize server connection errors It never fully worked, and it's more useful to have non-localized detailed error messages. * Don't prepend NS_SERVERBROWSER_CONNECTIONFAILED to server conn err msg The message always contains something like it, and it's always right after a connectiom anyways. * NSGetAuthFailReason always returns a string, so don't make it untyped --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 4 +++- Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index b2e2a8b6..b663a25a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1085,9 +1085,11 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) } else { + string reason = NSGetAuthFailReason() + DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Authentication Failed" + dialogData.message = reason dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index 95b7bdae..53d85387 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -571,12 +571,12 @@ void function TryAuthWithLocalServer() { CloseAllDialogs() - var reason = NSGetAuthFailReason() + string reason = NSGetAuthFailReason() DialogData dialogData dialogData.image = $"ui/menu/common/dialog_error" dialogData.header = "#ERROR" - dialogData.message = Localize("#NS_SERVERBROWSER_CONNECTIONFAILED") + "\nERROR: " + reason + "\n" + Localize("#" + reason) + dialogData.message = reason AddDialogButton( dialogData, "#OK", null ) OpenDialog( dialogData ) -- cgit v1.2.3 From c89364cdef3b78c09723733e759d124c8dd76838 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 23 Apr 2023 14:28:00 +0200 Subject: Bump mods version to `1.13.0` (#627) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index f0f45e67..00b779a4 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 374e13e4..66d29cae 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 657854da..e1df99ba 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 2d6ca83c3ab5f045dfbc5d0a167b925112b2bd84 Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:55:32 +0000 Subject: Use structs in the server browser (#623) * move to native structs * add connect callbacks * update native functions register * trigger callbacks on double click * use suggestions --- .github/nativefuncs.json | 74 +----- .../scripts/vscripts/cl_northstar_client_init.nut | 23 +- .../vscripts/ui/menu_ns_connect_password.nut | 3 + .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 254 +++++++++++---------- 4 files changed, 165 insertions(+), 189 deletions(-) (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index f52a969c..751b4893 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -449,76 +449,10 @@ "argTypes":"" }, { - "name":"NSGetServerName", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerDescription", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerMap", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerPlaylist", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerPlayerCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerMaxPlayerCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerID", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSServerRequiresPassword", - "helpText":"", - "returnTypeString":"bool", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRequiredModsCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRegion", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRequiredModName", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex, int modIndex" - }, - { - "name":"NSGetServerRequiredModVersion", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex, int modIndex" + "name": "NSGetGameServers", + "helpText": "Gets all fetched servers", + "returnTypeString": "array", + "argTypes": "" }, { "name":"NSClearRecievedServerList", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 212568d0..2a2ed3db 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -19,4 +19,25 @@ global struct UIPresenceStruct { bool isLobby string loadingLevel string loadedLevel -} \ No newline at end of file +} + +global struct RequiredModInfo +{ + string name + string version +} + +global struct ServerInfo +{ + int index + string id + string name + string description + string map + string playlist + int playerCount + int maxPlayerCount + bool requiresPassword + string region + array< RequiredModInfo > requiredMods +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index b5a2e9b6..1e10aa45 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -54,5 +54,8 @@ void function OnConnectWithPasswordMenuOpened() void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) + { + TriggerConnectToServerCallbacks() thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index b663a25a..c31185ee 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -4,6 +4,9 @@ untyped global function AddNorthstarServerBrowserMenu global function ThreadedAuthAndConnectToServer +global function AddConnectToServerCallback +global function RemoveConnectToServerCallback +global function TriggerConnectToServerCallbacks // Stop peeking @@ -67,7 +70,6 @@ struct serverStruct { struct { // UI state vars var menu - int lastSelectedServer = 999 int focusedServerIndex = 0 int scrollOffset = 0 bool serverListRequestFailed = false @@ -79,6 +81,10 @@ struct { // filtered array of servers array serversArrayFiltered + + array filteredServers + ServerInfo& focusedServer + ServerInfo& lastSelectedServer // UI references array serverButtons @@ -88,6 +94,8 @@ struct { array serversMap array serversGamemode array serversRegion + + array< void functionref( ServerInfo ) > connectCallbacks } file @@ -253,7 +261,7 @@ void function FlushMouseDeltaBuffer() void function SliderBarUpdate() { - if ( file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE ) + if ( file.filteredServers.len() <= BUTTONS_PER_PAGE ) { FlushMouseDeltaBuffer() return @@ -270,7 +278,7 @@ void function SliderBarUpdate() float maxYPos = minYPos - ( maxHeight - Hud_GetHeight( sliderPanel ) ) float useableSpace = ( maxHeight - Hud_GetHeight( sliderPanel ) ) - float jump = minYPos - ( useableSpace / ( float( file.serversArrayFiltered.len() ) ) ) + float jump = minYPos - ( useableSpace / ( float( file.filteredServers.len() ) ) ) // got local from official respaw scripts, without untyped throws an error local pos = Hud_GetPos( sliderButton )[1] @@ -284,7 +292,7 @@ void function SliderBarUpdate() Hud_SetPos( sliderPanel , 2, newPos ) Hud_SetPos( movementCapture , 2, newPos ) - file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.serversArrayFiltered.len() - BUTTONS_PER_PAGE ) ) + file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.filteredServers.len() - BUTTONS_PER_PAGE ) ) UpdateShownPage() } @@ -328,13 +336,13 @@ void function UpdateListSliderPosition( int servers ) void function OnScrollDown( var button ) { - if (file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE) return + if (file.filteredServers.len() <= BUTTONS_PER_PAGE) return file.scrollOffset += 5 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len()) { - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + if (file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len()) { + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } void function OnScrollUp( var button ) @@ -344,7 +352,7 @@ void function OnScrollUp( var button ) file.scrollOffset = 0 } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } //////////////////////////// @@ -484,7 +492,7 @@ void function OnHitDummyTop( var button ) { // only update if list position changed UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) DisplayFocusedServerInfo( file.serverButtonFocusedID ) Hud_SetFocused( Hud_GetChild( file.menu, "BtnServer1" ) ) } @@ -493,10 +501,10 @@ void function OnHitDummyTop( var button ) void function OnHitDummyBottom( var button ) { file.scrollOffset += 1 - if ( file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len() ) + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len() ) { // was at bottom already - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE Hud_SetFocused( Hud_GetChild( file.menu, "BtnServerSearch" ) ) HideServerInfo() } @@ -504,7 +512,7 @@ void function OnHitDummyBottom( var button ) { // only update if list position changed UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) DisplayFocusedServerInfo( file.serverButtonFocusedID ) Hud_SetFocused( Hud_GetChild( file.menu, "BtnServer15" ) ) } @@ -518,15 +526,15 @@ void function OnHitDummyAfterFilterClear( var button ) void function OnDownArrowSelected( var button ) { - if ( file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE ) return + if ( file.filteredServers.len() <= BUTTONS_PER_PAGE ) return file.scrollOffset += 1 - if ( file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len() ) + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len() ) { - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } @@ -539,7 +547,7 @@ void function OnUpArrowSelected( var button ) } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } //////////////////////// @@ -642,7 +650,7 @@ void function FilterAndUpdateList( var n ) filterArguments.hideProtected = GetConVarBool( "filter_hide_protected" ) file.scrollOffset = 0 - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) HideServerInfo() FilterServerList() @@ -741,51 +749,42 @@ void function WaitForServerListRequest() void function FilterServerList() { - file.serversArrayFiltered.clear() + file.filteredServers.clear() int totalPlayers = 0 - for ( int i = 0; i < NSGetServerCount(); i++ ) - { - serverStruct tempServer - tempServer.serverIndex = i - tempServer.serverProtected = NSServerRequiresPassword( i ) - tempServer.serverName = NSGetServerName( i ) - tempServer.serverPlayers = NSGetServerPlayerCount( i ) - tempServer.serverPlayersMax = NSGetServerMaxPlayerCount( i ) - tempServer.serverMap = NSGetServerMap( i ) - tempServer.serverGamemode = GetGameModeDisplayName( NSGetServerPlaylist ( i ) ) - tempServer.serverRegion = NSGetServerRegion( i ) - - totalPlayers += tempServer.serverPlayers + array servers = NSGetGameServers() + foreach ( ServerInfo server in servers ) + { + totalPlayers += server.playerCount // Filters - if ( filterArguments.hideEmpty && tempServer.serverPlayers == 0 ) + if ( filterArguments.hideEmpty && server.playerCount == 0 ) continue; - if ( filterArguments.hideFull && tempServer.serverPlayers == tempServer.serverPlayersMax ) + if ( filterArguments.hideFull && server.playerCount == server.maxPlayerCount ) continue; - if ( filterArguments.hideProtected && tempServer.serverProtected ) + if ( filterArguments.hideProtected && server.requiresPassword ) continue; - if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != tempServer.serverMap ) + if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != server.map ) continue; - if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != tempServer.serverGamemode ) + if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != server.playlist ) continue; - + // Search if ( filterArguments.useSearch ) { array sName - sName.append( tempServer.serverName.tolower() ) - sName.append( Localize( GetMapDisplayName( tempServer.serverMap ) ).tolower() ) - sName.append( tempServer.serverMap.tolower() ) - sName.append( tempServer.serverGamemode.tolower() ) - sName.append( Localize( tempServer.serverGamemode ).tolower() ) - sName.append( NSGetServerDescription( i ).tolower() ) - sName.append( NSGetServerRegion( i ).tolower() ) + sName.append( server.name.tolower() ) + sName.append( Localize( GetMapDisplayName( server.map ) ).tolower() ) + sName.append( server.map.tolower() ) + sName.append( server.playlist.tolower() ) + sName.append( Localize( server.playlist ).tolower() ) + sName.append( server.description.tolower() ) + sName.append( server.region.tolower() ) string sTerm = filterArguments.searchTerm.tolower() @@ -799,9 +798,8 @@ void function FilterServerList() if ( !found ) continue; } - - // Server fits our requirements, add it to the list - file.serversArrayFiltered.append( tempServer ) + + file.filteredServers.append( server ) } // Update player and server count @@ -824,23 +822,22 @@ void function UpdateShownPage() Hud_SetText( file.serversRegion[ i ], "" ) } - int j = file.serversArrayFiltered.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.serversArrayFiltered.len() + int j = file.filteredServers.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.filteredServers.len() for ( int i = 0; i < j; i++ ) { - int buttonIndex = file.scrollOffset + i - int serverIndex = file.serversArrayFiltered[ buttonIndex ].serverIndex + ServerInfo server = file.filteredServers[ buttonIndex ] Hud_SetEnabled( file.serverButtons[ i ], true ) Hud_SetVisible( file.serverButtons[ i ], true ) - Hud_SetVisible( file.serversProtected[ i ], file.serversArrayFiltered[ buttonIndex ].serverProtected ) - Hud_SetText( file.serversName[ i ], file.serversArrayFiltered[ buttonIndex ].serverName ) - Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", file.serversArrayFiltered[ buttonIndex ].serverPlayers, file.serversArrayFiltered[ buttonIndex ].serverPlayersMax ) ) - Hud_SetText( file.serversMap[ i ], GetMapDisplayName( file.serversArrayFiltered[ buttonIndex ].serverMap ) ) - Hud_SetText( file.serversGamemode[ i ], file.serversArrayFiltered[ buttonIndex ].serverGamemode ) - Hud_SetText( file.serversRegion[ i ], file.serversArrayFiltered[ buttonIndex ].serverRegion ) + Hud_SetVisible( file.serversProtected[ i ], server.requiresPassword ) + Hud_SetText( file.serversName[ i ], server.name ) + Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", server.playerCount, server.maxPlayerCount ) ) + Hud_SetText( file.serversMap[ i ], GetMapDisplayName( server.map ) ) + Hud_SetText( file.serversGamemode[ i ], GetGameModeDisplayName( server.playlist ) ) + Hud_SetText( file.serversRegion[ i ], server.region ) } @@ -850,7 +847,7 @@ void function UpdateShownPage() Hud_SetVisible( file.serverButtons[ 0 ], true ) Hud_SetText( file.serversName[ 0 ], "#NS_SERVERBROWSER_NOSERVERS" ) } - UpdateListSliderHeight( float( file.serversArrayFiltered.len() ) ) + UpdateListSliderHeight( float( file.filteredServers.len() ) ) } void function OnServerButtonFocused( var button ) @@ -860,8 +857,9 @@ void function OnServerButtonFocused( var button ) int scriptID = int ( Hud_GetScriptID( button ) ) file.serverButtonFocusedID = scriptID - if ( file.serversArrayFiltered.len() > 0 ) - file.focusedServerIndex = file.serversArrayFiltered[ file.scrollOffset + scriptID ].serverIndex + if ( file.filteredServers.len() > 0 ) + // file.focusedServerIndex = file.filteredServers[ file.scrollOffset + scriptID ].serverIndex + file.focusedServer = file.filteredServers[ file.scrollOffset + scriptID ] DisplayFocusedServerInfo( scriptID ) } @@ -882,13 +880,12 @@ void function CheckDoubleClick( int scriptID, bool wasClickNav ) int serverIndex = file.scrollOffset + scriptID bool sameServer = false - if ( file.lastSelectedServer == serverIndex ) sameServer = true - + if ( file.lastSelectedServer == file.filteredServers[ serverIndex ] ) sameServer = true file.serverSelectedTimeLast = file.serverSelectedTime file.serverSelectedTime = Time() - file.lastSelectedServer = serverIndex + file.lastSelectedServer = file.filteredServers[ serverIndex ] if ( wasClickNav && ( file.serverSelectedTime - file.serverSelectedTimeLast < DOUBLE_CLICK_TIME_MS ) && sameServer ) { @@ -900,7 +897,7 @@ void function DisplayFocusedServerInfo( int scriptID ) { if ( scriptID == 999 || scriptID == -1 || scriptID == 16 ) return - if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed || file.serversArrayFiltered.len() == 0 ) + if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed || file.filteredServers.len() == 0 ) return var menu = GetMenu( "ServerBrowserMenu" ) @@ -908,6 +905,7 @@ void function DisplayFocusedServerInfo( int scriptID ) int serverIndex = file.scrollOffset + scriptID if ( serverIndex < 0 ) serverIndex = 0 + ServerInfo server = file.filteredServers[ serverIndex ] Hud_SetVisible( Hud_GetChild( menu, "BtnServerDescription" ), true ) Hud_SetVisible( Hud_GetChild( menu, "BtnServerMods" ), true ) @@ -915,39 +913,39 @@ void function DisplayFocusedServerInfo( int scriptID ) // text panels Hud_SetVisible( Hud_GetChild( menu, "LabelDescription" ), true ) Hud_SetVisible( Hud_GetChild( menu, "LabelMods" ), false ) - Hud_SetText( Hud_GetChild( menu, "LabelDescription" ), NSGetServerDescription( file.serversArrayFiltered[ serverIndex ].serverIndex ) + "\n\nRequired Mods:\n" + FillInServerModsLabel( file.serversArrayFiltered[ serverIndex ].serverIndex ) ) + Hud_SetText( Hud_GetChild( menu, "LabelDescription" ), server.description + "\n\nRequired Mods:\n" + FillInServerModsLabel( server.requiredMods ) ) // map name/image/server name - string map = file.serversArrayFiltered[ serverIndex ].serverMap + string map = server.map Hud_SetVisible( Hud_GetChild( menu, "NextMapImage" ), true ) Hud_SetVisible( Hud_GetChild( menu, "NextMapBack" ), true ) RuiSetImage( Hud_GetRui( Hud_GetChild( menu, "NextMapImage" ) ), "basicImage", GetMapImageForMapName( map ) ) Hud_SetVisible( Hud_GetChild( menu, "NextMapName" ), true ) Hud_SetText( Hud_GetChild( menu, "NextMapName" ), GetMapDisplayName( map ) ) Hud_SetVisible( Hud_GetChild( menu, "ServerName" ), true ) - Hud_SetText( Hud_GetChild( menu, "ServerName" ), NSGetServerName( file.serversArrayFiltered[ serverIndex ].serverIndex ) ) + Hud_SetText( Hud_GetChild( menu, "ServerName" ), server.name ) // mode name/image - string mode = file.serversArrayFiltered[ serverIndex ].serverGamemode + string mode = server.playlist Hud_SetVisible( Hud_GetChild( menu, "NextModeIcon" ), true ) RuiSetImage( Hud_GetRui( Hud_GetChild( menu, "NextModeIcon" ) ), "basicImage", GetPlaylistThumbnailImage( mode ) ) Hud_SetVisible( Hud_GetChild( menu, "NextGameModeName" ), true ) if ( mode.len() != 0 ) - Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), mode ) + Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), GetGameModeDisplayName( mode ) ) else Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), "#NS_SERVERBROWSER_UNKNOWNMODE" ) } -string function FillInServerModsLabel( int server ) +string function FillInServerModsLabel( array mods ) { string ret - for ( int i = 0; i < NSGetServerRequiredModsCount( server ); i++ ) + foreach ( RequiredModInfo mod in mods ) { - ret += " " - ret += NSGetServerRequiredModName( server, i ) + " v" + NSGetServerRequiredModVersion( server, i ) + "\n" + ret += format( " %s v%s\n", mod.name, mod.version ) } + return ret } @@ -957,18 +955,17 @@ void function OnServerSelected( var button ) if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return - int serverIndex = file.focusedServerIndex + ServerInfo server = file.focusedServer - file.lastSelectedServer = serverIndex + file.lastSelectedServer = server - // check mods - for ( int i = 0; i < NSGetServerRequiredModsCount( serverIndex ); i++ ) + foreach ( RequiredModInfo mod in server.requiredMods ) { - if ( !NSGetModNames().contains( NSGetServerRequiredModName( serverIndex, i ) ) ) + if ( !NSGetModNames().contains( mod.name ) ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Missing mod \"" + NSGetServerRequiredModName( serverIndex, i ) + "\" v" + NSGetServerRequiredModVersion( serverIndex, i ) + dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG @@ -985,8 +982,8 @@ void function OnServerSelected( var button ) else { // this uses semver https://semver.org - array serverModVersion = split( NSGetServerRequiredModVersion( serverIndex, i ), "." ) - array clientModVersion = split( NSGetModVersionByModName( NSGetServerRequiredModName( serverIndex, i ) ), "." ) + array serverModVersion = split( mod.name, "." ) + array clientModVersion = split( NSGetModVersionByModName( mod.name ), "." ) bool semverFail = false // if server has invalid semver don't bother checking @@ -1004,7 +1001,7 @@ void function OnServerSelected( var button ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Server has mod \"" + NSGetServerRequiredModName( serverIndex, i ) + "\" v" + NSGetServerRequiredModVersion( serverIndex, i ) + " while we have v" + NSGetModVersionByModName( NSGetServerRequiredModName( serverIndex, i ) ) + dialogData.message = format( "Server has mod \"%s\" v%s while we have v%s", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG @@ -1021,13 +1018,16 @@ void function OnServerSelected( var button ) } } - if ( NSServerRequiresPassword( serverIndex ) ) + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else + { + TriggerConnectToServerCallbacks() thread ThreadedAuthAndConnectToServer() + } } @@ -1036,9 +1036,7 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSIsAuthenticatingWithServer() ) return - print( "trying to authenticate with server " + NSGetServerName( file.lastSelectedServer ) + " with password " + password ) - - NSTryAuthWithServer( file.lastSelectedServer, password ) + NSTryAuthWithServer( file.lastSelectedServer.index, password ) ToggleConnectingHUD( true ) @@ -1063,17 +1061,13 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) { bool modsChanged - array requiredMods - for ( int i = 0; i < NSGetServerRequiredModsCount( file.lastSelectedServer ); i++ ) - requiredMods.append( NSGetServerRequiredModName( file.lastSelectedServer, i ) ) - // unload mods we don't need, load necessary ones and reload mods before connecting - foreach ( string mod in NSGetModNames() ) + foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) { - if ( NSIsModRequiredOnClient( mod ) ) + if ( NSIsModRequiredOnClient( mod.name ) ) { - modsChanged = modsChanged || NSIsModEnabled( mod ) != requiredMods.contains( mod ) - NSSetModEnabled( mod, requiredMods.contains( mod ) ) + modsChanged = modsChanged || NSIsModEnabled( mod.name ) != file.lastSelectedServer.requiredMods.contains( mod ) + NSSetModEnabled( mod.name, file.lastSelectedServer.requiredMods.contains( mod ) ) } } @@ -1106,7 +1100,7 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) ////////////////////////////////////// // Shadow realm ////////////////////////////////////// -int function ServerSortLogic ( serverStruct a, serverStruct b ) +int function ServerSortLogic ( ServerInfo a, ServerInfo b ) { var aTemp var bTemp @@ -1117,44 +1111,44 @@ int function ServerSortLogic ( serverStruct a, serverStruct b ) switch ( filterDirection.sortingBy ) { case sortingBy.DEFAULT: - aTemp = a.serverPlayers - bTemp = b.serverPlayers + aTemp = a.playerCount + bTemp = b.playerCount // `1000` is assumed to always be higher than `serverPlayersMax` - if (aTemp + 1 < a.serverPlayersMax) + if (aTemp + 1 < a.maxPlayerCount) aTemp = aTemp+2000 - if (bTemp + 1 < b.serverPlayersMax) + if (bTemp + 1 < b.maxPlayerCount) bTemp = bTemp+2000 - if (aTemp + 1 == a.serverPlayersMax) + if (aTemp + 1 == a.maxPlayerCount) aTemp = aTemp+1000 - if (bTemp + 1 == b.serverPlayersMax) + if (bTemp + 1 == b.maxPlayerCount) bTemp = bTemp+1000 direction = filterDirection.serverName break; case sortingBy.NAME: - aTemp = a.serverName.tolower() - bTemp = b.serverName.tolower() + aTemp = a.name.tolower() + bTemp = b.name.tolower() direction = filterDirection.serverName break; case sortingBy.PLAYERS: - aTemp = a.serverPlayers - bTemp = b.serverPlayers + aTemp = a.playerCount + bTemp = b.playerCount direction = filterDirection.serverPlayers break; case sortingBy.MAP: - aTemp = Localize( a.serverMap ).tolower() - bTemp = Localize( b.serverMap ).tolower() + aTemp = Localize( a.map ).tolower() + bTemp = Localize( b.map ).tolower() direction = filterDirection.serverMap break; case sortingBy.GAMEMODE: - aTemp = Localize( a.serverGamemode ).tolower() - bTemp = Localize( b.serverGamemode ).tolower() + aTemp = Localize( a.playlist ).tolower() + bTemp = Localize( b.playlist ).tolower() direction = filterDirection.serverGamemode break; case sortingBy.REGION: - aTemp = a.serverRegion - bTemp = b.serverRegion + aTemp = a.region + bTemp = b.region direction = filterDirection.serverRegion break; default: @@ -1176,7 +1170,7 @@ void function SortServerListByDefault_Activate ( var button ) { filterDirection.sortingBy = sortingBy.DEFAULT - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverName = !filterDirection.serverName @@ -1188,7 +1182,7 @@ void function SortServerListByName_Activate ( var button ) { filterDirection.sortingBy = sortingBy.NAME - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverName = !filterDirection.serverName @@ -1200,7 +1194,7 @@ void function SortServerListByPlayers_Activate( var button ) { filterDirection.sortingBy = sortingBy.PLAYERS - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverPlayers = !filterDirection.serverPlayers @@ -1211,7 +1205,7 @@ void function SortServerListByMap_Activate( var button ) { filterDirection.sortingBy = sortingBy.MAP - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverMap = !filterDirection.serverMap @@ -1222,7 +1216,7 @@ void function SortServerListByGamemode_Activate( var button ) { filterDirection.sortingBy = sortingBy.GAMEMODE - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverGamemode = !filterDirection.serverGamemode @@ -1233,9 +1227,33 @@ void function SortServerListByRegion_Activate( var button ) { filterDirection.sortingBy = sortingBy.REGION - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverRegion = !filterDirection.serverRegion UpdateShownPage() } + +////////////////////////////////////// +// Callbacks +////////////////////////////////////// + +void function AddConnectToServerCallback( void functionref( ServerInfo ) callback ) +{ + if ( file.connectCallbacks.find( callback ) >= 0 ) + throw "ConnectToServerCallback has been registered twice. Duplicate callbacks are not allowed." + file.connectCallbacks.append( callback ) +} + +void function RemoveConnectToServerCallback( void functionref( ServerInfo ) callback ) +{ + file.connectCallbacks.fastremovebyvalue( callback ) +} + +void function TriggerConnectToServerCallbacks() +{ + foreach( callback in file.connectCallbacks ) + { + callback( file.lastSelectedServer ) + } +} -- cgit v1.2.3 From 0c14242f758d294187cd9cfbe7057bbe239d1ee1 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Mon, 1 May 2023 02:56:11 +0200 Subject: Add Bounty Hunt (#634) * Unlock bountyhunt in mode select menu * Initial push * Go through bank functions * Bug spotting * dissolve droppods faster * better camp hack solution * Revert wave start to 1st wave * Small formatting cleanup * Limit score to max playlist allows * Try to make ai camps work * Potentially fix winner not being set * metal pipe falling sound effect * Acteally document change * Better fix for match not properly ending * Add MVP dialogue (#631) * MVP dialogue and small audio fix * maybe better AI movement * revert accidental change * Remove comment about a already fixed issue * Revert froce assault point waitsignal * Don't reward player for ejecting * Don't reward for killing player npc titan * Don't allow titans to run banking thread * Bored npcs cleanup logic * Remove lefover whitespace changes * Metal pipe falling sound 2x * One day my brain will start properly functioning * Include reapers in bored check * Add bored check to other droppod func * Revert testing change * Fix typo * Remove debug prints * Debug log stuck AI for future navmesh debugging Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Fix formatting * [BH] Lock scores after game end (#635) * stop awarding score after game is ended --------- Co-authored-by: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../mod/scripts/vscripts/ui/menu_mode_select.nut | 3 +- .../scripts/vscripts/gamemodes/_ai_gamemodes.gnut | 4 +- .../scripts/vscripts/gamemodes/_gamemode_at.nut | 1941 +++++++++++++++++--- 3 files changed, 1694 insertions(+), 254 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut index 32a3c8f5..52a99b6f 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut @@ -52,7 +52,8 @@ void function UpdateVisibleModes() Hud_SetEnabled( buttons[ i ], true ) Hud_SetVisible( buttons[ i ], true ) - if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" ) + // This check is refactored in the new mode menu so we can just ignore this atrocity + if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" || modesArray[ modeIndex ] == "at" ) Hud_SetLocked( buttons[ i ], false ) else Hud_SetLocked( buttons[ i ], true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut index 78a9a208..4ed7ee4a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut @@ -62,11 +62,11 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c } -void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null ) +void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null, int flags = 0 ) { entity pod = CreateDropPod( pos, <0,0,0> ) - InitFireteamDropPod( pod ) + InitFireteamDropPod( pod, flags ) waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 915e03e0..c61cb585 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -1,12 +1,54 @@ +untyped // AddCallback_OnUseEntity() needs this global function GamemodeAt_Init global function RateSpawnpoints_AT -const int BH_AI_TEAM = TEAM_BOTH -const int BOUNTY_TITAN_DAMAGE_POOL = 400 // Rewarded for damage -const int BOUNTY_TITAN_KILL_REWARD = 100 // Rewarded for kill -const float WAVE_STATE_TRANSITION_TIME = 5.0 +// Old bobr note which still applies after a year :) +// IMPLEMENTATION NOTES: +// bounty hunt is a mode that was clearly pretty heavily developed, and had alot of scrapped concepts (i.e. most wanted player bounties, turret bounties, collectable blackbox objectives) +// in the interest of time, this script isn't gonna support any of that atm +// alot of the remote functions also take parameters that aren't used, i'm not gonna populate these and just use default values for now instead +// however, if you do want to mess with this stuff, almost all the remote functions for this stuff are still present in cl_gamemode_at, and should work fine with minimal fuckery in my experience + + +// Bank settings +const float AT_BANKS_OPEN_DURATION = 45.0 // Bank open time +const int AT_BANK_DEPOSIT_RATE = 10 // Amount deposited per second +const int AT_BANK_DEPOSIT_RADIUS = 256 // bank radius for depositing +const float AT_BANK_FORCE_CLOSE_DELAY = 4.0 // If all bonus money has been deposited close the banks after this constant early + +// TODO: The reference function no longer exists, check if this still holds true +// VoyageDB: HACK score events... respawn made things in AT_SetScoreEventOverride() really messed up, have to do some hack here +const array AT_ENABLE_SCOREEVENTS = +[ + // these are disabled in AT_SetScoreEventOverride(), but related scoreEvents are not implemented into gamemode + // needs to re-enable them + "DoomTitan", + "DoomAutoTitan" +] +const array AT_DISABLE_SCOREEVENTS = +[ + // these are missed in AT_SetScoreEventOverride(), but game actually used them + // needs to disable them + "KillStalker" +] + +// Wave settings +// General +const int AT_AI_TEAM = TEAM_BOTH // Allow AI to attack and be attacked by both player teams +const float AT_FIRST_WAVE_START_DELAY = 10.0 // First wave has an extra delay before begining +const float AT_WAVE_TRANSITION_DELAY = 5.0 // Time between each wave and banks opening/closing +const float AT_WAVE_END_ANNOUNCEMENT_DELAY = 1.0 // Extra wait before announcing wave cleaned + +// Squad settings +const int AT_DROPPOD_SQUADS_ALLOWED_ON_FIELD = 4 // default is 4 droppod squads on field, won't use if AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK turns on // TODO: verify this + +// Titan bounty settings +const float AT_BOUNTY_TITAN_CHECK_DELAY = 10.0 // wait for bounty titans landing before we start checking their life state +const float AT_BOUNTY_TITAN_HEALTH_MULTIPLIER = 3 // TODO: Verify this -const array VALID_BOUNTY_TITAN_SETTINGS = [ +// Titan boss settings, check sh_gamemode_at.nut for more info +const array AT_BOUNTY_TITANS_AI_SETTINGS = +[ "npc_titan_atlas_stickybomb_bounty", "npc_titan_atlas_tracker_bounty", "npc_titan_ogre_minigun_bounty", @@ -16,302 +58,1565 @@ const array VALID_BOUNTY_TITAN_SETTINGS = [ "npc_titan_atlas_vanguard_bounty" ] +// Extra +// Respawn didn't use the "totalAllowedOnField" for npc spawning, they only allow 1 squad to be on field for each type of npc. enabling this might cause too much npcs spawning and crash the game +const bool AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK = false + +// Objectives +const int AT_OBJECTIVE_EMPTY = -1 // Remove objective +const int AT_OBJECTIVE_KILL_DZ = 104 // #AT_OBJECTIVE_KILL_DZ +const int AT_OBJECTIVE_KILL_DZ_MULTI = 105 // #AT_OBJECTIVE_KILL_DZ_MULTI +const int AT_OBJECTIVE_KILL_BOSS = 106 // #AT_OBJECTIVE_KILL_BOSS +const int AT_OBJECTIVE_KILL_BOSS_MULTI = 107 // #AT_OBJECTIVE_KILL_BOSS_MULTI +const int AT_OBJECTIVE_BANK_OPEN = 109 // #AT_BANK_OPEN_OBJECTIVE + +// When a player tries to deposit when they have 0 bonus money +// we show a help mesage, this is the ratelimit for that message +// so that we dont spam it too much +const float AT_PLAYER_HUD_MESSAGE_COOLDOWN = 2.5 + +// Due to bad navmeshes NPCs may wonder off to bumfuck nowhere or the game +// might teleport them into the map while trying to correct their position +// This obviously breaks bounty hunt where the objective is to kill ALL ai +// so we try to cleanup the camps after a set amount of time of inactivity +const int AT_CAMP_BORED_NPCS_LEFT_TO_START_CLEANUP = 3 +const float AT_CAMP_BORED_CLEANUP_WAIT = 60.0 +struct +{ + array banks + array camps + + // Used to track ScriptmanagedEntArrays of ai squads + table< int, array > campScriptEntArrays + + table< entity, bool > titanIsBountyBoss + table< entity, int > bountyTitanRewards + table< entity, int > npcStolenBonus + table< entity, bool > playerBankUploading + table< entity, table > playerSavedBountyDamage + table< entity, float > playerHudMessageAllowedTime +} file + +void function GamemodeAt_Init() +{ + // wave + RegisterSignal( "ATWaveEnd" ) + // camp + RegisterSignal( "ATCampClean" ) + RegisterSignal( "ATAllCampsClean" ) + + // Set-up score callbacks + ScoreEvent_SetupEarnMeterValuesForMixedModes() + AddDamageFinalCallback( "npc_titan", OnNPCTitanFinalDamaged ) + AddCallback_OnPlayerKilled( AT_PlayerOrNPCKilledScoreEvent ) + AddCallback_OnNPCKilled( AT_PlayerOrNPCKilledScoreEvent ) + + // Set npc weapons + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_hemlok_smg", "mp_weapon_lstar", "mp_weapon_mastiff" ] ) + + // Gamestate callbacks + AddCallback_GameStateEnter( eGameState.Prematch, OnATGamePrematch ) + AddCallback_GameStateEnter( eGameState.Playing, OnATGamePlaying ) + + // Initilaze player + AddCallback_OnClientConnected( InitialiseATPlayer ) + + // Initilaze gamemode entities + AddCallback_EntitiesDidLoad( OnEntitiesDidLoad ) +} + +void function RateSpawnpoints_AT( int checkclass, array spawnpoints, int team, entity player ) +{ + RateSpawnpoints_Generic( checkclass, spawnpoints, team, player ) +} + + + +//////////////////////////////////////// +///// GAMESTATE CALLBACK FUNCTIONS ///// +//////////////////////////////////////// + +void function OnATGamePrematch() +{ + AT_ScoreEventsValueSetUp() +} + +void function OnATGamePlaying() +{ + thread AT_GameLoop_Threaded() +} + +//////////////////////////////////////////// +///// GAMESTATE CALLBACK FUNCTIONS END ///// +//////////////////////////////////////////// + + + +//////////////////////////// +///// PLAYER FUNCTIONS ///// +//////////////////////////// + +void function InitialiseATPlayer( entity player ) +{ + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_OnPlayerConnected" ) + player.SetPlayerNetInt( "AT_bonusPointMult", 1 ) + file.playerBankUploading[ player ] <- false + file.playerSavedBountyDamage[ player ] <- {} + file.playerHudMessageAllowedTime[ player ] <- 0.0 + thread AT_PlayerTitleThink( player ) + thread AT_PlayerObjectiveThink( player ) +} + +void function AT_PlayerTitleThink( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + while ( true ) + { + if ( GetGameState() == eGameState.Playing ) + { + // Set player money count + player.SetTitle( "$" + string( AT_GetPlayerBonusPoints( player ) ) ) + } + else if ( GetGameState() >= eGameState.WinnerDetermined ) + { + if ( player.IsTitan() ) + player.SetTitle( GetTitanPlayerTitle( player ) ) + else + player.SetTitle( "" ) + + return + } + + WaitFrame() + } +} + +string function GetTitanPlayerTitle( entity player ) +{ + entity soul = player.GetTitanSoul() + + if ( !IsValid( soul ) ) + return "" + + string settings = GetSoulPlayerSettings( soul ) + var title = GetPlayerSettingsFieldForClassName( settings, "printname" ) + + if ( title == null ) + return "" + + return expect string( title ) +} + +void function AT_PlayerObjectiveThink( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + int curObjective = AT_OBJECTIVE_EMPTY + while ( true ) + { + // game entered other state + if ( GetGameState() >= eGameState.WinnerDetermined ) + { + player.SetPlayerNetInt( "gameInfoStatusText", AT_OBJECTIVE_EMPTY ) + return + } + + int nextObjective = AT_OBJECTIVE_EMPTY + + // Determine objective text for player + if ( !IsAlive( player ) ) // Don't show objective to dead players + { + nextObjective = AT_OBJECTIVE_EMPTY + } + else // We're still alive + { + if ( GetGlobalNetBool( "banksOpen" ) ) + { + nextObjective = AT_OBJECTIVE_BANK_OPEN + } + else if ( GetGlobalNetBool( "preBankPhase" ) ) + { + nextObjective = AT_OBJECTIVE_EMPTY + } + else + { + // No checks have passed, try to do a "Kill all x near the marked dropzone" objective + int dropZoneActiveCount = 0 + int bossAliveCount = 0 + array campEnts + campEnts.append( GetGlobalNetEnt( "camp1Ent" ) ) + campEnts.append( GetGlobalNetEnt( "camp2Ent" ) ) + + foreach ( entity ent in campEnts ) + { + if ( IsValid( ent ) ) + { + if ( ent.IsTitan() ) + bossAliveCount += 1 + else + dropZoneActiveCount += 1 + } + } + + switch( dropZoneActiveCount ) + { + case 1: + nextObjective = AT_OBJECTIVE_KILL_DZ + break + case 2: + nextObjective = AT_OBJECTIVE_KILL_DZ_MULTI + break + } + + switch( bossAliveCount ) + { + case 1: + nextObjective = AT_OBJECTIVE_KILL_BOSS + break + case 2: + nextObjective = AT_OBJECTIVE_KILL_BOSS_MULTI + break + } + + // We couldn't get an objective, set it to empty + if ( dropZoneActiveCount == 0 && bossAliveCount == 0 ) + nextObjective = AT_OBJECTIVE_EMPTY + } + } + + // Set the objective when changed + if ( curObjective != nextObjective ) + { + player.SetPlayerNetInt( "gameInfoStatusText", nextObjective ) + curObjective = nextObjective + } + + WaitFrame() + } +} + +//////////////////////////////// +///// PLAYER FUNCTIONS END ///// +//////////////////////////////// + + + +//////////////////////////////////////// +///// GAMEMODE INITILAZE FUNCTIONS ///// +//////////////////////////////////////// + +void function OnEntitiesDidLoad() +{ + foreach ( entity info_target in GetEntArrayByClass_Expensive( "info_target" ) ) + { + if( info_target.HasKey( "editorclass" ) ) + { + switch( info_target.kv.editorclass ) + { + case "info_attrition_bank": + entity bank = CreateEntity( "prop_script" ) + bank.SetScriptName( "AT_Bank" ) // VoyageDB: don't know how to make client able to track it + bank.SetOrigin( info_target.GetOrigin() ) + bank.SetAngles( info_target.GetAngles() ) + DispatchSpawn( bank ) + bank.kv.solid = SOLID_VPHYSICS + bank.SetModel( info_target.GetModelName() ) + + // Minimap icon init + bank.Minimap_SetCustomState( eMinimapObject_prop_script.AT_BANK ) + bank.Minimap_SetAlignUpright( true ) + bank.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + bank.Minimap_Hide( TEAM_IMC, null ) + bank.Minimap_Hide( TEAM_MILITIA, null ) + + // Create tracker ent + // we don't need to store these at all, client just needs to get them + DispatchSpawn( GetAvailableBankTracker( bank ) ) + + // Make sure the bank is in it's disabled pose + thread PlayAnim( bank, "mh_inactive_idle" ) + // Set the bank usable + AddCallback_OnUseEntity( bank, OnPlayerUseBank ) + bank.SetUsable() + bank.SetUsePrompts( "#AT_USE_BANK_CLOSED", "#AT_USE_BANK_CLOSED" ) + + file.banks.append( bank ) + break; + case "info_attrition_camp": + AT_WaveOrigin campStruct + campStruct.ent = info_target + campStruct.origin = info_target.GetOrigin() + campStruct.radius = expect string( info_target.kv.radius ).tofloat() + campStruct.height = expect string( info_target.kv.height ).tofloat() + + // Assumes every info_attrition_camp will have all 9 phases, possibly not a good idea? + // TODO: verify this on all vanilla maps before release + for ( int i = 0; i < 9; i++ ) + campStruct.phaseAllowed.append( expect string( info_target.kv[ "phase_" + ( i + 1 ) ] ) == "1" ) + + // Get droppod spawns within the camp + foreach ( entity spawnpoint in SpawnPoints_GetDropPod() ) + { + vector campPos = info_target.GetOrigin() + vector spawnPos = spawnpoint.GetOrigin() + if ( Distance( campPos, spawnPos ) < campStruct.radius ) + campStruct.dropPodSpawnPoints.append( spawnpoint ) + } + + // Get titan spawns within the camp + foreach ( entity spawnpoint in SpawnPoints_GetTitan() ) + { + vector campPos = info_target.GetOrigin() + vector spawnPos = spawnpoint.GetOrigin() + if ( Distance( campPos, spawnPos ) < campStruct.radius ) + campStruct.titanSpawnPoints.append( spawnpoint ) + } + + file.camps.append( campStruct ) + break; + } + } + } +} + +//////////////////////////////////////////// +///// GAMEMODE INITILAZE FUNCTIONS END ///// +//////////////////////////////////////////// + + + +///////////////////////////// +///// SCORING FUNCTIONS ///// +///////////////////////////// + +// TODO: Don't reward in postmatch +// TODO: Dropping a titan on a bounty with it's dome-shield still up rewards you the bonus, but +// it doesn't actually damage the bounty titan + +void function AT_ScoreEventsValueSetUp() +{ + ScoreEvent_SetEarnMeterValues( "KillTitan", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillAutoTitan", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "AttritionTitanKilled", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillPilot", 0.10, 0.10 ) + ScoreEvent_SetEarnMeterValues( "AttritionPilotKilled", 0.10, 0.10 ) + ScoreEvent_SetEarnMeterValues( "AttritionBossKilled", 0.10, 0.20 ) + ScoreEvent_SetEarnMeterValues( "AttritionGruntKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionSpectreKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionStalkerKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionSuperSpectreKilled", 0.10, 0.10, 0.5 ) + + // HACK + foreach ( string eventName in AT_ENABLE_SCOREEVENTS ) + ScoreEvent_Enable( GetScoreEvent( eventName ) ) + + foreach ( string eventName in AT_DISABLE_SCOREEVENTS ) + ScoreEvent_Disable( GetScoreEvent( eventName ) ) +} + +void function AT_PlayerOrNPCKilledScoreEvent( entity victim, entity attacker, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + // Suicide + if ( attacker == victim ) + { + if ( victim.IsPlayer() ) + AT_PlayerBonusLoss( victim, AT_GetPlayerBonusPoints( victim ) / 2 ) + + return + } + + // NPC is the attacker + if ( !attacker.IsPlayer() ) + { + if ( attacker.IsTitan() && IsValid( GetPetTitanOwner( attacker ) ) ) // Re-asign attacker + attacker = GetPetTitanOwner( attacker ) + else // NPC steals money from player, killing it will award the stolen bonus + normal reward + AT_NPCTryStealBonusPoints( attacker, victim ) + + return + } + + // Get event name + string eventName = GetAttritionScoreEventName( victim.GetClassName() ) + + if ( victim.IsTitan() ) // titan specific + eventName = GetAttritionScoreEventNameFromAI( victim ) + + if ( eventName == "" ) // no valid scoreEvent + return + + int scoreVal = ScoreEvent_GetPointValue( GetScoreEvent( eventName ) ) + + // pet titan check + if ( victim.IsTitan() && IsValid( GetPetTitanOwner( victim ) ) ) + { + if( GetPetTitanOwner( victim ) == attacker ) // Player ejected + return + + if( GetPetTitanOwner( victim ).IsPlayer() ) // Killed player npc titan + return + + scoreVal = ATTRITION_SCORE_TITAN_MIN + } + + // killed npc + if ( victim.IsNPC() ) + { + int bonusFromNPC = 0 + // If NPC was carrying a bonus award it to the attacker + if ( victim in file.npcStolenBonus ) + { + bonusFromNPC = file.npcStolenBonus[ victim ] + delete file.npcStolenBonus[ victim ] + } + AT_AddPlayerBonusPointsForEntityKilled( attacker, scoreVal, damageInfo, bonusFromNPC ) + AddPlayerScore( attacker, eventName ) // we add scoreEvent here, since basic score events has been overwrited by sh_gamemode_at.nut + // update score difference and scoreboard + AT_AddToPlayerTeamScore( attacker, scoreVal ) + } + + // bonus stealing check + if ( victim.IsPlayer() ) + AT_PlayerTryStealBonusPoints( attacker, victim, damageInfo ) +} + +bool function AT_NPCTryStealBonusPoints( entity attacker, entity victim ) +{ + // basic checks + if ( !attacker.IsNPC() ) + return false + + if ( !victim.IsPlayer() ) + return false + + int victimBonus = AT_GetPlayerBonusPoints( victim ) + int bonusToSteal = victimBonus / 2 // npc always steal half the bonus from player, no extra bonus for killing the player + if ( bonusToSteal == 0 ) // player has no bonus! + return false + + if ( !( attacker in file.npcStolenBonus ) ) // init + file.npcStolenBonus[ attacker ] <- 0 + + file.npcStolenBonus[ attacker ] += bonusToSteal + + AT_PlayerBonusLoss( victim, bonusToSteal ) // tell victim of bonus stolen + + if ( !( attacker in file.titanIsBountyBoss ) ) // if attacker npc is not a bounty titan, we make them highlighted + NPCBountyStolenHighlight( attacker ) + + return true +} + +void function NPCBountyStolenHighlight( entity npc ) +{ + Highlight_SetEnemyHighlight( npc, "enemy_boss_bounty" ) +} + +bool function AT_PlayerTryStealBonusPoints( entity attacker, entity victim, var damageInfo ) +{ + // basic checks + if ( !attacker.IsPlayer() ) + return false + + if ( !victim.IsPlayer() ) + return false + + int victimBonus = AT_GetPlayerBonusPoints( victim ) + + int minScoreCanSteal = ATTRITION_SCORE_PILOT_MIN + if ( victim.IsTitan() ) + minScoreCanSteal = ATTRITION_SCORE_TITAN_MIN + + int bonusToSteal = victimBonus / 2 + int attackerScore = bonusToSteal + bool realStealBonus = true + if ( bonusToSteal <= minScoreCanSteal ) // no enough bonus to steal + { + attackerScore = minScoreCanSteal // give attacker min bonus + realStealBonus = false // we don't do attacker steal events below, just half victim's bonus + } + + // servercallback + int victimEHandle = victim.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + // only do attacker events if victim has enough bonus to steal + if ( realStealBonus ) + { + Remote_CallFunction_NonReplay( + attacker, + "ServerCallback_AT_PlayerKillScorePopup", + bonusToSteal, // stolenScore + victimEHandle, // victimEHandle + damageOrigin.x, // x + damageOrigin.y, // y + damageOrigin.z // z + ) + } + else // otherwise we do a normal entity killed scoreEvent + { + AT_AddPlayerBonusPointsForEntityKilled( attacker, attackerScore, damageInfo ) + } + + // update score difference and scoreboard + AT_AddToPlayerTeamScore( attacker, minScoreCanSteal ) + + // steal bonus + // only do attacker events if victim has enough bonus to steal + if ( realStealBonus ) + { + AT_AddPlayerBonusPoints( attacker, bonusToSteal ) + AddPlayerScore( attacker, "AttritionBonusStolen" ) + } + + // tell victim of bonus stolen + AT_PlayerBonusLoss( victim, bonusToSteal ) + + return realStealBonus +} + +void function AT_PlayerBonusLoss( entity player, int bonusLoss ) +{ + AT_AddPlayerBonusPoints( player, -bonusLoss ) + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_ShowStolenBonus", + bonusLoss // stolenScore + ) +} + +// team score meter +void function AT_AddToPlayerTeamScore( entity player, int amount ) +{ + // do not award any score after the match is ended + if ( GetGameState() > eGameState.Playing ) + return + + // add to scoreboard + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, amount ) + + // Check score so we dont go over max + if ( GameRules_GetTeamScore(player.GetTeam()) + amount > GetScoreLimit_FromPlaylist() ) + { + amount = GetScoreLimit_FromPlaylist() - GameRules_GetTeamScore(player.GetTeam()) + } + + // update score difference + AddTeamScore( player.GetTeam(), amount ) +} + +// bonus points, players earn from killing +void function AT_AddPlayerBonusPoints( entity player, int amount ) +{ + // do not award any score after the match is ended + if ( GetGameState() > eGameState.Playing ) + return + + // add to scoreboard + player.AddToPlayerGameStat( PGS_SCORE, amount ) + AT_SetPlayerBonusPoints( player, player.GetPlayerNetInt( "AT_bonusPoints" ) + ( player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 ) + amount ) +} + +int function AT_GetPlayerBonusPoints( entity player ) +{ + return player.GetPlayerNetInt( "AT_bonusPoints" ) + player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 +} + +void function AT_SetPlayerBonusPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_bonusPoints256", stacks ) + player.SetPlayerNetInt( "AT_bonusPoints", amount - stacks * 256 ) +} + +// total points, the value player actually uploaded to team score +void function AT_AddPlayerTotalPoints( entity player, int amount ) +{ + // update score difference and scoreboard, calling this function meaning player has deposited their bonus to team score + AT_AddToPlayerTeamScore( player, amount ) + AT_SetPlayerTotalPoints( player, player.GetPlayerNetInt( "AT_totalPoints" ) + ( player.GetPlayerNetInt( "AT_totalPoints256" ) * 256 ) + amount ) +} + +void function AT_SetPlayerTotalPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_totalPoints256", stacks ) + player.SetPlayerNetInt( "AT_totalPoints", amount - stacks * 256 ) +} + +// earn points, seems not used +void function AT_AddPlayerEarnedPoints( entity player, int amount ) +{ + AT_SetPlayerBonusPoints( player, player.GetPlayerNetInt( "AT_earnedPoints" ) + ( player.GetPlayerNetInt( "AT_earnedPoints256" ) * 256 ) + amount ) +} + +void function AT_SetPlayerEarnedPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_earnedPoints256", stacks ) + player.SetPlayerNetInt( "AT_earnedPoints", amount - stacks * 256 ) +} + +// damaging bounty +void function AT_AddPlayerBonusPointsForBossDamaged( entity player, entity victim, int amount, var damageInfo ) +{ + AT_AddPlayerBonusPoints( player, amount ) + // update score difference and scoreboard + AT_AddToPlayerTeamScore( player, amount ) + + // send servercallback for damaging + int bossEHandle = victim.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_BossDamageScorePopup", + amount, // damageScore + amount, // damageBonus + bossEHandle, // bossEHandle + damageOrigin.x, // x + damageOrigin.y, // y + damageOrigin.z // z + ) +} + +void function AT_AddPlayerBonusPointsForEntityKilled( entity player, int amount, var damageInfo, int extraBonus = 0 ) +{ + AT_AddPlayerBonusPoints( player, amount + extraBonus ) + + // send servercallback for damaging + int attackerEHandle = player.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_ShowATScorePopup", + attackerEHandle, // attackerEHandle + amount, // damageScore + amount + extraBonus, // damageBonus + damageOrigin.x, // damagePosX + damageOrigin.y, // damagePosX + damageOrigin.z, // damagePosX + 0 // damageType ( not used ) + ) +} + +///////////////////////////////// +///// SCORING FUNCTIONS END ///// +///////////////////////////////// + + + +////////////////////////////// +///// GAMELOOP FUNCTIONS ///// +////////////////////////////// + +void function AT_GameLoop_Threaded() +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // game end func + // TODO: Cant seem to be able to get this crash ??? + OnThreadEnd + ( + function() + { + // prevent crash before entity creation on map change + if ( GetGameState() >= eGameState.Prematch ) + { + SetGlobalNetBool( "preBankPhase", false ) + SetGlobalNetBool( "banksOpen", false ) + } + } + ) + + // Initial wait before first wave + wait AT_FIRST_WAVE_START_DELAY - AT_WAVE_TRANSITION_DELAY + + int lastWaveId = -1 + for ( int waveCount = 1; ; waveCount++ ) + { + wait AT_WAVE_TRANSITION_DELAY + + // cap to number of real waves + int waveId = ( waveCount - 1 ) / 2 + int waveCapAmount = 2 + waveId = int( min( waveId, GetWaveDataSize() - waveCapAmount ) ) + + // New wave dialogue + bool waveChanged = lastWaveId != waveId + if ( waveChanged ) + { + PlayFactionDialogueToTeam( "bh_newWave", TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_newWave", TEAM_MILITIA ) + } + else // same wave, second half + { + PlayFactionDialogueToTeam( "bh_incoming", TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_incoming", TEAM_MILITIA ) + } + + lastWaveId = waveId + + SetGlobalNetInt( "AT_currentWave", waveId ) + bool isBossWave = waveCount % 2 == 0 // even number waveCount means boss wave + + // announce the wave + foreach ( entity player in GetPlayerArray() ) + { + if ( isBossWave ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnounceBoss" ) + } + else + { + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_AnnouncePreParty", + 0.0, // endTime ( not used ) + waveId // waveNum + ) + } + } + + wait AT_WAVE_TRANSITION_DELAY + + // Run the wave + thread AT_CampSpawnThink( waveId, isBossWave ) + + if ( !isBossWave ) + { + svGlobal.levelEnt.WaitSignal( "ATAllCampsClean" ) // signaled when all camps cleaned in spawn functions + } + else + { + wait AT_BOUNTY_TITAN_CHECK_DELAY + // wait until all bounty titans killed + while ( IsAlive( GetGlobalNetEnt( "camp1Ent" ) ) || IsAlive( GetGlobalNetEnt( "camp2Ent" ) ) ) + WaitFrame() + } + + // wave end, prebank phase + svGlobal.levelEnt.Signal( "ATWaveEnd" ) // defensive fix, destroy existing campEnts + SetGlobalNetBool( "preBankPhase", true ) + + wait AT_WAVE_END_ANNOUNCEMENT_DELAY + + // announce wave end + foreach ( entity player in GetPlayerArray() ) + { + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_AnnounceWaveOver", + waveId, // waveNum ( not used ) + 0, // militiaDamageTotal ( not used ) + 0, // imcDamageTotal ( not used ) + 0, // milMVP ( not used ) + 0, // imcMVP ( not used ) + 0, // milMVPDamage ( not used ) + 0 // imcMVPDamage ( not used ) + ) + } + + wait AT_WAVE_TRANSITION_DELAY + + // banking phase + SetGlobalNetBool( "preBankPhase", false ) + SetGlobalNetTime( "AT_bankStartTime", Time() ) + SetGlobalNetTime( "AT_bankEndTime", Time() + AT_BANKS_OPEN_DURATION ) + SetGlobalNetBool( "banksOpen", true ) + + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_BankOpen" ) + + foreach ( entity bank in file.banks ) + thread AT_BankActiveThink( bank ) + + + float endTime = Time() + AT_BANKS_OPEN_DURATION + bool forceCloseTriggered = false + // wait until no player is holding bonus, or max wait time + while ( Time() <= endTime ) + { + // If everyone has deposited their bonuses close the banks early + if ( !ATAnyPlayerHasBonus() && !forceCloseTriggered ) + { + forceCloseTriggered = true + endTime = Time() + AT_BANK_FORCE_CLOSE_DELAY + } + + WaitFrame() + } + + SetGlobalNetBool( "banksOpen", false ) + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_BankClose" ) + } +} + +bool function ATAnyPlayerHasBonus() +{ + foreach ( entity player in GetPlayerArray() ) + { + if ( AT_GetPlayerBonusPoints( player ) ) + return true + } + return false +} + +////////////////////////////////// +///// GAMELOOP FUNCTIONS END ///// +////////////////////////////////// + + + +////////////////////////// +///// CAMP FUNCTIONS ///// +////////////////////////// + +void function AT_CampSpawnThink( int waveId, bool isBossWave ) +{ + AT_WaveData wave = GetWaveData( waveId ) + array< array > campSpawnData + + if ( isBossWave ) + campSpawnData = wave.bossSpawnData + else + campSpawnData = wave.spawnDataArrays + + array allCampsToUse + foreach ( AT_WaveOrigin campStruct in file.camps ) + { + if ( campStruct.phaseAllowed[ waveId ] ) + allCampsToUse.append( campStruct ) + } + + // HACK + // There's too many phase3 camps on exoplanet and rise, make sure we always have the correct count + int maxCampsForWave = waveId == 0 ? 1 : 2 + while( allCampsToUse.len() > maxCampsForWave ) + { + // Get the required number of camps + array tempCamps + for( int i = 0; i < maxCampsForWave; i++ ) + tempCamps.append( allCampsToUse[RandomInt( allCampsToUse.len() )] ) + + + // Check if they're intersecting, if they are, try again + bool intersecting = false + for( int i = 0; i < tempCamps.len(); i++ ) + { + AT_WaveOrigin campA = tempCamps[i] + for( int j = 0; j < tempCamps.len(); j++ ) + { + // Don't compare the same two camps + if( j == i ) + continue + + AT_WaveOrigin campB = tempCamps[j] + + if( Distance( campA.origin, campB.origin ) < campA.radius + campB.radius ) + intersecting = true + } + } + + if( !intersecting ) + allCampsToUse = tempCamps + + // If we ever get really unlucky just wait a frame + WaitFrame() + } + + foreach ( int spawnId, AT_WaveOrigin curCampData in allCampsToUse ) + { + array curSpawnData = campSpawnData[ spawnId ] + + int totalNPCsToSpawn = 0 + // initialise pending spawns and get total npcs + foreach ( AT_SpawnData spawnData in curSpawnData ) + { + spawnData.pendingSpawns = spawnData.totalToSpawn + // add to network variables + string npcNetVar = GetNPCNetVarName( spawnData.aitype, spawnId ) + SetGlobalNetInt( npcNetVar, spawnData.totalToSpawn ) + + totalNPCsToSpawn += spawnData.totalToSpawn + } + + if ( !isBossWave ) + { + // camp Ent, boss wave will use boss themselves as campEnt + string campEntVarName = "camp" + string( spawnId + 1 ) + "Ent" + bool waveNotActive = GetGlobalNetBool( "preBankPhase" ) || GetGlobalNetBool( "banksOpen" ) + if ( !IsValid( GetGlobalNetEnt( campEntVarName ) ) && !waveNotActive ) + SetGlobalNetEnt( campEntVarName, CreateCampTracker( curCampData, spawnId ) ) + + array minionSquadDatas + foreach ( AT_SpawnData data in curSpawnData ) + { + switch ( data.aitype ) + { + case "npc_soldier": + case "npc_spectre": + case "npc_stalker": + if ( !AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + minionSquadDatas.append( data ) + else + thread AT_DroppodSquadEvent_Single( curCampData, spawnId, data ) + break + + case "npc_super_spectre": + thread AT_ReaperEvent( curCampData, spawnId, data ) + break + } + } + + // minions squad spawn + if ( !AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + { + if ( minionSquadDatas.len() > 0 ) + thread AT_DroppodSquadEvent( curCampData, spawnId, minionSquadDatas ) + } + + // use campProgressThink for handling wave state + thread CampProgressThink( spawnId, totalNPCsToSpawn ) + } + else // bosswave spawn + { + foreach ( AT_SpawnData data in curSpawnData ) + { + if( data.aitype != "npc_titan" ) + continue + + thread AT_BountyTitanEvent( curCampData, spawnId, data ) + break + } + } + } +} + +void function CampProgressThink( int spawnId, int totalNPCsToSpawn ) +{ + string campLetter = GetCampLetter( spawnId ) + string campProgressName = campLetter + "campProgress" + string campEntVarName = "camp" + string( spawnId + 1 ) + "Ent" + + // initial wait + SetGlobalNetFloat( campProgressName, 1.0 ) + + // TODO: random wait, make this a constant ?? + wait 3.0 + + float cleanUpTime = -1.0 + + while ( true ) + { + int npcsLeft + // get all npcs might be in this camp + for ( int i = 0; i < 5; i++ ) + { + string netVarName = string( i + 1 ) + campLetter + "campCount" + int netVarValue = GetGlobalNetInt( netVarName ) + if ( netVarValue >= 0 ) // uninitialized network var starts from -1, avoid checking them + npcsLeft += netVarValue + } + + float campLeft = float( npcsLeft ) / float( totalNPCsToSpawn ) + SetGlobalNetFloat( campProgressName, campLeft ) + + if( npcsLeft <= AT_CAMP_BORED_NPCS_LEFT_TO_START_CLEANUP && cleanUpTime < 0.0 ) + { + cleanUpTime = Time() + AT_CAMP_BORED_CLEANUP_WAIT + print("Cleanup timer started!") + } + + if( Time() > cleanUpTime && cleanUpTime > 0.0 && spawnId in file.campScriptEntArrays ) + { + foreach( int handle in file.campScriptEntArrays[spawnId] ) + { + array entities = GetScriptManagedEntArray( handle ) + entities.removebyvalue( null ) + foreach ( entity ent in entities ) + { + if ( IsAlive( ent ) && ent.IsNPC() ) + { + printt( "Killing bored AI " + ent.GetClassName() + " at " + ent.GetOrigin() ) + ent.Die() + } + } + } + } -// IMPLEMENTATION NOTES: -// bounty hunt is a mode that was clearly pretty heavily developed, and had alot of scrapped concepts (i.e. most wanted player bounties, turret bounties, collectable blackbox objectives) -// in the interest of time, this script isn't gonna support any of that atm -// alot of the remote functions also take parameters that aren't used, i'm not gonna populate these and just use default values for now instead -// however, if you do want to mess with this stuff, almost all the remote functions for this stuff are still present in cl_gamemode_at, and should work fine with minimal fuckery in my experience + if ( campLeft <= 0.0 ) // camp wiped! + { + PlayFactionDialogueToTeam( "bh_cleared" + campLetter, TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_cleared" + campLetter, TEAM_MILITIA ) -struct { - array campsToRegisterOnEntitiesDidLoad + entity campEnt = GetGlobalNetEnt( campEntVarName ) + if ( IsValid( campEnt ) ) + campEnt.Signal( "ATCampClean" ) // destroy the camp ent - array banks - array camps - - table< int, table< string, int > > trackedCampNPCSpawns -} file + // check if both camps being destroyed + if ( !IsValid( GetGlobalNetEnt( "camp1Ent" ) ) && !IsValid( GetGlobalNetEnt( "camp2Ent" ) ) ) + svGlobal.levelEnt.Signal( "ATAllCampsClean" ) // end the wave + + return + } -void function GamemodeAt_Init() + WaitFrame() + } +} + +// entity funcs +// camp +entity function CreateCampTracker( AT_WaveOrigin campData, int spawnId ) { - AddCallback_GameStateEnter( eGameState.Playing, RunATGame ) - - AddCallback_OnClientConnected( InitialiseATPlayer ) + // store data + vector campOrigin = campData.origin + float campRadius = campData.radius + float campHeight = campData.height + // add a minimap icon + entity mapIconEnt = CreateEntity( "prop_script" ) + DispatchSpawn( mapIconEnt ) + + mapIconEnt.SetOrigin( campOrigin ) + mapIconEnt.DisableHibernation() + SetTeam( mapIconEnt, AT_AI_TEAM ) + mapIconEnt.Minimap_AlwaysShow( TEAM_IMC, null ) + mapIconEnt.Minimap_AlwaysShow( TEAM_MILITIA, null ) + + mapIconEnt.Minimap_SetCustomState( GetCampMinimapState( spawnId ) ) + mapIconEnt.Minimap_SetAlignUpright( true ) + mapIconEnt.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + mapIconEnt.Minimap_SetObjectScale( campRadius / 16000.0 ) // proper icon on the map - AddSpawnCallbackEditorClass( "info_target", "info_attrition_bank", CreateATBank ) - AddSpawnCallbackEditorClass( "info_target", "info_attrition_camp", CreateATCamp ) - AddCallback_EntitiesDidLoad( CreateATCamps_Delayed ) + // attach a location tracker + entity tracker = GetAvailableLocationTracker() + tracker.SetOwner( mapIconEnt ) // needs a owner to show up + tracker.SetOrigin( campOrigin ) + SetLocationTrackerRadius( tracker, campRadius ) + SetLocationTrackerID( tracker, spawnId ) + DispatchSpawn( tracker ) + + thread TrackWaveEndForCampInfo( tracker, mapIconEnt ) + return tracker } -void function RateSpawnpoints_AT( int checkclass, array spawnpoints, int team, entity player ) +void function TrackWaveEndForCampInfo( entity tracker, entity mapIconEnt ) { - RateSpawnpoints_Generic( checkclass, spawnpoints, team, player ) // temp + tracker.EndSignal( "OnDestroy" ) + tracker.EndSignal( "ATCampClean" ) + + OnThreadEnd + ( + function(): ( tracker, mapIconEnt ) + { + // camp cleaned, wave or game ended, destroy the camp info + if ( IsValid( tracker ) ) + tracker.Destroy() + + if ( IsValid( mapIconEnt ) ) + mapIconEnt.Destroy() + } + ) + + WaitSignal( svGlobal.levelEnt, "GameStateChanged", "ATWaveEnd" ) } -// world and player inits +string function GetCampLetter( int spawnId ) +{ + return spawnId == 0 ? "A" : "B" +} -void function InitialiseATPlayer( entity player ) +int function GetCampMinimapState( int id ) { - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_OnPlayerConnected" ) + switch ( id ) + { + case 0: + return eMinimapObject_prop_script.AT_DROPZONE_A + case 1: + return eMinimapObject_prop_script.AT_DROPZONE_B + case 2: + return eMinimapObject_prop_script.AT_DROPZONE_C + } + + unreachable } -void function CreateATBank( entity spawnpoint ) +////////////////////////////// +///// CAMP FUNCTIONS END ///// +////////////////////////////// + + + +////////////////////////// +///// BANK FUNCTIONS ///// +////////////////////////// + +void function AT_BankActiveThink( entity bank ) { - entity bank = CreatePropDynamic( spawnpoint.GetModelName(), spawnpoint.GetOrigin(), spawnpoint.GetAngles(), SOLID_VPHYSICS ) - bank.SetScriptName( "AT_Bank" ) - - // create tracker ent - // we don't need to store these at all, client just needs to get them - DispatchSpawn( GetAvailableBankTracker( bank ) ) + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + bank.EndSignal( "OnDestroy" ) - thread PlayAnim( bank, "mh_inactive_idle" ) + // Banks closed + OnThreadEnd + ( + function(): ( bank ) + { + if ( IsValid( bank ) ) + { + // Update use prompt + if ( GetGameState() != eGameState.Playing ) + bank.UnsetUsable() + else + bank.SetUsePrompts( "#AT_USE_BANK_CLOSED", "#AT_USE_BANK_CLOSED" ) + + thread PlayAnim( bank, "mh_active_2_inactive" ) + FadeOutSoundOnEntity( bank, "Mobile_Hardpoint_Idle", 0.5 ) + bank.Minimap_Hide( TEAM_IMC, null ) + bank.Minimap_Hide( TEAM_MILITIA, null ) + } + } + ) + + // Update use prompt to usable + bank.SetUsable() + bank.SetUsePrompts( "#AT_USE_BANK", "#AT_USE_BANK_PC" ) + + thread PlayAnim( bank, "mh_inactive_2_active" ) + EmitSoundOnEntity( bank, "Mobile_Hardpoint_Idle" ) + + // Show minimap icon for bank + bank.Minimap_AlwaysShow( TEAM_IMC, null ) + bank.Minimap_AlwaysShow( TEAM_MILITIA, null ) + bank.Minimap_SetCustomState( eMinimapObject_prop_script.AT_BANK ) - file.banks.append( bank ) + // Wait for bank close or game end + while ( GetGlobalNetBool( "banksOpen" ) ) + WaitFrame() } -void function CreateATCamp( entity spawnpoint ) +function OnPlayerUseBank( bank, player ) { - // delay this so we don't do stuff before all spawns are initialised and that - file.campsToRegisterOnEntitiesDidLoad.append( spawnpoint ) -} + // Banks are always usable so that we can show the use prompt + // Only allow deposit when banks are open + if ( !GetGlobalNetBool( "banksOpen" ) ) + return -void function CreateATCamps_Delayed() -{ - // we delay registering camps until EntitiesDidLoad since they rely on spawnpoints and stuff, which might not all be ready in the creation callback - // unsure if this would be an issue in practice, but protecting against it in case it would be - foreach ( entity camp in file.campsToRegisterOnEntitiesDidLoad ) + expect entity( bank ) + expect entity( player ) + + // bank.SetUsableByGroup( "pilot" ) didn't seem to work so we just + // exit here if player is in a titan + if( player.IsTitan() ) + return + + // Player has no bonus, try to send a tip using SendHUDMessage + if ( AT_GetPlayerBonusPoints( player ) == 0 ) { - AT_WaveOrigin campStruct - campStruct.ent = camp - campStruct.origin = camp.GetOrigin() - campStruct.radius = expect string( camp.kv.radius ).tofloat() - campStruct.height = expect string( camp.kv.height ).tofloat() - - // assumes every info_attrition_camp will have all 9 phases, possibly not a good idea? - for ( int i = 0; i < 9; i++ ) - campStruct.phaseAllowed.append( expect string( camp.kv[ "phase_" + ( i + 1 ) ] ) == "1" ) - - // get droppod spawns - foreach ( entity spawnpoint in SpawnPoints_GetDropPod() ) - if ( Distance( camp.GetOrigin(), spawnpoint.GetOrigin() ) < 1500.0 ) - campStruct.dropPodSpawnPoints.append( spawnpoint ) - - foreach ( entity spawnpoint in SpawnPoints_GetTitan() ) - if ( Distance( camp.GetOrigin(), spawnpoint.GetOrigin() ) < 1500.0 ) - campStruct.titanSpawnPoints.append( spawnpoint ) - - // todo: turret spawns someday maybe - - file.camps.append( campStruct ) + ATSendDepositTipToPlayer( player, "#AT_USE_BANK_NO_BONUS_HINT" ) + return } - - file.campsToRegisterOnEntitiesDidLoad.clear() -} -// scoring funcs + // Prevent more than one instance of this thread running + if ( !file.playerBankUploading[ player ] ) + thread PlayerUploadingBonus_Threaded( bank, player ) +} -// don't use this where possible as it doesn't set score and stuff -void function AT_SetPlayerCash( entity player, int amount ) +bool function ATSendDepositTipToPlayer( entity player, string message ) { - // split into stacks of 256 where necessary - int stacks = amount / 256 // automatically rounds down because int division + if ( Time() < file.playerHudMessageAllowedTime[ player ] ) + return false + + SendHudMessage( player, message, -1, 0.4, 255, 255, 255, 255, 0.5, 1.0, 0.5 ) + file.playerHudMessageAllowedTime[ player ] = Time() + AT_PLAYER_HUD_MESSAGE_COOLDOWN - player.SetPlayerNetInt( "AT_bonusPoints256", stacks ) - player.SetPlayerNetInt( "AT_bonusPoints", amount - stacks * 256 ) + return true } -void function AT_AddPlayerCash( entity player, int amount ) +struct AT_playerUploadStruct { - // update score difference - AddTeamScore( player.GetTeam(), amount / 2 ) - AT_SetPlayerCash( player, player.GetPlayerNetInt( "AT_bonusPoints" ) + ( player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 ) + amount ) + bool uploadSuccess = false + int depositedPoints = 0 +} + +void function PlayerUploadingBonus_Threaded( entity bank, entity player ) +{ + bank.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + + file.playerBankUploading[ player ] = true + + // this literally only exists because structs are passed by ref, + // and primitives like ints and bools are passed by val + // which meant that the OnThreadEnd was just getting 0 and false + AT_playerUploadStruct uploadInfo + + // Cleanup and call finish deposit func + OnThreadEnd + ( + function(): ( player, uploadInfo ) + { + if ( IsValid( player ) ) + { + file.playerBankUploading[ player ] = false + + // Clean up looping sound + StopSoundOnEntity( player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + StopSoundOnEntity( player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_3P" ) + + // Do medal event + // TODO: Check if vanilla actually do.s this every time you finish depositing??? + AddPlayerScore( player, "AttritionCashedBonus" ) + + // Do server callback + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_FinishDeposit", + uploadInfo.depositedPoints // deposit + ) + + player.SetPlayerNetBool( "AT_playerUploading", false ) + + if ( uploadInfo.uploadSuccess ) // Player deposited all remaining bonus + { + // Emit uploading successful sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Successful_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Successful_3P" ) + + // player is MVP + int ourScore = player.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + bool isMVP = true + foreach(teamPlayer in GetPlayerArrayOfTeam(player.GetTeam())) + { + if (ourScore < teamPlayer.GetPlayerGameStat( PGS_ASSAULT_SCORE )) + { + isMVP = false + break + } + } + if (isMVP) + PlayFactionDialogueToPlayer( "bh_mvp", player ) + } + else // Player was killed or left the bank radius + { + // Emit uploading failed sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Unsuccessful_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Unsuccessful_3P" ) + } + } + } + ) + + // Uploading start sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_3P" ) + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_3P" ) + + player.SetPlayerNetBool( "AT_playerUploading", true ) + + // Upload bonus while the player is within range of the bank + while ( Distance( player.GetOrigin(), bank.GetOrigin() ) <= AT_BANK_DEPOSIT_RADIUS && GetGlobalNetBool( "banksOpen" ) ) + { + // Calling this moves the "Uploading..." graphic to the same place it is + // in vanilla + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_ShowRespawnBonusLoss" ) + + int bonusToUpload = int( min( AT_BANK_DEPOSIT_RATE, AT_GetPlayerBonusPoints( player ) ) ) + // No more bonus to upload, return + if ( bonusToUpload == 0 ) + { + uploadInfo.uploadSuccess = true + return + } + + // Remove bonus points and add them to total poins + AT_AddPlayerBonusPoints( player, -bonusToUpload ) + AT_AddPlayerTotalPoints( player, bonusToUpload ) + + uploadInfo.depositedPoints += bonusToUpload + WaitFrame() + } } -// run gamestate +////////////////////////////// +///// BANK FUNCTIONS END ///// +////////////////////////////// + -void function RunATGame() + +///////////////////////// +///// NPC FUNCTIONS ///// +///////////////////////// + +int function GetScriptManagedNPCArrayLength_Alive( int scriptManagerId ) { - thread RunATGame_Threaded() + array entities = GetScriptManagedEntArray( scriptManagerId ) + entities.removebyvalue( null ) + int npcsAlive = 0 + foreach ( entity ent in entities ) + { + if ( IsAlive( ent ) && ent.IsNPC() ) + npcsAlive += 1 + } + return npcsAlive } -void function RunATGame_Threaded() +void function AT_DroppodSquadEvent( AT_WaveOrigin campData, int spawnId, array minionDatas ) { svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + // create a script managed array for all handled minions + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] - OnThreadEnd( function() - { - SetGlobalNetBool( "banksOpen", false ) - }) - - wait WAVE_STATE_TRANSITION_TIME // initial wait before first wave - - for ( int waveCount = 1; ; waveCount++ ) + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = SQUAD_SIZE * AT_DROPPOD_SQUADS_ALLOWED_ON_FIELD + while ( true ) { - wait WAVE_STATE_TRANSITION_TIME - - // cap to number of real waves - int waveId = ( waveCount / 2 ) - // last wave is clearly unfinished so don't use, just cap to last actually used one - if ( waveId >= GetWaveDataSize() - 1 ) + foreach ( AT_SpawnData data in minionDatas ) { - waveId = GetWaveDataSize() - 2 - waveCount = waveId * 2 + string ent = data.aitype + waitthread AT_SpawnDroppodSquad( campData, spawnId, ent, eventManager ) + data.pendingSpawns -= SQUAD_SIZE + if ( data.pendingSpawns <= 0 ) // current spawn data has reached max spawn amount + minionDatas.removebyvalue( data ) // remove this data + if ( GetScriptManagedNPCArrayLength_Alive( eventManager ) >= totalAllowedOnField ) // we have enough npcs on field? + break // stop following spawning functions } - - SetGlobalNetInt( "AT_currentWave", waveId ) - bool isBossWave = waveCount / float( 2 ) > waveId // odd number waveCount means boss wave - - // announce the wave - foreach ( entity player in GetPlayerArray() ) + if ( minionDatas.len() == 0 ) // all spawn data has finished spawn + return + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField - SQUAD_SIZE ) // wait until we have lost more than 1 squad { - if ( isBossWave ) - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnounceBoss" ) - else - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnouncePreParty", 0.0, waveId ) + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) } - - wait WAVE_STATE_TRANSITION_TIME - - // run the wave - - AT_WaveData wave = GetWaveData( waveId ) - array< array > campSpawnData - - if ( isBossWave ) - campSpawnData = wave.bossSpawnData - else - campSpawnData = wave.spawnDataArrays - - // initialise pending spawns - foreach ( array< AT_SpawnData > campData in campSpawnData ) + } +} + +// for AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK, handles a single spawndata +void function AT_DroppodSquadEvent_Single( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // get ent and create a script managed array for current event + string ent = data.aitype + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] + + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = data.totalAllowedOnField // mostly 12 for grunts and spectres, too much! + // start spawner + while ( true ) + { + waitthread AT_SpawnDroppodSquad( campData, spawnId, ent, eventManager ) + data.pendingSpawns -= SQUAD_SIZE + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField - SQUAD_SIZE ) // wait until we have less npcs than allowed count { - foreach ( AT_SpawnData spawnData in campData ) - spawnData.pendingSpawns = spawnData.totalToSpawn - } - - // clear tracked spawns - file.trackedCampNPCSpawns = {} - while ( true ) - { - // if this is ever 0 by the end of this loop, wave is complete - int numActiveCampSpawners = 0 - - // iterate over camp data for wave - for ( int campIdx = 0; campIdx < campSpawnData.len() && campIdx < file.camps.len(); campIdx++ ) - { - if ( !( campIdx in file.trackedCampNPCSpawns ) ) - file.trackedCampNPCSpawns[ campIdx ] <- {} - - // iterate over ai spawn data for camp - foreach ( AT_SpawnData spawnData in campSpawnData[ campIdx ] ) - { - if ( !( spawnData.aitype in file.trackedCampNPCSpawns[ campIdx ] ) ) - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] <- 0 - - if ( spawnData.pendingSpawns > 0 || file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] > 0 ) - numActiveCampSpawners++ - - // try to spawn as many ai as we can, as long as the camp doesn't already have too many spawned - int spawnCount - for ( spawnCount = 0; spawnCount < spawnData.pendingSpawns && spawnCount < spawnData.totalAllowedOnField - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ]; ) - { - // not doing this in a generic way atm, but could be good for the future if we want to support more ai - switch ( spawnData.aitype ) - { - case "npc_soldier": - case "npc_spectre": - case "npc_stalker": - thread AT_SpawnDroppodSquad( campIdx, spawnData.aitype ) - spawnCount += 4 - break - - case "npc_super_spectre": - thread AT_SpawnReaper( campIdx ) - spawnCount += 1 - break - - case "npc_titan": - thread AT_SpawnBountyTitan( campIdx ) - spawnCount += 1 - break - - default: - print( "BOUNTY HUNT: Tried to spawn unsupported ai of type \"" + "\" at camp " + campIdx ) - } - } - - // track spawns - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] += spawnCount - spawnData.pendingSpawns -= spawnCount - } - } - - if ( numActiveCampSpawners == 0 ) - break - - wait 0.5 + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) } - - wait WAVE_STATE_TRANSITION_TIME - - // banking phase } } -// entity funcs - -void function AT_SpawnDroppodSquad( int camp, string aiType ) +void function AT_SpawnDroppodSquad( AT_WaveOrigin campData, int spawnId, string aiType, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.dropPodSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].dropPodSpawnPoints.getrandom() + spawnpoint = campData.dropPodSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnDropPod( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, aiType, void function( array guys ) : ( camp, aiType ) - { - AT_HandleSquadSpawn( guys, camp, aiType ) - }) + AiGameModes_SpawnDropPod( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + aiType, + // squad handler + void function( array guys ) : ( campData, spawnId, aiType, scriptManagerId ) + { + AT_HandleSquadSpawn( guys, campData, spawnId, aiType, scriptManagerId ) + }, + eDropPodFlag.DISSOLVE_AFTER_DISEMBARKS + ) } -void function AT_HandleSquadSpawn( array guys, int camp, string aiType ) +void function AT_HandleSquadSpawn( array guys, AT_WaveOrigin campData, int spawnId, string aiType, int scriptManagerId ) { foreach ( entity guy in guys ) { - guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) - - // untrack them on death - thread AT_WaitToUntrackNPC( guy, camp, aiType ) + // TODO: NPCs still seem to go outside their camp ??? + //guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) + + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, guy ) + thread AT_TrackNPCLifeTime( guy, spawnId, aiType ) + + thread AT_ForceAssaultAroundCamp( guy, campData ) + } +} + +void function AT_ForceAssaultAroundCamp( entity guy, AT_WaveOrigin campData ) +{ + guy.EndSignal( "OnDestroy" ) + guy.EndSignal( "OnDeath" ) + + // goal check + vector ornull goalPos = NavMesh_ClampPointForAI(campData.origin, guy) + goalPos = goalPos == null ? campData.origin : goalPos + expect vector(goalPos) + + float goalRadius = campData.radius / 4 + float guyGoalRadius = guy.GetMinGoalRadius() + if ( guyGoalRadius > goalRadius ) // this npc cannot use forced goal radius? + goalRadius = guyGoalRadius + + while( true ) + { + guy.AssaultPoint( goalPos ) + guy.AssaultSetGoalRadius( goalRadius ) + guy.AssaultSetFightRadius( 0 ) + guy.AssaultSetArrivalTolerance( int(goalRadius) ) + + wait RandomFloatRange( 1, 5 ) + } +} + +void function AT_ReaperEvent( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // create a script managed array for current event + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] + + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = 1 // 1 allowed at the same time for heavy armor units + if ( AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + totalAllowedOnField = data.totalAllowedOnField + + while ( true ) + { + waitthread AT_SpawnReaper( campData, spawnId, eventManager ) + data.pendingSpawns -= 1 + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField ) // wait until we have less npcs than allowed count + { + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + } } } -void function AT_SpawnReaper( int camp ) +void function AT_SpawnReaper( AT_WaveOrigin campData, int spawnId, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.dropPodSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].titanSpawnPoints.getrandom() + spawnpoint = campData.dropPodSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnReaper( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, "npc_super_spectre",void function( entity reaper ) : ( camp ) + AiGameModes_SpawnReaper( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + "npc_super_spectre_aitdm", + // reaper handler + void function( entity reaper ) : ( campData, spawnId, scriptManagerId ) + { + AT_HandleReaperSpawn( reaper, campData, spawnId, scriptManagerId ) + } + ) +} + +void function AT_HandleReaperSpawn( entity reaper, AT_WaveOrigin campData, int spawnId, int scriptManagerId ) +{ + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, reaper ) + thread AT_TrackNPCLifeTime( reaper, spawnId, "npc_super_spectre" ) + + thread AT_ForceAssaultAroundCamp( reaper, campData ) +} + +void function AT_BountyTitanEvent( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // create a script managed array for current event + int eventManager = CreateScriptManagedEntArray() + + int totalAllowedOnField = 1 // 1 allowed at the same time for heavy armor units + if ( AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + totalAllowedOnField = data.totalAllowedOnField + while ( true ) { - thread AT_WaitToUntrackNPC( reaper, camp, "npc_super_spectre" ) - }) + waitthread AT_SpawnBountyTitan( campData, spawnId, eventManager ) + data.pendingSpawns -= 1 + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField ) // wait until we have less npcs than allowed count + { + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + } + } } -void function AT_SpawnBountyTitan( int camp ) +void function AT_SpawnBountyTitan( AT_WaveOrigin campData, int spawnId, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.titanSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].titanSpawnPoints.getrandom() + spawnpoint = campData.titanSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) @@ -320,57 +1625,191 @@ void function AT_SpawnBountyTitan( int camp ) int bountyID = 0 try { - bountyID = ReserveBossID( VALID_BOUNTY_TITAN_SETTINGS.getrandom() ) + bountyID = ReserveBossID( AT_BOUNTY_TITANS_AI_SETTINGS.getrandom() ) } catch ( ex ) {} // if we go above the expected wave count that vanilla supports, there's basically no way to ensure that this func won't error, so default 0 after that point string aisettings = GetTypeFromBossID( bountyID ) string titanClass = expect string( Dev_GetAISettingByKeyField_Global( aisettings, "npc_titan_player_settings" ) ) + AiGameModes_SpawnTitan( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + titanClass, + aisettings, + // titan handler + void function( entity titan ) : ( campData, spawnId, bountyID, scriptManagerId ) + { + AT_HandleBossTitanSpawn( titan, campData, spawnId, bountyID, scriptManagerId ) + } + ) +} + +void function AT_HandleBossTitanSpawn( entity titan, AT_WaveOrigin campData, int spawnId, int bountyID, int scriptManagerId ) +{ + // set the bounty to be campEnt, for client tracking + SetGlobalNetEnt( "camp" + string( spawnId + 1 ) + "Ent", titan ) + // set up health + titan.SetMaxHealth( titan.GetMaxHealth() * AT_BOUNTY_TITAN_HEALTH_MULTIPLIER ) + titan.SetHealth( titan.GetMaxHealth() ) + // make minimap always show them and highlight them + titan.Minimap_AlwaysShow( TEAM_IMC, null ) + titan.Minimap_AlwaysShow( TEAM_MILITIA, null ) + thread BountyBossHighlightThink( titan ) + + // set up titan-specific death callbacks, mark it as bounty boss for finalDamageCallbacks to work + file.titanIsBountyBoss[ titan ] <- true + file.bountyTitanRewards[ titan ] <- ATTRITION_SCORE_BOSS_DAMAGE + AddEntityCallback_OnKilled( titan, OnBountyTitanKilled ) - AiGameModes_SpawnTitan( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, titanClass, aisettings, void function( entity titan ) : ( camp, bountyID ) + titan.GetTitanSoul().soul.skipDoomState = true + // i feel like this should be localised, but there's nothing for it in r1_english? + titan.SetTitle( GetNameFromBossID( bountyID ) ) + + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, titan ) + thread AT_TrackNPCLifeTime( titan, spawnId, "npc_titan" ) +} + +void function BountyBossHighlightThink( entity titan ) +{ + titan.EndSignal( "OnDestroy" ) + titan.EndSignal( "OnDeath" ) + + while ( true ) { - // set up titan-specific death/damage callbacks - AddEntityCallback_OnDamaged( titan, OnBountyDamaged) - AddEntityCallback_OnKilled( titan, OnBountyKilled ) - - titan.GetTitanSoul().soul.skipDoomState = true - // i feel like this should be localised, but there's nothing for it in r1_english? - titan.SetTitle( GetNameFromBossID( bountyID ) ) - thread AT_WaitToUntrackNPC( titan, camp, "npc_titan" ) - } ) + Highlight_SetEnemyHighlight( titan, "enemy_boss_bounty" ) + titan.WaitSignal( "StopPhaseShift" ) // prevent phase shift mess up highlights + } +} + +void function OnNPCTitanFinalDamaged( entity titan, var damageInfo ) +{ + if ( titan in file.titanIsBountyBoss ) + OnBountyTitanDamaged( titan, damageInfo ) } -// Tracked entities will require their own "wallet" -// for titans it should be used for rounding error compenstation -// for infantry it sould be used to store money if the npc kills a player -void function OnBountyDamaged( entity titan, var damageInfo ) +void function OnBountyTitanDamaged( entity titan, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) + if ( !IsValid( attacker ) ) // delayed by projectile shots + return + // damaged by npc or something? if ( !attacker.IsPlayer() ) - attacker = GetLatestAssistingPlayerInfo( titan ).player - - if ( IsValid( attacker ) && attacker.IsPlayer() ) { - int reward = int ( BOUNTY_TITAN_DAMAGE_POOL * DamageInfo_GetDamage( damageInfo ) / titan.GetMaxHealth() ) - printt ( titan.GetMaxHealth(), DamageInfo_GetDamage( damageInfo ) ) - - AT_AddPlayerCash( attacker, reward ) + attacker = GetBountyBossDamageOwner( attacker, titan ) + if ( !IsValid( attacker ) || !attacker.IsPlayer() ) + return } + + // respawn FUCKED UP pilot weapon against titan's damage calculation, have to copy-paste this check from Titan_NPCTookDamage() + if ( HeavyArmorCriticalHitRequired( damageInfo ) && + CritWeaponInDamageInfo( damageInfo ) && + !IsCriticalHit( attacker, titan, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) ) && + IsValid( attacker ) && + !attacker.IsTitan() ) + return + + int rewardSegment = ATTRITION_SCORE_BOSS_DAMAGE + int healthSegment = titan.GetMaxHealth() / rewardSegment + + // sometimes damage is not enough to add 1 point, we save the damage for player's next attack + if ( !( titan in file.playerSavedBountyDamage[ attacker ] ) ) + file.playerSavedBountyDamage[ attacker ][ titan ] <- 0 + + file.playerSavedBountyDamage[ attacker ][ titan ] += int( DamageInfo_GetDamage( damageInfo ) ) + if ( file.playerSavedBountyDamage[ attacker ][ titan ] < healthSegment ) + return // they can't earn reward from this shot + + int damageSegment = file.playerSavedBountyDamage[ attacker ][ titan ] / healthSegment + int savedDamageLeft = file.playerSavedBountyDamage[ attacker ][ titan ] % healthSegment + file.playerSavedBountyDamage[ attacker ][ titan ] = savedDamageLeft + + float damageFrac = float( damageSegment ) / rewardSegment + int rewardLeft = file.bountyTitanRewards[ titan ] + int reward = int( ATTRITION_SCORE_BOSS_DAMAGE * damageFrac ) + if ( reward >= rewardLeft ) // overloaded shot? + reward = rewardLeft + file.bountyTitanRewards[ titan ] -= reward + + if ( reward > 0 ) + AT_AddPlayerBonusPointsForBossDamaged( attacker, titan, reward, damageInfo ) } -void function OnBountyKilled( entity titan, var damageInfo ) +void function OnBountyTitanKilled( entity titan, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) + if ( !IsValid( attacker ) ) // delayed by projectile shots + return + // damaged by npc or something? if ( !attacker.IsPlayer() ) - attacker = GetLatestAssistingPlayerInfo( titan ).player + { + attacker = GetBountyBossDamageOwner( attacker, titan ) + if ( !IsValid( attacker ) || !attacker.IsPlayer() ) + return + } + + // add all remaining reward to attacker + // bounty killed bonus handled by AT_PlayerOrNPCKilledScoreEvent() + int rewardLeft = file.bountyTitanRewards[ titan ] + delete file.bountyTitanRewards[ titan ] + if ( rewardLeft > 0 ) + AT_AddPlayerBonusPointsForBossDamaged( attacker, titan, rewardLeft, damageInfo ) + + // remove this bounty's damage saver + foreach ( entity player in GetPlayerArray() ) + { + if ( titan in file.playerSavedBountyDamage[ player ] ) + delete file.playerSavedBountyDamage[ player ][ titan ] + } + + // faction dialogue + int team = attacker.GetTeam() + PlayFactionDialogueToPlayer( "bh_playerKilledBounty", attacker ) + PlayFactionDialogueToTeamExceptPlayer( "bh_bountyClaimedByFriendly", team, attacker ) + PlayFactionDialogueToTeam( "bh_bountyClaimedByEnemy", GetOtherTeam( team ) ) +} + +entity function GetBountyBossDamageOwner( entity attacker, entity titan ) +{ + if ( attacker.IsPlayer() ) // already a player + return attacker - if ( IsValid( attacker ) && attacker.IsPlayer() ) - AT_AddPlayerCash( attacker, BOUNTY_TITAN_KILL_REWARD ) + if ( attacker.IsTitan() ) // attacker is a npc titan + { + // try to find it's pet titan owner + if ( IsValid( GetPetTitanOwner( attacker ) ) ) + return GetPetTitanOwner( attacker ) + } + + // other damages or non-owner npcs, not sure how it happens, just use this titan's last attacker + return GetLatestAssistingPlayerInfo( titan ).player } -void function AT_WaitToUntrackNPC( entity guy, int camp, string aiType ) +void function AT_TrackNPCLifeTime( entity guy, int spawnId, string aiType ) { guy.WaitSignal( "OnDeath", "OnDestroy" ) - file.trackedCampNPCSpawns[ camp ][ aiType ]-- + + string npcNetVar = GetNPCNetVarName( aiType, spawnId ) + SetGlobalNetInt( npcNetVar, GetGlobalNetInt( npcNetVar ) - 1 ) +} + + +// network var +string function GetNPCNetVarName( string className, int spawnId ) +{ + string npcId = string( GetAiTypeInt( className ) + 1 ) + string campLetter = GetCampLetter( spawnId ) + if ( npcId == "0" ) // cannot find this ai support! + { + if ( className == "npc_super_spectre" ) // stupid, reapers are not handled by GetAiTypeInt(), but it must be 4 + return "4" + campLetter + "campCount" + return "" + } + return npcId + campLetter + "campCount" } + +///////////////////////////// +///// NPC FUNCTIONS END ///// +///////////////////////////// -- cgit v1.2.3 From 9181e52e0af606986af3c733ad78360f16a40be8 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 4 May 2023 22:32:48 +0100 Subject: Fix serverbrowser filtering by gamemode (#639) --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index c31185ee..7ea8134a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -771,7 +771,7 @@ void function FilterServerList() if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != server.map ) continue; - if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != server.playlist ) + if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != GetGameModeDisplayName(server.playlist) ) continue; // Search -- cgit v1.2.3 From c2f124f3879158e4e3e1733c2c31b3decaf2b1b4 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 12 May 2023 00:25:42 +0200 Subject: Bump mods version to `1.14.0` (#643) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 00b779a4..54834676 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 66d29cae..f3f73fde 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index e1df99ba..3525c434 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From d2a7bcbfed51494caa11da1e1376b21feb6976d6 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Wed, 24 May 2023 20:11:04 +0300 Subject: Add Mod Settings (#518) * Add Mod Settings * Make rounding optional * Add recursive search * too much shit Add custom buttons, expand menu further, sanitize display names, cleanup, add more descriptive errors and throw them early, rework slightly func params * Remove Test Stuff * Clean-Up * Revert mod version change * Replace GetIndex with PureModulo better, more understandable version of the function. * Fix Slider bug * Fix Localization * Add eject quotes (#527) * Upload cl_titan_cockpit.nut * Add eject string in script * Moved to client * index issue + removed else so always returns * Apply suggestions from code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Rest of the suggestions because github makes me want to cry * Commit suggestions from review GitHub really hates batching suggestions Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update localization * Update Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut From ASpoonPlaysGames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update Northstar.Client/mod.json From ASpoonPlaysames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut From ASpoonPlaysGames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Delete cl_titan_cockpit.nut * Apply suggestions from Spoon's code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Formatting for ModSettings + Remove Base Northstar Settings (#1) * fix formatting * add newline * formatting part 1 * formatting part 2 * formatting again Co-authored-by: EladNLG * reset vmt (#2) * reset vmt * formatting * more formatting * Fixes, color modification * Fix Image behind button & make image clickable using a hack because imagepanels don't get click events and i hate them * Formatting Fixes The First * Apply suggestions from Spoon's review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Formatting Fixes The Second * Fix reset popup appearing when not clicking on button * Fix only being able to type 1 char at a time * Fix more bugs - never being able to get out of modsettings dialogs - setting duplication glitch * Fix alignment * add no results/mods (need localization) * he forgor :( make addmodsettingsbutton global Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * Clean up (thanks @uniboi) Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * forgot to add this too Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * Mod settings submenus (#4) * allow for submenu closing * hide reset vgui on buttons * My code got GECKO'd gecko suggestions Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * uniboi fixing his own mistakes moment + more prints removed (thanks @uniboi) Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * aaaaaaaa Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * rename ms_slider * add a newline * add temporary aliases * fix aliases and localization * update button width for categories * fix resets accessing out of bounds index * allow unicode search * use correct index variable * update function names --------- Co-authored-by: JMM889901 <41163714+JMM889901@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Co-authored-by: uniboi Co-authored-by: uniboi --- Northstar.Client/mod.json | 11 + Northstar.Client/mod/materials/vgui/reset.vmt | 12 + Northstar.Client/mod/materials/vgui/reset.vtf | Bin 0 -> 5712 bytes .../northstar_client_localisation_english.txt | 21 + .../northstar_client_localisation_french.txt | 18 + .../northstar_client_localisation_italian.txt | 18 + .../mod/resource/ui/menus/mod_settings.menu | 511 +++++++++ .../mod/resource/ui/menus/panels/mod_setting.res | 183 ++++ .../mod/scripts/vscripts/ui/menu_ingame.nut | 15 +- .../mod/scripts/vscripts/ui/menu_lobby.nut | 9 +- .../mod/scripts/vscripts/ui/menu_mod_settings.nut | 1105 ++++++++++++++++++++ .../mod/scripts/vscripts/ui/ns_slider.nut | 52 + .../mod/scripts/vscripts/ui/panel_mainmenu.nut | 4 + 13 files changed, 1952 insertions(+), 7 deletions(-) create mode 100644 Northstar.Client/mod/materials/vgui/reset.vmt create mode 100644 Northstar.Client/mod/materials/vgui/reset.vtf create mode 100644 Northstar.Client/mod/resource/ui/menus/mod_settings.menu create mode 100644 Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 54834676..e9536d66 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -115,6 +115,17 @@ "RunOn": "UI" }, { + "Path": "ui/ns_slider.nut", + "RunOn": "UI" + }, + { + "Path": "ui/menu_mod_settings.nut", + "RunOn": "UI", + "UICallback":{ + "Before": "AddModSettingsMenu" + } + }, + { "Path": "ui/ui_mouse_capture.nut", "RunOn": "UI" } diff --git a/Northstar.Client/mod/materials/vgui/reset.vmt b/Northstar.Client/mod/materials/vgui/reset.vmt new file mode 100644 index 00000000..84034586 --- /dev/null +++ b/Northstar.Client/mod/materials/vgui/reset.vmt @@ -0,0 +1,12 @@ +"Basic" +{ + "$basetexture" "vgui/reset" + "$translucent" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$no_fullbright" 1 + "$ignorez" 1 + "$nolod" 1 + + "$SHADERSRGBREAD360" 1 +} diff --git a/Northstar.Client/mod/materials/vgui/reset.vtf b/Northstar.Client/mod/materials/vgui/reset.vtf new file mode 100644 index 00000000..5ffb86a9 Binary files /dev/null and b/Northstar.Client/mod/materials/vgui/reset.vtf differ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index c25708a6..5dabd539 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -321,5 +321,26 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" + + // Mod Settings + "MOD_SETTINGS" "Mod Settings" + "NORTHSTAR_BASE_SETTINGS" "Northstar Base Settings" + "ONLY_HOST_MATCH_SETTINGS" "Only Host can change Private Match settings" + "ONLY_HOST_CAN_START_MATCH" "Only Host can Start the Match" + "MATCH_COUNTDOWN_LENGTH" "Private Match Countdown Duration" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Log Unknown Client Commands" + "DISALLOWED_TACTICALS" "Prohibited Tacticals" + "TACTICAL_REPLACEMENT" "Replacement Tactical" + "DISALLOWED_WEAPONS" "Prohibited Weapons" + "REPLACEMENT_WEAPON" "Replacement Weapon" + "SHOULD_RETURN_TO_LOBBY" "Return To Lobby After Match End" + "ARE_YOU_SURE" "Are you sure?" + "WILL_RESET_ALL_SETTINGS" "This will reset ALL settings that belong to this category.\n\nThis is not revertable." + "WILL_RESET_SETTING" "This will reset the %s1 setting to it's default value.\n\nThis is not revertable." + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Reset" + "MOD_SETTINGS_RESET_ALL" "Reset All" + "NO_RESULTS" "No results." + "NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 2a199186..d90cea05 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -319,5 +319,23 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "INVALID_MASTERSERVER_TOKEN" "Jeton du server maître invalide ou expiré" "JSON_PARSE_ERROR" "Une erreur est survenue durant l'analyse JSON" "UNSUPPORTED_VERSION" "La version que vous utilisez n'est plus supportée" + + "MOD_SETTINGS" "Paramètres de mod" + "NORTHSTAR_BASE_SETTINGS" "Paramètres de base de Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Seul l'hôte peut changer les paramètres de match privé" + "ONLY_HOST_CAN_START_MATCH" "Seul l'hôte peut lancer le match" + "MATCH_COUNTDOWN_LENGTH" "Durée du compte à rebours de match privé" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Enregistrer les commandes client inconnues" + "DISALLOWED_TACTICALS" "Capacités interdites" + "TACTICAL_REPLACEMENT" "Capacités de remplacement" + "DISALLOWED_WEAPONS" "Armes interdites" + "REPLACEMENT_WEAPON" "Armes de remplacement" + "SHOULD_RETURN_TO_LOBBY" "Retour au lobby après la fin du match" + "ARE_YOU_SURE" "Êtes-vous certain ?" + "WILL_RESET_ALL_SETTINGS" "Ceci réinitialisera tous les paramètres de cette catégorie.\n\nCette action est irréversible." + "WILL_RESET_SETTING" "Ceci réinitialisera le paramètre %s1 à sa valeur par défaut.\n\nCette action est irréversible." + "MOD_SETTINGS_SERVER" "Serveur" + "MOD_SETTINGS_RESET" "Réinitialiser" + "MOD_SETTINGS_RESET_ALL" "Tout réinitialiser" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index 72bf7030..13835b8b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -319,5 +319,23 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto" "JSON_PARSE_ERROR" "Errore nell'analisi di risposta json" "UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata" + + "MOD_SETTINGS" "Impostazioni Mod" + "NORTHSTAR_BASE_SETTINGS" "Impostazioni base Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Solo l'Host può modificare le impostazioni della Partita Privata" + "ONLY_HOST_CAN_START_MATCH" "Solo l'Host può Iniziare la Partita" + "MATCH_COUNTDOWN_LENGTH" "Durata Countdown della Partita Privata" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registra Comandi Client Sconosciuti" + "DISALLOWED_TACTICALS" "Abilità Proibite" + "TACTICAL_REPLACEMENT" "Sostituzione Abilità" + "DISALLOWED_WEAPONS" "Armi Proibite" + "REPLACEMENT_WEAPON" "Sostituzione Armi" + "SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita" + "ARE_YOU_SURE" "Sei sicuro?" + "WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato." + "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1. + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Ripristina" + "MOD_SETTINGS_RESET_ALL" "Ripristina Tutto" } } diff --git a/Northstar.Client/mod/resource/ui/menus/mod_settings.menu b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu new file mode 100644 index 00000000..2fed2bd1 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu @@ -0,0 +1,511 @@ +"resource/ui/menus/mods_browse.menu" +{ + "menu" + { + "ControlName" "Frame" + "xpos" "0" + "ypos" "0" + "zpos" "3" + "wide" "f0" + "tall" "f0" + "autoResize" "1" + "visible" "1" + "enabled" "1" + "pinCorner" "0" + "PaintBackgroundType" "0" + "infocus_bgcolor_override" "0 0 0 0" + "outoffocus_bgcolor_override" "0 0 0 0" + "Vignette" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuVignette" + } + "Title" + { + "ControlName" "Label" + "InheritProperties" "MenuTitle" + "labelText" "#MOD_SETTINGS" + } + "ImgTopBar" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + } + "DarkenBackground" + { + "ControlName" "Label" + "classname" "ConnectingHUD" + "xpos" "0" + "ypos" "0" + "zpos" "99" + "wide" "%100" + "tall" "%100" + "labelText" "" + "bgcolor_override" "0 0 0 0" + "visible" "0" + "paintbackground" "1" + } + "ButtonRowAnchor" + { + "ControlName" "Label" + "labelText" "" + "pin_to_sibling" "DarkenBackground" + "pin_to_sibling_corner" "TOP_LEFT" + "pin_corner_to_sibling" "BOTTOM_LEFT" + "xpos" "-150" + "ypos" "-200" + } + "FilterButtonsRowAnchor" + { + "ControlName" "Label" + "pin_to_sibling" "LabelDetails" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "pin_corner_to_sibling" "TOP_LEFT" + "labelText" "" + "ypos" "12" + } + "NoResultLabel" + { + "ControlName" "Label" + "xpos" "0" + ypos "0" + wide "1200" + tall "675" + //auto_tall_tocontents 1 + visible "1" + enabled "1" + //auto_wide_tocontents 1 + labelText "No results." + textAlignment "center" + //auto_wide_tocontents "1" + //auto_tall_tocontents "1" + //fgcolor_override "255 255 255 255" + //bgcolor_override "0 0 0 200" + font Default_41 + + pin_to_sibling ButtonRowAnchor + pin_to_sibling_corner TOP_LEFT + pin_corner_to_sibling TOP_LEFT + } + // pain // + "BtnMod1" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "pin_to_sibling" "ButtonRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + "navUp" "BtnMod15" + "navDown" "BtnMod2" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "scriptID" "0" + } + "BtnMod2" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "pin_to_sibling" "BtnMod1" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod1" + "navDown" "BtnMod3" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "scriptID" "1" + } + "BtnMod3" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "2" + "pin_to_sibling" "BtnMod2" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod2" + "navDown" "BtnMod4" + } + "BtnMod4" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "3" + "pin_to_sibling" "BtnMod3" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod3" + "navDown" "BtnMod5" + } + "BtnMod5" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "4" + "pin_to_sibling" "BtnMod4" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod4" + "navDown" "BtnMod6" + } + "BtnMod6" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "5" + "pin_to_sibling" "BtnMod5" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod5" + "navDown" "BtnMod7" + } + "BtnMod7" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "6" + "pin_to_sibling" "BtnMod6" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod6" + "navDown" "BtnMod8" + } + "BtnMod8" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "7" + "pin_to_sibling" "BtnMod7" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod7" + "navDown" "BtnMod9" + } + "BtnMod9" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "8" + "pin_to_sibling" "BtnMod8" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod8" + "navDown" "BtnMod10" + } + "BtnMod10" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "9" + "pin_to_sibling" "BtnMod9" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod9" + "navDown" "BtnMod11" + } + "BtnMod11" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "10" + "pin_to_sibling" "BtnMod10" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod10" + "navDown" "BtnMod12" + } + "BtnMod12" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "11" + "pin_to_sibling" "BtnMod11" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod11" + "navDown" "BtnMod13" + } + "BtnMod13" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "12" + "pin_to_sibling" "BtnMod12" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod12" + "navDown" "BtnMod14" + } + "BtnMod14" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "13" + "pin_to_sibling" "BtnMod13" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod13" + "navDown" "BtnMod15" + } + "BtnMod15" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "14" + "pin_to_sibling" "BtnMod14" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod14" + "navDown" "BtnMod1" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "FilterPanel" + { + "ControlName" "RuiPanel" + "wide" "1220" + "tall" "112" + //"xpos" "-8" + "classname" "FilterPanelChild" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "FilterButtonsRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "LabelDetails" + { + "ControlName" "RuiPanel" + "tall" "695" + "wide" "1220" + "xpos" "10" + "ypos" "10" + "pin_to_sibling" "ButtonRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + "rui" "ui/knowledgebase_panel.rpak" + "wrap" "1" + "visible" "1" + "zpos" "-1" + } + "BtnSearchLabel" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "#SEARCHBAR_LABEL" + "textAlignment" "west" + "classname" "FilterPanelChild" + "wide" "500" + "xpos" "-23" + "ypos" "-16" + "wrap" "1" + "visible" "1" + "zpos" "0" + "pin_to_sibling" "FilterButtonsRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModsSearch" + { + "ControlName" "TextEntry" + "classname" "FilterPanelChild" + "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + "xpos" "-400" + "ypos" "-5" + "wide" "390" + "tall" "30" + "textHidden" "0" + "editable" "1" + "font" "Default_21" + "allowRightClickMenu" "0" + "allowSpecialCharacters" "1" + "unicode" "1" + "pin_to_sibling" "BtnSearchLabel" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + } + "BtnFiltersClear" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "#CLEAR_FILTERS" + "classname" "FilterPanelChild" + "wide" "100" + "xpos" "0" + "ypos" "0" + "zpos" "90" + "scriptID" "999" + "pin_to_sibling" "BtnSearchLabel" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "BtnModListUpArrow" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "A"F + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "0" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListUpArrowPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "0" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListDownArrow" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "V" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "-655" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListDownArrowPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "-655" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListSlider" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "V" + "wide" "40" + "tall" "420" + "xpos" "2" + "ypos" "-40" + "zpos" "0" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListSliderPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "420" + "xpos" "2" + "ypos" "-40" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + // sh_menu_models.gnut has a global function which gets called when + // left mouse button gets called while hovering and has mouse + // deltaX; deltaY which we can yoink for ourselfes + "MouseMovementCapture" + { + "ControlName" "CMouseMovementCapturePanel" + "wide" "40" + "tall" "604" + "xpos" "2" + "ypos" "-40" + "zpos" "1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "ButtonTooltip" + { + "ControlName" "CNestedPanel" + "InheritProperties" "ButtonTooltip" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "FooterButtons" + { + "ControlName" "CNestedPanel" + "InheritProperties" "FooterButtons" + } + } +} diff --git a/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res new file mode 100644 index 00000000..92dce922 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res @@ -0,0 +1,183 @@ +"resource/ui/menus/panels/mod_setting.res" +{ + "FULL" + { + "ControlName" "Label" + "classname" "ConnectingHUD" + "xpos" "0" + "ypos" "0" + "zpos" "99" + "wide" "1200" + "tall" "45" + "labelText" "" + "bgcolor_override" "0 0 0 0" + "visible" "0" + "paintbackground" "1" + } + "BtnMod" + { + "ControlName" "Label" + "InheritProperties" "RuiSmallButton" + "labelText" "Mod" + //"auto_wide_tocontents" "1" + "navRight" "EnumSelectButton" + "navLeft" "TextEntrySetting" + "wide" "390" + "tall" "45" + } + // we're getting to the top of this :) + "TopLine" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + "ypos" "0" + "wide" "%100" + "pin_to_sibling" "BtnMod" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "ModTitle" + { + "ControlName" "Label" + "InheritProperties" "RuiSmallButton" + "labelText" "Mod" + "font" "DefaultBold_43" + //"auto_wide_tocontents" "1" + "zpos" "-999" + "textAlignment" "center" + "navRight" "EnumSelectButton" + "navLeft" "TextEntrySetting" + "wide" "1200" + "tall" "45" + + } + "Slider" + { + "ControlName" "SliderControl" + //"InheritProperties" "RuiSmallButton" + minValue 0.0 + maxValue 2.0 + stepSize 0.05 + "pin_to_sibling" "BtnMod" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + "navRight" "ResetModToDefault" + "navLeft" "TextEntrySetting" + //isValueClampedToStepSize 1 + BtnDropButton + { + ControlName RuiButton + //InheritProperties WideButton + style SliderButton + "wide" "320" + "tall" "45" + "labelText" "" + "auto_wide_tocontents" "0" + } + "wide" "320" + "tall" "45" + } + "EnumSelectButton" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "style" "DialogListButton" + "labelText" "" + "zpos" "4" + "wide" "225" + "tall" "45" + //"xpos" "10" + "scriptID" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "RIGHT" + "navLeft" "ResetModToDefault" + "navRight" "TextEntrySetting" + } + "ResetModToDefault" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "" + "zpos" "0" + "xpos" "10" + "wide" "45" + "tall" "45" + "scriptID" "0" + "pin_to_sibling" "EnumSelectButton" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "LEFT" + "navLeft" "Slider" + "navRight" "TextEntrySetting" + } + "ResetModImage" + { + "ControlName" "ImagePanel" + "image" "vgui/reset" + "scaleImage" "1" + "drawColor" "180 180 180 255" // vanilla label color + "visible" "0" + "wide" "30" + "tall" "30" + "enabled" "0" + + "pin_to_sibling" "ResetModToDefault" + "pin_corner_to_sibling" "CENTER" + "pin_to_sibling_corner" "CENTER" + } + "OpenCustomMenu" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "Open" + //"auto_wide_tocontents" "1" + "zpos" "4" + "wide" "1200" + "textAlignment" "center" + //"font" "Default_41" + //"xpos" "10" + "tall" "40" + "scriptID" "0" + "visible" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "RIGHT" + "navLeft" "TextEntrySetting" + "navRight" "TextEntrySetting" + } + "TextEntrySetting" + { + "ControlName" "TextEntry" + "classname" "MatchSettingTextEntry" + //"xpos" "-35" + //"ypos" "-5" + "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + "wide" "160" + "tall" "30" + "scriptID" "0" + "textHidden" "0" + "editable" "1" + // NumericInputOnly 1 + "font" "Default_21" + "allowRightClickMenu" "0" + "allowSpecialCharacters" "1" + "unicode" "0" + "pin_to_sibling" "EnumSelectButton" + "pin_corner_to_sibling" "CENTER" + "pin_to_sibling_corner" "CENTER" + "navLeft" "EnumSelectButton" + "navRight" "EnumSelectButton" + } + // we're getting to the bottom of this :) + "BottomLine" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + "ypos" "5" + "wide" "%100" + //"tall" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "BOTTOM_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + } +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut index 03bd8959..35c9e9ba 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut @@ -112,8 +112,13 @@ void function InitInGameMPMenu() 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" ) ) ) + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) + + // Nobody reads the FAQ so we replace it with ModSettings because of the limited combobutton space available + //file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) + //Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) //var dataCenterButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#DATA_CENTER" ) //Hud_AddEventHandler( dataCenterButton, UIE_CLICK, OpenDataCenterDialog ) @@ -133,7 +138,7 @@ void function OnInGameMPMenu_Open() bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) - ComboButton_SetNew( file.faqButton, faqIsNew ) + //ComboButton_SetNew( file.faqButton, faqIsNew ) UpdateLoadoutButtons() RefreshCreditsAvailable() @@ -255,6 +260,10 @@ void function InitInGameSPMenu() var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif + + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) array orderedButtons diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 3c868aab..2bef0e20 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -352,8 +352,9 @@ void function SetupComboButtonTest( var menu ) 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" ) ) ) + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) comboStruct.navUpButtonDisabled = true comboStruct.navDownButton = file.genUpButton @@ -635,9 +636,9 @@ void function OnLobbyMenu_Open() ComboButton_SetNew( file.factionButton, anyNewFactions ) } - bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + /*bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) - ComboButton_SetNew( file.faqButton, faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew )*/ TryUnlockSRSCallsign() diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut new file mode 100644 index 00000000..a45082c7 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut @@ -0,0 +1,1105 @@ +untyped +global function AddModSettingsMenu +global function ModSettings_AddSetting +global function ModSettings_AddEnumSetting +global function ModSettings_AddSliderSetting +global function ModSettings_AddButton +global function ModSettings_AddModTitle +global function ModSettings_AddModCategory +global function PureModulo + +// Legacy functions for backwards compatability. These will be removed eventually +global function AddConVarSetting +global function AddConVarSettingEnum +global function AddConVarSettingSlider +global function AddModSettingsButton +global function AddModTitle +global function AddModCategory + +const int BUTTONS_PER_PAGE = 15 +const string SETTING_ITEM_TEXT = " " // this is long enough to be the same size as the textentry field + +enum eEmptySpaceType +{ + None, + TopBar, + BottomBar +} + +struct ConVarData { + string displayName + bool isEnumSetting = false + string conVar + string type + + string modName + string catName + bool isCategoryName = false + bool isModName = false + + bool isEmptySpace = false + int spaceType = 0 + + // SLIDER BULLSHIT + bool sliderEnabled = false + float min = 0.0 + float max = 1.0 + float stepSize = 0.05 + bool forceClamp = false + + bool isCustomButton = false + void functionref() onPress + + array values + var customMenu + bool hasCustomMenu = false +} + +struct { + var menu + int scrollOffset = 0 + bool updatingList = false + bool isOpen + + array conVarList + // if people use searches - i hate them but it'll do : ) + array filteredList + string filterText = "" + table enumRealValues + table setFuncs + array modPanels + array resetModButtons + array sliders + string currentMod = "" + string currentCat = "" +} file + +struct { + int deltaX = 0 + int deltaY = 0 +} mouseDeltaBuffer + +void function AddModSettingsMenu() +{ + AddMenu( "ModSettings", $"resource/ui/menus/mod_settings.menu", InitModMenu ) +} + +void function InitModMenu() +{ + file.menu = GetMenu( "ModSettings" ) + // DumpStack(2) + AddMenuFooterOption( file.menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + + ///////////////////////////// + // BASE NORTHSTAR SETTINGS // + ///////////////////////////// + + /* + ModSettings_AddModTitle( "^FF000000EXAMPLE" ) + ModSettings_AddModCategory( "I wasted way too much time on this..." ) + ModSettings_AddButton( "This is a custom button you can click on!", void function() : () + { + print( "HELLOOOOOO" ) + } ) + ModSettings_AddEnumSetting( "filter_mods", "Very Huge Enum Example", split( "Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you", " " ) ) + */ + // Nuke weird rui on filter switch :D + // RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnShowFilter" ) ), "buttonText", "" ) + + file.modPanels = GetElementsByClassname( file.menu, "ModButton" ) + + AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) + AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnModMenuClosed ) + + int len = file.modPanels.len() + for ( int i = 0; i < len; i++ ) + { + + // AddButtonEventHandler( button, UIE_CHANGE, OnSettingButtonPressed ) + // get panel + var panel = file.modPanels[i] + + // reset to default nav + var child = Hud_GetChild( panel, "BtnMod" ) + + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "BtnMod" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "BtnMod" ) ) + + // Enum button nav + child = Hud_GetChild( panel, "EnumSelectButton" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "main" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "next" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "prev" ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "EnumSelectButton" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "EnumSelectButton" ) ) + Hud_AddEventHandler( child, UIE_CLICK, UpdateEnumSetting ) + + // reset button nav + + child = Hud_GetChild( panel, "ResetModToDefault" ) + Hud_AddEventHandler( child, UIE_GET_FOCUS, void function( var child ) : (panel) + { + Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 0, 0, 0, 255 ) + }) + Hud_AddEventHandler( child, UIE_LOSE_FOCUS, void function( var child ) : (panel) + { + Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 180, 180, 180, 180 ) + }) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "ResetModToDefault" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "ResetModToDefault" ) ) + + Hud_AddEventHandler( child, UIE_CLICK, ResetConVar ) + file.resetModButtons.append(child) + + // text field nav + child = Hud_GetChild( panel, "TextEntrySetting" ) + + Hud_AddEventHandler( child, UIE_LOSE_FOCUS, SendTextPanelChanges ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "TextEntrySetting" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "TextEntrySetting" ) ) + + child = Hud_GetChild( panel, "Slider" ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "Slider" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "Slider" ) ) + + file.sliders.append( MS_Slider_Setup( child ) ) + + Hud_AddEventHandler( child, UIE_CHANGE, OnSliderChange ) + + child = Hud_GetChild( panel, "OpenCustomMenu" ) + + Hud_AddEventHandler( child, UIE_CLICK, CustomButtonPressed ) + } + + // Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_LOSE_FOCUS, OnFilterTextPanelChanged ) + Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear" ), UIE_CLICK, OnClearButtonPressed ) + // mouse delta + AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + + Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_CHANGE, void function ( var inputField ) : () + { + file.filterText = Hud_GetUTF8Text( inputField ) + OnFiltersChange() + } ) +} + +// "PureModulo" +// Used instead of modulo in some places. +// Why? beacuse PureModulo loops back onto positive numbers instead of going into the negatives. +// DO NOT TOUCH. +// a / b != floor( float( a ) / b ) +// int( float( a ) / b ) != floor( float( a ) / b ) +// Examples: +// -1 % 5 = -1 +// PureModulo( -1, 5 ) = 4 +float function PureModulo( int a, int b ) +{ + return b * ( ( float( a ) / b ) - floor( float( a ) / b ) ) +} + +void function ResetConVar( var button ) +{ + ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ] + + if ( conVar.isCategoryName ) + ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetAllConVarsForModEventHandler( conVar.catName ), "#WILL_RESET_ALL_SETTINGS" ) + else + ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetConVarEventHandler( int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ), Localize( "#WILL_RESET_SETTING", Localize( conVar.displayName ) ) ) +} + +void function ShowAreYouSureDialog( string header, void functionref() func, string details ) +{ + DialogData dialogData + dialogData.header = header + dialogData.message = details + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", func ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) +} + +void functionref() function ResetAllConVarsForModEventHandler( string catName ) +{ + return void function() : ( catName ) + { + for ( int i = 0; i < file.conVarList.len(); i++ ) + { + ConVarData c = file.conVarList[ i ] + if ( c.catName != catName || c.isCategoryName || c.isEmptySpace || c.isCustomButton ) + continue + SetConVarToDefault( c.conVar ) + + int index = file.filteredList.find( c ) + if ( file.filteredList.find( c ) < 0 ) + continue + + if ( min( BUTTONS_PER_PAGE - 1, max( 0, index - file.scrollOffset ) ) == index - file.scrollOffset ) + { + Hud_SetText( Hud_GetChild( file.modPanels[ index - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) ) + if( c.sliderEnabled ) + MS_Slider_SetValue( file.sliders[ index - file.scrollOffset ], GetConVarFloat( c.conVar ) ) + } + } + } +} + +void functionref() function ResetConVarEventHandler( int modIndex ) +{ + return void function() : ( modIndex ) + { + ConVarData c = file.filteredList[ modIndex ] + SetConVarToDefault( c.conVar ) + if ( min( BUTTONS_PER_PAGE - 1, max( 0, modIndex - file.scrollOffset ) ) == modIndex - file.scrollOffset ) + { + Hud_SetText( Hud_GetChild( file.modPanels[ modIndex - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) ) + if( c.sliderEnabled ) + MS_Slider_SetValue( file.sliders[ modIndex - file.scrollOffset ], GetConVarFloat( c.conVar ) ) + } + } +} + +//////////// +// slider // +//////////// +void function UpdateMouseDeltaBuffer( int x, int y ) +{ + mouseDeltaBuffer.deltaX += x + mouseDeltaBuffer.deltaY += y + + SliderBarUpdate() +} + +void function FlushMouseDeltaBuffer() +{ + mouseDeltaBuffer.deltaX = 0 + mouseDeltaBuffer.deltaY = 0 +} + +void function SliderBarUpdate() +{ + if ( file.filteredList.len() <= 15 ) + { + FlushMouseDeltaBuffer() + return + } + + var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" ) + + Hud_SetFocused( sliderButton ) + + float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded positions?!?!?!?!?! + float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 ) + float maxYPos = minYPos - ( maxHeight - Hud_GetHeight( sliderPanel ) ) + float useableSpace = ( maxHeight - Hud_GetHeight( sliderPanel ) ) + + float jump = minYPos - ( useableSpace / ( float( file.filteredList.len() ) ) ) + + int pos = expect int( expect array( Hud_GetPos( sliderButton ) )[1] ) + float newPos = float( pos - mouseDeltaBuffer.deltaY ) + FlushMouseDeltaBuffer() + + if ( newPos < maxYPos ) newPos = maxYPos + if ( newPos > minYPos ) newPos = minYPos + + Hud_SetPos( sliderButton, 2, newPos ) + Hud_SetPos( sliderPanel, 2, newPos ) + Hud_SetPos( movementCapture, 2, newPos ) + + file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.filteredList.len() - BUTTONS_PER_PAGE ) ) + UpdateList() +} + +void function UpdateListSliderHeight() +{ + var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" ) + + float mods = float ( file.filteredList.len() ) + + float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded 320/80??? + float minHeight = 80.0 * ( GetScreenSize()[1] / 1080.0 ) + + float height = maxHeight * ( float( BUTTONS_PER_PAGE ) / mods ) + + if ( height > maxHeight ) height = maxHeight + if ( height < minHeight ) height = minHeight + + Hud_SetHeight( sliderButton, height ) + Hud_SetHeight( sliderPanel, height ) + Hud_SetHeight( movementCapture, height ) +} + +void function UpdateList() +{ + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModsSearch" ) ) + file.updatingList = true + + array filteredList = [] + + array filters = split( file.filterText, "," ) + array list = file.conVarList + if ( filters.len() <= 0 ) + filters.append( "" ) + foreach( string f in filters ) + { + string filter = strip( f ) + string lastCatNameInFilter = "" + string lastModNameInFilter = "" + int curCatIndex = 0 + int curModTitleIndex = -1 + for ( int i = 0; i < list.len(); i++ ) + { + ConVarData prev = list[ maxint( 0, i - 1 ) ] + ConVarData c = list[i] + ConVarData next = list[ minint( list.len() - 1, i + 1 ) ] + if ( c.isEmptySpace ) + continue + + string displayName = c.displayName + if ( c.isModName ) + { + displayName = c.modName + curModTitleIndex = i + } + if ( c.isCategoryName ) + { + displayName = c.catName + curCatIndex = i + } + if ( filter == "" || SanitizeDisplayName( Localize( displayName ) ).tolower().find( filter.tolower() ) != null ) + { + if ( c.isModName ) + { + lastModNameInFilter = c.modName + array modVars = GetAllVarsInMod( list, c.modName ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + i += modVars.len() - 1 + } + else if ( c.isCategoryName ) + { + if ( lastModNameInFilter != c.modName ) + { + array modVars = GetModConVarDatas( list, curModTitleIndex ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + lastModNameInFilter = c.modName + } + filteredList.extend( GetAllVarsInCategory( list, c.catName ) ) + i += GetAllVarsInCategory( list, c.catName ).len() - 1 + lastCatNameInFilter = c.catName + } + else + { + if ( lastModNameInFilter != c.modName ) + { + array modVars = GetModConVarDatas( list, curModTitleIndex ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + lastModNameInFilter = c.modName + } + if ( lastCatNameInFilter != c.catName ) + { + filteredList.extend( GetCatConVarDatas( curCatIndex ) ) + lastCatNameInFilter = c.catName + } + filteredList.append( c ) + } + } + } + list = filteredList + filteredList = [] + } + filteredList = list + + + file.filteredList = filteredList + + int j = int( min( file.filteredList.len() + file.scrollOffset, BUTTONS_PER_PAGE ) ) + + for ( int i = 0; i < BUTTONS_PER_PAGE; i++ ) + { + Hud_SetEnabled( file.modPanels[i], i < j ) + Hud_SetVisible( file.modPanels[i], i < j ) + + if ( i < j ) + SetModMenuNameText( file.modPanels[i] ) + } + file.updatingList = false + + if ( file.conVarList.len() <= 0 ) + { + Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true ) + Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_MODS" ) + } + else if ( file.filteredList.len() <= 0 ) + { + Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true ) + Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_RESULTS" ) + } + else + { + Hud_Hide( Hud_GetChild( file.menu, "NoResultLabel" ) ) + } +} + +array function GetModConVarDatas( array arr, int index ) +{ + if ( index <= 1 ) + return [ arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ] + return [ arr[ index - 2 ], arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ] +} + +array function GetCatConVarDatas( int index ) +{ + if ( file.conVarList[ index - 1 ].spaceType != eEmptySpaceType.None ) + return [ file.conVarList[ index ] ] + return [ file.conVarList[ index - 1 ], file.conVarList[ index ] ] +} + +array function GetAllVarsInCategory( array arr, string catName ) +{ + array vars = [] + for ( int i = 0; i < arr.len(); i++ ) + { + ConVarData c = arr[i] + if ( c.catName == catName ) + { + vars.append( arr[i] ) + } + } + return vars +} + +array function GetAllVarsInMod( array arr, string modName ) +{ + array vars = [] + for ( int i = 0; i < arr.len(); i++ ) + { + ConVarData c = arr[i] + if ( c.modName == modName ) + { + vars.append( arr[i] ) + } + } + return vars +} + +void function SetModMenuNameText( var button ) +{ + int index = int ( Hud_GetScriptID( button ) ) + file.scrollOffset + ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ] + + var panel = file.modPanels[ int ( Hud_GetScriptID( button ) ) ] + + var label = Hud_GetChild( panel, "BtnMod" ) + var textField = Hud_GetChild( panel, "TextEntrySetting" ) + var enumButton = Hud_GetChild( panel, "EnumSelectButton" ) + var resetButton = Hud_GetChild( panel, "ResetModToDefault" ) + var resetVGUI = Hud_GetChild( panel, "ResetModImage" ) + var bottomLine = Hud_GetChild( panel, "BottomLine" ) + var topLine = Hud_GetChild( panel, "TopLine" ) + var modTitle = Hud_GetChild( panel, "ModTitle" ) + var customMenuButton = Hud_GetChild( panel, "OpenCustomMenu") + var slider = Hud_GetChild( panel, "Slider" ) + Hud_SetVisible( slider, false ) + Hud_SetEnabled( slider, true ) + + + if ( conVar.isEmptySpace ) + { + string s = "" + Hud_SetPos( label, 0, 0 ) + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( modTitle, false ) + Hud_SetVisible( customMenuButton, false ) + Hud_SetVisible( bottomLine, false ) + Hud_SetVisible( topLine, false ) + switch ( conVar.spaceType ) + { + case eEmptySpaceType.TopBar: + Hud_SetVisible( topLine, true ) + return + + case eEmptySpaceType.BottomBar: + Hud_SetVisible( bottomLine, true ) + return + + case eEmptySpaceType.None: + return + } + } + + Hud_SetVisible( textField, !conVar.isCategoryName ) + Hud_SetVisible( bottomLine, conVar.isCategoryName || conVar.spaceType == eEmptySpaceType.BottomBar ) + Hud_SetVisible( topLine, false ) + Hud_SetVisible( enumButton, !conVar.isCategoryName && conVar.isEnumSetting ) + Hud_SetVisible( modTitle, conVar.isModName ) + Hud_SetVisible( customMenuButton, false ) + float scaleX = GetScreenSize()[1] / 1080.0 + float scaleY = GetScreenSize()[1] / 1080.0 + if ( conVar.sliderEnabled ) + { + Hud_SetSize( slider, int( 320 * scaleX ), int( 45 * scaleY ) ) + MS_Slider s = file.sliders[ int ( Hud_GetScriptID( button ) ) ] + MS_Slider_SetMin( s, conVar.min ) + MS_Slider_SetMax( s, conVar.max ) + MS_Slider_SetStepSize( s, conVar.stepSize ) + MS_Slider_SetValue( s, GetConVarFloat( conVar.conVar ) ) + } + else Hud_SetSize( slider, 0, int( 45 * scaleY ) ) + if ( conVar.isCustomButton ) + { + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( modTitle, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( customMenuButton, true ) + Hud_SetText( customMenuButton, conVar.displayName ) + } + else if ( conVar.isModName ) + { + Hud_SetText( modTitle, conVar.modName ) + Hud_SetPos( label, 0, 0 ) + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( bottomLine, false ) + Hud_SetVisible( topLine, false ) + } + else if ( conVar.isCategoryName ) + { + Hud_SetText( label, conVar.catName ) + Hud_SetPos( label, 0, 0 ) + Hud_SetSize( label, int( scaleX * ( 1180 - 420 - 85 ) ), int( scaleY * 40 ) ) + Hud_SetVisible( label, true ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, true ) + Hud_SetVisible( resetVGUI, true ) + + Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) ) + } + else { + Hud_SetVisible( slider, conVar.sliderEnabled ) + + Hud_SetText( label, conVar.displayName ) + if (conVar.type == "float") + Hud_SetText( textField, string( GetConVarFloat(conVar.conVar) ) ) + else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) ) + Hud_SetPos( label, int(scaleX * 25), 0 ) + Hud_SetText( resetButton, "" ) + if (conVar.sliderEnabled) + Hud_SetSize( label, int(scaleX * (375 + 85)), int(scaleY * 40) ) + else Hud_SetSize( label, int(scaleX * (375 + 405)), int(scaleY * 40) ) + if ( conVar.type == "float" ) + Hud_SetText( textField, string( GetConVarFloat( conVar.conVar ) ) ) + else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) ) + Hud_SetPos( label, int( scaleX * 25 ), 0 ) + Hud_SetText( resetButton, "" ) + Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) ) + if ( conVar.sliderEnabled ) + Hud_SetSize( label, int( scaleX * ( 375 + 85 ) ), int( scaleY * 40 ) ) + else Hud_SetSize( label, int( scaleX * ( 375 + 405 ) ), int( scaleY * 40 ) ) + Hud_SetVisible( label, true ) + Hud_SetVisible( textField, true ) + Hud_SetVisible( resetButton, true ) + Hud_SetVisible( resetVGUI, true ) + } +} + +void function CustomButtonPressed( var button ) +{ + var panel = Hud_GetParent( button ) + ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ] + c.onPress() +} + +void function OnScrollDown( var button ) +{ + if ( file.filteredList.len() <= BUTTONS_PER_PAGE ) return + file.scrollOffset += 5 + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredList.len() ) + { + file.scrollOffset = file.filteredList.len() - BUTTONS_PER_PAGE + } + UpdateList() + UpdateListSliderPosition() +} + +void function OnScrollUp( var button ) +{ + file.scrollOffset -= 5 + if ( file.scrollOffset < 0 ) + { + file.scrollOffset = 0 + } + UpdateList() + UpdateListSliderPosition() +} + +void function UpdateListSliderPosition() +{ + var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) + + float mods = float ( file.filteredList.len() ) + + float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 ) + float useableSpace = ( 615.0 * ( GetScreenSize()[1] / 1080.0 ) - Hud_GetHeight( sliderPanel ) ) + + float jump = minYPos - ( useableSpace / ( mods - float( BUTTONS_PER_PAGE ) ) * file.scrollOffset ) + + + if ( jump > minYPos ) jump = minYPos + + Hud_SetPos( sliderButton , 2, jump ) + Hud_SetPos( sliderPanel , 2, jump ) + Hud_SetPos( movementCapture , 2, jump ) +} + +void function OnModMenuOpened() +{ + if( !file.isOpen ) + { + file.scrollOffset = 0 + file.filterText = "" + + RegisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp ) + RegisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown ) + RegisterButtonPressedCallback( MOUSE_LEFT , OnClick ) + + OnFiltersChange() + file.isOpen = true + } +} + +void function OnClick( var button ) +{ + if (file.resetModButtons.contains(GetFocus())) + thread CheckFocus(GetFocus()) + if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel")) + thread CheckFocus(GetFocus()) +} + +void function CheckFocus( var button ) +{ + wait 0.05 + if (file.resetModButtons.contains(GetFocus())) + { + thread ResetConVar(GetFocus()) + } + if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel")) + LaunchExternalWebBrowser( "https://northstar.thunderstore.io/", WEBBROWSER_FLAG_FORCEEXTERNAL ) +} + +void function OnFiltersChange() +{ + file.scrollOffset = 0 + + UpdateList() + + UpdateListSliderHeight() +} + +void function OnModMenuClosed() +{ + DeregisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp ) + DeregisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown ) + DeregisterButtonPressedCallback( MOUSE_LEFT , OnClick ) + + file.scrollOffset = 0 + UpdateListSliderPosition() + file.isOpen = false +} + +void function ModSettings_AddModTitle( string modName, int stackPos = 2 ) +{ + file.currentMod = modName + if ( file.conVarList.len() > 0 ) + { + ConVarData catData + + catData.isEmptySpace = true + catData.modName = file.currentMod + + file.conVarList.append( catData ) + } + ConVarData topBar + topBar.isEmptySpace = true + topBar.modName = modName + topBar.spaceType = eEmptySpaceType.TopBar + + + ConVarData modData + + modData.modName = modName + modData.displayName = modName + modData.isModName = true + + + ConVarData botBar + botBar.isEmptySpace = true + botBar.modName = modName + botBar.spaceType = eEmptySpaceType.BottomBar + file.conVarList.extend( [ topBar, modData, botBar ] ) + file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] <- false +} + +void function AddModTitle( string modName, int stackPos = 2 ) +{ + ModSettings_AddModTitle( modName, stackPos + 1 ) +} + +void function ModSettings_AddModCategory( string catName, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a category before a mod title!" + + ConVarData space + space.isEmptySpace = true + space.modName = file.currentMod + space.catName = catName + file.conVarList.append( space ) + + ConVarData catData + + catData.catName = catName + catData.displayName = catName + catData.modName = file.currentMod + catData.isCategoryName = true + + file.conVarList.append( catData ) + + file.currentCat = catName + file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] = true +} + +void function AddModCategory( string catName, int stackPos = 2 ) +{ + ModSettings_AddModCategory( catName, stackPos + 1 ) +} + +void function ModSettings_AddButton( string buttonLabel, void functionref() onPress, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a button before a category and mod title!" + + ConVarData data + + data.isCustomButton = true + data.displayName = buttonLabel + data.modName = file.currentMod + data.catName = file.currentCat + data.onPress = onPress + + file.conVarList.append( data ) +} + +void function AddModSettingsButton( string buttonLabel, void functionref() onPress, int stackPos = 2 ) +{ + ModSettings_AddButton( buttonLabel, onPress, stackPos + 1 ) +} + +void function ModSettings_AddSetting( string conVar, string displayName, string type = "", int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.conVar = conVar + data.modName = file.currentMod + data.displayName = displayName + data.type = type + + file.conVarList.append( data ) +} + +void function AddConVarSetting( string conVar, string displayName, string type = "", int stackPos = 2 ) +{ + ModSettings_AddSetting( conVar, displayName, type, stackPos + 1 ) +} + +void function ModSettings_AddSliderSetting( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.conVar = conVar + data.modName = file.currentMod + data.displayName = displayName + data.type = "float" + data.sliderEnabled = true + data.forceClamp = false + data.min = min + data.max = max + data.stepSize = stepSize + + file.conVarList.append( data ) +} + +void function AddConVarSettingSlider( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 ) +{ + ModSettings_AddSliderSetting( conVar, displayName, min, max, stepSize, forceClamp, stackPos + 1 ) +} + +void function ModSettings_AddEnumSetting( string conVar, string displayName, array values, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.modName = file.currentMod + data.conVar = conVar + data.displayName = displayName + data.values = values + data.isEnumSetting = true + data.min = 0 + data.max = values.len() - 1.0 + data.sliderEnabled = values.len() > 2 + data.forceClamp = true + data.stepSize = 1 + + file.conVarList.append( data ) +} + +void function AddConVarSettingEnum( string conVar, string displayName, array values, int stackPos = 2 ) +{ + ModSettings_AddEnumSetting( conVar, displayName, values, stackPos + 1 ) +} + +void function OnSliderChange( var button ) +{ + if ( file.updatingList ) + return + var panel = Hud_GetParent( button ) + ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ] + var textPanel = Hud_GetChild( panel, "TextEntrySetting" ) + + if ( c.isEnumSetting ) + { + int val = int( RoundToNearestInt( Hud_SliderControl_GetCurrentValue( button ) ) ) + SetConVarInt( c.conVar, val ) + Hud_SetText( textPanel, ( c.values[ GetConVarInt( c.conVar ) ] ) ) + MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], float( val ) ) + + return + } + float val = Hud_SliderControl_GetCurrentValue( button ) + if ( c.forceClamp ) + { + int mod = int( RoundToNearestInt( val % c.stepSize / c.stepSize ) ) + val = ( int( val / c.stepSize ) + mod ) * c.stepSize + } + SetConVarFloat( c.conVar, val ) + MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], val ) + + Hud_SetText( textPanel, string( GetConVarFloat( c.conVar ) ) ) +} + +void function SendTextPanelChanges( var textPanel ) +{ + ConVarData c = file.filteredList[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) + file.scrollOffset ] + if ( c.conVar == "" ) return + // enums don't need to do this + if ( !c.isEnumSetting ) + { + string newSetting = Hud_GetUTF8Text( textPanel ) + + switch ( c.type ) + { + case "int": + try + { + SetConVarInt( c.conVar, newSetting.tointeger() ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + case "bool": + if ( newSetting != "0" && newSetting != "1" ) + { + ThrowInvalidValue( "This setting is a boolean, and only accepts values of 0 or 1." ) + + // set back to previous value : ) + Hud_SetText( textPanel, string( GetConVarBool( c.conVar ) ) ) + + break + } + SetConVarBool( c.conVar, newSetting == "1" ) + break + case "float": + try + { + SetConVarFloat( c.conVar, newSetting.tofloat() ) + } + catch ( ex ) + { + printt( ex ) + ThrowInvalidValue( "This setting is a float, and only accepts a number - we could not parse this!\n\n( Use \".\" for the floating point, not \",\". )" ) + } + if ( c.sliderEnabled ) + { + var panel = Hud_GetParent( textPanel ) + MS_Slider s = file.sliders[ int ( Hud_GetScriptID( panel ) ) ] + + MS_Slider_SetValue( s, GetConVarFloat( c.conVar ) ) + } + break + case "float2": + try + { + array split = split( newSetting, " " ) + if ( split.len() != 2 ) + { + ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put in " + split.len() + "!" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + break + } + vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 > + + SetConVarString( c.conVar, newSetting ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + break + // idk sometimes it's called Float3 most of the time it's called vector, I am not complaining. + case "vector": + case "float3": + try + { + array split = split( newSetting, " " ) + if ( split.len() != 3 ) + { + ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put in " + split.len() + "!" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + break + } + vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 > + + SetConVarString( c.conVar, newSetting ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + break + default: + SetConVarString( c.conVar, newSetting ) + break; + } + } + else Hud_SetText( textPanel, Localize( c.values[ GetConVarInt( c.conVar ) ] ) ) +} + +void function ThrowInvalidValue( string desc ) +{ + DialogData dialogData + dialogData.header = "Invalid Value" + dialogData.image = $"ui/menu/common/dialog_error" + dialogData.message = desc + AddDialogButton( dialogData, "#OK" ) + OpenDialog( dialogData ) +} + +void function UpdateEnumSetting( var button ) +{ + int scriptId = int( Hud_GetScriptID( Hud_GetParent( button ) ) ) + ConVarData c = file.filteredList[ scriptId + file.scrollOffset ] + + var panel = file.modPanels[ scriptId ] + + var textPanel = Hud_GetChild( panel, "TextEntrySetting" ) + + string selectionVal = Hud_GetDialogListSelectionValue( button ) + + if ( selectionVal == "main" ) + return + + int enumVal = GetConVarInt( c.conVar ) + if ( selectionVal == "next" ) // enum val += 1 + enumVal = ( enumVal + 1 ) % c.values.len() + else // enum val -= 1 + { + enumVal-- + if ( enumVal == -1 ) + enumVal = c.values.len() - 1 + } + + SetConVarInt( c.conVar, enumVal ) + Hud_SetText( textPanel, c.values[ enumVal ] ) + + Hud_SetDialogListSelectionValue( button, "main" ) +} + +void function OnClearButtonPressed( var button ) +{ + file.filterText = "" + Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) + + OnFiltersChange() +} + +string function SanitizeDisplayName( string displayName ) +{ + array parts = split( displayName, "^" ) + string result = "" + if ( parts.len() == 1 ) + return parts[0] + foreach ( string p in parts ) + { + if ( p == "" ) + { + result += "^" + continue + } + int i = 0 + for ( i = 0; i < 8 && i < p.len(); i++ ) + { + var c = p[i] + if ( ( c < 'a' || c > 'f' ) && ( c < 'A' || c > 'F' ) && ( c < '0' || c > '9' ) ) + break + } + if ( i == 0 ) + result += p + else result += p.slice( i, p.len() ) + } + return result +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut new file mode 100644 index 00000000..33a79cdc --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut @@ -0,0 +1,52 @@ +// ModSettings_Slider +// since we are missing some utility functions (e.g. GetMax, GetMin, SetValue), this is basically a collection of workarounds. +global struct MS_Slider +{ + var slider + float min = 0.0 + float max = 1.0 + float stepSize = 0.05 +} + +globalize_all_functions + +MS_Slider function MS_Slider_Setup( var slider, float min = 0.0, float max = 1.0, float startVal = 0.0, float stepSize = 0.05 ) +{ + MS_Slider result + result.slider = slider + result.min = min + result.max = max + result.stepSize = stepSize + Hud_SliderControl_SetMin( slider, startVal ) + Hud_SliderControl_SetMax( slider, startVal ) + Hud_SliderControl_SetStepSize( slider, stepSize ) + Hud_SliderControl_SetMin( slider, min ) + Hud_SliderControl_SetMax( slider, max ) + return result +} + +void function MS_Slider_SetValue( MS_Slider slider, float val ) +{ + Hud_SliderControl_SetMin( slider.slider, val ) + Hud_SliderControl_SetMax( slider.slider, val ) + Hud_SliderControl_SetMin( slider.slider, slider.min ) + Hud_SliderControl_SetMax( slider.slider, slider.max ) +} + +void function MS_Slider_SetMin( MS_Slider slider, float min ) +{ + slider.min = min + Hud_SliderControl_SetMin( slider.slider, min ) +} + +void function MS_Slider_SetMax( MS_Slider slider, float max ) +{ + slider.max = max + Hud_SliderControl_SetMax( slider.slider, max ) +} + +void function MS_Slider_SetStepSize( MS_Slider slider, float stepSize ) +{ + slider.stepSize = stepSize + Hud_SliderControl_SetStepSize( slider.slider, stepSize ) +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index 53d85387..eef19b5e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -101,6 +101,10 @@ void function InitMainMenuPanel() var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif + + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) var spotlightLargeButton = Hud_GetChild( file.spotlightPanel, "SpotlightLarge" ) spotlightLargeButton.SetNavLeft( file.spButtons[0] ) -- cgit v1.2.3 From 5be5a6da1c7f658a44e396404425444fd6f83a0c Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 28 May 2023 22:37:09 +0200 Subject: Improve Italian translation (#610) Based on community suggested translations Co-authored-by: n00neheregit <94216450+n00neheregit@users.noreply.github.com> Co-authored-by: CloudSE7EN <87913937+CloudSE7EN@users.noreply.github.com> --- .../northstar_client_localisation_italian.txt | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index 13835b8b..fa84b6a2 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -7,18 +7,18 @@ "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Ricarica Mods" "WARNING", "Attenzione" - "CORE_MOD_DISABLE_WARNING", "Disattivare Mods Principali può rompere il tuo Client!" + "CORE_MOD_DISABLE_WARNING", "Disattivare le Mods Principali può rompere il tuo Client!" "DISABLE", "Disattiva" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Grazie per aver installato Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Affinché Northstar funzioni, è necessario autenticarsi utilizzando il server principale di Northstar. Ciò richiederà l'invio del tuo token di Origin al server principale, non verrà archiviato o utilizzato per altri scopi. -Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi momento nel menu mods." +Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi momento nel Menu delle Mods." "BACK_AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT_RESTART" "Dovrai riavviare Titanfall 2 affinché questa scelta abbia effetto." "DIALOG_AUTHENTICATING_MASTERSERVER", "Autenticazione Sul Master Server in corso" - "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu Mods" + "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu delle Mods" "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Nessun server trovato" @@ -39,7 +39,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Single-Player)" // fra hint for private match menu, because fra only has PL_fra_desc in vanilla - "PL_fra_hint" "Tutti contro tutti. Uccidi nemici per vincere. Raccogli 3 batterie per chiamare il Titan." + "PL_fra_hint" "Tutti contro tutti. Uccidi i nemici per vincere. Raccogli 3 batterie per chiamare il tuo Titan." // mode settings "MODE_SETTING_CATEGORY_PILOT" "Pilota" @@ -63,7 +63,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "earn_meter_titan_multiplier" "Moltiplicatore nucleo Titan" "aegis_upgrades" "Upgrade Aegis" - "infinite_doomed_state" "Doom state Infinito" + "infinite_doomed_state" "Stato Doom Infinito" "titan_shield_regen" "Rigenerazione Scudi" "riff_floorislava" "Terreno Mortale" @@ -80,12 +80,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "cp_amped_capture_points" "Hardpoints Amplificati" "coliseum_loadouts_enabled" "Equipaggiamento Colosseo" - "aitdm_archer_grunts", "Schagniozzi Archer" + "aitdm_archer_grunts", "Scagnozzi Archer" // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" - "PL_sbox_desc" "come gmod ma peggio." + "PL_sbox_desc" "Come gmod ma peggio." "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" @@ -94,9 +94,9 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_gg_desc" "Ottieni un'uccisione con ogni arma per vincere." "PL_gg_hint" "Ottieni una nuova arma ogni uccisione." "PL_gg_abbr" "GG" - "GAMEMODE_GG" "Gioco d'Armi" - "aitdm_archer_grunts", "Schagniozzi Archer" - "gg_kill_reward", "Punteggio Riconpensa Uccisione" + "GAMEMODE_GG" "Gioco delle Armi" + "aitdm_archer_grunts", "Scagnozzi Archer" + "gg_kill_reward", "Punteggio Ricompensa Uccisione" "gg_assist_reward", "Punteggio Ricompensa Assist" "gg_execution_reward", "Punteggio Ricompensa Esecuzione" @@ -126,11 +126,11 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_sns", "Sticks and Stones" "PL_sns_lobby", "Sticks and Stones Lobby" - "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e Esecuzioni per Resettare il Puntegio Nemico" + "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e le Esecuzioni per Resettare il Punteggio Nemico" "PL_sns_abbr", "SNS" "GAMEMODE_SNS", "Sticks and Stones" "SCOREBOARD_BANKRUPTS", "Uccisioni Bancarotta" - "SNS_LEADER_BANKRUPT", "Leader Punteggio andato in Bancarotta!" + "SNS_LEADER_BANKRUPT", "Il Leader punteggio è andato in Bancarotta!" "SNS_LEADER_BANKRUPT_SUB", "%s1 è stato Resettato da %s2" "SNS_BANKRUPT", "Bancarotta!" "SNS_BANKRUPT_SUB", "Il Tuo Punteggio è stato Resettato da %s1" @@ -156,12 +156,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INFECTION_YOU_ARE_LAST_SURVIVOR" "Sei l'Ultimo Sopravvissuto!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sopravvivi." - "PL_tffa", "Titan Free for All" - "PL_tffa_lobby", "Titan Free for All Lobby" + "PL_tffa", "Titan Tutti contro Tutti" + "PL_tffa_lobby", "Lobby: Titan Tutti contro Tutti" "PL_tffa_desc", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." "PL_tffa_hint", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." "PL_tffa_abbr", "TFFA" - "GAMEMODE_TFFA", "Titan Free for All" + "GAMEMODE_TFFA", "Titan Tutti contro Tutti" "PL_hs" "Nascondino" "PL_hs_lobby" "Lobby: Nascondino" @@ -177,14 +177,14 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDEANDSEEK_DONT_GET_FOUND" "Non farti trovare!" "HIDEANDSEEK_GET_LAST_HIDER" "%s1 è L'ULTIMO CERCATORE" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "SEI L'ULTIMO NASCOSTO" - "HIDEANDSEEK_GOT_STIM" "Sei stimmato! Non farti prendere!" + "HIDEANDSEEK_GOT_STIM" "Sei stimolato! Non farti prendere!" "hideandseek_balance_teams" "Bilanciamento Squadre..." "hideandseek_hiding_time" "Tempo per Nascondersi" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development - "GAMEMODE_fw" "Frontier War" - "PL_fw" "Frontier War" - "PL_fw_lobby" "Lobby: Frontier War" + "GAMEMODE_fw" "Guerra di Frontiera" + "PL_fw" "Guerra di Frontiera" + "PL_fw_lobby" "Lobby: Guerra di Frontiera" "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo." "PL_fw_abbr" "FW" @@ -250,7 +250,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper incontra BT-7274." "SP_SEWERS1" "Sangue e Ruggine" - "SP_SEWERS1_CLASSIC_DESC" "Cooper e BT cercano di raggiungere il Major Anderson." + "SP_SEWERS1_CLASSIC_DESC" "Cooper e BT cercano di raggiungere il Maggiore Anderson." "SP_BOOMTOWN_START" "Nell'abisso" "SP_BOOMTOWN_START_CLASSIC_DESC" "Una scorciatoia sotterranea porta a conseguenze impreviste." @@ -272,7 +272,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo // Better.Serverbrowser "SERVERS_COLUMN" "Server" - "PLAYERS_COLUMN" "Players" + "PLAYERS_COLUMN" "Giocatori" "MAP_COLUMN" "Mappa" "GAMEMODE_COLUMN" "Modalità" "REGION_COLUMN" "Regione" @@ -306,18 +306,18 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDE_LOCKED" "Nascondi bloccati" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" + "HUD_CHAT_WHISPER_PREFIX" [BISBIGLIO]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" "NO_GAMESERVER_RESPONSE" "Non è stato possibile raggiungere il server" "BAD_GAMESERVER_RESPONSE" "Il server ha dato una risposta invalida" "UNAUTHORIZED_GAMESERVER" "Il server non è autorizzato a fare quella richiesta" - "UNAUTHORIZED_GAME" "Stryder non è riuscito a confermare che questo account possiede Titanfall 2" + "UNAUTHORIZED_GAME" "Stryder non è riuscito a confermare che questo account possieda Titanfall 2" "UNAUTHORIZED_PWD" "Password errata" - "STRYDER_RESPONSE" "Non è stato possibile analizzare la risposta Stryder" + "STRYDER_RESPONSE" "Non è stato possibile analizzare la risposta di Stryder" "PLAYER_NOT_FOUND" "Non è stato trovato l'account player" "INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto" - "JSON_PARSE_ERROR" "Errore nell'analisi di risposta json" + "JSON_PARSE_ERROR" "Errore nell'analisi della risposta json" "UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata" "MOD_SETTINGS" "Impostazioni Mod" -- cgit v1.2.3 From fd5680a6ba02896ce30a88e0f683fa3f4b1e0c5a Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 24 Jun 2023 00:51:46 +0200 Subject: Translations update from Weblate (#646) * Translated using Weblate (German) Currently translated at 89.4% (246 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ * Translated using Weblate (Italian) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/it/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/zh_Hant/ * Translated using Weblate (Russian) Currently translated at 74.5% (205 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ --------- Co-authored-by: GeckoEidechse Co-authored-by: CloudSE7EN Co-authored-by: SamZong Co-authored-by: Andrew --- .../northstar_client_localisation_german.txt | 1 + .../northstar_client_localisation_italian.txt | 65 ++++++++++++++++---- .../northstar_client_localisation_russian.txt | 6 ++ .../northstar_client_localisation_tchinese.txt | 71 ++++++++++++++-------- 4 files changed, 107 insertions(+), 36 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 0316bbcf..f5c814f5 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -310,5 +310,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "INVALID_MASTERSERVER_TOKEN" "Ungültiger oder abgelaufener Token vom Masterserver" "JSON_PARSE_ERROR" "Fehler beim Verarbeiten der JSON-Antwort" "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" + "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index fa84b6a2..38e67dea 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -84,8 +84,8 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" - "PL_sbox_lobby" "Sandbox Lobby" - "PL_sbox_desc" "Come gmod ma peggio." + "PL_sbox_lobby" "Lobby: Sandbox" + "PL_sbox_desc" "Come gmod ma peggio" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" @@ -170,7 +170,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_hs_abbr" "NS" "GAMEMODE_hs" "Nascondino" "HIDEANDSEEK_YOU_ARE_SEEKER" "TROVA I GIOCATORI NASCOSTI" - "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi." + "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi" "HIDEANDSEEK_YOU_ARE_HIDER" "NASCONDITI" "HIDEANDSEEK_HIDER_DESC" "Nasconditi e cerca di non farti trovare." "HIDEANDSEEK_SEEKERS_INCOMING" "HANNO INIZIATO A CERCARTI" @@ -178,14 +178,14 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDEANDSEEK_GET_LAST_HIDER" "%s1 è L'ULTIMO CERCATORE" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "SEI L'ULTIMO NASCOSTO" "HIDEANDSEEK_GOT_STIM" "Sei stimolato! Non farti prendere!" - "hideandseek_balance_teams" "Bilanciamento Squadre..." + "hideandseek_balance_teams" "Bilanciamento Squadre" "hideandseek_hiding_time" "Tempo per Nascondersi" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development "GAMEMODE_fw" "Guerra di Frontiera" "PL_fw" "Guerra di Frontiera" "PL_fw_lobby" "Lobby: Guerra di Frontiera" - "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo." + "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo" "PL_fw_abbr" "FW" "GAMEMODE_kr" "Killrace Amplificata" @@ -198,10 +198,10 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "KR_NEW_RACER" "%s1 è il killracer amplificato" "KR_YOU_ARE_NEW_RACER" "Sei il killracer amplificato" "KR_YOU_SET_NEW_RECORD" "Stabilisci un nuovo record di uccisioni!" - "KR_FLAG_INCOMING" "Bandiera in Arrivo!" + "KR_FLAG_INCOMING" "Bandiera in Arrivo" "KR_COLLECT_FLAG" "Raccoglila per diventare il killracer!" - "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita." - "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita." + "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita" + "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita" "KR_YOUR_KILLRACE_SCORE" "Hai ottenuto %s1 uccisioni." "GAMEMODE_fastball" "Fastball" @@ -222,7 +222,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "custom_air_accel_pilot" "Accelerazione Aerea" "no_pilot_collision" "Collisione tra Piloti" "promode_enable" "Armi Modalità Competitiva" - "fp_embark_enabled" "Imbarchi/esecuzioni in 1ºpers." + "fp_embark_enabled" "Imbarchi/esecuzioni in 1º persona" "classic_rodeo" "Rodeo classico" "oob_timer_enabled" "Timer Fuori dai Limiti" "riff_instagib" "Modalità Instagib" @@ -262,7 +262,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SP_BEACON_CLASSIC_DESC" "Cooper e BT tentano di informare la flotta rimanente dei piani dell'IMC." "SP_TDAY" "Prova del fuoco" - "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca." + "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca" "SP_S2S" "L'Arca" "SP_S2S_CLASSIC_DESC" "Cooper e BT inseguono l'Arca affrontando una nave dopo l'altra." @@ -333,9 +333,52 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita" "ARE_YOU_SURE" "Sei sicuro?" "WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato." - "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1. + "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON è reversibile." // obviously, don't translate %s1. "MOD_SETTINGS_SERVER" "Server" "MOD_SETTINGS_RESET" "Ripristina" "MOD_SETTINGS_RESET_ALL" "Ripristina Tutto" + "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" + "NO_RESULTS" "Nessun Risultato." + "DISABLE" "Disattiva" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticazione al master server." + "NS_SERVERBROWSER_UNKNOWNMODE" "Modalità sconosciuta" + "respawnprotection" "Tempo di protezione al respawn" + "NO_MODS" "Nessuna impostazione disponibile! Installa più mods a ^5588FF00northstar.thunderstore.io^0." + "gg_assist_reward" "Percentuale ricompensa per assist" + "gg_execution_reward" "Percentuale ricompensa per esecuzione" + "PL_sns" "Sticks and Stones" + "PL_sns_lobby" "Lobby: Sticks and Stones" + "PL_sns_abbr" "SNS" + "GAMEMODE_SNS" "Sticks and Stones" + "SCOREBOARD_BANKRUPTS" "Uccisioni bancarotta" + "SNS_LEADER_BANKRUPT" "Leader punteggio in bancarotta!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 è stato resettato da %s2" + "SNS_BANKRUPT" "Bancarotta!" + "sns_softball_kill_value" "Valore per uccisione Softball" + "sns_offhand_kill_value" "Valore per uccisione manuale" + "sns_melee_kill_value" "Valore per uccisione corpo a corpo" + "sns_softball_enabled" "Softball abilitato" + "PL_tffa" "Tutti contro tutti Titan" + "PL_tffa_lobby" "Lobby: Tutti contro tutti Titan" + "PL_tffa_hint" "Ogni pilota per sè, distruggi tutti i titan nemici." + "PL_tffa_abbr" "TFFA" + "GAMEMODE_TFFA" "Tutti contro tutti Titan" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Cooldown reset all'uccisione" + "SHOW" "Mostra" + "SHOW_ALL" "Tutto" + "SHOW_ONLY_ENABLED" "Solo Abilitate" + "SHOW_ONLY_DISABLED" "Solo Disabilitate" + "SHOW_ONLY_NOT_REQUIRED" "Solo Mods opzionali" + "SHOW_ONLY_REQUIRED" "Solo Mods richieste" + "WARNING" "Attenzione" + "CORE_MOD_DISABLE_WARNING" "Disattivare mods di base può rompere il client!" + "AUTHENTICATIONAGREEMENT_NO" "Hai scelto di non autenticarti con Northstar. Puoi vedere l'accordo nel menu delle Mods." + "aitdm_archer_grunts" "Soldati Archer" + "gg_kill_reward" "Percentuale ricompensa per uccisione" + "PL_sns_desc" "Tutti contro tutti. Usa la Lama Impulsi e l'esecuzione per resettare il punteggio avversario" + "SNS_BANKRUPT_SUB" "Il you punteggio è stato resettato da %s1" + "sns_wme_kill_value" "Valore per uccisione Wingman d'Elite" + "sns_reset_kill_value" "Valore per uccisione Lama Impulsi/Esecuzione" + "PL_tffa_desc" "Ogni pilota per sè, distruggi tutti i titan nemici." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 9ce0c2e3..fe7cf2b3 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -253,5 +253,11 @@ "INVALID_MASTERSERVER_TOKEN" "Срок действия жетона главного сервера истек или не является правильным" "JSON_PARSE_ERROR" "Ошибка разбора ответа json" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" + "DISABLE" "Выключить" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Аутентификация на главном сервере." + "WARNING" "Предупреждение" + "CORE_MOD_DISABLE_WARNING" "Выключение главных модов может сломать ваш клиент!" + "AUTHENTICATIONAGREEMENT_NO" "Вы выбрали не аутентифицироваться с Northstar-ом. Вы можете посмотреть соглашение в меню модов." + "NS_SERVERBROWSER_UNKNOWNMODE" "Неизвестный режим" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 12b6cad1..e543f711 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -127,7 +127,7 @@ "PL_sns" "冷兵器" "PL_sns_lobby" "冷兵器大廳" - "PL_sns_desc" "模擬十字弓和飛斧的作戰模式。使用脈衝刀及處決擊殺來重置敵人的分數。" + "PL_sns_desc" "无规则. 使用脈衝刀及處決擊殺來重置敵人的分數" "PL_sns_abbr" "SNS" "GAMEMODE_SNS" "冷兵器" "SCOREBOARD_BANKRUPTS" "破產次數" @@ -155,7 +155,7 @@ "INFECTION_LAST_SURVIVOR" "%s1是最後的倖存者!" "INFECTION_KILL_LAST_SURVIVOR" "在時間用盡前感染他!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "你是最後的倖存者!" - "INFECTION_SURVIVE_LAST_SURVIVOR" "倖存" + "INFECTION_SURVIVE_LAST_SURVIVOR" "最後幸存者." "PL_tffa" "泰坦混戰" "PL_tffa_lobby" "泰坦混戰大廳" @@ -238,38 +238,38 @@ "player_bleedout_aiBleedingPlayerMissChance" "倒地時AI的失誤率" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Singleplayer Coop Lobby" - "PL_sp_coop_desc" "Play through the singleplayer campaign with friends" - "PL_sp_coop_hint" "Play through the singleplayer campaign with friends" + "PL_sp_coop" "(未完成) 單人合作" + "PL_sp_coop_lobby" "單人合作模式大廳" + "PL_sp_coop_desc" "與朋友一起遊玩單人戰役" + "PL_sp_coop_hint" "與朋友一起遊玩單人戰役" "PL_sp_coop_abbr" "SP" - "SP_TRAINING" "The Pilot's Gauntlet" - "SP_TRAINING_CLASSIC_DESC" "Captain Lastimosa's training simulation." + "SP_TRAINING" "鐵御的試煉" + "SP_TRAINING_CLASSIC_DESC" "拉絲提莫沙上尉的模擬訓練." "SP_CRASHSITE" "BT-7274" - "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper meets BT-7274." + "SP_CRASHSITE_CLASSIC_DESC" "傑克庫博預見BT-7274." - "SP_SEWERS1" "Blood and Rust" - "SP_SEWERS1_CLASSIC_DESC" "Cooper and BT set out to rendezvous with Major Anderson." + "SP_SEWERS1" "鮮血與鐵鏽" + "SP_SEWERS1_CLASSIC_DESC" "庫博和BT一起出發前往與安德森上尉回合." - "SP_BOOMTOWN_START" "Into the Abyss" - "SP_BOOMTOWN_START_CLASSIC_DESC" "An underground shortcut yields unexpected consequences." + "SP_BOOMTOWN_START" "踏入虛空" + "SP_BOOMTOWN_START_CLASSIC_DESC" "一個地下捷徑造成了不可預見的後果." - "SP_HUB_TIMESHIFT" "Effect and Cause" - "SP_HUB_TIMESHIFT_CLASSIC_DESC" "A strange phenomenon is discovered at Major Anderson's coordinates." + "SP_HUB_TIMESHIFT" "因果報應" + "SP_HUB_TIMESHIFT_CLASSIC_DESC" "在安德森上尉的坐標處發現了奇異的現象." - "SP_BEACON" "The Beacon" - "SP_BEACON_CLASSIC_DESC" "Cooper and BT attempt to inform the remaining fleet of the IMC's plans." + "SP_BEACON" "信號台" + "SP_BEACON_CLASSIC_DESC" "庫博和BT嘗試將IMC的計劃通知給剩餘反抗軍艦隊." - "SP_TDAY" "Trial by Fire" - "SP_TDAY_CLASSIC_DESC" "Cooper's Titan skills are put to the test in an all-out battle to capture the Ark" + "SP_TDAY" "烈火審判" + "SP_TDAY_CLASSIC_DESC" "庫博驾馭泰坦的技術在爭奪聖櫃的全面戰爭中得到考驗" - "SP_S2S" "The Ark" - "SP_S2S_CLASSIC_DESC" "Cooper and BT go ship to ship in pursuit of the Ark." + "SP_S2S" "聖櫃" + "SP_S2S_CLASSIC_DESC" "庫博和BT在艦艇中穿梭追尋聖櫃." - "SP_SKYWAY_V1" "The Fold Weapon" - "SP_SKYWAY_V1_CLASSIC_DESC" "BT and Cooper are captured by Kuben Blisk." + "SP_SKYWAY_V1" "折疊時空武器" + "SP_SKYWAY_V1_CLASSIC_DESC" "BT和庫博被庫本布里斯克擒拿." // Better.Serverbrowser "SERVERS_COLUMN" "伺服器" @@ -310,8 +310,8 @@ "HUD_CHAT_SERVER_PREFIX" "[伺服器]" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" - "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "HUD_CHAT_WHISPER_PREFIX" "[悄悄話]" + "HUD_CHAT_SERVER_PREFIX" "[伺服器]" "NO_GAMESERVER_RESPONSE" "無法連接到遊戲伺服器'" "BAD_GAMESERVER_RESPONSE" "遊戲伺服器回應無效" @@ -323,5 +323,26 @@ "INVALID_MASTERSERVER_TOKEN" "主伺服器token過期或無效" "JSON_PARSE_ERROR" "讀取json回應時發生錯誤" "UNSUPPORTED_VERSION" "您的遊戲版本過低" + "NORTHSTAR_BASE_SETTINGS" "北极星基础设置" + "ONLY_HOST_CAN_START_MATCH" "只有服主可以開始對局" + "MATCH_COUNTDOWN_LENGTH" "私人對局倒計時時間" + "DISALLOWED_TACTICALS" "禁用的技能" + "TACTICAL_REPLACEMENT" "替換的技能" + "NO_RESULTS" "無結果." + "LOG_UNKNOWN_CLIENTCOMMANDS" "登記未知客戶端指令" + "SHOULD_RETURN_TO_LOBBY" "對局結束後返回大廳" + "ARE_YOU_SURE" "確定?" + "WILL_RESET_SETTING" "這將會重置 %s1 的設置為默認值.\n\n此操作不可復原." + "MOD_SETTINGS_SERVER" "服務器" + "MOD_SETTINGS_RESET" "重置" + "MOD_SETTINGS_RESET_ALL" "重置所有" + "SHOW_ONLY_NOT_REQUIRED" "僅展示非必需模組" + "SHOW_ONLY_REQUIRED" "僅展示必須模組" + "MOD_SETTINGS" "模组设置" + "ONLY_HOST_MATCH_SETTINGS" "只有服主可以修改私人對局設置" + "DISALLOWED_WEAPONS" "禁用的武器" + "REPLACEMENT_WEAPON" "替换的武器" + "WILL_RESET_ALL_SETTINGS" "這將會重置所有屬於改條目的設置.\n\n此操作不可復原." + "NO_MODS" "無可用模組! 前往 ^5588FF00northstar.thunderstore.io^0 下載更多." } } -- cgit v1.2.3 From 77ef26e748fa66e2b94a31889029c7b477dd6826 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:46:39 +0100 Subject: disable RequiredOnClient mods properly (#658) * disable RequiredOnClient mods properly * better disabling logic --- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 7ea8134a..c4046132 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1059,15 +1059,39 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged + bool modsChanged = false - // unload mods we don't need, load necessary ones and reload mods before connecting + // disable all RequiredOnClient mods that are not required by the server and are currently enabled + foreach ( string modName in NSGetModNames() ) + { + if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) + { + // find the mod name in the list of server required mods + bool found = false + foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) + { + if (mod.name == modName) + { + found = true + break + } + } + // if we didnt find the mod name, disable the mod + if (!found) + { + modsChanged = true + NSSetModEnabled( modName, false ) + } + } + } + + // enable all RequiredOnClient mods that are required by the server and are currently disabled foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) { - if ( NSIsModRequiredOnClient( mod.name ) ) + if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name )) { - modsChanged = modsChanged || NSIsModEnabled( mod.name ) != file.lastSelectedServer.requiredMods.contains( mod ) - NSSetModEnabled( mod.name, file.lastSelectedServer.requiredMods.contains( mod ) ) + modsChanged = true + NSSetModEnabled( mod.name, true ) } } -- cgit v1.2.3 From fc6c8c0d295fee70d08d422bf0426d807d7b740b Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 12 Jul 2023 23:08:22 +0200 Subject: Bump mods version to `1.16.0` (#665) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index e9536d66..8040c14c 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index f3f73fde..ca33fa22 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 3525c434..4f19307d 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 281850f63719e88a7a32d623f0e03719f61352bb Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 23 Jul 2023 13:55:47 +0200 Subject: Translations update from Weblate (#668) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index d90cea05..d5881d6c 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -64,7 +64,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "earn_meter_pilot_multiplier" "Multiplicateur de boost pilote" "earn_meter_titan_multiplier" "Multiplicateur de boost titan" - "aegis_upgrades" "Aegis Upgrades" + "aegis_upgrades" "Upgrades Aegis" "infinite_doomed_state" "Etat condamné infini" "titan_shield_regen" "Régénération des boucliers" @@ -86,13 +86,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Bac à sable" - "PL_sbox_lobby" "Lobby: Bac à sable" - "PL_sbox_desc" "GMod, mais en pire..." + "PL_sbox_lobby" "Lobby : Bac à sable" + "PL_sbox_desc" "GMod, mais en pire" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Bac à sable" "PL_gg" "Gun game" - "PL_gg_lobby" "Lobby: Gun game" + "PL_gg_lobby" "Lobby : Gun game" "PL_gg_desc" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner." "PL_gg_hint" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner." "PL_gg_abbr" "GG" @@ -102,21 +102,21 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "gg_execution_reward" "Récompense pourcentage d'exécutions" "PL_tt" "Titan tag" - "PL_tt_lobby" "Lobby: Titan tag" + "PL_tt_lobby" "Lobby : Titan tag" "PL_tt_desc" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre." "PL_tt_hint" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre." "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan tag" "PL_chamber" "Le professionnel" - "PL_chamber_lobby" "Lobby: Le professionnel" + "PL_chamber_lobby" "Lobby : Le professionnel" "PL_chamber_desc" "Un tir, un mort.\nObtenez une balle en tuant un pilote." "PL_chamber_hint" "Un tir, un mort.\nObtenez une balle en tuant un pilote." "PL_chamber_abbr" "CHAMBER" "GAMEMODE_CHAMBER" "Le professionnel" "PL_hidden" "Chasse" - "PL_hidden_lobby" "Lobby: Chasse" + "PL_hidden_lobby" "Lobby : Chasse" "PL_hidden_desc" "Un pilote est invisible et chasse les autres." "PL_hidden_hint" "Un pilote est invisible et chasse les autres." "PL_hidden_abbr" "HIDDEN" @@ -126,7 +126,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "HIDDEN_FIRST_HIDDEN" "%s1 est le chasseur." "PL_sns" "Sticks and Stones" - "PL_sns_lobby" "Lobby: Sticks and Stones" + "PL_sns_lobby" "Lobby : Sticks and Stones" "PL_sns_desc" "Chacun pour soi.\nLes exécutions et les lames à impulsions réinitialisent le score de vos ennemis." "PL_sns_abbr" "SNS" "GAMEMODE_SNS" "Sticks and Stones" @@ -144,7 +144,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "sns_softball_enabled" "Softball activé" "PL_inf" "Infection" - "PL_inf_lobby" "Lobby: Infection" + "PL_inf_lobby" "Lobby : Infection" "PL_inf_desc" "Les pilotes survivants deviennent infectés lorsque tués." "PL_inf_hint" "Les pilotes survivants deviennent infectés lorsque tués." "PL_inf_abbr" "INF" @@ -158,14 +158,14 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "INFECTION_SURVIVE_LAST_SURVIVOR" "Survivez." "PL_tffa" "Chacun pour soi (titans)" - "PL_tffa_lobby" "Lobby: Chacun pour soi (titans)" + "PL_tffa_lobby" "Lobby : Chacun pour soi (titans)" "PL_tffa_desc" "Chacun pour soi.\nDétruisez les titans ennemis." "PL_tffa_hint" "Chacun pour soi.\nDétruisez les titans ennemis." "PL_tffa_abbr" "TFFA" "GAMEMODE_TFFA" "Chacun pour soi (titans)" "PL_hs" "Cache-cache" - "PL_hs_lobby" "Lobby: Cache-cache" + "PL_hs_lobby" "Lobby : Cache-cache" "PL_hs_desc" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux." "PL_hs_hint" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux." "PL_hs_abbr" "HS" @@ -185,13 +185,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development "GAMEMODE_fw" "Guerre pour la Frontière" "PL_fw" "Guerre pour la Frontière" - "PL_fw_lobby" "Lobby: Guerre pour la Frontière" + "PL_fw_lobby" "Lobby : Guerre pour la Frontière" "PL_fw_desc" "Détruisez le collecteur ennemi et protégez le vôtre." "PL_fw_abbr" "FW" "GAMEMODE_kr" "Course aux frags" "PL_kr" "Course aux frags" - "PL_kr_lobby" "Lobby: Course aux frags" + "PL_kr_lobby" "Lobby : Course aux frags" "PL_kr_desc" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte." "PL_kr_hint" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte." "PL_kr_abbr" "KR" @@ -207,12 +207,12 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "GAMEMODE_fastball" "Fastball" "PL_fastball" "Fastball" - "PL_fastball_lobby" "Lobby: Fastball" + "PL_fastball_lobby" "Lobby : Fastball" "PL_fastball_desc" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers." "PL_fastball_hint" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers." "PL_fastball_abbr" "FB" "FASTBALL_PANEL_CAPTURED" "%s1 a piraté le panneau de contrôle %s2 !" - "SCOREBOARD_FASTBALL_HACKS" "Panneaux de\ncontrôle capturés" + "SCOREBOARD_FASTBALL_HACKS" "Panneaux de contrôle capturés" "GAMEMODE_ctf_comp" "Capture de drapeau - Compétitif" @@ -239,7 +239,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // coop stuff "PL_sp_coop" "(ALPHA) Campagne (coop)" - "PL_sp_coop_lobby" "Lobby: Campagne (coop)" + "PL_sp_coop_lobby" "Lobby : Campagne (coop)" "PL_sp_coop_desc" "Jouez la campagne avec des amis." "PL_sp_coop_hint" "Jouez la campagne avec des amis." "PL_sp_coop_abbr" "SP" @@ -337,5 +337,9 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "MOD_SETTINGS_SERVER" "Serveur" "MOD_SETTINGS_RESET" "Réinitialiser" "MOD_SETTINGS_RESET_ALL" "Tout réinitialiser" + "SHOW_ONLY_REQUIRED" "Afficher les mods requis" + "SHOW_ONLY_NOT_REQUIRED" "Uniquement les mods optionnels" + "NO_RESULTS" "Aucun résultat." + "NO_MODS" "Aucun paramètre trouvé ! Installez d'autres mods depuis ^5588FF00northstar.thunderstore.io^0." } } -- cgit v1.2.3 From 5fb567743e5a5b72d8de486de3296063740dceca Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:05:01 +0200 Subject: Translations update from Weblate (#669) * Translated using Weblate (Portuguese) Currently translated at 99.6% (274 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ --------- Co-authored-by: William Miller --- .../northstar_client_localisation_portuguese.txt | 106 ++++++++++++++------- 1 file changed, 69 insertions(+), 37 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 51854726..b6364db4 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -15,14 +15,14 @@ "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Obrigado por instalar Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para o Northstar funcionar é necessário autenticar com o servidor mestre Northstar. Isso requer enviar seu token da Origin para o servidor, ele não será utilizado pra outros propósitos. Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momento no menu de mods." - "BACK_AUTHENTICATION_AGREEMENT" "Aceitação de autorização" - "AUTHENTICATION_AGREEMENT" "Aceitação de autorização" + "BACK_AUTHENTICATION_AGREEMENT" "Acordo de Autenticação" + "AUTHENTICATION_AGREEMENT" "Acordo de Autenticação" "AUTHENTICATION_AGREEMENT_RESTART" "Você precisa reiniciar o Titanfall 2 para esta mudança ter efeito." "DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticando com o servidor mestre." - "AUTHENTICATIONAGREEMENT_NO" "Você não autorizou a autenticação com Northstar. Troque a configuração no menu de mods." + "AUTHENTICATIONAGREEMENT_NO" "Você escolheu não autenticar com Northstar. Você pode ver o acordo no menu de Mods." - "MENU_TITLE_SERVER_BROWSER" "Servidores" + "MENU_TITLE_SERVER_BROWSER" "Lista de Servidores" "NS_SERVERBROWSER_NOSERVERS" "Nenhum servidor encontrado" "NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconhecido" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Aguardando servidores..." @@ -52,9 +52,9 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "classic_mp" "MP Clássico" "run_epilogue" "Executar epílogo" "scorelimit" "Limite de pontos" - "roundscorelimit" "Limite de pontos (por round)" + "roundscorelimit" "Limite de pontos (por rodada)" "timelimit" "Tempo limite" - "roundtimelimit" "Tempo limite (por round)" + "roundtimelimit" "Tempo limite (por rodada)" "respawnprotection" "Proteção de reaparecimento" "pilot_health_multiplier" "Multiplicador de vida" @@ -64,16 +64,16 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "earn_meter_pilot_multiplier" "Multiplicador de bônus" "earn_meter_titan_multiplier" "Multiplicador de bônus do titã" - "aegis_upgrades" "Upgrades Aegis" + "aegis_upgrades" "Melhorias de Égide" "infinite_doomed_state" "Estado condenado infinito" "titan_shield_regen" "Escudos regeneradores" - "riff_floorislava" "Deadly Ground" - "featured_mode_all_holopilot" "The Great Bamboozle" - "featured_mode_all_grapple" "Attack on Titanfall" - "featured_mode_all_phase" "The Otherside" - "featured_mode_all_ticks" "Spicy" - "featured_mode_tactikill" "Tactikill" + "riff_floorislava" "Terreno Mortal" + "featured_mode_all_holopilot" "A Grande Enganação" + "featured_mode_all_grapple" "Ataque aos Titãs" + "featured_mode_all_phase" "O Outro Lado" + "featured_mode_all_ticks" "Picante" + "featured_mode_tactikill" "Mortático" "featured_mode_amped_tacticals" "Habilidades táticas melhoradas" "featured_mode_rocket_arena" "Arena Foguete" "featured_mode_shotguns_snipers" "Armado e perigoso" @@ -89,14 +89,14 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" - "PL_gg" "Gun Game" - "PL_gg_lobby" "Saguão de Gun Game" - "PL_gg_desc" "Mate com todas as armas para vencer" - "PL_gg_hint" "Mate com todas as armas para vencer" + "PL_gg" "Jogo de Armas" + "PL_gg_lobby" "Saguão de Jogo de Armas" + "PL_gg_desc" "Mate com cada arma para vencer." + "PL_gg_hint" "Mate com cada arma para vencer." "PL_gg_abbr" "GG" - "GAMEMODE_GG" "Gun Game" + "GAMEMODE_GG" "Jogo de Armas" "gg_kill_reward" "% recompensa/morte" - "gg_assist_reward" "% recompensa/assist" + "gg_assist_reward" "% recompensa/assistência" "gg_execution_reward" "% recompensa/execução" "PL_tt" "Titan Tag" @@ -106,20 +106,20 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan Tag" - "PL_chamber" "One in the Chamber" - "PL_chamber_lobby" "Saguão de One in the Chamber" - "PL_chamber_desc" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo." - "PL_chamber_hint" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo." - "PL_chamber_abbr" "CHAMBER" - "GAMEMODE_CHAMBER" "One in the Chamber" + "PL_chamber" "Um na Câmara" + "PL_chamber_lobby" "Saguão de Um na Câmara" + "PL_chamber_desc" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo." + "PL_chamber_hint" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo." + "PL_chamber_abbr" "CÂMARA" + "GAMEMODE_CHAMBER" "Um na Câmara" - "PL_hidden" "O Fantasma" - "PL_hidden_lobby" "Saguão de O Fantasma" + "PL_hidden" "O Oculto" + "PL_hidden_lobby" "Saguão de O Oculto" "PL_hidden_desc" "Um jogador se torna invisível enquanto o resto o caça." "PL_hidden_hint" "Um jogador se torna invisível enquanto o resto o caça." "PL_hidden_abbr" "HIDDEN" - "GAMEMODE_HIDDEN" "The Hidden" - "HIDDEN_YOU_ARE_HIDDEN" "Você é o fantasma!" + "GAMEMODE_HIDDEN" "O Oculto" + "HIDDEN_YOU_ARE_HIDDEN" "Você é o ocultado!" "HIDDEN_KILL_SURVIVORS" "Mate todos os sobreviventes." "HIDDEN_FIRST_HIDDEN" "%s1 é O Fantasma." @@ -155,12 +155,12 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "INFECTION_YOU_ARE_LAST_SURVIVOR" "Você é o último sobrevivente!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sobreviva." - "PL_tffa" "Free for All Titã" - "PL_tffa_lobby" "Saguão de Free for All Titã" + "PL_tffa" "Cada Titã por si" + "PL_tffa_lobby" "Saguão de Cada Titã por si" "PL_tffa_desc" "Cada um por si, destrua todos os titãs inimigos." "PL_tffa_hint" "Cada um por si, destrua todos os titãs inimigos." "PL_tffa_abbr" "TFFA" - "GAMEMODE_TFFA" "Free for All Titã" + "GAMEMODE_TFFA" "Cada Titã por si" "PL_hs" "Esconde-esconde" "PL_hs_lobby" "Saguão de Esconde-esconde" @@ -168,7 +168,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_hs_hint" "Jogo clássico de esconde-esconde." "PL_hs_abbr" "HS" "GAMEMODE_hs" "Esconde-esconde" - "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA!" + "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA" "HIDEANDSEEK_SEEKER_DESC" "Ache os outros e bata neles.\nVocê reaparecerá em %s1 segundos" "HIDEANDSEEK_YOU_ARE_HIDER" "VOCÊ ESCONDE" "HIDEANDSEEK_HIDER_DESC" "Esconda-se." @@ -203,8 +203,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "KR_YOUR_KILLRACE_OVER" "Sua matança acabou" "KR_YOUR_KILLRACE_SCORE" "Você conseguiu %s1 mortes." - "GAMEMODE_fastball" "Fastball" - "PL_fastball" "Fastball" + "GAMEMODE_fastball" "Travessia Impulsionada" + "PL_fastball" "Travessia Impulsionada" "PL_fastball_lobby" "Saguão de Fastball" "PL_fastball_desc" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados." "PL_fastball_hint" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados." @@ -236,8 +236,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "player_bleedout_aiBleedingPlayerMissChance" "Chance de erro da IA ao cair" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Saguão de Singleplayer em grupo" + "PL_sp_coop" "(NÃO-TERMINADO) Campanha Cooperativa" + "PL_sp_coop_lobby" "Saguão de Campanha Cooperativa" "PL_sp_coop_desc" "Jogue através da campanha com seus amigos" "PL_sp_coop_hint" "Jogue através da campanha com seus amigos" "PL_sp_coop_abbr" "SP" @@ -306,5 +306,37 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "ONLY_HOST_MATCH_SETTINGS" "Somente o Host pode mudar as configurações da Partida Privada" + "ONLY_HOST_CAN_START_MATCH" "Somente o Host pode Iniciar a Partida" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar Comandos desconhecidos de Clientes" + "DISALLOWED_TACTICALS" "Táticos Proibidos" + "TACTICAL_REPLACEMENT" "Tático Substituto" + "DISALLOWED_WEAPONS" "Armas Proibidas" + "REPLACEMENT_WEAPON" "Armas Substitutas" + "ARE_YOU_SURE" "Tem certeza?" + "WILL_RESET_ALL_SETTINGS" "Isso irá resetar TODAS as configurações que pertecem a essa categoria.\n\nAção não reversível." + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET" "Resetar" + "MOD_SETTINGS_RESET_ALL" "Resetar Tudo" + "NO_RESULTS" "Sem resultados." + "NO_MODS" "Sem configurações disponíveis. Instale mais mods em ^5588FF00northstar.thunderstore.io^0." + "SHOW_ONLY_NOT_REQUIRED" "Somente Mods Opcionais" + "NO_GAMESERVER_RESPONSE" "Não foi possível alcançar o servidor da partida" + "BAD_GAMESERVER_RESPONSE" "Servidor da partida sem resposta válida" + "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" + "UNAUTHORIZED_PWD" "Senha inválida" + "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido" + "JSON_PARSE_ERROR" "Erro ao ler a resposta json" + "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" + "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" + "STRYDER_RESPONSE" "Não foi possível ler a resposta do Stryder" + "UNSUPPORTED_VERSION" "A versão que você está usando não é mais suportada" + "MOD_SETTINGS" "Configurações de Mod" + "NORTHSTAR_BASE_SETTINGS" "Configurações Base do Northstar" + "MATCH_COUNTDOWN_LENGTH" "Duração da contagem da Partida Privada" + "SHOULD_RETURN_TO_LOBBY" "Retornar ao saguão após término de Partida" + "WILL_RESET_SETTING" "Isso irá resetar a configuração %s1 ao valor padrão.\n\nAção não reversível." + "aitdm_archer_grunts" "Soldados com Archer" } } -- cgit v1.2.3 From 75dc032a8184e770360c6bd3acc1e9b6f37da13f Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 24 Jul 2023 20:49:36 +0200 Subject: Translations update from Weblate (#670) Translated using Weblate (German) Currently translated at 89.8% (247 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ Co-authored-by: GeckoEidechse --- Northstar.Client/mod/resource/northstar_client_localisation_german.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index f5c814f5..f1994a24 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -311,5 +311,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "JSON_PARSE_ERROR" "Fehler beim Verarbeiten der JSON-Antwort" "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" + "SNS_BANKRUPT_SUB" "Dein Punkestand wurde von %s1 zurückgesetzt" } } -- cgit v1.2.3 From efdf780a8e8645b854c43683cc366e4db63dcae0 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 30 Jul 2023 11:52:16 +0200 Subject: Translations update from Weblate (#675) Translated using Weblate (Russian) Currently translated at 94.9% (261 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../northstar_client_localisation_russian.txt | 152 +++++++++++++++------ 1 file changed, 111 insertions(+), 41 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index fe7cf2b3..d26017b8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -17,7 +17,7 @@ "MENU_TITLE_SERVER_BROWSER" "Список серверов" "NS_SERVERBROWSER_NOSERVERS" "Серверов не найдено" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Ожидание серверов..." - "NS_SERVERBROWSER_CONNECTIONFAILED" "Соединение провалено!" + "NS_SERVERBROWSER_CONNECTIONFAILED" "Не удалось подключиться!" "REFRESH_SERVERS" "Обновить" "MENU_TITLE_CONNECT_PASSWORD" "Подключиться с помощью пароля" @@ -41,7 +41,7 @@ "MODE_SETTING_CATEGORY_MATCH" "Матч" "classic_mp" "Классический мультиплеер" - "run_epilogue" "Запустить эпилог" + "run_epilogue" "Показывать эпилог" "scorelimit" "Лимит очков" "roundscorelimit" "Лимит очков (по раундам)" "timelimit" "Лимит времени" @@ -58,19 +58,19 @@ "infinite_doomed_state" "Бесконечное обречённое состояние" "titan_shield_regen" "Регенерация щитов" - "riff_floorislava" "Смертельная Земля" + "riff_floorislava" "Пол это лава" "featured_mode_all_holopilot" "Великий обманщик" - "featured_mode_all_grapple" "Зацепщик" - "featured_mode_all_phase" "Альтернативное пространство" - "featured_mode_all_ticks" "Острый" + "featured_mode_all_grapple" "Зацепер" + "featured_mode_all_phase" "Мир иной" + "featured_mode_all_ticks" "Горячие парни" "featured_mode_tactikill" "Тактический удар" "featured_mode_amped_tacticals" "Усиленные тактики" "featured_mode_rocket_arena" "Ракетная Арена" "featured_mode_shotguns_snipers" "Вооружён и опасен" "iron_rules" "Правила Железного Титана" - "cp_amped_capture_points" "Усиленные точки опоры" - "coliseum_loadouts_enabled" "Выгрузка коллизея" + "cp_amped_capture_points" "Усиленные опорные пункты" + "coliseum_loadouts_enabled" "Экипировка Колизея" // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Песочница" @@ -81,9 +81,9 @@ "PL_gg" "Гонка вооружений" "PL_gg_lobby" "Лобби гонки вооружений" - "PL_gg_desc" "Уничтожьте противника из всех видов оружия чтобы победить." - "PL_gg_hint" "Уничтожьте противника из всех видов оружия чтобы победить." - "PL_gg_abbr" "GG" + "PL_gg_desc" "Убейте по одному противнику из каждого вида оружия." + "PL_gg_hint" "Убейте по одному противнику из каждого вида оружия." + "PL_gg_abbr" "ГВ" "GAMEMODE_GG" "Гонка вооружений" "PL_tt" "Разборки Титанов" @@ -99,10 +99,10 @@ "PL_inf_hint" "Переживите инфекцию. Выжившие становятся заражёнными при убийстве." "PL_inf_abbr" "INF" "GAMEMODE_INF" "Заражение" - "INFECTION_YOU_ARE_INFECTED" "Вы были заражены!" + "INFECTION_YOU_ARE_INFECTED" "Вас заразили!" "INFECTION_KILL_SURVIVORS" "Заразите всех оставшихся выживших." "INFECTION_FIRST_INFECTED" "%s1 был заражён первым." - "INFECTION_LAST_SURVIVOR" "%s1 выжил последним!" + "INFECTION_LAST_SURVIVOR" "%s1 — последний выживший!" "INFECTION_KILL_LAST_SURVIVOR" "Зарази их, пока время не вышло!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "Вы последний выживший!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Выживите." @@ -116,19 +116,19 @@ "HIDEANDSEEK_YOU_ARE_SEEKER" "ВЫ ИЩЕТЕ" "HIDEANDSEEK_SEEKER_DESC" "Найдите прячущихся и ударьте их.\nВы появитесь через %s1 секунд(у)" "HIDEANDSEEK_YOU_ARE_HIDER" "ВЫ ПРЯЧЕТЕСЬ" - "HIDEANDSEEK_HIDER_DESC" "Спрятайтесь." + "HIDEANDSEEK_HIDER_DESC" "Спрячьтесь." "HIDEANDSEEK_SEEKERS_INCOMING" "ИЩУЩИЕ ВЫДВИГАЮТСЯ" "HIDEANDSEEK_DONT_GET_FOUND" "Не дайте себя найти!" "HIDEANDSEEK_GET_LAST_HIDER" "%s1 ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "ВЫ ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ" - "HIDEANDSEEK_GOT_STIM" "Вас остановили! Не попадитесь!" + "HIDEANDSEEK_GOT_STIM" "Применён стим! Не попадитесь!" "hideandseek_balance_teams" "Автобаланс обеих сторон" "hideandseek_hiding_time" "Время спрятаться" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development - "GAMEMODE_fw" "Пограничная война" - "PL_fw" "Пограничная война" - "PL_fw_lobby" "Лобби пограничной войны" + "GAMEMODE_fw" "Война за Фронтир" + "PL_fw" "Война за Фронтир" + "PL_fw_lobby" "Лобби Войны за Фронтир" "PL_fw_desc" "Уничтожьте харвестер противника и защитите свой" "PL_fw_abbr" "FW" @@ -136,22 +136,22 @@ "PL_kr" "Усиленные гонки убийств" "PL_kr_lobby" "Лобби усиленных гонок убийств" - "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить." - "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить." + "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить." + "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить." "PL_kr_abbr" "KR" "SCOREBOARD_KR_RECORD" "Рекорд убийств" "KR_NEW_RACER" "%s1 усиленный гонщик за убийства" "KR_YOU_ARE_NEW_RACER" "Вы усиленный гонщик за убийства" "KR_YOU_SET_NEW_RECORD" "Установите новый рекорд убийств!" "KR_FLAG_INCOMING" "Флаг прибывает" - "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убиства!" + "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убийства!" "KR_ENEMY_KILLRACE_OVER" "Гонки убийств у %s1 закончились" "KR_YOUR_KILLRACE_OVER" "Ваши гонки убийств кончились" "KR_YOUR_KILLRACE_SCORE" "У вас %s1 убийств." - "GAMEMODE_fastball" "Фастболл" - "PL_fastball" "Фастболл" - "PL_fastball_lobby" "Лобби фастболла" + "GAMEMODE_fastball" "Фастбол" + "PL_fastball" "Фастбол" + "PL_fastball_lobby" "Лобби фастбола" "PL_fastball_desc" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды." "PL_fastball_hint" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды." "PL_fastball_abbr" "FB" @@ -161,20 +161,20 @@ "GAMEMODE_ctf_comp" "Соревновательное CTF" // mode settings - "MODE_SETTING_CATEGORY_PROMODE" "Продвинутое оружие" + "MODE_SETTING_CATEGORY_PROMODE" "Режим про" "MODE_SETTING_CATEGORY_BLEEDOUT" "Кровотечение пилота" "custom_air_accel_pilot" "Ускорение в воздухе" - "promode_enable" "Продвинутое оружие" - "fp_embark_enabled" "Отправления/Казни от первого лица" + "promode_enable" "Оружие из режима про" + "fp_embark_enabled" "Казни/посадки в титана от первого лица" "classic_rodeo" "Классическое родео" "oob_timer_enabled" "Таймер уничтожения за пределами карты" "riff_instagib" "Моментальная смерть при попадании" "riff_player_bleedout" "Кровотечение пилота" - "player_bleedout_forceHolster" "Использовать оружие из кобуры при кровотечении" + "player_bleedout_forceHolster" "Убирать оружие при кровотечении" "player_bleedout_forceDeathOnTeamBleedout" "Смерть при кровотечении во всей команде" - "player_bleedout_bleedoutTime" "Кремя кровотечения" + "player_bleedout_bleedoutTime" "Время кровотечения" "player_bleedout_firstAidTime" "Время оказания первой помощи" "player_bleedout_firstAidTimeSelf" "Время оказания помощи самому себе" "player_bleedout_firstAidHealPercent" "Процент здоровья после лечения" @@ -187,8 +187,8 @@ "PL_sp_coop_hint" "Сыграть в кампанию с друзьями" "PL_sp_coop_abbr" "SP" - "SP_TRAINING" "Тренировачная полоса пилотов" - "SP_TRAINING_CLASSIC_DESC" "Тренировачная имитация капитана Ластимозы." + "SP_TRAINING" "Полоса препятствий" + "SP_TRAINING_CLASSIC_DESC" "Симуляция капитана Ластимозы." "SP_CRASHSITE" "БT-7274" "SP_CRASHSITE_CLASSIC_DESC" "Джек Купер встречает BT-7274." @@ -200,7 +200,7 @@ "SP_BOOMTOWN_START_CLASSIC_DESC" "Подземная срезка приводит к неожиданным последствиям." "SP_HUB_TIMESHIFT" "Следствие и Причина" - "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местополжении Майора Андерсена." + "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местоположении Майора Андерсена." "SP_BEACON" "Маяк" "SP_BEACON_CLASSIC_DESC" "Купер и БТ пытаются известить оставшийся флот о планах IMC." @@ -229,7 +229,7 @@ "SERVER_DESCRIPTION" "Описание" "SERVER_MODS" "Моды" "CLEAR_FILTERS" "ОЧИСТИТЬ" - "JOIN_BUTTON" "ПРИСОЕДИНИТЬСЯ" + "JOIN_BUTTON" "ЗАЙТИ" "SWITCH_YES" "Да" "SWITCH_NO" "Нет" @@ -240,24 +240,94 @@ "TOTAL_SERVERS" "Серверов: ^C46C6C00%s1" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" - "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "HUD_CHAT_WHISPER_PREFIX" "[ЛИЧНОЕ]" + "HUD_CHAT_SERVER_PREFIX" "[СЕРВЕР]" "NO_GAMESERVER_RESPONSE" "Игровой сервер не отвечает" - "BAD_GAMESERVER_RESPONSE" "Игровой сервер не дал правильного ответа" + "BAD_GAMESERVER_RESPONSE" "Игровой сервер вернул некорректный ответ" "UNAUTHORIZED_GAMESERVER" "Игровой сервер не авторизирован чтобы сделать данный запрос" - "UNAUTHORIZED_GAME" "Не удалось найти Titanfall 2 на этом аккаунте" + "UNAUTHORIZED_GAME" "Stryder не смог найти Titanfall 2 на этом аккаунте" "UNAUTHORIZED_PWD" "Неправильный пароль" - "STRYDER_RESPONSE" "Не удалось разобрать ответ stryder" + "STRYDER_RESPONSE" "Не удалось разобрать ответ Stryder" "PLAYER_NOT_FOUND" "Не удалось найти аккаунт игрока" - "INVALID_MASTERSERVER_TOKEN" "Срок действия жетона главного сервера истек или не является правильным" - "JSON_PARSE_ERROR" "Ошибка разбора ответа json" + "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера" + "JSON_PARSE_ERROR" "Ошибка разбора json-ответа" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" "DISABLE" "Выключить" "DIALOG_AUTHENTICATING_MASTERSERVER" "Аутентификация на главном сервере." "WARNING" "Предупреждение" - "CORE_MOD_DISABLE_WARNING" "Выключение главных модов может сломать ваш клиент!" + "CORE_MOD_DISABLE_WARNING" "Выключение основных модов может сломать ваш клиент!" "AUTHENTICATIONAGREEMENT_NO" "Вы выбрали не аутентифицироваться с Northstar-ом. Вы можете посмотреть соглашение в меню модов." "NS_SERVERBROWSER_UNKNOWNMODE" "Неизвестный режим" + "SNS_BANKRUPT" "Банкрот!" + "MOD_SETTINGS" "Настройки модов" + "NORTHSTAR_BASE_SETTINGS" "Основные настройки Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Только создатель матча может изменять настройки" + "ONLY_HOST_CAN_START_MATCH" "Только создатель матча может его начать" + "MATCH_COUNTDOWN_LENGTH" "Длительность обратного отсчёта частного матча" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Записывать в лог неизвестные команды" + "DISALLOWED_TACTICALS" "Запрещённое спецоружие" + "TACTICAL_REPLACEMENT" "Заменять запрещённое спецоружие на" + "DISALLOWED_WEAPONS" "Запрещённое оружие" + "REPLACEMENT_WEAPON" "Заменять запрещённое оружие на" + "SHOULD_RETURN_TO_LOBBY" "Возвращаться в лобби после матча" + "ARE_YOU_SURE" "Вы уверены?" + "WILL_RESET_ALL_SETTINGS" "ВСЕ настройки этой категории будут сброшены.\n\nЭто действие нельзя будет откатить." + "WILL_RESET_SETTING" "Это сбросит значение настройки %s1.\n\nЭто действие нельзя будет откатить." + "MOD_SETTINGS_SERVER" "Сервер" + "MOD_SETTINGS_RESET" "Сброс" + "MOD_SETTINGS_RESET_ALL" "Сбросить все" + "NO_RESULTS" "Нет результатов." + "NO_MODS" "Нечего настраивать! Загрузите моды с ^5588FF00northstar.thunderstore.io^0." + "respawnprotection" "Длит. защиты после возрождения" + "SNS_BANKRUPT_SUB" "Вас обнулил %s1" + "PL_hidden" "Невидимка" + "PL_hidden_lobby" "Невидимка — лобби" + "GAMEMODE_HIDDEN" "Невидимка" + "HIDDEN_YOU_ARE_HIDDEN" "Вы — Невидимка!" + "HIDDEN_KILL_SURVIVORS" "Убейте всех." + "aitdm_archer_grunts" "Пехотинцы со Стрельцами" + "PL_chamber" "Последний патрон" + "PL_chamber_lobby" "Последний патрон — лобби" + "PL_chamber_abbr" "ПАТРОН" + "GAMEMODE_CHAMBER" "Последний патрон" + "PL_sns" "Камни и палки" + "PL_sns_lobby" "Камни и палки — лобби" + "PL_sns_desc" "Все против всех. Убийства пульс. клинком и казни сбрасывают очки противника" + "PL_sns_abbr" "КИП" + "GAMEMODE_SNS" "Камни и палки" + "PL_hidden_hint" "Один из игроков невидим." + "PL_hidden_abbr" "НЕВИД" + "SCOREBOARD_BANKRUPTS" "Врагов обанкрочено" + "SNS_LEADER_BANKRUPT" "Лидер обанкрочен!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 был обнулён игроком %s2" + "gg_kill_reward" "Множитель награды за убийство" + "gg_execution_reward" "Множитель награды за казнь" + "PL_tffa" "Все против всех на титанах" + "PL_tffa_lobby" "Все против всех на титанах — лобби" + "PL_tffa_desc" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов." + "PL_tffa_abbr" "ТВПВ" + "sns_wme_kill_value" "Очков за убийство Элитным ведомым" + "sns_offhand_kill_value" "Очков за убийство спецоружием" + "sns_reset_kill_value" "Очков за убийство пульс./казнь" + "sns_melee_kill_value" "Очков за убийство врукопашную" + "sns_softball_enabled" "Включить Софтбол" + "no_pilot_collision" "Столкновения между пилотами" + "SHOW" "Показать" + "SHOW_ALL" "Все" + "SHOW_ONLY_ENABLED" "Только включенные" + "SHOW_ONLY_NOT_REQUIRED" "Только необязательные" + "SHOW_ONLY_REQUIRED" "Только обязательные" + "HIDDEN_FIRST_HIDDEN" "%s1 — Невидимка." + "GAMEMODE_TFFA" "Все против всех на титанах" + "SHOW_ONLY_DISABLED" "Только выключенные" + "HIDE_LOCKED" "Скрыть недоступные" + "PL_chamber_desc" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым." + "PL_chamber_hint" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым." + "PL_hidden_desc" "Один из игроков невидим." + "PL_tffa_hint" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов." + "sns_softball_kill_value" "Очков за убийство Софтболом" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" + "gg_assist_reward" "Множитель награды за помощь в убийстве" } } -- cgit v1.2.3 From f16af287534fceeb466bbd474d1ab3d94c19d1a3 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 2 Sep 2023 17:49:26 +0100 Subject: Force player respawn to match vanilla (#554) Automatically respawns dead players after 5 seconds unless set otherwise --- .../northstar_client_localisation_english.txt | 1 + Northstar.CustomServers/keyvalues/playlists_v2.txt | 13 +++++++++++ .../lobby/sh_private_lobby_modes_init.gnut | 1 + .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 25 ++++++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 Northstar.CustomServers/keyvalues/playlists_v2.txt (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 5dabd539..b2608331 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -227,6 +227,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "classic_rodeo" "Classic Rodeo" "oob_timer_enabled" "Out of Bounds Timer" "riff_instagib" "Instagib Mode" + "player_force_respawn" "Forced Respawn" "riff_player_bleedout" "Pilot Bleedout" "player_bleedout_forceHolster" "Holster weapons when downed" diff --git a/Northstar.CustomServers/keyvalues/playlists_v2.txt b/Northstar.CustomServers/keyvalues/playlists_v2.txt new file mode 100644 index 00000000..c49fb0e9 --- /dev/null +++ b/Northstar.CustomServers/keyvalues/playlists_v2.txt @@ -0,0 +1,13 @@ +playlists +{ + Gamemodes + { + defaults + { + vars + { + player_force_respawn 5 + } + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut index ccccefaf..d2be2ab4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut @@ -17,6 +17,7 @@ void function PrivateMatchModesInit() AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "boosts_enabled", [ "#SETTING_DEFAULT", "#SETTING_DISABLED" ], "1" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_overdrive", [ "#SETTING_DISABLED", "#SETTING_ENABLED", "Only" ], "1" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_multiplier", "1.0" ) + AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "player_force_respawn", "5" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_TITAN", "earn_meter_titan_multiplier", "1.0" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "aegis_upgrades", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut index ec426754..3bd0cd69 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -274,6 +274,9 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga ClearRespawnAvailable( player ) + // reset this so that we default to pilot spawn + player.SetPersistentVar( "spawnAsTitan", false ) + OnThreadEnd( function() : ( player ) { if ( !IsValid( player ) ) @@ -379,6 +382,13 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga SetRespawnAvailable( player ) wait respawnDelay + + int forceRespawn = GetCurrentPlaylistVarInt( "player_force_respawn", -1 ) + + // -1 is disabled, anything over is the time we wait in seconds + // before respawning the player + if( forceRespawn >= 0 ) + thread ForceRespawnMeSignalAfterDelay( player, forceRespawn ) player.WaitSignal( "RespawnMe" ) // set in base_gametype: ClientCommand_RespawnPlayer @@ -398,6 +408,21 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga } } +// idk if this is a good delay or if it matches vanilla +void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 ) +{ + player.EndSignal( "RespawnMe" ) + player.EndSignal( "OnDestroy" ) + + if( player.IsWatchingKillReplay() ) + player.WaitSignal( "KillCamOver" ) + + wait delay + + printt( format( "Forcing player respawn for player %s (took >%d seconds to respawn)", player.GetPlayerName(), delay ) ) + player.Signal( "RespawnMe" ) +} + void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) { player.EndSignal( "RespawnMe" ) -- cgit v1.2.3 From 1d95b7d5f3a4b7176456c94b147f0382de04f18e Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 2 Sep 2023 17:52:06 +0100 Subject: Progression system (#655) This also can't hurt right? --------- Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> --- .../northstar_client_localisation_english.txt | 18 + .../mod/scripts/vscripts/ui/menu_lobby.nut | 53 + Northstar.CustomServers/mod.json | 18 + .../mod/cfg/autoexec_ns_server.cfg | 5 +- .../mod/scripts/vscripts/_items.nut | 8 +- .../mod/scripts/vscripts/_menu_callbacks.gnut | 2 + .../mod/scripts/vscripts/_xp.gnut | 39 +- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 2 + .../mod/scripts/vscripts/evac/_evac.gnut | 45 + .../mod/scripts/vscripts/faction_xp.gnut | 3 + .../mod/scripts/vscripts/lobby/_lobby.gnut | 12 + .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 9 + .../mod/scripts/vscripts/mp/_changemap.nut | 4 +- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 2 + .../mod/scripts/vscripts/mp/_score.nut | 11 +- .../mod/scripts/vscripts/mp/_stats.nut | 1043 ++++++++++++++++++- .../mod/scripts/vscripts/sh_loadouts.nut | 4 +- .../mod/scripts/vscripts/sh_progression.nut | 1091 ++++++++++++++++++++ .../mod/scripts/vscripts/sh_utility_all.gnut | 6 +- .../mod/scripts/vscripts/titan_xp.gnut | 3 + .../mod/scripts/vscripts/weapon_xp.gnut | 5 +- 21 files changed, 2337 insertions(+), 46 deletions(-) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index b2608331..8c7bab3a 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -343,5 +343,23 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "MOD_SETTINGS_RESET_ALL" "Reset All" "NO_RESULTS" "No results." "NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0." + + // Toggleable progression + "TOGGLE_PROGRESSION" "Toggle Progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Toggle Progression" + + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disable Progression?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Enable Progression?" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby.\n\n^CC000000Warning: if you have currently equipped any items that you do not have unlocked, they will be reset!" + + "PROGRESSION_ENABLED_HEADER" "Progression Enabled!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Progression has been enabled.^\n\nTitans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_DISABLED_HEADER" "Progression Disabled!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time." } } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 2bef0e20..e4cc5687 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -178,6 +178,8 @@ void function InitLobbyMenu() 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 ) + // Client side progression toggle + AddMenuFooterOption( menu, BUTTON_Y, "#Y_BUTTON_TOGGLE_PROGRESSION", "#TOGGLE_PROGRESSION", ShowToggleProgressionDialog ) InitChatroom( menu ) @@ -226,6 +228,57 @@ void function InitLobbyMenu() RegisterSignal( "LeaveParty" ) } +void function ShowToggleProgressionDialog( var button ) +{ + bool enabled = Progression_GetPreference() + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = enabled ? "#PROGRESSION_TOGGLE_ENABLED_HEADER" : "#PROGRESSION_TOGGLE_DISABLED_HEADER" + dialogData.message = enabled ? "#PROGRESSION_TOGGLE_ENABLED_BODY" : "#PROGRESSION_TOGGLE_DISABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", enabled ? DisableProgression : EnableProgression ) + + OpenDialog( dialogData ) +} + +void function EnableProgression() +{ + Progression_SetPreference( true ) + + // update the cache just in case something changed + UpdateCachedLoadouts_Delayed() + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#PROGRESSION_ENABLED_HEADER" + dialogData.message = "#PROGRESSION_ENABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#OK" ) + + EmitUISound( "UI_Menu_Item_Purchased_Stinger" ) + + OpenDialog( dialogData ) +} + +void function DisableProgression() +{ + Progression_SetPreference( false ) + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#PROGRESSION_DISABLED_HEADER" + dialogData.message = "#PROGRESSION_DISABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) +} + void function SetupComboButtonTest( var menu ) { ComboStruct comboStruct = ComboButtons_Create( menu ) diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 4f19307d..8f5508c8 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -53,6 +53,11 @@ { "Name": "ns_allow_kill_commands", "DefaultValue": "0" + }, + { + "Name": "ns_progression_enabled", + "DefaultValue": "0", + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ @@ -150,6 +155,19 @@ "ServerCallback": { "After": "AiTurretSentry_Init" } + }, + { + "Path": "sh_progression.nut", + "RunOn": "UI || SERVER || CLIENT", + "ServerCallback": { + "Before": "Progression_Init" + }, + "ClientCallback": { + "Before": "Progression_Init" + }, + "UICallback": { + "Before": "Progression_Init" + } } ] } diff --git a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg index f28f601b..bd422783 100644 --- a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg +++ b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg @@ -21,4 +21,7 @@ sv_updaterate_mp 20 // default updaterate: 20 tick sv_minupdaterate 20 // unsure if this actually works, but if it does, should set minimum client updaterate sv_max_snapshots_multiplayer 300 // this needs to be updaterate * 15, or clients will dc in killreplay net_data_block_enabled 0 // not really sure on this, have heard datablock could have security issues? doesn't seem to have any adverse effects being disabled -host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit \ No newline at end of file +host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit + +announcementVersion 1 +announcement #PROGRESSION_ANNOUNCEMENT_BODY \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index 539b72bc..5878da13 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -5698,7 +5698,7 @@ bool function IsUnlockValid( string ref, string parentRef = "" ) bool function IsSubItemLocked( entity player, string ref, string parentRef ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false if ( IsItemInEntitlementUnlock( ref, parentRef ) ) @@ -5817,7 +5817,7 @@ bool function IsSubItemLocked( entity player, string ref, string parentRef ) bool function IsItemLocked( entity player, string ref ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false if ( IsItemInEntitlementUnlock( ref ) ) @@ -5906,7 +5906,7 @@ bool function IsItemLockedForEntitlement( entity player, string ref, string pare bool function IsSubItemOwned( entity player, string ref, string parentRef ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false Assert( IsValid( player ) ) @@ -5990,7 +5990,7 @@ bool function IsSubItemOwned( entity player, string ref, string parentRef ) bool function IsItemOwned( entity player, string ref ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false Assert( IsValid( player ) ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut index 1092bf2d..6499faa2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut @@ -65,6 +65,8 @@ bool function ClientCommandCallback_GenUp( entity player, array args ) player.GenChanged() player.XPChanged() } + + RegenPersistentLoadouts(player) return true } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 6f044b7a..2b95d1a8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -1,6 +1,7 @@ global function SvXP_Init global function PlayerProgressionAllowed global function HandleXPGainForScoreEvent +global function AddXP void function SvXP_Init() { @@ -29,46 +30,38 @@ bool function PlayerProgressionAllowed( entity player ) void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) { // note: obviously all xp stuff can be cheated in if people want to on customs, this is mainly just here for fun for those who want it and feature completeness - // most score events don't have this, so we'll set this to the xp value of other categories later if needed + int xpValue = ScoreEvent_GetXPValue( event ) int weaponXp = ScoreEvent_GetXPValueWeapon( event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) - - if ( xpValue < weaponXp ) - xpValue = weaponXp - else if ( xpValue < titanXp ) - xpValue = titanXp + int factionXp = ScoreEvent_GetXPValueFaction( event ) entity weapon = player.GetActiveWeapon() - if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) ) - AddWeaponXP( player, xpValue ) + if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 ) + AddWeaponXP( player, weaponXp ) // if we specifically gain titan xp, then give titan xp no matter what, otherwise only give it when we're in a titan - if ( titanXp != 0 || player.IsTitan() ) - AddTitanXP( player, xpValue ) - - // most events don't have faction xp but almost everything should give it - int factionXp = ScoreEvent_GetXPValueFaction( event ) - if ( xpValue > factionXp ) - factionXp = xpValue - else if ( xpValue < factionXp ) - xpValue = factionXp + if ( titanXp != 0 ) + AddTitanXP( player, titanXp ) if ( factionXp != 0 ) AddFactionXP( player, factionXp ) - if ( xpValue == 0 ) - return - // global xp + if ( xpValue != 0 ) + AddXP( player, xpValue ) +} + +void function AddXP( entity player, int amount ) +{ int oldXp = player.GetPersistentVarAsInt( "xp" ) - if(oldXp<0) oldXp = 0 + if( oldXp < 0 ) oldXp = 0 int oldLevel = GetLevelForXP( oldXp ) - player.SetPersistentVar( "xp", min( oldXp + xpValue, PlayerGetMaxXPPerGen() ) ) + player.SetPersistentVar( "xp", min( oldXp + amount, PlayerGetMaxXPPerGen() ) ) player.XPChanged() // network xp change to client, gen can't change here int newXp = player.GetPersistentVarAsInt( "xp" ) int newLevel = GetLevelForXP( newXp ) if ( newLevel != oldLevel ) Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel ) -} \ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 5821d015..56750352 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -265,6 +265,8 @@ void function UseBurnCardWeapon( entity weapon, entity player ) PlayerEarnMeter_SetRewardUsed( player ) thread PlayerInventory_PopInventoryItem( player ) + + UpdatePlayerStat( player, "misc_stats", "boostsActivated" ) } void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index f23c841d..af074689 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -422,6 +422,40 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa foreach ( entity otherPlayer in GetPlayerArray() ) Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() ) } + + // award player score to evacing team + int evacCount = 0 + array evacingPlayers = GetPlayerArrayOfTeam( dropship.GetTeam() ) // all players that are supposed to evac in the dropship + + // count how many players are in the dropship + foreach ( entity player in evacingPlayers ) + { + if ( !PlayerInDropship( player, dropship ) ) + continue + + evacCount++ + } + + bool allEvac = evacCount == evacingPlayers.len() + + foreach(entity player in evacingPlayers) + { + if ( !PlayerInDropship( player, dropship ) ) + continue + + AddPlayerScore( player, "HotZoneExtract" ) + UpdatePlayerStat( player, "misc_stats", "evacsSurvived" ) + + if ( allEvac ) + AddPlayerScore( player, "TeamBonusFullEvac" ) + } + + // sole survivor (but not the only one on the team) + if ( evacCount == 1 && !allEvac ) + { + // we can assume there is one player in the array because otherwise evacCount wouldn't be 1 + AddPlayerScore( evacingPlayers[0], "SoleSurvivor" ) + } } void function AddPlayerToEvacDropship( entity dropship, entity player ) @@ -442,6 +476,8 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) if ( !PlayerInDropship( player, dropship ) ) return + UpdatePlayerStat( player, "misc_stats", "evacsAttempted" ) + // need to cancel if the dropship dies dropship.EndSignal( "OnDeath", "OnDestroy" ) @@ -507,6 +543,15 @@ void function CheckIfAnyPlayerLeft( int evacTeam ) SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" ) thread EvacEpilogueCompleted( null ) + + // score for killing the entire evacing team + foreach ( entity player in GetPlayerArray() ) + { + if ( player.GetTeam() == evacTeam ) + continue + + AddPlayerScore( player, "TeamBonusKilledAll") + } } ) while( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 5fd7d101..6555c875 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -3,8 +3,11 @@ global function AddFactionXP void function AddFactionXP( entity player, int amount ) { string faction = GetFactionChoice( player ) + int oldLevel = FactionGetLevel( player, faction ) // increment xp player.SetPersistentVar( "factionXP[" + faction + "]", min( FactionGetXP( player, faction ) + amount, FactionGetMaxXP( faction ) ) ) // note: no notif for faction level up + if ( FactionGetLevel( player, faction ) != oldLevel ) + AddPlayerScore( player, "FactionLevelUp" ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut index ae933b71..8b65ec93 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut @@ -14,6 +14,7 @@ void function Lobby_Init() { // non-private lobby clientcommands AddClientCommandCallback( "StartPrivateMatchSearch", ClientCommandCallback_StartPrivateMatchSearch ) + AddClientCommandCallback( "SetAnnouncementVersionSeen", ClientCommandCallback_SetAnnouncementVersionSeen ) } } @@ -37,3 +38,14 @@ bool function ClientCommandCallback_StartPrivateMatchSearch( entity player, arra return true } + +bool function ClientCommandCallback_SetAnnouncementVersionSeen( entity player, array args ) +{ + if ( args.len() < 1 ) + return false + + int version = int( args[0] ) + + player.SetPersistentVar( "announcementVersionSeen", version ) + return true +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut index 3bd0cd69..bab7eaed 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -134,6 +134,15 @@ void function CodeCallback_OnClientConnectionCompleted( entity player ) Lobby_OnClientConnectionCompleted( player ) return } + else if ( !IsFDMode( GAMETYPE ) ) + { + // reset this for non-fd modes + // for some reason the postgame scoreboard uses this to + // determine if it should show the FD aegis rank one + // FD should either set this in their own mode, or add an else + // to this if statement when it releases + player.SetPersistentVar( "lastFDTitanRef", "" ) + } player.hasConnected = true diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut index 16a3ce92..0ababfc7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut @@ -58,7 +58,9 @@ void function CodeCallback_MatchIsOver() #if MP void function PopulatePostgameData() { - // something's busted here because this isn't showing automatically on match end, ag + // show the postgame scoreboard summary + SetUIVar( level, "showGameSummary", true ) + foreach ( entity player in GetPlayerArray() ) { int teams = GetCurrentPlaylistVarInt( "max_teams", 2 ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 46b39ebc..3426cec5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -800,6 +800,8 @@ void function SetWinner( int team, string winningReason = "", string losingReaso } else SetGameState( eGameState.WinnerDetermined ) + + ScoreEvent_MatchComplete( team ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index dacd43b0..0b55e9ff 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -7,6 +7,7 @@ global function ScoreEvent_PlayerKilled global function ScoreEvent_TitanDoomed global function ScoreEvent_TitanKilled global function ScoreEvent_NPCKilled +global function ScoreEvent_MatchComplete global function ScoreEvent_SetEarnMeterValues global function ScoreEvent_SetupEarnMeterValuesForMixedModes @@ -230,7 +231,15 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn catch ( ex ) {} } - +void function ScoreEvent_MatchComplete( int winningTeam ) +{ + foreach( entity player in GetPlayerArray() ) + { + AddPlayerScore( player, "MatchComplete" ) + if ( player.GetTeam() == winningTeam ) + AddPlayerScore( player, "MatchVictory" ) + } +} void function ScoreEvent_SetEarnMeterValues( string eventName, float earned, float owned, float coreScale = 1.0 ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 0e8b58f4..92c0f401 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -1,3 +1,5 @@ +untyped // because entity.s + global function Stats_Init global function AddStatCallback global function Stats_SaveStatDelayed @@ -12,67 +14,1084 @@ global function PreScoreEventUpdateStats global function PostScoreEventUpdateStats global function Stats_OnPlayerDidDamage +struct { + table< string, array > refs + table< string, array< void functionref( entity, float, string ) > > callbacks + + table< entity, table< string, int > > cachedIntStatChanges + table< table< string, float > > cachedFloatStatChanges + + table< entity, float > playerKills + table< entity, float > playerKillsPvp + table< entity, float > playerDeaths + table< entity, float > playerDeathsPvp + + bool isFirstStrike = true +} file + void function Stats_Init() { + AddCallback_OnPlayerKilled( OnPlayerOrNPCKilled ) + AddCallback_OnNPCKilled( OnPlayerOrNPCKilled ) + AddCallback_OnPlayerRespawned( OnPlayerRespawned ) + AddCallback_OnClientConnected( OnClientConnected ) + AddCallback_OnClientDisconnected( OnClientDisconnected ) + AddCallback_GameStateEnter( eGameState.Epilogue, OnEpilogueStarted ) + thread HandleDistanceAndTimeStats_Threaded() + thread SaveStatsPeriodically_Threaded() } -void function AddStatCallback(string statCategory, string statAlias, string statSubAlias, void functionref(entity, float, string) callback, string subRef) +void function AddStatCallback( string statCategory, string statAlias, string statSubAlias, void functionref( entity, float, string ) callback, string subRef ) { + if ( !IsValidStat( statCategory, statAlias, statSubAlias ) ) + throw format( "INVALID STAT: %s : %s : %s", statCategory, statAlias, statSubAlias ) + + + string statVar = GetStatVar( statCategory, statAlias, statSubAlias ) + if ( statVar in file.refs ) + { + file.refs[ statVar ].append( subRef ) + file.callbacks[ statVar ].append( callback ) + } + else + { + file.refs[ statVar ] <- [ subRef ] + file.callbacks[ statVar ] <- [ callback ] + } } -void function Stats_SaveStatDelayed(entity player, string statCategory, string statAlias, string statSubAlias) +// a lot of this file seems to be doing caching of stats in some way +void function Stats_SaveStatDelayed( entity player, string statCategory, string statAlias, string statSubAlias, float delay = 0.1 ) { + // idk how long the delay is meant to be but whatever + wait delay + + if ( !IsValid( player ) ) + return + + Stats_SaveStat( player, statCategory, statAlias, statSubAlias ) +} + +void function Stats_SaveAllStats( entity player ) +{ + if ( player in file.cachedIntStatChanges ) + { + foreach( string key, int val in file.cachedIntStatChanges[ player ] ) + { + player.SetPersistentVar( key, player.GetPersistentVarAsInt( key ) + val ) + } + + delete file.cachedIntStatChanges[ player ] + } + // save cached float stat change + if ( player in file.cachedFloatStatChanges ) + { + foreach( string key, float val in file.cachedFloatStatChanges[ player ] ) + { + player.SetPersistentVar( key, expect float( player.GetPersistentVar( key ) ) + val ) + } + delete file.cachedFloatStatChanges[ player ] + } } -int function PlayerStat_GetCurrentInt(entity player, string statCategory, string statAlias, string statSubAlias) +void function Stats_SaveStat( entity player, string statCategory, string statAlias, string statSubAlias ) { + string stat = GetStatVar( statCategory, statAlias, statSubAlias ) + // save cached int stat change + if ( player in file.cachedIntStatChanges && stat in file.cachedIntStatChanges[ player ] ) + { + player.SetPersistentVar( stat, player.GetPersistentVarAsInt( stat ) + file.cachedIntStatChanges[ player ][ stat ] ) + delete file.cachedIntStatChanges[ player ][ stat ] + return + } + // save cached float stat change + if ( player in file.cachedFloatStatChanges && stat in file.cachedFloatStatChanges[ player ] ) + { + player.SetPersistentVar( stat, expect float( player.GetPersistentVar( stat ) ) + file.cachedFloatStatChanges[ player ][ stat ] ) + delete file.cachedFloatStatChanges[ player ][ stat ] + return + } +} + +// this gets the cached change, not the actual value +int function PlayerStat_GetCurrentInt( entity player, string statCategory, string statAlias, string statSubAlias ) +{ + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + + if ( player in file.cachedIntStatChanges && str in file.cachedIntStatChanges[ player ] ) + return file.cachedIntStatChanges[ player ][ str ] return 0 } -float function PlayerStat_GetCurrentFloat(entity player, string statCategory, string statAlias, string statSubAlias) +// this gets the cached change, not the actual value +float function PlayerStat_GetCurrentFloat( entity player, string statCategory, string statAlias, string statSubAlias ) { + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + + if ( player in file.cachedFloatStatChanges && str in file.cachedFloatStatChanges[ player ] ) + return file.cachedFloatStatChanges[ player ][ str ] return 0 } -void function UpdatePlayerStat(entity player, string statCategory, string subStat, int count = 0) +void function UpdatePlayerStat( entity player, string statCategory, string subStat, int count = 1 ) { + if ( !IsValid( player ) ) + return + + Stats_IncrementStat( player, statCategory, subStat, "", count.tofloat() ) +} + +void function IncrementPlayerDidPilotExecutionWhileCloaked( entity player ) +{ + UpdatePlayerStat( player, "kills_stats", "pilotExecutePilotWhileCloaked" ) +} + +void function UpdateTitanDamageStat( entity attacker, float savedDamage, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + Stats_IncrementStat( attacker, "titan_stats", "titanDamage", GetTitanCharacterName( attacker ), savedDamage ) +} + +void function UpdateTitanWeaponDamageStat( entity attacker, float savedDamage, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + string weaponName = GetPersistenceRefFromDamageInfo( damageInfo ) + if ( weaponName == "" ) + return + + Stats_IncrementStat( attacker, "weapon_stats", "titanDamage", weaponName, savedDamage ) +} + +void function UpdateTitanCoreEarnedStat( entity player, entity titan, int count = 1 ) +{ + if ( !IsValid( player ) ) + return + + if ( !IsValid( titan ) ) + return + + Stats_IncrementStat( player, "titan_stats", "coresEarned", GetTitanCharacterName( titan ), count.tofloat() ) +} + +void function PreScoreEventUpdateStats( entity attacker, entity ent ) +{ + // used to track kill streaks ending i think ( that stuff gets reset during score event update ) +} + +void function PostScoreEventUpdateStats( entity attacker, entity ent ) +{ + if ( !attacker.IsPlayer() ) + return + // used to track kill streaks starting maybe + if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT ) + { + // killingSpressAs_ + if ( attacker.IsTitan() ) + Stats_IncrementStat( attacker, "kills_stats", "killingSpressAs_" + GetTitanCharacterName( attacker ), "", 1.0 ) + + entity weapon = attacker.GetActiveWeapon() + // I guess if you dont have a valid active weapon when you get awarded a killing spree + // you dont get the stat. Too bad! + if ( !IsValid( weapon ) ) + return + Stats_IncrementStat( attacker, "weapon_kill_stats", "killingSprees", weapon.GetWeaponClassName(), 1.0 ) + } +} + +void function Stats_OnPlayerDidDamage( entity victim, var damageInfo ) +{ + // try and get the player + entity attacker = DamageInfo_GetAttacker( damageInfo ) + // get the player from their titan + if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + attacker = attacker.GetTitanSoul().GetBossPlayer() + + if ( !attacker.IsPlayer() ) + return + + string weaponName = GetPersistenceRefFromDamageInfo( damageInfo ) + if ( weaponName == "" ) + return + + Stats_IncrementStat( attacker, "weapon_stats", "shotsHit", weaponName, 1.0 ) + + if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_CRITICAL ) + Stats_IncrementStat( attacker, "weapon_stats", "critHits", weaponName, 1.0 ) + if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) + Stats_IncrementStat( attacker, "weapon_stats", "headshots", weaponName, 1.0 ) +} + +void function Stats_IncrementStat( entity player, string statCategory, string statAlias, string statSubAlias, float amount ) +{ + if ( !IsValidStat( statCategory, statAlias, statSubAlias ) ) + { + printt( "invalid stat: " + statCategory + " : " + statAlias + " : " + statSubAlias ) + return + } + + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + int type = GetStatVarType( statCategory, statAlias, statSubAlias ) + + // stupid exception because respawn set this up as an int in script + // but it is actually a float, so the game will crash if we don't fix it somewhere + // i dont feel like committing all of sh_stats.gnut so im doing this instead + if ( str == "mapStats[%mapname%].hoursPlayed[%gamemode%]" ) + type = ePlayerStatType.FLOAT + + // this is rather hacky + string mode = GAMETYPE + int difficulty = GetDifficultyLevel() + if ( difficulty >= 5 ) + return + + string saveVar = Stats_GetFixedSaveVar( str, GetMapName(), mode, difficulty.tostring() ) + // check if the map and mode exist in persistence + try + { + PersistenceGetEnumIndexForItemName( "gamemodes", mode ) + PersistenceGetEnumIndexForItemName( "maps", GetMapName() ) + } + catch( ex ) + { + // if we have an invalid mode or map for persistence, and it is used in the + // persistence string, we can't save the persistence so we have to just return + if ( str != saveVar ) + { + printt( ex ) + return + } + } + str = saveVar + + switch ( type ) + { + case ePlayerStatType.INT: + // populate table if needed + if ( !( player in file.cachedIntStatChanges ) ) + file.cachedIntStatChanges[ player ] <- {} + if ( !( str in file.cachedIntStatChanges[ player ] ) ) + file.cachedIntStatChanges[ player ][ str ] <- 0 + + file.cachedIntStatChanges[ player ][ str ] += amount.tointeger() + break + case ePlayerStatType.FLOAT: + // populate table if needed + if ( !( player in file.cachedFloatStatChanges ) ) + file.cachedFloatStatChanges[ player ] <- {} + if ( !( str in file.cachedFloatStatChanges[ player ] ) ) + file.cachedFloatStatChanges[ player ][ str ] <- 0.0 + + file.cachedFloatStatChanges[ player ][ str ] += amount + break + default: + throw "UNIMPLEMENTED STAT TYPE: " + type + } + + // amount here is never used + Stats_RunCallbacks( str, player, amount ) +} + +void function Stats_RunCallbacks( string statVar, entity player, float change ) +{ + if ( !( statVar in file.refs ) ) + return + + for( int i = 0; i < file.refs[ statVar ].len(); i++ ) + { + string ref = file.refs[ statVar ][ i ] + void functionref( entity, float, string ) callback = file.callbacks[ statVar ][ i ] + + callback( player, change, ref ) + } +} + +void function OnClientConnected( entity player ) +{ + Stats_IncrementStat( player, "game_stats", "game_joined", "", 1.0 ) +} + +void function OnClientDisconnected( entity player ) +{ + Stats_SaveAllStats( player ) + // maybe we can save this stuff, but idk if we can access persistence in this callback + if ( player in file.cachedIntStatChanges ) + delete file.cachedIntStatChanges[ player ] + + if ( player in file.cachedFloatStatChanges ) + delete file.cachedFloatStatChanges[ player ] +} + +void function OnPlayerOrNPCKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim.IsPlayer() ) + thread SetLastPosForDistanceStatValid_Threaded( victim, false ) + + HandleDeathStats( victim, attacker, damageInfo ) + HandleKillStats( victim, attacker, damageInfo ) + HandleWeaponKillStats( victim, attacker, damageInfo ) + HandleTitanStats( victim, attacker, damageInfo ) +} + +void function HandleDeathStats( entity player, entity attacker, var damageInfo ) +{ + if ( !IsValid( player ) || !player.IsPlayer() ) + return + + if ( player in file.playerDeaths ) + file.playerDeaths[ player ]++ + else + file.playerDeaths[ player ] <- 1.0 + // total + Stats_IncrementStat( player, "deaths_stats", "total", "", 1.0 ) + + // these all rely on the attacker being valid + if ( IsValid( attacker ) ) + { + // totalPVP + // note: I'm not sure if owned entities count towards totalPVP + // such as auto-titans, turrets, etc. + if ( attacker.IsPlayer() || attacker.GetBossPlayer() ) + { + if ( player in file.playerDeathsPvp ) + file.playerDeathsPvp[ player ]++ + else + file.playerDeathsPvp[ player ] <- 1.0 + Stats_IncrementStat( player, "deaths_stats", "totalPVP", "", 1.0 ) + } + + // byPilots + if ( IsPilot( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "byPilots", "", 1.0 ) + + // byTitan_ + if ( attacker.IsTitan() && attacker.IsPlayer() ) + Stats_IncrementStat( player, "deaths_stats", "byTitan_" + GetTitanCharacterName( attacker ), "", 1.0 ) + + // bySpectres + if ( IsSpectre( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "bySpectres", "", 1.0 ) + + // byGrunts + if ( IsGrunt( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "byGrunts", "", 1.0 ) + + // byNPCTitans_ + if ( attacker.IsTitan() && attacker.IsNPC() ) + Stats_IncrementStat( player, "deaths_stats", "byNPCTitans_" + GetTitanCharacterName( attacker ), "", 1.0 ) + } + + // asPilot + if ( IsPilot( player ) ) + Stats_IncrementStat( player, "deaths_stats", "asPilot", "", 1.0 ) + + // asTitan_ + if ( player.IsTitan() ) + Stats_IncrementStat( player, "deaths_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 ) + + // suicides + if ( IsSuicide( attacker, player, DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) ) + Stats_IncrementStat( player, "deaths_stats", "suicides", "", 1.0 ) + + // whileEjecting + if ( player.p.pilotEjecting ) + Stats_IncrementStat( player, "deaths_stats", "whileEjecting", "", 1.0 ) +} + +void function HandleWeaponKillStats( entity victim, entity attacker, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + string damageSourceStr = GetPersistenceRefFromDamageInfo( damageInfo ) + // cant do weapon stats for no weapon + if ( damageSourceStr == "" ) + return + + // check things once, for performance + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + + // total + Stats_IncrementStat( player, "weapon_kill_stats", "total", damageSourceStr, 1.0 ) + + // pilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "weapon_kill_stats", "pilots", damageSourceStr, 1.0 ) + + // ejecting_pilots + if ( victimIsPilot && victim.p.pilotEjecting ) + Stats_IncrementStat( player, "weapon_kill_stats", "ejecting_pilots", damageSourceStr, 1.0 ) + + // titansTotal + if ( victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "titansTotal", damageSourceStr, 1.0 ) + // spectres + if ( IsSpectre( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "spectres", damageSourceStr, 1.0 ) + + // marvins + if ( IsMarvin( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "marvins", damageSourceStr, 1.0 ) + + // grunts + if ( IsGrunt( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "grunts", damageSourceStr, 1.0 ) + + // ai + if ( victimIsNPC ) + Stats_IncrementStat( player, "weapon_kill_stats", "ai", damageSourceStr, 1.0 ) + + // titans_ + if ( victimIsPlayer && victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "titans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 ) + + // npcTitans_ + if ( victimIsNPC && victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "npcTitans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 ) } -void function IncrementPlayerDidPilotExecutionWhileCloaked(entity player) +void function HandleKillStats( entity victim, entity attacker, var damageInfo ) { + if ( !IsValid( attacker ) ) + return + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + // check things once, for performance + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + + if ( player in file.playerKills ) + file.playerKills[ player ]++ + else + file.playerKills[ player ] <- 1.0 + // total + Stats_IncrementStat( player, "kills_stats", "total", "", 1.0 ) + + // totalPVP + if ( victimIsPlayer ) + { + if ( player in file.playerKillsPvp ) + file.playerKillsPvp[ player ]++ + else + file.playerKillsPvp[ player ] <- 1.0 + Stats_IncrementStat( player, "kills_stats", "totalPVP", "", 1.0 ) + } + + // pilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "kills_stats", "pilots", "", 1.0 ) + + // spectres + if ( IsSpectre( victim ) ) + Stats_IncrementStat( player, "kills_stats", "spectres", "", 1.0 ) + + // marvins + if ( IsMarvin( victim ) ) + Stats_IncrementStat( player, "kills_stats", "marvins", "", 1.0 ) + + // grunts + if ( IsGrunt( victim ) ) + Stats_IncrementStat( player, "kills_stats", "grunts", "", 1.0 ) + + // totalTitans + if ( victimIsTitan ) + Stats_IncrementStat( player, "kills_stats", "totalTitans", "", 1.0 ) + + // totalPilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "kills_stats", "totalPilots", "", 1.0 ) + + // totalNPC + if ( victimIsNPC ) + Stats_IncrementStat( player, "kills_stats", "totalNPC", "", 1.0 ) + + // totalTitansWhileDoomed + if ( victimIsTitan && attacker.IsTitan() && GetDoomedState( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "totalTitansWhileDoomed", "", 1.0 ) + + // asPilot + if ( IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "asPilot", "", 1.0 ) + + // totalAssists + // assistsTotal ( weapon_kill_stats ) + // note: eww + table alreadyAssisted + foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) + { + if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim ) + continue + + bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false + if( attackerInfo.attacker != attacker && !exists ) + { + alreadyAssisted[ attackerInfo.attacker.GetEncodedEHandle() ] <- true + Stats_IncrementStat( attackerInfo.attacker, "kills_stats", "totalAssists", "", 1.0 ) + + string source = DamageSourceIDToString( attackerInfo.damageSourceId ) + + if ( IsValidStatItemString( source ) ) + Stats_IncrementStat( attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 ) + } + } + + // asTitan_ + if ( player.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 ) + + // firstStrikes + if ( file.isFirstStrike && attacker.IsPlayer() && victimIsPlayer ) + { + Stats_IncrementStat( player, "kills_stats", "firstStrikes", "", 1.0 ) + file.isFirstStrike = false + } + + // ejectingPilots + if ( victimIsPilot && victim.p.pilotEjecting ) + Stats_IncrementStat( player, "kills_stats", "ejectingPilots", "", 1.0 ) + + // whileEjecting + if ( attacker.IsPlayer() && attacker.p.pilotEjecting ) + Stats_IncrementStat( player, "kills_stats", "whileEjecting", "", 1.0 ) + + // cloakedPilots + if ( victimIsPilot && IsCloaked( victim ) ) + Stats_IncrementStat( player, "kills_stats", "cloakedPilots", "", 1.0 ) + + // whileCloaked + if ( attacker == player && IsCloaked( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "whileCloaked", "", 1.0 ) + + // wallrunningPilots + if ( victimIsPilot && victim.IsWallRunning() ) + Stats_IncrementStat( player, "kills_stats", "wallrunningPilots", "", 1.0 ) + + // whileWallrunning + if ( attacker == player && attacker.IsWallRunning() ) + Stats_IncrementStat( player, "kills_stats", "whileWallrunning", "", 1.0 ) + + // wallhangingPilots + if ( victimIsPilot && victim.IsWallHanging() ) + Stats_IncrementStat( player, "kills_stats", "wallhangingPilots", "", 1.0 ) + + // whileWallhanging + if ( attacker == player && attacker.IsWallHanging() ) + Stats_IncrementStat( player, "kills_stats", "whileWallhanging", "", 1.0 ) + + // pilotExecution + if ( damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecution", "", 1.0 ) + + // pilotExecutePilot + if ( victimIsPilot && damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecutePilot", "", 1.0 ) + + // pilotKillsWithHoloPilotActive + if ( victimIsPilot && GetDecoyActiveCountForPlayer( player ) > 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWithHoloPilotActive", "", 1.0 ) + + // pilotKillsWithAmpedWallActive + if ( victimIsPilot && GetAmpedWallsActiveCountForPlayer( player ) > 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWithAmpedWallActive", "", 1.0 ) + + // pilotExecutePilotUsing_ + if ( victimIsPilot && damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecutePilotUsing_" + player.p.lastExecutionUsed, "", 1.0 ) + + // pilotKickMelee + if ( damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "pilotKickMelee", "", 1.0 ) + + // pilotKickMeleePilot + if ( victimIsPilot && damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "pilotKickMeleePilot", "", 1.0 ) + + // titanMelee + if ( DamageIsTitanMelee( damageSource ) ) + Stats_IncrementStat( player, "kills_stats", "titanMelee", "", 1.0 ) + + // titanMeleePilot + if ( victimIsPilot && DamageIsTitanMelee( damageSource ) ) + Stats_IncrementStat( player, "kills_stats", "titanMeleePilot", "", 1.0 ) + + // titanStepCrush + if ( IsTitanCrushDamage( damageInfo ) ) + Stats_IncrementStat( player, "kills_stats", "titanStepCrush", "", 1.0 ) + + // titanStepCrushPilot + if ( victimIsPilot && IsTitanCrushDamage( damageInfo ) ) + Stats_IncrementStat( player, "kills_stats", "titanStepCrushPilot", "", 1.0 ) + + // titanExocution + // note: RESPAWN WHY? EXPLAIN + if ( damageSource == eDamageSourceId.titan_execution ) + { + string titanName = GetTitanCharacterName( player ) + titanName = titanName.slice( 0, 1 ).toupper() + titanName.slice( 1, titanName.len() ) + Stats_IncrementStat( player, "kills_stats", "titanExocution" + titanName, "", 1.0 ) + } + + // titanFallKill + if ( damageSource == eDamageSourceId.damagedef_titan_fall ) + Stats_IncrementStat( player, "kills_stats", "titanFallKill", "", 1.0 ) + + // petTitanKillsFollowMode + if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.FOLLOW ) + Stats_IncrementStat( player, "kills_stats", "petTitanKillsFollowMode", "", 1.0 ) + + // petTitanKillsGuardMode + if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.STAY ) + Stats_IncrementStat( player, "kills_stats", "petTitanKillsGuardMode", "", 1.0 ) + + // rodeo_total + if ( damageSource == eDamageSourceId.rodeo_battery_removal ) + Stats_IncrementStat( player, "kills_stats", "rodeo_total", "", 1.0 ) + + // pilot_headshots_total + if ( victimIsPilot && DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) + Stats_IncrementStat( player, "kills_stats", "pilot_headshots_total", "", 1.0 ) + + // evacShips + if ( IsEvacDropship( victim ) ) + Stats_IncrementStat( player, "kills_stats", "evacShips", "", 1.0 ) + + // nuclearCore + if ( damageSource == eDamageSourceId.damagedef_nuclear_core ) + Stats_IncrementStat( player, "kills_stats", "nuclearCore", "", 1.0 ) + + // meleeWhileCloaked + if ( IsCloaked( attacker ) && damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "meleeWhileCloaked", "", 1.0 ) + + // titanKillsAsPilot + if ( victimIsTitan && IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "titanKillsAsPilot", "", 1.0 ) + + // pilotKillsWhileStimActive + if ( victimIsPilot && StatusEffect_Get( attacker, eStatusEffect.stim_visual_effect ) <= 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWhileStimActive", "", 1.0 ) + + // pilotKillsAsTitan + if ( victimIsPilot && attacker.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsAsTitan", "", 1.0 ) + + // pilotKillsAsPilot + if ( victimIsPilot && IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsAsPilot", "", 1.0 ) + + // titanKillsAsTitan + if ( victimIsTitan && attacker.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "titanKillsAsTitan", "", 1.0 ) } -void function UpdateTitanDamageStat(entity attacker, float savedDamage, var damageInfo) +void function HandleTitanStats( entity victim, entity attacker, var damageInfo ) { + if ( !IsValid( attacker ) ) + return + + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + bool titanIsPrime = IsTitanPrimeTitan( player ) + // pilots + if ( victimIsPilot && attacker.IsTitan() ) + Stats_IncrementStat( player, "titan_stats", "pilots", GetTitanCharacterName( attacker ), 1.0 ) + + // titansTotal + if ( victimIsTitan && attacker.IsTitan() ) + Stats_IncrementStat( player, "titan_stats", "titansTotal", GetTitanCharacterName( attacker ), 1.0 ) + + // pilotsAsPrime + if ( victimIsPilot && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "pilotsAsPrime", GetTitanCharacterName( attacker ), 1.0 ) + + // titansAsPrime + if ( victimIsTitan && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "titansAsPrime", GetTitanCharacterName( attacker ), 1.0 ) + + // executionsAsPrime + if ( damageSource == eDamageSourceId.titan_execution && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "executionsAsPrime", GetTitanCharacterName( attacker ), 1.0 ) } -void function UpdateTitanWeaponDamageStat(entity attacker, float savedDamage, var damageInfo) +void function OnPlayerRespawned( entity player ) { + thread SetLastPosForDistanceStatValid_Threaded( player, true ) +} + +void function OnEpilogueStarted() +{ + // award players for match completed, wins, and losses + foreach ( entity player in GetPlayerArray() ) + { + Stats_IncrementStat( player, "game_stats", "game_completed", "", 1.0 ) + + if ( player.GetTeam() == GetWinningTeam() ) + Stats_IncrementStat( player, "game_stats", "game_won", "", 1.0 ) + else + Stats_IncrementStat( player, "game_stats", "game_lost", "", 1.0 ) + } + + if ( IsValidGamemodeString( GAMETYPE ) ) + { + // award players with matches played on the mode + foreach ( entity player in GetPlayerArray() ) + { + Stats_IncrementStat( player, "game_stats", "mode_played", GAMETYPE, 1.0 ) + + if ( player.GetTeam() == GetWinningTeam() ) + Stats_IncrementStat( player, "game_stats", "mode_won", GAMETYPE, 1.0 ) + } + } + + // update player's KD + foreach ( entity player in GetPlayerArray() ) + { + // kd stats + // index 0 is most recent game + // index 9 is least recent game + float playerKills = ( player in file.playerKills ) ? file.playerKills[ player ] : 0.0 + float playerDeaths = ( player in file.playerDeaths ) ? file.playerDeaths[ player ] : 0.0 + float kdratio_match + if ( playerDeaths == 0.0 ) + kdratio_match = playerKills + else + kdratio_match = playerKills / playerDeaths + + float playerKillsPvp = ( player in file.playerKillsPvp ) ? file.playerKillsPvp[ player ] : 0.0 + float playerDeathsPvp = ( player in file.playerDeathsPvp ) ? file.playerDeathsPvp[ player ] : 0.0 + float kdratiopvp_match + if ( playerDeathsPvp == 0.0 ) + kdratiopvp_match = playerKillsPvp + else + kdratiopvp_match = playerKillsPvp / playerDeathsPvp + + float totalDeaths = player.GetPersistentVarAsInt( "deathStats.total" ).tofloat() + float totalKills = player.GetPersistentVarAsInt( "killStats.total" ).tofloat() + float totalDeathsPvp = player.GetPersistentVarAsInt( "deathStats.totalPVP" ).tofloat() + float totalKillsPvp = player.GetPersistentVarAsInt( "killStats.totalPVP" ).tofloat() + float kdratio_lifetime + if ( totalDeaths == 0.0 ) + kdratio_lifetime = totalKills + else + kdratio_lifetime = totalKills / totalDeaths + float kdratio_lifetimepvp + if ( totalDeathsPvp == 0.0 ) + kdratio_lifetimepvp = totalKillsPvp + else + kdratio_lifetimepvp = totalKillsPvp / totalDeathsPvp + + // shift stats by 1 to make room for new game data + for ( int i = NUM_GAMES_TRACK_KDRATIO - 2; i >= 0; --i ) + { + player.SetPersistentVar( format( "kdratio_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format("kdratio_match[%i]", i ) ) ) + player.SetPersistentVar( format( "kdratiopvp_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format( "kdratiopvp_match[%i]", i ) ) ) + } + // add new game data + player.SetPersistentVar( "kdratio_match[0]", kdratio_match ) + player.SetPersistentVar( "kdratiopvp_match[0]", kdratiopvp_match ) + player.SetPersistentVar( "kdratio_lifetime", kdratio_lifetime ) + player.SetPersistentVar( "kdratio_lifetime_pvp", kdratio_lifetimepvp ) + } + + // award mvp and top 3 in each team + if ( !IsFFAGame() ) + { + string gamemode = GameRules_GetGameMode() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( gamemode ) + + for( int team = 0; team < MAX_TEAMS; team++ ) + { + array players = GetPlayerArrayOfTeam( team ) + if ( compareFunc == null ) + { + printt( "gamemode doesn't have a compare func to get the top 3" ) + return + } + players.sort( compareFunc ) + int maxAwards = int( min( players.len(), 3 ) ) + for ( int i = 0; i < maxAwards; i++ ) + { + if ( i == 0 ) + Stats_IncrementStat( players[ i ], "game_stats", "mvp", "", 1.0 ) + Stats_IncrementStat( players[ i ], "game_stats", "top3OnTeam", "", 1.0 ) + } + } + + } +} +void function SetLastPosForDistanceStatValid_Threaded( entity player, bool val ) +{ + WaitFrame() + if ( !IsValid( player ) ) + return + player.p.lastPosForDistanceStatValid = val } -void function UpdateTitanCoreEarnedStat( entity player, entity titan ) +// Respawn did this through stuff found in _entitystructs.gnut (stuff like stats_wallrunTime) +// but their implementation seems kinda bad. The advantage it has over this method is not polling +// every 0.25 seconds, and using movement callbacks and stuff instead. However, since i can't find +// callbacks for things like changing weapon, i would have to poll for that *anyway* and thus, +// there is no point in doing things Respawn's way here +void function HandleDistanceAndTimeStats_Threaded() { + // just to be safe + if ( IsLobby() ) + return + + while ( GetGameState() < eGameState.Playing ) + WaitFrame() + + float lastTickTime = Time() + + while( true ) + { + // track distance stats + foreach ( entity player in GetPlayerArray() ) + { + if ( player.p.lastPosForDistanceStatValid ) + { + // not 100% sure on using Distance2D over Distance tbh + float distInches = Distance2D( player.p.lastPosForDistanceStat, player.GetOrigin() ) + float distMiles = distInches / 63360.0 + + // more generic distance stats + Stats_IncrementStat( player, "distance_stats", "total", "", distMiles ) + if ( player.IsTitan() ) + { + Stats_IncrementStat( player, "distance_stats", "asTitan_" + GetTitanCharacterName( player ), "", distMiles ) + Stats_IncrementStat( player, "distance_stats", "asTitan", "", distMiles ) + } + else + Stats_IncrementStat( player, "distance_stats", "asPilot", "", distMiles ) + + + string state = "" + // specific distance stats + if ( player.IsWallRunning() ) + state = "wallrunning" + else if ( PlayerIsRodeoingTitan( player ) ) + { + if ( player.GetTitanSoulBeingRodeoed().GetTeam() == player.GetTeam() ) + state = "onFriendlyTitan" + else + state = "onEnemyTitan" + } + else if ( player.IsZiplining() ) + state = "ziplining" + else if ( !player.IsOnGround() ) + state = "inAir" + + if ( state != "" ) + Stats_IncrementStat( player, "distance_stats", state, "", distMiles ) + } + + player.p.lastPosForDistanceStat = player.GetOrigin() + } + + float timeSeconds = Time() - lastTickTime + float timeHours = timeSeconds / 3600.0 + + // track time stats + foreach ( entity player in GetPlayerArray() ) + { + // first tick i dont count + if ( timeSeconds == 0 ) + break + + // more generic time stats + Stats_IncrementStat( player, "time_stats", "hours_total", "", timeHours ) + if ( player.IsTitan() ) + { + Stats_IncrementStat( player, "time_stats", "hours_as_titan_" + GetTitanCharacterName( player ), "", timeHours ) + Stats_IncrementStat( player, "time_stats", "hours_as_titan", "", timeHours ) + } + else + Stats_IncrementStat( player, "time_stats", "hours_as_pilot", "", timeHours ) + + string state = "" + // specific time stats + if ( !IsAlive( player ) ) + state = "hours_dead" + else if ( player.IsWallHanging() ) + state = "hours_wallhanging" + else if ( player.IsWallRunning() ) + state = "hours_wallrunning" + else if ( !player.IsOnGround() ) + state = "hours_inAir" + if ( state != "" ) + Stats_IncrementStat( player, "time_stats", state, "", timeHours ) + + // weapon time stats + entity activeWeapon = player.GetActiveWeapon() + if ( IsValid( activeWeapon ) ) + { + if ( IsValidStatItemString( activeWeapon.GetWeaponClassName() ) ) + Stats_IncrementStat( player, "weapon_stats", "hoursUsed", activeWeapon.GetWeaponClassName(), timeHours ) + + foreach( entity weapon in player.GetMainWeapons() ) + { + if ( IsValidStatItemString( weapon.GetWeaponClassName() ) ) + Stats_IncrementStat( player, "weapon_stats", "hoursEquipped", weapon.GetWeaponClassName(), timeHours ) + } + } + + // map time stats + Stats_IncrementStat( player, "game_stats", "hoursPlayed", "", timeHours ) + } + + lastTickTime = Time() + // not rly worth doing this every frame, just a couple of times per second should be fine + wait 0.25 + } +} + +// this is kinda shit +void function SaveStatsPeriodically_Threaded() +{ + while( true ) + { + foreach( entity player in GetPlayerArray() ) + Stats_SaveAllStats( player ) + wait 5 + } } -void function PreScoreEventUpdateStats(entity attacker, entity ent) +bool function IsValidGamemodeString( string mode ) { + int gameModeCount = PersistenceGetEnumCount( "gameModes" ) + for ( int modeIndex = 0; modeIndex < gameModeCount; modeIndex++ ) + { + string gameModeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeIndex ) + + if ( gameModeName == mode ) + return true + } + return false } -void function PostScoreEventUpdateStats(entity attacker, entity ent) +bool function IsValidStatItemString( string item ) { + foreach( str in shGlobalMP.statsItemsList ) + { + if ( str == item ) + return true + } + return false } -void function Stats_OnPlayerDidDamage(entity player, var damageInfo) +string function GetPersistenceRefFromDamageInfo( var damageInfo ) { + string damageSourceString = DamageSourceIDToString( DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + + foreach( str in shGlobalMP.statsItemsList ) + { + if ( str == damageSourceString ) + return damageSourceString + } + return "" +} + +bool function DamageIsTitanMelee( int damageSourceId ) +{ + switch( damageSourceId ) + { + case eDamageSourceId.melee_titan_punch: + case eDamageSourceId.melee_titan_punch_ion: + case eDamageSourceId.melee_titan_punch_legion: + case eDamageSourceId.melee_titan_punch_tone: + case eDamageSourceId.melee_titan_punch_scorch: + case eDamageSourceId.melee_titan_punch_northstar: + case eDamageSourceId.melee_titan_punch_fighter: + case eDamageSourceId.melee_titan_sword: + case eDamageSourceId.melee_titan_sword_aoe: + return true + default: + return false + } + unreachable } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut index 85f5aa05..7a7498b8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut @@ -785,7 +785,7 @@ bool function IsSettingPrimeTitanWithoutSetFile( entity player, string loadoutTy bool function SkipItemLockedCheck( entity player, string ref, string parentRef, string loadoutProperty ) //Hack: Skip entitlement related unlock checks for now. Can fail. { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return true //if ( IsItemInEntitlementUnlock( ref ) && IsLobby() ) //TODO: Look into restricting this to lobby only? But entitlement checks can fail randomly... @@ -3993,7 +3993,7 @@ bool function IsValidTitanLoadoutIndex( int loadoutIndex ) bool function HasPrimeToMatchExecutionType( entity player, int itemType ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return true switch( itemType ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut new file mode 100644 index 00000000..00bdff60 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -0,0 +1,1091 @@ +global function Progression_Init +global function ProgressionEnabledForPlayer +#if CLIENT || UI +global function Progression_SetPreference +global function Progression_GetPreference +global function UpdateCachedLoadouts_Delayed +#endif + +// SO FOR SOME GOD DAMN REASON, PUTTING THESE INTO ONE STRUCT +// AND PUTTING THE #if STUFF AROUND THE VARS CAUSES A COMPILE +// ERROR, SO I HAVE TO DO THIS AWFULNESS + +#if SERVER +struct { + table progressionEnabled +} file +#else // UI || CLIENT +struct { + bool isUpdatingCachedLoadouts = false +} file +#endif + + +void function Progression_Init() +{ + #if SERVER + AddCallback_OnClientDisconnected( OnClientDisconnected ) + AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression ) + AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) + #elseif CLIENT + AddCallback_OnClientScriptInit( OnClientScriptInit ) + #endif +} + +bool function ProgressionEnabledForPlayer( entity player ) +{ + #if SERVER + if ( player in file.progressionEnabled ) + return file.progressionEnabled[player] + + return false + #else // CLIENT || UI + return GetConVarBool( "ns_progression_enabled" ) + #endif +} + +#if SERVER +void function OnPlaying() +{ + SetUIVar( level, "penalizeDisconnect", false ) // dont show the "you will lose merits thing" +} + +void function OnClientDisconnected( entity player ) +{ + // cleanup table when player leaves + if ( player in file.progressionEnabled ) + delete file.progressionEnabled[player] +} + +bool function ClientCommand_SetProgression( entity player, array args ) +{ + if ( args.len() != 1 ) + return false + if ( args[0] != "0" && args[0] != "1" ) + return false + + file.progressionEnabled[player] <- args[0] == "1" + + // loadout validation when progression is turned on + if ( file.progressionEnabled[player] ) + ValidateEquippedItems( player ) + + return true +} +#endif + +#if CLIENT +void function OnClientScriptInit( entity player ) +{ + // unsure if this is needed, just being safe + if ( player != GetLocalClientPlayer() ) + return + + Progression_SetPreference( GetConVarBool( "ns_progression_enabled" ) ) + UpdateCachedLoadouts_Delayed() +} +#endif + +#if CLIENT || UI +void function Progression_SetPreference( bool enabled ) +{ + SetConVarBool( "ns_progression_enabled", enabled ) + + #if CLIENT + GetLocalClientPlayer().ClientCommand( "ns_progression " + enabled.tointeger() ) + #else // UI + ClientCommand( "ns_progression " + enabled.tointeger() ) + #endif +} + +bool function Progression_GetPreference() +{ + return GetConVarBool( "ns_progression_enabled" ) +} + +void function UpdateCachedLoadouts_Delayed() +{ + if ( file.isUpdatingCachedLoadouts ) + return + + file.isUpdatingCachedLoadouts = true + + #if UI + RunClientScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced + #else // CLIENT + RunUIScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced + #endif + + thread UpdateCachedLoadouts_Threaded() +} + +void function UpdateCachedLoadouts_Threaded() +{ + wait 1.0 // give the server time to network our new persistence + + UpdateCachedLoadouts() + + // below here is just making all the menu models update properly and such + + #if UI + uiGlobal.pilotSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "pilot" ) + uiGlobal.titanSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "titan" ) + #endif + + #if CLIENT + entity player = GetLocalClientPlayer() + ClearAllTitanPreview( player ) + ClearAllPilotPreview( player ) + UpdateTitanModel( player, GetPersistentSpawnLoadoutIndex( player, "titan" ) ) + UpdatePilotModel( player, GetPersistentSpawnLoadoutIndex( player, "pilot" ) ) + #endif + + file.isUpdatingCachedLoadouts = false +} +#endif + +#if SERVER +void function ValidateEquippedItems( entity player ) +{ + printt( "VALIDATING EQUIPPED ITEMS FOR PLAYER: " + player.GetPlayerName() ) + + // banner + CallingCard card = PlayerCallingCard_GetActive( player ) + if ( IsItemLocked( player, card.ref ) ) + { + printt( "- BANNER CARD IS LOCKED, RESETTING" ) + PlayerCallingCard_SetActiveByRef( player, "callsign_16_col" ) // copied from _persistentdata.gnut + } + + // patch + CallsignIcon icon = PlayerCallsignIcon_GetActive( player ) + if ( IsItemLocked( player, icon.ref ) ) + { + printt( "- BANNER PATCH IS LOCKED, RESETTING" ) + PlayerCallsignIcon_SetActiveByRef( player, "gc_icon_titanfall" ) // copied from _persistentdata.gnut + } + + // faction + int factionIndex = player.GetPersistentVarAsInt( "factionChoice" ) + string factionRef = PersistenceGetEnumItemNameForIndex( "faction", factionIndex ) + if ( IsItemLocked( player, factionRef ) ) + { + printt( "- FACTION IS LOCKED, RESETTING" ) + player.SetPersistentVar( "factionChoice", "faction_marauder" ) // im so sorry that i am setting you to use sarah, you don't deserve this + } + + // boost + BurnReward reward = BurnReward_GetById( player.GetPersistentVarAsInt( "burnmeterSlot" ) ) + if ( IsItemLocked( player, reward.ref ) ) + { + printt( "- BOOST IS LOCKED, RESETTING" ) + player.SetPersistentVar( "burnmeterSlot", BurnReward_GetByRef( "burnmeter_amped_weapons" ).id ) + } + + // titan loadouts + for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ ) + { + printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex ) + + bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) + TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex ) + TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex] + + printt( " - CHASSIS: " + loadout.titanClass ) + + // passive1 - "Titan Kit" (things like overcore) + if ( loadout.passive1 != defaultLoadout.passive1 && IsSubItemLocked( player, loadout.passive1, loadout.titanClass ) ) + { + printt( " - TITAN KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + + // passive2 - " Kit" (things like zero point tripwire) + if ( loadout.passive2 != defaultLoadout.passive2 && IsSubItemLocked( player, loadout.passive2, loadout.titanClass ) ) + { + printt( " - CHASSIS KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + + // passive3 - "Titanfall Kit" (warpfall/dome shield) + if ( loadout.passive3 != defaultLoadout.passive3 && IsSubItemLocked( player, loadout.passive3, loadout.titanClass ) ) + { + printt( " - TITANFALL KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive3", defaultLoadout.passive3 ) + } + + // passive4 - monarch core 1 + if ( loadout.passive4 != defaultLoadout.passive4 && IsSubItemLocked( player, loadout.passive4, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 1 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive4", defaultLoadout.passive4 ) + } + + // passive5 - monarch core 2 + if ( loadout.passive5 != defaultLoadout.passive5 && IsSubItemLocked( player, loadout.passive5, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 2 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive5", defaultLoadout.passive5 ) + } + + // passive6 - monarch core 3 + if ( loadout.passive6 != defaultLoadout.passive6 && IsSubItemLocked( player, loadout.passive6, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 3 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive6", defaultLoadout.passive6 ) + } + + // titanExecution + if ( !IsRefValid( loadout.titanExecution ) || !IsValidTitanExecution( titanLoadoutIndex, "titanExecution", "", loadout.titanExecution ) ) + { + printt( " - TITAN EXECUTION IS INVALID FOR CHASSIS, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + else if ( IsItemLocked( player, loadout.titanExecution ) ) + { + printt( " - TITAN EXECUTION EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + else if ( GetItemData( loadout.titanExecution ).reqPrime && IsItemLocked( player, loadout.primeTitanRef ) ) + { + printt( " - PRIME TITAN EXECUTION EQUIPPED WHEN PRIME TITAN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + + // skinIndex + // camoIndex + if ( loadout.skinIndex == TITAN_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.camoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + } + else if ( loadout.skinIndex == 0 ) + { + if ( loadout.camoIndex != 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + else + { + string ref = GetSkinRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.skinIndex ) + if ( ref == INVALID_REF ) + { + printt( " - INVALID TITAN WARPAINT, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else if ( IsSubItemLocked( player, ref, loadout.titanClass ) ) + { + printt( " - TITAN WARPAINT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + + // decalIndex + string noseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.decalIndex ) + if ( loadout.decalIndex != defaultLoadout.decalIndex && IsSubItemLocked( player, noseArtRef, loadout.titanClass ) ) + { + printt( " - NOSE ART EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].decalIndex", defaultLoadout.decalIndex ) + } + + // primarySkinIndex + // primaryCamoIndex + if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 ) + { + printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + } + else if ( loadout.primarySkinIndex == 0 && loadout.primaryCamoIndex != 0 ) + { + // titan weapons do not have skins, if we ever do add them lots of stuff will + //need a refactor outside of here so with that being said, i cannot be bothered + printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + + + // isPrime + if ( loadout.isPrime == "titan_is_prime" && IsItemLocked( player, loadout.primeTitanRef ) ) + { + printt( " - PRIME TITAN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].isPrime", defaultLoadout.isPrime ) + } + + // primeSkinIndex + // primeCamoIndex + if ( loadout.primeSkinIndex == TITAN_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primeCamoIndex >= camoSkins.len() || loadout.primeCamoIndex < 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primeCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + } + } + else if ( loadout.primeSkinIndex == 0 ) + { + if ( loadout.primeCamoIndex != 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + } + else + { + printt( " - INVALID PRIME TITAN SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + + // primeDecalIndex + string primeNoseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.primeDecalIndex ) + if ( loadout.primeDecalIndex != defaultLoadout.primeDecalIndex && IsSubItemLocked( player, primeNoseArtRef, loadout.titanClass ) ) + { + printt( " - PRIME NOSE ART EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeDecalIndex", defaultLoadout.primeDecalIndex ) + } + + // showArmBadge - equipped and shouldnt be able to + if ( loadout.showArmBadge && !CanEquipArmBadge( player, loadout.titanClass ) ) + { + printt( " - ARM BADGE EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].showArmBadge", defaultLoadout.showArmBadge ) + } + + // equipped titan loadout - equipped titan class is locked + if ( isSelected && IsItemLocked( player, loadout.titanClass ) ) + { + printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" ) + player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 ) + } + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) ) + + // pilot loadouts + for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ ) + { + printt( "- VALIDATING PILOT LOADOUT: " + pilotLoadoutIndex ) + + bool isSelected = pilotLoadoutIndex == player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" ) + PilotLoadoutDef loadout = GetPilotLoadout( player, pilotLoadoutIndex ) + PilotLoadoutDef defaultLoadout = shGlobal.defaultPilotLoadouts[pilotLoadoutIndex] + + // note: for readability, I have added {} around the different items, + // so that you can collapse them in visual studio code (and other good IDEs) + + // tactical + { + if ( !IsRefValid( loadout.suit ) ) + { + printt( " - TACTICAL IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit ) + } + else if ( IsItemLocked( player, loadout.suit ) ) + { + printt( " - TACTICAL IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit ) + } + } + + // ordnance + { + if ( !IsRefValid( loadout.ordnance ) ) + { + printt( " - ORDNANCE IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance ) + } + else if ( IsItemLocked( player, loadout.ordnance ) ) + { + printt( " - ORDNANCE IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance ) + } + } + + // race ( gender ) + { + if ( !IsRefValid( loadout.race ) ) + { + printt( " - GENDER IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race ) + } + else if ( IsItemLocked( player, loadout.race ) ) + { + printt( " - GENDER IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race ) + } + } + + // camoIndex + // skinIndex + { + if ( loadout.skinIndex == PILOT_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_PILOT ) + if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 ) + { + printt( " - INVALID PILOT CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.camoIndex] + if ( IsItemLocked( player, camoSkin.ref ) ) + { + printt( " - PILOT CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + } + else if ( loadout.skinIndex == 0 ) + { + if ( loadout.camoIndex != 0 ) + { + printt( " - INVALID PILOT CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + else + { + // pilots can't have skins other than 0 and 1 right? + printt( " - INVALID PILOT SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + + // primary weapon + { + if ( !IsRefValid( loadout.primary ) || GetItemType( loadout.primary ) != eItemTypes.PILOT_PRIMARY ) + { + printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary ) + } + else if ( IsItemLocked( player, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary ) + } + } + + // primary weapon mods + { + // mod1 + if ( loadout.primaryMod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.primary, loadout.primaryMod1 ) ) + { + printt( " - PRIMARY WEAPON MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod1, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 ) + } + // mod2 + if ( loadout.primaryMod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "primarymod2", loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( !HasSubitem( loadout.primary, loadout.primaryMod2 ) ) + { + printt( " - PRIMARY WEAPON MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod2, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( loadout.primaryMod2 == loadout.primaryMod1 && loadout.primaryMod2 != "" ) + { + printt( " - PRIMARY WEAPON MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( loadout.primaryAttachment == "threat_scope" ) + { + printt( " - PRIMARY WEAPON MOD 2 IS SET WITH THREAT SCOPE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + // attachment + if ( loadout.primaryAttachment == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.primary, loadout.primaryAttachment ) ) + { + printt( " - PRIMARY WEAPON ATTACHMENT IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment ) + } + else if ( IsSubItemLocked( player, loadout.primaryAttachment, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON ATTACHMENT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment ) + } + // mod3 (pro screen) + if ( loadout.primaryMod3 == "" ) + { + // do nothing + } + else if ( loadout.primaryMod3 == "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - PRIMARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod3, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 ) + } + } + + // primary weapon camoIndex + // primary weapon skinIndex + { + if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 ) + { + printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + } + else if ( loadout.primarySkinIndex == 0 ) + { + if ( loadout.primaryCamoIndex != 0 ) + { + printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.primarySkinIndex, loadout.primary ), loadout.primary ) ) + { + printt( " - PRIMARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + + // secondary weapon + { + if ( !IsRefValid( loadout.secondary ) || GetItemType( loadout.secondary ) != eItemTypes.PILOT_SECONDARY ) + { + printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.secondary + if ( loadout.secondary == ref ) // item dupes swap + { + ref = defaultLoadout.weapon3 + } + else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.weapon3 + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref ) + } + else if ( IsItemLocked( player, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.secondary + if ( loadout.weapon3 == ref ) // item dupes swap + { + ref = defaultLoadout.weapon3 + } + else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.weapon3 + } + + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref ) + } + } + + // secondary weapon mods + { + // mod1 + if ( loadout.secondaryMod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod1 ) ) + { + printt( " - SECONDARY WEAPON MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 ) + } + else if ( IsSubItemLocked( player, loadout.secondaryMod1, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 ) + } + // mod2 + if ( loadout.secondaryMod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "secondarymod2", loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod2 ) ) + { + printt( " - SECONDARY WEAPON MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( IsSubItemLocked( player, loadout.secondaryMod2, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( loadout.secondaryMod2 == loadout.secondaryMod1 && loadout.secondaryMod2 != "" ) + { + printt( " - SECONDARY WEAPON MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + // mod3 (pro screen) + if ( loadout.secondaryMod3 == "" ) + { + // do nothing + } + else if ( loadout.secondaryMod3 == "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - SECONDARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 ) + } + else if ( IsSubItemLocked( player, "secondarymod3", loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 ) + } + } + + // secondary weapon camoIndex + // secondary weapon skinIndex + { + if ( loadout.secondarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.secondaryCamoIndex >= camoSkins.len() || loadout.secondaryCamoIndex < 0 ) + { + printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.secondaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + } + else if ( loadout.secondarySkinIndex == 0 ) + { + if ( loadout.secondaryCamoIndex != 0 ) + { + printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.secondarySkinIndex, loadout.secondary ), loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + + // weapon3 + // note: these are always eItemTypes.PILOT_SECONDARY + { + if ( !IsRefValid( loadout.weapon3 ) || GetItemType( loadout.weapon3 ) != eItemTypes.PILOT_SECONDARY ) + { + printt( " - WEAPON3 WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.weapon3 + if ( loadout.weapon3 == ref ) // item dupes swap + { + ref = defaultLoadout.secondary + } + else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.secondary + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref ) + } + else if ( IsItemLocked( player, loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.weapon3 + if ( loadout.secondary == ref ) // item dupes swap + { + ref = defaultLoadout.secondary + } + else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.secondary + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref ) + } + } + + // weapon3 mods + { + // mod1 + if ( loadout.weapon3Mod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod1 ) ) + { + printt( " - WEAPON3 MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 ) + } + else if ( IsSubItemLocked( player, loadout.weapon3Mod1, loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 ) + } + // mod2 + if ( loadout.weapon3Mod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "secondarymod2", loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod2 ) ) + { + printt( " - WEAPON3 MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( IsSubItemLocked( player, loadout.weapon3Mod2, loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( loadout.weapon3Mod2 == loadout.weapon3Mod1 && loadout.weapon3Mod2 != "" ) + { + printt( " - WEAPON3 MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + // mod3 (pro screen) + if ( loadout.weapon3Mod3 == "" ) + { + // do nothing + } + else if ( loadout.weapon3Mod3 != "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - WEAPON3 PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 ) + } + else if ( IsSubItemLocked( player, "secondarymod3", loadout.weapon3 ) ) + { + printt( " - WEAPON3 PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 ) + } + } + + // weapon3 camoIndex + // weapon3 skinIndex + { + if ( loadout.weapon3SkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.weapon3CamoIndex >= camoSkins.len() || loadout.weapon3CamoIndex < 0 ) + { + printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.weapon3CamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + } + else if ( loadout.weapon3SkinIndex == 0 ) + { + if ( loadout.weapon3CamoIndex != 0 ) + { + printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.weapon3SkinIndex, loadout.weapon3 ), loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + + // kit 1 + { + if ( !IsRefValid( loadout.passive1 ) || GetItemType( loadout.passive1 ) != eItemTypes.PILOT_PASSIVE1 ) + { + printt( " - KIT 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + else if ( IsItemLocked( player, loadout.passive1 ) ) + { + printt( " - KIT 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + } + + // kit 2 + { + if ( !IsRefValid( loadout.passive2 ) || GetItemType( loadout.passive2 ) != eItemTypes.PILOT_PASSIVE2 ) + { + printt( " - KIT 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + else if ( IsItemLocked( player, loadout.passive2 ) ) + { + printt( " - KIT 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + } + + // execution + // note: not sure why defaultLoadout has this set to "", but neck snap should be default + { + if ( !IsRefValid( loadout.execution ) || GetItemType( loadout.execution ) != eItemTypes.PILOT_EXECUTION ) + { + printt( " - EXECUTION IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" ) + } + else if ( IsItemLocked( player, loadout.execution ) ) + { + printt( " - EXECUTION IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" ) + } + } + + // equipped pilot loadout + { + if ( isSelected && IsItemLocked( player, "pilot_loadout_" + ( pilotLoadoutIndex + 1 ) ) ) + { + printt( " - SELECTED PILOT LOADOUT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotSpawnLoadout.index", 0 ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", 0 ) + } + } + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" ) ) + + printt( "ITEM VALIDATION COMPLETE FOR PLAYER: " + player.GetPlayerName() ) +} + +// basically just PopulateTitanLoadoutFromPersistentData but without validation, we are doing the validation in a better way +// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need +TitanLoadoutDef function GetTitanLoadout( entity player, int loadoutIndex ) +{ + TitanLoadoutDef loadout + + loadout.name = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "name" ) + loadout.titanClass = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanClass" ) + loadout.primaryMod = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "primaryMod" ) + loadout.special = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "special" ) + loadout.antirodeo = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "antirodeo" ) + loadout.passive1 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive1" ) + loadout.passive2 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive2" ) + loadout.passive3 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive3" ) + loadout.passive4 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive4" ) + loadout.passive5 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive5" ) + loadout.passive6 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive6" ) + loadout.camoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "camoIndex" ) + loadout.skinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.decalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "decalIndex" ) + loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primaryCamoIndex" ) + loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.titanExecution = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanExecution" ) + loadout.showArmBadge = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "showArmBadge" ) + + //Prime Titan related vars + loadout.isPrime = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "isPrime" ) + loadout.primeCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeCamoIndex" ) + loadout.primeSkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeSkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.primeDecalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeDecalIndex" ) + + UpdateDerivedTitanLoadoutData( loadout ) + OverwriteLoadoutWithDefaultsForSetFile( loadout ) + + return loadout +} + +// basically just PopulatePilotLoadoutFromPersistentData but without validation, we are doing the validation in a better way +// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need +PilotLoadoutDef function GetPilotLoadout( entity player, int loadoutIndex ) +{ + PilotLoadoutDef loadout + + loadout.name = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "name" ) + loadout.suit = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "suit" ) + loadout.race = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "race" ) + loadout.execution = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "execution" ) + loadout.primary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primary" ) + loadout.primaryAttachment = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryAttachment" ) + loadout.primaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod1" ) + loadout.primaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod2" ) + loadout.primaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod3" ) + loadout.secondary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondary" ) + loadout.secondaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod1" ) + loadout.secondaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod2" ) + loadout.secondaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod3" ) + loadout.weapon3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3" ) + loadout.weapon3Mod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod1" ) + loadout.weapon3Mod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod2" ) + loadout.weapon3Mod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod3" ) + loadout.ordnance = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "ordnance" ) + loadout.passive1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive1" ) + loadout.passive2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive2" ) + loadout.camoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "camoIndex" ) + loadout.skinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primaryCamoIndex" ) + loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.secondaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondaryCamoIndex" ) + loadout.secondarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.weapon3CamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3CamoIndex" ) + loadout.weapon3SkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3SkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + + UpdateDerivedPilotLoadoutData( loadout ) + + return loadout +} + +bool function CanEquipArmBadge( entity player, string titanClass ) +{ + string skinRef + switch ( titanClass ) + { + case "ion": + skinRef = "ion_skin_fd" + break + case "scorch": + skinRef = "scorch_skin_fd" + break + case "northstar": + skinRef = "northstar_skin_fd" + break + case "ronin": + skinRef = "ronin_skin_fd" + break + case "tone": + skinRef = "tone_skin_fd" + break + case "legion": + skinRef = "legion_skin_fd" + break + case "vanguard": + skinRef = "monarch_skin_fd" + break + } + + return !IsSubItemLocked( player, skinRef, titanClass ) +} + +string function GetWeaponWarpaintRefByIndex( int skinIndex, string parentRef ) +{ + ItemData parentItem = GetItemData( parentRef ) + foreach ( subItem in parentItem.subitems ) + { + if ( GetSubitemType( parentRef, subItem.ref ) != eItemTypes.WEAPON_SKIN ) + continue + if ( subItem.i.skinIndex != skinIndex ) + continue + + return subItem.ref + } + + return INVALID_REF +} +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index 7f356a18..a2de9913 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -386,8 +386,12 @@ float function RoundToNearestMultiplier( float value, float multiplier ) return value } -function DevEverythingUnlocked() +function DevEverythingUnlocked( entity player = null ) { + // check if player has opted into progression or not + if ( player != null && ProgressionEnabledForPlayer( player ) ) + return false + return EverythingUnlockedConVarEnabled() } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut index 4bfeb4f8..0436a393 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut @@ -10,5 +10,8 @@ void function AddTitanXP( entity player, int amount ) // level up notif if ( TitanGetLevel( player, titan ) != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_TitanLeveledUp", shTitanXP.titanClasses.find( titan ), TitanGetGen( player, titan ), TitanGetLevel( player, titan ) ) + AddPlayerScore( player, "TitanLevelUp" ) + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut index 8e100257..4e25e301 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut @@ -12,8 +12,11 @@ void function AddWeaponXP( entity player, int amount ) // level up notif if ( WeaponGetLevel( player, weaponClassname ) != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponLeveledUp", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetGen( player, weaponClassname ), WeaponGetLevel( player, weaponClassname ) ) - + AddPlayerScore( player, "WeaponLevelUp" ) + } + // proscreen if ( player == activeWeapon.GetProScreenOwner() ) { -- cgit v1.2.3 From 9e9d7b7517e4af8df9879302d34deb93cadd9bc5 Mon Sep 17 00:00:00 2001 From: Klemmbaustein <83748124+Klemmbaustein@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:53:06 +0200 Subject: Changed TriggerConnectToServerCallbacks to take in an optional server for which the callback was triggered (#688) What's the point of this --- .../mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index c4046132..efc8d66c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1274,10 +1274,16 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call file.connectCallbacks.fastremovebyvalue( callback ) } -void function TriggerConnectToServerCallbacks() +void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { + ServerInfo server; + if (targetServer == null) + { + targetServer = file.lastSelectedServer + } + foreach( callback in file.connectCallbacks ) { - callback( file.lastSelectedServer ) + callback( expect ServerInfo( targetServer ) ) } } -- cgit v1.2.3 From 43d238aa41b85345266f1c35fe1d42ef88610f1e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 3 Sep 2023 16:24:30 +0200 Subject: Translations update from Weblate (#697) Translated using Weblate (Russian) Currently translated at 95.4% (274 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../resource/northstar_client_localisation_russian.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index d26017b8..514e4fd1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -62,7 +62,7 @@ "featured_mode_all_holopilot" "Великий обманщик" "featured_mode_all_grapple" "Зацепер" "featured_mode_all_phase" "Мир иной" - "featured_mode_all_ticks" "Горячие парни" + "featured_mode_all_ticks" "Крутые перцы" "featured_mode_tactikill" "Тактический удар" "featured_mode_amped_tacticals" "Усиленные тактики" "featured_mode_rocket_arena" "Ракетная Арена" @@ -211,7 +211,7 @@ "SP_S2S" "Ковчег" "SP_S2S_CLASSIC_DESC" "Купер и БТ перемещаются по кораблям, преследуя Ковчег." - "SP_SKYWAY_V1" "Сложенное оружие" + "SP_SKYWAY_V1" "Искажающее орудие" "SP_SKYWAY_V1_CLASSIC_DESC" "БT и Купер были захвачены Кубеном Блиском." // Better.Serverbrowser @@ -329,5 +329,17 @@ "sns_softball_kill_value" "Очков за убийство Софтболом" "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" "gg_assist_reward" "Множитель награды за помощь в убийстве" + "TOGGLE_PROGRESSION" "Вкл/выкл прогресс" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Вкл/выкл прогресс" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Включить прогресс?" + "PROGRESSION_ENABLED_HEADER" "Прогресс включён!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Прогресс включён.^\n\nНедоступных титанов, оружие, фракции, раскраски, и т.п. теперь нужно разблокировать, или купить за Заслуги.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "PROGRESSION_DISABLED_HEADER" "Прогресс выключен!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000Прогресс выключен.^\n\nВсе титаны, оружие, фракции, раскраски, и т.п. теперь доступны.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "player_force_respawn" "Принудительное возрождение" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Отключить прогресс?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Все титаны, оружие, фракции, раскраски, и т.п. станут разблокированы.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Будут доступны только разблокированные или купленные вами титаны, оружие, фракции, раскраски, и т.п.\n\nЭту настройку всегда можно изменить в лобби сетевой игры.\n\n^CC000000Внимание: недоступные предметы в экипировке будут заменены на доступные!" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Прогресс!^\n\nВ Northstar теперь работает оригинальная система прогресса разблокировок. Титанов, оружие, фракции, раскраски, и т.п. теперь можно разблокировать через получение новых уровней и прохождение испытаний.\n\nПрогресс можно включить с помощью кнопки внизу меню лобби.\n\nЭту настройку всегда можно изменить." } } -- cgit v1.2.3 From 578cb2bea79c8440b5870a1557d1c6a870620f53 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 17 Sep 2023 12:55:55 +0200 Subject: Translations update from Weblate (#703) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (French) Currently translated at 98.9% (284 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ * Translated using Weblate (French) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ --------- Co-authored-by: FÁ_monkey Co-authored-by: Andrés Co-authored-by: Lorin-lab Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 12 +++ .../northstar_client_localisation_spanish.txt | 103 ++++++++++++++------- 2 files changed, 80 insertions(+), 35 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index d5881d6c..45abcfc5 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -341,5 +341,17 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "SHOW_ONLY_NOT_REQUIRED" "Uniquement les mods optionnels" "NO_RESULTS" "Aucun résultat." "NO_MODS" "Aucun paramètre trouvé ! Installez d'autres mods depuis ^5588FF00northstar.thunderstore.io^0." + "player_force_respawn" "Réapparition forcée" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Désactiver la progression ?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Les Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Activer la progression ?" + "PROGRESSION_ENABLED_HEADER" "Progression activée !" + "PROGRESSION_DISABLED_HEADER" "Progression désactivée !" + "PROGRESSION_DISABLED_BODY" "^CCCC0000La progression a été désactivée.^\n\nLes Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" + "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "TOGGLE_PROGRESSION" "Activer la progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Activer la progression" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 0dc82570..43ee412f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -9,10 +9,10 @@ "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Recargar Mods" "WARNING" "Advertencia" - "CORE_MOD_DISABLE_WARNING" "Puedes romper el cliente si deshabilitas los mods principales!" + "CORE_MOD_DISABLE_WARNING" "¡Puedes romper el cliente si deshabilitas los mods principales!" "DISABLE" "Deshabilitar" - "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Gracias por instalar Northstar!." + "DIALOG_TITLE_INSTALLED_NORTHSTAR" "¡Gracias por instalar Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para que Northstar funcione, necesita autentificarse con el servidor maestro Northstar. Esto requiere enviar tu token Origin al servidor maestro, no se guardará ni se usará para cualquier otro fin. Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mods en cualquier momento." "BACK_AUTHENTICATION_AGREEMENT" "Acuerdo de autentificación" @@ -26,7 +26,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "NS_SERVERBROWSER_NOSERVERS" "No se encontraron servidores" "NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconocido" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Esperando por servidores..." - "NS_SERVERBROWSER_CONNECTIONFAILED" "Connexión fallida!" + "NS_SERVERBROWSER_CONNECTIONFAILED" "¡Conexión fallida!" "REFRESH_SERVERS" "Recargar" "MENU_TITLE_CONNECT_PASSWORD" "Conectar con contraseña" @@ -36,7 +36,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PRIVATE_MATCH_PAGE_NEXT" "Página siguiente" "MENU_MATCH_SETTINGS" "Configuración de partida" - "MENU_MATCH_SETTINGS_SUBMENU" "%s1 Configuraciones" + "MENU_MATCH_SETTINGS_SUBMENU" "Configuración de %s1" "PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Un jugador)" @@ -46,16 +46,16 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo // mode settings "MODE_SETTING_CATEGORY_PILOT" "Piloto" "MODE_SETTING_CATEGORY_TITAN" "Titán" - "MODE_SETTING_CATEGORY_RIFF" "Riffs" + "MODE_SETTING_CATEGORY_RIFF" "Fragmento" "MODE_SETTING_CATEGORY_MATCH" "Partida" "classic_mp" "Multijugador Clasico" "run_epilogue" "Habilitar Epílogo" "scorelimit" "Limite de puntuación" - "roundscorelimit" "Puntaje limite (rondas)" - "timelimit" "Tiempo limite" - "roundtimelimit" "Tiempo limite (rondas)" - "respawnprotection" "Tiempo de proteccion en reaparición" + "roundscorelimit" "Límite de punataje (rondas)" + "timelimit" "Límite de tiempo" + "roundtimelimit" "Límite de tiempo (rondas)" + "respawnprotection" "Tiempo de protección en reaparición" "pilot_health_multiplier" "Multiplicador de salúd" "respawn_delay" "Retraso de aparición" @@ -73,7 +73,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "featured_mode_all_grapple" "Ataque a los titanes" "featured_mode_all_phase" "El otro lado" "featured_mode_all_ticks" "Picante" - "featured_mode_tactikill" "Eliminación tactica" + "featured_mode_tactikill" "Eliminación con tactica" "featured_mode_amped_tacticals" "Tacticas mejoradas" "featured_mode_rocket_arena" "Arena de cohetes" "featured_mode_shotguns_snipers" "Armado y peligroso" @@ -85,11 +85,11 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "aitdm_archer_grunts" "Soldado Archer" // northstar.custom localisation is just deciding not to work, so putting it here for now - "PL_sbox" "Sandbox" - "PL_sbox_lobby" "Vestíbulo de Sandbox" - "PL_sbox_desc" "como gmod pero peor" + "PL_sbox" "Custom" + "PL_sbox_lobby" "Vestíbulo de juego abierto" + "PL_sbox_desc" "Como \"gmod\" pero peor" "PL_sbox_abbr" "SBOX" - "GAMEMODE_SBOX" "Sandbox" + "GAMEMODE_SBOX" "CUstom" "PL_gg" "Carrera armamentística" "PL_gg_lobby" "Vestíbulo de Carrera armamentística" @@ -103,37 +103,37 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PL_tt" "Titan Tag" "PL_tt_lobby" "Vestíbulo de Titan Tag" - "PL_tt_desc" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo." - "PL_tt_hint" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo." + "PL_tt_desc" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo." + "PL_tt_hint" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo." "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan Tag" "PL_chamber" "Uno en la recamara" "PL_chamber_lobby" "Vestíbulo de uno en la recamara" - "PL_chamber_desc" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien." - "PL_chamber_hint" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien." - "PL_chamber_abbr" "CHAMBER" - "GAMEMODE_CHAMBER" "Uno en la recamara" + "PL_chamber_desc" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien." + "PL_chamber_hint" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien." + "PL_chamber_abbr" "RECÁMARA" + "GAMEMODE_CHAMBER" "Uno en la recámara" "PL_hidden" "El escondido" "PL_hidden_lobby" "Vestíbulo de El escondido" "PL_hidden_desc" "Un jugador es invisible. El escondido caza." "PL_hidden_hint" "Un jugador es invisible. El escondido caza." - "PL_hidden_abbr" "HIDDEN" + "PL_hidden_abbr" "OCULTO" "GAMEMODE_HIDDEN" "El escondido" - "HIDDEN_YOU_ARE_HIDDEN" "Eres el escondido!" + "HIDDEN_YOU_ARE_HIDDEN" "¡Eres el escondido!" "HIDDEN_KILL_SURVIVORS" "Mata a todos los supervivientes." "HIDDEN_FIRST_HIDDEN" "%s1 es El Escondido." - "PL_sns" "Piedras y palos" - "PL_sns_lobby" "Vestíbulo de Piedras y palos" + "PL_sns" "Palos y Piedras" + "PL_sns_lobby" "Vestíbulo de Palos y Piedras" "PL_sns_desc" "Todos contra todos. Usa cuchillas de pulso y ejecucciones para reestablecer el puntaje del enemigo" "PL_sns_abbr" "SNS" - "GAMEMODE_SNS" "Piedras y palos" + "GAMEMODE_SNS" "Palos y Piedras" "SCOREBOARD_BANKRUPTS" "Eliminaciones de bancarrota" - "SNS_LEADER_BANKRUPT" "Lider de puntaje en bancarrota!" - "SNS_LEADER_BANKRUPT_SUB" "%s1 Fue reseteado por %s2" - "SNS_BANKRUPT" "Arruinado!" + "SNS_LEADER_BANKRUPT" "¡Lider de puntaje en bancarrota!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 fue reseteado por %s2" + "SNS_BANKRUPT" "¡Arruinado!" "SNS_BANKRUPT_SUB" "Tu puntaje fue reseteado por %s1" "sns_wme_kill_value" "Valor por eliminacion con Wingman Elite" "sns_softball_kill_value" "Valor por eliminacion con Softball" @@ -152,7 +152,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "INFECTION_YOU_ARE_INFECTED" "Has sido infectado!" "INFECTION_KILL_SURVIVORS" "Infecta a todos los supervivientes restantes." "INFECTION_FIRST_INFECTED" "%s1 es el primer Infectado." - "INFECTION_LAST_SURVIVOR" "%s1 es el ultimo superviviente!" + "INFECTION_LAST_SURVIVOR" "¡%s1 es el ultimo superviviente!" "INFECTION_KILL_LAST_SURVIVOR" "Infectalo antes de que el tiempo se acabe!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "Eres el ultimo superviviente!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sobrevive." @@ -186,7 +186,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "GAMEMODE_fw" "Guerra fronteriza" "PL_fw" "Guerra fronteriza" "PL_fw_lobby" "Vestíbulo de Guerra fronteriza" - "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo." + "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo" "PL_fw_abbr" "FW" "GAMEMODE_kr" "Carrera por muertes" @@ -205,8 +205,8 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "KR_YOUR_KILLRACE_OVER" "Tu carrera ha acabado" "KR_YOUR_KILLRACE_SCORE" "Has obtenido %s1 bajas." - "GAMEMODE_fastball" "Fastball" - "PL_fastball" "Fastball" + "GAMEMODE_fastball" "Lanzamiento" + "PL_fastball" "Lanzamiento" "PL_fastball_lobby" "Vestíbulo de Fastball" "PL_fastball_desc" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo." "PL_fastball_hint" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo." @@ -263,7 +263,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "SP_BEACON_CLASSIC_DESC" "Cooper y BT intentan contactar con lo que queda de la flota para alertar de los planes de IMC." "SP_TDAY" "Prueba de fuego" - "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca." + "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca" "SP_S2S" "El Arca" "SP_S2S_CLASSIC_DESC" "Cooper y BT van de nave en nave en busca del Arca." @@ -284,7 +284,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "HIDE_EMPTY_FILTER" "Esconder servidores vacios" "HIDE_PROT_FILTER" "Esconder servidores protegidos" "SERVER_DESCRIPTION" "Descripción" - "SERVER_MODS" "Mods" + "SERVER_MODS" "Modificaciones" "CLEAR_FILTERS" "LIMPIAR" "JOIN_BUTTON" "UNIR" @@ -318,6 +318,39 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PLAYER_NOT_FOUND" "No se encontró la cuenta del jugador" "INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido" "JSON_PARSE_ERROR" "Error procesando respuesta json" - "UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada" + "UNSUPPORTED_VERSION" "La versión que estás usando ya no está siendo mantenida" + "MATCH_COUNTDOWN_LENGTH" "Duración cronometrada de la partida privada" + "ONLY_HOST_MATCH_SETTINGS" "Sólo el anfitrión puede cambiar las configuraciones de la partida" + "ONLY_HOST_CAN_START_MATCH" "Sólo el anfitrión puede iniciar la partida" + "DISALLOWED_WEAPONS" "Armas prohibidas" + "REPLACEMENT_WEAPON" "Arma de reemplazo" + "MOD_SETTINGS" "Configuración de Mods" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar comandos no reconocidos desde el cliente" + "DISALLOWED_TACTICALS" "Tácticas prohibidas" + "TACTICAL_REPLACEMENT" "Reemplazo de la táctica" + "SHOULD_RETURN_TO_LOBBY" "Regresar a la sala de espera después de la partida" + "ARE_YOU_SURE" "¿Segur@?" + "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las opciones de ésta categoría.\n\nNo se podrá revertir el proceso." + "NORTHSTAR_BASE_SETTINGS" "Opciones de Northstar por defecto" + "NO_RESULTS" "No hay resultados." + "MOD_SETTINGS_RESET" "Reiniciar" + "SHOW_ONLY_NOT_REQUIRED" "Mostrar sólo mods opcionales" + "SHOW_ONLY_REQUIRED" "Mostrar sólo mods obligatorios" + "NO_MODS" "¡No hay configuraciones disponibles! Instala más mods desde ^5588FF00northstar.thunderstore.io^0." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "¿Habilitar progreso?" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "¿Deshabilitar progresión?" + "PROGRESSION_ENABLED_HEADER" "¡Progreso habilitado!" + "PROGRESSION_DISABLED_HEADER" "¡Progreso deshabilitado!" + "TOGGLE_PROGRESSION" "Cambiar modo de progresión" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Cambiar modo de progresión" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados sólo al subir de nivel, o a través de Logros.\n\nÉsta opción puede ser cambiada cuando quieras en la sala de espera.\n\n^CC000000Advertencia: ¡Cualquier equipamiento o utensilio será reiniciado si no lo tienes desbloqueado!" + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET_ALL" "Reiniciar completamente" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Los Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados y permanecerán utilizables.\n\nÉsta opción puede ser cambiada cuando quieras desde la sala de espera." + "PROGRESSION_ENABLED_BODY" "^CCCC0000El modo de progreso ha sido habilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros se desbloquearán al subir de nivel o por Logros.\n\nPuedes cambiar ésta opción cuando quieras en la sala de espera." + "PROGRESSION_DISABLED_BODY" "^CCCC0000El modo de progreso ha sido deshabilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros están desbloqueados y puedes utilizarlos cuando quieras.\n\nPuedes cambiar ésta opción cuando quieras desde la sala de espera." + "WILL_RESET_SETTING" "Ésta acción reiniciará %s1 a su valor por defecto.\n\nNo se podrá revertir el proceso." + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000El progreso puede ser habilitado desde ahora^\n\nNorthstar ahora es compatible con el progreso normal del juego, esto significa que puedes elegir desbloquear Armas, Aspectos, Titanes y otros a través de desafíos y subiendo de nivel.\n\nPuedes habilitar el progreso normal del juego en la opción ubicada al final de la pantalla de la sala de espera.\n\nÉsta opción puede ser cambiada en cualquier momento." + "player_force_respawn" "Reaparición Forzada" } } -- cgit v1.2.3 From afdadc6f897df342f882e0f98b2fccaa9e140289 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:58:00 +0200 Subject: Translations update from Weblate (#712) Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/zh_Hant/ Co-authored-by: zxcPandora <81985226+zxcPandora@users.noreply.github.com> --- .../mod/resource/northstar_client_localisation_tchinese.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index e543f711..003ca28a 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -344,5 +344,17 @@ "REPLACEMENT_WEAPON" "替换的武器" "WILL_RESET_ALL_SETTINGS" "這將會重置所有屬於改條目的設置.\n\n此操作不可復原." "NO_MODS" "無可用模組! 前往 ^5588FF00northstar.thunderstore.io^0 下載更多." + "player_force_respawn" "強制重生" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "啟用個人進度?" + "PROGRESSION_ENABLED_HEADER" "個人進度已開啟!" + "PROGRESSION_TOGGLE_DISABLED_BODY" "泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。\n\n^CC000000警告:如果您已經裝備了尚未解鎖的物品,它們將會被重置!" + "PROGRESSION_TOGGLE_ENABLED_BODY" "泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品都將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" + "TOGGLE_PROGRESSION" "遊戲進度" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% 遊戲進度" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "停用個人進度?" + "PROGRESSION_DISABLED_HEADER" "個人進度已關閉!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000個人進度已停用^\n\n泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" + "PROGRESSION_ENABLED_BODY" "^CCCC0000個人進度已啟用^\n\n泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000現在可以隨時開啟個人進度!^\n\nNorthstar 現在支持類似官服的進度系統, 这意味着你可以选择通过升级和完成挑战来解锁武器、皮肤、泰坦等。\n\n您可以通過多人大廳底部的“遊戲進度”按鈕來進行開啟。\n\n您可以隨時在多人大廳中更改此項。" } } -- cgit v1.2.3 From 9864becc72543206f2d2b1305aed7041b81e1c4b Mon Sep 17 00:00:00 2001 From: EnderBoy9217 <122132914+EnderBoy9217@users.noreply.github.com> Date: Tue, 3 Oct 2023 18:02:03 -0400 Subject: Fix integer functionality for modsettings (#718) Add missing break statement --- Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut | 1 + 1 file changed, 1 insertion(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut index a45082c7..8c13955c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut @@ -949,6 +949,7 @@ void function SendTextPanelChanges( var textPanel ) ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." ) Hud_SetText( textPanel, GetConVarString( c.conVar ) ) } + break case "bool": if ( newSetting != "0" && newSetting != "1" ) { -- cgit v1.2.3 From 0dda99e77f9f1d7724a2fec11b4fab48b2f62456 Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 4 Oct 2023 00:31:55 +0200 Subject: Add chatroom.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/chatroom.nut | 902 +++++++++++++++++++++ 1 file changed, 902 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut new file mode 100644 index 00000000..b474f7a6 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut @@ -0,0 +1,902 @@ +untyped + +global function Chatroom_GlobalInit +global function InitChatroom +global function UpdateChatroomUI +global function UICodeCallback_ShowUserInfo +global function UICodeCallback_RemoteMatchInfoUpdated +global function UICodeCallback_SetChatroomMode +global function UpdateOpenInvites +global function HideOpenInvite +global function ShowOpenInvite +global function FillInUserInfoPanel +global function UpdateChatroomThread +global function IsVoiceChatPushToTalk + +global function bsupdate + +global const LOBBY_MATERIAL_OWNER = $"rui/menu/common/lobby_icon_owner" +global const LOBBY_MATERIAL_ADMIN = $"rui/menu/common/lobby_icon_admin" + +struct RemoteMatchPlayerInfoRow +{ + var playerPanel + var name + var score + var kills + var deaths +} + +struct RemoteMatchInfoPanel +{ + var panel + var PlaylistName + var MapName + var ModeName + var TimeLeft + var ScoreLimit + var Team1Score + var Team2Score + array team1Players + array team2Players +} + +struct OpenInviteUI +{ + var openInviteJoinButton + var openInvitePanel + var openInviteMessage + var openInviteCountdownText + array openInvitePlayerSlots + array openInvitePlaylistSlots +} + +global struct UserInfoPanel +{ + var Panel + var Name + var Kills + var Wins + var Losses + var Deaths + var XP + var callsignCard + array communityLabels + array communityNames +} + +struct ChatroomWidget +{ + var chatroomPanel + var chatroomWidget + var chatroomTextChat + + var chatroomBackground + var chatroomDivider + var chatroomHappyHour + var chatroomMode + + UserInfoPanel userInfoPanel + + RemoteMatchInfoPanel remoteMatchInfoPanelWidgets + + var communityChatroomModeButton + var chatroomHintText + var happyHourTimeLeft + + OpenInviteUI openInviteUI +} + +struct +{ + string userInfoPanel_hardware = "" + string userInfoPanel_userId = "0" + var communityChatroomMode + bool currentUserIsStreaming = false + array chatroomUIs + bool hasFocus +} file + +bool function IsVoiceChatPushToTalk() +{ + if ( GetPartySize() > 1 ) + return true + return DoesCurrentCommunitySupportChat() +} + +void function UICodeCallback_SetChatroomMode( string mode ) +{ + file.communityChatroomMode = mode + UpdateChatroomUI() +} + +void function UpdateChatroomUI() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + if ( file.communityChatroomMode == "chatroom" ) + { + int communityId = GetCurrentCommunityId() + CommunitySettings ornull communitySettings = GetCommunitySettings( communityId ) + + string communityName + if ( communitySettings != null ) + { + expect CommunitySettings( communitySettings ) + communityName = GetCurrentCommunityName() + " [" + communitySettings.clanTag + "]" + } + else + { + communityName = expect string( GetCurrentCommunityName() ) + } + + if ( IsChatroomMuted() ) + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM_MUTED", communityName ) ) + else + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM", communityName ) ) + } + else if ( file.communityChatroomMode == "party" ) + { + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_PARTY", GetPartyLeaderName() ) ) + } + else + { + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( file.communityChatroomMode ) ) + } + + int meritsLeft = GetHappyHourMeritsLeft() + if ( meritsLeft == 0 ) + { + SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( "#HAPPYHOUR_NOMERITSLEFT", meritsLeft ) ) + SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", "" ) + //SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_ACTIVE_01" ) ) + } + else if ( meritsLeft >= 1 ) + { + SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( GetHappyHourStatus() ) ) + SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_MERITS", 5 ) ) + } + UICodeCallback_ShowUserInfo( file.userInfoPanel_hardware, file.userInfoPanel_userId ) + } + + UpdateFooterOptions() +} + +bool function FillInCommunityMembership( UserInfoPanel userInfoPanel, CommunityMembership membershipData, int communityIndex ) +{ + if ( userInfoPanel.communityNames.len() <= communityIndex ) + return false; + + string title + title = "[" + membershipData.communityClantag + "] " + Localize( membershipData.communityName ); + + if ( membershipData.membershipLevel == "owner" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_OWNER" ) + else if ( membershipData.membershipLevel == "admin" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_ADMIN" ) + else if ( membershipData.membershipLevel == "member" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_MEMBER" ) + else + Assert( false, "Unknown membership level " + membershipData.membershipLevel + " in FillInCommunityMembership" ) + + Hud_SetText( userInfoPanel.communityNames[communityIndex], title ) + Hud_Show( userInfoPanel.communityLabels[communityIndex] ); + Hud_Show( userInfoPanel.communityNames[communityIndex] ); + + return true +} + +void function FillInUserInfoPanel( UserInfoPanel userInfoPanel, CommunityUserInfo userInfo ) +{ + file.currentUserIsStreaming = userInfo.isLivestreaming + + Hud_SetText( userInfoPanel.Name, userInfo.name ) + string killsText = "" + userInfo.kills + Hud_SetText( userInfoPanel.Kills, killsText ) + string winsText = "" + userInfo.wins + Hud_SetText( userInfoPanel.Wins, winsText ) + string lossesText = "" + userInfo.losses + Hud_SetText( userInfoPanel.Losses, lossesText ) + string deathsText = "" + userInfo.deaths + Hud_SetText( userInfoPanel.Deaths, deathsText ) + string xpText = ShortenNumber( userInfo.xp ) + Hud_EnableKeyBindingIcons( userInfoPanel.XP ) + Hud_SetText( userInfoPanel.XP, Localize( "#CREDITSIGN_N", xpText ) ) + + CallingCard callingCard = CallingCard_GetByIndex( userInfo.callingCardIdx ) + CallsignIcon callsignIcon = CallsignIcon_GetByIndex( userInfo.callSignIdx ) + + var card = userInfoPanel.callsignCard + var rui = Hud_GetRui( userInfoPanel.callsignCard ) + RuiSetImage( rui, "cardImage", callingCard.image ) + RuiSetImage( rui, "iconImage", callsignIcon.image ) + RuiSetInt( rui, "layoutType", callingCard.layoutType ) + RuiSetImage( rui, "cardGenImage", GetGenIcon( userInfo.gen, userInfo.lvl ) ) + RuiSetString( rui, "playerLevel", PlayerXPDisplayGenAndLevel( userInfo.gen, userInfo.lvl ) ) + RuiSetString( rui, "playerName", userInfo.name ) + + array ownerCommunities + array adminCommunities + array memberCommunities + + for ( int i = 0; i < userInfo.numCommunities; i++ ) + { + CommunityMembership ornull communityInfo = GetCommunityUserMembershipInfo( userInfo.hardware, userInfo.uid, i ) + if ( !communityInfo ) + continue; + expect CommunityMembership( communityInfo ) + string membershipLevel = communityInfo.membershipLevel + if ( membershipLevel == "owner" ) + { + ownerCommunities.append( communityInfo ) + } + else if ( membershipLevel == "admin" ) + { + adminCommunities.append( communityInfo ) + } + else if ( membershipLevel == "member" ) + { + memberCommunities.append( communityInfo ) + } + else + { + printt( "Unknown membershipLevel " + membershipLevel ) + Assert( false, "Unknown membershipLevel" ) + } + } + + array allCommunities + for ( int i = 0; i < ownerCommunities.len(); i++ ) + allCommunities.append( ownerCommunities[i] ) + for ( int i = 0; i < adminCommunities.len(); i++ ) + allCommunities.append( adminCommunities[i] ) + for ( int i = 0; i < memberCommunities.len(); i++ ) + allCommunities.append( memberCommunities[i] ) + + int currentCommunityIndex = 0 + for ( ; currentCommunityIndex < allCommunities.len(); currentCommunityIndex++ ) + { + if ( !FillInCommunityMembership( userInfoPanel, allCommunities[currentCommunityIndex], currentCommunityIndex ) ) + break; + } + + for ( ; currentCommunityIndex < userInfoPanel.communityNames.len(); currentCommunityIndex++ ) + { + Hud_Hide( userInfoPanel.communityLabels[currentCommunityIndex] ); + Hud_Hide( userInfoPanel.communityNames[currentCommunityIndex] ); + } + + UpdateFooterOptions() +} + +void function GetUserInfoThread( string hardware, string userId ) +{ + EndSignal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + + printt( "getting userinfo for user " + userId ) + + CommunityUserInfo fakeSettings + fakeSettings.name = Localize( "#COMMUNITY_FETCHING" ) + foreach ( chatroomUI in file.chatroomUIs ) + FillInUserInfoPanel( chatroomUI.userInfoPanel, fakeSettings ) + + while ( true ) + { + printt( "asking for userinfo for " + hardware + "=" + userId ) + + CommunityUserInfo ornull userInfo = GetCommunityUserInfo( hardware, userId ) + if ( !userInfo ) + { + wait 0.05 + } + else + { + printt( "Got user info for user " + userId + " on hardware " + hardware ) + expect CommunityUserInfo( userInfo ) + + printt( "User " + userId + " is in " + userInfo.numCommunities + " communities" ) + + foreach ( chatroomUI in file.chatroomUIs ) + FillInUserInfoPanel( chatroomUI.userInfoPanel, userInfo ) + break + } + } +} + + +void function UICodeCallback_ShowUserInfo( string hardware, string userId ) +{ + Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + + printt( "Showing user info for UID " + userId + " on hardware " + hardware ) + + file.userInfoPanel_userId = userId + file.userInfoPanel_hardware = hardware + + if ( hardware == "" && userId == "0" ) + { + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.userInfoPanel.Panel ) + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatrooUI.chatroomHeader, Hud_GetBaseWidth( chatrooUI.chatroomHeader ) ) + // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) ) + #if CONSOLE_PROG + Hud_Show( chatroomUI.chatroomHintText ) + #else + Hud_Show( chatroomUI.chatroomTextChat ) + #endif + } + } + else + { + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Show( chatroomUI.userInfoPanel.Panel ) + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + Hud_Hide( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatroomUI.chatroomHeader, Hud_GetBaseWidth( chatroomUI.chatroomHeader ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + #if CONSOLE_PROG + Hud_Hide( chatroomUI.chatroomHintText ) + #else + Hud_Hide( chatroomUI.chatroomTextChat ) + #endif + } + + thread GetUserInfoThread( hardware, userId ) + } +} + +void function FindRemoteMatchInfoWidgetsInPanel( RemoteMatchInfoPanel infostruct, var panel ) +{ + infostruct.PlaylistName = Hud_GetChild( panel, "PlaylistName" ) + infostruct.MapName = Hud_GetChild( panel, "MapName" ) + infostruct.ModeName = Hud_GetChild( panel, "ModeName" ) + infostruct.TimeLeft = Hud_GetChild( panel, "TimeLeft" ) + infostruct.ScoreLimit = Hud_GetChild( panel, "ScoreLimit" ) + infostruct.Team1Score = Hud_GetChild( panel, "Team1Score" ) + infostruct.Team2Score = Hud_GetChild( panel, "Team2Score" ) + for ( int i = 1; i <= 2; i++ ) + { + array teamPlayers + if ( i == 1 ) + teamPlayers = infostruct.team1Players + else + teamPlayers = infostruct.team2Players + + for ( int j = 1; j <= 8; j++ ) + { + RemoteMatchPlayerInfoRow teamPlayer + string key = "Team" + i + "Player" + j + teamPlayer.playerPanel = Hud_GetChild( panel, key ) + teamPlayer.name = Hud_GetChild( teamPlayer.playerPanel, "Name" ) + teamPlayer.score = Hud_GetChild( teamPlayer.playerPanel, "Score" ) + teamPlayer.kills = Hud_GetChild( teamPlayer.playerPanel, "Kills" ) + teamPlayer.deaths = Hud_GetChild( teamPlayer.playerPanel, "Deaths" ) + teamPlayers.append( teamPlayer ) + } + } +} + +int function RemoteMatchInfoPlayerSort( RemoteClientInfoFromMatchInfo a, RemoteClientInfoFromMatchInfo b ) +{ + return ( b.score - a.score ) +} + +void function FillInRemoteMatchInfoPanel( RemoteMatchInfo info, RemoteMatchInfoPanel panel ) +{ + Hud_Show( panel.panel ) + + Hud_SetText( panel.PlaylistName, GetPlaylistDisplayName( info.playlist ) ) + Hud_SetText( panel.MapName, Localize( "#" + info.map ) ) + + string modeName + + if ( IsFDMode( info.gamemode ) ) + { + modeName = "#GAMEMODE_COOP" + // HACK because fd has multiple gamemodes in playlists + } + else + { + modeName = GAMETYPE_TEXT[ info.gamemode ] + } + + if ( IsFullyConnected() ) + modeName = GetGameModeDisplayName( info.gamemode ) + + Hud_SetText( panel.ModeName, modeName ) + int minsLeft = info.timeLeftSecs / 60 + int secsLeft = info.timeLeftSecs % 60 + string timeLeft = "" + minsLeft + if ( secsLeft < 10 ) + timeLeft = timeLeft + ":0" + secsLeft + else + timeLeft = timeLeft + ":" + secsLeft + Hud_SetText( panel.TimeLeft, timeLeft ) + string scoreLimit = "" + info.maxScore + Hud_SetText( panel.ScoreLimit, scoreLimit ) + string imcScore = "" + info.teamScores[TEAM_IMC] + string milScore = "" + info.teamScores[TEAM_MILITIA] + Hud_SetText( panel.Team1Score, imcScore ) + Hud_SetText( panel.Team2Score, milScore ) + + int team1PlayerCount = 0 + int team2PlayerCount = 0 + + info.clients.sort( RemoteMatchInfoPlayerSort ) + + for ( int i = 0; i < info.clients.len(); i++ ) + { + RemoteMatchPlayerInfoRow teamPlayer + if ( info.clients[i].teamNum == TEAM_IMC ) + { + if ( team1PlayerCount >= panel.team1Players.len() ) + { + printt( "too many team players" ) + continue + } + + teamPlayer = panel.team1Players[team1PlayerCount] + team1PlayerCount++ + } + else if ( info.clients[i].teamNum == TEAM_MILITIA ) + { + if ( team2PlayerCount >= panel.team2Players.len() ) + { + printt( "too many team players" ) + continue + } + + teamPlayer = panel.team2Players[team2PlayerCount] + team2PlayerCount++ + } + else + { + printt( "Unhandled player team " + info.clients[i].teamNum ) + continue + } + string score = "" + info.clients[i].score + string kills = "" + info.clients[i].kills + string deaths = "" + info.clients[i].deaths + + Hud_Hide( teamPlayer.playerPanel ) // not enough room for these + Hud_SetText( teamPlayer.name, info.clients[i].name ) + Hud_SetText( teamPlayer.score, score ) + Hud_SetText( teamPlayer.kills, kills ) + Hud_SetText( teamPlayer.deaths, deaths ) + } + for ( int i = team1PlayerCount; i < panel.team1Players.len(); i++ ) + Hud_Hide( panel.team1Players[i].playerPanel ) + for ( int i = team2PlayerCount; i < panel.team2Players.len(); i++ ) + Hud_Hide( panel.team2Players[i].playerPanel ) + +} + +void function RemoteMatchInfoVisibilityThread() +{ + EndSignal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" ) + wait 2 + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.remoteMatchInfoPanelWidgets.panel ) +} + +void function UICodeCallback_RemoteMatchInfoUpdated() +{ + printt( "Remote Match Info Updated!" ) + + RemoteMatchInfo info = GetRemoteMatchInfo() + foreach ( chatroomUI in file.chatroomUIs ) + FillInRemoteMatchInfoPanel( info, chatroomUI.remoteMatchInfoPanelWidgets ) + + Signal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" ) + thread RemoteMatchInfoVisibilityThread() +} + +void function Chatroom_GlobalInit() +{ + RegisterSignal( "StopRemoteMatchInfoThread" ) +} + +bool function IsSelectedUserStreaming() +{ + if ( !ChatroomHasFocus() ) + return false + return file.currentUserIsStreaming +} + +void function InitChatroom( var parentMenu ) +{ + RegisterSignal( "StopUserInfoLookups" ) + + file.communityChatroomMode = "chatroom" + + var menu = Hud_GetChild( parentMenu, "ChatroomPanel" ) + + ChatroomWidget chatroomUI + file.chatroomUIs.append( chatroomUI ) + + chatroomUI.chatroomPanel = menu + chatroomUI.chatroomWidget = Hud_GetChild( menu, "ChatRoom" ) + chatroomUI.chatroomTextChat = Hud_GetChild( menu, "ChatRoomTextChat" ) + chatroomUI.chatroomBackground = Hud_GetChild( menu, "ChatbarBackground" ) + chatroomUI.chatroomDivider = Hud_GetChild( menu, "ChatroomHeaderBackground" ) + chatroomUI.chatroomHappyHour = Hud_GetChild( menu, "HappyHourTimeLeft" ) + chatroomUI.chatroomMode = Hud_GetChild( menu, "CommunityChatRoomMode" ) + + var remoteMatchInfoPanel = Hud_GetChild( parentMenu, "MatchDetails" ) + chatroomUI.remoteMatchInfoPanelWidgets.panel = remoteMatchInfoPanel + FindRemoteMatchInfoWidgetsInPanel( chatroomUI.remoteMatchInfoPanelWidgets, remoteMatchInfoPanel ) + + chatroomUI.userInfoPanel.Panel = Hud_GetChild( parentMenu, "UserInfo" ) + chatroomUI.userInfoPanel.Name = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Name" ) + chatroomUI.userInfoPanel.Kills = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Kills" ) + chatroomUI.userInfoPanel.Wins = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Wins" ) + chatroomUI.userInfoPanel.Losses = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Losses" ) + chatroomUI.userInfoPanel.Deaths = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Deaths" ) + chatroomUI.userInfoPanel.XP = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "XP" ) + chatroomUI.userInfoPanel.callsignCard = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "CallsignCard" ) + + // chatroomUI.userInfoPanel.ViewUserCardButton = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "ViewUserCard" ) + + for ( int i = 0; i < 6; i++ ) + { + if ( !Hud_HasChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" ) ) + break; + var communityLabel = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" ) + var communityName = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i ) + Assert( communityName, "found Community" + i + "Label, but no Community" + i + " in userInfo panel" ); + chatroomUI.userInfoPanel.communityLabels.append( communityLabel ) + chatroomUI.userInfoPanel.communityNames.append( communityName ) + } + + chatroomUI.communityChatroomModeButton = Hud_GetChild( menu, "CommunityChatRoomMode" ) +#if CONSOLE_PROG + chatroomUI.chatroomHintText = Hud_GetChild( menu, "TextChatHintForConsole" ) +#endif + chatroomUI.happyHourTimeLeft = Hud_GetChild( menu, "HappyHourTimeLeft" ) + // Hud_EnableKeyBindingIcons( chatroomUI.communityChatroomModeButton ) + + OpenInviteUI openInviteUI = chatroomUI.openInviteUI + openInviteUI.openInvitePanel = Hud_GetChild( parentMenu, "OpenInvitePanel" ) + openInviteUI.openInviteMessage = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteMessage" ) + openInviteUI.openInviteCountdownText = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteCountdownText" ) + + var openInviteBackground = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteBox" ) + RuiSetColorAlpha( Hud_GetRui( openInviteBackground ), "backgroundColor", <0, 0, 0>, 0.9 ) + + int i = 0; + while ( i < 8 ) + { + int count = i + 1 + var widget = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInvitePlayer" + count ) + if ( !widget ) + break + openInviteUI.openInvitePlayerSlots.append( widget ) + i++ + } + for ( int idx = 0; idx < 9; ++idx ) + { + string widgetName = ("OpenInvitePlaylist" + format( "%02d", idx )) + var widget = Hud_GetChild( openInviteUI.openInvitePanel, widgetName ) + openInviteUI.openInvitePlaylistSlots.append( widget ) + i++ + } + + openInviteUI.openInviteJoinButton = Hud_GetChild( openInviteUI.openInvitePanel, "JoinOpenInviteButton" ) + Hud_EnableKeyBindingIcons( openInviteUI.openInviteJoinButton ) + + AddEventHandlerToButton( openInviteUI.openInvitePanel, "JoinOpenInviteButton", UIE_CLICK, JoinOpenInvite_OnClick ) + AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteCountdownText", UIE_CLICK, JoinOpenInvite_OnClick ) + AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteMessageButtonOverlay", UIE_CLICK, JoinOpenInvite_OnClick ) + + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_MUTEROOM", "#MUTEROOM", MuteRoom, ChatroomIsNotMuted ) + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_UNMUTEROOM", "#UNMUTEROOM", UnmuteRoom, ChatroomIsMuted ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_DESTROY_FOOTER", "#OPENINVITE_DESTROY", LeaveOpenInviteButton, CanDestroyOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_JOIN_FOOTER", "#OPENINVITE_JOIN", JoinOpenInvite, CanJoinOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_LEAVE_FOOTER", "#OPENINVITE_LEAVE", LeaveOpenInviteButton, CanLeaveOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_A, "#BUTTON_VIEW_PLAYER_PROFILE", "#MOUSE1_VIEW_PROFILE", null, IsChatroomViewProfileValid ) + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_RIGHT, "#COMMUNITY_RB_CHATROOM_VIEWSTREAM", "#COMMUNITY_CHATROOM_VIEWSTREAM", null, IsSelectedUserStreaming ) + AddMenuFooterOption( parentMenu, BUTTON_X, "#BUTTON_MUTE", "#MOUSE2_MUTE", null, ChatroomHasFocus ) + + UpdateChatroomUI() + + Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_LOSE_FOCUS, LostFocus ) + Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_GET_FOCUS, GotFocus ) +} + +void function bsupdate() +{ + ShowOpenInvite() + + OpenInvite openInvite + openInvite.amILeader = false + openInvite.amIInThis = false + openInvite.numSlots = 5 + openInvite.numClaimedSlots = 1 + + string inviteString = openInvite.amILeader ? "#OPENINVITE_SENDER_PLAYLIST" : "#OPENINVITE_PLAYLIST" + + float endTime = Time() + 10.0 + while ( Time() < endTime ) + { + openInvite.timeLeft = endTime - Time() + + int remainingTime = int( ceil( endTime - Time() ) ) + UpdateOpenInvites( openInvite, inviteString, "scriptacus", "Bounty Hunt", remainingTime ) + + if ( remainingTime == 8 ) + openInvite.numClaimedSlots = 2 + + if ( remainingTime == 6 ) + openInvite.numClaimedSlots = 4 + + //if ( remainingTime == 5 ) + // openInvite.numClaimedSlots = 5 + // + //if ( remainingTime == 4 ) + // openInvite.numClaimedSlots = 6 + + WaitFrame() + } +} + +void function UpdateOpenInvites( OpenInvite openInvite, string message, string param1, string ornull param2, int countdown ) +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + if ( param2 ) + Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1, param2 ); + else + Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1 ); + + string countdownText = "" + countdown +// Hud_SetText( chatroomUI.openInviteUI.openInviteCountdownText, "#OPENINVITE_COUNTDOWN", countdownText ) + var countdownRui = Hud_GetRui( chatroomUI.openInviteUI.openInviteCountdownText ) + RuiSetFloat( countdownRui, "timeLeft", openInvite.timeLeft ) + RuiSetFloat( countdownRui, "maxTime", GetConVarFloat( "openinvite_duration_default" ) ) + + bool started = openInvite.timeLeft <= 0 || openInvite.numFreeSlots == 0 + + if ( started ) + { + Hud_Hide( chatroomUI.openInviteUI.openInviteJoinButton ) + } + else if ( CanDestroyOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_DESTROY" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_DESTROY" ) + } + else if ( CanLeaveOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_LEAVE" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_LEAVE" ) + } + else if ( CanJoinOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_JOIN" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_JOIN" ) + } + + string myUID = GetPlayerUID() + int i = 0 + foreach ( player in chatroomUI.openInviteUI.openInvitePlayerSlots ) + { + var rui = Hud_GetRui( player ) + Hud_Show( player ) + + if ( i >= openInvite.numSlots ) + { + //Hud_Hide( player ) + RuiSetBool( rui, "isEnabled", false ) + RuiSetBool( rui, "hasPlayer", false ) + } + else + { + CallsignIcon callsignIcon + bool isMe = false + // asset playerImage + + if ( i < openInvite.numClaimedSlots ) + { + PartyMember member = openInvite.members[i] + isMe = ( member.uid == myUID ) + if ( isMe ) + { + if ( GetUIPlayer() != null ) // this can happen sometimes after a resolution/windowed mode change + callsignIcon = PlayerCallsignIcon_GetActive( GetUIPlayer() ) + else + callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" ) + } + else + { + callsignIcon = CallsignIcon_GetByIndex( member.callsignIdx ) + } + } + else + { + callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" ) + } + + Hud_Show( player ) + RuiSetBool( rui, "isEnabled", true ) + + RuiSetBool( rui, "hasPlayer", i < openInvite.numClaimedSlots ) + RuiSetBool( rui, "isViewPlayer", isMe ) + RuiSetImage( rui, "playerImage", callsignIcon.image ) + + //if ( i < openInvite.numClaimedSlots ) + // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_occupiedslot" ) + //else + // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_emptyslot" ) + } + i++ + } + + array checklistPlaylists = GetChecklistPlaylistsArray() + + if ( Lobby_IsFDMode() ) + checklistPlaylists = GetFDDifficultyArray() + + array invitePlaylists = split( openInvite.playlistName, "," ) + bool shouldShowCheckboxPlaylists = true + if ( !MixtapeMatchmakingIsEnabled() ) + shouldShowCheckboxPlaylists = false + else if ( invitePlaylists.len() == 0 ) + shouldShowCheckboxPlaylists = false + else if ( (invitePlaylists.len() == 1) && (!checklistPlaylists.contains( invitePlaylists[0] )) ) + shouldShowCheckboxPlaylists = false + + int playlistSlotCount = chatroomUI.openInviteUI.openInvitePlaylistSlots.len() + for( int idx = 0; idx < playlistSlotCount; ++idx ) + { + var slot = chatroomUI.openInviteUI.openInvitePlaylistSlots[idx] + + string thisPlaylistName = idx < checklistPlaylists.len() ? checklistPlaylists[idx] : "" + if ( (thisPlaylistName == "") || !shouldShowCheckboxPlaylists ) + { + Hud_Hide( slot ) + continue + } + + Hud_Show( slot ) + var slotRui = Hud_GetRui( slot ) + asset playlistThumbnail = GetPlaylistThumbnailImage( thisPlaylistName ) + RuiSetImage( slotRui, "checkImage", playlistThumbnail ) + + bool isChecked = invitePlaylists.contains( thisPlaylistName ) + RuiSetBool( slotRui, "isChecked", isChecked ) + + string abbr = GetPlaylistVarOrUseValue( thisPlaylistName, "abbreviation", "" ) + RuiSetString( slotRui, "abbreviation", Localize( abbr ) ) + } + } +} + + +void function HideOpenInvite() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + Hud_Hide( chatroomUI.openInviteUI.openInvitePanel ) + } +} + +void function ShowOpenInvite() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + Hud_Show( chatroomUI.openInviteUI.openInvitePanel ) + } +} + + +void function LostFocus( panel ) +{ + Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + printt( "Chatroom lost focus" ) + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.userInfoPanel.Panel ) + file.hasFocus = false + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomTextChat ) + } +} + + +void function OnChatroomWidgetGetFocus( var widget ) +{ +} + +void function OnChatroomWidgetLoseFocus( var widget ) +{ +} + +void function GotFocus( panel ) +{ + printt( "Chatroom got focus" ) + file.hasFocus = true + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + Hud_Hide( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_Hide( chatroomUI.chatroomTextChat ) + } +} + +bool function IsChatroomViewProfileValid() +{ + #if PC_PROG + if ( !Origin_IsOverlayAvailable() ) + return false + #endif // PC_PROG + + return ChatroomHasFocus() +} + +bool function ChatroomHasFocus() +{ + return file.hasFocus +} + +bool function ChatroomIsMuted() +{ + if ( IsControllerModeActive() ) + return ChatroomHasFocus() && IsChatroomMuted() + return IsChatroomMuted() +} + +bool function ChatroomIsNotMuted() +{ + if ( IsControllerModeActive() ) + return ChatroomHasFocus() && !IsChatroomMuted() + return !IsChatroomMuted() +} + +void function MuteRoom( var button ) +{ + printt( "muting the room" ) + ClientCommand( "muteroom" ) +} + +void function UnmuteRoom( var button ) +{ + printt( "unmuting the room" ) + ClientCommand( "unmuteroom" ) +} + +void function UpdateChatroomThread() +{ + EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) + while ( true ) + { + UpdateChatroomUI() + wait 30 + } +} -- cgit v1.2.3 From 1226f7599fdfe63a08ee0fbc2b0e3e296f38f2da Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:37:35 +0100 Subject: Remove annoying recurring print from `chatroom.nut` (#676) Commented out instead of fully removing --- Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut index b474f7a6..4e98ee8a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut @@ -308,7 +308,7 @@ void function UICodeCallback_ShowUserInfo( string hardware, string userId ) { Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) - printt( "Showing user info for UID " + userId + " on hardware " + hardware ) + // printt( "Showing user info for UID " + userId + " on hardware " + hardware ) file.userInfoPanel_userId = userId file.userInfoPanel_hardware = hardware -- cgit v1.2.3 From e719d304d20f5f50948a6681b5f4088bbccd2b5d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:43:55 +0200 Subject: Bump mods version to `1.19.0` (#732) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 8040c14c..7d695a4b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 22f9c45f..93f371bd 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 8f5508c8..e6f2c4b7 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 15b3b65fc4e88fe98ba12b4d7603e396fba91fb3 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 7 Oct 2023 11:40:31 +0100 Subject: Display origin auth failure in a dialog (#648) Currently, we don't do anything with origin auth failure, meaning the next request just fails, and we get not particularly relevant error messages (player not found, invalid masterserver token) --- .github/nativefuncs.json | 6 +++ Northstar.Client/mod.json | 7 +++ .../northstar_client_localisation_english.txt | 5 ++ .../scripts/vscripts/cl_northstar_client_init.nut | 7 +++ .../mod/scripts/vscripts/ui/atlas_auth.nut | 56 ++++++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 6f46095f..13a7edd3 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -729,6 +729,12 @@ "helpText":"", "returnTypeString":"void", "argTypes":"struct presence" + }, + { + "name":"NSGetMasterServerAuthResult", + "helpText":"", + "returnTypeString":"MasterServerAuthResult", + "argTypes":"" } ] } \ No newline at end of file diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7d695a4b..f7c7c9b5 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -128,6 +128,13 @@ { "Path": "ui/ui_mouse_capture.nut", "RunOn": "UI" + }, + { + "Path": "ui/atlas_auth.nut", + "RunOn": "UI", + "UICallback": { + "After": "AtlasAuthDialog" + } } ], "Localisation": [ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 8c7bab3a..49e9ee43 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -322,6 +322,11 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" + + "AUTHENTICATION_FAILED_HEADER" "Authentication Failed" + "AUTHENTICATION_FAILED_BODY" "Failed to authenticate with Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Error code: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Help" // Mod Settings "MOD_SETTINGS" "Mod Settings" diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 2a2ed3db..a844478a 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -41,3 +41,10 @@ global struct ServerInfo string region array< RequiredModInfo > requiredMods } + +global struct MasterServerAuthResult +{ + bool success + string errorCode + string errorMessage +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut new file mode 100644 index 00000000..89b7f719 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut @@ -0,0 +1,56 @@ +global function AtlasAuthDialog + +void function AtlasAuthDialog() +{ + thread AtlasAuthDialog_Threaded() +} + +void function AtlasAuthDialog_Threaded() +{ + // wait at least 1 frame so that the main menu can be loaded first + WaitFrame() + + while ( !NSIsMasterServerAuthenticated() || GetConVarBool( "ns_auth_allow_insecure" ) ) + WaitFrame() + + if ( GetConVarBool( "ns_auth_allow_insecure" ) ) + return + + MasterServerAuthResult res = NSGetMasterServerAuthResult() + + // do nothing on successful authentication + if ( res.success ) + return + + EmitUISound( "blackmarket_purchase_fail" ) + + DialogData dialogData + dialogData.image = $"ui/menu/common/dialog_error" + dialogData.header = Localize( "#AUTHENTICATION_FAILED_HEADER" ) + + // if we got a special error message from Atlas, display it + if ( res.errorMessage != "" ) + dialogData.message = res.errorMessage + else + dialogData.message = Localize( "#AUTHENTICATION_FAILED_BODY" ) + + if ( res.errorCode != "" ) + dialogData.message += format( "\n\n%s", Localize( "#AUTHENTICATION_FAILED_ERROR_CODE", res.errorCode ) ) + + string link = "https://r2northstar.gitbook.io/r2northstar-wiki/installing-northstar/troubleshooting" + // link to generic troubleshooting page if we don't have an error code from Atlas + if ( res.errorCode != "" ) + link = format( "%s#%s", link, res.errorCode ) + + CloseAllDialogs() + AddDialogButton( dialogData, "#OK" ) + AddDialogButton( dialogData, Localize( "#AUTHENTICATION_FAILED_HELP" ), void function() : ( dialogData, link ) + { + // todo: get MS to redirect, so i can use an MS link or something? + LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL ) + // keep the dialog open + OpenDialog( dialogData ) + } ) + + OpenDialog( dialogData ) +} -- cgit v1.2.3 From 0ee1f3daea0cd1c2badfb7c373fe9d0b14917501 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 8 Oct 2023 16:19:51 +0200 Subject: Translations update from Weblate (#739) Translated using Weblate (Russian) Currently translated at 95.1% (277 of 291 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../mod/resource/northstar_client_localisation_russian.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 514e4fd1..f7c6bc6e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -341,5 +341,9 @@ "PROGRESSION_TOGGLE_ENABLED_BODY" "Все титаны, оружие, фракции, раскраски, и т.п. станут разблокированы.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." "PROGRESSION_TOGGLE_DISABLED_BODY" "Будут доступны только разблокированные или купленные вами титаны, оружие, фракции, раскраски, и т.п.\n\nЭту настройку всегда можно изменить в лобби сетевой игры.\n\n^CC000000Внимание: недоступные предметы в экипировке будут заменены на доступные!" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Прогресс!^\n\nВ Northstar теперь работает оригинальная система прогресса разблокировок. Титанов, оружие, фракции, раскраски, и т.п. теперь можно разблокировать через получение новых уровней и прохождение испытаний.\n\nПрогресс можно включить с помощью кнопки внизу меню лобби.\n\nЭту настройку всегда можно изменить." + "AUTHENTICATION_FAILED_BODY" "Не удалось войти в Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Код ошибки: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Справка" + "AUTHENTICATION_FAILED_HEADER" "Ошибка аутентификации" } } -- cgit v1.2.3 From 89c0d98ed62ec32861045852dbbfd295b0859761 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:44:02 +0100 Subject: Fix localisation string for toggling progression on controller (#717) Fix the controller button for toggling progression not showing up. --- Northstar.Client/mod/resource/northstar_client_localisation_english.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_french.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_russian.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt | 2 +- .../mod/resource/northstar_client_localisation_tchinese.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 49e9ee43..c7b25a70 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -351,7 +351,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a // Toggleable progression "TOGGLE_PROGRESSION" "Toggle Progression" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Toggle Progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Toggle Progression" "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disable Progression?" "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 45abcfc5..377f6917 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -351,7 +351,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." "TOGGLE_PROGRESSION" "Activer la progression" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Activer la progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index f7c6bc6e..cf410ff2 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -330,7 +330,7 @@ "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" "gg_assist_reward" "Множитель награды за помощь в убийстве" "TOGGLE_PROGRESSION" "Вкл/выкл прогресс" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Вкл/выкл прогресс" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Вкл/выкл прогресс" "PROGRESSION_TOGGLE_DISABLED_HEADER" "Включить прогресс?" "PROGRESSION_ENABLED_HEADER" "Прогресс включён!" "PROGRESSION_ENABLED_BODY" "^CCCC0000Прогресс включён.^\n\nНедоступных титанов, оружие, фракции, раскраски, и т.п. теперь нужно разблокировать, или купить за Заслуги.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 43ee412f..3d9ae4c6 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -342,7 +342,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PROGRESSION_ENABLED_HEADER" "¡Progreso habilitado!" "PROGRESSION_DISABLED_HEADER" "¡Progreso deshabilitado!" "TOGGLE_PROGRESSION" "Cambiar modo de progresión" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Cambiar modo de progresión" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Cambiar modo de progresión" "PROGRESSION_TOGGLE_DISABLED_BODY" "Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados sólo al subir de nivel, o a través de Logros.\n\nÉsta opción puede ser cambiada cuando quieras en la sala de espera.\n\n^CC000000Advertencia: ¡Cualquier equipamiento o utensilio será reiniciado si no lo tienes desbloqueado!" "MOD_SETTINGS_SERVER" "Servidor" "MOD_SETTINGS_RESET_ALL" "Reiniciar completamente" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 003ca28a..500f8a96 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -350,7 +350,7 @@ "PROGRESSION_TOGGLE_DISABLED_BODY" "泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。\n\n^CC000000警告:如果您已經裝備了尚未解鎖的物品,它們將會被重置!" "PROGRESSION_TOGGLE_ENABLED_BODY" "泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品都將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" "TOGGLE_PROGRESSION" "遊戲進度" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% 遊戲進度" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% 遊戲進度" "PROGRESSION_TOGGLE_ENABLED_HEADER" "停用個人進度?" "PROGRESSION_DISABLED_HEADER" "個人進度已關閉!" "PROGRESSION_DISABLED_BODY" "^CCCC0000個人進度已停用^\n\n泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" -- cgit v1.2.3 From 70c599a345bf5be16ae76d98de2943ee388e6d07 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:04:47 +0200 Subject: Use string convar flags (#740) Uses string names for convars (been supported since refactor but not yet used) rather than magic numbers Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> --- Northstar.Client/mod.json | 4 ++-- Northstar.CustomServers/mod.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index f7c7c9b5..a22f49fd 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -36,12 +36,12 @@ { "Name": "modlist_show_convars", "DefaultValue": "0", - "Flags": 16777216 + "Flags": "ARCHIVE_PLAYERPROFILE" }, { "Name": "modlist_reverse", "DefaultValue": "0", - "Flags": 16777216 + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index e6f2c4b7..de3fcd0d 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -20,7 +20,7 @@ { "Name": "ns_allow_spectators", "DefaultValue": "0", - "Flags": 8192 + "Flags": "REPLICATED" }, { "Name": "ns_private_match_last_mode", -- cgit v1.2.3 From add7305318b6fc1fe74389c60c352a19bddd7748 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:41:48 +0100 Subject: Remove unnecessary convars (#530) Removes some convars we don't need at all --- .../mod/scripts/vscripts/ui/menu_lobby.nut | 45 ++++++---------------- .../mod/scripts/vscripts/ui/menu_mode_select.nut | 18 +++------ .../mod/scripts/vscripts/ui/menu_private_match.nut | 19 +-------- .../mod/scripts/vscripts/ui/openinvites.nut | 5 ++- .../mod/scripts/vscripts/ui/panel_mainmenu.nut | 2 - Northstar.CustomServers/mod.json | 9 ----- .../mod/scripts/vscripts/sh_northstar_utils.gnut | 6 --- 7 files changed, 22 insertions(+), 82 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index e4cc5687..23dae99d 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -288,44 +288,21 @@ void function SetupComboButtonTest( var menu ) 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 ) - } + // server browser + 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 ) - // 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 ) - } + // private match + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) 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 ) - } + + 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 ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut index 52a99b6f..605af383 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut @@ -18,8 +18,8 @@ void function InitModesMenu() 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 ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward ) } void function OnOpenModesMenu() @@ -56,13 +56,7 @@ void function UpdateVisibleModes() if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" || modesArray[ modeIndex ] == "at" ) Hud_SetLocked( buttons[ i ], false ) else - Hud_SetLocked( buttons[ i ], true ) - - if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeIndex ] ) && !IsNorthstarServer() ) - { - Hud_SetLocked( buttons[ i ], true ) - SetButtonRuiText( buttons[ i ], Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetGameModeDisplayName( modesArray[ modeIndex ] ) ) ) ) - } + Hud_SetLocked( buttons[ i ], true ) } } @@ -90,9 +84,7 @@ void function ModeButton_GetFocus( var button ) 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! + if ( IsFDMode( modeName ) ) // HACK! Hud_SetText( nextModeDesc, Localize( "#FD_PLAYERS_DESC", Localize( GetGameModeDisplayHint( modeName ) ) ) ) else Hud_SetText( nextModeDesc, GetGameModeDisplayHint( modeName ) ) @@ -114,7 +106,7 @@ void function ModeButton_Click( var button ) // 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 ] ) ) + if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) ) ClientCommand( "SetCustomMap " + GetPrivateMatchMapsForMode( modeName )[ 0 ] ) // set it diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut index d7c7442f..e3c1f268 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut @@ -247,10 +247,7 @@ void function OnSelectMatchSettings_Activate( var button ) if ( Hud_IsLocked( button ) ) return - if ( !IsNorthstarServer() ) - AdvanceMenu( GetMenu( "MatchSettingsMenu" ) ) - else - AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) ) + AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) ) } void function SetupComboButtons( var menu, var navUpButton, var navDownButton ) @@ -274,13 +271,6 @@ void function SetupComboButtons( var menu, var navUpButton, var navDownButton ) file.matchSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_MATCH_SETTINGS" ) Hud_AddEventHandler( file.matchSettingsButton, UIE_CLICK, OnSelectMatchSettings_Activate ) - if ( !IsNorthstarServer() ) - { - var friendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) - file.inviteFriendsButton = friendsButton - Hud_AddEventHandler( friendsButton, UIE_CLICK, InviteFriendsIfAllowed ) - } - headerIndex++ buttonIndex = 0 file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" ) @@ -575,17 +565,12 @@ function UpdatePrivateMatchButtons() Hud_SetLocked( file.selectMapButton, true ) Hud_SetLocked( file.selectModeButton, true ) Hud_SetLocked( file.matchSettingsButton, true ) - - if ( !IsNorthstarServer() ) - Hud_SetLocked( file.inviteFriendsButton, true ) } else { RHud_SetText( file.startMatchButton, "#START_MATCH" ) Hud_SetLocked( file.selectMapButton, false ) Hud_SetLocked( file.selectModeButton, false ) - if ( !IsNorthstarServer() ) - Hud_SetLocked( file.inviteFriendsButton, false ) string modeName = PrivateMatch_GetSelectedMode() bool settingsLocked = IsFDMode( modeName ) @@ -648,7 +633,7 @@ function UpdateLobby() { float varOrigVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, false ) ) float varOverrideVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, true ) ) - if ( varOrigVal == varOverrideVal && !IsNorthstarServer() ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist + if ( varOrigVal == varOverrideVal ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist continue string label = Localize( MatchSettings_PlaylistVarLabels[varName] ) + ": " diff --git a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut index 4b3d0f55..f91231b6 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut @@ -202,7 +202,10 @@ void function UpdateOpenInvite_Thread() void function UICodeCallback_OpenInviteUpdated() { - if ( file.openInviteVisible || IsNorthstarServer() ) + // don't support on northstar + return + + if ( file.openInviteVisible ) return int currentPartySize = GetPartySize() diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index eef19b5e..c97c8cdc 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -531,7 +531,6 @@ void function OnPlayFDButton_Activate( var button ) // repurposed for launching { if ( !Hud_IsLocked( button ) ) { - SetConVarBool( "ns_is_modded_server", true ) SetConVarString( "communities_hostname", "" ) // disable communities due to crash exploits that are still possible through it NSTryAuthWithLocalServer() thread TryAuthWithLocalServer() @@ -601,7 +600,6 @@ void function OnPlayMPButton_Activate( var button ) { Lobby_SetAutoFDOpen( false ) // Lobby_SetFDMode( false ) - SetConVarBool( "ns_is_modded_server", false ) thread file.mpButtonActivateFunc() } } diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index de3fcd0d..fa51f4d4 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -4,15 +4,6 @@ "Version": "1.19.0", "LoadPriority": 0, "ConVars": [ - { - "Name": "ns_lobby_type", - "DefaultValue": "0" - }, - { - "Name": "ns_is_modded_server", - "DefaultValue": "1", - "Flags": 8192 - }, { "Name": "ns_should_return_to_lobby", "DefaultValue": "1" diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut index b26e48ca..f8597744 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut @@ -1,11 +1,5 @@ globalize_all_functions -// whether the server is a modded, northstar server -bool function IsNorthstarServer() -{ - return GetConVarBool( "ns_is_modded_server" ) -} - // whether the game should return to the lobby on GameRules_EndMatch() bool function ShouldReturnToLobby() { -- cgit v1.2.3 From 7893a11faa5a9f3d13b241b1269b169ae8c519d3 Mon Sep 17 00:00:00 2001 From: Respawn Date: Thu, 12 Oct 2023 02:22:29 +0200 Subject: Add menu_edit_pilot_loadouts.nut from englishclient_frontend --- .../vscripts/ui/menu_edit_pilot_loadouts.nut | 165 +++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut new file mode 100644 index 00000000..e785b067 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut @@ -0,0 +1,165 @@ +untyped + +global function InitEditPilotLoadoutsMenu + +struct +{ + var menu + var loadoutPanel + var[NUM_PERSISTENT_PILOT_LOADOUTS] loadoutHeaders + var[NUM_PERSISTENT_PILOT_LOADOUTS] activateButtons + bool enteringEdit = false + var unlockReq +} file + +void function InitEditPilotLoadoutsMenu() +{ + file.menu = GetMenu( "EditPilotLoadoutsMenu" ) + var menu = file.menu + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnPilotLoadoutsMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnPilotLoadoutsMenu_Close ) + AddMenuEventHandler( menu, eUIEvent.MENU_INPUT_MODE_CHANGED, OnPilotLoadoutsMenu_InputModeChanged ) + + for ( int i = 0; i < NUM_PERSISTENT_PILOT_LOADOUTS; i++ ) + { + var activateButton = Hud_GetChild( menu, "Button" + i ) + activateButton.s.rowIndex <- i + Hud_SetVisible( activateButton, true ) + Hud_AddEventHandler( activateButton, UIE_CLICK, OnLoadoutButton_Activate ) + Hud_AddEventHandler( activateButton, UIE_GET_FOCUS, OnLoadoutButton_Focused ) + Hud_AddEventHandler( activateButton, UIE_LOSE_FOCUS, OnLoadoutButton_LostFocus ) + file.activateButtons[i] = activateButton + } + + Hud_SetFocused( file.activateButtons[0] ) + + file.loadoutPanel = Hud_GetChild( menu, "PilotLoadoutDisplay" ) + file.unlockReq = Hud_GetChild( menu, "UnlockReq" ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) +} + +void function OnPilotLoadoutsMenu_Open() +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + RunMenuClientFunction( "ClearEditingPilotLoadoutIndex" ) + + int loadoutIndex = uiGlobal.pilotSpawnLoadoutIndex + UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons ) + UpdatePilotLoadoutPanel( file.loadoutPanel, GetCachedPilotLoadout( loadoutIndex ) ) + UI_SetPresentationType( ePresentationType.PILOT ) + + RefreshCreditsAvailable() +} + +void function OnPilotLoadoutsMenu_Close() +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + foreach ( i, button in file.activateButtons ) + { + string pilotLoadoutRef = "pilot_loadout_" + ( i + 1 ) + if ( !IsItemNew( player, pilotLoadoutRef ) ) + continue + + ClearNewStatus( button, pilotLoadoutRef ) + } +} + +void function OnPilotLoadoutsMenu_InputModeChanged() +{ + UpdatePilotLoadoutPanelBinds( file.loadoutPanel ) +} + +void function OnLoadoutButton_Focused( var button ) +{ + int index = expect int( button.s.rowIndex ) + + UpdatePilotLoadout( index ) + + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + string unlockReq = GetItemUnlockReqText( pilotLoadoutRef ) + RHud_SetText( file.unlockReq, unlockReq ) +} + +void function UpdatePilotLoadout( int loadoutIndex ) +{ + PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex ) + + UpdatePilotLoadoutPanel( file.loadoutPanel, loadout ) + RunMenuClientFunction( "UpdatePilotModel", loadoutIndex ) +} + +void function OnLoadoutButton_Activate( var button ) +{ + if ( !IsFullyConnected() ) + return + + if ( Hud_IsLocked( button ) ) + { + int index = expect int ( button.s.rowIndex ) + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + + array buttons + foreach ( button in file.activateButtons ) + { + buttons.append( button ) + } + + OpenBuyItemDialog( buttons, button, GetItemName( pilotLoadoutRef ), pilotLoadoutRef ) + return + } + + int loadoutIndex = expect int ( button.s.rowIndex ) + SetEditLoadout( "pilot", loadoutIndex ) + + if ( EDIT_LOADOUT_SELECTS ) + { + bool indexChanged = loadoutIndex != uiGlobal.pilotSpawnLoadoutIndex + + if ( indexChanged ) + { + EmitUISound( "Menu_LoadOut_Pilot_Select" ) + + if ( !IsLobby() ) + uiGlobal.updatePilotSpawnLoadout = true + } + + uiGlobal.pilotSpawnLoadoutIndex = loadoutIndex + ClientCommand( "RequestPilotLoadout " + loadoutIndex ) + } + + if ( PRE_RELEASE_DEMO && loadoutIndex < 3 ) + { + UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons ) + return + } + + RunMenuClientFunction( "SetEditingPilotLoadoutIndex", loadoutIndex ) + AdvanceMenu( GetMenu( "EditPilotLoadoutMenu" ) ) +} + +void function OnLoadoutButton_LostFocus( var button ) +{ + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + + int loadoutIndex = expect int ( button.s.rowIndex ) + string pilotLoadoutRef = "pilot_loadout_" + ( loadoutIndex + 1 ) + ClearNewStatus( button, pilotLoadoutRef ) + + if ( IsItemLocked( player, pilotLoadoutRef ) ) + return + + PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex ) + if ( (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) ) + Hud_SetNew( button, true ) +} -- cgit v1.2.3 From c2716db187ce1e896031ac75e097f96754dc92cf Mon Sep 17 00:00:00 2001 From: Respawn Date: Thu, 12 Oct 2023 02:23:02 +0200 Subject: Add menu_pilot_loadouts_shared.nut from englishclient_frontend --- .../vscripts/ui/menu_pilot_loadouts_shared.nut | 284 +++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut new file mode 100644 index 00000000..122403a3 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut @@ -0,0 +1,284 @@ + +global function UpdatePilotLoadoutPanel +global function UpdatePilotLoadoutPanelBinds +global function UpdatePilotLoadoutButtons +global function UpdatePilotItemButton + +void function UpdatePilotLoadoutButtons( int selectedIndex, var[NUM_PERSISTENT_PILOT_LOADOUTS] buttons, bool focusSelected = true ) +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + int numLoadouts = GetAllCachedPilotLoadouts().len() + + // HACK: num_pilot_loadouts is just used to disable certain loadouts for FNF + int numLoadoutsForPlaylist = GetCurrentPlaylistVarInt( "num_pilot_loadouts", 0 ) + if ( numLoadoutsForPlaylist > 0 ) + numLoadouts = numLoadoutsForPlaylist + + foreach ( index, button in buttons ) + { + PilotLoadoutDef loadout = GetCachedPilotLoadout( index ) + RHud_SetText( button, GetPilotLoadoutName( loadout ) ) + Hud_SetPanelAlpha( button, 0 ) + + bool isSelected = ( index == selectedIndex ) ? true : false + Hud_SetSelected( button, isSelected ) + + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + Hud_SetLocked( button, IsItemLocked( player, pilotLoadoutRef ) ) + + bool shouldShowNew = ButtonShouldShowNew( eItemTypes.FEATURE, pilotLoadoutRef ) + if ( !shouldShowNew && (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) ) + shouldShowNew = true + + if ( IsItemLocked( player, pilotLoadoutRef ) ) + shouldShowNew = false + + Hud_SetNew( button, shouldShowNew ) + + RefreshButtonCost( button, pilotLoadoutRef ) + } + + if ( focusSelected ) + Hud_SetFocused( buttons[ selectedIndex ] ) +} + +void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout ) +{ + SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalName" ), Localize( GetItemName( loadout.special ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryName" ), Localize( GetItemName( loadout.primary ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryName" ), Localize( GetItemName( loadout.secondary ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Name" ), Localize( GetItemName( loadout.weapon3 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceName" ), Localize( GetItemName( loadout.ordnance ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit1Name" ), Localize( GetItemName( loadout.passive1 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit2Name" ), Localize( GetItemName( loadout.passive2 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "ExecutionName" ), Localize( GetItemName( loadout.execution ) ) ) + + UpdatePilotLoadoutPanelBinds( loadoutPanel ) + + var menu = Hud_GetParent( loadoutPanel ) + array buttons = GetElementsByClassname( menu, "PilotLoadoutPanelButtonClass" ) + + /*if ( button ) + { + // TEMP disabled since Hud_GetChild( menu, "ButtonTooltip" ) will fail + //if ( HandleLockedMenuItem( menu, button ) ) + // return + }*/ + bool isEdit + if ( Hud_GetHudName( loadoutPanel ) == "PilotLoadoutButtons" ) // Edit menu + isEdit = true + else // Select menu + isEdit = false + + foreach ( button in buttons ) + UpdatePilotItemButton( button, loadout, isEdit ) + + var renameEditBox = Hud_GetChild( loadoutPanel, "RenameEditBox" ) + + asset pilotAppearanceImage = loadout.camoIndex > 0 ? CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.camoIndex ) ) : $"rui/menu/common/appearance_button_swatch" + + asset primaryAppearanceImage + if ( loadout.primarySkinIndex == 0 ) // default skin + primaryAppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.primarySkinIndex == 1 ) // camo + primaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.primaryCamoIndex ) ) + else // warpaint skin + primaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex ) ) + + asset secondaryAppearanceImage + if ( loadout.secondarySkinIndex == 0 ) // default skin + secondaryAppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.secondarySkinIndex == 1 ) // camo + secondaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.secondaryCamoIndex ) ) + else // warpaint skin + secondaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex ) ) + + asset weapon3AppearanceImage + if ( loadout.weapon3SkinIndex == 0 ) // default skin + weapon3AppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.weapon3SkinIndex == 1 ) // camo + weapon3AppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.weapon3CamoIndex ) ) + else // warpaint skin + weapon3AppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex ) ) + + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ), "camoImage", pilotAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ), "camoImage", primaryAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) ), "camoImage", secondaryAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) ), "camoImage", weapon3AppearanceImage ) + + array nonItemElements + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonGender" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) ) + nonItemElements.append( renameEditBox ) + + foreach ( elem in nonItemElements ) + { + if ( isEdit ) + Hud_Show( elem ) + else + Hud_Hide( elem ) + } + Hud_SetEnabled( renameEditBox, isEdit ) +} + +void function UpdatePilotItemButton( var button, PilotLoadoutDef loadout, bool isEdit ) +{ + string propertyName = Hud_GetScriptID( button ) + string itemRef = GetPilotLoadoutValue( loadout, propertyName ) + int itemType = GetItemTypeFromPilotLoadoutProperty( propertyName ) + asset image + + ItemDisplayData parentItem + + if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT || itemType == eItemTypes.PILOT_PRIMARY_MOD || itemType == eItemTypes.PILOT_SECONDARY_MOD || itemType == eItemTypes.PILOT_WEAPON_MOD3 ) + { + string parentProperty = GetParentLoadoutProperty( "pilot", propertyName ) + Assert( parentProperty == "primary" || parentProperty == "secondary" || parentProperty == "weapon3" ) + + if ( parentProperty == "primary" ) + parentItem = GetItemDisplayData( loadout.primary ) + else if ( parentProperty == "secondary" ) + parentItem = GetItemDisplayData( loadout.secondary ) + else + parentItem = GetItemDisplayData( loadout.weapon3 ) + + bool isHiddenAttachment = false + + if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT ) + { + // Disable attachment option for "special" primary weapons + if ( "menuCategory" in parentItem.i && ( expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.SPECIAL || expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.HANDGUN ) ) + { + isHiddenAttachment = true + + Hud_SetWidth( button, 0 ) + Hud_SetPos( button, 0, 0 ) // Clear sibling offset + } + else + { + int defaultButtonWidth = int( ContentScaledX( 72 ) ) + int defaultOffsetX = int( ContentScaledX( 6 ) ) + + Hud_SetWidth( button, defaultButtonWidth ) + Hud_SetPos( button, defaultOffsetX, 0 ) + } + } + + if ( !isHiddenAttachment ) + image = GetImage( itemType, parentItem.ref, itemRef ) + } + else + { + image = GetImage( itemType, itemRef ) + } + + if ( itemType == eItemTypes.PILOT_PRIMARY || itemType == eItemTypes.PILOT_SECONDARY ) + { + //if ( isEdit ) + //{ + // RuiSetString( Hud_GetRui( button ), "subText", "" ) + // RuiSetFloat( Hud_GetRui( button ), "numSegments", 0 ) + // RuiSetFloat( Hud_GetRui( button ), "filledSegments", 0 ) + //} + //else + { + int currentXP = WeaponGetXP( GetLocalClientPlayer(), itemRef ) + int numPips = WeaponGetNumPipsForXP( itemRef, currentXP ) + int filledPips = WeaponGetFilledPipsForXP( itemRef, currentXP ) + RuiSetString( Hud_GetRui( button ), "subText", WeaponGetDisplayGenAndLevelForXP( itemRef, currentXP ) ) + RuiSetFloat( Hud_GetRui( button ), "numSegments", float( numPips ) ) + RuiSetFloat( Hud_GetRui( button ), "filledSegments", float( filledPips ) ) + } + } + + var rui = Hud_GetRui( button ) + + if ( image == $"" ) + { + RuiSetBool( rui, "isVisible", false ) + Hud_SetEnabled( button, false ) + } + else + { + RuiSetBool( rui, "isVisible", true ) + RuiSetImage( rui, "buttonImage", image ) + + Hud_SetEnabled( button, true ) + } + + bool isLocked = false + bool shouldShowNew = false + + // For unlock and subitem checks below, treat weapon3 as secondary + if ( propertyName == "weapon3Mod1" ) + propertyName = "secondaryMod1" + else if ( propertyName == "weapon3Mod2" ) + propertyName = "secondaryMod2" + else if ( propertyName == "weapon3Mod3" ) + propertyName = "secondaryMod3" + + string propertyRef = propertyName.tolower() + + if ( !IsSubItemType( itemType ) ) + { + if ( IsUnlockValid( propertyRef ) && IsItemLocked( GetUIPlayer(), propertyRef ) ) + { + RefreshButtonCost( button, propertyRef ) + isLocked = true + } + shouldShowNew = ButtonShouldShowNew( itemType, itemRef ) + } + else + { + if ( IsUnlockValid( propertyRef, parentItem.ref ) && IsSubItemLocked( GetUIPlayer(), propertyRef, parentItem.ref ) ) + { + RefreshButtonCost( button, propertyRef ) + isLocked = true + } + shouldShowNew = ButtonShouldShowNew( itemType, itemRef, parentItem.ref ) + } + + Hud_SetLocked( button, isLocked ) + + if ( !shouldShowNew && IsUnlockValid( propertyRef, parentItem.ref ) ) + shouldShowNew = ButtonShouldShowNew( GetSubitemType( parentItem.ref, propertyRef ), propertyRef, parentItem.ref ) + Hud_SetNew( button, shouldShowNew ) + +#if HAS_THREAT_SCOPE_SLOT_LOCK + if ( propertyName == "primaryMod2" ) + { + string attatchmentRef = GetPilotLoadoutValue( loadout, "primaryAttachment" ) + if ( attatchmentRef == "threat_scope" ) + { + Hud_SetLocked( button, true ) + RefreshButtonCost( button, propertyRef, "", 0, 0 ) + Hud_SetNew( button, false ) + } + } +#endif +} + +void function UpdatePilotLoadoutPanelBinds( var loadoutPanel ) +{ + if ( IsControllerModeActive() ) + { + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponCycle%" ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponCycle%" ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_HOLD_HINT" ) ) + } + else + { + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponSelectPrimary0%" ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponSelectPrimary1%" ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_PRESS_HINT" ) ) + } + + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalBind" ), Localize( "%offhand1%" ) ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceBind" ), Localize( "%offhand0%" ) ) +} -- cgit v1.2.3 From 407c5ce39c3124658a869c387e4308e6b72e4c23 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 12 Oct 2023 01:29:31 +0100 Subject: Fix INVALID_REF errors caused by mods (#657) `INVALID_REF` errors were being caused by trying to get the item image for weapon skins. If a mod (e.g. moreskins) added new skins, the client equipped one, and then the mod is disabled, the client now has bad persistence. This is mostly handled fine by the game, except for weapon skins. This PR prevents the crash, and resets the bad persistence to default. --- .../vscripts/ui/menu_edit_pilot_loadouts.nut | 5 +++++ .../vscripts/ui/menu_pilot_loadouts_shared.nut | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut index e785b067..89479a76 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut @@ -82,6 +82,11 @@ void function OnLoadoutButton_Focused( var button ) { int index = expect int( button.s.rowIndex ) + // update the editingLoadoutIndex on focus so that it always matches + // with the pilot loadout panel + uiGlobal.editingLoadoutIndex = index + uiGlobal.editingLoadoutType = "pilot" + UpdatePilotLoadout( index ) string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut index 122403a3..f0139e04 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut @@ -86,7 +86,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.primarySkinIndex == 1 ) // camo primaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.primaryCamoIndex ) ) else // warpaint skin - primaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex ) ) + primaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex, "primarySkinIndex" ) asset secondaryAppearanceImage if ( loadout.secondarySkinIndex == 0 ) // default skin @@ -94,7 +94,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.secondarySkinIndex == 1 ) // camo secondaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.secondaryCamoIndex ) ) else // warpaint skin - secondaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex ) ) + secondaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex, "secondarySkinIndex" ) asset weapon3AppearanceImage if ( loadout.weapon3SkinIndex == 0 ) // default skin @@ -102,7 +102,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.weapon3SkinIndex == 1 ) // camo weapon3AppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.weapon3CamoIndex ) ) else // warpaint skin - weapon3AppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex ) ) + weapon3AppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex, "weapon3SkinIndex" ) RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ), "camoImage", pilotAppearanceImage ) RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ), "camoImage", primaryAppearanceImage ) @@ -282,3 +282,19 @@ void function UpdatePilotLoadoutPanelBinds( var loadoutPanel ) //SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalBind" ), Localize( "%offhand1%" ) ) //SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceBind" ), Localize( "%offhand0%" ) ) } + +asset function GetItemImageFromWeaponRefAndPersistenceValue(string weaponRef, int persistenceValue, string loadoutProperty) +{ + string skinRef = GetSkinRefFromWeaponRefAndPersistenceValue( weaponRef, persistenceValue ) + if (!IsRefValid(skinRef)) + { + if (uiGlobal.editingLoadoutIndex != -1) + { + printt( "Resetting invalid " + loadoutProperty + " for weapon " + weaponRef ) + SetCachedLoadoutValue(GetUIPlayer(), "pilot", uiGlobal.editingLoadoutIndex, loadoutProperty, "0") + } + return $"rui/menu/common/appearance_button_swatch" + } + + return GetItemImage( skinRef ) +} -- cgit v1.2.3 From 5076bea54cfb2f88d5420ede0c207fb77dc5be05 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 5 Nov 2023 12:26:59 +0000 Subject: Remove "Launch Multiplayer" button (#719) As currently Northstar does not support launching into vanilla. --- Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index c97c8cdc..2f1bcf02 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -81,8 +81,9 @@ void function InitMainMenuPanel() headerIndex++ buttonIndex = 0 var multiplayerHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MULTIPLAYER_ALLCAPS" ) - file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" ) - Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate ) + // "Launch Multiplayer" button removed because we don't support vanilla yet :clueless: + //file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" ) + //Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate ) file.fdButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LAUNCH_NORTHSTAR" ) Hud_AddEventHandler( file.fdButton, UIE_CLICK, OnPlayFDButton_Activate ) Hud_SetLocked( file.fdButton, true ) @@ -169,7 +170,8 @@ void function OnShowMainMenuPanel() #endif // PS4_PROG UpdateSPButtons() - thread UpdatePlayButton( file.mpButton ) + // dont try and update the launch multiplayer button, because it doesn't exist + //thread UpdatePlayButton( file.mpButton ) thread UpdatePlayButton( file.fdButton ) thread MonitorTrialVersionChange() @@ -459,7 +461,8 @@ void function UpdatePlayButton( var button ) message = "" } - ComboButton_SetText( file.mpButton, buttonText ) + // dont try and update the launch multiplayer button, because it doesn't exist + //ComboButton_SetText( file.mpButton, buttonText ) ComboButton_SetText( file.fdButton, "#MENU_LAUNCH_NORTHSTAR" ) //Hud_SetEnabled( file.fdButton, false ) -- cgit v1.2.3 From c0e8a9084846a12e549851aa9b734c5b1c8498b8 Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Sun, 5 Nov 2023 20:23:45 -0500 Subject: Plugins v3 (#652) Script component of plugins v3. See launcher PR for more info. https://github.com/R2Northstar/NorthstarLauncher/pull/472 --- .github/nativefuncs.json | 14 +------------- .../scripts/vscripts/cl_northstar_client_init.nut | 13 +++++++++---- .../mod/scripts/vscripts/presence/cl_presence.nut | 11 ++++------- .../mod/scripts/vscripts/presence/ui_presence.nut | 20 ++++++++++++-------- 4 files changed, 26 insertions(+), 32 deletions(-) (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 13a7edd3..8397232d 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -421,13 +421,7 @@ "helpText":"Returns whether or not a given path leads to a folder.", "returnTypeString":"bool", "argTypes":"string path" - }, - { - "name":"NSPushGameStateData", - "helpText":"", - "returnTypeString":"void", - "argTypes":"struct gamestate" - } + } ], "UI":[ { @@ -724,12 +718,6 @@ "returnTypeString":"bool", "argTypes":"string path" }, - { - "name":"NSPushUIPresence", - "helpText":"", - "returnTypeString":"void", - "argTypes":"struct presence" - }, { "name":"NSGetMasterServerAuthResult", "helpText":"", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index a844478a..765d29c3 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -1,3 +1,11 @@ +global enum eDiscordGameState +{ + LOADING = 0 + MAINMENU + LOBBY + INGAME +} + global struct GameStateStruct { string map @@ -15,10 +23,7 @@ global struct GameStateStruct { } global struct UIPresenceStruct { - bool isLoading - bool isLobby - string loadingLevel - string loadedLevel + int gameState } global struct RequiredModInfo diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut index c8a8274a..f17216fb 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut @@ -1,10 +1,8 @@ untyped globalize_all_functions -void function NorthstarCodeCallback_GenerateGameState() { - - GameStateStruct gs - +GameStateStruct function DiscordRPC_GenerateGameState( GameStateStruct gs ) +{ int highestScore = 0 int secondHighest = 0 @@ -40,6 +38,5 @@ void function NorthstarCodeCallback_GenerateGameState() { gs.timeEnd = expect float(level.nv.roundEndTime - Time()) else gs.timeEnd = expect float(level.nv.gameEndTime - Time()) - - NSPushGameStateData(gs) -} \ No newline at end of file + return gs +} diff --git a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut index cdf1c981..ce5abe86 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut @@ -1,12 +1,16 @@ untyped globalize_all_functions -void function NorthstarCodeCallback_GenerateUIPresence() { - UIPresenceStruct uis +UIPresenceStruct function DiscordRPC_GenerateUIPresence( UIPresenceStruct uis ) +{ + if ( uiGlobal.isLoading ) + uis.gameState = eDiscordGameState.LOADING; + else if ( uiGlobal.loadedLevel == "" ) + uis.gameState = eDiscordGameState.MAINMENU; + else if ( IsLobby() || uiGlobal.loadedLevel == "mp_lobby" ) + uis.gameState = eDiscordGameState.LOBBY; + else + uis.gameState = eDiscordGameState.INGAME; - uis.isLoading = uiGlobal.isLoading - uis.isLobby = IsLobby() - uis.loadingLevel = uiGlobal.loadingLevel - uis.loadedLevel = uiGlobal.loadedLevel - NSPushUIPresence(uis) -} \ No newline at end of file + return uis +} -- cgit v1.2.3 From a93756633184bba4c4741198e0e452e71a2e108d Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 7 Nov 2023 22:22:48 +0100 Subject: Translations update from Weblate (#760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (291 of 291 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../mod/resource/northstar_client_localisation_french.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 377f6917..b0e579cf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -353,5 +353,9 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "TOGGLE_PROGRESSION" "Activer la progression" "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." + "AUTHENTICATION_FAILED_HEADER" "Échec de l'authentification" + "AUTHENTICATION_FAILED_HELP" "Aide" + "AUTHENTICATION_FAILED_ERROR_CODE" "Code d'erreur : ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." } } -- cgit v1.2.3 From e49e7e8321269a3de19f07981c8974e87e9fd938 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Thu, 14 Dec 2023 22:19:08 +0100 Subject: Mod download UI integration (#761) UI integration for the mod downloading feature. Feature activation locked behind a convar. --- .github/nativefuncs.json | 19 ++++ Northstar.Client/mod.json | 8 ++ .../northstar_client_localisation_english.txt | 20 ++++ .../scripts/vscripts/cl_northstar_client_init.nut | 8 ++ .../scripts/vscripts/ui/menu_ns_moddownload.nut | 117 +++++++++++++++++++++ .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 59 +++++++++-- 6 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 8397232d..1148d3e5 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -502,6 +502,25 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSIsModDownloadable", + "helpText": "checks whether a mod is verified and can be auto-downloaded", + "returnTypeString": "bool", + "argTypes": "string name, string version" + + }, + { + "name": "NSDownloadMod", + "helpText": "downloads a given mod from distant API to local game profile", + "returnTypeString": "void", + "argTypes": "string name, string version" + }, + { + "name": "NSGetModInstallState", + "helpText": "get status of the mod currently being installed", + "returnTypeString": "ModInstallState", + "argTypes": "" + }, { "name":"NSReloadMods", "helpText":"", diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index a22f49fd..44937a2b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -5,6 +5,10 @@ "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ + { + "Name": "allow_mod_auto_download", + "DefaultValue": "0" + }, { "Name": "filter_hide_empty", "DefaultValue": "0" @@ -82,6 +86,10 @@ "After": "NSUpdateGameStateClientStart" } }, + { + "Path": "ui/menu_ns_moddownload.nut", + "RunOn": "UI" + }, { "Path": "ui/menu_ns_serverbrowser.nut", "RunOn": "UI", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index c7b25a70..9bb36940 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -366,5 +366,25 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time." + + // Mod downloading + "MISSING_MOD" "Missing mod \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" + "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "DOWNLOADING_MOD_TITLE" "Downloading mod" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Downloading %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Checksuming mod" + "CHECKSUMING_TEXT" "Verifying contents of %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extracting mod (%s1%)" + "EXTRACTING_MOD_TEXT" "Extracting %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Failed downloading mod" + "FAILED_READING_ARCHIVE" "An error occurred while reading mod archive." + "FAILED_WRITING_TO_DISK" "An error occurred while extracting mod files to the filesystem." + "MOD_FETCHING_FAILED" "Mod archive could not be downloaded from Thunderstore." + "MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature." + "NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk." + "MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details." } } diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 765d29c3..3560fd56 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -53,3 +53,11 @@ global struct MasterServerAuthResult string errorCode string errorMessage } + +global struct ModInstallState +{ + int status + int progress + int total + float ratio +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut new file mode 100644 index 00000000..4d299362 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -0,0 +1,117 @@ +global function DownloadMod +global function DisplayModDownloadErrorDialog + +global enum eModInstallStatus +{ + DOWNLOADING, + CHECKSUMING, + EXTRACTING, + DONE, + FAILED, + FAILED_READING_ARCHIVE, + FAILED_WRITING_TO_DISK, + MOD_FETCHING_FAILED, + MOD_CORRUPTED, + NO_DISK_SPACE_AVAILABLE, + NOT_FOUND +} + +const int MB = 1024*1000; + +bool function DownloadMod( RequiredModInfo mod ) +{ + // Downloading mod UI + DialogData dialogData + dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" ) + dialogData.message = Localize( "#DOWNLOADING_MOD_TEXT", mod.name, mod.version ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Save reference to UI elements, to update their content + var menu = GetMenu( "Dialog" ) + var header = Hud_GetChild( menu, "DialogHeader" ) + var body = GetSingleElementByClassname( menu, "DialogMessageClass" ) + + // Start actual mod downloading + NSDownloadMod( mod.name, mod.version ) + + ModInstallState state = NSGetModInstallState() + while ( state.status < eModInstallStatus.DONE ) + { + state = NSGetModInstallState() + UpdateModDownloadDialog( mod, state, menu, header, body ) + WaitFrame() + } + + printt( "Mod status:", state.status ) + + // Close loading dialog + CloseActiveMenu() + + return state.status == eModInstallStatus.DONE +} + +void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState state, var menu, var header, var body ) +{ + switch ( state.status ) + { + case eModInstallStatus.DOWNLOADING: + Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + case eModInstallStatus.CHECKSUMING: + Hud_SetText( header, Localize( "#CHECKSUMING_TITLE" ) ) + Hud_SetText( body, Localize( "#CHECKSUMING_TEXT", mod.name, mod.version ) ) + break + case eModInstallStatus.EXTRACTING: + Hud_SetText( header, Localize( "#EXTRACTING_MOD_TITLE", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#EXTRACTING_MOD_TEXT", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + default: + break + } +} + +void function DisplayModDownloadErrorDialog( string modName ) +{ + ModInstallState state = NSGetModInstallState() + + DialogData dialogData + dialogData.header = Localize( "#FAILED_DOWNLOADING", modName ) + dialogData.image = $"ui/menu/common/dialog_error" + + switch ( state.status ) + { + case eModInstallStatus.FAILED_READING_ARCHIVE: + dialogData.message = Localize( "#FAILED_READING_ARCHIVE" ) + break + case eModInstallStatus.FAILED_WRITING_TO_DISK: + dialogData.message = Localize( "#FAILED_WRITING_TO_DISK" ) + break + case eModInstallStatus.MOD_FETCHING_FAILED: + dialogData.message = Localize( "#MOD_FETCHING_FAILED" ) + break + case eModInstallStatus.MOD_CORRUPTED: + dialogData.message = Localize( "#MOD_CORRUPTED" ) + break + case eModInstallStatus.NO_DISK_SPACE_AVAILABLE: + dialogData.message = Localize( "#NO_DISK_SPACE_AVAILABLE" ) + break + case eModInstallStatus.NOT_FOUND: + dialogData.message = Localize( "#NOT_FOUND" ) + break + case eModInstallStatus.FAILED: + default: + dialogData.message = Localize( "#MOD_FETCHING_FAILED_GENERAL" ) + break + } + + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index efc8d66c..29c7621c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -951,33 +951,65 @@ string function FillInServerModsLabel( array mods ) void function OnServerSelected( var button ) +{ + thread OnServerSelected_Threaded( button ) +} + +void function OnServerSelected_Threaded( var button ) { if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return ServerInfo server = file.focusedServer - file.lastSelectedServer = server + // Count mods that have been successfully downloaded + bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) + int downloadedMods = 0; + foreach ( RequiredModInfo mod in server.requiredMods ) { if ( !NSGetModNames().contains( mod.name ) ) { - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) - dialogData.image = $"ui/menu/common/dialog_error" + // Check if mod can be auto-downloaded + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display an error message if not + if ( !modIsVerified || !autoDownloadAllowed ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.image = $"ui/menu/common/dialog_error" + + // Specify error (only if autoDownloadAllowed is set) + if ( autoDownloadAllowed ) + { + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + } - #if PC_PROG AddDialogButton( dialogData, "#DISMISS" ) AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - OpenDialog( dialogData ) + OpenDialog( dialogData ) + + return + } - return + else // Launch download + { + if ( DownloadMod( mod ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } } else { @@ -1018,6 +1050,13 @@ void function OnServerSelected( var button ) } } + // Make Northstar aware new mods have been added + if ( downloadedMods > 0 ) + { + print( "Some new mods have been downloaded or enabled, reloading mods." ) + NSReloadMods(); + } + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() -- cgit v1.2.3 From bbd4ced1eaffb7f7471ef9ea47724daa05811a93 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 19 Dec 2023 01:10:39 +0000 Subject: Make `RequiredOnClient` text clearer (#720) Also makes that text get localised as it was hardcoded before. --- .../mod/resource/northstar_client_localisation_english.txt | 1 + Northstar.Client/mod/resource/ui/menus/modlist.menu | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 9bb36940..98d5bfc7 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -304,6 +304,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "SHOW_ONLY_DISABLED" "Only Disabled" "SHOW_ONLY_NOT_REQUIRED" "Only Optional Mods" "SHOW_ONLY_REQUIRED" "Only Required Mods" + "MOD_REQUIRED_WARNING" " : This mod may get (un)loaded when joining a server" // Maps menu "HIDE_LOCKED" "Hide locked" diff --git a/Northstar.Client/mod/resource/ui/menus/modlist.menu b/Northstar.Client/mod/resource/ui/menus/modlist.menu index da59bcdd..bd350a33 100644 --- a/Northstar.Client/mod/resource/ui/menus/modlist.menu +++ b/Northstar.Client/mod/resource/ui/menus/modlist.menu @@ -488,8 +488,8 @@ resource/ui/menus/modlist.menu { ControlName Label - labelText " : This mod gets (un)loaded automatically" - wide 500 + labelText "#MOD_REQUIRED_WARNING" + auto_wide_tocontents 1 tall 50 visible 0 -- cgit v1.2.3 From feee261dd2269a9f2e13f30d890bc38c6e50351c Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 20 Dec 2023 21:14:57 +0000 Subject: Add missing server browser localisation for `WRONG_MOD_VERSION` (#710) --- Northstar.Client/mod/resource/northstar_client_localisation_english.txt | 1 + Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 98d5bfc7..e6518feb 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -370,6 +370,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a // Mod downloading "MISSING_MOD" "Missing mod \"%s1\" v%s2" + "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3" "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" "DOWNLOADING_MOD_TITLE" "Downloading mod" diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 29c7621c..1bc8e405 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1033,7 +1033,7 @@ void function OnServerSelected_Threaded( var button ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = format( "Server has mod \"%s\" v%s while we have v%s", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) + dialogData.message = Localize( "#WRONG_MOD_VERSION", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG -- cgit v1.2.3 From 00a4bb6fb5e107788ea77cad51c8c8004a9537f1 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:55:33 +0100 Subject: Translations update from Weblate (#776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (Spanish (Mexico)) Currently translated at 91.3% (284 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es_MX/ Co-authored-by: Andrés --- .../northstar_client_localisation_mspanish.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index 18634668..50d1ef17 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -319,5 +319,35 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido" "JSON_PARSE_ERROR" "Error procesando respuesta json" "UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada" + "SHOW_ONLY_REQUIRED" "Solo Mods requeridos" + "player_force_respawn" "Reaparición Forzada" + "TOGGLE_PROGRESSION" "Alternar Progreso" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Desactivar Progreso?" + "NO_RESULTS" "No hay resultados." + "NO_MODS" "No hay configuraciones disponibles! Instala mas mods en: ^5588FF00northstar.thunderstore.io^0." + "AUTHENTICATION_FAILED_HEADER" "Verificacion fallida" + "AUTHENTICATION_FAILED_BODY" "Autenticación fallada con Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Codigo de error: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Ayuda" + "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las configuraciones de categoría\nEsto no es reversible" + "WILL_RESET_SETTING" "Esto revertirá %s1 a la configuracion por defecto. \n \nEsto no es revertible." + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET" "Reiniciar" + "MOD_SETTINGS_RESET_ALL" "Reiniciar todo" + "MOD_REQUIRED_WARNING" " Este mod puede ser deshabilitado al entrar a un servidor" + "MOD_SETTINGS" "Configuracion de Mods" + "NORTHSTAR_BASE_SETTINGS" "Configuracion base de Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Solo el Host puede cambiar ajustes de partida" + "ONLY_HOST_CAN_START_MATCH" "Solo el host puede iniciar la partida" + "MATCH_COUNTDOWN_LENGTH" "Cuenta Atrás de partida privada" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registro desconocido de comandos de cliente" + "DISALLOWED_TACTICALS" "Tactica Prohibida" + "TACTICAL_REPLACEMENT" "Reemplazo de Tactica" + "DISALLOWED_WEAPONS" "Arma Prohibida" + "REPLACEMENT_WEAPON" "Arma de Reemplazo" + "SHOULD_RETURN_TO_LOBBY" "Volver al lobby al finalizar partida" + "ARE_YOU_SURE" "Seguro?" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Alternar Progreso" + "SHOW_ONLY_NOT_REQUIRED" "Solo Mods Opcionales" } } -- cgit v1.2.3 From 8847f70ac698a8865842cecd8f0354cdcaac29e1 Mon Sep 17 00:00:00 2001 From: Maya <11448698+RoyalBlue1@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:30:06 +0100 Subject: Fix mod reloading for MAD (#780) Use the proper function instead of NSReloadMods on join --- .../mod/scripts/vscripts/ui/menu_ns_connect_password.nut | 2 +- .../mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index 1e10aa45..b89e665b 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -56,6 +56,6 @@ void function ConnectWithPassword( var button ) if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 1bc8e405..4f17dedf 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1050,13 +1050,6 @@ void function OnServerSelected_Threaded( var button ) } } - // Make Northstar aware new mods have been added - if ( downloadedMods > 0 ) - { - print( "Some new mods have been downloaded or enabled, reloading mods." ) - NSReloadMods(); - } - if ( server.requiresPassword ) { OnCloseServerBrowserMenu() @@ -1065,12 +1058,12 @@ void function OnServerSelected_Threaded( var button ) else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer() + thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) } } -void function ThreadedAuthAndConnectToServer( string password = "" ) +void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1098,8 +1091,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged = false - // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { -- cgit v1.2.3 From 0e5bf9e64a861a1027d572cc334fc7696d493d65 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:48:24 +0100 Subject: Enable MAD by default (#782) Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com> Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: Alystrasz --- Northstar.Client/mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 44937a2b..cbd0f64c 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -7,7 +7,7 @@ "ConVars": [ { "Name": "allow_mod_auto_download", - "DefaultValue": "0" + "DefaultValue": "1" }, { "Name": "filter_hide_empty", -- cgit v1.2.3 From 06fd34d87db022cfb646528a5502b07f2cc4efe7 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 4 Feb 2024 02:50:20 +0100 Subject: Disable MAD by default (#787) Disables MAD by default again by flipping the value of the corresponding convar by reverting #782 --- Northstar.Client/mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index cbd0f64c..44937a2b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -7,7 +7,7 @@ "ConVars": [ { "Name": "allow_mod_auto_download", - "DefaultValue": "1" + "DefaultValue": "0" }, { "Name": "filter_hide_empty", -- cgit v1.2.3 From 343051c9014207f8785d2194a52ec2f082657ca2 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Fri, 9 Feb 2024 21:05:36 +0100 Subject: Translations update from Weblate (#790) Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../northstar_client_localisation_portuguese.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6364db4..5570b047 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -338,5 +338,41 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "SHOULD_RETURN_TO_LOBBY" "Retornar ao saguão após término de Partida" "WILL_RESET_SETTING" "Isso irá resetar a configuração %s1 ao valor padrão.\n\nAção não reversível." "aitdm_archer_grunts" "Soldados com Archer" + "player_force_respawn" "Resurgimento Forçado" + "PROGRESSION_ENABLED_HEADER" "Progressão Habilitada!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Progressão foi habilitada.^\n\nTitãs, Armas, Facções, Cosméticos, etc. serão destravados ao ganhar níveis, ou comprados com Méritos.\n\nIsso pode ser alterado a qualquer momento no menu de multijogador." + "PROGRESSION_DISABLED_HEADER" "Progressão Desabilitada!" + "TOGGLE_PROGRESSION" "Habilitar Progressão" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Desabilitar Progressão?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titãs, Armas, Facções, Cosméticos etc. serão todos destravados e usáveis a qualquer momento.\n\nIsso pode ser alterado a qualquer hora no menu de multijogador." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Habilitar Progressão?" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titãs, Armas, Facções, Cosméticos, etc. terão que ser destravados ao ganhar níveis, ou comprados com Méritos.\n\nIsso pode ser alterado a qualquer momento no menu de multijogador.\n\n^CC000000Aviso: Se você atualmente tem qualquer item equipado que não foi préviamente destravado, ele será resetado!" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Alternar Progressão" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Baixando mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Baixando %s1 v%s2..." + "MISSING_MOD" "Mod em falta \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(o mod não é verificado, e não pode ser baixado automaticamente)" + "MOD_DL_DISABLED" "(download automático de mod está desabilitado)" + "DOWNLOADING_MOD_TITLE" "Baixando mod" + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Baixando %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Verificando o mod" + "CHECKSUMING_TEXT" "Verificando conteúdo de %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extraíndo mod (%s1%)" + "MOD_REQUIRED_WARNING" " Este mod pode ser desativado quando entrar em um servidor" + "AUTHENTICATION_FAILED_HEADER" "Autenticação Falhou" + "AUTHENTICATION_FAILED_BODY" "Falha ao autenticar com Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Código de Erro: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Ajuda" + "EXTRACTING_MOD_TEXT" "Extraíndo %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Falha ao baixar mod" + "FAILED_READING_ARCHIVE" "Um erro ocorreu ao ler o aqruivo do mod." + "MOD_FETCHING_FAILED" "O arquivo do mod não pode ser baixado da Thunderstore." + "MOD_CORRUPTED" "O aquivo baixado não condiz com a assinatura de verificação registrada." + "NO_DISK_SPACE_AVAILABLE" "Não há espaço suficiente no disco." + "PROGRESSION_DISABLED_BODY" "^CCCC0000Progressão foi desabilitada.^\n\nTitãs, Facções, Armas, Cosméticos, etc. estarão disponíveis para uso a qualquer momento.\n\nIsso pode ser alterado a qualquer hora no menu de multijogador." + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progressão agora pode ser habilitada!^\n\nNorthstar agora suporta a progressão original, o que significa que você pode optar por destravar Armas, Cosméticos, Titãs e outros através do ganho de níveis e completando os desafios.\n\nVocê pode habilitar a progressão usando o botão no rodapé do menu de multijogador.\n\nIsso pode ser alterado a qualquer momento." + "WRONG_MOD_VERSION" "O servidor tem o mod \"%s1\" v%s2 enquanto você possui v%s3" + "FAILED_WRITING_TO_DISK" "Um erro ocorreu enquanto se extraía o conteúdo do mod para o sistema." + "MOD_FETCHING_FAILED_GENERAL" "Extração do mod falhou. Verifique os logs para mais detalhes." } } -- cgit v1.2.3 From 76ba7bf0bae819040a966ea81598f8906d1126b8 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 13 Apr 2024 02:06:44 +0200 Subject: Translations update from Weblate (#801) Translated using Weblate (Spanish) Currently translated at 92.6% (288 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ Co-authored-by: NachosChipeados --- Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 3d9ae4c6..d4172232 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -352,5 +352,6 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "WILL_RESET_SETTING" "Ésta acción reiniciará %s1 a su valor por defecto.\n\nNo se podrá revertir el proceso." "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000El progreso puede ser habilitado desde ahora^\n\nNorthstar ahora es compatible con el progreso normal del juego, esto significa que puedes elegir desbloquear Armas, Aspectos, Titanes y otros a través de desafíos y subiendo de nivel.\n\nPuedes habilitar el progreso normal del juego en la opción ubicada al final de la pantalla de la sala de espera.\n\nÉsta opción puede ser cambiada en cualquier momento." "player_force_respawn" "Reaparición Forzada" + "MOD_REQUIRED_WARNING" " : Esta modificacion puede ser desactivada al entrar a un servidor" } } -- cgit v1.2.3 From 8037da592fa508a07e56811438a55a8b27e4b478 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 29 May 2024 16:22:43 +0200 Subject: Translations update from Weblate (#804) * Translated using Weblate (German) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ * Translated using Weblate (German) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ --------- Co-authored-by: justplus Co-authored-by: GeckoEidechse --- .../northstar_client_localisation_german.txt | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index f1994a24..996a3e2b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -312,5 +312,69 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" "SNS_BANKRUPT_SUB" "Dein Punkestand wurde von %s1 zurückgesetzt" + "respawnprotection" "Respawn Schutzdauer" + "SNS_BANKRUPT" "Bankrott!" + "SNS_LEADER_BANKRUPT" "Punktzahlführer Bankrott!" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Kill Cooldown Zurücksetzungen" + "player_force_respawn" "Erzwungener Respawn" + "SHOW_ONLY_NOT_REQUIRED" "Nur optionale Mods" + "SHOW_ONLY_REQUIRED" "Nur notwendige Mods" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Fortschritt aktivieren?" + "TOGGLE_PROGRESSION" "Fortschritt zuschalten" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Fortschritt deaktivieren?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Waffen, Fraktionen, Skins, usw werden freigeschaltet und sind zu jeder Zeit verfügbar .\n\nDies kann in der Mehrspielerlobby zu jedem Zeitpunkt geändert werden." + "MATCH_COUNTDOWN_LENGTH" "Countdown für privates Match" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Unbekannte Clientbefehle loggen" + "DISALLOWED_TACTICALS" "Verbotene Taktiken" + "TACTICAL_REPLACEMENT" "Taktischer Austausch" + "AUTHENTICATION_FAILED_HEADER" "Authentifizierung fehlgeschlagen" + "AUTHENTICATION_FAILED_BODY" "Authentifizierung mit Atlas fehlgeschlagen!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Fehlercode: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Hilfe" + "NORTHSTAR_BASE_SETTINGS" "Northstar Grundeinstellungen" + "ONLY_HOST_MATCH_SETTINGS" "Nur der Host kann die Einstellungen eines privaten Matches ändern" + "ONLY_HOST_CAN_START_MATCH" "Nur der Host kann das Match starten" + "MISSING_MOD" "Fehlender Mod \"%s1\" v%s2" + "MOD_DL_DISABLED" "(automatisches Herunterladen ist deaktiviert)" + "DOWNLOADING_MOD_TITLE" "Lade Mod herunter" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Lade Mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Lade %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Lade %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Überprüfe Mod Prüfsumme" + "MOD_NOT_VERIFIED" "(mod ist nicht verifiziert und kann nicht automatisch herunterladen werden)" + "MOD_REQUIRED_WARNING" " : Dieser Mod könnte Sie (un)ausgestattet hinterlassen, sobald Sie einem Server beitreten" + "MOD_SETTINGS" "Mod Einstellungen" + "DISALLOWED_WEAPONS" "Verbotene Waffen" + "REPLACEMENT_WEAPON" "Austausch Waffen" + "SHOULD_RETURN_TO_LOBBY" "Zur Lobby nach Matchende zurückkehren" + "ARE_YOU_SURE" "Sind Sie sich sicher?" + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Zurücksetzen" + "MOD_SETTINGS_RESET_ALL" "Alles zurücksetzen" + "NO_RESULTS" "Keine Ergebnisse." + "NO_MODS" "Keine Einstellungen verfügbar! Installieren sie weitere Mods über^5588FF00northstar.thunderstore.io^0." + "PROGRESSION_ENABLED_HEADER" "Fortschritt aktiviert!" + "PROGRESSION_DISABLED_HEADER" "Fortschritt deaktiviert!" + "WILL_RESET_ALL_SETTINGS" "Dadurch werden ALLE Einstellungen, die zu dieser Kategorie gehören, zurückgesetzt.\n\nDies kann nicht rückgängig gemacht werden." + "WILL_RESET_SETTING" "Dies setzten die Einstellungen %s1 auf deren Ursprungeswert zurück.\n\nDies kann nicht rückgängig gemacht werden." + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Fortschritt zuschalten." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titans, Waffen, Fraktionen, Skins usw. müssen durch Levelaufstieg freigeschaltet oder mit Verdiensten gekauft werden.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden.\n\n^CC000000Warnung: Wenn Sie derzeit ausgerüstete Gegenstände besitzen, die Sie nicht freigeschaltet haben, werden diese zurückgesetzt!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Fortschritt wurde aktiviert.^\n\nTitans, Waffen, Fraktionen, Skins usw. müssen durch Levelaufstieg freigeschaltet oder mit Verdiensten gekauft werden.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden." + "PROGRESSION_DISABLED_BODY" "^CCCC0000Fortschritt wurde deaktiviert.^\n\nTitans, Waffen, Fraktionen, Skins usw. werden alle freigeschaltet und jederzeit nutzbar sein.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden." + "CHECKSUMING_TEXT" "Verifiziere Inhalte von %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extrahiere Mod (%s1%)" + "EXTRACTING_MOD_TEXT" "Extrahiere %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Herunterladen der Mod fehlgeschlagen" + "FAILED_READING_ARCHIVE" "Während des Lesens der Mod Archivs ist ein Fehler aufgetreten." + "FAILED_WRITING_TO_DISK" "Während des Extrahierens der Mod in das Dateisysteme ist ein Fehler aufgetreten." + "WRONG_MOD_VERSION" "Der Server verfügt über Mod \"%s1\" v%s2 während Sie v%s3 haben" + "MOD_FETCHING_FAILED" "Mod Archiv konnte nicht von Thunderstore heruntergeladen werden." + "MOD_CORRUPTED" "Prüfsumme des heruntergeladenen Archivs stimmt nicht mit der verifizierten Signatur überein." + "NO_DISK_SPACE_AVAILABLE" "Sie verfügen nicht über ausreichend Speicherplatz auf ihrer Festplatte." + "MOD_FETCHING_FAILED_GENERAL" "Mod Extraktion fehlgeschlagen. Überprüfen Sie die Logs für weitere Details." + "gg_assist_reward" "Assist Anteilige Belohnung" + "SCOREBOARD_BANKRUPTS" "Bankrott Kills" + "sns_offhand_kill_value" "Freihand Killwert" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Fortschritt kann jetzt aktiviert werden!^\n\nNorthstar unterstützt nun den standardmäßigen Fortschritt, was bedeutet, dass Sie Waffen, Skins, Titans usw. durch Levelaufstieg und das Abschließen von Herausforderungen freischalten können.\n\nSie können den Fortschritt mit dem Button am unteren Rand des Lobbybildschirms aktivieren.\n\nDies kann jederzeit geändert werden." } } -- cgit v1.2.3 From 35318c3b1496fe7dc162f51a73617d399d38cbb2 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:28:21 +0200 Subject: Translations update from Weblate (#806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 94.2% (293 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- Northstar.Client/mod/resource/northstar_client_localisation_french.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index b0e579cf..52009f4f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -357,5 +357,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "AUTHENTICATION_FAILED_HELP" "Aide" "AUTHENTICATION_FAILED_ERROR_CODE" "Code d'erreur : ^DB6F2C00%s1^" "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." + "MISSING_MOD" "Mod manquant \"%s1\" v%s2" + "MOD_REQUIRED_WARNING" " : Ce mod peut être (dé)chargé automatiquement en rejoignant un serveur" } } -- cgit v1.2.3 From 8181dd7e0726883e335d09df637487f61dcbbb11 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:56:30 +0200 Subject: Translations update from Weblate (#807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 52009f4f..0bb6b328 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -348,7 +348,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PROGRESSION_ENABLED_HEADER" "Progression activée !" "PROGRESSION_DISABLED_HEADER" "Progression désactivée !" "PROGRESSION_DISABLED_BODY" "^CCCC0000La progression a été désactivée.^\n\nLes Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." - "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équipez des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." "TOGGLE_PROGRESSION" "Activer la progression" "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" @@ -359,5 +359,23 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." "MISSING_MOD" "Mod manquant \"%s1\" v%s2" "MOD_REQUIRED_WARNING" " : Ce mod peut être (dé)chargé automatiquement en rejoignant un serveur" + "EXTRACTING_MOD_TITLE" "Extraction du mod (%s1%)" + "MOD_NOT_VERIFIED" "(ce mod n'est pas vérifié, et n'a donc pas pu être automatiquement téléchargé)" + "MOD_DL_DISABLED" "(le téléchargement automatique de mods est désactivé)" + "DOWNLOADING_MOD_TITLE" "Téléchargement du mod" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Téléchargement du mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Téléchargement de %s1 v%s2..." + "WRONG_MOD_VERSION" "Le serveur requiert la version v%s2 du mod \"%s1\" (vous avez la version v%s3)" + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Téléchargement de %s1 v%s2...\n(%s3/%s4 Mo)" + "CHECKSUMING_TITLE" "Vérification de la somme de contrôle du mod" + "CHECKSUMING_TEXT" "Vérification du contenu de %s1 v%s2..." + "EXTRACTING_MOD_TEXT" "Extraction de %s1 v%s2...\n(%s3/%s4 Mo)" + "FAILED_DOWNLOADING" "Echec du téléchargement du mod" + "FAILED_READING_ARCHIVE" "Une erreur est survenue lors de la lecture de l'archive." + "FAILED_WRITING_TO_DISK" "Une erreur est survenue lors de l'extraction des fichiers." + "MOD_FETCHING_FAILED" "L'archive n'a pas pu être téléchargée depuis Thunderstore." + "MOD_CORRUPTED" "La somme de contrôle de l'archive ne correspond pas à la signature vérifiée." + "NO_DISK_SPACE_AVAILABLE" "L'espace restant sur votre disque est insuffisant." + "MOD_FETCHING_FAILED_GENERAL" "L'extraction du mod a échoué. Consultez le journal pour plus d'informations." } } -- cgit v1.2.3 From bfadbc4d598d595aef02034c1b63e614b164567e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 8 Jul 2024 09:20:55 +0200 Subject: Translations update from Weblate (#815) * Translated using Weblate (English) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/en/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ * Translated using Weblate (Russian) Currently translated at 95.1% (296 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ * Translated using Weblate (English) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/en/ --------- Co-authored-by: William Miller Co-authored-by: WofWca Co-authored-by: GeckoEidechse --- .../northstar_client_localisation_english.txt | 2 +- .../northstar_client_localisation_portuguese.txt | 2 +- .../northstar_client_localisation_russian.txt | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index e6518feb..eaec0cc7 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -320,7 +320,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "UNAUTHORIZED_PWD" "Wrong password" "STRYDER_RESPONSE" "Couldn't parse stryder response" "PLAYER_NOT_FOUND" "Couldn't find player account" - "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" + "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token, try restarting EA App." "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 5570b047..457779eb 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -326,7 +326,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" "UNAUTHORIZED_PWD" "Senha inválida" "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" - "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido" + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, por favor reinicie o EA App para atualizar o Token." "JSON_PARSE_ERROR" "Erro ao ler a resposta json" "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index cf410ff2..56402ca9 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -250,7 +250,7 @@ "UNAUTHORIZED_PWD" "Неправильный пароль" "STRYDER_RESPONSE" "Не удалось разобрать ответ Stryder" "PLAYER_NOT_FOUND" "Не удалось найти аккаунт игрока" - "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера" + "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера. Перезапустите EA App, чтобы обновить токен." "JSON_PARSE_ERROR" "Ошибка разбора json-ответа" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" "DISABLE" "Выключить" @@ -345,5 +345,25 @@ "AUTHENTICATION_FAILED_ERROR_CODE" "Код ошибки: ^DB6F2C00%s1^" "AUTHENTICATION_FAILED_HELP" "Справка" "AUTHENTICATION_FAILED_HEADER" "Ошибка аутентификации" + "MISSING_MOD" "Отсутствует мод \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(мод не был загружен автоматически, т.к. он не проверенный)" + "MOD_DL_DISABLED" "(автоматическая загрузка модов не включена)" + "DOWNLOADING_MOD_TITLE" "Загрузка мода" + "DOWNLOADING_MOD_TEXT" "Загружаем %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Загружаем %s1 v%s2...\n(%s3/%s4 МБ)" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Загрузка мода (%s1%)" + "CHECKSUMING_TITLE" "Проверка целостности" + "MOD_REQUIRED_WARNING" " : Этот мод может автоматически включиться / отключиться при подключении к серверу" + "WRONG_MOD_VERSION" "Версии мода \"%s1\" не совпадают. На сервере: v%s2. У вас: v%s3" + "CHECKSUMING_TEXT" "Проверяем целостность %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Распаковка мода (%s1%)" + "EXTRACTING_MOD_TEXT" "Распаковываем %s1 v%s2...\n(%s3/%s4 МБ)" + "FAILED_DOWNLOADING" "Ошибка загрузки мода" + "FAILED_READING_ARCHIVE" "Ошибка чтения архива мода." + "FAILED_WRITING_TO_DISK" "Ошибка распаковки файлов мода." + "MOD_FETCHING_FAILED" "Ошибка скачивания мода с Thunderstore." + "MOD_CORRUPTED" "Файл архива мода повреждён: контрольная сумма не совпадает." + "NO_DISK_SPACE_AVAILABLE" "Недостаточно места на диске." + "MOD_FETCHING_FAILED_GENERAL" "Ошибка распаковки мода. Проверьте файл лога, чтобы узнать подробности." } } -- cgit v1.2.3 From 278eaf2bf5de61cf705974317909a1f521bf0948 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Fri, 19 Jul 2024 19:36:50 +0200 Subject: Translations update from Weblate (#822) Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../mod/resource/northstar_client_localisation_portuguese.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 457779eb..b6f5ba26 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -326,7 +326,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" "UNAUTHORIZED_PWD" "Senha inválida" "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" - "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, por favor reinicie o EA App para atualizar o Token." + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, tente reiniciar o EA App." "JSON_PARSE_ERROR" "Erro ao ler a resposta json" "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" -- cgit v1.2.3 From 0e8990f1d2272587e19df0de367e9a839b9ebc97 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 27 Jul 2024 20:58:00 +0200 Subject: Translations update from Weblate (#823) * Translated using Weblate (Japanese) Currently translated at 96.1% (299 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ja/ * Translated using Weblate (Japanese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ja/ --------- Co-authored-by: IROHASTUDIO --- .../northstar_client_localisation_japanese.txt | 73 +++++++++++++++++++--- 1 file changed, 65 insertions(+), 8 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index b7fadeaf..798d603e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -233,8 +233,8 @@ "GAMEMODE_fastball" "ファストボール" "PL_fastball" "ファストボール" "PL_fastball_lobby" "ファストボール ロビー" - "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる" - "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる" + "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる。" + "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる。" "PL_fastball_abbr" "FB" "FASTBALL_PANEL_CAPTURED" "%s1 がパネル%s2を制圧した" "SCOREBOARD_FASTBALL_HACKS" "制圧パネル" @@ -265,10 +265,10 @@ "player_bleedout_aiBleedingPlayerMissChance" "ダウン時のAI命中率" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Singleplayer Coop Lobby" - "PL_sp_coop_desc" "Play through the singleplayer campaign with friends" - "PL_sp_coop_hint" "Play through the singleplayer campaign with friends" + "PL_sp_coop" "(未完成) シングルプレイヤー 協力モード" + "PL_sp_coop_lobby" "シングルプレイヤー 協力モード ロビー" + "PL_sp_coop_desc" "シングルプレイヤーのキャンペーンモードをフレンドと一緒にプレイできる" + "PL_sp_coop_hint" "シングルプレイヤーのキャンペーンモードをフレンドと一緒にプレイできる" "PL_sp_coop_abbr" "SP" "SP_TRAINING" "パイロット・ガントレット" @@ -340,13 +340,70 @@ "NO_GAMESERVER_RESPONSE" "ゲームサーバーに接続できません\n(Couldn't reach game server)" "BAD_GAMESERVER_RESPONSE" "ゲームサーバーが不明なレスポンスを返しました\n(Game server gave an invalid response)" "UNAUTHORIZED_GAMESERVER" "ゲームサーバーにそのリクエストを作成する許可がありません\n(Game server is not authorized to make that request)" - "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\nStryder couldn't confirm that this account owns Titanfall 2" + "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\n(Stryder couldn't confirm that this account owns Titanfall 2)" "UNAUTHORIZED_PWD" "パスワードが間違っています\n(Wrong password)" "STRYDER_RESPONSE" "Stryderからのレスポンスの処理に失敗しました\n(Couldn't parse stryder response)" "PLAYER_NOT_FOUND" "プレイヤーのアカウントが見つかりません\n(Couldn't find player account)" - "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです\n(Invalid or expired masterserver token)" + "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです。EAアプリの再起動をお試しください。\n(Invalid or expired masterserver token, try restarting EA App.)" "JSON_PARSE_ERROR" "JSONレスポンスの処理に失敗しました\n(Error parsing json response)" "UNSUPPORTED_VERSION" "現在使用しているバージョンはサポートされていません\n(The version you are using is no longer supported)" + "player_force_respawn" "強制リスポーン" + "SHOW_ONLY_REQUIRED" "必須のModのみ" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% 進行システム切り替え" + "TOGGLE_PROGRESSION" "進行システム切り替え" + "AUTHENTICATION_FAILED_HEADER" "認証に失敗" + "DOWNLOADING_MOD_TITLE" "Modをダウンロード中" + "PROGRESSION_TOGGLE_ENABLED_BODY" "タイタン、武器、勢力、スキンなどが全てアンロックされ、いつでも使えるようになる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "進行システムを有効にしますか?" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "進行システムを無効にしますか?" + "PROGRESSION_DISABLED_HEADER" "進行システムが無効になりました!" + "PROGRESSION_ENABLED_HEADER" "進行システムが有効になりました!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000進行システムが無効化された。^\n\nタイタン、武器、勢力、スキンなどが全てアンロックされ、いつでも使えるようになる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "SHOULD_RETURN_TO_LOBBY" "マッチ終了後にロビーへ戻る" + "REPLACEMENT_WEAPON" "武器の置き換え" + "TACTICAL_REPLACEMENT" "戦術の置き換え" + "DISALLOWED_TACTICALS" "戦術の禁止" + "DISALLOWED_WEAPONS" "武器の禁止" + "ONLY_HOST_CAN_START_MATCH" "マッチを開始できるのはホストのみ" + "ONLY_HOST_MATCH_SETTINGS" "プライベートマッチの設定を変更できるのはホストのみ" + "AUTHENTICATION_FAILED_HELP" "ヘルプ" + "MATCH_COUNTDOWN_LENGTH" "プライベートマッチのカウントダウン時間" + "ARE_YOU_SURE" "よろしいですか?" + "MOD_SETTINGS_SERVER" "サーバー" + "MOD_SETTINGS_RESET" "リセット" + "MOD_SETTINGS_RESET_ALL" "全てリセット" + "NO_RESULTS" "リザルトなし。" + "MOD_SETTINGS" "Modの設定" + "NORTHSTAR_BASE_SETTINGS" "Northstarの基本設定" + "NO_DISK_SPACE_AVAILABLE" "ディスクに十分な領域がありません。" + "FAILED_DOWNLOADING" "Modのダウンロードに失敗" + "FAILED_READING_ARCHIVE" "Modアーカイブの読込中にエラーが発生しました。" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Modをダウンロード中 (%s1%)" + "DOWNLOADING_MOD_TEXT" "ダウンロード中 %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "ダウンロード中 %s1 v%s2...\n(%s3/%s4 MB)" + "MOD_FETCHING_FAILED" "ThunderstoreからModアーカイブをダウンロードできませんでした。" + "EXTRACTING_MOD_TITLE" "Modを抽出中 (%s1%)" + "EXTRACTING_MOD_TEXT" "抽出中 %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_WRITING_TO_DISK" "Modファイルをファイルシステムに抽出する際にエラーが発生しました。" + "MOD_FETCHING_FAILED_GENERAL" "Modの抽出に失敗。詳細はログを確認してください。" + "MOD_CORRUPTED" "ダウンロードしたアーカイブのチェックサムが検証済み署名と一致しませんでした。" + "CHECKSUMING_TITLE" "Modをチェックサム中" + "CHECKSUMING_TEXT" "コンテンツを検証中 %s1 v%s2..." + "MOD_DL_DISABLED" "(自動Modダウンロードは無効です)" + "PROGRESSION_TOGGLE_DISABLED_BODY" "タイタン、武器、勢力、スキンなどのアンロックにレベル上げやメリットが必要になる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。\n\n^CC000000警告: 現在装備しているアイテムがロック中の場合、装備状況は初期化されます!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000進行システムが有効化された。^\n\nタイタン、武器、勢力、スキンなどのアンロックにレベル上げやメリットが必要になる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "LOG_UNKNOWN_CLIENTCOMMANDS" "不明なクライアントコマンドを記録する" + "SHOW_ONLY_NOT_REQUIRED" "任意のModのみ" + "AUTHENTICATION_FAILED_ERROR_CODE" "エラーコード: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_BODY" "Atlasの認証に失敗しました!\n(Failed to authenticate with Atlas!)" + "MISSING_MOD" "Mod消失 \"%s1\" v%s2" + "MOD_REQUIRED_WARNING" " :このModはサーバーに参加した際に読み込まる(または読み込まれない)ことがあります" + "WILL_RESET_ALL_SETTINGS" "カテゴリー内の全設定をリセットしようとしています。\n\nこの操作は取り消せません。" + "WILL_RESET_SETTING" "%s1 の設定を初期値に戻そうとしています。\n\nこの操作は取り消せません。" + "NO_MODS" "設定が利用できません!Modのインストールはこちらから: ^5588FF00northstar.thunderstore.io^0" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000進行システムが開放されました!^\n\nNorthstarはバニラの進行システム、つまり武器、スキン、タイタン等をレベルアップやチャレンジ達成で解除する機能をサポートしています。\n\nこの進行システムは、ロビー画面下のボタンから有効にできます。\n\nこの設定はいつでも変更可能です。" + "MOD_NOT_VERIFIED" "(Modが検証されていないため、自動ダウンロードできませんでした)" + "WRONG_MOD_VERSION" "サーバーはMod\"%s1\"v%s2 を要求していますが、あなたのModバージョンは%s3です" // Translation done by Zetryox and CYakigasi } -- cgit v1.2.3 From 7abae6cf8326a768729cc314805606b6a0344f33 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Sun, 28 Jul 2024 09:35:46 +0300 Subject: Move fontfiletable.txt to keyvalues (#612) This is done so mods using keyvalues folders to add custom fonts to the game don't revert the changes done by Northstar --- .../keyvalues/resource/fontfiletable.txt | 10 ++++++ Northstar.Client/mod/resource/fontfiletable.txt | 40 ---------------------- 2 files changed, 10 insertions(+), 40 deletions(-) create mode 100644 Northstar.Client/keyvalues/resource/fontfiletable.txt delete mode 100644 Northstar.Client/mod/resource/fontfiletable.txt (limited to 'Northstar.Client') diff --git a/Northstar.Client/keyvalues/resource/fontfiletable.txt b/Northstar.Client/keyvalues/resource/fontfiletable.txt new file mode 100644 index 00000000..f0b91c07 --- /dev/null +++ b/Northstar.Client/keyvalues/resource/fontfiletable.txt @@ -0,0 +1,10 @@ +FontFileTable +{ + "arial unicode ms" "resource/Lato-Regular.ttf" + + "lucida console" "resource/NorthstarMono.ttf" [$PC] + + "arial" "resource/Lato-Regular.ttf" + "arial bold" "resource/Lato-Regular.ttf" + "arial narrow" "resource/Lato-Regular.ttf" +} diff --git a/Northstar.Client/mod/resource/fontfiletable.txt b/Northstar.Client/mod/resource/fontfiletable.txt deleted file mode 100644 index b4238134..00000000 --- a/Northstar.Client/mod/resource/fontfiletable.txt +++ /dev/null @@ -1,40 +0,0 @@ -FontFileTable -{ - "Default" "resource/MetronicPro-Regular.vfont" [!$JAPANESE && !$TCHINESE] - "Default" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "Default" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - - "DefaultBold" "resource/MetronicPro-SemiBold.vfont" [!$JAPANESE && !$TCHINESE] - "DefaultBold" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "DefaultBold" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - - "Titanfall" "resource/Titanfall-Regular.vfont" [!$JAPANESE && !$TCHINESE && !$RUSSIAN] - "Titanfall" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "Titanfall" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - "Titanfall" "resource/MetronicPro-SemiBold.vfont" [$RUSSIAN] - - "marlett" "vgui/fonts/marlett.ttf" - - // Everything below is DONOTSHIP / Dev only - - "arial unicode ms" "resource/Lato-Regular.ttf" - - "lucida console" "resource/NorthstarMono.ttf" [$PC] - "lucida console" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] - - "tahoma" "fonts\\tahoma.ttf" [$PC] - "tahoma" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] - - "tahoma bold" "fonts\\tahomabd.ttf" [$PC] - "tahoma bold" "resource/MetronicPro-SemiBold.vfont" [$GAMECONSOLE] - - "courier new" "fonts\\cour.ttf" [$PC] - "courier new" "vgui/fonts/cour.ttf" [$GAMECONSOLE] - - "times new roman" "fonts\\times.ttf" [$PC] - "times new roman" "vgui/fonts/times.ttf" [$GAMECONSOLE] - - "arial" "resource/Lato-Regular.ttf" - "arial bold" "resource/Lato-Regular.ttf" - "arial narrow" "resource/Lato-Regular.ttf" -} -- cgit v1.2.3 From d5b35ee69a1ad7f9c6515ed70474babfb33519f7 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Tue, 30 Jul 2024 00:41:10 +0200 Subject: Only fetch MAD manifesto on server join (#821) Previously, the verified mods manifesto was fetched on game start without checking if the verified mod feature is enabled Squirrel-side; with this, the manifesto is only fetched when the user wants to download a mod (meaning they enabled the feature beforehand). --- .github/nativefuncs.json | 7 ++ .../northstar_client_localisation_english.txt | 2 + .../scripts/vscripts/ui/menu_ns_moddownload.nut | 37 ++++++++- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 96 ++++++++++++++++------ 4 files changed, 115 insertions(+), 27 deletions(-) (limited to 'Northstar.Client') diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 1148d3e5..889432d7 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -502,6 +502,13 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSFetchVerifiedModsManifesto", + "helpText": "Retrieves the verified mods list from the central authority (GitHub).", + "returnTypeString": "void", + "argTypes": "" + + }, { "name": "NSIsModDownloadable", "helpText": "checks whether a mod is verified and can be auto-downloaded", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index eaec0cc7..baceed22 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -373,6 +373,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3" "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "MANIFESTO_FETCHING_TITLE" "Setting up mod download" + "MANIFESTO_FETCHING_TEXT" "Retrieving the list of verified mods..." "DOWNLOADING_MOD_TITLE" "Downloading mod" "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut index 4d299362..3b81c7f9 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -1,8 +1,10 @@ global function DownloadMod global function DisplayModDownloadErrorDialog +global function FetchVerifiedModsManifesto global enum eModInstallStatus { + MANIFESTO_FETCHING, DOWNLOADING, CHECKSUMING, EXTRACTING, @@ -18,7 +20,36 @@ global enum eModInstallStatus const int MB = 1024*1000; -bool function DownloadMod( RequiredModInfo mod ) + +void function FetchVerifiedModsManifesto() +{ + print("Start fetching verified mods manifesto from the Internet") + + // Fetching UI + DialogData dialogData + dialogData.header = Localize( "#MANIFESTO_FETCHING_TITLE" ) + dialogData.message = Localize( "#MANIFESTO_FETCHING_TEXT" ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Do the actual fetching + NSFetchVerifiedModsManifesto() + + ModInstallState state = NSGetModInstallState() + while ( state.status == eModInstallStatus.MANIFESTO_FETCHING ) + { + state = NSGetModInstallState() + WaitFrame() + } + + // Close dialog when manifesto has been received + CloseActiveMenu() +} + +bool function DownloadMod( RequiredModInfo mod, string serverName ) { // Downloading mod UI DialogData dialogData @@ -58,6 +89,10 @@ void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState stat { switch ( state.status ) { + case eModInstallStatus.MANIFESTO_FETCHING: + Hud_SetText( header, Localize( "#MANIFESTO_FETCHING_TITLE" ) ) + Hud_SetText( body, Localize( "#MANIFESTO_FETCHING_TEXT" ) ) + break case eModInstallStatus.DOWNLOADING: Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 4f17dedf..22cdffcf 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -967,49 +967,93 @@ void function OnServerSelected_Threaded( var button ) bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) int downloadedMods = 0; + // Check out if there's any server-required mod that is not locally installed + array modNames = NSGetModNames() + bool uninstalledModFound = false + foreach ( requiredModInfo in server.requiredMods ) + { + // Tolerate core mods having different versions + if ( requiredModInfo.name.len() > 10 && requiredModInfo.name.slice(0, 10) == "Northstar." ) + continue + + if ( !modNames.contains( requiredModInfo.name ) ) + { + print( format ( "\"%s\" was not found locally, triggering manifesto fetching.", requiredModInfo.name ) ) + uninstalledModFound = true + break + } else if ( NSGetModVersionByModName( requiredModInfo.name ) != requiredModInfo.version ) { + print( format ( "\"%s\" was found locally but has version \"%s\" while server requires \"%s\", triggering manifesto fetching.", requiredModInfo.name, NSGetModVersionByModName( requiredModInfo.name ), requiredModInfo.version ) ) + uninstalledModFound = true + break + } + } + + // If yes, we fetch the verified mods manifesto, to check whether uninstalled + // mods can be installed through auto-download + if ( uninstalledModFound && autoDownloadAllowed ) + { + print("Auto-download is allowed, checking if missing mods can be installed automatically.") + FetchVerifiedModsManifesto() + } + foreach ( RequiredModInfo mod in server.requiredMods ) { - if ( !NSGetModNames().contains( mod.name ) ) + // Tolerate core mods having different versions + if ( mod.name.len() > 10 && mod.name.slice(0, 10) == "Northstar." ) + continue + + if ( !NSGetModNames().contains( mod.name ) || NSGetModVersionByModName( mod.name ) != mod.version ) { - // Check if mod can be auto-downloaded - bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + // Auto-download mod + if ( autoDownloadAllowed ) + { + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display error message if mod is not verified + if ( !modIsVerified ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + dialogData.image = $"ui/menu/common/dialog_error" - // Display an error message if not - if ( !modIsVerified || !autoDownloadAllowed ) + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) + return + } + else + { + if ( DownloadMod( mod, server.name ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } + } + + // Mod not found, display error message + else { DialogData dialogData dialogData.header = "#ERROR" dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) dialogData.image = $"ui/menu/common/dialog_error" - // Specify error (only if autoDownloadAllowed is set) - if ( autoDownloadAllowed ) - { - dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) - } - AddDialogButton( dialogData, "#DISMISS" ) - AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) OpenDialog( dialogData ) - return } - - else // Launch download - { - if ( DownloadMod( mod ) ) - { - downloadedMods++ - } - else - { - DisplayModDownloadErrorDialog( mod.name ) - return - } - } } else { -- cgit v1.2.3 From e4b3cc7d3ee17488053cae24c8a8c981dbe95eab Mon Sep 17 00:00:00 2001 From: Klemmbaustein <83748124+Klemmbaustein@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:45:17 +0200 Subject: Add a generic "JoinServer" function (#693) Adds a function that allows the client to join a server from a `ServerInfo` struct. This also changes the server browser to use this function. --- .../vscripts/ui/menu_ns_connect_password.nut | 9 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 148 +++++++++++++++++++-- 2 files changed, 147 insertions(+), 10 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index b89e665b..acc6bb36 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -1,4 +1,5 @@ global function AddNorthstarConnectWithPasswordMenu +global function SetPasswordTargetServer struct { @@ -6,6 +7,7 @@ struct var enterPasswordBox var enterPasswordDummy var connectButton + ServerInfo& targetServer } file void function AddNorthstarConnectWithPasswordMenu() @@ -51,11 +53,16 @@ void function OnConnectWithPasswordMenuOpened() } +void function SetPasswordTargetServer( ServerInfo server ) +{ + file.targetServer = server +} + void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) + thread JoinServer( file.targetServer, Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 22cdffcf..5517843e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -2,7 +2,10 @@ untyped // Only way to get Hud_GetPos(sliderButton) working was to use untyped global function AddNorthstarServerBrowserMenu -global function ThreadedAuthAndConnectToServer + +global function JoinServer +global function JoinServerByName +global function CancelJoinServer global function AddConnectToServerCallback global function RemoveConnectToServerCallback @@ -370,7 +373,7 @@ void function ToggleConnectingHUD( bool vis ) void function ConnectingButton_Activate( var button ) { - file.cancelConnection = true + CancelJoinServer() } //////////////////////////// @@ -1097,17 +1100,18 @@ void function OnServerSelected_Threaded( var button ) if ( server.requiresPassword ) { OnCloseServerBrowserMenu() + SetPasswordTargetServer( file.lastSelectedServer ) AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) + thread ThreadedAuthAndConnectToServer() } } -void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) +void function ThreadedAuthAndConnectToServer( string password = "" ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1135,6 +1139,8 @@ void function ThreadedAuthAndConnectToServer( string password = "", bool modsCha if ( NSWasAuthSuccessful() ) { + bool modsChanged = false + // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { @@ -1350,14 +1356,138 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { - ServerInfo server; - if (targetServer == null) - { + if ( !targetServer ) targetServer = file.lastSelectedServer - } + + expect ServerInfo( targetServer ) foreach( callback in file.connectCallbacks ) { - callback( expect ServerInfo( targetServer ) ) + callback( targetServer ) + } +} + +////////////////////////////////////// +// Join server +////////////////////////////////////// + +void function CancelJoinServer() +{ + file.cancelConnection = true +} + +bool function JoinServerByName( string serverName, string password = "" ) +{ + // Request list of online servers. + NSRequestServerList() + while ( NSIsRequestingServerList() ) + { + WaitFrame() + } + + // Go through all servers that are currently online + foreach ( server in NSGetGameServers() ) + { + // Join the server if it has the correct server name. + if ( server.name == serverName ) + { + return JoinServer( server ) + } } + + print( format( "Failed to connect to server %s: No such server", serverName ) ) + + return false +} + +bool function JoinServer( ServerInfo server, string password = "" ) +{ + if ( NSIsAuthenticatingWithServer() ) + return false + + printt( format( "Connecting to server %s with id of %s", server.name, server.id ) ) + + TriggerConnectToServerCallbacks( server ) + NSTryAuthWithServer( server.index, password ) + + ToggleConnectingHUD( true ) + + while ( NSIsAuthenticatingWithServer() && !file.cancelConnection ) + WaitFrame() + + ToggleConnectingHUD( false ) + + if ( file.cancelConnection ) + { + file.cancelConnection = false + return false + } + + file.cancelConnection = false + + if ( NSWasAuthSuccessful() ) + { + bool modsChanged = false + + // disable all RequiredOnClient mods that are not required by the server and are currently enabled + foreach ( string modName in NSGetModNames() ) + { + if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) + { + // find the mod name in the list of server required mods + bool found = false + foreach ( RequiredModInfo mod in server.requiredMods ) + { + if ( mod.name == modName ) + { + found = true + break + } + } + // if we didnt find the mod name, disable the mod + if ( !found ) + { + modsChanged = true + NSSetModEnabled( modName, false ) + } + } + } + + // enable all RequiredOnClient mods that are required by the server and are currently disabled + foreach ( RequiredModInfo mod in server.requiredMods ) + { + if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name ) ) + { + modsChanged = true + NSSetModEnabled( mod.name, true ) + } + } + + // only actually reload if we need to since the uiscript reset on reload lags hard + if ( modsChanged ) + ReloadMods() + + NSConnectToAuthedServer() + return true + } + else + { + string reason = NSGetAuthFailReason() + + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = reason + dialogData.image = $"ui/menu/common/dialog_error" + + #if PC_PROG + AddDialogButton( dialogData, "#DISMISS" ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + #endif // PC_PROG + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) + return false + } + return false } -- cgit v1.2.3 From cff6f92f030445b7eacb478a64dbd3d22b28586e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:24:17 +0200 Subject: Translations update from Weblate (#825) Translated using Weblate (Russian) Currently translated at 94.8% (297 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- Northstar.Client/mod/resource/northstar_client_localisation_russian.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 56402ca9..91a0dede 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -365,5 +365,7 @@ "MOD_CORRUPTED" "Файл архива мода повреждён: контрольная сумма не совпадает." "NO_DISK_SPACE_AVAILABLE" "Недостаточно места на диске." "MOD_FETCHING_FAILED_GENERAL" "Ошибка распаковки мода. Проверьте файл лога, чтобы узнать подробности." + "MANIFESTO_FETCHING_TEXT" "Скачиваем список проверенных модов..." + "MANIFESTO_FETCHING_TITLE" "Начало загрузки модов" } } -- cgit v1.2.3 From 459e83b35c3485280bee56e2d3419731d3dd29bc Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:00:21 +0200 Subject: Translations update from Weblate (#826) Translated using Weblate (Portuguese) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../mod/resource/northstar_client_localisation_portuguese.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6f5ba26..75a5faad 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -374,5 +374,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "WRONG_MOD_VERSION" "O servidor tem o mod \"%s1\" v%s2 enquanto você possui v%s3" "FAILED_WRITING_TO_DISK" "Um erro ocorreu enquanto se extraía o conteúdo do mod para o sistema." "MOD_FETCHING_FAILED_GENERAL" "Extração do mod falhou. Verifique os logs para mais detalhes." + "MANIFESTO_FETCHING_TEXT" "Retornando a lista de mods verificados..." + "MANIFESTO_FETCHING_TITLE" "Preparando o download do mod" } } -- cgit v1.2.3 From ad2e09bd8d416be5548bf48c866be42ac402d744 Mon Sep 17 00:00:00 2001 From: wolf109909 <84360921+wolf109909@users.noreply.github.com> Date: Wed, 31 Jul 2024 20:21:18 +0800 Subject: Remove redundant parameter in DownloadMod (#827) This parameter is a leftover of a previous refactor, and isn't used anywhere in the function. --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut | 2 +- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut index 3b81c7f9..4968714c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -49,7 +49,7 @@ void function FetchVerifiedModsManifesto() CloseActiveMenu() } -bool function DownloadMod( RequiredModInfo mod, string serverName ) +bool function DownloadMod( RequiredModInfo mod ) { // Downloading mod UI DialogData dialogData diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 5517843e..1396dd22 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1030,7 +1030,7 @@ void function OnServerSelected_Threaded( var button ) } else { - if ( DownloadMod( mod, server.name ) ) + if ( DownloadMod( mod ) ) { downloadedMods++ } -- cgit v1.2.3 From ed76f2bed281d5a8733a559820fcc61e66068b2d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:49:23 +0200 Subject: Revert "Add a generic "JoinServer" function" (#828) Revert "Add a generic "JoinServer" function (#693)" as it causes issues with MAD due to duplicated server join logic as discussed on Discord This reverts commit e4b3cc7d3ee17488053cae24c8a8c981dbe95eab. --- .../vscripts/ui/menu_ns_connect_password.nut | 9 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 148 ++------------------- 2 files changed, 10 insertions(+), 147 deletions(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index acc6bb36..b89e665b 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -1,5 +1,4 @@ global function AddNorthstarConnectWithPasswordMenu -global function SetPasswordTargetServer struct { @@ -7,7 +6,6 @@ struct var enterPasswordBox var enterPasswordDummy var connectButton - ServerInfo& targetServer } file void function AddNorthstarConnectWithPasswordMenu() @@ -53,16 +51,11 @@ void function OnConnectWithPasswordMenuOpened() } -void function SetPasswordTargetServer( ServerInfo server ) -{ - file.targetServer = server -} - void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread JoinServer( file.targetServer, Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 1396dd22..cdeb8b3e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -2,10 +2,7 @@ untyped // Only way to get Hud_GetPos(sliderButton) working was to use untyped global function AddNorthstarServerBrowserMenu - -global function JoinServer -global function JoinServerByName -global function CancelJoinServer +global function ThreadedAuthAndConnectToServer global function AddConnectToServerCallback global function RemoveConnectToServerCallback @@ -373,7 +370,7 @@ void function ToggleConnectingHUD( bool vis ) void function ConnectingButton_Activate( var button ) { - CancelJoinServer() + file.cancelConnection = true } //////////////////////////// @@ -1100,18 +1097,17 @@ void function OnServerSelected_Threaded( var button ) if ( server.requiresPassword ) { OnCloseServerBrowserMenu() - SetPasswordTargetServer( file.lastSelectedServer ) AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer() + thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) } } -void function ThreadedAuthAndConnectToServer( string password = "" ) +void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1139,8 +1135,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged = false - // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { @@ -1356,138 +1350,14 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { - if ( !targetServer ) - targetServer = file.lastSelectedServer - - expect ServerInfo( targetServer ) - - foreach( callback in file.connectCallbacks ) - { - callback( targetServer ) - } -} - -////////////////////////////////////// -// Join server -////////////////////////////////////// - -void function CancelJoinServer() -{ - file.cancelConnection = true -} - -bool function JoinServerByName( string serverName, string password = "" ) -{ - // Request list of online servers. - NSRequestServerList() - while ( NSIsRequestingServerList() ) + ServerInfo server; + if (targetServer == null) { - WaitFrame() - } - - // Go through all servers that are currently online - foreach ( server in NSGetGameServers() ) - { - // Join the server if it has the correct server name. - if ( server.name == serverName ) - { - return JoinServer( server ) - } - } - - print( format( "Failed to connect to server %s: No such server", serverName ) ) - - return false -} - -bool function JoinServer( ServerInfo server, string password = "" ) -{ - if ( NSIsAuthenticatingWithServer() ) - return false - - printt( format( "Connecting to server %s with id of %s", server.name, server.id ) ) - - TriggerConnectToServerCallbacks( server ) - NSTryAuthWithServer( server.index, password ) - - ToggleConnectingHUD( true ) - - while ( NSIsAuthenticatingWithServer() && !file.cancelConnection ) - WaitFrame() - - ToggleConnectingHUD( false ) - - if ( file.cancelConnection ) - { - file.cancelConnection = false - return false + targetServer = file.lastSelectedServer } - file.cancelConnection = false - - if ( NSWasAuthSuccessful() ) - { - bool modsChanged = false - - // disable all RequiredOnClient mods that are not required by the server and are currently enabled - foreach ( string modName in NSGetModNames() ) - { - if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) - { - // find the mod name in the list of server required mods - bool found = false - foreach ( RequiredModInfo mod in server.requiredMods ) - { - if ( mod.name == modName ) - { - found = true - break - } - } - // if we didnt find the mod name, disable the mod - if ( !found ) - { - modsChanged = true - NSSetModEnabled( modName, false ) - } - } - } - - // enable all RequiredOnClient mods that are required by the server and are currently disabled - foreach ( RequiredModInfo mod in server.requiredMods ) - { - if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name ) ) - { - modsChanged = true - NSSetModEnabled( mod.name, true ) - } - } - - // only actually reload if we need to since the uiscript reset on reload lags hard - if ( modsChanged ) - ReloadMods() - - NSConnectToAuthedServer() - return true - } - else + foreach( callback in file.connectCallbacks ) { - string reason = NSGetAuthFailReason() - - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = reason - dialogData.image = $"ui/menu/common/dialog_error" - - #if PC_PROG - AddDialogButton( dialogData, "#DISMISS" ) - - AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - - OpenDialog( dialogData ) - return false + callback( expect ServerInfo( targetServer ) ) } - return false } -- cgit v1.2.3 From 75bbc189f9d595e5811f8e501c423c6d39b1390b Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:55:56 +0200 Subject: Translations update from Weblate (#834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../mod/resource/northstar_client_localisation_french.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Northstar.Client') diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 0bb6b328..9444a39e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -316,7 +316,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "UNAUTHORIZED_PWD" "Mot de passe incorrect" "STRYDER_RESPONSE" "Impossible d'analyser la réponse de Stryder" "PLAYER_NOT_FOUND" "Impossible de trouver le compte du joueur" - "INVALID_MASTERSERVER_TOKEN" "Jeton du server maître invalide ou expiré" + "INVALID_MASTERSERVER_TOKEN" "Token du server maître invalide ou expiré, veuillez relancer l'application EA." "JSON_PARSE_ERROR" "Une erreur est survenue durant l'analyse JSON" "UNSUPPORTED_VERSION" "La version que vous utilisez n'est plus supportée" @@ -377,5 +377,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "MOD_CORRUPTED" "La somme de contrôle de l'archive ne correspond pas à la signature vérifiée." "NO_DISK_SPACE_AVAILABLE" "L'espace restant sur votre disque est insuffisant." "MOD_FETCHING_FAILED_GENERAL" "L'extraction du mod a échoué. Consultez le journal pour plus d'informations." + "MANIFESTO_FETCHING_TITLE" "Préparation du téléchargement du mod" + "MANIFESTO_FETCHING_TEXT" "Récupération de la liste des mods vérifiés..." } } -- cgit v1.2.3