From fd02b453d3ada42d4fd1774737fca9559d971956 Mon Sep 17 00:00:00 2001 From: Casper Talvio Date: Tue, 2 Jan 2024 23:22:08 +0200 Subject: Add validity check to `SaveStatsPeriodically_Threaded` (#769) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index bd64e4caa..f31802142 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -1035,7 +1035,10 @@ void function SaveStatsPeriodically_Threaded() while( true ) { foreach( entity player in GetPlayerArray() ) - Stats_SaveAllStats( player ) + { + if ( IsValid( player ) ) + Stats_SaveAllStats( player ) + } wait 5 } } -- cgit v1.2.3 From af84c42f714484e196cf0d82f9c296e3567b5f35 Mon Sep 17 00:00:00 2001 From: Casper Talvio Date: Tue, 2 Jan 2024 23:24:14 +0200 Subject: Add validity check to `HandleDistanceAndTimeStats_Threaded` to prevent crash (#767) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index f31802142..101d5e4ef 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -931,6 +931,9 @@ void function HandleDistanceAndTimeStats_Threaded() // track distance stats foreach ( entity player in GetPlayerArray() ) { + if ( !IsValid( player ) ) + continue + if ( player.p.lastPosForDistanceStatValid ) { // not 100% sure on using Distance2D over Distance tbh -- cgit v1.2.3 From 0e153649396355f8d726bad233992725633edea6 Mon Sep 17 00:00:00 2001 From: Aibek <35672535+L1ghtman2k@users.noreply.github.com> Date: Tue, 2 Jan 2024 17:18:18 -0500 Subject: Fix spectating for LTS (#774) Adds missing spectator initialisation Co-authored-by: Khalmee <87766895+Khalmee@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 4c52a9bfd..e2bb36d2b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -201,6 +201,14 @@ void function GameStateEnter_Prematch() if ( !GetClassicMPMode() && !ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) thread StartGameWithoutClassicMP() + + // Initialise any spectators. Hopefully they are all initialised already in CodeCallback_OnClientConnectionCompleted + // (_base_gametype_mp.gnut) but for modes like LTS this doesn't seem to happen late enough to work properly. + foreach ( player in GetPlayerArray() ) + { + if ( IsPrivateMatchSpectator( player ) ) + InitialisePrivateMatchSpectatorPlayer( player ) + } } void function StartGameWithoutClassicMP() -- cgit v1.2.3 From 44505833b1fb686c614e75d8269f23f0bc3173c4 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 4 Jan 2024 00:26:31 +0000 Subject: Prevent crash when selecting first infected (#731) End match early if there are no players when trying to select infected --- .../mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index fef4c8b6c..c7175e749 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -45,6 +45,15 @@ void function SelectFirstInfectedDelayed() wait 10.0 + RandomFloat( 5.0 ) array players = GetPlayerArray() + + // End game if server empty on selecting infected + if ( !players.len() ) + { + printt( "Couldn't select first infected: player array was empty" ) + SetWinner( INFECTION_TEAM_SURVIVOR ) + return + } + entity infected = players[ RandomInt( players.len() ) ] InfectPlayer( infected ) -- cgit v1.2.3 From 76582b6890294d2a53163a4be1b806c454aba90e Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 4 Jan 2024 01:32:45 +0100 Subject: Use `getrandom()` instead of random int from player array (#778) Use `getrandom()` instead of random int from player array to select infected Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com> --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index c7175e749..02f0799a1 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -54,7 +54,7 @@ void function SelectFirstInfectedDelayed() return } - entity infected = players[ RandomInt( players.len() ) ] + entity infected = players.getrandom() InfectPlayer( infected ) RespawnInfected( infected ) -- 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(-) 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 1e10aa45f..b89e665b8 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 1bc8e405b..4f17dedf2 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(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 44937a2b0..cbd0f64c7 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 7edb0f2e726221d99db56c434ab6757f3428651f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 21 Jan 2024 00:20:33 +0000 Subject: Prevent client side crash in MFD when marked target dies out of bounds. (#705) --- .../mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index 659dbb7a3..d36045a61 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -188,10 +188,15 @@ void function UpdateMarksForKill( entity victim, entity attacker, var damageInfo { if ( victim == GetMarked( victim.GetTeam() ) ) { - MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, attacker.GetEncodedEHandle() ) + // handle suicides. Not sure what the actual message is that vanilla shows for this + // but this will prevent crashing for now + bool isSuicide = IsSuicide( victim, attacker, DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + entity actualAttacker = isSuicide ? victim : attacker + + MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, actualAttacker.GetEncodedEHandle() ) svGlobal.levelEnt.Signal( "MarkKilled", { mark = victim } ) - - if ( attacker.IsPlayer() ) + + if ( !isSuicide && attacker.IsPlayer() ) attacker.SetPlayerGameStat( PGS_ASSAULT_SCORE, attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + 1 ) } } \ No newline at end of file -- cgit v1.2.3 From 51ed7763f70273603a45dec1ca611ad3eba7f5f6 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 26 Jan 2024 18:44:31 -0300 Subject: Change Aegis Reset Functionality to use titan chassis ref instead of raw index (#788) The previous index passed to the method did not correspond properly with the persistent data index. Instead pass their class reference and then use that to grab the correct index. --- .../mod/scripts/vscripts/sh_progression.nut | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 2dc88d0d4..5098dd328 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -88,7 +88,8 @@ bool function ClientCommand_SetProgression( entity player, array args ) /// Resets a specific Titan's Aegis rank back to `0` /// * `player` - The player entity to perform the action on -/// * `args` - The arguments passed from the client command. `args[0]` should be an integer corresponding to the index of the Titan to reset. +/// * `args` - The arguments passed from the client command. `args[0]` should be a string corresponding to the chassis name of the Titan to reset. +/// Valid chassis are: ion, tone, vanguard, northstar, ronin, legion, and scorch. /// /// Returns `true` on success and `false` on missing args. bool function ClientCommand_ResetTitanAegis( entity player, array args ) @@ -96,7 +97,12 @@ bool function ClientCommand_ResetTitanAegis( entity player, array args ) if ( !args.len() ) return false - int suitIndex = args[0].tointeger() + string titanRef = args[0].tolower() + if( !PersistenceEnumValueIsValid( "titanClasses", titanRef ) ) + return false + + int suitIndex = PersistenceGetEnumIndexForItemName( "titanClasses", titanRef ) + player.SetPersistentVar( "titanFDUnlockPoints[" + suitIndex + "]", 0 ) player.SetPersistentVar( "previousFDUnlockPoints[" + suitIndex + "]", 0 ) player.SetPersistentVar( "fdTitanXP[" + suitIndex + "]", 0 ) -- cgit v1.2.3 From 14561cf90f3f80ad844803bdb621c6bd720bdc55 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 26 Jan 2024 18:47:24 -0300 Subject: Unlock remaining DLC items while progression is enabled (#786) As they cannot be unlocked by levelling up and some players may still want to use them while having progression enabled, we simply keep them unlocked when progression is enabled. --- Northstar.CustomServers/mod/scripts/vscripts/_items.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index a23a68b0c..96623086c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -10094,7 +10094,7 @@ void function InitUnlockAsEntitlement( string itemRef, string parentRef, int ent unlock = file.entitlementUnlocks[fullRef] } - unlock.entitlementIds.append( entitlementId ) + unlock.entitlementIds.append( 1 ) // Using `1` here instead of the huge DLC check I did previously. Having the `1` seems to keep all paid cosmetics unlocked with progression enabled. } array function GetEntitlementIds( string itemRef, string parentRef = "" ) -- cgit v1.2.3 From c8193f64ff169441ef9a359af126a99121040224 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:12:10 +0000 Subject: Scale pilot kill core gain properly for mixed modes (#702) Closes #682 --- Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index be20982df..aba1d5401 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -304,7 +304,7 @@ void function ScoreEvent_SetupEarnMeterValuesForMixedModes() // mixed modes in t { // todo needs earn/overdrive values // player-controlled stuff - ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15, 0.33 ) // 5% for titan cores ScoreEvent_SetEarnMeterValues( "KillTitan", 0.0, 0.15 ) ScoreEvent_SetEarnMeterValues( "TitanKillTitan", 0.0, 0.0 ) // unsure ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.35 ) // this actually just doesn't have overdrive in vanilla even -- 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(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index cbd0f64c7..44937a2b0 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6364db4e..5570b0471 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 77aefb01fb641af47aa5f855333844835e27047d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:16:08 +0100 Subject: Remove duplicate entries of `mp_lf_stacks` (#793) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index c22e2174d..ac638b069 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -395,7 +395,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -449,7 +448,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -498,7 +496,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -747,7 +744,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -795,7 +791,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 -- cgit v1.2.3 From cc8df6a8748176cd24f4bb122386a2424e89cd13 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:18:47 +0100 Subject: Fix indentation in `playlist_v2.txt` (#794) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index ac638b069..741696007 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -824,18 +824,18 @@ playlists { maps { - mp_forwardbase_kodai 1 - mp_grave 1 - mp_homestead 1 - mp_thaw 1 - mp_black_water_canal 1 - mp_eden 1 - mp_drydock 1 - mp_crashsite3 1 - mp_complex3 1 - mp_angel_city 1 - mp_colony02 1 - mp_glitch 1 + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_relic02 1 mp_wargames 1 mp_rise 1 -- cgit v1.2.3 From 0982cb08e92bd2d64d8bbc421c34f08a82901155 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:46:34 +0100 Subject: Fix map rotation for CTF and remove duplicate entries (#795) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index 741696007..e6258edd9 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -623,35 +623,27 @@ playlists { maps { - mp_complex3 1 - mp_drydock 1 - mp_glitch 1 - mp_homestead 2 - mp_eden 1 mp_forwardbase_kodai 1 - mp_black_water_canal 1 - mp_glitch 1 - mp_angel_city 1 - mp_colony02 1 - mp_relic02 1 mp_grave 1 mp_homestead 1 - mp_drydock 1 - mp_glitch 1 mp_thaw 1 - mp_eden 2 mp_black_water_canal 1 - mp_glitch 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 + mp_eden 1 + mp_drydock 1 mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 } } } -- cgit v1.2.3 From f2041fbb144707e68c8c772d418479b6ac53bf07 Mon Sep 17 00:00:00 2001 From: Austin Rollfing Date: Thu, 22 Feb 2024 19:50:48 -0500 Subject: Fix map rotation for Hide-and-Seek and remove duplicate entries (#792) --- Northstar.Custom/keyvalues/playlists_v2.txt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index e6258edd9..d60a24e5c 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -670,35 +670,27 @@ playlists { maps { - mp_complex3 1 - mp_drydock 1 - mp_glitch 1 - mp_homestead 2 - mp_eden 1 mp_forwardbase_kodai 1 - mp_black_water_canal 1 - mp_glitch 1 - mp_angel_city 1 - mp_colony02 1 - mp_relic02 1 mp_grave 1 mp_homestead 1 - mp_drydock 1 - mp_glitch 1 mp_thaw 1 - mp_eden 2 mp_black_water_canal 1 - mp_glitch 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 + mp_eden 1 + mp_drydock 1 mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 } } } -- cgit v1.2.3 From 51eb5eade9aedd69b64a293e95c008a8a8d1f908 Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Thu, 29 Feb 2024 00:37:57 +0100 Subject: Add weapon dropped callback Adds a callback for when a weapon is dropped. In the progress this also fixes weapons still dropping unintentionally in certain case. --- .../mod/scripts/vscripts/_loadouts_mp.gnut | 20 ++++------------- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 2 ++ .../mod/scripts/vscripts/mp/_codecallbacks.gnut | 25 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 63756fdc8..141cfe15b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -51,8 +51,6 @@ void function SvLoadoutsMP_Init() AddClientCommandCallback( "InGameMPMenuClosed", ClientCommandCallback_InGameMPMenuClosed ) AddClientCommandCallback( "LoadoutMenuClosed", ClientCommandCallback_LoadoutMenuClosed ) } - - AddCallback_OnPlayerKilled( DestroyDroppedWeapon ) } void function SetLoadoutGracePeriodEnabled( bool enabled ) @@ -62,20 +60,10 @@ void function SetLoadoutGracePeriodEnabled( bool enabled ) void function SetWeaponDropsEnabled( bool enabled ) { - file.weaponDropsEnabled = enabled -} - -void function DestroyDroppedWeapon( entity victim, entity attacker, var damageInfo ) -{ - if ( !file.weaponDropsEnabled && IsValid( victim.GetActiveWeapon() ) ) - thread DelayDestroyDroppedWeapon( victim.GetActiveWeapon() ) -} - -void function DelayDestroyDroppedWeapon( entity weapon ) -{ - WaitEndFrame() - if ( IsValid( weapon ) ) - weapon.Destroy() + if( enabled ) + FlagSet( "WeaponDropsAllowed" ) + else + FlagClear( "WeaponDropsAllowed" ) } void function AddCallback_OnTryGetTitanLoadout( TryGetTitanLoadoutCallbackType callback ) 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 9288f75e3..b77a37b2a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -43,6 +43,8 @@ void function BaseGametype_Init_MPSP() AddCallback_OnPlayerKilled( CheckForAutoTitanDeath ) RegisterSignal( "PlayerRespawnStarted" ) RegisterSignal( "KillCamOver" ) + + FlagInit( "WeaponDropsAllowed", true ) } void function SetIntermissionCamera( entity camera ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index ff281d6eb..8644296e4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -18,6 +18,8 @@ global function CodeCallback_OnProjectileGrappled global function DamageInfo_ScaleDamage global function CodeCallback_CheckPassThroughAddsMods global function SetTitanMeterGainScale +global function CodeCallback_WeaponDropped +global function AddCallback_OnWeaponDropped #if MP global function CodeCallback_OnServerAnimEvent @@ -43,6 +45,7 @@ struct ] table playerAccumulatedDamageData + array< void functionref( entity ) > weaponDroppedCallbacks } file void function CodeCallback_Init() @@ -1030,4 +1033,26 @@ void function CodeCallback_OnServerAnimEvent( entity ent, string eventName ) PerfEnd( PerfIndexServer.CB_OnServerAnimEvent ) } + +void function AddCallback_OnWeaponDropped( void functionref( entity ) callback ) +{ + file.weaponDroppedCallbacks.append( callback ) +} + +void function CodeCallback_WeaponDropped( entity weapon ) +{ + // shamelessly taken form SP + if ( !IsValid( weapon ) ) + return + + // Might look a bit hacky to put it here, but thats how SP does it + if ( !Flag( "WeaponDropsAllowed" ) ) + { + weapon.Destroy() + return + } + + foreach( callback in file.weaponDroppedCallbacks ) + callback( weapon ) +} #endif // #if MP \ No newline at end of file -- cgit v1.2.3 From a8c0653b25616a4b3b5cf224ae7eddc856fad7cc Mon Sep 17 00:00:00 2001 From: Cyn <70904206+itscynxx@users.noreply.github.com> Date: Tue, 26 Mar 2024 07:52:16 -0500 Subject: Fix weapon drop callback breaking SP (#797) Move weapon drop callback globalization to `#if MP` --- Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index 8644296e4..0d1b42b7e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -18,11 +18,11 @@ global function CodeCallback_OnProjectileGrappled global function DamageInfo_ScaleDamage global function CodeCallback_CheckPassThroughAddsMods global function SetTitanMeterGainScale -global function CodeCallback_WeaponDropped -global function AddCallback_OnWeaponDropped #if MP global function CodeCallback_OnServerAnimEvent +global function CodeCallback_WeaponDropped +global function AddCallback_OnWeaponDropped #endif struct AccumulatedDamageData -- cgit v1.2.3 From 11787b3896b8242ac8f7e583d72cabf68f9161a9 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:50:38 +0100 Subject: Validate selected Titan loadout index better (#762) Seemingly there are cases where mods can set an invalid Titan loadout index, which then causes the progression checks to attempt to set the player's Titan model to an invalid index. This commit adds a check to ensure that it is within the bounds of the titan loadout array. --- .../mod/scripts/vscripts/sh_progression.nut | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 5098dd328..3297643ec 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -224,11 +224,12 @@ void function ValidateEquippedItems( entity player ) } // titan loadouts + int selectedTitanLoadoutIndex = player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ ) { printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex ) - bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) + bool isSelected = titanLoadoutIndex == selectedTitanLoadoutIndex TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex ) TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex] @@ -446,11 +447,18 @@ void function ValidateEquippedItems( entity player ) { printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" ) player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) - Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 ) + selectedTitanLoadoutIndex = 0 } } - Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) ) + if ( selectedTitanLoadoutIndex < 0 || selectedTitanLoadoutIndex >= NUM_PERSISTENT_TITAN_LOADOUTS ) + { + printt( "- SELECTED TITAN CLASS IS INVALID, RESETTING" ) + player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) + selectedTitanLoadoutIndex = 0 + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", selectedTitanLoadoutIndex ) // pilot loadouts for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ ) -- cgit v1.2.3 From f427583ec497f80aa2f80ac4d34dc44b7e23643f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:52:53 +0100 Subject: Add initial unit testing logic (#708) Adds initial logic to allow for some form of basic unit testing. --- Northstar.Custom/mod.json | 13 + Northstar.Custom/mod/scripts/vscripts/_testing.nut | 302 +++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/_testing.nut diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 399311e43..69432f498 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -440,6 +440,19 @@ "Path": "sh_northstar_safe_io.gnut", "RunOn": "CLIENT || SERVER || UI" }, + { + "Path": "_testing.nut", + "RunOn": "CLIENT || SERVER || UI", + "ClientCallback": { + "Before": "Testing_Init" + }, + "ServerCallback": { + "Before": "Testing_Init" + }, + "UICallback": { + "Before": "Testing_Init" + } + }, { "Path": "_event_models.gnut", "RunOn": "SERVER && LOBBY", diff --git a/Northstar.Custom/mod/scripts/vscripts/_testing.nut b/Northstar.Custom/mod/scripts/vscripts/_testing.nut new file mode 100644 index 000000000..15bcf18ba --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/_testing.nut @@ -0,0 +1,302 @@ +global function Testing_Init +global function RunAllTests +global function RunAllTests_SaveToFile +global function RunTestsByCategory +global function RunTestByCategoryAndName + +global function AddTest + +struct TestInfo +{ + string testName + var functionref() callback + // whether the test completed successfully + // if this is true, actualResult is valid + bool completed + // var not string because then i can just set it to an exception + // which print can then handle + var error + // whether the test is considered successful + var expectedResult + var actualResult + bool passed +} + +struct { + table< string, array< TestInfo > > tests = {} +} file + +void function Testing_Init() +{ + // tests for the testing functions :) + //AddTest( "Example Tests", "example succeeding test", ExampleTest_ReturnsTrue, true ) + //AddTest( "Example Tests", "example failing test", ExampleTest_ReturnsFalse, true ) + //AddTest( "Example Tests", "example erroring test", ExampleTest_ThrowsError, true ) + //AddTest( "Example Tests", "example test with args", var function() { + // return ExampleTest_HasArgs_ReturnsNonVar( 2, 3 ) + //}, 6 ) +} + +int function ExampleTest_HasArgs_ReturnsNonVar( int first, int second ) +{ + return first * second +} + +var function ExampleTest_ReturnsFalse() +{ + return false +} + +var function ExampleTest_ReturnsTrue() +{ + return true +} + +var function ExampleTest_ThrowsError() +{ + throw "Example exception" + return null +} + +void function RunAllTests_SaveToFile() +{ + RunAllTests() + + #if UI + string fileName = "ns-unit-tests-UI.json" + #elseif CLIENT + string fileName = "ns-unit-tests-CLIENT.json" + #elseif SERVER + string fileName = "ns-unit-tests-SERVER.json" + #endif + + // cant encode structs so have to reconstruct a table manually from the structs + table out = {} + foreach ( category, tests in file.tests ) + { + array categoryResults = [] + foreach ( test in tests ) + { + table testTable = {} + testTable[ "name" ] <- test.testName + testTable[ "completed" ] <- test.completed + testTable[ "passed" ] <- test.passed + if ( !test.completed ) + testTable[ "error" ] <- test.error + else if ( !test.passed ) + { + testTable[ "expectedResult" ] <- test.expectedResult + testTable[ "actualResult" ] <- test.actualResult + } + + categoryResults.append( testTable ) + } + out[ category ] <- categoryResults + } + + NSSaveJSONFile( fileName, out ) +} + +void function RunAllTests() +{ + printt( "Running all tests!" ) + + foreach ( category, categoryTests in file.tests ) + { + foreach ( test in categoryTests ) + { + RunTest( test ) + } + } + + PrintAllTestResults() +} + +void function RunTestsByCategory( string category ) +{ + if ( !( category in file.tests ) ) + { + printt( format( "Category '%s' has no tests registered", category ) ) + return + } + + foreach ( categoryTest in file.tests[ category ] ) + { + RunTest( categoryTest ) + } +} + +void function RunTestByCategoryAndName( string category, string testName ) +{ + // find test + if ( !( category in file.tests ) ) + { + printt( format( "Category '%s' has no tests registered", category ) ) + return + } + + TestInfo ornull foundTest = null + foreach ( categoryTest in file.tests[ category ] ) + { + if ( categoryTest.testName == testName ) + { + foundTest = categoryTest + break + } + } + + if ( !foundTest ) + { + printt( format( "Category '%s' does not contain a test with name '%s'", category, testName ) ) + return + } + + expect TestInfo( foundTest ) + + printt( "Running test!" ) + // run test + RunTest( foundTest ) + // print result + PrintTestResult( foundTest ) +} + +void function RunTest( TestInfo test ) +{ + test.completed = false + test.passed = false + test.actualResult = null + test.error = "" + + try + { + test.actualResult = test.callback() + test.completed = true + test.passed = test.actualResult == test.expectedResult + } + catch ( exception ) + { + test.completed = false + test.error = exception + } +} + +void function PrintAllTestResults() +{ + int totalSucceeded = 0 + int totalFailed = 0 + int totalErrored = 0 + + foreach ( category, categoryTests in file.tests ) + { + int categorySucceeded = 0 + int categoryFailed = 0 + int categoryErrored = 0 + + printt( format( "Results for category: '%s'", category ) ) + foreach ( test in categoryTests ) + { + if ( test.completed ) + { + if ( test.passed ) + { + printt( "\t", test.testName, "- Passed!" ) + categorySucceeded++ + } + else + { + printt( "\t", test.testName, "- Failed!" ) + printt( "\t\tExpected:", test.expectedResult ) + printt( "\t\tActual: ", test.actualResult ) + categoryFailed++ + } + } + else + { + printt( "\t", test.testName, "- Errored!" ) + printt( "\t\tError:", test.error ) + categoryErrored++ + } + } + + printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored ) + + totalSucceeded += categorySucceeded + totalFailed += categoryFailed + totalErrored += categoryErrored + } + + printt( "TOTAL SUCCEEDED:", totalSucceeded, "TOTAL FAILED:", totalFailed, "TOTAL ERRORED:", totalErrored ) +} + +void function PrintCategoryResults( string category ) +{ + int categorySucceeded = 0 + int categoryFailed = 0 + int categoryErrored = 0 + + printt( format( "Results for category: '%s'", category ) ) + foreach ( test in file.tests[ category ] ) + { + if ( test.completed ) + { + if ( test.passed ) + { + printt( "\t", test.testName, "- Passed!" ) + categorySucceeded++ + } + else + { + printt( "\t", test.testName, "- Failed!" ) + printt( "\t\tExpected:", test.expectedResult ) + printt( "\t\tActual: ", test.actualResult ) + categoryFailed++ + } + } + else + { + printt( "\t", test.testName, "- Errored!" ) + printt( "\t\tError:", test.error ) + categoryErrored++ + } + } + + printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored ) +} + +void function PrintTestResult( TestInfo test ) +{ + string resultString = test.testName + + if ( test.completed ) + { + if ( test.passed ) + resultString += " - Passed!" + else + { + resultString += " - Failed!" + resultString += "\n\tExpected: " + test.expectedResult + resultString += "\n\tActual: " + test.actualResult + } + } + else + { + resultString += " - Not completed!" + resultString += "\n\tError: " + test.error + } + + printt( resultString ) +} + +void function AddTest( string testCategory, string testName, var functionref() testFunc, var expectedResult ) +{ + TestInfo newTest + newTest.testName = testName + newTest.callback = testFunc + newTest.expectedResult = expectedResult + + // create the test category if it doesn't exist + if ( !( testCategory in file.tests ) ) + file.tests[ testCategory ] <- [ newTest ] + else + file.tests[ testCategory ].append( newTest ) +} -- cgit v1.2.3 From 9661372712f47f3c5d3ef83f1c7776484eeab52f Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 12 Apr 2024 20:54:55 -0300 Subject: Move all owned NPCs together with player on Team Switching (#789) Uses a call back that is triggered when the player switches team to update their own entities accordingly. --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index e2bb36d2b..5cc096f29 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -96,6 +96,7 @@ void function PIN_GameStart() AddCallback_OnPlayerKilled( OnPlayerKilled ) AddDeathCallback( "npc_titan", OnTitanKilled ) + AddCallback_EntityChangedTeam( "player", OnPlayerChangedTeam ) RegisterSignal( "CleanUpEntitiesForRoundEnd" ) } @@ -1017,3 +1018,21 @@ void function DialoguePlayWinnerDetermined() PlayFactionDialogueToTeam( "scoring_lost", losingTeam ) } } + +/// This is to move all NPCs that a player owns from one team to the other during a match +/// Auto-Titans, Turrets, Ticks and Hacked Spectres will all move along together with the player to the new Team +/// Also possibly prevents mods that spawns other types of NPCs that players can own from breaking when switching (i.e Drones, Hacked Reapers) +void function OnPlayerChangedTeam( entity player ) +{ + if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams + return + + NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) + + foreach( npc in GetNPCArray() ) + { + entity bossPlayer = npc.GetBossPlayer() + if ( IsValidPlayer( bossPlayer ) && bossPlayer == player && IsAlive( npc ) ) + SetTeam( npc, player.GetTeam() ) + } +} -- 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 3d9ae4c6c..d4172232e 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index f1994a243..996a3e2ba 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 83e97763b3421e59d13e9a40bf20c0d987da9129 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:29:40 +0200 Subject: Bump Actions Ubuntu version to 22.04 (#805) Bump the Ubuntu version used for encoding and missing translations check from `20.04` to `22.04`. --- .github/workflows/encoding.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index a88e3961a..5a730c203 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: check-loc-encoding: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 @@ -12,7 +12,7 @@ jobs: files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) IFS=$'\n'; files=($files); unset IFS; ! file --mime "${files[@]}" | grep -v "charset=utf-16le" check-missing-translations: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 -- cgit v1.2.3 From 6581c4e800e5cec0e4d6f5b3f87b80bd6989233c Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 28 Jun 2024 15:10:45 -0300 Subject: Implement Match Goals menu and XP tracking (#756) for vanilla parity when it comes to the progression system. See PR description for full details --- .../mod/scripts/vscripts/_xp.gnut | 16 ++ .../mod/scripts/vscripts/evac/_evac.gnut | 10 + .../mod/scripts/vscripts/faction_xp.gnut | 9 + .../scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_at.nut | 6 + .../scripts/vscripts/gamemodes/_gamemode_cp.nut | 41 +++- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 19 ++ .../scripts/vscripts/gamemodes/_gamemode_fra.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_lts.nut | 33 +++ .../scripts/vscripts/gamemodes/_gamemode_mfd.nut | 15 +- .../scripts/vscripts/gamemodes/_gamemode_ps.nut | 1 + .../vscripts/gamemodes/_gamemode_speedball.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_tdm.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_ttdm.nut | 31 +++ .../mod/scripts/vscripts/mp/_challenges.gnut | 268 +++++++++++++++++++++ .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 38 ++- .../mod/scripts/vscripts/mp/_score.nut | 17 ++ .../mod/scripts/vscripts/titan_xp.gnut | 22 ++ .../mod/scripts/vscripts/weapon_xp.gnut | 7 + 19 files changed, 533 insertions(+), 4 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 2b95d1a8c..97d993e65 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -16,7 +16,10 @@ void function SetupPlayerPreviousXPValues( entity player ) player.SetPersistentVar( "previousFactionXP[" + xpFaction + "]", FactionGetXP( player, xpFaction ) ) foreach ( string xpTitan in shTitanXP.titanClasses ) + { player.SetPersistentVar( "previousTitanXP[" + xpTitan + "]", TitanGetXP( player, xpTitan ) ) + player.SetPersistentVar( "fdPreviousTitanXP[" + xpTitan + "]", FD_TitanGetXP( player, xpTitan ) ) + } foreach ( string xpWeapon in shWeaponXP.weaponClassNames ) player.SetPersistentVar( GetItemPersistenceStruct( xpWeapon ) + ".previousWeaponXP", WeaponGetXP( player, xpWeapon ) ) @@ -35,6 +38,14 @@ void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) int weaponXp = ScoreEvent_GetXPValueWeapon( event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) int factionXp = ScoreEvent_GetXPValueFaction( event ) + + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) == 1 ) + { + xpValue *= 2 + weaponXp *= 2 + titanXp *= 2 + factionXp *= 2 + } entity weapon = player.GetActiveWeapon() if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 ) @@ -63,5 +74,10 @@ void function AddXP( entity player, int amount ) int newXp = player.GetPersistentVarAsInt( "xp" ) int newLevel = GetLevelForXP( newXp ) if ( newLevel != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForPlayerLevels( player, player.GetPersistentVarAsInt( "gen" ), newLevel ) + } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index af074689c..760daef0b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -246,6 +246,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract", Time() + arrivalTime, file.evacIcon ) + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) //Show the Evac Match Goal for players of the team that lost the match + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 0 ) + // would've liked to use cd_dropship_rescue_side_start length here, but can't since this is done before dropship spawn, can't wait arrivalTime - 4.33333 @@ -280,6 +283,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa { SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) + + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) + SetPlayerChallengeEvacState( player, 0 ) } foreach ( entity player in dropship.s.evacSlots ) @@ -402,7 +408,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa if ( !PlayerInDropship( player, dropship ) ) { if ( player.GetTeam() == dropship.GetTeam() ) + { SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" ) + SetPlayerChallengeEvacState( player, 2 ) + } continue } @@ -417,6 +426,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa Remote_CallFunction_NonReplay( player, "ServerCallback_DisableHudForEvac" ) Remote_CallFunction_NonReplay( player, "ServerCallback_SetClassicSkyScale", dropship.GetEncodedEHandle(), 0.7 ) Remote_CallFunction_NonReplay( player, "ServerCallback_SetMapSettings", 4.0, false, 0.4, 0.125 ) + SetPlayerChallengeEvacState( player, 1 ) // display player [Evacuated] in killfeed foreach ( entity otherPlayer in GetPlayerArray() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 6555c875b..5aee11044 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -4,10 +4,19 @@ void function AddFactionXP( entity player, int amount ) { string faction = GetFactionChoice( player ) int oldLevel = FactionGetLevel( player, faction ) + int FactionXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]" ) + // 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" ) + IncrementPlayerChallengeFactionLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]", FactionXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFactionLevels( player, faction, oldLevel, FactionGetLevel( player, faction ) ) + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index f47ee90f9..7d73c926f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -60,6 +60,7 @@ void function GamemodeAITdm_Init() } ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericTDMChallenge() } // add settings diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 93a3aa168..9cf0021d7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -178,6 +178,12 @@ void function AT_PlayerTitleThink( entity player ) { // Set player money count player.SetTitle( "$" + string( AT_GetPlayerBonusPoints( player ) ) ) + + if( AT_GetPlayerBonusPoints( player ) >= 600 && !HasPlayerCompletedMeritScore( player ) ) //Challenge is: "Earn $600." + { + AddPlayerScore( player, "ChallengeATAssault" ) + SetPlayerChallengeMeritScore( player ) + } } else if ( GetGameState() >= eGameState.WinnerDetermined ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index c5765300f..d8b0c9bdd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -29,6 +29,8 @@ struct { array hardpoints array players + table playerAssaultPoints + table playerDefensePoints } file void function GamemodeCP_Init() @@ -112,11 +114,13 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointDefense", victim ) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_DEFENSE) } else if((victimCP.hardpoint.GetTeam()==victim.GetTeam())||(GetHardpointCappingTeam(victimCP)==victim.GetTeam())) { AddPlayerScore( attacker, "HardpointAssault", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_ASSAULT) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_ASSAULT,0) } } } @@ -127,10 +131,12 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointSnipe", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SNIPE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SNIPE,0) } else{ AddPlayerScore( attacker , "HardpointSiege", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SIEGE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SIEGE,0) } } else if(attackerCP.hardpoint!=null)//Perimeter Defense @@ -138,6 +144,7 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama if(attackerCP.hardpoint.GetTeam()==attacker.GetTeam()) AddPlayerScore( attacker , "HardpointPerimeterDefense", victim) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) } foreach(CP_PlayerStruct player in file.players) //Reset Victim Holdtime Counter @@ -308,6 +315,7 @@ void function CapturePointForTeam(HardpointStruct hardpoint, int Team) if(player.IsPlayer()){ AddPlayerScore(player,"ControlPointCapture") player.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_CAPTURE) + UpdatePlayerScoreForChallenge(player,POINTVALUE_HARDPOINT_CAPTURE,0) } } } @@ -319,12 +327,17 @@ void function GamemodeCP_InitPlayer(entity player) playerStruct.timeOnPoints = [0.0,0.0,0.0] playerStruct.isOnHardpoint = false file.players.append(playerStruct) + file.playerAssaultPoints[player] <- 0 + file.playerDefensePoints[player] <- 0 thread PlayerThink(playerStruct) } void function GamemodeCP_RemovePlayer(entity player) { - + if(player in file.playerAssaultPoints) + delete file.playerAssaultPoints[player] + if(player in file.playerDefensePoints) + delete file.playerDefensePoints[player] foreach(index,CP_PlayerStruct playerStruct in file.players) { if(playerStruct.player==player) @@ -376,11 +389,13 @@ void function PlayerThink(CP_PlayerStruct player) { AddPlayerScore(player.player,"ControlPointAmpedHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_AMPED_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_AMPED_HOLD) } else { AddPlayerScore(player.player,"ControlPointHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_HOLD) } } break @@ -574,6 +589,7 @@ void function HardpointThink( HardpointStruct hardpoint ) { AddPlayerScore(player,"ControlPointAmped") player.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_AMPED) + UpdatePlayerScoreForChallenge(player,0,POINTVALUE_HARDPOINT_AMPED) } } } @@ -714,3 +730,26 @@ string function GetHardpointGroup(entity hardpoint) //Hardpoint Entity B on Home return string(hardpoint.kv.hardpointGroup) } + +void function UpdatePlayerScoreForChallenge(entity player,int assaultpoints = 0,int defensepoints = 0) +{ + if(player in file.playerAssaultPoints) + { + file.playerAssaultPoints[player] += assaultpoints + if( file.playerAssaultPoints[player] >= 1000 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPAssault") + SetPlayerChallengeMeritScore(player) + } + } + + if(player in file.playerDefensePoints) + { + file.playerDefensePoints[player] += defensepoints + if( file.playerDefensePoints[player] >= 500 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPDefense") + SetPlayerChallengeMeritScore(player) + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 9b05c3d42..fefdbcddd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -421,8 +421,15 @@ void function CaptureFlag( entity player, entity flag ) assistList = file.militiaCaptureAssistList foreach( entity assistPlayer in assistList ) + { if ( player != assistPlayer ) AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) + if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + { + AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) + SetPlayerChallengeMeritScore( assistPlayer ) + } + } assistList.clear() @@ -430,6 +437,12 @@ void function CaptureFlag( entity player, entity flag ) MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) @@ -503,6 +516,12 @@ void function TryReturnFlag( entity player, entity flag ) AddPlayerScore( player, "FlagReturn", player ) player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, 1 ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut index 9d8f84b5c..6d0fd3c7b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut @@ -17,6 +17,7 @@ void function GamemodeFRA_Init() ScoreEvent_SetEarnMeterValues( "PilotBatteryPickup", 0.0, 0.34 ) EarnMeterMP_SetPassiveMeterGainEnabled( false ) PilotBattery_SetMaxCount( 3 ) + SetupGenericFFAChallenge() AddCallback_OnPlayerKilled( FRARemoveEarnMeter ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut index 31c85a573..8999231d3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut @@ -8,6 +8,8 @@ struct { float lastDamageInfoTime bool shouldDoHighlights + + table< entity, int > pilotstreak } file void function GamemodeLts_Init() @@ -34,6 +36,37 @@ void function GamemodeLts_Init() ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) ClassicMP_ForceDisableEpilogue( true ) AddCallback_GameStateEnter( eGameState.Playing, WaitForThirtySecondsLeft ) + + AddCallback_OnClientConnected( SetupPlayerLTSChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerLTSChallenges ) //Safety removal of data to prevent crashes + AddCallback_OnPlayerKilled( LTSChallengeForPlayerKilled ) +} + +void function SetupPlayerLTSChallenges( entity player ) +{ + file.pilotstreak[ player ] <- 0 +} + +void function RemovePlayerLTSChallenges( entity player ) +{ + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function LTSChallengeForPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeLTS" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } void function WaitForThirtySecondsLeft() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index d36045a61..768bbde11 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -180,6 +180,12 @@ void function MarkPlayers( entity imcMark, entity militiaMark ) entity livingMark = GetMarked( GetOtherTeam( deadMark.GetTeam() ) ) livingMark.SetPlayerGameStat( PGS_DEFENSE_SCORE, livingMark.GetPlayerGameStat( PGS_DEFENSE_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( livingMark ) ) + { + AddPlayerScore( livingMark, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( livingMark ) + } + // thread this so we don't kill our own thread thread AddTeamScore( livingMark.GetTeam(), 1 ) } @@ -195,8 +201,15 @@ void function UpdateMarksForKill( entity victim, entity attacker, var damageInfo MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, actualAttacker.GetEncodedEHandle() ) svGlobal.levelEnt.Signal( "MarkKilled", { mark = victim } ) - + if ( !isSuicide && attacker.IsPlayer() ) + { attacker.SetPlayerGameStat( PGS_ASSAULT_SCORE, attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index 57355ad8b..c91c27d11 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -19,6 +19,7 @@ void function GamemodePs_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericFFAChallenge() // spawnzone stuff SetShouldCreateMinimapSpawnZones( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut index cb277b004..4617476eb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -18,6 +18,7 @@ void function GamemodeSpeedball_Init() Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericFFAChallenge() AddSpawnCallbackEditorClass( "script_ref", "info_speedball_flag", CreateFlag ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut index 5c0e6feca..61ede2d44 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut @@ -6,6 +6,7 @@ void function GamemodeTdm_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericTDMChallenge() } void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 6b30a3990..3ba843945 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -2,6 +2,11 @@ global function GamemodeTTDM_Init const float TTDMIntroLength = 15.0 +struct +{ + table< entity, int > challengeCount +} file + void function GamemodeTTDM_Init() { Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) @@ -14,6 +19,8 @@ void function GamemodeTTDM_Init() ClassicMP_ForceDisableEpilogue( true ) SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + AddCallback_OnClientConnected( SetupPlayerTTDMChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerTTDMChallenges ) //Safety removal of data to prevent crashes AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode // probably needs scoreevent earnmeter values @@ -56,6 +63,17 @@ void function TTDMIntroShowIntermissionCam( entity player ) thread PlayerWatchesTTDMIntroIntermissionCam( player ) } +void function SetupPlayerTTDMChallenges( entity player ) +{ + file.challengeCount[ player ] <- 0 +} + +void function RemovePlayerTTDMChallenges( entity player ) +{ + if( player in file.challengeCount ) + delete file.challengeCount[ player ] +} + void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) { player.EndSignal( "OnDestroy" ) @@ -79,6 +97,19 @@ void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var d if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() && GetGameState() == eGameState.Playing ) return + if( victim in file.challengeCount ) + file.challengeCount[victim] = 0 + + if( attacker in file.challengeCount ) + { + file.challengeCount[attacker]++ + if( file.challengeCount[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 466a50425..4b866a40f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -1,6 +1,274 @@ global function InitChallenges +global function SetPlayerChallengeEvacState //Hooked in _evac.gnut +global function SetPlayerChallengeMatchWon //Hooked in _score.nut +global function SetPlayerChallengeMatchComplete //Hooked in _score.nut +global function SetPlayerChallengeMeritScore //Up to gamemodes to use this directly if needed +global function IncrementPlayerChallengeTitanLeveledUp //Hooked in titan_xp.gnut +global function IncrementPlayerChallengeWeaponLeveledUp //Hooked in weapon_xp.gnut +global function IncrementPlayerChallengeFactionLeveledUp //Hooked in faction_xp.gnut (invisible but necessary for post-summary menu) +global function RegisterChallenges_OnMatchEnd //Hooked in _gamestate_mp.gnut + +global function HasPlayerCompletedMeritScore //Check from gamemodes to not reapply SetPlayerChallengeMeritScore +global function SetupGenericTDMChallenge //Used by gamemodes which simply adopts the: "Kill 3 Pilots without dying." Challenge +global function SetupGenericFFAChallenge //Used by gamemodes which simply adopts the: "Kill 5 Pilots." Challenge + +struct +{ + table< entity, int > playerTotalMeritCount + table< entity, bool > playerChallenge + table< entity, int > pilotstreak + bool isHappyHourActive +} file + + + + + + +/*============================================================================================================= + __ __ _ _ ____ _ _ _ + | \/ | __ _ | |_ ___ | |__ / ___|| |__ __ _ | || | ___ _ __ __ _ ___ ___ + | |\/| | / _` || __|/ __|| '_ \ | | | '_ \ / _` || || | / _ \| '_ \ / _` | / _ \/ __| + | | | || (_| || |_| (__ | | | | | |___ | | | || (_| || || || __/| | | || (_| || __/\__ \ + |_| |_| \__,_| \__|\___||_| |_| \____||_| |_| \__,_||_||_| \___||_| |_| \__, | \___||___/ + |___/ +=============================================================================================================*/ void function InitChallenges() { +#if (UI && CLIENT) + + SCB_SetCompleteMeritState( 4 ) + SCB_SetEvacMeritState( 4 ) + SCB_SetMeritCount( 4 ) + SCB_SetScoreMeritState( 4 ) + SCB_SetWinMeritState( 4 ) + SCB_SetWeaponMeritCount( -1 ) + SCB_SetTitanMeritCount( -1 ) + +#elseif (SERVER && MP) + + AddCallback_OnClientConnected( SetupPlayerMenuChallenges ) + AddCallback_OnClientDisconnected( RemovePlayerFromChallengePool ) + +#endif +} + +void function SetupPlayerMenuChallenges( entity player ) +{ + file.playerTotalMeritCount[ player ] <- 0 + file.pilotstreak[ player ] <- 0 + file.playerChallenge[ player ] <- false + + thread SetupChallenges_Threaded( player ) +} +void function SetupChallenges_Threaded( entity player ) +{ + WaitFrame() + + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it + Remote_CallFunction_UI( player, "SCB_SetMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", 0 ) +} + +void function SetupGenericTDMChallenge() +{ + AddCallback_OnPlayerKilled( TDMChallenges_OnPlayerKilled ) +} + +void function SetupGenericFFAChallenge() +{ + AddCallback_OnPlayerKilled( FFAChallenges_OnPlayerKilled ) +} + +void function RemovePlayerFromChallengePool( entity player ) +{ + if( player in file.playerChallenge ) + delete file.playerChallenge[ player ] + if( player in file.playerTotalMeritCount ) + delete file.playerTotalMeritCount[ player ] + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function RegisterChallenges_OnMatchEnd() +{ + bool eliteWarpaintRNG = false + + if( RandomIntRange( 0, 100 ) <= 30 ) //30% Chance to trigger akin to vanilla, apply always since all players have paid cosmetics unlocked + eliteWarpaintRNG = true + + foreach( player in GetPlayerArray() ) + { + player.SetPersistentVar( "isPostGameScoreboardValid", true ) + player.SetPersistentVar( "isFDPostGameScoreboardValid", false ) //FD itself overrides this right after when match ends + SetUIVar( level, "showGameSummary", true ) + + if( eliteWarpaintRNG ) + SetPlayerChallengeSquadLeader( player ) + + if( ShouldAwardHappyHourBonus( player ) ) + { + AddPlayerScore( player, "HappyHourBonus" ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.HAPPY_HOUR + "]", 5 ) //The XP Given from Happy Hour Score is 5 merits + } + } +} + +void function TDMChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() ) + { + if( victim in file.pilotstreak ) + file.pilotstreak[victim] = 0 + if( attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 3 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + } +} + +void function FFAChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 5 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengePVPKillCount" ) + SetPlayerChallengeMeritScore( attacker ) + } + } +} + +bool function HasPlayerCompletedMeritScore( entity player ) +{ + Assert( player in file.playerChallenge, player + " is not registered in the challenge pool hooks." ) + return file.playerChallenge[ player ] +} + + + + + + + +/*============================================================================================================= + ____ _ _ _ _ + / ___| __ _ _ __ ___ ___ _ __ ___ ___ __| | ___ | | | | ___ ___ | | __ ___ + | | _ / _` || '_ ` _ \ / _ \| '_ ` _ \ / _ \ / _` | / _ \ | |_| | / _ \ / _ \ | |/ // __| + | |_| || (_| || | | | | || __/| | | | | || (_) || (_| || __/ | _ || (_) || (_) || < \__ \ + \____| \__,_||_| |_| |_| \___||_| |_| |_| \___/ \__,_| \___| |_| |_| \___/ \___/ |_|\_\|___/ + +=============================================================================================================*/ + +void function SetPlayerChallengeEvacState( entity player, int successEvac = 0 ) +{ + if( successEvac == 0 ) //Evac Ship destroyed + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 2 ) + + else if( successEvac == 1 ) //Player itself managed to evac + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.EVAC + "]", 1 ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + + else if( successEvac == 2 ) //Team managed to evac + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 3 ) +} + +void function SetPlayerChallengeMatchWon( entity player, bool playerWon ) +{ + if( playerWon ) + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_VICTORY + "]", 1 ) + player.SetPersistentVar( "matchWin", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + else + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", -1 ) +} + +void function SetPlayerChallengeMatchComplete( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_COMPLETED + "]", 1 ) + player.SetPersistentVar( "matchComplete", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function SetPlayerChallengeSquadLeader( entity player ) +{ + if( !ProgressionEnabledForPlayer( player ) ) + return + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderDoubleXP" ) + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", player.GetEncodedEHandle() ) + player.SetPersistentVar( "matchSquadBonus", true ) + Player_GiveDoubleXP( player, 1 ) + foreach( entity teamplayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) + { + if( teamplayer == player ) + continue + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", teamplayer.GetEncodedEHandle() ) + } +} + +void function SetPlayerChallengeMeritScore( entity player ) +{ + if( !HasPlayerCompletedMeritScore( player ) ) + { + file.playerChallenge[ player ] = true + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.SCORE_MILESTONE + "]", 1 ) + player.SetPersistentVar( "matchScoreEvent", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } +} + +void function IncrementPlayerChallengeTitanLeveledUp( entity player ) +{ + player.p.meritData.titanMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", player.p.meritData.titanMerits++ ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeWeaponLeveledUp( entity player ) +{ + player.p.meritData.weaponMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", player.p.meritData.weaponMerits ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeFactionLeveledUp( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 5cc096f29..5eba24acd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -396,6 +396,7 @@ void function GameStateEnter_WinnerDetermined_Threaded() } else { + RegisterChallenges_OnMatchEnd() if ( ClassicMP_ShouldRunEpilogue() ) { ClassicMP_SetupEpilogue() @@ -834,11 +835,44 @@ void function SetWinner( int team, string winningReason = "", string losingReaso } SetGameState( eGameState.WinnerDetermined ) + ScoreEvent_RoundComplete( team ) } else + { SetGameState( eGameState.WinnerDetermined ) - - ScoreEvent_MatchComplete( team ) + ScoreEvent_MatchComplete( team ) + + array players = GetPlayerArray() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( GAMETYPE ) + if ( compareFunc != null ) + { + players.sort( compareFunc ) + int playerCount = players.len() + int currentPlace = 1 + for ( int i = 0; i < 3; i++ ) + { + if ( i >= playerCount ) + continue + + if ( i > 0 && compareFunc( players[i - 1], players[i] ) != 0 ) + currentPlace += 1 + + switch( currentPlace ) + { + case 1: + UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 2: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 3: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + } + } + } + } } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index aba1d5401..2a4c4282c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -8,6 +8,7 @@ global function ScoreEvent_TitanDoomed global function ScoreEvent_TitanKilled global function ScoreEvent_NPCKilled global function ScoreEvent_MatchComplete +global function ScoreEvent_RoundComplete global function ScoreEvent_SetEarnMeterValues global function ScoreEvent_SetupEarnMeterValuesForMixedModes @@ -287,8 +288,24 @@ void function ScoreEvent_MatchComplete( int winningTeam ) foreach( entity player in GetPlayerArray() ) { AddPlayerScore( player, "MatchComplete" ) + SetPlayerChallengeMatchComplete( player ) if ( player.GetTeam() == winningTeam ) + { AddPlayerScore( player, "MatchVictory" ) + SetPlayerChallengeMatchWon( player, true ) + } + else + SetPlayerChallengeMatchWon( player, false ) + } +} + +void function ScoreEvent_RoundComplete( int winningTeam ) +{ + foreach( entity player in GetPlayerArray() ) + { + AddPlayerScore( player, "RoundComplete" ) + if ( player.GetTeam() == winningTeam ) + AddPlayerScore( player, "RoundVictory" ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut index 0436a393c..847881b58 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut @@ -1,17 +1,39 @@ global function AddTitanXP +global function AddFDTitanXP void function AddTitanXP( entity player, int amount ) { string titan = GetActiveTitanLoadout( player ).titanClass int oldLevel = TitanGetLevel( player, titan ) + int TitanXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]" ) // increment xp player.SetPersistentVar( "titanXP[" + titan + "]", min( TitanGetXP( player, titan ) + amount, TitanGetMaxXP( titan ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_TitanXPAdded", shTitanXP.titanClasses.find( titan ), TitanGetXP( player, titan ), 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" ) + IncrementPlayerChallengeTitanLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]", TitanXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForTitanLevels( player, titan, oldLevel, TitanGetLevel( player, titan ) ) } +} + +void function AddFDTitanXP( entity player, int fdXPamount ) +{ + string titanRef = GetActiveTitanLoadout( player ).titanClass + + player.SetPersistentVar( "fdTitanXP[" + titanRef + "]", FD_TitanGetPreviousXP( player, titanRef ) + fdXPamount ) + int startingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetPreviousXP( player, titanRef ) ) + int endingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetXP( player, titanRef ) ) + + Player_GiveFDUnlockPoints( player, endingLevel - startingLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFDTitanLevels( player, titanRef, startingLevel, endingLevel ) } \ 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 4e25e3019..0b0084b3c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut @@ -6,15 +6,22 @@ void function AddWeaponXP( entity player, int amount ) entity activeWeapon = player.GetActiveWeapon() string weaponClassname = activeWeapon.GetWeaponClassName() int oldLevel = WeaponGetLevel( player, weaponClassname ) + int WeaponXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]" ) // increment xp player.SetPersistentVar( GetItemPersistenceStruct( weaponClassname ) + ".weaponXP", min( WeaponGetXP( player, weaponClassname ) + amount, WeaponGetMaxXP( weaponClassname ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponXPAdded", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetXP( player, weaponClassname ), 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" ) + IncrementPlayerChallengeWeaponLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]", WeaponXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForWeaponLevels( player, weaponClassname, oldLevel, WeaponGetLevel( player, weaponClassname ) ) } // proscreen -- 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index b0e579cff..52009f4fd 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(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 52009f4fd..0bb6b328a 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 0198d3f99c40ab641c85fff62b62276407e0dfc3 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 5 Jul 2024 19:02:11 -0300 Subject: Unfuck the Spawns (#808) 1. Get rid of the odd logic of limiting the algorithm to 3 spawn points 2. Changes the specific CTF algorithm to calculate the spawn points from the flag bases themselves rather than the initial spawn points which was causing severe inconsistencies. 3. Remove some checks in regards to map side swapping when matches reaches half-times due to odd behaviour in native code 4. Mitigate usage of `GetOtherTeam` for certain checks since that function might return Unreachable when it's a gamemode with more than 2 Teams and intentionally script crash the server. --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 31 ++++++-------- .../mod/scripts/vscripts/mp/spawn.nut | 48 +++++++++------------- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index fefdbcddd..97addc241 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -75,27 +75,20 @@ void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, in bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) { // ensure spawnpoints aren't too close to enemy base + vector allyFlagSpot + vector enemyFlagSpot + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + { + if( spawn.GetTeam() == team ) + allyFlagSpot = spawn.GetOrigin() + else + enemyFlagSpot = spawn.GetOrigin() + } - if ( HasSwitchedSides() ) - team = GetOtherTeam( team ) - - array startSpawns = SpawnPoints_GetPilotStart( team ) - array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( team ) ) - - vector averageFriendlySpawns - vector averageEnemySpawns - - foreach ( entity spawn in startSpawns ) - averageFriendlySpawns += spawn.GetOrigin() - - averageFriendlySpawns /= startSpawns.len() - - foreach ( entity spawn in enemyStartSpawns ) - averageEnemySpawns += spawn.GetOrigin() - - averageEnemySpawns /= startSpawns.len() + if( Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) > Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) ) + return false - return Distance2D( spawnpoint.GetOrigin(), averageEnemySpawns ) / Distance2D( averageFriendlySpawns, averageEnemySpawns ) > 0.35 + return true } void function CTFInitPlayer( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index 4956375bd..d64e3a5b6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -130,7 +130,7 @@ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnp { int team = player.GetTeam() if ( HasSwitchedSides() ) - team = GetOtherTeam( team ) + team = ( team == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA array spawnpoints if ( useStartSpawnpoint ) @@ -181,29 +181,19 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) foreach ( entity spawnpoint in spawnpoints ) { if ( IsSpawnpointValid( spawnpoint, player.GetTeam() ) ) - { validSpawns.append( spawnpoint ) - - if ( validSpawns.len() == 3 ) // arbitrary small sample size - break - } } - if ( validSpawns.len() == 0 ) + if ( !validSpawns.len() ) { // no valid spawns, very bad, so dont care about spawns being valid anymore print( "found no valid spawns! spawns may be subpar!" ) foreach ( entity spawnpoint in spawnpoints ) - { validSpawns.append( spawnpoint ) - - if ( validSpawns.len() == 3 ) // arbitrary small sample size - break - } } // last resort - if ( validSpawns.len() == 0 ) + if ( !validSpawns.len() ) { print( "map has literally 0 spawnpoints, as such everything is fucked probably, attempting to use info_player_start if present" ) entity start = GetEnt( "info_player_start" ) @@ -215,7 +205,7 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) } } - return validSpawns[ RandomInt( validSpawns.len() ) ] // slightly randomize it + return validSpawns.getrandom() // slightly randomize it } bool function IsSpawnpointValid( entity spawnpoint, int team ) @@ -232,15 +222,18 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } + if( IsFFAGame() && !spawnpoint.IsVisibleToEnemies( team ) ) + return true + int compareTeam = spawnpoint.GetTeam() - if ( HasSwitchedSides() && ( compareTeam == TEAM_MILITIA || compareTeam == TEAM_IMC ) ) - compareTeam = GetOtherTeam( compareTeam ) - + if ( HasSwitchedSides() ) + compareTeam = ( compareTeam == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA + foreach ( bool functionref( entity, int ) customValidationRule in file.customSpawnpointValidationRules ) if ( !customValidationRule( spawnpoint, team ) ) return false - if ( spawnpoint.GetTeam() > 0 && compareTeam != team && !IsFFAGame() ) + if ( spawnpoint.GetTeam() > 0 && compareTeam != team ) return false if ( spawnpoint.IsOccupied() ) @@ -261,13 +254,12 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } - const minEnemyDist = 1000.0 // about 20 meters? - // in rsquirrel extend returns null unlike in vanilla squirrel - array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) - spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) ) - foreach ( entity blocker in spawnBlockers ) - if ( blocker.GetTeam() != team ) - return false + const minEnemyDist = 1200.0 + array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) + spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) + spawnBlockers.extend( GetNPCArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) + if ( spawnBlockers.len() ) + return false // los check return !spawnpoint.IsVisibleToEnemies( team ) @@ -399,11 +391,9 @@ void function InitPreferSpawnNodes() // frontline void function RateSpawnpoints_Frontline( int checkClass, array spawnpoints, int team, entity player ) { + float rating = RandomFloatRange( 0.0, 100.0 ) foreach ( entity spawnpoint in spawnpoints ) - { - float rating = spawnpoint.CalculateFrontlineRating() - spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating > 0 ? rating * 0.25 : rating ) - } + spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating ) } // spawnzones -- cgit v1.2.3 From f3fa134ff6508f88cf966b92f6690b6f8b58fea1 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:30:01 -0400 Subject: Fix `cl_earn_meter` crash when Core does not exist during Core Active state (#494) Fix crash when getting core weapon --- Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut b/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut index 16908362c..3971d2bec 100644 --- a/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut @@ -335,7 +335,11 @@ void function EarnMeter_Update() break entity soul = player.GetTitanSoul() - entity core = player.GetOffhandWeapons()[3] + entity core = player.GetOffhandWeapon( OFFHAND_EQUIPMENT ) + + if ( !IsValid( core ) ) + break + string coreName = core.GetWeaponClassName() array coreMods = core.GetMods() -- cgit v1.2.3 From 852f3bcb04f7dfbf8f41676d47c01d4d6fbf084e Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:02:53 -0300 Subject: Rework Intro Dropship Script to avoid player overlap (#809) This overhaul makes the Dropships behave consistently now like vanilla and players will only start overlapping each other when both Dropships are full, otherwise code will always attempt to populate them properly instead. --- .../vscripts/mp/_classic_mp_dropship_intro.gnut | 177 ++++++++++----------- 1 file changed, 86 insertions(+), 91 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 23ae37a17..7b6c7e9f8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -26,18 +26,9 @@ const int MAX_DROPSHIP_PLAYERS = 4 global const float DROPSHIP_INTRO_LENGTH = 15.0 // TODO tweak this -struct IntroDropship -{ - entity dropship - - int playersInDropship - entity[MAX_DROPSHIP_PLAYERS] players -} - struct { - // these used to be IntroDropship[2]s but i wanted to be able to use array.getrandom so they have to be actual arrays - array militiaDropships - array imcDropships + table< entity, array > militiaDropships + table< entity, array > imcDropships float introStartTime } file @@ -52,7 +43,12 @@ void function ClassicMP_DefaultDropshipIntro_Setup() void function DropshipIntro_OnClientConnected( entity player ) { if ( GetGameState() == eGameState.Prematch ) - thread SpawnPlayerIntoDropship( player ) + { + if( PlayerCanSpawn( player ) ) + DoRespawnPlayer( player, null ) + + PutPlayerInDropship( player ) + } } void function OnPrematchStart() @@ -62,11 +58,11 @@ void function OnPrematchStart() print( "starting dropship intro!" ) file.introStartTime = Time() - // make 2 empty dropship structs per team - IntroDropship emptyDropship + // Clear Dropship arrays of Teams for Match Restarts (i.e Half-Times) file.militiaDropships.clear() file.imcDropships.clear() + // Try to gather all possible Dropship spawn points for Team array validDropshipSpawns array dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) foreach ( entity dropshipSpawn in dropshipSpawns ) @@ -78,47 +74,47 @@ void function OnPrematchStart() validDropshipSpawns.append( dropshipSpawn ) } - // if no dropship spawns for this mode, just allow any dropship spawns + // Use any spawn point if not enough valid for this Gamemode exists if ( validDropshipSpawns.len() < 2 ) validDropshipSpawns = dropshipSpawns // spawn dropships foreach ( entity dropshipSpawn in validDropshipSpawns ) { - // todo: possibly make this only spawn dropships if we've got enough players to need them int createTeam = HasSwitchedSides() ? GetOtherTeam( dropshipSpawn.GetTeam() ) : dropshipSpawn.GetTeam() - array teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships + table< entity, array > teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships if ( teamDropships.len() >= 2 ) - continue + break - // create entity entity dropship = CreateDropship( createTeam, dropshipSpawn.GetOrigin(), dropshipSpawn.GetAngles() ) - - teamDropships.append( clone emptyDropship ) - teamDropships[ teamDropships.len() - 1 ].dropship = dropship - AddAnimEvent( dropship, "dropship_warpout", WarpoutEffect ) + dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + if ( dropshipSpawn.GetTeam() == TEAM_IMC ) + dropship.SetValueForModelKey( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) DispatchSpawn( dropship ) - // have to do this after dispatch otherwise it won't work for some reason - // weirdly enough, tf2 actually does use different dropships for imc and militia, despite these concepts not really being a thing for players in tf2 - // probably was just missed by devs, but keeping it in for accuracy + dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) if ( dropshipSpawn.GetTeam() == TEAM_IMC ) dropship.SetModel( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) - else - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + + teamDropships[ dropship ] <- [ null, null, null, null ] thread PlayAnim( dropship, "dropship_classic_mp_flyin" ) } + // Populate Dropships foreach ( entity player in GetPlayerArray() ) { if ( !IsPrivateMatchSpectator( player ) ) - thread SpawnPlayerIntoDropship( player ) + { + if( PlayerCanSpawn( player ) ) + DoRespawnPlayer( player, null ) + + PutPlayerInDropship( player ) + } else RespawnPrivateMatchSpectator( player ) } @@ -128,68 +124,69 @@ void function OnPrematchStart() void function EndIntroWhenFinished() { - wait 15.0 + wait DROPSHIP_INTRO_LENGTH ClassicMP_OnIntroFinished() } -void function SpawnPlayerIntoDropship( entity player ) +void function PutPlayerInDropship( entity player ) { - player.EndSignal( "OnDestroy" ) + //Find the player's dropship and seat + table< entity, array > teamDropships + if ( player.GetTeam() == TEAM_MILITIA ) + teamDropships = file.militiaDropships + else + teamDropships = file.imcDropships + + entity playerDropship + array< int > availableShipSlots + array< entity > introDropships + int playerDropshipIndex = RandomInt( MAX_DROPSHIP_PLAYERS ) + foreach( dropship, playerslot in teamDropships ) + { + introDropships.append( dropship ) + for ( int i = 0; i < MAX_DROPSHIP_PLAYERS; i++ ) + { + if ( !IsValidPlayer( playerslot[i] ) ) + availableShipSlots.append( i ) + } + + if( !availableShipSlots.len() ) + continue + + int slotPick = availableShipSlots.getrandom() + playerslot[slotPick] = player + playerDropship = dropship + playerDropshipIndex = slotPick + break + } + + if( !IsAlive( playerDropship ) ) //If we're at this point, we have more players than we do dropships, so just pick a random one + playerDropship = introDropships.getrandom() + + thread SpawnPlayerIntoDropship( player, playerDropshipIndex, playerDropship ) +} - if ( IsAlive( player ) ) - player.Die() // kill them so we don't have any issues respawning them later +void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, entity playerDropship ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) - player.s.dropshipIntroIsJumping <- false - OnThreadEnd( function() : ( player ) + OnThreadEnd( function() : ( player, playerDropshipIndex, playerDropship ) { if ( IsValid( player ) ) { player.ClearParent() ClearPlayerAnimViewEntity( player ) - - if ( !player.s.dropshipIntroIsJumping ) - { - player.MovementEnable() - player.EnableWeaponViewModel() - RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - } + } + if( IsAlive( playerDropship ) ) + { + if ( playerDropship.GetTeam() == TEAM_MILITIA ) + file.militiaDropships[ playerDropship ][ playerDropshipIndex ] = null + else + file.imcDropships[ playerDropship ][ playerDropshipIndex ] = null } }) - WaitFrame() - - player.EndSignal( "OnDeath" ) - - // find the player's dropship and seat - array teamDropships - if ( player.GetTeam() == TEAM_MILITIA ) - teamDropships = file.militiaDropships - else - teamDropships = file.imcDropships - - IntroDropship playerDropship - int playerDropshipIndex = -1 - foreach ( IntroDropship dropship in teamDropships ) - for ( int i = 0; i < dropship.players.len(); i++ ) - if ( dropship.players[ i ] == null ) - { - playerDropship = dropship - playerDropshipIndex = i - - dropship.players[ i ] = player - break - } - - if ( playerDropship.dropship == null ) - { - // if we're at this point, we have more players than we do dropships, so just pick a random one - playerDropship = teamDropships.getrandom() - playerDropshipIndex = RandomInt( MAX_DROPSHIP_PLAYERS ) - } - - // respawn player and holster their weapons so they aren't out - if ( !IsAlive( player ) ) - player.RespawnPlayer( null ) HolsterAndDisableWeapons(player) player.DisableWeaponViewModel() @@ -208,9 +205,7 @@ void function SpawnPlayerIntoDropship( entity player ) idleSequence.viewConeFunction = ViewConeRampFree idleSequence.hideProxy = true idleSequence.setInitialTime = Time() - file.introStartTime - thread FirstPersonSequence( idleSequence, player, playerDropship.dropship ) - WaittillAnimDone( player ) - + waitthread FirstPersonSequence( idleSequence, player, playerDropship ) // todo: possibly rework this to actually get the time the idle anim takes and start the starttime of the jump sequence for very late joiners using that // jump sequence @@ -218,13 +213,12 @@ void function SpawnPlayerIntoDropship( entity player ) jumpSequence.firstPersonAnim = DROPSHIP_JUMP_ANIMS_POV[ playerDropshipIndex ] jumpSequence.thirdPersonAnim = DROPSHIP_JUMP_ANIMS[ playerDropshipIndex ] jumpSequence.attachment = "ORIGIN" + jumpSequence.viewConeFunction = ViewConeFree jumpSequence.setInitialTime = max( 0.0, Time() - ( file.introStartTime + 11.0 ) ) // pretty sure you should do this with GetScriptedAnimEventCycleFrac? // idk unsure how to use that, all i know is getsequenceduration > the length it actually should be - thread FirstPersonSequence( jumpSequence, player, playerDropship.dropship ) - WaittillAnimDone( player ) // somehow this is better than just waiting for the blocking FirstPersonSequence call? + waitthread FirstPersonSequence( jumpSequence, player, playerDropship ) - player.s.dropshipIntroIsJumping <- true thread PlayerJumpsFromDropship( player ) } @@ -244,16 +238,17 @@ void function PlayerJumpsFromDropship( entity player ) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) - - // wait for intro timer to be fully done - wait ( file.introStartTime + DROPSHIP_INTRO_LENGTH ) - Time() - player.MovementDisable() // disable all movement but let them look around still - player.ConsumeDoubleJump() // movementdisable doesn't prevent double jumps // wait for player to hit the ground - wait 0.1 // assume players will never actually hit ground before this + player.ClearParent() + WaitFrame() + player.SetVelocity( < 0, 0, -100 > ) // Toss players a bit down so it makes a smoother transition when jumping off the Dropship + player.MovementDisable() // Disable all movement but let them look around still + player.ConsumeDoubleJump() // MovementDisable doesn't prevent double jumps + WaitFrame() while ( !player.IsOnGround() && !player.IsWallRunning() && !player.IsWallHanging() ) // todo this needs tweaking WaitFrame() - TryGameModeAnnouncement( player ) + if ( GetRoundsPlayed() == 0 ) //Intro is announced only for the first round in Vanilla as certain gamemodes have different announcements for rounds restarts + TryGameModeAnnouncement( player ) } -- cgit v1.2.3 From 2849218b47666c5611e3de591fc5f77a77a807eb Mon Sep 17 00:00:00 2001 From: Zanieon Date: Sun, 7 Jul 2024 00:06:51 +0200 Subject: Fix formatting in dropship intro taken from #809 --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 7b6c7e9f8..8b75a982a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -187,7 +187,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e } }) - HolsterAndDisableWeapons(player) + HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() // hide hud and fade screen out from black @@ -234,7 +234,7 @@ void function PlayerJumpsFromDropship( entity player ) // show weapon viewmodel and hud and let them move again player.MovementEnable() player.EnableWeaponViewModel() - DeployAndEnableWeapons(player) + DeployAndEnableWeapons( player ) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) -- cgit v1.2.3 From dc0074d24923ec2e9cc3e4b9129c53730f338dd7 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:12:30 +0200 Subject: Play battle chatter during dropship intro (#810) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 8b75a982a..22dc1e675 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -217,6 +217,11 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e jumpSequence.setInitialTime = max( 0.0, Time() - ( file.introStartTime + 11.0 ) ) // pretty sure you should do this with GetScriptedAnimEventCycleFrac? // idk unsure how to use that, all i know is getsequenceduration > the length it actually should be + #if BATTLECHATTER_ENABLED + if( playerDropshipIndex == 0 ) + PlayBattleChatterLine( player, "bc_pIntroChat" ) + #endif + waitthread FirstPersonSequence( jumpSequence, player, playerDropship ) thread PlayerJumpsFromDropship( player ) -- cgit v1.2.3 From 34bd1b1ae6b9b232ce85e2ff3b7192c141a31853 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:15:39 +0200 Subject: Mitigate muted audio during dropship intro (#811) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 22dc1e675..3d8abd9d6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -189,6 +189,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() + UnMuteAll( player ) // hide hud and fade screen out from black AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) -- cgit v1.2.3 From 1c54129e11b496f049764d0bc7feed53a6341a57 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:19:21 +0200 Subject: Mitigate muted audio during dropship intro (#812) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 3d8abd9d6..5ab14121f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -190,6 +190,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() UnMuteAll( player ) + StopSoundOnEntity( player, "Duck_For_FrontierDefenseTitanSelectScreen" ) // hide hud and fade screen out from black AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) -- cgit v1.2.3 From e898b0a17d817bf36189ed9c5499ded4cefdbb26 Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:49:01 -0300 Subject: Prevent suicides registering progression stats (#813) Prevent suicides registering stats --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 101d5e4ef..674923e71 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -334,6 +334,10 @@ void function OnPlayerOrNPCKilled( entity victim, entity attacker, var damageInf thread SetLastPosForDistanceStatValid_Threaded( victim, false ) HandleDeathStats( victim, attacker, damageInfo ) + + if( victim == attacker ) //Suicides are registering stats, afaik vanilla ignores them + return + HandleKillStats( victim, attacker, damageInfo ) HandleWeaponKillStats( victim, attacker, damageInfo ) HandleTitanStats( victim, attacker, damageInfo ) -- cgit v1.2.3 From de01dc34c66a57eb77b68e1403f5503e84802df8 Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:53:51 -0300 Subject: Fix oversight in "Total MVP" not registering in regards to progression (#814) The game have an extra stat especifically to count the total amount of times a player has been MVP in all matches, while the other mvp stat which i previously thought to be absolutely is only registered per map, not globally. --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 5eba24acd..f7c398d97 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -861,6 +861,7 @@ void function SetWinner( int team, string winningReason = "", string losingReaso { case 1: UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "mvp_total" ) UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) break case 2: -- 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(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index e6518febb..eaec0cc72 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 5570b0471..457779eb7 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 cf410ff29..56402ca90 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 e76789be99d43242bb06e148c1e32485217ce79a Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 8 Jul 2024 05:52:50 -0300 Subject: Hotfix for Intro Dropship (#816) to fix script error --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 5ab14121f..c3bdf01c6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -196,7 +196,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) ScreenFadeFromBlack( player, 0.5, 0.5 ) // faction leaders are done clientside, spawn them here - Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.dropship.GetEncodedEHandle(), file.introStartTime ) + Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.GetEncodedEHandle(), file.introStartTime ) // do firstperson sequence FirstPersonSequenceStruct idleSequence -- cgit v1.2.3 From 52e007ac0634ee5dd9376bd82ae76af6fd5f44d7 Mon Sep 17 00:00:00 2001 From: fvnkhead <98965760+fvnkhead@users.noreply.github.com> Date: Thu, 11 Jul 2024 20:31:29 +0300 Subject: Check player validity in `SetupChallenges_Threaded` (#819) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 4b866a40f..ffefc3b4e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -66,6 +66,9 @@ void function SetupPlayerMenuChallenges( entity player ) void function SetupChallenges_Threaded( entity player ) { WaitFrame() + + if ( !IsValid( player ) ) + return Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it -- cgit v1.2.3 From f586107e62dc0dfa09f1b08cbf418d31d0346886 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 12 Jul 2024 17:45:49 -0300 Subject: Change `IsValid()` check to `EndSignal()` (#820) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index ffefc3b4e..016097f20 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -65,10 +65,9 @@ void function SetupPlayerMenuChallenges( entity player ) void function SetupChallenges_Threaded( entity player ) { + player.EndSignal( "OnDestroy" ) + WaitFrame() - - if ( !IsValid( player ) ) - return Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it -- cgit v1.2.3 From 26d649fa7bf53e83758dd824297f402c8b9d174e Mon Sep 17 00:00:00 2001 From: William Miller Date: Wed, 17 Jul 2024 06:10:06 -0300 Subject: Fix "Kills by Auto-Titan" not registering at all (#817) This is a quick fix that will redirect the attacker entity to a proper NPC owned by the player. By default behavior of the game, attackers are always the final entity in the owning hiearchy, which is always a player if owned NPCs kills enemies. This change properly redirects the code to the correct NPC whenever they have an owning player. --- .../mod/scripts/vscripts/mp/_stats.nut | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 674923e71..74a9088b8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -493,23 +493,32 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo ) // get the player and it's pet titan entity player entity playerPetTitan - if ( attacker.IsPlayer() ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + + if ( IsValid( inflictor ) ) { - // the player is just the attacker - player = attacker - playerPetTitan = player.GetPetTitan() + if ( inflictor.IsProjectile() && IsValid( inflictor.GetOwner() ) ) // Attackers are always the final entity in the owning hierarchy, projectile owners though migh be a player's NPC minion (i.e Auto-Titans) + attacker = inflictor.GetOwner() + + else if ( inflictor.IsNPC() ) // NPCs are bypassed as Attackers if they are owned by players, instead they become just inflictors + attacker = inflictor } - else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + + if ( attacker.IsNPC() ) { - // the attacker is the player's auto titan + if ( !attacker.IsTitan() ) // Normal NPCs case + return + + if ( !IsPetTitan( attacker ) ) // NPC Titans case + return + player = attacker.GetTitanSoul().GetBossPlayer() playerPetTitan = attacker } + else if ( attacker.IsPlayer() ) // Still checks this because worldspawn might be the attacker + player = attacker else - { - // attacker could be something like an NPC, or worldspawn return - } // check things once, for performance int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) -- 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(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 457779eb7..b6f5ba261 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(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index b7fadeaff..798d603e0 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 diff --git a/Northstar.Client/keyvalues/resource/fontfiletable.txt b/Northstar.Client/keyvalues/resource/fontfiletable.txt new file mode 100644 index 000000000..f0b91c07e --- /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 b42381341..000000000 --- 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(-) diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 1148d3e58..889432d73 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 eaec0cc72..baceed225 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 4d299362d..3b81c7f9a 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 4f17dedf2..22cdffcf9 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(-) 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 b89e665b8..acc6bb36f 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 22cdffcf9..5517843e8 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 d130ab7d957693b0c83b9acd130bcec02928e7a2 Mon Sep 17 00:00:00 2001 From: Creamy <88903493+CozyMerc@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:46:27 +0200 Subject: Update tbshotgun mdls with skinfamillies/lods, add pbr materials (#796) See pull request description for highly detailed changelog. --- .../ptpov_shotgun_doublebarrel.mdl | Bin 1268987 -> 1277105 bytes .../w_shotgun_doublebarrel.mdl | Bin 743828 -> 924194 bytes .../paks/mp_weapon_shotgun_doublebarrel.rpak | Bin 264566 -> 197556 bytes .../paks/mp_weapon_shotgun_doublebarrel.starpak | Bin 16539736 -> 9605416 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl index 2fcc34390..82b58becc 100644 Binary files a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl index 137d985d6..9e6603745 100644 Binary files a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak index 3a714d3b6..440f16aef 100644 Binary files a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak differ diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak index 3bd344679..93e59c892 100644 Binary files a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak differ -- 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 56402ca90..91a0dedee 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(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6f5ba261..75a5faad6 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(-) 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 3b81c7f9a..4968714c7 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 5517843e8..1396dd22f 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(-) 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 acc6bb36f..b89e665b8 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 1396dd22f..cdeb8b3e0 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 94fa6608c72a051929f7f579d366c18e1ec75a26 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:01:02 +0200 Subject: Add option to manually run merge conflict label action (#832) so that labels can easily be updated if need be --- .github/workflows/merge-conflict-auto-label.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml index e237726af..372687fc7 100644 --- a/.github/workflows/merge-conflict-auto-label.yml +++ b/.github/workflows/merge-conflict-auto-label.yml @@ -1,5 +1,6 @@ name: Merge Conflict Auto Label on: + workflow_dispatch: # Manual run push: branches: - main -- cgit v1.2.3 From fe8972fe40fd4cd63adae1c000107ae3d012cf91 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:06:27 +0200 Subject: Run merge conflict label action periodically (#833) --- .github/workflows/merge-conflict-auto-label.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml index 372687fc7..abb7cabde 100644 --- a/.github/workflows/merge-conflict-auto-label.yml +++ b/.github/workflows/merge-conflict-auto-label.yml @@ -4,6 +4,8 @@ on: push: branches: - main + schedule: + - cron: "10 21 * * *" # Runs at 21:10; time was chosen based on contributor activity and low GitHub Actions cron load. jobs: triage: -- 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(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 0bb6b328a..9444a39e3 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 From 7aa3958ccd8e32970736654dfae0c7a87f0798bb Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Wed, 14 Aug 2024 09:19:02 -0400 Subject: Support multiple spaces in custom damage source ID display names (#835) Replace all spaces --- Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut index 4987ee015..bae0116ef 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut @@ -727,7 +727,7 @@ bool function RegisterWeaponDamageSourceInternal( int id, string newVal, string damageSourceID[ newVal ] <- id file.damageSourceIDToString[ id ] <- newVal file.damageSourceIDToName[ id ] <- stringVal - file.customDamageSourceIDList.extend( [ id.tostring(), newVal, StringReplace( stringVal, " ", MESSAGE_SPACE_PADDING ) ] ) + file.customDamageSourceIDList.extend( [ id.tostring(), newVal, StringReplace( stringVal, " ", MESSAGE_SPACE_PADDING, true ) ] ) return true } @@ -773,6 +773,6 @@ void function ReceiveNewDamageSourceIDs( array args ) { // IDs are inserted to the custom list in triplets, so we can trust these indices exist and the loop will end properly for ( int i = 0; i < args.len(); i += 3 ) - RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " " ) ) + RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " ", true ) ) } #endif -- cgit v1.2.3 From 0466de8fc58c5a9bb2f5f027234c579d6ba2d0f2 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:06:11 +0200 Subject: Translations update from Weblate (#837) Translated using Weblate (Italian) Currently translated at 99.6% (312 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/it/ Co-authored-by: Nostromo --- .../northstar_client_localisation_italian.txt | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index 38e67dea4..089edf35b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -316,7 +316,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "UNAUTHORIZED_PWD" "Password errata" "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" + "INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto, prova a riavviare l'App EA" "JSON_PARSE_ERROR" "Errore nell'analisi della risposta json" "UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata" @@ -380,5 +380,42 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "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." + "player_force_respawn" "Respawn Forzato" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Attivare Progressione?" + "TOGGLE_PROGRESSION" "Attiva/Disattiva Progressione" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Attiva/Disattiva Progressione" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disattivare la Progressione?" + "AUTHENTICATION_FAILED_BODY" "Fallimento nell'autenticare con Atlas" + "AUTHENTICATION_FAILED_ERROR_CODE" "Codice di errore: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Aiuto" + "AUTHENTICATION_FAILED_HEADER" "Autenticazione Fallita" + "MISSING_MOD" "Mod mancante \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(Mod non verificata, non è stato possibile il download automatico)" + "MOD_DL_DISABLED" "(Il download automatico delle mod è disabilitato)" + "DOWNLOADING_MOD_TEXT" "Download %s1 v%s2..." + "CHECKSUMING_TEXT" "Verifica contenuti %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Estrazione mod (%s1%)" + "FAILED_DOWNLOADING" "Download della mod fallito" + "NO_DISK_SPACE_AVAILABLE" "Non c'è abbastanza spazio sul disco." + "MOD_FETCHING_FAILED_GENERAL" "Estrazione mod fallita. Controlla i file di log per più dettagli." + "DOWNLOADING_MOD_TITLE" "Download mod in corso" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Download in corso della mod (%s1%)" + "FAILED_READING_ARCHIVE" "C'è stato un errore durante la lettura dell'archivio della mod." + "FAILED_WRITING_TO_DISK" "C'è stato un errore durante l'estrazione della mod al filesystem." + "MOD_FETCHING_FAILED" "Impossibile scaricare l'archivio mod da Thunderstore." + "MOD_CORRUPTED" "La firma dell'archivio scaricato non corrisponde con quella verificata." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Download %s1 v%s2...\n(%s3/%s4 MB)" + "EXTRACTING_MOD_TEXT" "Estraendo %s1 v%s2...\n(%s3/%s4 MB)" + "MOD_REQUIRED_WARNING" " : Questa mod potrebbe venire (non)caricata entrando in un server" + "PROGRESSION_ENABLED_HEADER" "Progressione Attivata!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000La progessione è stata abilitata.^\n\nTitan, Armi, Fazioni, Skin, etc. dovranno essere sbloccate livellando, o comprate con i Meriti.\n\nQuesto può essere cambiato in qualsiasi momento nella lobby multigiocatore." + "PROGRESSION_DISABLED_HEADER" "Progressione Disabilitata!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000La progressione è stata disabilitata.^\n\nTitan, Armi, Fazioni, Skin, etc. saranno sbloccate e utilizzabili in qualsiasi momento.\n\nQuesto può essere cambiato in qualsiasi momento nella lobby multigiocatore." + "WRONG_MOD_VERSION" "Il server ha la mod \"%s1\" v%s2 mentre tu hai v%s3" + "MANIFESTO_FETCHING_TITLE" "Iniziando download mod" + "MANIFESTO_FETCHING_TEXT" "Recuperando lista delle mod verificate..." + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titan, Armi, Fazioni, Skin, etc. saranno tutti sbloccati e utilizzabili in ogni momento.\n\nQuesto può essere cambiato in qualsiasi momento nella lobby Multigiocatore." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titan, Armi, Factions, Skin, etc. avranno bisogno di essere sbloccate livellando, o comprate con i Meriti.\n\nQuesto può essere cambiato in ogni momento nella lobby Multiplayer.\n\n^CC000000Attenzione: se al momento hai equipaggiato degli item che non hai sbloccato, verranno resettati!" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000La progressione può essere abilitata ora!^\n\nNorthstar ora supporta la progressione vanilla, ciò significa che puoi scegliere di sbloccare Armi, Skin, Titan, etc. attraverso i livelli e le sfide.\n\nPuoi abilitare la progressione cliccando il pulsante in basso nella schermata lobby.\n\nQuesto può essere cambiato in qualsiasi momento." } } -- cgit v1.2.3 From d92378f23f92c70d1ffe572cd4064b5c2515ff93 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:29:37 +0200 Subject: Translations update from Weblate (#840) Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/zh_Hant/ Co-authored-by: RainTrap341 --- .../northstar_client_localisation_tchinese.txt | 28 +++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 500f8a969..fd649cdb6 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -320,7 +320,7 @@ "UNAUTHORIZED_PWD" "密碼錯誤" "STRYDER_RESPONSE" "無法讀取Stryder回應" "PLAYER_NOT_FOUND" "找不到玩家賬戶" - "INVALID_MASTERSERVER_TOKEN" "主伺服器token過期或無效" + "INVALID_MASTERSERVER_TOKEN" "主伺服器token過期或無效。" "JSON_PARSE_ERROR" "讀取json回應時發生錯誤" "UNSUPPORTED_VERSION" "您的遊戲版本過低" "NORTHSTAR_BASE_SETTINGS" "北极星基础设置" @@ -356,5 +356,31 @@ "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您可以隨時在多人大廳中更改此項。" + "AUTHENTICATION_FAILED_HEADER" "認證失敗" + "AUTHENTICATION_FAILED_BODY" "無法與Atlas驗證!" + "AUTHENTICATION_FAILED_ERROR_CODE" "錯誤代碼:^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "幫助" + "MISSING_MOD" "缺少Mod \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(Mod未經驗證并且無法自動下載)" + "MOD_REQUIRED_WARNING" " : 加入一個服務器時,這個Mod可能加載或不加載" + "DOWNLOADING_MOD_TEXT" "正在下載Mod %s1 %s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "正在下載Mod %s1 %s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "正在校驗Mod" + "WRONG_MOD_VERSION" "服務器的 \"%s1\" Mod版本為 %s2 而你的版本是 %s3" + "MOD_DL_DISABLED" "(Mod自動下載已禁用)" + "DOWNLOADING_MOD_TITLE" "下載Mod中" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "下載Mod中(%s1%)" + "CHECKSUMING_TEXT" "驗證内容 %s1 %s2……" + "EXTRACTING_MOD_TITLE" "解壓Mod中 (%s1%)" + "EXTRACTING_MOD_TEXT" "解壓Mod中 %s1 %s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "下載Mod失敗" + "FAILED_READING_ARCHIVE" "在讀取Mod檔案時發生錯誤。" + "FAILED_WRITING_TO_DISK" "在解壓Mod文件到文件系統時發生錯誤。" + "MOD_FETCHING_FAILED" "從Thunderstore下載Mod檔案失敗。" + "MOD_CORRUPTED" "已下載檔案的校驗和無法與驗證簽名匹配。" + "NO_DISK_SPACE_AVAILABLE" "你的存儲設備沒有足夠空間。" + "MOD_FETCHING_FAILED_GENERAL" "Mod解壓失敗。在日志中查看更多詳情。" + "MANIFESTO_FETCHING_TITLE" "設置Mod下載" + "MANIFESTO_FETCHING_TEXT" "獲取已驗證Mod列表……" } } -- cgit v1.2.3 From 984a30c99842fd40769ddcf49070a99d10489727 Mon Sep 17 00:00:00 2001 From: Bobbyperson Date: Mon, 19 Aug 2024 05:33:06 -0400 Subject: Fix Attrition SquadHandler crash (#839) Adds an `IsAlive()` check to temporarily handle a rare crash --- .../mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index 7d73c926f..cacb54cf1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -435,9 +435,12 @@ void function SquadHandler( array guys ) // Setup AI, first assault point foreach ( guy in guys ) { - guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) - guy.AssaultPoint( point ) - guy.AssaultSetGoalRadius( 1600 ) // 1600 is minimum for npc_stalker, works fine for others + if ( IsAlive( guy ) ) + { + guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) + guy.AssaultPoint( point ) + guy.AssaultSetGoalRadius( 1600 ) // 1600 is minimum for npc_stalker, works fine for others + } //thread AITdm_CleanupBoredNPCThread( guy ) } -- cgit v1.2.3 From b254bc5f83080dd97c84ec0a379293bfd0da8bee Mon Sep 17 00:00:00 2001 From: eve <145144394+eve-v0@users.noreply.github.com> Date: Mon, 26 Aug 2024 00:20:26 +0200 Subject: Add Polish translations (#843) Adds file for Polish translations as well as the translations themselves. --- .../northstar_client_localisation_polish.txt | 394 +++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 Northstar.Client/mod/resource/northstar_client_localisation_polish.txt diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt new file mode 100644 index 000000000..d3a60cb86 --- /dev/null +++ b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt @@ -0,0 +1,394 @@ +"lang" +{ + "Language" "polish" + "Tokens" + { + // This file needs to be encoded as UTF-16 LE + + "MENU_LAUNCH_NORTHSTAR" "Uruchom Northstar" + "MENU_TITLE_MODS" "Mody" + "RELOAD_MODS" "Przeładuj Mody" + "WARNING" "Ostrzeżenie" + "CORE_MOD_DISABLE_WARNING" "Wyłączenie kluczowych Modów może zepsuć Northstar!" + "DISABLE" "Wyłącz" + + "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Dzięki za instalację Northstar!" + "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Dla poprawnego działania Northstar potrzebne jest uwierzytelnienie z głównym serwerem. Potrzebne będzie wysłanie twojego tokena Origin do głównego serwera, nie będzie on przechowywany ani użyty do żadnych innych celów. +Naciśnij "Tak" jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Modów." + "BACK_AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnienie" + "AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnienie" + "AUTHENTICATION_AGREEMENT_RESTART" "Potrzebne jest ponowne odpalenie Titanfall 2 by zmiany dały efekt." + + "DIALOG_AUTHENTICATING_MASTERSERVER" "Uwierzytelnianie z głównym serwerem." + "AUTHENTICATIONAGREEMENT_NO" "Zdecydowałeś się nie uwierzytelniać się z Northstar. Zgodę może wyrazić w menu z modami." + + "MENU_TITLE_SERVER_BROWSER" "Wyszukiwarka serwerów" + "NS_SERVERBROWSER_NOSERVERS" "Nie znaleziono serwerów" + "NS_SERVERBROWSER_UNKNOWNMODE" "Nieznany tryb" + "NS_SERVERBROWSER_WAITINGFORSERVERS" "Oczekiwanie na serwery..." + "NS_SERVERBROWSER_CONNECTIONFAILED" "Połączenie nieudane!" + "REFRESH_SERVERS" "Odśwież" + + "MENU_TITLE_CONNECT_PASSWORD" "Dołącz z hasłem" + "MENU_CONNECT_MENU_CONNECT" "Dołącz" + + "PRIVATE_MATCH_PAGE_PREV" "Poprzednia strona" + "PRIVATE_MATCH_PAGE_NEXT" "Następna strona" + + "MENU_MATCH_SETTINGS" "Ustawienia meczu" + "MENU_MATCH_SETTINGS_SUBMENU" "%s1 Ustawienia trybu" + + "PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Tryb Jednoosobowy)" + + // fra hint for private match menu, because fra only has PL_fra_desc in vanilla + "PL_fra_hint" "Każdy na każdego. Zbierz 3 baterie, aby otrzymać Tytana." + + // mode settings + "MODE_SETTING_CATEGORY_PILOT" "Pilot" + "MODE_SETTING_CATEGORY_TITAN" "Tytan" + "MODE_SETTING_CATEGORY_RIFF" "modyfikatory meczu" + "MODE_SETTING_CATEGORY_MATCH" "Mecz" + + "classic_mp" "Klasyczny tryb wieloosobowy" + "run_epilogue" "Epilog" + "scorelimit" "Limit wyniku" + "roundscorelimit" "Limit wyniku (na rundę)" + "timelimit" "Limit Czasu" + "roundtimelimit" "Limit Czasu (na rundę)" + "respawnprotection" "Ochrona po odrodzeniu" + + "pilot_health_multiplier" "Mnożnik życia" + "respawn_delay" "Opóźnienie odrodzeń" + "boosts_enabled" "Wzmocnienia" + "earn_meter_pilot_overdrive" "Doładowanie wskaźnika Tytana/wzmocnienia" + "earn_meter_pilot_multiplier" "Mnożnik wsk. Tytana/wzm." + + "earn_meter_titan_multiplier" "Mnożnik wskaźnika rdzenia" + "aegis_upgrades" "POSTĘPY DOTYCZĄCE RANGI EGIDY" + "infinite_doomed_state" "Stan tytana spisany na straty jest nieskończony" + "titan_shield_regen" "Regeneracja tarczy Tytanów" + + "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" + "featured_mode_amped_tacticals" "Amped Tacticals" + "featured_mode_rocket_arena" "Rocket Arena" + "featured_mode_shotguns_snipers" "Armed and Dangerous" + "iron_rules" "Iron Titan Rules" + + "cp_amped_capture_points" "Obrona umocnień" + "coliseum_loadouts_enabled" "Uzbrojenie Koloseum" + + "aitdm_archer_grunts" "Piechurzy z łucznikami" + + // northstar.custom localisation is just deciding not to work, so putting it here for now + "PL_sbox" "Piaskownica" + "PL_sbox_lobby" "Piaskownica Lobby" + "PL_sbox_desc" "jak gmod tylko gorsze" + "PL_sbox_abbr" "Piaskownica" + "GAMEMODE_SBOX" "Piaskownica" + + "PL_gg" "Gun Game" + "PL_gg_lobby" "Gun Game" + "PL_gg_desc" "Zdobądź zabójstwo każdą bronią by wygrać." + "PL_gg_hint" "Zdobądź zabójstwo każdą bronią by wygrać." + "PL_gg_abbr" "GG" + "GAMEMODE_GG" "Gun Game" + "gg_kill_reward" "Procentowa nagroda za zabójstwo" + "gg_assist_reward" "Procentowa nagroda za asystę" + "gg_execution_reward" "Procentowa nagroda za egzekucję" + + "PL_tt" "Titan Tag" + "PL_tt_lobby" "Titan Tag Lobby" + "PL_tt_desc" "Zdobywaj punkty będąc w Tytanie. Zniszcz Tytana by otrzymać własnego." + "PL_tt_hint" "Zdobywaj punkty będąc w Tytanie. Zniszcz Tytana by otrzymać własnego." + "PL_tt_abbr" "TT" + "GAMEMODE_TT" "Titan Tag" + + "PL_chamber" "One in the Chamber" + "PL_chamber_lobby" "One in the Chamber Lobby" + "PL_chamber_desc" "Jeden strzał, Jedno zabójstwo. Zdobądź kolejny pocisk w magazynku zabijając przeciwnika." + "PL_chamber_hint" "Jeden strzał, Jedno zabójstwo. Zdobądź kolejny pocisk w magazynku zabijając przeciwnika." + "PL_chamber_abbr" "CHAMBER" + "GAMEMODE_CHAMBER" "One in the Chamber Lobby" + + "PL_hidden" "The Hidden" + "PL_hidden_lobby" "The Hidden Lobby" + "PL_hidden_desc" "Jeden gracz jest niewidzialny i poluję na resztę." + "PL_hidden_hint" "Jeden gracz jest niewidzialny i poluję na resztę." + "PL_hidden_abbr" "HIDDEN" + "GAMEMODE_HIDDEN" "The Hidden" + "HIDDEN_YOU_ARE_HIDDEN" "Jesteś The Hidden!" + "HIDDEN_KILL_SURVIVORS" "Zabij wszystkich ocaleńców." + "HIDDEN_FIRST_HIDDEN" "%s1 jest The Hidden." + + "PL_sns" "Sticks and Stones" + "PL_sns_lobby" "Sticks and Stones Lobby" + "PL_sns_desc" "Każdy na każdego. Zabij przeciwnika ostrzem pulsacyjnym lub wykonaj egzekucję by zresetować jego wynik" + "PL_sns_abbr" "SNS" + "GAMEMODE_SNS" "Sticks and Stones" + "SCOREBOARD_BANKRUPTS" "Zabójstwa resetujące" + "SNS_LEADER_BANKRUPT" "Wynik Lidera został zresetowany!" + "SNS_LEADER_BANKRUPT_SUB" "Wynik %s1 został zresetowany przez %s2" + "SNS_BANKRUPT" "Reset!" + "SNS_BANKRUPT_SUB" "Twój wynik został zresetowany przez %s1" + "sns_wme_kill_value" "Wartość zabójstwa przy użyciu Elitarny skrzydłowy" + "sns_softball_kill_value" "Wartość zabójstwa przy użyciu Softball" + "sns_offhand_kill_value" "Wartość zabójstwa przy użyciu Offhand " + "sns_reset_kill_value" "Wartość zabójstwa przy użyciu Ostrza pulsacyjnego/egzekucji" + "sns_melee_kill_value" "Wartość zabójstwa wręcz" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Zabójstwa regenerują zdolność taktyczną - Ostrze pulsacyjne" + "sns_softball_enabled" "Softball Włączony" + + "PL_inf" "Infekcja" + "PL_inf_lobby" "Infekcja Lobby" + "PL_inf_desc" "Przeżyj zarazę. Ocaleńcy zostają zainfekowani gdy zabici." + "PL_inf_hint" "Przeżyj zarazę. Ocaleńcy zostają zainfekowani gdy zabici.." + "PL_inf_abbr" "INF" + "GAMEMODE_INF" "Infekcja" + "INFECTION_YOU_ARE_INFECTED" "Zostałeś zainfekowany!" + "INFECTION_KILL_SURVIVORS" "Zainfekuj pozostałych ocaleńców." + "INFECTION_FIRST_INFECTED" "%s1 jest pierwszym zainfekowanym." + "INFECTION_LAST_SURVIVOR" "%s1 jest ostatnim ocaleńcem!" + "INFECTION_KILL_LAST_SURVIVOR" "Zainfekuj ich przed końcem czasu!" + "INFECTION_YOU_ARE_LAST_SURVIVOR" "Jesteś ostatnim ocaleńcem!" + "INFECTION_SURVIVE_LAST_SURVIVOR" "Przeżyj..." + + "PL_tffa" "Każdy na każdego Tytany" + "PL_tffa_lobby" "Każdy na każdego Tytany" + "PL_tffa_desc" "Każdy na każdego, zniszcz tytany przeciwników." + "PL_tffa_hint" "Każdy na każdego, zniszcz tytany przeciwników." + "PL_tffa_abbr" "TFFA" + "GAMEMODE_TFFA" "Każdy na każdego Tytany" + + "PL_hs" "Chowany" + "PL_hs_lobby" "Chowany Lobby" + "PL_hs_desc" "Szukający szukają chowających się." + "PL_hs_hint" "Szukający szukają chowających się." + "PL_hs_abbr" "HS" + "GAMEMODE_hs" "Chowany" + "HIDEANDSEEK_YOU_ARE_SEEKER" "JESTEŚ SZUKAJĄCYM" + "HIDEANDSEEK_SEEKER_DESC" "Znajdź chowających się i przyłóż im wręcz.\nOdrodzisz się w %s1 sekund" + "HIDEANDSEEK_YOU_ARE_HIDER" "JESTEŚ CHOWAJĄCYM SIĘ" + "HIDEANDSEEK_HIDER_DESC" "Schowaj się." + "HIDEANDSEEK_SEEKERS_INCOMING" "Szukający nadchodzi" + "HIDEANDSEEK_DONT_GET_FOUND" "Nie daj się znaleźć!" + "HIDEANDSEEK_GET_LAST_HIDER" "%s1 JEST OSTATNIM CHOWAJĄCYM SIĘ" + "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "JESTEŚ OSTATNIM CHOWAJĄCYM SIĘ" + "HIDEANDSEEK_GOT_STIM" "Masz Stymulant! Nie daj się złapać!" + "hideandseek_balance_teams" "Automatyczny balans Chowający się/Szukający" + "hideandseek_hiding_time" "Czas na ukrycie się dla Chowających się" + + // 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" "Wojna Kresów" + "PL_fw" "Wojna Kresów" + "PL_fw_lobby" "Wojna Kresów Lobby" + "PL_fw_desc" "Zniszcz Zbieracz przeciwnika i ochroń swój" + "PL_fw_abbr" "FW" + + "GAMEMODE_kr" "Seria Zabójstw" + "PL_kr" "Seria Zabójstw" + "PL_kr_lobby" "Seria Zabójstw Lobby" + "PL_kr_desc" "Zabijaj przeciwników by ustanowić rekord serii i wygrać. Zbierz flagę by ją aktywować." + "PL_kr_hint" "Zabijaj przeciwników by ustanowić rekord serii i wygrać. Zbierz flagę by ją aktywować." + "PL_kr_abbr" "KR" + "SCOREBOARD_KR_RECORD" "Rekord Zabójstw" + "KR_NEW_RACER" "%s1 aktywował Serię" + "KR_YOU_ARE_NEW_RACER" "Aktywowałeś Serię" + "KR_YOU_SET_NEW_RECORD" "Ustaw nowy rekord zabójstw!" + "KR_FLAG_INCOMING" "Niedługo pojawi się flaga" + "KR_COLLECT_FLAG" "Zdobądź ją by aktywować Serię!" + "KR_ENEMY_KILLRACE_OVER" "Seria %s1 się skończyła" + "KR_YOUR_KILLRACE_OVER" "Twoja Seria się skończyła" + "KR_YOUR_KILLRACE_SCORE" "Zdobyłeś %s1 zabójstw." + + "GAMEMODE_fastball" "Fastball" + "PL_fastball" "Fastball" + "PL_fastball_lobby" "Fastball Lobby" + "PL_fastball_desc" "Śmierć pernamentna. Hackuj panele kotrolne by wygrywać rundy i odradzać swoich osoby z swojej drużyny." + "PL_fastball_hint" "Śmierć pernamentna. Hackuj panele kotrolne by wygrywać rundy i odradzać swoich osoby z swojej drużyny." + "PL_fastball_abbr" "FB" + "FASTBALL_PANEL_CAPTURED" "%s1 przęjeli panel %s2" + "SCOREBOARD_FASTBALL_HACKS" "Przejęte panele" + + "GAMEMODE_ctf_comp" "Kompetetywne - Walka o flagę" + + // mode settings + "MODE_SETTING_CATEGORY_PROMODE" "Tryb pro" + "MODE_SETTING_CATEGORY_BLEEDOUT" "Krwawienie Pilotów" + + "custom_air_accel_pilot" "Air Acceleration" + "no_pilot_collision" "Kolidowanie Pilotów" + "promode_enable" "Bronie trybu pro" + "fp_embark_enabled" "Pierwszoosobowe wsiadanie/egzekucje" + "classic_rodeo" "Klasyczne Rodeo" + "oob_timer_enabled" "Licznik czasu poza granicami mapy" + "riff_instagib" "Instagib Mode" + "player_force_respawn" "Wymuszone odrodzenie" + + "riff_player_bleedout" "Krwawienie Pilotów" + "player_bleedout_forceHolster" "Schowaj bronie gdy powalonym" + "player_bleedout_forceDeathOnTeamBleedout" "Umrzyj przy wykrawieniu się drużyny" + "player_bleedout_bleedoutTime" "Czas do wykrwawienia się" + "player_bleedout_firstAidTime" "Czas potrzebny do udzielenia pierwszej pomocy" + "player_bleedout_firstAidTimeSelf" "Czas potrzebny do samo-reanimacji" + "player_bleedout_firstAidHealPercent" "Procent życia po otrzymaniu pierwszej pomocy" + "player_bleedout_aiBleedingPlayerMissChance" "Szanasa na nietrafienie przez powalone SI" + + // coop stuff + "PL_sp_coop" "(NIE UKOŃCZONE) Kampania w trybie Kooperacji" + "PL_sp_coop_lobby" "Kampania w trybie Kooperacji Lobby" + "PL_sp_coop_desc" "Zagraj kampanie z przyjaciółmi" + "PL_sp_coop_hint" "Zagraj kampanie z przyjaciółmi" + "PL_sp_coop_abbr" "SP" + + "SP_TRAINING" "Tor przeszkód" + "SP_TRAINING_CLASSIC_DESC" "Symulacja kapitana Lastimosy." + + "SP_CRASHSITE" "BT-7274" + "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper spotyka BT-7274." + + "SP_SEWERS1" "Krew i rdza" + "SP_SEWERS1_CLASSIC_DESC" "Cooper i BT ruszają spotkać się z majorem Andersonem." + + "SP_BOOMTOWN_START" "W paszczę otchłani" + "SP_BOOMTOWN_START_CLASSIC_DESC" "Przeprawa podziemnym skrótem przynosi nieoczekiwane skutki." + + "SP_HUB_TIMESHIFT" "Skutek i przyczyna" + "SP_HUB_TIMESHIFT_CLASSIC_DESC" "W miejscu, w którym przebywa major Anderson zaobserwowano osobliwe zjawisko." + + "SP_BEACON" "Nadajnik" + "SP_BEACON_CLASSIC_DESC" "Cooper i BT podejmują próbę nawiązania kontaktu z pozostałymi siłami by przekazać im plany IMC." + + "SP_TDAY" "Próba ognia" + "SP_TDAY_CLASSIC_DESC" "Zdolności pilotażu Coopera zostają wystawione na próbę w ostatecznym starciu o Arkę." + + "SP_S2S" "Arka" + "SP_S2S_CLASSIC_DESC" "Cooper i BT ruszają statkiem w pościg za Arką." + + "SP_SKYWAY_V1" "Zakrzywiacz" + "SP_SKYWAY_V1_CLASSIC_DESC" "Cooper i BT zostają pojmani przez Kubena Bliska." + + // Better.Serverbrowser + "SERVERS_COLUMN" "Serwery" + "PLAYERS_COLUMN" "Gracze" + "MAP_COLUMN" "Mapa" + "GAMEMODE_COLUMN" "Tryb gry" + "REGION_COLUMN" "Region" + "SEARCHBAR_LABEL" "Wyszukiwanie:" + "MAP_FILTER" "Mapa" + "GAMEMODE_FILTER" "Tryb gry" + "HIDE_FULL_FILTER" "Ukryj Pełne Serwery" + "HIDE_EMPTY_FILTER" "Ukryj Puste Serwery" + "HIDE_PROT_FILTER" "Ukryj Chronione Hasłem Serwery" + "SERVER_DESCRIPTION" "Opis" + "SERVER_MODS" "Mody" + "CLEAR_FILTERS" "WYCZYŚĆ" + "JOIN_BUTTON" "DOŁĄCZ" + + "SWITCH_YES" "Tak" + "SWITCH_NO" "Nie" + "SWITCH_ANY" "Dowolnie" + + "CONNECTING" "Łączenie..." + "INGAME_PLAYERS" "Gracze: ^6BA6C400%s1" + "TOTAL_SERVERS" "Serwery: ^C46C6C00%s1" + + // Mods menu + "SHOW" "Pokaż" + "SHOW_ALL" "Wszystko" + "SHOW_ONLY_ENABLED" "Tylko Włączone" + "SHOW_ONLY_DISABLED" "Tylko Wyłączone" + "SHOW_ONLY_NOT_REQUIRED" "Tylko Mody Opcjonalne" + "SHOW_ONLY_REQUIRED" "Tylko Mody Wymagane" + "MOD_REQUIRED_WARNING" " : Ten mod może zostać wyłączony po dołączeniu na serwer" + + // Maps menu + "HIDE_LOCKED" "Ukryj zablokowane" + + // In-game chat + "HUD_CHAT_WHISPER_PREFIX" "[SZEPT]" + "HUD_CHAT_SERVER_PREFIX" "[SERWER]" + + "NO_GAMESERVER_RESPONSE" "Nie udało się osiągnąć serwera" + "BAD_GAMESERVER_RESPONSE" "Serwer dał nieprawidłową odpowiedź" + "UNAUTHORIZED_GAMESERVER" "Serwer nie ma autoryzacji by przedstawić takie zapytanie" + "UNAUTHORIZED_GAME" "Stryder nie może potwierdzić że to konto ma Titanfall 2" + "UNAUTHORIZED_PWD" "Nieprawidłowe hasło" + "STRYDER_RESPONSE" "Nieprawidłowa odpowiedź od Stryder" + "PLAYER_NOT_FOUND" "Nie udało się znaleźć konta gracza" + "INVALID_MASTERSERVER_TOKEN" "Token głównego serwera jest nieprawidłowy lub wygasł, spróbuj odpalić ponownie aplikację EA" + "JSON_PARSE_ERROR" "Wystąpił błąd przy sprawdzaniu pliku json" + "UNSUPPORTED_VERSION" "Wersja której używasz nie jest już wspierana" + + "AUTHENTICATION_FAILED_HEADER" "Uwierzytelnianie się nie powiodło" + "AUTHENTICATION_FAILED_BODY" "Uwierzytelnianie z Atlas się nie powiodło!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Kod błędu: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Pomoc" + + // Mod Settings + "MOD_SETTINGS" "Ustawienia Modów" + "NORTHSTAR_BASE_SETTINGS" "Główne ustawienia Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Tylko Host może zmienić ustawienia meczu prywatnego" + "ONLY_HOST_CAN_START_MATCH" "Tylko Host może rozpocząć mecz" + "MATCH_COUNTDOWN_LENGTH" "Długość odliczana do rozpoczęcia meczu prywatnego" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Loguj nieznane komendy klienta" + "DISALLOWED_TACTICALS" "Zabroniona umiejętność taktyczna" + "TACTICAL_REPLACEMENT" "Zastępująca umiejętność taktyczna" + "DISALLOWED_WEAPONS" "Zabroniona broń" + "REPLACEMENT_WEAPON" "Zastępująca broń" + "SHOULD_RETURN_TO_LOBBY" "Powróć do lobby po zakończeniu meczu" + "ARE_YOU_SURE" "Jesteś pewien?" + "WILL_RESET_ALL_SETTINGS" "Zresetujesz WSZYSTKIE ustawienia tej kategorii.\n\nAkcja jest nieodwracalna." + "WILL_RESET_SETTING" "Zresetujesz %s1 do startowej wartości.\n\nAkcja jest nieodwracalna." + "MOD_SETTINGS_SERVER" "Serwer" + "MOD_SETTINGS_RESET" "Zresetuj" + "MOD_SETTINGS_RESET_ALL" "Zresetuj WSZYSTKO" + "NO_RESULTS" "Brak rezultatu." + "NO_MODS" "Brak dostępnych ustawień, zainstaluj więcej modów w ^5588FF00northstar.thunderstore.io^0." + + // Toggleable progression + "TOGGLE_PROGRESSION" "Przełącz Progresję" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Przełącz Progresję" + + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Wyłączyć Progresję?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Tytany, Bronie, Fakcje, Skórki, itd. zostaną wszytskie odblokowane.\n\nDecyzję możesz zmienić kiedykolwiek w Lobby trybu wieloosobowego." + + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Włączyć Progresję?" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Tytany, Bronie, Fakcje, Skórki, itd. będą musiały być odblokowane poprzez zwiększanie swojego poziomu lub zakupione.\n\nDecyzję możesz zmienić kiedykolwiek w Lobby trybu wieloosobowego.\n\n^CC000000Ostrzeżenie: jeżeli masz wyekwipowane uzbrojenie której nie jest odblokowane zostenie ono zresetowane!" + + "PROGRESSION_ENABLED_HEADER" "Progresja została Włączona!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Progresja została Włączona.^\n\nTytany, Bronie, Fakcje, Skórki, itd. będą musiały być odblokowane poprzez zwiększanie swojego poziomu lub zakupione.\n\nDecyzję możesz zmienić kiedykolwiek w Lobby trybu wieloosobowego." + + "PROGRESSION_DISABLED_HEADER" "Progresja została Wyłączona!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000Progresja została Wyłączona.^\n\nTytany, Bronie, Fakcje, Skórki, itd. zostaną wszytskie odblokowane.\n\nDecyzję możesz zmienić kiedykolwiek w Lobby trybu wieloosobowego." + + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Jest już możliwość włączenia Progresjii!^\n\nNorthstar teraz wspiera klasyczną Progresję, Dzięki niej możesz wybrać odblokowawanie Broni, Tytanów, Skórek, itd. poprzez zwiększanie swojego poziomu lub ukańczanie wyzwań.\n\nProgresja może zostać włączona poprzez przycisk na dole ekranu Lobby.\n\nDecyzję możesz zmienić kiedykolwiek." + + // Mod downloading + "MISSING_MOD" "Brakujący Mod \"%s1\" v%s2" + "WRONG_MOD_VERSION" "Serwer ma Moda \"%s1\" v%s2 podczas gdy ty masz v%s3" + "MOD_NOT_VERIFIED" "(Mod nie został zweryfikowany i nie mógł być pobrany automatycznie)" + "MOD_DL_DISABLED" "(Automatyczne pobieranie modów jest wyłączone)" + "MANIFESTO_FETCHING_TITLE" "Przygotowywanie do pobierania Moda" + "MANIFESTO_FETCHING_TEXT" "Zdobywanie listy zweryfikowanych modów..." + "DOWNLOADING_MOD_TITLE" "Pobieranie" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Pobieranie (%s1%)" + "DOWNLOADING_MOD_TEXT" "Pobieranie %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Pobieranie %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Sprawdzanie wartości kontrolnej Moda" + "CHECKSUMING_TEXT" "Weryfikowanie zawartości %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Rozpakowywanie Moda (%s1%)" + "EXTRACTING_MOD_TEXT" "Rozpakowywanie %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Pobieranie Moda się nie powiodło" + "FAILED_READING_ARCHIVE" "Wystąpił błąd podczas czytania archiwum Moda." + "FAILED_WRITING_TO_DISK" "Wystąpił błąd podczas rozpakowywania Moda." + "MOD_FETCHING_FAILED" "Pobieranie archiwum Moda się nie powiodło." + "MOD_CORRUPTED" "Wartość kontrolna pobranego archiwum/moda nie zgadza się z zweryfikowaną wartośćią kontrolną." + "NO_DISK_SPACE_AVAILABLE" "Nie ma wystarczająco miejsca na dysku." + "MOD_FETCHING_FAILED_GENERAL" "Rozpakowywanie Moda się nie powiodło. Sprawdź Logi po więcej detali." + } +} -- cgit v1.2.3 From a1e77030f834219a12252925dd9204f00b74e30d Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:12:57 +0200 Subject: Translations update from Weblate (#844) Translated using Weblate (Polish) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pl/ Co-authored-by: eve --- .../mod/resource/northstar_client_localisation_polish.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt index d3a60cb86..2df36d8df 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt @@ -15,12 +15,12 @@ "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Dzięki za instalację Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Dla poprawnego działania Northstar potrzebne jest uwierzytelnienie z głównym serwerem. Potrzebne będzie wysłanie twojego tokena Origin do głównego serwera, nie będzie on przechowywany ani użyty do żadnych innych celów. Naciśnij "Tak" jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Modów." - "BACK_AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnienie" - "AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnienie" + "BACK_AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnianie" + "AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnianie" "AUTHENTICATION_AGREEMENT_RESTART" "Potrzebne jest ponowne odpalenie Titanfall 2 by zmiany dały efekt." "DIALOG_AUTHENTICATING_MASTERSERVER" "Uwierzytelnianie z głównym serwerem." - "AUTHENTICATIONAGREEMENT_NO" "Zdecydowałeś się nie uwierzytelniać się z Northstar. Zgodę może wyrazić w menu z modami." + "AUTHENTICATIONAGREEMENT_NO" "Zdecydowałeś się nie uwierzytelniać się z Northstar. Zgodę można wyrazić w menu z modami." "MENU_TITLE_SERVER_BROWSER" "Wyszukiwarka serwerów" "NS_SERVERBROWSER_NOSERVERS" "Nie znaleziono serwerów" @@ -46,7 +46,7 @@ Naciśnij "Tak" jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu // mode settings "MODE_SETTING_CATEGORY_PILOT" "Pilot" "MODE_SETTING_CATEGORY_TITAN" "Tytan" - "MODE_SETTING_CATEGORY_RIFF" "modyfikatory meczu" + "MODE_SETTING_CATEGORY_RIFF" "Modyfikatory meczu" "MODE_SETTING_CATEGORY_MATCH" "Mecz" "classic_mp" "Klasyczny tryb wieloosobowy" -- cgit v1.2.3 From 426777ba50f83c18a80568e4f87bbb2ed2f1cf0a Mon Sep 17 00:00:00 2001 From: eve <145144394+eve-v0@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:04:49 +0200 Subject: Remove quotation marks from Polish translations breaking file parsing (#846) The quotation marks caused file parsing to end early and break --- Northstar.Client/mod/resource/northstar_client_localisation_polish.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt index 2df36d8df..2d94a0411 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt @@ -14,7 +14,7 @@ "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Dzięki za instalację Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Dla poprawnego działania Northstar potrzebne jest uwierzytelnienie z głównym serwerem. Potrzebne będzie wysłanie twojego tokena Origin do głównego serwera, nie będzie on przechowywany ani użyty do żadnych innych celów. -Naciśnij "Tak" jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Modów." +Naciśnij Tak jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Modów." "BACK_AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnianie" "AUTHENTICATION_AGREEMENT" "Zgoda na uwierzytelnianie" "AUTHENTICATION_AGREEMENT_RESTART" "Potrzebne jest ponowne odpalenie Titanfall 2 by zmiany dały efekt." -- cgit v1.2.3 From 05b6f7ab1f7ea172ab36b17d25c1e3fbec314ecc Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:20:07 +0200 Subject: Bump actions/checkout to v4 (#847) from v3 which is being deprecated --- .github/workflows/compile-check.yml | 2 +- .github/workflows/encoding.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml index cb7ab1d08..8803f4f4c 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -8,7 +8,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: "mods" diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index 5a730c203..b1d851a14 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check localization files encoding run: | files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Look out for missing translations run: node .github/build/find-missing-translations.js continue-on-error: true -- cgit v1.2.3 From ffc5dfd0b637f56846ac1bb6330dce7544d40762 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 28 Aug 2024 01:02:57 +0200 Subject: Translations update from Weblate (#848) Translated using Weblate (Polish) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pl/ Co-authored-by: p0358 --- Northstar.Client/mod/resource/northstar_client_localisation_polish.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt index 2d94a0411..9b570cebe 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_polish.txt @@ -46,7 +46,7 @@ Naciśnij Tak jeżeli wyrażasz zgodę. Wybór może zostać zmieniony w menu Mo // mode settings "MODE_SETTING_CATEGORY_PILOT" "Pilot" "MODE_SETTING_CATEGORY_TITAN" "Tytan" - "MODE_SETTING_CATEGORY_RIFF" "Modyfikatory meczu" + "MODE_SETTING_CATEGORY_RIFF" "Modyfikatory rozgrywki" "MODE_SETTING_CATEGORY_MATCH" "Mecz" "classic_mp" "Klasyczny tryb wieloosobowy" -- cgit v1.2.3 From 3d278b3b25fe0b62bec1f196116d175b29c20640 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Thu, 29 Aug 2024 15:44:12 +0200 Subject: Hide remote mods in mods display (#799) As they are supposed to be disabled unless joining a server that requires that mod. --- .github/nativefuncs.json | 18 ++++++++++++++++++ .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 889432d73..110429031 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -18,6 +18,12 @@ "returnTypeString":"void", "argTypes":"string modName, bool enabled" }, + { + "name":"NSIsModRemote", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, { "name":"NSGetModDescriptionByModName", "helpText":"", @@ -266,6 +272,12 @@ "returnTypeString":"void", "argTypes":"string modName, bool enabled" }, + { + "name":"NSIsModRemote", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, { "name":"NSGetModDescriptionByModName", "helpText":"", @@ -466,6 +478,12 @@ "returnTypeString":"void", "argTypes":"string modName, bool enabled" }, + { + "name":"NSIsModRemote", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, { "name":"NSGetModDescriptionByModName", "helpText":"", 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 3f643aa3d..f08d69a72 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -338,6 +338,10 @@ void function RefreshMods() { string mod = modNames[i] + // Do not display remote mods + if ( NSIsModRemote( mod ) ) + continue + if ( searchTerm.len() && mod.tolower().find( searchTerm ) == null ) continue -- cgit v1.2.3 From a5b144a95c0a77ddba4a162530d9c0aa3d318047 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:04:56 +0200 Subject: Add code review and testing sections to pull request template (#850) --- .github/pull_request_template.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8cda06a32..e4dd3515d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,3 +16,11 @@ Note that commit messages in PRs will generally be squashed to keep commit histo --> Replace this line with a description of your change (and screenshots/screenrecordings if applicable). + +### Code review: + +Replace this line with anything specific to look out for during code reviews. + +### Testing: + +Replace this line with instructions on how to test your pull request. The more detailed, the easier it is for reviewers to test, the faster your PR gets merged. -- cgit v1.2.3 From 83afd8cb140001d415b6a8efc27995559485b1f7 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Fri, 30 Aug 2024 01:55:44 +0200 Subject: Translations update from Weblate (#851) Translated using Weblate (German) Currently translated at 99.0% (310 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ Co-authored-by: Maya --- .../mod/resource/northstar_client_localisation_german.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 996a3e2ba..7951fe35b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -320,7 +320,7 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "SHOW_ONLY_NOT_REQUIRED" "Nur optionale Mods" "SHOW_ONLY_REQUIRED" "Nur notwendige Mods" "PROGRESSION_TOGGLE_DISABLED_HEADER" "Fortschritt aktivieren?" - "TOGGLE_PROGRESSION" "Fortschritt zuschalten" + "TOGGLE_PROGRESSION" "Fortschritt umschalten" "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" @@ -357,7 +357,7 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "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." + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Fortschritt umschalten" "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." -- cgit v1.2.3 From 6cd957e93f8eccf42d7cb08afc19fd4650ee0efd Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:52:21 +0200 Subject: Add missing valid check for militia flag spawn (#853) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 97addc241..6033940bb 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -123,7 +123,9 @@ void function CreateFlags() file.imcFlagSpawn.Destroy() file.imcFlag.Destroy() file.imcFlagReturnTrigger.Destroy() - + } + if ( IsValid( file.militiaFlagSpawn ) ) + { file.militiaFlagSpawn.Destroy() file.militiaFlag.Destroy() file.militiaFlagReturnTrigger.Destroy() -- cgit v1.2.3 From 3eb15eef1123f71e09e773adb15f52b5fa63a179 Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 14:59:47 +0200 Subject: Move `SetFlagStateForTeam` to end of file in an effort to have all related functions close to each other --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 6033940bb..81971e00b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -249,15 +249,6 @@ void function TrackFlagReturnTrigger( entity flag, entity returnTrigger ) } } -void function SetFlagStateForTeam( int team, int state ) -{ - if ( state == eFlagState.Away ) // we tell the client the flag is the player carrying it if they're carrying it - SetGlobalNetEnt( team == TEAM_IMC ? "imcFlag" : "milFlag", ( team == TEAM_IMC ? file.imcFlag : file.militiaFlag ).GetParent() ) - else - SetGlobalNetEnt( team == TEAM_IMC ? "imcFlag" : "milFlag", team == TEAM_IMC ? file.imcFlag : file.militiaFlag ) - - SetGlobalNetInt( team == TEAM_IMC ? "imcFlagState" : "milFlagState", state ) -} bool function OnFlagCollected( entity player, entity flag ) { @@ -524,4 +515,14 @@ void function TryReturnFlag( entity player, entity flag ) MessageToTeam( GetOtherTeam( flag.GetTeam() ), eEventNotifications.PlayerReturnedEnemyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyReturnsFlag", GetOtherTeam( flag.GetTeam() ) ) PlayFactionDialogueToTeam( "ctf_flagReturnedEnemy", GetOtherTeam( flag.GetTeam() ) ) -} \ No newline at end of file +} + +void function SetFlagStateForTeam( int team, int state ) +{ + if ( state == eFlagState.Away ) // we tell the client the flag is the player carrying it if they're carrying it + SetGlobalNetEnt( team == TEAM_IMC ? "imcFlag" : "milFlag", ( team == TEAM_IMC ? file.imcFlag : file.militiaFlag ).GetParent() ) + else + SetGlobalNetEnt( team == TEAM_IMC ? "imcFlag" : "milFlag", team == TEAM_IMC ? file.imcFlag : file.militiaFlag ) + + SetGlobalNetInt( team == TEAM_IMC ? "imcFlagState" : "milFlagState", state ) +} -- cgit v1.2.3 From c674e3c0583c5c8eca136a5ebeb5ed2ac6cae6c4 Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 15:03:52 +0200 Subject: Move some drop flag related functions to end of file in an effort to have all related functions close to each other Part of the refactor in #830 --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 81971e00b..72f43e18b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -287,26 +287,6 @@ void function GiveFlag( entity player, entity flag ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Away ) // used for held } -void function DropFlagIfPhased( entity player, entity flag ) -{ - player.EndSignal( "StartPhaseShift" ) - player.EndSignal( "OnDestroy" ) - - OnThreadEnd( function() : ( player ) - { - if (GetGameState() == eGameState.Playing || GetGameState() == eGameState.SuddenDeath) - DropFlag( player, true ) - }) - // the IsValid check is purely to prevent a crash due to a destroyed flag (epilogue) - while( IsValid(flag) && flag.GetParent() == player ) - WaitFrame() -} - -void function DropFlagForBecomingTitan( entity pilot, entity titan ) -{ - DropFlag( pilot, true ) -} - void function DropFlag( entity player, bool realDrop = true ) { entity flag = GetFlagForTeam( GetOtherTeam( player.GetTeam() ) ) @@ -344,15 +324,6 @@ void function DropFlag( entity player, bool realDrop = true ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Home ) // used for return prompt } -void function TrackFlagDropTimeout( entity flag ) -{ - flag.EndSignal( "ResetDropTimeout" ) - - wait CTF_GetDropTimeout() - - ResetFlag( flag ) -} - void function ResetFlag( entity flag ) { // prevents crash when flag is reset after it's been destroyed due to epilogue @@ -526,3 +497,32 @@ void function SetFlagStateForTeam( int team, int state ) SetGlobalNetInt( team == TEAM_IMC ? "imcFlagState" : "milFlagState", state ) } + +void function DropFlagIfPhased( entity player, entity flag ) +{ + player.EndSignal( "StartPhaseShift" ) + player.EndSignal( "OnDestroy" ) + + OnThreadEnd( function() : ( player ) + { + if (GetGameState() == eGameState.Playing || GetGameState() == eGameState.SuddenDeath) + DropFlag( player, true ) + }) + // the IsValid check is purely to prevent a crash due to a destroyed flag (epilogue) + while( IsValid(flag) && flag.GetParent() == player ) + WaitFrame() +} + +void function DropFlagForBecomingTitan( entity pilot, entity titan ) +{ + DropFlag( pilot, true ) +} + +void function TrackFlagDropTimeout( entity flag ) +{ + flag.EndSignal( "ResetDropTimeout" ) + + wait CTF_GetDropTimeout() + + ResetFlag( flag ) +} -- cgit v1.2.3 From dafc1d1e9729093b00fd27bc3083133f6af4d4b7 Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 15:08:38 +0200 Subject: Move `CaptureFlag` function as part of the refactoring effort in #830 --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 123 +++++++++++---------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 72f43e18b..7375d1991 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -287,6 +287,68 @@ void function GiveFlag( entity player, entity flag ) SetFlagStateForTeam( flag.GetTeam(), eFlagState.Away ) // used for held } +void function CaptureFlag( entity player, entity flag ) +{ + // can only capture flags during normal play or sudden death + if (GetGameState() != eGameState.Playing && GetGameState() != eGameState.SuddenDeath) + { + printt( player + " tried to capture the flag, but the game state was " + GetGameState() + " not " + eGameState.Playing + " or " + eGameState.SuddenDeath) + return + } + // reset flag + ResetFlag( flag ) + + print( player + " captured the flag!" ) + + // score + int team = player.GetTeam() + AddTeamScore( team, 1 ) + AddPlayerScore( player, "FlagCapture", player ) + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) // add 1 to captures on scoreboard + SetRoundWinningKillReplayAttacker( player ) // set attacker for last cap replay + + array assistList + if ( player.GetTeam() == TEAM_IMC ) + assistList = file.imcCaptureAssistList + else + assistList = file.militiaCaptureAssistList + + foreach( entity assistPlayer in assistList ) + { + if ( player != assistPlayer ) + AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) + if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + { + AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) + SetPlayerChallengeMeritScore( assistPlayer ) + } + } + + assistList.clear() + + // notifs + MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) + + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + + MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) + EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) + + MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) + EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() ) + + if ( GameRules_GetTeamScore( team ) == GameMode_GetRoundScoreLimit( GAMETYPE ) - 1 ) + { + PlayFactionDialogueToTeam( "ctf_notifyWin1more", team ) + PlayFactionDialogueToTeam( "ctf_notifyLose1more", GetOtherTeam( team ) ) + } +} + void function DropFlag( entity player, bool realDrop = true ) { entity flag = GetFlagForTeam( GetOtherTeam( player.GetTeam() ) ) @@ -351,67 +413,6 @@ void function ResetFlag( entity flag ) flag.Signal( "ResetDropTimeout" ) } -void function CaptureFlag( entity player, entity flag ) -{ - // can only capture flags during normal play or sudden death - if (GetGameState() != eGameState.Playing && GetGameState() != eGameState.SuddenDeath) - { - printt( player + " tried to capture the flag, but the game state was " + GetGameState() + " not " + eGameState.Playing + " or " + eGameState.SuddenDeath) - return - } - // reset flag - ResetFlag( flag ) - - print( player + " captured the flag!" ) - - // score - int team = player.GetTeam() - AddTeamScore( team, 1 ) - AddPlayerScore( player, "FlagCapture", player ) - player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) // add 1 to captures on scoreboard - SetRoundWinningKillReplayAttacker( player ) // set attacker for last cap replay - - array assistList - if ( player.GetTeam() == TEAM_IMC ) - assistList = file.imcCaptureAssistList - else - assistList = file.militiaCaptureAssistList - - foreach( entity assistPlayer in assistList ) - { - if ( player != assistPlayer ) - AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) - if( !HasPlayerCompletedMeritScore( assistPlayer ) ) - { - AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) - SetPlayerChallengeMeritScore( assistPlayer ) - } - } - - assistList.clear() - - // notifs - MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) - EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) - - if( !HasPlayerCompletedMeritScore( player ) ) - { - AddPlayerScore( player, "ChallengeCTFRetAssist" ) - SetPlayerChallengeMeritScore( player ) - } - - MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) - EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) - - MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) - EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() ) - - if ( GameRules_GetTeamScore( team ) == GameMode_GetRoundScoreLimit( GAMETYPE ) - 1 ) - { - PlayFactionDialogueToTeam( "ctf_notifyWin1more", team ) - PlayFactionDialogueToTeam( "ctf_notifyLose1more", GetOtherTeam( team ) ) - } -} void function OnPlayerEntersFlagReturnTrigger( entity trigger, entity player ) { -- cgit v1.2.3 From bd77a936a90f4b30c5e88b5fa26e4d995930d9ff Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 15:11:51 +0200 Subject: Move `CTFInitPlayer` function as part of the refactoring effort in #830 --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 7375d1991..e1c179b51 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -91,18 +91,6 @@ bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) return true } -void function CTFInitPlayer( entity player ) -{ - if ( !IsValid( file.imcFlagSpawn ) ) - return - - vector imcSpawn = file.imcFlagSpawn.GetOrigin() - Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_IMC, imcSpawn.x, imcSpawn.y, imcSpawn.z ) - - vector militiaSpawn = file.militiaFlagSpawn.GetOrigin() - Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_MILITIA, militiaSpawn.x, militiaSpawn.y, militiaSpawn.z ) -} - void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { if ( !IsValid( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ) ) ) // getting a crash idk @@ -236,6 +224,18 @@ void function RemoveFlags() SetFlagStateForTeam( TEAM_IMC, eFlagState.None ) } +void function CTFInitPlayer( entity player ) +{ + if ( !IsValid( file.imcFlagSpawn ) ) + return + + vector imcSpawn = file.imcFlagSpawn.GetOrigin() + Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_IMC, imcSpawn.x, imcSpawn.y, imcSpawn.z ) + + vector militiaSpawn = file.militiaFlagSpawn.GetOrigin() + Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_MILITIA, militiaSpawn.x, militiaSpawn.y, militiaSpawn.z ) +} + void function TrackFlagReturnTrigger( entity flag, entity returnTrigger ) { // this is a bit of a hack, it seems parenting the return trigger to the flag actually sets the pickup radius of the flag to be the same as the trigger -- cgit v1.2.3 From 8b34689dca9f2392ad74c57a19e64ec58abda69e Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 15:12:42 +0200 Subject: Move `OnPlayerKilled` function as part of the refactoring effort in #830 --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index e1c179b51..752aa907d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -91,19 +91,6 @@ bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) return true } -void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) -{ - if ( !IsValid( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ) ) ) // getting a crash idk - return - if ( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ).GetParent() == victim ) - { - if ( victim != attacker && attacker.IsPlayer() ) - AddPlayerScore( attacker, "FlagCarrierKill", victim ) - - DropFlag( victim ) - } -} - void function CreateFlags() { if ( IsValid( file.imcFlagSpawn ) ) @@ -236,6 +223,19 @@ void function CTFInitPlayer( entity player ) Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_MILITIA, militiaSpawn.x, militiaSpawn.y, militiaSpawn.z ) } +void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( !IsValid( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ) ) ) // getting a crash idk + return + if ( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ).GetParent() == victim ) + { + if ( victim != attacker && attacker.IsPlayer() ) + AddPlayerScore( attacker, "FlagCarrierKill", victim ) + + DropFlag( victim ) + } +} + void function TrackFlagReturnTrigger( entity flag, entity returnTrigger ) { // this is a bit of a hack, it seems parenting the return trigger to the flag actually sets the pickup radius of the flag to be the same as the trigger -- cgit v1.2.3 From 9e9d08ff8ba0c85b90590f17cb9be38cba4f6450 Mon Sep 17 00:00:00 2001 From: Zanieon Date: Fri, 30 Aug 2024 15:16:35 +0200 Subject: Move CTF spawn point related functions as part of the refactoring effort in #830 --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 752aa907d..3c5eb12c1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -67,30 +67,6 @@ void function CaptureTheFlag_Init() ScoreEvent_SetEarnMeterValues( "FlagReturn", 0.0, 0.20 ) } -void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, int team, entity player ) -{ - RateSpawnpoints_SpawnZones( checkClass, spawnpoints, team, player ) -} - -bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) -{ - // ensure spawnpoints aren't too close to enemy base - vector allyFlagSpot - vector enemyFlagSpot - foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) - { - if( spawn.GetTeam() == team ) - allyFlagSpot = spawn.GetOrigin() - else - enemyFlagSpot = spawn.GetOrigin() - } - - if( Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) > Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) ) - return false - - return true -} - void function CreateFlags() { if ( IsValid( file.imcFlagSpawn ) ) @@ -211,6 +187,30 @@ void function RemoveFlags() SetFlagStateForTeam( TEAM_IMC, eFlagState.None ) } +void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, int team, entity player ) +{ + RateSpawnpoints_SpawnZones( checkClass, spawnpoints, team, player ) +} + +bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) +{ + // ensure spawnpoints aren't too close to enemy base + vector allyFlagSpot + vector enemyFlagSpot + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + { + if( spawn.GetTeam() == team ) + allyFlagSpot = spawn.GetOrigin() + else + enemyFlagSpot = spawn.GetOrigin() + } + + if( Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) > Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) ) + return false + + return true +} + void function CTFInitPlayer( entity player ) { if ( !IsValid( file.imcFlagSpawn ) ) -- cgit v1.2.3 From ebbf9df5134d75c7d46bca0826cfee47090d8215 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:25:54 +0200 Subject: Add missing `IsValidPlayer()` check for CTF capture assists (#854) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 3c5eb12c1..31c05eb36 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -315,12 +315,15 @@ void function CaptureFlag( entity player, entity flag ) foreach( entity assistPlayer in assistList ) { - if ( player != assistPlayer ) - AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) - if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + if ( IsValidPlayer( assistPlayer ) ) { - AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) - SetPlayerChallengeMeritScore( assistPlayer ) + if ( player != assistPlayer ) + AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) + if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + { + AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) + SetPlayerChallengeMeritScore( assistPlayer ) + } } } -- cgit v1.2.3 From 331828005244bd9da0f5a0213ecfff9c957c1453 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:21:30 +0200 Subject: Add is `IsValidPlayer()` check (#855) to prevent potential script crash Co-authored-by: Zanieon --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 31c05eb36..1f06ff4a6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -509,8 +509,11 @@ void function DropFlagIfPhased( entity player, entity flag ) OnThreadEnd( function() : ( player ) { - if (GetGameState() == eGameState.Playing || GetGameState() == eGameState.SuddenDeath) - DropFlag( player, true ) + if ( IsValidPlayer( player ) ) + { + if ( GetGameState() == eGameState.Playing || GetGameState() == eGameState.SuddenDeath ) + DropFlag( player, true ) + } }) // the IsValid check is purely to prevent a crash due to a destroyed flag (epilogue) while( IsValid(flag) && flag.GetParent() == player ) -- cgit v1.2.3 From e253357946fd7287c31d1e2a439bac4762c3ba3d Mon Sep 17 00:00:00 2001 From: x3Karma Date: Sat, 31 Aug 2024 20:39:12 +0800 Subject: Fix `PlayerInventory_TakeAllInventoryItems` not being threaded (#852) This needs to be threaded as there's a `waitthread` further below on that function, which will cause an error if not threaded. --- .../mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut index 9057f7d8b..3814126ba 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut @@ -32,7 +32,7 @@ void function PrematchClearInventory() // vanilla behavior { foreach( entity player in GetPlayerArray() ) { - PlayerInventory_TakeAllInventoryItems( player ) + thread PlayerInventory_TakeAllInventoryItems( player ) } } -- cgit v1.2.3 From d51ceccf3baf9313f22dfee14a693e096c3d2f77 Mon Sep 17 00:00:00 2001 From: birb Date: Mon, 2 Sep 2024 15:20:32 +0100 Subject: Fix typo in README to match actual folder structure (#857) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b6dfaf02..4dbbd6edd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Issues in this repository should be created if they are related to these domains - `Northstar.Client` - Localisation files, UI and client-side scripts. - `Northstar.Coop` - Soon™. - `Northstar.Custom` - Northstar custom content. -- `Northstar.CustomServer` - Server config files and scripts necessary for multiplayer. +- `Northstar.CustomServers` - Server config files and scripts necessary for multiplayer. ### Translating -- cgit v1.2.3 From b664005c5dc0142531176258db53a3bf47392faf Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Sep 2024 19:40:47 -0300 Subject: Avoid duplication of challenge award (#858) --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 3 --- 1 file changed, 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 1f06ff4a6..90b20a8a6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -334,10 +334,7 @@ void function CaptureFlag( entity player, entity flag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) if( !HasPlayerCompletedMeritScore( player ) ) - { - AddPlayerScore( player, "ChallengeCTFRetAssist" ) SetPlayerChallengeMeritScore( player ) - } MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) -- cgit v1.2.3 From 0aa2d0adb1812ed78a9dc3b4452f4ced01bed8f2 Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Sep 2024 20:23:10 -0300 Subject: Add `IsValidPlayer()` before flag return cleanup (#859) Add validity check to player validity as the thread of that function might end on via OnDestroy signal by disconnection, and by that point, the player is no longer valid. --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 90b20a8a6..e52b0de52 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -453,9 +453,11 @@ void function TryReturnFlag( entity player, entity flag ) OnThreadEnd( function() : ( player ) { - // cleanup - Remote_CallFunction_NonReplay( player, "ServerCallback_CTF_StopReturnFlagProgressBar" ) - StopSoundOnEntity( player, "UI_CTF_1P_FlagReturnMeter" ) + if ( IsValidPlayer( player ) ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_CTF_StopReturnFlagProgressBar" ) + StopSoundOnEntity( player, "UI_CTF_1P_FlagReturnMeter" ) + } }) player.EndSignal( "FlagReturnEnded" ) -- cgit v1.2.3 From 628e2b39fb53f2b10fa45f58a19b23c21b0439ba Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Sep 2024 20:26:57 -0300 Subject: Play effect on flag match over (#860) Actually not even vanilla does this, but this is just a fancied effect for when the match is over, the flags simply vanish together with their bases. So this adds some effects on top of it to not look so bland. --- .../mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index e52b0de52..c82dcf8fc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -171,12 +171,14 @@ void function RemoveFlags() // destroy all the flag related things if ( IsValid( file.imcFlagSpawn ) ) { + PlayFX( $"P_phase_shift_main", file.imcFlagSpawn.GetOrigin() ) file.imcFlagSpawn.Destroy() file.imcFlag.Destroy() file.imcFlagReturnTrigger.Destroy() } if ( IsValid( file.militiaFlagSpawn ) ) { + PlayFX( $"P_phase_shift_main", file.militiaFlagSpawn.GetOrigin() ) file.militiaFlagSpawn.Destroy() file.militiaFlag.Destroy() file.militiaFlagReturnTrigger.Destroy() -- cgit v1.2.3 From 957f6a3ac6ff0cca3168e15a362cee80c8e9dcf0 Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Sep 2024 20:33:36 -0300 Subject: Complete overhaul for the CTF script (#830) Refactors CTF script that was dearly needed for a while --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 358 +++++++++++++-------- 1 file changed, 220 insertions(+), 138 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index c82dcf8fc..85b80d744 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -1,5 +1,4 @@ untyped -// this needs a refactor lol global function CaptureTheFlag_Init global function RateSpawnpoints_CTF @@ -12,16 +11,31 @@ const array SWAP_FLAG_MAPS = [ struct { entity imcFlagSpawn entity imcFlag - entity imcFlagReturnTrigger entity militiaFlagSpawn entity militiaFlag - entity militiaFlagReturnTrigger array imcCaptureAssistList array militiaCaptureAssistList } file + + + + + + + + + +/* + ██████ █████ ██████ ████████ ██ ██ ██████ ███████ ████████ ██ ██ ███████ ███████ ██ █████ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██████ ██ ██ ██ ██████ █████ ██ ███████ █████ █████ ██ ███████ ██ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██████ ██ ██ ██ ██ ██████ ██ ██ ███████ ██ ██ ██ ███████ ██ ███████ ██ ██ ██████ +*/ + void function CaptureTheFlag_Init() { PrecacheModel( CTF_FLAG_MODEL ) @@ -30,30 +44,31 @@ void function CaptureTheFlag_Init() PrecacheParticleSystem( FLAG_FX_ENEMY ) CaptureTheFlagShared_Init() + SetSwitchSidesBased( true ) SetSuddenDeathBased( true ) + SetShouldUseRoundWinningKillReplay( true ) - SetRoundWinningKillReplayKillClasses( false, false ) // make these fully manual + SetRoundWinningKillReplayKillClasses( false, false ) AddCallback_OnClientConnected( CTFInitPlayer ) - + AddCallback_OnClientDisconnected( CTFPlayerDisconnected ) + AddCallback_GameStateEnter( eGameState.Prematch, CreateFlags ) AddCallback_GameStateEnter( eGameState.Epilogue, RemoveFlags ) + AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) + AddCallback_OnTouchHealthKit( "item_flag", OnFlagCollected ) + AddCallback_OnPlayerKilled( OnPlayerKilled ) AddCallback_OnPilotBecomesTitan( DropFlagForBecomingTitan ) - SetSpawnZoneRatingFunc( DecideSpawnZone_CTF ) AddSpawnpointValidationRule( VerifyCTFSpawnpoint ) - RegisterSignal( "FlagReturnEnded" ) RegisterSignal( "ResetDropTimeout" ) - // setup stuff for the functions in sh_gamemode_ctf - // don't really like using level for stuff but just how it be level.teamFlags <- {} - // setup score event earnmeter values ScoreEvent_SetEarnMeterValues( "KillPilot", 0.05, 0.20 ) ScoreEvent_SetEarnMeterValues( "Headshot", 0.0, 0.02 ) ScoreEvent_SetEarnMeterValues( "FirstStrike", 0.0, 0.05 ) @@ -67,33 +82,42 @@ void function CaptureTheFlag_Init() ScoreEvent_SetEarnMeterValues( "FlagReturn", 0.0, 0.20 ) } + + + + + + + + +/* +███████ ██████ █████ ██ ██ ███ ██ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ +███████ ██████ ███████ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ + ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ███ ███ ██ ████ ███████ ██████ ██████ ██ ██████ +*/ + void function CreateFlags() { if ( IsValid( file.imcFlagSpawn ) ) { file.imcFlagSpawn.Destroy() file.imcFlag.Destroy() - file.imcFlagReturnTrigger.Destroy() } if ( IsValid( file.militiaFlagSpawn ) ) { file.militiaFlagSpawn.Destroy() file.militiaFlag.Destroy() - file.militiaFlagReturnTrigger.Destroy() } foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) { - // on some maps flags are on the opposite side from what they should be - // likely this is because respawn uses distance checks from spawns to check this in official - // but i don't like doing that so just using a list of maps to swap them on lol bool switchedSides = HasSwitchedSides() == 1 - - // i dont know why this works and whatever we had before didn't, but yeah + bool shouldSwap = switchedSides - if (!shouldSwap && SWAP_FLAG_MAPS.contains( GetMapName() )) + if ( !shouldSwap && SWAP_FLAG_MAPS.contains( GetMapName() ) ) shouldSwap = !shouldSwap - int flagTeam = spawn.GetTeam() if ( shouldSwap ) @@ -101,48 +125,33 @@ void function CreateFlags() flagTeam = GetOtherTeam( flagTeam ) SetTeam( spawn, flagTeam ) } - - // create flag base + entity base = CreatePropDynamic( CTF_FLAG_BASE_MODEL, spawn.GetOrigin(), spawn.GetAngles(), 0 ) SetTeam( base, spawn.GetTeam() ) svGlobal.flagSpawnPoints[ flagTeam ] = base - // create flag entity flag = CreateEntity( "item_flag" ) flag.SetValueForModelKey( CTF_FLAG_MODEL ) SetTeam( flag, flagTeam ) flag.MarkAsNonMovingAttachment() - flag.Minimap_AlwaysShow( TEAM_IMC, null ) // show flag icon on minimap + flag.Minimap_AlwaysShow( TEAM_IMC, null ) flag.Minimap_AlwaysShow( TEAM_MILITIA, null ) flag.Minimap_SetAlignUpright( true ) DispatchSpawn( flag ) flag.SetModel( CTF_FLAG_MODEL ) - flag.SetOrigin( spawn.GetOrigin() + < 0, 0, base.GetBoundingMaxs().z * 2 > ) // ensure flag doesn't spawn clipped into geometry + flag.SetOrigin( spawn.GetOrigin() + < 0, 0, base.GetBoundingMaxs().z * 2 > ) flag.SetVelocity( < 0, 0, 1 > ) flag.s.canTake <- true - flag.s.playersReturning <- [] level.teamFlags[ flag.GetTeam() ] <- flag - - entity returnTrigger = CreateEntity( "trigger_cylinder" ) - SetTeam( returnTrigger, flagTeam ) - returnTrigger.SetRadius( CTF_GetFlagReturnRadius() ) - returnTrigger.SetAboveHeight( CTF_GetFlagReturnRadius() ) - returnTrigger.SetBelowHeight( CTF_GetFlagReturnRadius() ) - - returnTrigger.SetEnterCallback( OnPlayerEntersFlagReturnTrigger ) - returnTrigger.SetLeaveCallback( OnPlayerExitsFlagReturnTrigger ) - DispatchSpawn( returnTrigger ) - - thread TrackFlagReturnTrigger( flag, returnTrigger ) + thread FlagProximityTracker( flag ) if ( flagTeam == TEAM_IMC ) { file.imcFlagSpawn = base file.imcFlag = flag - file.imcFlagReturnTrigger = returnTrigger SetGlobalNetEnt( "imcFlag", file.imcFlag ) SetGlobalNetEnt( "imcFlagHome", file.imcFlagSpawn ) @@ -151,52 +160,76 @@ void function CreateFlags() { file.militiaFlagSpawn = base file.militiaFlag = flag - file.militiaFlagReturnTrigger = returnTrigger SetGlobalNetEnt( "milFlag", file.militiaFlag ) SetGlobalNetEnt( "milFlagHome", file.militiaFlagSpawn ) } } - // reset the flag states, prevents issues where flag is home but doesnt think it's home when halftime goes SetFlagStateForTeam( TEAM_MILITIA, eFlagState.None ) SetFlagStateForTeam( TEAM_IMC, eFlagState.None ) - - foreach ( entity player in GetPlayerArray() ) - CTFInitPlayer( player ) } void function RemoveFlags() { - // destroy all the flag related things if ( IsValid( file.imcFlagSpawn ) ) { PlayFX( $"P_phase_shift_main", file.imcFlagSpawn.GetOrigin() ) file.imcFlagSpawn.Destroy() file.imcFlag.Destroy() - file.imcFlagReturnTrigger.Destroy() } + if ( IsValid( file.militiaFlagSpawn ) ) { PlayFX( $"P_phase_shift_main", file.militiaFlagSpawn.GetOrigin() ) file.militiaFlagSpawn.Destroy() file.militiaFlag.Destroy() - file.militiaFlagReturnTrigger.Destroy() } - - // unsure if this is needed, since the flags are destroyed? idk + SetFlagStateForTeam( TEAM_MILITIA, eFlagState.None ) SetFlagStateForTeam( TEAM_IMC, eFlagState.None ) } void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, int team, entity player ) { - RateSpawnpoints_SpawnZones( checkClass, spawnpoints, team, player ) + vector allyFlagSpot + vector enemyFlagSpot + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + { + if( spawn.GetTeam() == team ) + allyFlagSpot = spawn.GetOrigin() + else + enemyFlagSpot = spawn.GetOrigin() + } + + foreach ( entity spawn in spawnpoints ) + { + float rating = 0.0 + float allyFlagDistance = Distance2D( spawn.GetOrigin(), allyFlagSpot ) + float enemyFlagDistance = Distance2D( spawn.GetOrigin(), enemyFlagSpot ) + + if( enemyFlagDistance > allyFlagDistance ) + { + rating += spawn.NearbyAllyScore( team, "ai" ) + rating += spawn.NearbyAllyScore( team, "titan" ) + rating += spawn.NearbyAllyScore( team, "pilot" ) + + rating += spawn.NearbyEnemyScore( team, "ai" ) + rating += spawn.NearbyEnemyScore( team, "titan" ) + rating += spawn.NearbyEnemyScore( team, "pilot" ) + + rating = rating / allyFlagDistance + } + + if ( spawn == player.p.lastSpawnPoint ) + rating += GetConVarFloat( "spawnpoint_last_spawn_rating" ) + + spawn.CalculateRating( checkClass, team, rating, rating * 0.25 ) + } } bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) { - // ensure spawnpoints aren't too close to enemy base vector allyFlagSpot vector enemyFlagSpot foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) @@ -213,23 +246,62 @@ bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) return true } + + + + + + + + +/* +██████ ██ █████ ██ ██ ███████ ██████ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ███████ ████ █████ ██████ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██ ██ ██ ███████ ██ ██ ███████ ██████ ██████ ██ ██████ +*/ + +void function OnPlaying() +{ + foreach ( entity player in GetPlayerArray() ) + CTFInitPlayer( player ) +} + void function CTFInitPlayer( entity player ) { - if ( !IsValid( file.imcFlagSpawn ) ) + if ( !GamePlaying() ) return - vector imcSpawn = file.imcFlagSpawn.GetOrigin() - Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_IMC, imcSpawn.x, imcSpawn.y, imcSpawn.z ) + if ( IsValid( file.imcFlagSpawn ) ) + { + vector imcSpawn = file.imcFlagSpawn.GetOrigin() + Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_IMC, imcSpawn.x, imcSpawn.y, imcSpawn.z ) + } + + if ( IsValid( file.militiaFlagSpawn ) ) + { + vector militiaSpawn = file.militiaFlagSpawn.GetOrigin() + Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_MILITIA, militiaSpawn.x, militiaSpawn.y, militiaSpawn.z ) + } +} + +void function CTFPlayerDisconnected( entity player ) +{ + // This has no validity checks on the player because the disconnection callback happens in the exact last frame the player entity still exists + if( !GamePlaying() ) + return - vector militiaSpawn = file.militiaFlagSpawn.GetOrigin() - Remote_CallFunction_NonReplay( player, "ServerCallback_SetFlagHomeOrigin", TEAM_MILITIA, militiaSpawn.x, militiaSpawn.y, militiaSpawn.z ) + if ( PlayerHasEnemyFlag( player ) ) + DropFlag( player, false ) } void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { if ( !IsValid( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ) ) ) // getting a crash idk return - if ( GetFlagForTeam( GetOtherTeam( victim.GetTeam() ) ).GetParent() == victim ) + + if ( PlayerHasEnemyFlag( victim ) ) { if ( victim != attacker && attacker.IsPlayer() ) AddPlayerScore( attacker, "FlagCarrierKill", victim ) @@ -238,31 +310,35 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) } } -void function TrackFlagReturnTrigger( entity flag, entity returnTrigger ) -{ - // this is a bit of a hack, it seems parenting the return trigger to the flag actually sets the pickup radius of the flag to be the same as the trigger - // this isn't wanted since only pickups should use that additional radius - flag.EndSignal( "OnDestroy" ) - - while ( true ) - { - returnTrigger.SetOrigin( flag.GetOrigin() ) - WaitFrame() - } -} + + + + + + + + +/* +███████ ██ █████ ██████ ██ ██████ ██████ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +█████ ██ ███████ ██ ███ ██ ██ ██ ██ ███ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██ ██ ██████ ███████ ██████ ██████ ██ ██████ +*/ + bool function OnFlagCollected( entity player, entity flag ) { if ( !IsAlive( player ) || flag.GetParent() != null || player.IsTitan() || player.IsPhaseShifted() ) return false if ( player.GetTeam() != flag.GetTeam() && flag.s.canTake ) - GiveFlag( player, flag ) // pickup enemy flag + GiveFlag( player, flag ) else if ( player.GetTeam() == flag.GetTeam() && IsFlagHome( flag ) && PlayerHasEnemyFlag( player ) ) - CaptureFlag( player, GetFlagForTeam( GetOtherTeam( flag.GetTeam() ) ) ) // cap the flag + CaptureFlag( player, GetFlagForTeam( GetOtherTeam( flag.GetTeam() ) ) ) - return false // don't wanna delete the flag entity + return false // Don't delete the flag } void function GiveFlag( entity player, entity flag ) @@ -271,7 +347,8 @@ void function GiveFlag( entity player, entity flag ) flag.Signal( "ResetDropTimeout" ) flag.SetParent( player, "FLAG" ) - thread DropFlagIfPhased( player, flag ) + if ( GetCurrentPlaylistVarInt( "phase_shift_drop_flag", 0 ) == 1 ) + thread DropFlagIfPhased( player, flag ) // do notifications MessageToPlayer( player, eEventNotifications.YouHaveTheEnemyFlag ) @@ -292,7 +369,7 @@ void function GiveFlag( entity player, entity flag ) void function CaptureFlag( entity player, entity flag ) { // can only capture flags during normal play or sudden death - if (GetGameState() != eGameState.Playing && GetGameState() != eGameState.SuddenDeath) + if ( GetGameState() != eGameState.Playing && GetGameState() != eGameState.SuddenDeath ) { printt( player + " tried to capture the flag, but the game state was " + GetGameState() + " not " + eGameState.Playing + " or " + eGameState.SuddenDeath) return @@ -344,10 +421,12 @@ void function CaptureFlag( entity player, entity flag ) MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() ) - if ( GameRules_GetTeamScore( team ) == GameMode_GetRoundScoreLimit( GAMETYPE ) - 1 ) + if ( GameRules_GetTeamScore( team ) == GetScoreLimit_FromPlaylist() - 1 ) { PlayFactionDialogueToTeam( "ctf_notifyWin1more", team ) PlayFactionDialogueToTeam( "ctf_notifyLose1more", GetOtherTeam( team ) ) + foreach( entity otherPlayer in GetPlayerArray() ) + Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_CTF_PlayMatchNearEndMusic" ) } } @@ -355,7 +434,7 @@ void function DropFlag( entity player, bool realDrop = true ) { entity flag = GetFlagForTeam( GetOtherTeam( player.GetTeam() ) ) - if ( flag.GetParent() != player ) + if( !IsValid( flag ) || flag.GetParent() != player ) return print( player + " dropped the flag!" ) @@ -366,94 +445,92 @@ void function DropFlag( entity player, bool realDrop = true ) if ( realDrop ) { - // start drop timeout countdown - thread TrackFlagDropTimeout( flag ) - - // add to capture assists - if ( player.GetTeam() == TEAM_IMC ) + if ( player.GetTeam() == TEAM_IMC && !file.imcCaptureAssistList.contains( player ) ) file.imcCaptureAssistList.append( player ) - else + + else if( !file.militiaCaptureAssistList.contains( player ) ) file.militiaCaptureAssistList.append( player ) - // do notifications MessageToPlayer( player, eEventNotifications.YouDroppedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_FlagDrop" ) MessageToTeam( player.GetTeam(), eEventNotifications.PlayerDroppedEnemyFlag, player, player ) - // todo need a sound here maybe MessageToTeam( GetOtherTeam( player.GetTeam() ), eEventNotifications.PlayerDroppedFriendlyFlag, player, player ) - // todo need a sound here maybe } - SetFlagStateForTeam( flag.GetTeam(), eFlagState.Home ) // used for return prompt + thread TrackFlagDropTimeout( flag ) + SetFlagStateForTeam( flag.GetTeam(), eFlagState.Home ) } void function ResetFlag( entity flag ) { - // prevents crash when flag is reset after it's been destroyed due to epilogue - if (!IsValid(flag)) - return - // ensure we can't pickup the flag after it's been dropped but before it's been reset flag.s.canTake = false if ( flag.GetParent() != null ) DropFlag( flag.GetParent(), false ) - entity spawn + entity flagBase if ( flag.GetTeam() == TEAM_IMC ) - spawn = file.imcFlagSpawn + flagBase = file.imcFlagSpawn else - spawn = file.militiaFlagSpawn + flagBase = file.militiaFlagSpawn - flag.SetOrigin( spawn.GetOrigin() + < 0, 0, spawn.GetBoundingMaxs().z + 1 > ) + flag.SetOrigin( flagBase.GetOrigin() + < 0, 0, flagBase.GetBoundingMaxs().z + 1 > ) - // we can take it again now flag.s.canTake = true - SetFlagStateForTeam( flag.GetTeam(), eFlagState.None ) // used for home + SetFlagStateForTeam( flag.GetTeam(), eFlagState.None ) flag.Signal( "ResetDropTimeout" ) } - -void function OnPlayerEntersFlagReturnTrigger( entity trigger, entity player ) +//----------------------------------------------------------------------------- +// Purpose: Check proximity for flag returns +// Input : flag - The flag entity +//----------------------------------------------------------------------------- +void function FlagProximityTracker( entity flag ) { - entity flag - if ( trigger.GetTeam() == TEAM_IMC ) - flag = file.imcFlag - else - flag = file.militiaFlag - - if( !IsValid( flag ) || !IsValid( player ) ) - return + flag.EndSignal( "OnDestroy" ) - if ( !player.IsPlayer() || player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null ) - return + array < entity > playerInsidePerimeter + while( true ) + { + if( !playerInsidePerimeter.len() ) + ArrayRemoveDead( playerInsidePerimeter ) - thread TryReturnFlag( player, flag ) -} - -void function OnPlayerExitsFlagReturnTrigger( entity trigger, entity player ) -{ - entity flag - if ( trigger.GetTeam() == TEAM_IMC ) - flag = file.imcFlag - else - flag = file.militiaFlag + foreach ( player in GetPlayerArrayOfTeam_Alive( flag.GetTeam() ) ) + { + if ( Distance( player.GetOrigin(), flag.GetOrigin() ) < CTF_GetFlagReturnRadius() ) + { + if ( player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null ) + continue + + if( playerInsidePerimeter.contains( player ) ) + continue + + playerInsidePerimeter.append( player ) + thread TryReturnFlag( player, flag ) + } + else + { + if( playerInsidePerimeter.contains( player ) ) + { + player.Signal( "CTF_LeftReturnTriggerArea" ) // Cut the progress if outside range + playerInsidePerimeter.removebyvalue( player ) + } + } + } - if ( !player.IsPlayer() || player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null ) - return - - player.Signal( "FlagReturnEnded" ) -} + WaitFrame() + } +} void function TryReturnFlag( entity player, entity flag ) { - // start return progress bar Remote_CallFunction_NonReplay( player, "ServerCallback_CTF_StartReturnFlagProgressBar", Time() + CTF_GetFlagReturnTime() ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_FlagReturnMeter" ) - OnThreadEnd( function() : ( player ) + OnThreadEnd( function() : ( flag, player ) { if ( IsValidPlayer( player ) ) { @@ -462,35 +539,37 @@ void function TryReturnFlag( entity player, entity flag ) } }) - player.EndSignal( "FlagReturnEnded" ) - flag.EndSignal( "FlagReturnEnded" ) // avoid multiple players to return one flag at once + flag.EndSignal( "CTF_ReturnedFlag" ) + flag.EndSignal( "OnDestroy" ) + + player.EndSignal( "CTF_LeftReturnTriggerArea" ) player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) wait CTF_GetFlagReturnTime() - // flag return succeeded - // return flag ResetFlag( flag ) - flag.Signal( "FlagReturnEnded" ) - - // do notifications for return + + MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) + EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) + PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) + MessageToPlayer( player, eEventNotifications.YouReturnedFriendlyFlag ) AddPlayerScore( player, "FlagReturn", player ) player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, 1 ) - if( !HasPlayerCompletedMeritScore( player ) ) + if ( !HasPlayerCompletedMeritScore( player ) ) { AddPlayerScore( player, "ChallengeCTFRetAssist" ) SetPlayerChallengeMeritScore( player ) } - MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) - EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) - PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) - MessageToTeam( GetOtherTeam( flag.GetTeam() ), eEventNotifications.PlayerReturnedEnemyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyReturnsFlag", GetOtherTeam( flag.GetTeam() ) ) + EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_ReturnsFlag" ) PlayFactionDialogueToTeam( "ctf_flagReturnedEnemy", GetOtherTeam( flag.GetTeam() ) ) + + flag.Signal( "CTF_ReturnedFlag" ) } void function SetFlagStateForTeam( int team, int state ) @@ -507,6 +586,7 @@ void function DropFlagIfPhased( entity player, entity flag ) { player.EndSignal( "StartPhaseShift" ) player.EndSignal( "OnDestroy" ) + flag.EndSignal( "OnDestroy" ) OnThreadEnd( function() : ( player ) { @@ -516,8 +596,8 @@ void function DropFlagIfPhased( entity player, entity flag ) DropFlag( player, true ) } }) - // the IsValid check is purely to prevent a crash due to a destroyed flag (epilogue) - while( IsValid(flag) && flag.GetParent() == player ) + + while( flag.GetParent() == player ) WaitFrame() } @@ -528,7 +608,9 @@ void function DropFlagForBecomingTitan( entity pilot, entity titan ) void function TrackFlagDropTimeout( entity flag ) { + flag.EndSignal( "CTF_ReturnedFlag" ) flag.EndSignal( "ResetDropTimeout" ) + flag.EndSignal( "OnDestroy" ) wait CTF_GetDropTimeout() -- cgit v1.2.3 From 34e5b52282a7d3619e032a928d16058cc7044678 Mon Sep 17 00:00:00 2001 From: LightBlueCube <115393812+LightBlueCube@users.noreply.github.com> Date: Tue, 3 Sep 2024 07:49:15 +0800 Subject: Prevent rare crash when player disconnects during War Games intro (#856) --- .../mod/scripts/vscripts/mp/levels/mp_wargames.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut index 8d859ba63..376c5b7c3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut @@ -231,6 +231,8 @@ void function OnPrematchStart() void function PlayerWatchesWargamesIntro( entity player ) { + player.EndSignal( "OnDestroy" ) + if ( IsAlive( player ) ) player.Die() @@ -253,8 +255,6 @@ void function PlayerWatchesWargamesIntro( entity player ) // we need to wait a frame if we killed ourselves to spawn into this, so just easier to do it all the time to remove any weirdness WaitFrame() - - player.EndSignal( "OnDestroy" ) player.EndSignal( "OnDeath" ) int factionTeam = ConvertPlayerFactionToIMCOrMilitiaTeam( player ) -- cgit v1.2.3 From 23abddd7019a186230f794c483cd5372a3b89c66 Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Sep 2024 20:55:10 -0300 Subject: Remove `SetShouldCreateMinimapSpawnZones()` from `_gamemode_ps.nut` (#861) Function is not necessary anymore, the reworked spawning logic at #829 uses playlistvars to control spawnzones creation on minimap. --- .../mod/scripts/vscripts/gamemodes/_gamemode_ps.nut | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index c91c27d11..fb84cc82b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -20,12 +20,6 @@ void function GamemodePs_Init() ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) SetupGenericFFAChallenge() - - // spawnzone stuff - SetShouldCreateMinimapSpawnZones( true ) - - //AddCallback_OnPlayerKilled( CheckSpawnzoneSuspiciousDeaths ) - //AddSpawnCallbackEditorClass( "trigger_multiple", "trigger_mp_spawn_zone", SpawnzoneTriggerInit ) file.militiaPreviousSpawnZones = [ null, null, null ] file.imcPreviousSpawnZones = [ null, null, null ] -- cgit v1.2.3 From e66b164473151573905db92781b87b11e867c46f Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:40:48 +0200 Subject: Add basic contributing docs (#664) Adds initial docs with guidelines for contributing --- CONTRIBUTING.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..64b8c0c3c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing +> NOTE: This is the first iteration of this file. You're welcome to pull request changes + +### Contents +- [Making issues](#Making-issues) +- [Making pull requests](#Making-pull-requests) +- [Formatting code](#Formatting-code) + +## Making issues +When creating issues, whether to track a bug or suggest a feature, please try to follow this set of rules: +1. When filing a bug report issue, please attach a log file ( Located in `R2Northstar/logs/` ). +2. **Short, consise.** No-one wants to read an essay on why x should be added. +3. When applicable attach a short video / screen shots to better convey what the issue is about. + +## Making pull requests +When creating a pull request please follow this set of rules: +1. **1 Fix/Feature should equal to 1 Pull Request.** The more you do in 1 PR the longer it'll take to merge. +2. Mark your Pull Request as draft if it isnt finished just yet. +3. Properly format your code. As we currently don't have a formatter we're very lax on this. That doesn't mean you don't have to try to format your code. +4. **Mention how to test your changes / add a test mod to make it easier to test** + +## Formatting code +A basic set of rules you should follow when creating a Pull Request + +### Comment your code +- If you're adding a new file you should add a doc comment noting what the file does and its origin + ```cpp + ///----------------------------------------------------------------------------- + /// Origin: Northstar + /// Purpose: handles server-side rui + ///----------------------------------------------------------------------------- + ``` + Alternative to `Origin: Northstar` would be `Origin: Respawn` +- Each function should have a header doc comment + ```cpp + ///----------------------------------------------------------------------------- + /// Sends a string message to player + /// Returns true if it succeeded + ///----------------------------------------------------------------------------- + bool function NSSendInfoMessageToPlayer( entity player, string text ) + ``` +### Functions +- Functions should have spaces in the parentheses + ```cpp + bool function NSSendInfoMessageToPlayer( entity player, string text ) + ``` +- If a function need to be threaded off using `thread` it should have a `_Threaded` suffix + +### File +- Files should use tabs for indentation -- cgit v1.2.3 From e961892684fae8d7f411986f59efb1b25bacc8d3 Mon Sep 17 00:00:00 2001 From: GeckoEidechse Date: Wed, 4 Sep 2024 12:01:43 +0200 Subject: Ensure consistent whitespace usage for alignment previous version mixed tabs and spaces --- .../mod/scripts/vscripts/weapons/_arc_cannon.nut | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut index defb1a56f..3ae60fb96 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -85,28 +85,28 @@ global const ARC_CANNON_BEAM_EFFECT_MOD = $"wpn_arc_cannon_beam_mod" global const ARC_CANNON_FX_TABLE = "exp_arc_cannon" global const ArcCannonTargetClassnames = { - [ "npc_drone" ] = true, - [ "npc_dropship" ] = true, - [ "npc_marvin" ] = true, - [ "npc_prowler" ] = true, - [ "npc_soldier" ] = true, - [ "npc_soldier_heavy" ] = true, - [ "npc_soldier_shield" ] = true, - [ "npc_spectre" ] = true, - [ "npc_stalker" ] = true, - [ "npc_super_spectre" ] = true, - [ "npc_titan" ] = true, - [ "npc_turret_floor" ] = true, - [ "npc_turret_mega" ] = true, - [ "npc_turret_sentry" ] = true, - [ "npc_frag_drone" ] = true, - [ "player" ] = true, - [ "prop_dynamic" ] = true, - [ "prop_script" ] = true, - [ "grenade_frag" ] = true, - [ "rpg_missile" ] = true, - [ "script_mover" ] = true, - [ "turret" ] = true, + [ "npc_drone" ] = true, + [ "npc_dropship" ] = true, + [ "npc_marvin" ] = true, + [ "npc_prowler" ] = true, + [ "npc_soldier" ] = true, + [ "npc_soldier_heavy" ] = true, + [ "npc_soldier_shield" ] = true, + [ "npc_spectre" ] = true, + [ "npc_stalker" ] = true, + [ "npc_super_spectre" ] = true, + [ "npc_titan" ] = true, + [ "npc_turret_floor" ] = true, + [ "npc_turret_mega" ] = true, + [ "npc_turret_sentry" ] = true, + [ "npc_frag_drone" ] = true, + [ "player" ] = true, + [ "prop_dynamic" ] = true, + [ "prop_script" ] = true, + [ "grenade_frag" ] = true, + [ "rpg_missile" ] = true, + [ "script_mover" ] = true, + [ "turret" ] = true, } struct { -- cgit v1.2.3 From 16c1f6da4c1c81cafab7333c3ad2047b1a591fa3 Mon Sep 17 00:00:00 2001 From: NachosChipeados <103285866+NachosChipeados@users.noreply.github.com> Date: Wed, 4 Sep 2024 06:10:12 -0400 Subject: Fix Arc Cannon not hurting `npc_gunship` and `npc_pilot_elite` (#863) Adds `npc_gunship` and `npc_pilot_elite` to the target list. --- Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut index 3ae60fb96..e198f7265 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -87,11 +87,13 @@ global const ARC_CANNON_FX_TABLE = "exp_arc_cannon" global const ArcCannonTargetClassnames = { [ "npc_drone" ] = true, [ "npc_dropship" ] = true, + [ "npc_gunship" ] = true, [ "npc_marvin" ] = true, [ "npc_prowler" ] = true, [ "npc_soldier" ] = true, [ "npc_soldier_heavy" ] = true, [ "npc_soldier_shield" ] = true, + [ "npc_pilot_elite" ] = true, [ "npc_spectre" ] = true, [ "npc_stalker" ] = true, [ "npc_super_spectre" ] = true, -- cgit v1.2.3 From b8b0f29424d1445800984ff2e5dc0b39d1fd89f6 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Thu, 5 Sep 2024 01:54:31 +0200 Subject: Translations update from Weblate (#867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (English) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/en/ Co-authored-by: Rémy Raes --- .../mod/resource/northstar_client_localisation_english.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index baceed225..29d7cddf8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -379,8 +379,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "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..." + "CHECKSUMING_TITLE" "Verifying mod integrity" + "CHECKSUMING_TEXT" "Validating files 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" -- cgit v1.2.3 From e978c6084508221cb40e5bb59277e7d33592af87 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:29:18 +0200 Subject: Translations update from Weblate (#870) Translated using Weblate (German) Currently translated at 98.4% (308 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ Co-authored-by: NeighbourVadim --- .../mod/resource/northstar_client_localisation_german.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 7951fe35b..726ad6ac8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -17,9 +17,9 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü ändern." "BACK_AUTHENTICATION_AGREEMENT" "Authentifizierungs-Einwilligung" "AUTHENTICATION_AGREEMENT" "Authentifizierungs-Einwilligung" - "AUTHENTICATION_AGREEMENT_RESTART" "Ein Neustart ist notwendig, um diese Änderung zu übernehmen" + "AUTHENTICATION_AGREEMENT_RESTART" "Ein Neustart ist notwendig, um diese Änderung zu übernehmen." - "DIALOG_AUTHENTICATING_MASTERSERVER" "Authentifizierung mit Master Server" + "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" -- cgit v1.2.3 From 6b839def7fa1aff2519dccb7cf7d9dcee661a6ef Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 7 Sep 2024 17:07:52 -0300 Subject: Refactor and improve spawns (#829) Overhauls the spawning logic to primarily use native functions and with Squirrel only doing refining on the selected spawns. --- .../mod/scripts/vscripts/mp/spawn.nut | 763 ++++++++------------- 1 file changed, 302 insertions(+), 461 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index d64e3a5b6..c47552b3e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -1,27 +1,30 @@ untyped -global function InitRatings // temp for testing - global function Spawn_Init -global function SetRespawnsEnabled -global function RespawnsEnabled +global function FindSpawnPoint + global function SetSpawnpointGamemodeOverride global function GetSpawnpointGamemodeOverride global function AddSpawnpointValidationRule + +global function SetRespawnsEnabled +global function RespawnsEnabled global function CreateNoSpawnArea global function DeleteNoSpawnArea - -global function FindSpawnPoint +global function SpawnPointInNoSpawnArea global function RateSpawnpoints_Generic global function RateSpawnpoints_Frontline - -global function SetSpawnZoneRatingFunc -global function SetShouldCreateMinimapSpawnZones -global function CreateTeamSpawnZoneEntity global function RateSpawnpoints_SpawnZones global function DecideSpawnZone_Generic -global function DecideSpawnZone_CTF + +global struct spawnZoneProperties{ + int controllingTeam = TEAM_UNASSIGNED + entity minimapEnt = null + float zoneRating = 0.0 +} + +global table< entity, spawnZoneProperties > mapSpawnZones // Global so other scripts can access this for custom ratings if needed struct NoSpawnArea { @@ -35,30 +38,61 @@ struct NoSpawnArea struct { bool respawnsEnabled = true + array noSpawnAreas string spawnpointGamemodeOverride array< bool functionref( entity, int ) > customSpawnpointValidationRules - - table noSpawnAreas + bool shouldCreateMinimapSpawnzones } file + + + + + + + + + + +/* +██████ █████ ███████ ███████ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██████ ███████ ███████ █████ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ██ ███████ ███████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ + void function Spawn_Init() -{ +{ + // callbacks for generic spawns AddSpawnCallback( "info_spawnpoint_human", InitSpawnpoint ) - AddSpawnCallback( "info_spawnpoint_human_start", InitSpawnpoint ) AddSpawnCallback( "info_spawnpoint_titan", InitSpawnpoint ) + AddSpawnCallback( "info_spawnpoint_droppod", InitSpawnpoint ) + AddSpawnCallback( "info_spawnpoint_dropship", InitSpawnpoint ) + AddSpawnCallback( "info_spawnpoint_human_start", InitSpawnpoint ) AddSpawnCallback( "info_spawnpoint_titan_start", InitSpawnpoint ) - - // callbacks for generic spawns - AddCallback_EntitiesDidLoad( InitPreferSpawnNodes ) + AddSpawnCallback( "info_spawnpoint_droppod_start", InitSpawnpoint ) + AddSpawnCallback( "info_spawnpoint_dropship_start", InitSpawnpoint ) // callbacks for spawnzone spawns AddCallback_GameStateEnter( eGameState.Prematch, ResetSpawnzones ) AddSpawnCallbackEditorClass( "trigger_multiple", "trigger_mp_spawn_zone", AddSpawnZoneTrigger ) -} - -void function InitSpawnpoint( entity spawnpoint ) -{ - spawnpoint.s.lastUsedTime <- -999 + + float friendlyAIValue = 1.75 + if ( GameModeHasCapturePoints() ) + friendlyAIValue = 0.75 + + SpawnPoints_SetRatingMultipliers_Enemy( TD_TITAN, -10.0, -6.0, -1.0 ) + SpawnPoints_SetRatingMultipliers_Enemy( TD_PILOT, -10.0, -6.0, -1.0 ) + SpawnPoints_SetRatingMultipliers_Enemy( TD_AI, -2.0, -0.25, 0.0 ) + + SpawnPoints_SetRatingMultipliers_Friendly( TD_TITAN, 0.25, 1.75, friendlyAIValue ) + SpawnPoints_SetRatingMultipliers_Friendly( TD_PILOT, 0.25, 1.75, friendlyAIValue ) + SpawnPoints_SetRatingMultipliers_Friendly( TD_AI, 0.5, 0.25, 0.0 ) + + SpawnPoints_SetRatingMultiplier_PetTitan( 2.0 ) + + file.shouldCreateMinimapSpawnzones = GetCurrentPlaylistVarInt( "spawn_zone_enabled", 1 ) != 0 } void function SetRespawnsEnabled( bool enabled ) @@ -71,9 +105,10 @@ bool function RespawnsEnabled() return file.respawnsEnabled } -void function AddSpawnpointValidationRule( bool functionref( entity spawn, int team ) rule ) +void function InitSpawnpoint( entity spawnpoint ) { - file.customSpawnpointValidationRules.append( rule ) + spawnpoint.s.lastUsedTime <- -999 + spawnpoint.s.inUse <- false } string function CreateNoSpawnArea( int blockSpecificTeam, int blockEnemiesOfTeam, vector position, float lifetime, float radius ) @@ -85,11 +120,12 @@ string function CreateNoSpawnArea( int blockSpecificTeam, int blockEnemiesOfTeam noSpawnArea.lifetime = lifetime noSpawnArea.radius = radius - // generate an id noSpawnArea.id = UniqueString( "noSpawnArea" ) - thread NoSpawnAreaLifetime( noSpawnArea ) + if ( lifetime > 0 ) + thread NoSpawnAreaLifetime( noSpawnArea ) + file.noSpawnAreas.append( noSpawnArea ) return noSpawnArea.id } @@ -101,8 +137,41 @@ void function NoSpawnAreaLifetime( NoSpawnArea noSpawnArea ) void function DeleteNoSpawnArea( string noSpawnIdx ) { - if ( noSpawnIdx in file.noSpawnAreas ) - delete file.noSpawnAreas[ noSpawnIdx ] + foreach ( noSpawnArea in file.noSpawnAreas ) + { + if ( noSpawnArea.id == noSpawnIdx ) + file.noSpawnAreas.removebyvalue( noSpawnArea ) + } +} + +bool function SpawnPointInNoSpawnArea( vector vec, int team ) +{ + foreach ( noSpawnArea in file.noSpawnAreas ) + { + if ( Distance( noSpawnArea.position, vec ) < noSpawnArea.radius ) + { + if ( noSpawnArea.blockedTeam != TEAM_INVALID && noSpawnArea.blockedTeam == team ) + return true + + if ( noSpawnArea.blockOtherTeams != TEAM_INVALID && noSpawnArea.blockOtherTeams != team ) + return true + } + } + + return false +} + +bool function IsSpawnpointValidDrop( entity spawnpoint, int team ) +{ + if ( spawnpoint.IsOccupied() || spawnpoint.s.inUse ) + return false + + return true +} + +void function AddSpawnpointValidationRule( bool functionref( entity spawn, int team ) rule ) +{ + file.customSpawnpointValidationRules.append( rule ) } void function SetSpawnpointGamemodeOverride( string gamemode ) @@ -114,35 +183,38 @@ string function GetSpawnpointGamemodeOverride() { if ( file.spawnpointGamemodeOverride != "" ) return file.spawnpointGamemodeOverride - else - return GAMETYPE - unreachable + return GAMETYPE } -void function InitRatings( entity player, int team ) -{ - if ( player != null ) - SpawnPoints_InitRatings( player, team ) // no idea what the second arg supposed to be lol -} + + + + + + + + + +/* +███████ ██████ █████ ██ ██ ███ ██ ██████ ██████ ██████ ███████ ██████ ██ ███ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +███████ ██████ ███████ ██ █ ██ ██ ██ ██ ██ ██ ██████ ██ ██ █████ ██████ ██ ██ ██ ██ ██ ███ + ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ███ ███ ██ ████ ██████ ██ ██ ██████ ███████ ██ ██ ██ ██ ████ ██████ +*/ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnpoint ) { int team = player.GetTeam() - if ( HasSwitchedSides() ) - team = ( team == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA - + array spawnpoints if ( useStartSpawnpoint ) spawnpoints = isTitan ? SpawnPoints_GetTitanStart( team ) : SpawnPoints_GetPilotStart( team ) else spawnpoints = isTitan ? SpawnPoints_GetTitan() : SpawnPoints_GetPilot() - InitRatings( player, player.GetTeam() ) - - // don't think this is necessary since we call discardratings - //foreach ( entity spawnpoint in spawnpoints ) - // spawnpoint.CalculateRating( isTitan ? TD_TITAN : TD_PILOT, team, 0.0, 0.0 ) + SpawnPoints_InitRatings( player, team ) void functionref( int, array, int, entity ) ratingFunc = isTitan ? GameMode_GetTitanSpawnpointsRatingFunc( GAMETYPE ) : GameMode_GetPilotSpawnpointsRatingFunc( GAMETYPE ) ratingFunc( isTitan ? TD_TITAN : TD_PILOT, spawnpoints, team, player ) @@ -166,36 +238,46 @@ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnp spawnpoints = useStartSpawnpoint ? SpawnPoints_GetPilotStart( team ) : SpawnPoints_GetPilot() } - entity spawnpoint = GetBestSpawnpoint( player, spawnpoints ) + entity spawnpoint = GetBestSpawnpoint( player, spawnpoints, isTitan ) spawnpoint.s.lastUsedTime = Time() player.SetLastSpawnPoint( spawnpoint ) + + //SpawnPoints_DiscardRatings() return spawnpoint } -entity function GetBestSpawnpoint( entity player, array spawnpoints ) +entity function GetBestSpawnpoint( entity player, array spawnpoints, bool isTitan ) { - // not really 100% sure on this randomisation, needs some thought array validSpawns + + // I know this looks hacky but the native funcs to get the spawns is returning null arrays for FFA idk why. + if ( IsFFAGame() ) + { + spawnpoints.clear() + if ( isTitan ) + spawnpoints = GetEntArrayByClass_Expensive( "info_spawnpoint_titan" ) + else + spawnpoints = GetEntArrayByClass_Expensive( "info_spawnpoint_human" ) + } + foreach ( entity spawnpoint in spawnpoints ) { if ( IsSpawnpointValid( spawnpoint, player.GetTeam() ) ) validSpawns.append( spawnpoint ) } - if ( !validSpawns.len() ) + if ( !validSpawns.len() ) // First validity check { - // no valid spawns, very bad, so dont care about spawns being valid anymore - print( "found no valid spawns! spawns may be subpar!" ) + CodeWarning( "Map has no valid spawn points for " + GAMETYPE + " gamemode, attempting any other possible spawn point" ) foreach ( entity spawnpoint in spawnpoints ) validSpawns.append( spawnpoint ) } - // last resort - if ( !validSpawns.len() ) + if ( !validSpawns.len() ) // On all validity check, just gather the most basic spawn { - print( "map has literally 0 spawnpoints, as such everything is fucked probably, attempting to use info_player_start if present" ) + CodeWarning( "Map has no proper spawn points, falling back to info_player_start" ) entity start = GetEnt( "info_player_start" ) if ( IsValid( start ) ) @@ -203,14 +285,19 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) start.s.lastUsedTime <- -999 validSpawns.append( start ) } + else + throw( "Map has no player spawns at all" ) } - return validSpawns.getrandom() // slightly randomize it + if ( IsFFAGame() ) + return validSpawns.getrandom() + + return validSpawns[0] // Return first entry in the array because native have already sorted everything through the ratings, so first one is the best one } bool function IsSpawnpointValid( entity spawnpoint, int team ) { - if ( !spawnpoint.HasKey( "ignoreGamemode" ) || ( spawnpoint.HasKey( "ignoreGamemode" ) && spawnpoint.kv.ignoreGamemode == "0" ) ) // used by script-spawned spawnpoints + if ( !spawnpoint.HasKey( "ignoreGamemode" ) || spawnpoint.HasKey( "ignoreGamemode" ) && spawnpoint.kv.ignoreGamemode == "0" ) // used by script-spawned spawnpoints { if ( file.spawnpointGamemodeOverride != "" ) { @@ -222,223 +309,149 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } - if( IsFFAGame() && !spawnpoint.IsVisibleToEnemies( team ) ) - return true - - int compareTeam = spawnpoint.GetTeam() - if ( HasSwitchedSides() ) - compareTeam = ( compareTeam == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA - foreach ( bool functionref( entity, int ) customValidationRule in file.customSpawnpointValidationRules ) if ( !customValidationRule( spawnpoint, team ) ) return false - if ( spawnpoint.GetTeam() > 0 && compareTeam != team ) + if ( !IsSpawnpointValidDrop( spawnpoint, team ) || Time() - spawnpoint.s.lastUsedTime <= 10.0 ) return false - if ( spawnpoint.IsOccupied() ) + if ( SpawnPointInNoSpawnArea( spawnpoint.GetOrigin(), team ) ) return false - - if ( Time() - spawnpoint.s.lastUsedTime <= 10.0 ) - return false - - foreach ( k, NoSpawnArea noSpawnArea in file.noSpawnAreas ) + + // Line of Sight Check, could use IsVisibleToEnemies but apparently that considers only players, not NPCs + array< entity > enemyTitans = GetTitanArrayOfEnemies( team ) + if ( GetConVarBool( "spawnpoint_avoid_npc_titan_sight" ) ) { - if ( Distance( noSpawnArea.position, spawnpoint.GetOrigin() ) > noSpawnArea.radius ) - continue - - if ( noSpawnArea.blockedTeam != TEAM_INVALID && noSpawnArea.blockedTeam == team ) - return false - - if ( noSpawnArea.blockOtherTeams != TEAM_INVALID && noSpawnArea.blockOtherTeams != team ) - return false + foreach ( titan in enemyTitans ) + { + if ( IsAlive( titan ) && titan.IsNPC() && titan.CanSee( spawnpoint ) ) + return false + } } - - const minEnemyDist = 1200.0 - array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) - spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) - spawnBlockers.extend( GetNPCArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) - if ( spawnBlockers.len() ) - return false - // los check return !spawnpoint.IsVisibleToEnemies( team ) } -// SPAWNPOINT RATING FUNCS BELOW -// generic -struct { - array preferSpawnNodes -} spawnStateGeneric -void function RateSpawnpoints_Generic( int checkClass, array spawnpoints, int team, entity player ) -{ - if ( !IsFFAGame() ) - { - // use frontline spawns in 2-team modes - RateSpawnpoints_Frontline( checkClass, spawnpoints, team, player ) - return - } - else - { - // todo: ffa spawns :terror: - } - // old algo: keeping until we have a better ffa spawn algo - // i'm not a fan of this func, but i really don't have a better way to do this rn, and it's surprisingly good with los checks implemented now - - // calculate ratings for preferred nodes - // this tries to prefer nodes with more teammates, then activity on them - // todo: in the future it might be good to have this prefer nodes with enemies up to a limit of some sort - // especially in ffa modes i could deffo see this falling apart a bit rn - // perhaps dead players could be used to calculate some sort of activity rating? so high-activity points with an even balance of friendly/unfriendly players are preferred - array preferSpawnNodeRatings - foreach ( vector preferSpawnNode in spawnStateGeneric.preferSpawnNodes ) + + + + +/* +██████ ██████ ██ ███ ██ ████████ ██████ █████ ████████ ██ ███ ██ ██████ +██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██████ ██ ██ ██ ██ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██████ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██████ +*/ + +void function RateSpawnpoints_Generic( int checkClass, array spawnpoints, int team, entity player ) +{ + foreach ( entity spawnpoint in spawnpoints ) { - float currentRating + float currentRating = 0.0 - // this seems weird, not using rn - //Frontline currentFrontline = GetCurrentFrontline( team ) - //if ( !IsFFAGame() || currentFrontline.friendlyCenter != < 0, 0, 0 > ) - // currentRating += max( 0.0, ( 1000.0 - Distance2D( currentFrontline.origin, preferSpawnNode ) ) / 200 ) + // Gather friendly scoring first to give positive rating first + currentRating += spawnpoint.NearbyAllyScore( team, "ai" ) + currentRating += spawnpoint.NearbyAllyScore( team, "titan" ) + currentRating += spawnpoint.NearbyAllyScore( team, "pilot" ) - foreach ( entity nodePlayer in GetPlayerArray() ) - { - float currentChange = 0.0 - - // the closer a player is to a node the more they matter - float dist = Distance2D( preferSpawnNode, nodePlayer.GetOrigin() ) - if ( dist > 600.0 ) - continue - - currentChange = ( 600.0 - dist ) / 5 - if ( player == nodePlayer ) - currentChange *= -3 // always try to stay away from places we've already spawned - else if ( !IsAlive( nodePlayer ) ) // dead players mean activity which is good, but they're also dead so they don't matter as much as living ones - currentChange *= 0.6 - if ( nodePlayer.GetTeam() != player.GetTeam() ) // if someone isn't on our team and alive they're probably bad - { - if ( IsFFAGame() ) // in ffa everyone is on different teams, so this isn't such a big deal - currentChange *= -0.2 - else - currentChange *= -0.6 - } - - currentRating += currentChange - } + // Enemies then subtract that rating ( Values already returns negative, so no need to apply subtract again ) + currentRating += spawnpoint.NearbyEnemyScore( team, "ai" ) + currentRating += spawnpoint.NearbyEnemyScore( team, "titan" ) + currentRating += spawnpoint.NearbyEnemyScore( team, "pilot" ) - preferSpawnNodeRatings.append( currentRating ) - } - - foreach ( entity spawnpoint in spawnpoints ) - { - float currentRating - float petTitanModifier - // scale how much a given spawnpoint matters to us based on how far it is from each node - bool spawnHasRecievedInitialBonus = false - for ( int i = 0; i < spawnStateGeneric.preferSpawnNodes.len(); i++ ) - { - // bonus if autotitan is nearish - if ( IsAlive( player.GetPetTitan() ) && Distance( player.GetPetTitan().GetOrigin(), spawnStateGeneric.preferSpawnNodes[ i ] ) < 1200.0 ) - petTitanModifier += 10.0 - - float dist = Distance2D( spawnpoint.GetOrigin(), spawnStateGeneric.preferSpawnNodes[ i ] ) - if ( dist > 750.0 ) - continue - - if ( dist < 600.0 && !spawnHasRecievedInitialBonus ) - { - currentRating += 10.0 - spawnHasRecievedInitialBonus = true // should only get a bonus for simply being by a node once to avoid over-rating - } + if ( spawnpoint == player.p.lastSpawnPoint ) // Reduce the rating of the spawn point used previously + currentRating += GetConVarFloat( "spawnpoint_last_spawn_rating" ) - currentRating += ( preferSpawnNodeRatings[ i ] * ( ( 750.0 - dist ) / 75 ) ) + max( RandomFloat( 1.25 ), 0.9 ) - if ( dist < 250.0 ) // shouldn't get TOO close to an active node - currentRating *= 0.7 - - if ( spawnpoint.s.lastUsedTime < 10.0 ) - currentRating *= 0.7 - } - - float rating = spawnpoint.CalculateRating( checkClass, team, currentRating, currentRating + petTitanModifier ) - //print( "spawnpoint at " + spawnpoint.GetOrigin() + " has rating: " + ) - - if ( rating != 0.0 || currentRating != 0.0 ) - print( "rating = " + rating + ", internal rating = " + currentRating ) + spawnpoint.CalculateRating( checkClass, team, currentRating, currentRating * 0.25 ) } } -void function InitPreferSpawnNodes() +void function RateSpawnpoints_Frontline( int checkClass, array spawnpoints, int team, entity player ) { - foreach ( entity hardpoint in GetEntArrayByClass_Expensive( "info_hardpoint" ) ) + Frontline currentFrontline = GetFrontline( team ) + + vector inverseFrontlineDir = currentFrontline.combatDir * -1 + vector adjustedPosition = currentFrontline.origin + currentFrontline.combatDir * 8000 + + SpawnPoints_InitFrontlineData( adjustedPosition, currentFrontline.combatDir, currentFrontline.origin, currentFrontline.friendlyCenter, 4000 ) + + foreach ( entity spawnpoint in spawnpoints ) { - if ( !hardpoint.HasKey( "hardpointGroup" ) ) - continue - - if ( hardpoint.kv.hardpointGroup != "A" && hardpoint.kv.hardpointGroup != "B" && hardpoint.kv.hardpointGroup != "C" ) - continue - - spawnStateGeneric.preferSpawnNodes.append( hardpoint.GetOrigin() ) + float frontlineRating = spawnpoint.CalculateFrontlineRating() + + spawnpoint.CalculateRating( checkClass, team, frontlineRating, frontlineRating * 0.25 ) } - - //foreach ( entity frontline in GetEntArrayByClass_Expensive( "info_frontline" ) ) - // spawnStateGeneric.preferSpawnNodes.append( frontline.GetOrigin() ) } -// frontline -void function RateSpawnpoints_Frontline( int checkClass, array spawnpoints, int team, entity player ) -{ - float rating = RandomFloatRange( 0.0, 100.0 ) - foreach ( entity spawnpoint in spawnpoints ) - spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating ) -} -// spawnzones -struct { - array mapSpawnzoneTriggers - entity functionref( array, int ) spawnzoneRatingFunc - bool shouldCreateMinimapSpawnzones = false - - // for DecideSpawnZone_Generic - table activeTeamSpawnzones - table activeTeamSpawnzoneMinimapEnts -} spawnStateSpawnzones + + + + + + + + +/* +███████ ██████ █████ ██ ██ ███ ██ ███████ ██████ ███ ██ ███████ ███████ +██ ██ ██ ██ ██ ██ ██ ████ ██ ███ ██ ██ ████ ██ ██ ██ +███████ ██████ ███████ ██ █ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ █████ ███████ + ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ███ ███ ██ ████ ███████ ██████ ██ ████ ███████ ███████ +*/ void function ResetSpawnzones() { - spawnStateSpawnzones.activeTeamSpawnzones.clear() - - foreach ( int team, entity minimapEnt in spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts ) - if ( IsValid( minimapEnt ) ) - minimapEnt.Destroy() - - spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts.clear() + foreach ( zone, zoneProperties in mapSpawnZones ) + { + if ( IsValid( zoneProperties.minimapEnt ) ) + zoneProperties.minimapEnt.Destroy() + + zoneProperties.controllingTeam = TEAM_UNASSIGNED + zoneProperties.zoneRating = 0.0 + } } void function AddSpawnZoneTrigger( entity trigger ) { - trigger.s.spawnzoneRating <- 0.0 - spawnStateSpawnzones.mapSpawnzoneTriggers.append( trigger ) + spawnZoneProperties zoneProperties + mapSpawnZones[trigger] <- zoneProperties } -void function SetSpawnZoneRatingFunc( entity functionref( array, int ) ratingFunc ) +bool function TeamHasDirtySpawnzone( int team ) { - spawnStateSpawnzones.spawnzoneRatingFunc = ratingFunc -} - -void function SetShouldCreateMinimapSpawnZones( bool shouldCreateMinimapSpawnzones ) -{ - spawnStateSpawnzones.shouldCreateMinimapSpawnzones = shouldCreateMinimapSpawnzones + foreach ( zone, zoneProperties in mapSpawnZones ) + { + if ( zoneProperties.controllingTeam == team ) + { + int numDeadInZone = 0 + array teamPlayers = GetPlayerArrayOfTeam( team ) + foreach ( entity player in teamPlayers ) + { + if ( Time() - player.p.postDeathThreadStartTime < 20.0 && zone.ContainsPoint( player.p.deathOrigin ) ) + numDeadInZone++ + } + + if ( numDeadInZone < teamPlayers.len() ) + return false + } + } + + return true } -entity function CreateTeamSpawnZoneEntity( entity spawnzone, int team ) +void function CreateTeamSpawnZoneEntity( entity spawnzone, int team ) { entity minimapObj = CreatePropScript( $"models/dev/empty_model.mdl", spawnzone.GetOrigin() ) SetTeam( minimapObj, team ) - minimapObj.Minimap_SetObjectScale( 100.0 / Distance2D( < 0, 0, 0 >, spawnzone.GetBoundingMaxs() ) ) + minimapObj.Minimap_SetObjectScale( Distance2D( < 0, 0, 0 >, spawnzone.GetBoundingMaxs() ) / 16000 ) // 16000 cuz thats the total space Minimap uses minimapObj.Minimap_SetAlignUpright( true ) minimapObj.Minimap_AlwaysShow( TEAM_IMC, null ) minimapObj.Minimap_AlwaysShow( TEAM_MILITIA, null ) @@ -451,67 +464,58 @@ entity function CreateTeamSpawnZoneEntity( entity spawnzone, int team ) minimapObj.Minimap_SetCustomState( eMinimapObject_prop_script.SPAWNZONE_MIL ) minimapObj.DisableHibernation() - return minimapObj + mapSpawnZones[spawnzone].minimapEnt = minimapObj } void function RateSpawnpoints_SpawnZones( int checkClass, array spawnpoints, int team, entity player ) { - if ( spawnStateSpawnzones.spawnzoneRatingFunc == null ) - spawnStateSpawnzones.spawnzoneRatingFunc = DecideSpawnZone_Generic - - // don't use spawnzones if we're using start spawns if ( ShouldStartSpawn( player ) ) { RateSpawnpoints_Generic( checkClass, spawnpoints, team, player ) return } - - entity spawnzone = spawnStateSpawnzones.spawnzoneRatingFunc( spawnStateSpawnzones.mapSpawnzoneTriggers, player.GetTeam() ) - if ( !IsValid( spawnzone ) ) // no spawn zone, use generic algo + + array< entity > zoneTriggers + foreach ( zone, zoneProperties in mapSpawnZones ) + zoneTriggers.append( zone ) + + entity spawnzone = DecideSpawnZone_Generic( zoneTriggers, player.GetTeam() ) + if ( !IsValid( spawnzone ) ) { RateSpawnpoints_Generic( checkClass, spawnpoints, team, player ) return } - // rate spawnpoints foreach ( entity spawn in spawnpoints ) { float rating = 0.0 float distance = Distance2D( spawn.GetOrigin(), spawnzone.GetOrigin() ) if ( distance < Distance2D( < 0, 0, 0 >, spawnzone.GetBoundingMaxs() ) ) - rating = 100.0 - else // max 35 rating if not in zone, rate by closest - rating = 35.0 * ( 1 - ( distance / 5000.0 ) ) + rating = 10.0 + else + rating = 2.0 * ( 1 - ( distance / 3000.0 ) ) - spawn.CalculateRating( checkClass, player.GetTeam(), rating, rating ) + spawn.CalculateRating( checkClass, team, rating, rating * 0.25 ) } } entity function DecideSpawnZone_Generic( array spawnzones, int team ) { - if ( spawnzones.len() == 0 ) + if ( !spawnzones.len() ) return null - // get average team startspawn positions - int spawnCompareTeam = team - if ( HasSwitchedSides() ) - spawnCompareTeam = GetOtherTeam( team ) - - array startSpawns = SpawnPoints_GetPilotStart( spawnCompareTeam ) - array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( spawnCompareTeam ) ) + array startSpawns = SpawnPoints_GetPilotStart( team ) + array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( team ) ) - if ( startSpawns.len() == 0 || enemyStartSpawns.len() == 0 ) // ensure we don't crash + if ( !startSpawns.len() || !enemyStartSpawns.len() ) return null - - // get average startspawn position and max dist between spawns - // could probably cache this, tbh, not like it should change outside of halftimes - vector averageFriendlySpawns + + vector averageFriendlySpawns foreach ( entity spawn in startSpawns ) averageFriendlySpawns += spawn.GetOrigin() averageFriendlySpawns /= startSpawns.len() - // get average enemy startspawn position vector averageEnemySpawns foreach ( entity spawn in enemyStartSpawns ) averageEnemySpawns += spawn.GetOrigin() @@ -520,250 +524,87 @@ entity function DecideSpawnZone_Generic( array spawnzones, int team ) float baseDistance = Distance2D( averageFriendlySpawns, averageEnemySpawns ) - bool needNewZone = true - if ( team in spawnStateSpawnzones.activeTeamSpawnzones ) + if ( TeamHasDirtySpawnzone( team ) ) { - foreach ( entity player in GetPlayerArray() ) - { - // couldn't get IsTouching, GetTouchingEntities or enter callbacks to work in testing, so doing this - if ( player.GetTeam() != team && spawnStateSpawnzones.activeTeamSpawnzones[ team ].ContainsPoint( player.GetOrigin() ) ) - break - } - - int numDeadInZone = 0 - array teamPlayers = GetPlayerArrayOfTeam( team ) - foreach ( entity player in teamPlayers ) - { - // check if they died in the zone recently, get a new zone if too many died - if ( Time() - player.p.postDeathThreadStartTime < 15.0 && spawnStateSpawnzones.activeTeamSpawnzones[ team ].ContainsPoint( player.p.deathOrigin ) ) - numDeadInZone++ - } - - // cast to float so result is float - if ( float( numDeadInZone ) / teamPlayers.len() <= 0.1 ) - needNewZone = false - } - - if ( needNewZone ) - { - // find new zone array possibleZones - foreach ( entity spawnzone in spawnStateSpawnzones.mapSpawnzoneTriggers ) + foreach ( zone, zoneProperties in mapSpawnZones ) { - // don't remember if you can do a "value in table.values" sorta thing in squirrel so doing manual lookup - bool spawnzoneTaken = false - foreach ( int otherTeam, entity otherSpawnzone in spawnStateSpawnzones.activeTeamSpawnzones ) - { - if ( otherSpawnzone == spawnzone ) - { - spawnzoneTaken = true - break - } - } - - if ( spawnzoneTaken ) + if ( zoneProperties.controllingTeam == GetOtherTeam( team ) ) continue - // check zone validity - bool spawnzoneEvil = false - foreach ( entity player in GetPlayerArray() ) + bool spawnzoneHasEnemies = false + foreach ( entity enemy in GetPlayerArrayOfEnemies_Alive( team ) ) { - // couldn't get IsTouching, GetTouchingEntities or enter callbacks to work in testing, so doing this - if ( player.GetTeam() != team && spawnzone.ContainsPoint( player.GetOrigin() ) ) + if ( zone.ContainsPoint( enemy.GetOrigin() ) ) { - spawnzoneEvil = true + spawnzoneHasEnemies = true break } } - // don't choose spawnzones that are closer to enemy base than friendly base - // note: vanilla spawns might not necessarily require this, worth checking - if ( !spawnzoneEvil && Distance2D( spawnzone.GetOrigin(), averageFriendlySpawns ) > Distance2D( spawnzone.GetOrigin(), averageEnemySpawns ) ) - spawnzoneEvil = true + if ( !spawnzoneHasEnemies && Distance2D( zone.GetOrigin(), averageFriendlySpawns ) > Distance2D( zone.GetOrigin(), averageEnemySpawns ) ) + spawnzoneHasEnemies = true - if ( spawnzoneEvil ) + if ( spawnzoneHasEnemies ) continue - // rate spawnzone based on distance to frontline Frontline frontline = GetFrontline( team ) - - // prefer spawns close to base pos - float rating = 10 * ( 1.0 - Distance2D( averageFriendlySpawns, spawnzone.GetOrigin() ) / baseDistance ) + float rating = 10 * ( 1.0 - Distance2D( averageFriendlySpawns, zone.GetOrigin() ) / baseDistance ) if ( frontline.friendlyCenter != < 0, 0, 0 > ) { - // rate based on distance to frontline, and then prefer spawns in the same dir from the frontline as the combatdir - rating += rating * ( 1.0 - ( Distance2D( spawnzone.GetOrigin(), frontline.friendlyCenter ) / baseDistance ) ) - rating *= fabs( frontline.combatDir.y - Normalize( spawnzone.GetOrigin() - averageFriendlySpawns ).y ) + rating += rating * ( 1.0 - ( Distance2D( zone.GetOrigin(), frontline.friendlyCenter ) / baseDistance ) ) + rating *= fabs( frontline.combatDir.y - Normalize( zone.GetOrigin() - averageFriendlySpawns ).y ) } - spawnzone.s.spawnzoneRating = rating - possibleZones.append( spawnzone ) + zoneProperties.zoneRating = rating + possibleZones.append( zone ) } - if ( possibleZones.len() == 0 ) + if ( !possibleZones.len() ) return null - possibleZones.sort( int function( entity a, entity b ) - { - if ( a.s.spawnzoneRating > b.s.spawnzoneRating ) - return -1 - - if ( b.s.spawnzoneRating > a.s.spawnzoneRating ) - return 1 - - return 0 - } ) - entity chosenZone = possibleZones[ minint( RandomInt( 3 ), possibleZones.len() - 1 ) ] - - if ( spawnStateSpawnzones.shouldCreateMinimapSpawnzones ) - { - entity oldEnt - if ( team in spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts ) - oldEnt = spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts[ team ] - - spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts[ team ] <- CreateTeamSpawnZoneEntity( chosenZone, team ) - if ( IsValid( oldEnt ) ) - oldEnt.Destroy() - } + possibleZones.sort( SortPossibleZones ) - spawnStateSpawnzones.activeTeamSpawnzones[ team ] <- chosenZone - } - - return spawnStateSpawnzones.activeTeamSpawnzones[ team ] -} - -// ideally this should be in the gamemode_ctf file, but would need refactors to expose more stuff that's not available there rn -entity function DecideSpawnZone_CTF( array spawnzones, int team ) -{ - if ( spawnzones.len() == 0 ) - return null - - int otherTeam = GetOtherTeam( team ) - array enemyPlayers = GetPlayerArrayOfTeam( otherTeam ) - - // get average team startspawn positions - int spawnCompareTeam = team - if ( HasSwitchedSides() ) - spawnCompareTeam = GetOtherTeam( team ) - - array startSpawns = SpawnPoints_GetPilotStart( spawnCompareTeam ) - array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( spawnCompareTeam ) ) - - if ( startSpawns.len() == 0 || enemyStartSpawns.len() == 0 ) // ensure we don't crash - return null - - // get average startspawn position and max dist between spawns - // could probably cache this, tbh, not like it should change outside of halftimes - vector averageFriendlySpawns - foreach ( entity spawn in startSpawns ) - averageFriendlySpawns += spawn.GetOrigin() - - averageFriendlySpawns /= startSpawns.len() - - // get average enemy startspawn position - vector averageEnemySpawns - foreach ( entity spawn in enemyStartSpawns ) - averageEnemySpawns += spawn.GetOrigin() - - averageEnemySpawns /= enemyStartSpawns.len() - - float baseDistance = Distance2D( averageFriendlySpawns, averageEnemySpawns ) - - // find new zone - array possibleZones - foreach ( entity spawnzone in spawnStateSpawnzones.mapSpawnzoneTriggers ) - { - // can't choose zone if another team has it - if ( otherTeam in spawnStateSpawnzones.activeTeamSpawnzones && spawnStateSpawnzones.activeTeamSpawnzones[ otherTeam ] == spawnzone ) - continue + entity chosenZone = possibleZones[ minint( RandomInt( 3 ), possibleZones.len() - 1 ) ] - // check zone validity - bool spawnzoneEvil = false - foreach ( entity player in enemyPlayers ) + if ( file.shouldCreateMinimapSpawnzones ) { - // couldn't get IsTouching, GetTouchingEntities or enter callbacks to work in testing, so doing this - if ( spawnzone.ContainsPoint( player.GetOrigin() ) ) + foreach ( zone, zoneProperties in mapSpawnZones ) { - spawnzoneEvil = true - break + if ( chosenZone == zone ) + continue + + if ( IsValid( zoneProperties.minimapEnt ) && zoneProperties.controllingTeam == team ) + zoneProperties.minimapEnt.Destroy() } + + CreateTeamSpawnZoneEntity( chosenZone, team ) } - // don't choose spawnzones that are closer to enemy base than friendly base - if ( !spawnzoneEvil && Distance2D( spawnzone.GetOrigin(), averageFriendlySpawns ) > Distance2D( spawnzone.GetOrigin(), averageEnemySpawns ) ) - spawnzoneEvil = true - - if ( spawnzoneEvil ) - continue - - // rate spawnzone based on distance to frontline - Frontline frontline = GetFrontline( team ) - - // prefer spawns close to base pos - float rating = 10 * ( 1.0 - Distance2D( averageFriendlySpawns, spawnzone.GetOrigin() ) / baseDistance ) - - if ( frontline.friendlyCenter != < 0, 0, 0 > ) + foreach ( zone, zoneProperties in mapSpawnZones ) { - // rate based on distance to frontline, and then prefer spawns in the same dir from the frontline as the combatdir - rating += rating * ( 1.0 - ( Distance2D( spawnzone.GetOrigin(), frontline.friendlyCenter ) / baseDistance ) ) - rating *= fabs( frontline.combatDir.y - Normalize( spawnzone.GetOrigin() - averageFriendlySpawns ).y ) - - // reduce rating based on players that can currently see the zone - bool hasAppliedInitialLoss = false - foreach ( entity player in enemyPlayers ) - { - // don't trace here, just do an angle check - if ( PlayerCanSee( player, spawnzone, false, 65 ) && Distance2D( player.GetOrigin(), spawnzone.GetOrigin() ) <= 2000.0 ) - { - float distFrac = TraceLineSimple( player.GetOrigin(), spawnzone.GetOrigin(), player ) - - if ( distFrac >= 0.65 ) - { - // give a fairly large loss if literally anyone can see it - if ( !hasAppliedInitialLoss ) - { - rating *= 0.8 - hasAppliedInitialLoss = true - } - - rating *= ( 1.0 / enemyPlayers.len() ) * distFrac - } - } - } + if ( chosenZone == zone ) + continue + + if ( zoneProperties.controllingTeam == team ) + zoneProperties.controllingTeam = TEAM_UNASSIGNED } - spawnzone.s.spawnzoneRating = rating - possibleZones.append( spawnzone ) + mapSpawnZones[chosenZone].controllingTeam = team + return chosenZone } - if ( possibleZones.len() == 0 ) - return null - - possibleZones.sort( int function( entity a, entity b ) - { - if ( a.s.spawnzoneRating > b.s.spawnzoneRating ) - return -1 + return null +} + +int function SortPossibleZones( entity a, entity b ) +{ + if ( mapSpawnZones[a].zoneRating > mapSpawnZones[b].zoneRating ) + return -1 - if ( b.s.spawnzoneRating > a.s.spawnzoneRating ) - return 1 + if ( mapSpawnZones[b].zoneRating > mapSpawnZones[a].zoneRating ) + return 1 - return 0 - } ) - entity chosenZone = possibleZones[ minint( RandomInt( 3 ), possibleZones.len() - 1 ) ] - - if ( spawnStateSpawnzones.shouldCreateMinimapSpawnzones ) - { - entity oldEnt - if ( team in spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts ) - oldEnt = spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts[ team ] - - spawnStateSpawnzones.activeTeamSpawnzoneMinimapEnts[ team ] <- CreateTeamSpawnZoneEntity( chosenZone, team ) - if ( IsValid( oldEnt ) ) - oldEnt.Destroy() - } - - spawnStateSpawnzones.activeTeamSpawnzones[ team ] <- chosenZone - - return spawnStateSpawnzones.activeTeamSpawnzones[ team ] + return 0 } \ No newline at end of file -- cgit v1.2.3 From 62b92155adc962fce83206c5de9aa210023e14da Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 7 Sep 2024 17:31:16 -0300 Subject: Expose more game state information to DiscordRPC (#869) When playing Frontier Defense it will show when the player is in a Wave Break or which Wave they are currently through Whenever the server is NOT at the Playing gamestate, the plugin will report the respective states instead such as Selecting Titan screen, Prematch, Epilogue, Postmatch, etc... --- .../mod/scripts/vscripts/cl_northstar_client_init.nut | 3 +++ .../mod/scripts/vscripts/presence/cl_presence.nut | 13 +++++++++++++ 2 files changed, 16 insertions(+) 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 3560fd562..9e683a869 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -20,6 +20,9 @@ global struct GameStateStruct { int otherHighestScore int maxScore float timeEnd + int serverGameState + int fd_waveNumber + int fd_totalWaves } global struct UIPresenceStruct { diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut index f17216fbc..142c94bad 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut @@ -30,6 +30,19 @@ GameStateStruct function DiscordRPC_GenerateGameState( GameStateStruct gs ) if ( IsValid( GetLocalClientPlayer() ) ) gs.ownScore = GameRules_GetTeamScore( GetLocalClientPlayer().GetTeam() ) + if ( GameRules_GetGameMode() == FD ) + { + gs.playlist = "fd" // So it returns only one thing to the plugin side instead of the 5 separate difficulties FD have + if ( GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_INCOMING || GetGlobalNetInt( "FD_waveState" ) == WAVE_STATE_IN_PROGRESS ) + { + gs.fd_waveNumber = GetGlobalNetInt( "FD_currentWave" ) + 1 + gs.fd_totalWaves = GetGlobalNetInt( "FD_totalWaves" ) + } + else + gs.fd_waveNumber = -1 // Tells plugin it's on Wave Break + } + + gs.serverGameState = GetGameState() == -1 ? 0 : GetGameState() gs.otherHighestScore = gs.ownScore == highestScore ? secondHighest : highestScore gs.maxScore = IsRoundBased() ? GetCurrentPlaylistVarInt( "roundscorelimit", 0 ) : GetCurrentPlaylistVarInt( "scorelimit", 0 ) -- cgit v1.2.3 From 05837fa96d914350234afab1dafaeac3e332e374 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 8 Sep 2024 01:01:59 +0200 Subject: Add GitHub Action to automatically label PRs (#871) Adds "needs code review" and "needs testing" to all new PRs Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .github/labeler.yml | 9 +++++++++ .github/workflows/auto-label-pr.yml | 14 ++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/auto-label-pr.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..cc83d7cd3 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,9 @@ +# Add 'needs code review' label to any changes within the entire repository +needs code review: +- changed-files: + - any-glob-to-any-file: '**' + +# Add 'needs testing' label to any changes within the entire repository +needs testing: +- changed-files: + - any-glob-to-any-file: '**' diff --git a/.github/workflows/auto-label-pr.yml b/.github/workflows/auto-label-pr.yml new file mode 100644 index 000000000..659ff351d --- /dev/null +++ b/.github/workflows/auto-label-pr.yml @@ -0,0 +1,14 @@ +name: Auto-Labeler +on: + pull_request_target: + types: + - opened + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 -- cgit v1.2.3 From bf5f6b02e8ad74ece0aa43d21a6cec88db6641ed Mon Sep 17 00:00:00 2001 From: Respawn Date: Mon, 9 Sep 2024 14:47:05 +0200 Subject: Add mode_select.menu from englishclient_frontend --- .../mod/resource/ui/menus/mode_select.menu | 343 +++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 Northstar.Client/mod/resource/ui/menus/mode_select.menu diff --git a/Northstar.Client/mod/resource/ui/menus/mode_select.menu b/Northstar.Client/mod/resource/ui/menus/mode_select.menu new file mode 100644 index 000000000..f8afcf0ff --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/mode_select.menu @@ -0,0 +1,343 @@ +resource/ui/menus/mode_select.menu +{ + menu + { + ControlName Frame + xpos 0 + ypos 0 + zpos 3 + wide f0 + tall f0 + autoResize 0 + pinCorner 0 + visible 1 + enabled 1 + PaintBackgroundType 0 + infocus_bgcolor_override "0 0 0 0" + outoffocus_bgcolor_override "0 0 0 0" + + MenuCommon + { + ControlName CNestedPanel + xpos 0 + ypos 0 + wide f0 + tall f0 + visible 1 + controlSettingsFile "resource/ui/menus/panels/menu_common.res" + } + + MatchmakingStatus + { + ControlName CNestedPanel + xpos 0 + ypos 0 + wide f0 + tall f0 + visible 1 + controlSettingsFile "resource/ui/menus/panels/matchmaking_status.res" + } + + NextModeImageFrame + { + ControlName RuiPanel + xpos 800 + ypos 160 + wide 860 + tall 418 + labelText "" + visible 1 + bgcolor_override "0 0 0 0" + paintbackground 1 + rui "ui/basic_border_box.rpak" + } + + NextModeImage + { + ControlName RuiPanel + pin_to_sibling NextModeImageFrame + pin_corner_to_sibling BOTTOM + pin_to_sibling_corner BOTTOM +// xpos -12 + ypos -12 + wide 480 + tall 240 + visible 1 + scaleImage 1 + rui "ui/basic_menu_image.rpak" + zpos 2 + } + + ModeIconImage + { + ControlName RuiPanel + pin_to_sibling NextModeImage + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + xpos 0 + ypos -16 + wide 72 + tall 72 + visible 1 + scaleImage 1 + rui "ui/basic_image_add.rpak" + zpos 2 + } + + NextModeName + { + ControlName Label + pin_to_sibling NextModeImageFrame + pin_corner_to_sibling TOP + pin_to_sibling_corner TOP + ypos -20 + wide 840 + auto_tall_tocontents 1 + visible 1 + labelText "Foo" + textAlignment center + centerWrap 1 + font Default_43_DropShadow + allcaps 1 + fgcolor_override "255 255 255 255" + } + + NextModeDesc + { + ControlName Label + pin_to_sibling NextModeName + pin_corner_to_sibling TOP + pin_to_sibling_corner BOTTOM + xpos 0 + ypos 0 + wide 840 + wrap 1 + auto_tall_tocontents 1 + visible 1 + labelText "Bar" + textAlignment center + centerWrap 1 + font Default_27 + allcaps 0 + fgcolor_override "255 255 255 255" + } + + MenuTitle + { + ControlName Label + InheritProperties MenuTitle + labelText "#SELECT_GAME_MODE" + } + + ButtonRowAnchor + { + ControlName Label + labelText "" + + xpos 96 + ypos 160 + } + + BtnMode1 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 0 + navUp BtnMode15 + navDown BtnMode2 + + pin_to_sibling ButtonRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + BtnMode2 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 1 + pin_to_sibling BtnMode1 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode1 + navDown BtnMode3 + } + BtnMode3 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 2 + pin_to_sibling BtnMode2 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode2 + navDown BtnMode4 + } + BtnMode4 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 3 + pin_to_sibling BtnMode3 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + //ypos 11 + navUp BtnMode3 + navDown BtnMode5 + } + BtnMode5 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 4 + pin_to_sibling BtnMode4 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode4 + navDown BtnMode6 + } + BtnMode6 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 5 + pin_to_sibling BtnMode5 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode5 + navDown BtnMode7 + } + BtnMode7 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 6 + pin_to_sibling BtnMode6 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode6 + navDown BtnMode8 + } + BtnMode8 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 7 + pin_to_sibling BtnMode7 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode7 + navDown BtnMode9 + } + BtnMode9 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 8 + pin_to_sibling BtnMode8 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode8 + navDown BtnMode10 + } + BtnMode10 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 9 + pin_to_sibling BtnMode9 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode9 + navDown BtnMode11 + } + BtnMode11 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 10 + pin_to_sibling BtnMode10 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode10 + navDown BtnMode12 + } + BtnMode12 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 11 + pin_to_sibling BtnMode11 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode11 + navDown BtnMode13 + } + BtnMode13 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 12 + pin_to_sibling BtnMode12 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode12 + navDown BtnMode14 + } + BtnMode14 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 13 + pin_to_sibling BtnMode13 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode13 + navDown BtnMode15 + } + BtnMode15 + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModeButton + scriptID 14 + pin_to_sibling BtnMode14 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + navUp BtnMode14 + navDown BtnMode1 + } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ButtonTooltip + { + ControlName CNestedPanel + InheritProperties ButtonTooltip + } + + FooterButtons + { + ControlName CNestedPanel + xpos 0 + ypos r119 + wide f0 + tall 36 + visible 1 + controlSettingsFile "resource/ui/menus/panels/footer_buttons.res" + } + } +} -- cgit v1.2.3 From ee33fd31e7559630260541bef3492ef895647b8c Mon Sep 17 00:00:00 2001 From: LightBlueCube <115393812+LightBlueCube@users.noreply.github.com> Date: Tue, 10 Sep 2024 06:26:23 +0800 Subject: Fix crash when player is in a special team (#866) on player team switch. Adds a check whether player is in a default team (IMC/Milita) before calling `GetOtherTeam()` --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index f7c398d97..5d3777b49 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -1062,7 +1062,9 @@ void function OnPlayerChangedTeam( entity player ) if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams return - NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) + // only TEAM_IMC and TEAM_MILITIA can use function GetOtherTeam(), doesnt need to notify them when player got a special team + if( IsIMCOrMilitiaTeam( player.GetTeam() ) ) + NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) foreach( npc in GetNPCArray() ) { -- cgit v1.2.3 From 3dfd2091b4e72aad14b5d9cfd2332e7ec643c7fd Mon Sep 17 00:00:00 2001 From: William Miller Date: Tue, 10 Sep 2024 11:52:40 -0300 Subject: Reorder code of `_gamestate_mp.nut` (#875) Reorder functions to prepare for refactor and add big ASCII text comments for wayfinding using common IDE minimap --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 574 ++++++++++++++------- 1 file changed, 380 insertions(+), 194 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 5d3777b49..0c66f5a96 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -59,18 +59,21 @@ struct { bool functionref( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) shouldTryUseProjectileReplayCallback } file -void function SetCallback_TryUseProjectileReplay( bool functionref( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) callback ) -{ - file.shouldTryUseProjectileReplayCallback = callback -} -bool function ShouldTryUseProjectileReplay( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) -{ - if ( file.shouldTryUseProjectileReplayCallback != null ) - return file.shouldTryUseProjectileReplayCallback( victim, attacker, damageInfo, isRoundEnd ) - // default to true (vanilla behaviour) - return true -} + + + + + + + +/* + ██████ █████ ███ ███ ███████ ███████ ████████ █████ ████████ ███████ ███████ +██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███ ███████ ██ ████ ██ █████ ███████ ██ ███████ ██ █████ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██████ ██ ██ ██ ██ ███████ ███████ ██ ██ ██ ██ ███████ ███████ +*/ void function PIN_GameStart() { @@ -101,6 +104,61 @@ void function PIN_GameStart() RegisterSignal( "CleanUpEntitiesForRoundEnd" ) } +void function GameState_EntitiesDidLoad() +{ + if ( GetClassicMPMode() || ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) + ClassicMP_SetupIntro() +} + +void function WaittillGameStateOrHigher( int gameState ) +{ + while ( GetGameState() < gameState ) + svGlobal.levelEnt.WaitSignal( "GameStateChanged" ) +} + +bool function ShouldTryUseProjectileReplay( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) +{ + if ( file.shouldTryUseProjectileReplayCallback != null ) + return file.shouldTryUseProjectileReplayCallback( victim, attacker, damageInfo, isRoundEnd ) + // default to true (vanilla behaviour) + return true +} + +/// This is to move all NPCs that a player owns from one team to the other during a match +/// Auto-Titans, Turrets, Ticks and Hacked Spectres will all move along together with the player to the new Team +/// Also possibly prevents mods that spawns other types of NPCs that players can own from breaking when switching (i.e Drones, Hacked Reapers) +void function OnPlayerChangedTeam( entity player ) +{ + if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams + return + + if( IsIMCOrMilitiaTeam( player.GetTeam() ) ) + NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) + + foreach( npc in GetNPCArray() ) + { + entity bossPlayer = npc.GetBossPlayer() + if ( IsValidPlayer( bossPlayer ) && bossPlayer == player && IsAlive( npc ) ) + SetTeam( npc, player.GetTeam() ) + } +} + + + + + + + + + +/* + ██████ █████ ███ ███ ███████ ███████ ███████ ████████ ██ ██ ██████ +██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███ ███████ ██ ████ ██ █████ ███████ █████ ██ ██ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██████ ██ ██ ██ ██ ███████ ███████ ███████ ██ ██████ ██ +*/ + void function SetGameState( int newState ) { if ( newState == GetGameState() ) @@ -115,23 +173,166 @@ void function SetGameState( int newState ) callbackFunc() } -void function GameState_EntitiesDidLoad() +void function AddTeamScore( int team, int amount ) { - if ( GetClassicMPMode() || ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) - ClassicMP_SetupIntro() + GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + amount ) + GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + amount ) + + int scoreLimit + if ( IsRoundBased() ) + scoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE ) + else + scoreLimit = GameMode_GetScoreLimit( GAMETYPE ) + + int score = GameRules_GetTeamScore( team ) + if ( score >= scoreLimit || GetGameState() == eGameState.SuddenDeath ) + SetWinner( team ) + else if ( ( file.switchSidesBased && !file.hasSwitchedSides ) && score >= ( scoreLimit.tofloat() / 2.0 ) ) + SetGameState( eGameState.SwitchingSides ) } -void function WaittillGameStateOrHigher( int gameState ) +void function SetWinner( int team, string winningReason = "", string losingReason = "" ) +{ + SetServerVar( "winningTeam", team ) + + file.gameWonThisFrame = true + thread UpdateGameWonThisFrameNextFrame() + + if ( winningReason.len() == 0 ) + file.announceRoundWinnerWinningSubstr = 0 + else + file.announceRoundWinnerWinningSubstr = GetStringID( winningReason ) + + if ( losingReason.len() == 0 ) + file.announceRoundWinnerLosingSubstr = 0 + else + file.announceRoundWinnerLosingSubstr = GetStringID( losingReason ) + + if ( GamePlayingOrSuddenDeath() ) + { + if ( IsRoundBased() ) + { + if ( team != TEAM_UNASSIGNED ) + { + GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + 1 ) + GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + 1 ) + } + + SetGameState( eGameState.WinnerDetermined ) + ScoreEvent_RoundComplete( team ) + } + else + { + SetGameState( eGameState.WinnerDetermined ) + ScoreEvent_MatchComplete( team ) + + array players = GetPlayerArray() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( GAMETYPE ) + if ( compareFunc != null ) + { + players.sort( compareFunc ) + int playerCount = players.len() + int currentPlace = 1 + for ( int i = 0; i < 3; i++ ) + { + if ( i >= playerCount ) + continue + + if ( i > 0 && compareFunc( players[i - 1], players[i] ) != 0 ) + currentPlace += 1 + + switch( currentPlace ) + { + case 1: + UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "mvp_total" ) + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 2: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 3: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + } + } + } + } + } +} + +void function SetTimeoutWinnerDecisionFunc( int functionref() callback ) { - while ( GetGameState() < gameState ) - svGlobal.levelEnt.WaitSignal( "GameStateChanged" ) + file.timeoutWinnerDecisionFunc = callback } +void function SetCallback_TryUseProjectileReplay( bool functionref( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) callback ) +{ + file.shouldTryUseProjectileReplayCallback = callback +} -// logic for individual gamestates: +void function AddCallback_OnRoundEndCleanup( void functionref() callback ) +{ + file.roundEndCleanupCallbacks.append( callback ) +} + +void function SetShouldUsePickLoadoutScreen( bool shouldUse ) +{ + file.usePickLoadoutScreen = shouldUse +} +void function SetSwitchSidesBased( bool switchSides ) +{ + file.switchSidesBased = switchSides +} + +void function SetSuddenDeathBased( bool suddenDeathBased ) +{ + file.suddenDeathBased = suddenDeathBased +} + +void function SetTimerBased( bool timerBased ) +{ + file.timerBased = timerBased +} + +void function SetShouldUseRoundWinningKillReplay( bool shouldUse ) +{ + SetServerVar( "roundWinningKillReplayEnabled", shouldUse ) +} + +void function SetRoundWinningKillReplayKillClasses( bool pilot, bool titan ) +{ + file.roundWinningKillReplayTrackPilotKills = pilot + file.roundWinningKillReplayTrackTitanKills = titan // player kills in titans should get tracked anyway, might be worth renaming this +} + +void function SetRoundWinningKillReplayAttacker( entity attacker, int inflictorEHandle = -1 ) +{ + file.roundWinningKillReplayTime = Time() + file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) + file.roundWinningKillReplayAttacker = attacker + file.roundWinningKillReplayInflictorEHandle = inflictorEHandle == -1 ? attacker.GetEncodedEHandle() : inflictorEHandle + file.roundWinningKillReplayTimeOfDeath = Time() +} + + + + + + + + + + +/* + ██████ ██ ██ ███████ ████████ ██████ ███ ███ ███████ ████████ █████ ██████ ████████ +██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ███████ ██ ██ ██ ██ ████ ██ ███████ ██ ███████ ██████ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██████ ██████ ███████ ██ ██████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ +*/ -// eGameState.WaitingForCustomStart void function GameStateEnter_WaitingForCustomStart() { // unused in release, comments indicate this was supposed to be used for an e3 demo @@ -139,7 +340,22 @@ void function GameStateEnter_WaitingForCustomStart() } -// eGameState.WaitingForPlayers + + + + + + + + +/* +██ ██ █████ ██ ████████ ██ ███ ██ ██████ ███████ ██████ ██████ ██████ ██ █████ ██ ██ ███████ ██████ ███████ +██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ █ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ███ █████ ██ ██ ██████ ██████ ██ ███████ ████ █████ ██████ ███████ +██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ███ ███ ██ ██ ██ ██ ██ ██ ████ ██████ ██ ██████ ██ ██ ██ ███████ ██ ██ ██ ███████ ██ ██ ███████ +*/ + void function GameStateEnter_WaitingForPlayers() { foreach ( entity player in GetPlayerArray() ) @@ -171,7 +387,22 @@ void function WaitingForPlayers_ClientConnected( entity player ) ScreenFadeToBlackForever( player, 0.0 ) } -// eGameState.PickLoadout + + + + + + + + +/* +██████ ██ ██████ ██ ██ ██ ██████ █████ ██████ ██████ ██ ██ ████████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██████ ██ ██ █████ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██████ ██ ██ ███████ ██████ ██ ██ ██████ ██████ ██████ ██ +*/ + void function GameStateEnter_PickLoadout() { thread GameStateEnter_PickLoadout_Threaded() @@ -190,7 +421,22 @@ void function GameStateEnter_PickLoadout_Threaded() } -// eGameState.Prematch + + + + + + + + +/* +██████ ██████ ███████ ███ ███ █████ ████████ ██████ ██ ██ +██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ +██████ ██████ █████ ██ ████ ██ ███████ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ███████ ██ ██ ██ ██ ██ ██████ ██ ██ +*/ + void function GameStateEnter_Prematch() { int timeLimit = GameMode_GetTimeLimit( GAMETYPE ) * 60 @@ -236,7 +482,22 @@ void function StartGameWithoutClassicMP() } -// eGameState.Playing + + + + + + + + +/* +██████ ██ █████ ██ ██ ██ ███ ██ ██████ +██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +██████ ██ ███████ ████ ██ ██ ██ ██ ██ ███ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ███████ ██ ██ ██ ██ ██ ████ ██████ +*/ + void function GameStateEnter_Playing() { thread GameStateEnter_Playing_Threaded() @@ -279,7 +540,22 @@ void function GameStateEnter_Playing_Threaded() } -// eGameState.WinnerDetermined + + + + + + + + +/* +██ ██ ██ ███ ██ ███ ██ ███████ ██████ ██████ ███████ ████████ ███████ ██████ ███ ███ ██ ███ ██ ███████ ██████ +██ ██ ██ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ +██ █ ██ ██ ██ ██ ██ ██ ██ ██ █████ ██████ ██ ██ █████ ██ █████ ██████ ██ ████ ██ ██ ██ ██ ██ █████ ██ ██ +██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ███ ███ ██ ██ ████ ██ ████ ███████ ██ ██ ██████ ███████ ██ ███████ ██ ██ ██ ██ ██ ██ ████ ███████ ██████ +*/ + // these are likely innacurate const float ROUND_END_FADE_KILLREPLAY = 1.0 const float ROUND_END_DELAY_KILLREPLAY = 3.0 @@ -446,7 +722,22 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLe } -// eGameState.SwitchingSides + + + + + + + + +/* +███████ ██ ██ ██ ████████ ██████ ██ ██ ██ ███ ██ ██████ ███████ ██ ██████ ███████ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ █ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ███ ███████ ██ ██ ██ █████ ███████ + ██ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ███ ███ ██ ██ ██████ ██ ██ ██ ██ ████ ██████ ███████ ██ ██████ ███████ ███████ +*/ + void function GameStateEnter_SwitchingSides() { thread GameStateEnter_SwitchingSides_Threaded() @@ -537,7 +828,22 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla } -// eGameState.SuddenDeath + + + + + + + + +/* +███████ ██ ██ ██████ ██████ ███████ ███ ██ ██████ ███████ █████ ████████ ██ ██ +██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ █████ ███████ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +███████ ██████ ██████ ██████ ███████ ██ ████ ██████ ███████ ██ ██ ██ ██ ██ +*/ + void function GameStateEnter_SuddenDeath() { // disable respawns, suddendeath calling is done on a kill callback @@ -559,7 +865,22 @@ void function GameStateEnter_SuddenDeath() } -// eGameState.Postmatch + + + + + + + + +/* +██████ ██████ ███████ ████████ ███ ███ █████ ████████ ██████ ██ ██ +██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ +██████ ██ ██ ███████ ██ ██ ████ ██ ███████ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██████ ███████ ██ ██ ██ ██ ██ ██ ██████ ██ ██ +*/ + void function GameStateEnter_Postmatch() { foreach ( entity player in GetPlayerArray() ) @@ -592,7 +913,21 @@ void function ForceFadeToBlack( entity player ) } -// shared across multiple gamestates + + + + + + + + +/* +██ ██ ██ ██ ██ ██████ █████ ██ ██ ██████ █████ ██████ ██ ██ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +█████ ██ ██ ██ ██ ███████ ██ ██ ██████ ███████ ██ █████ ███████ +██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +██ ██ ██ ███████ ███████ ██████ ██ ██ ███████ ███████ ██████ ██ ██ ██████ ██ ██ ███████ +*/ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) { @@ -722,10 +1057,22 @@ void function OnTitanKilled( entity victim, var damageInfo ) } } -void function AddCallback_OnRoundEndCleanup( void functionref() callback ) -{ - file.roundEndCleanupCallbacks.append( callback ) -} + + + + + + + + + +/* +████████ ██████ ██████ ██ ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ + ██ ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ██ ██████ ██████ ███████ ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ +*/ void function CleanUpEntitiesForRoundEnd() { @@ -763,120 +1110,6 @@ void function CleanUpEntitiesForRoundEnd() SetPlayerDeathsHidden( false ) } - - -// stuff for gamemodes to call - -void function SetShouldUsePickLoadoutScreen( bool shouldUse ) -{ - file.usePickLoadoutScreen = shouldUse -} - -void function SetSwitchSidesBased( bool switchSides ) -{ - file.switchSidesBased = switchSides -} - -void function SetSuddenDeathBased( bool suddenDeathBased ) -{ - file.suddenDeathBased = suddenDeathBased -} - -void function SetTimerBased( bool timerBased ) -{ - file.timerBased = timerBased -} - -void function SetShouldUseRoundWinningKillReplay( bool shouldUse ) -{ - SetServerVar( "roundWinningKillReplayEnabled", shouldUse ) -} - -void function SetRoundWinningKillReplayKillClasses( bool pilot, bool titan ) -{ - file.roundWinningKillReplayTrackPilotKills = pilot - file.roundWinningKillReplayTrackTitanKills = titan // player kills in titans should get tracked anyway, might be worth renaming this -} - -void function SetRoundWinningKillReplayAttacker( entity attacker, int inflictorEHandle = -1 ) -{ - file.roundWinningKillReplayTime = Time() - file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) - file.roundWinningKillReplayAttacker = attacker - file.roundWinningKillReplayInflictorEHandle = inflictorEHandle == -1 ? attacker.GetEncodedEHandle() : inflictorEHandle - file.roundWinningKillReplayTimeOfDeath = Time() -} - -void function SetWinner( int team, string winningReason = "", string losingReason = "" ) -{ - SetServerVar( "winningTeam", team ) - - file.gameWonThisFrame = true - thread UpdateGameWonThisFrameNextFrame() - - if ( winningReason.len() == 0 ) - file.announceRoundWinnerWinningSubstr = 0 - else - file.announceRoundWinnerWinningSubstr = GetStringID( winningReason ) - - if ( losingReason.len() == 0 ) - file.announceRoundWinnerLosingSubstr = 0 - else - file.announceRoundWinnerLosingSubstr = GetStringID( losingReason ) - - if ( GamePlayingOrSuddenDeath() ) - { - if ( IsRoundBased() ) - { - if ( team != TEAM_UNASSIGNED ) - { - GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + 1 ) - GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + 1 ) - } - - SetGameState( eGameState.WinnerDetermined ) - ScoreEvent_RoundComplete( team ) - } - else - { - SetGameState( eGameState.WinnerDetermined ) - ScoreEvent_MatchComplete( team ) - - array players = GetPlayerArray() - int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( GAMETYPE ) - if ( compareFunc != null ) - { - players.sort( compareFunc ) - int playerCount = players.len() - int currentPlace = 1 - for ( int i = 0; i < 3; i++ ) - { - if ( i >= playerCount ) - continue - - if ( i > 0 && compareFunc( players[i - 1], players[i] ) != 0 ) - currentPlace += 1 - - switch( currentPlace ) - { - case 1: - UpdatePlayerStat( players[i], "game_stats", "mvp" ) - UpdatePlayerStat( players[i], "game_stats", "mvp_total" ) - UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) - break - case 2: - UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) - break - case 3: - UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) - break - } - } - } - } - } -} - void function UpdateGameWonThisFrameNextFrame() { WaitFrame() @@ -884,29 +1117,6 @@ void function UpdateGameWonThisFrameNextFrame() file.hasKillForGameWonThisFrame = false } -void function AddTeamScore( int team, int amount ) -{ - GameRules_SetTeamScore( team, GameRules_GetTeamScore( team ) + amount ) - GameRules_SetTeamScore2( team, GameRules_GetTeamScore2( team ) + amount ) - - int scoreLimit - if ( IsRoundBased() ) - scoreLimit = GameMode_GetRoundScoreLimit( GAMETYPE ) - else - scoreLimit = GameMode_GetScoreLimit( GAMETYPE ) - - int score = GameRules_GetTeamScore( team ) - if ( score >= scoreLimit || GetGameState() == eGameState.SuddenDeath ) - SetWinner( team ) - else if ( ( file.switchSidesBased && !file.hasSwitchedSides ) && score >= ( scoreLimit.tofloat() / 2.0 ) ) - SetGameState( eGameState.SwitchingSides ) -} - -void function SetTimeoutWinnerDecisionFunc( int functionref() callback ) -{ - file.timeoutWinnerDecisionFunc = callback -} - int function GetWinningTeamWithFFASupport() { if ( !IsFFAGame() ) @@ -936,8 +1146,6 @@ int function GetWinningTeamWithFFASupport() unreachable } -// idk - float function GameState_GetTimeLimitOverride() { return 100 @@ -967,8 +1175,6 @@ float function GetTimeLimit_ForGameMode() return GetCurrentPlaylistVarFloat( playlistString, 10 ) } -// faction dialogue - void function DialoguePlayNormal() { int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() ) @@ -1052,24 +1258,4 @@ void function DialoguePlayWinnerDetermined() PlayFactionDialogueToTeam( "scoring_won", winningTeam ) PlayFactionDialogueToTeam( "scoring_lost", losingTeam ) } -} - -/// This is to move all NPCs that a player owns from one team to the other during a match -/// Auto-Titans, Turrets, Ticks and Hacked Spectres will all move along together with the player to the new Team -/// Also possibly prevents mods that spawns other types of NPCs that players can own from breaking when switching (i.e Drones, Hacked Reapers) -void function OnPlayerChangedTeam( entity player ) -{ - if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams - return - - // only TEAM_IMC and TEAM_MILITIA can use function GetOtherTeam(), doesnt need to notify them when player got a special team - if( IsIMCOrMilitiaTeam( player.GetTeam() ) ) - NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) - - foreach( npc in GetNPCArray() ) - { - entity bossPlayer = npc.GetBossPlayer() - if ( IsValidPlayer( bossPlayer ) && bossPlayer == player && IsAlive( npc ) ) - SetTeam( npc, player.GetTeam() ) - } -} +} \ No newline at end of file -- cgit v1.2.3