aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com>2023-12-31 18:58:50 +0100
committerGitHub <noreply@github.com>2023-12-31 18:58:50 +0100
commita1502e9ad3ed44b2a0a8ab5f17d4d2bf5238d9cf (patch)
tree0f171ab768fa6f8dd8d68fc4f0675baffbfd5e5d
parentad70253601a77844347d8aa1989ae5ab4fb4217c (diff)
parent00a4bb6fb5e107788ea77cad51c8c8004a9537f1 (diff)
downloadNorthstarMods-gamemode_fd.tar.gz
NorthstarMods-gamemode_fd.zip
Merge pull request #777 from R2Northstar/maingamemode_fd
Update FD branch
-rw-r--r--.gitattributes5
-rw-r--r--.github/nativefuncs.json33
-rw-r--r--.github/workflows/add-to-project.yml2
-rw-r--r--.github/workflows/merge-conflict-auto-label.yml16
-rw-r--r--Northstar.Client/mod.json8
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_english.txt22
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_french.txt4
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt30
-rw-r--r--Northstar.Client/mod/resource/ui/menus/modlist.menu4
-rw-r--r--Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut21
-rw-r--r--Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut11
-rw-r--r--Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut20
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut117
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut61
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut11
-rw-r--r--Northstar.Custom/keyvalues/playlists_v2.txt2
-rw-r--r--Northstar.Custom/mod.json19
-rw-r--r--Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt18
-rw-r--r--Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtfbin0 -> 524512 bytes
-rw-r--r--Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdlbin0 -> 311481 bytes
-rw-r--r--Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdlbin0 -> 3029949 bytes
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/_event_models.gnut21
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut8
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut8
-rw-r--r--Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut62
-rw-r--r--Northstar.Custom/paks/bt.rpakbin0 -> 308606 bytes
-rw-r--r--Northstar.Custom/paks/bt.starpakbin0 -> 19296360 bytes
-rw-r--r--Northstar.Custom/paks/giftwrap.rpakbin0 -> 264704 bytes
-rw-r--r--Northstar.Custom/paks/giftwrap.starpakbin0 -> 1335384 bytes
-rw-r--r--Northstar.Custom/paks/leaves.rpakbin0 -> 265631 bytes
-rw-r--r--Northstar.Custom/paks/leaves.starpakbin0 -> 3956824 bytes
-rw-r--r--Northstar.Custom/paks/rpak.json9
-rw-r--r--Northstar.Custom/paks/snow.rpakbin0 -> 308548 bytes
-rw-r--r--Northstar.Custom/paks/snow.starpakbin0 -> 4616296 bytes
-rw-r--r--Northstar.Custom/paks/tree_stump.rpakbin0 -> 308670 bytes
-rw-r--r--Northstar.Custom/paks/tree_stump.starpakbin0 -> 4616296 bytes
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_items.nut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut4
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut14
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut34
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut75
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut10
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut10
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut27
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut24
-rw-r--r--README.md11
46 files changed, 596 insertions, 129 deletions
diff --git a/.gitattributes b/.gitattributes
index c6a941df..1bb89156 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,4 @@
-/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM \ No newline at end of file
+/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM
+
+# Highlight `.gnut` like `.nut` files
+*.gnut linguist-language=Squirrel
diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json
index 13a7edd3..1148d3e5 100644
--- a/.github/nativefuncs.json
+++ b/.github/nativefuncs.json
@@ -421,13 +421,7 @@
"helpText":"Returns whether or not a given path leads to a folder.",
"returnTypeString":"bool",
"argTypes":"string path"
- },
- {
- "name":"NSPushGameStateData",
- "helpText":"",
- "returnTypeString":"void",
- "argTypes":"struct gamestate"
- }
+ }
],
"UI":[
{
@@ -509,6 +503,25 @@
"argTypes":"string modName"
},
{
+ "name": "NSIsModDownloadable",
+ "helpText": "checks whether a mod is verified and can be auto-downloaded",
+ "returnTypeString": "bool",
+ "argTypes": "string name, string version"
+
+ },
+ {
+ "name": "NSDownloadMod",
+ "helpText": "downloads a given mod from distant API to local game profile",
+ "returnTypeString": "void",
+ "argTypes": "string name, string version"
+ },
+ {
+ "name": "NSGetModInstallState",
+ "helpText": "get status of the mod currently being installed",
+ "returnTypeString": "ModInstallState",
+ "argTypes": ""
+ },
+ {
"name":"NSReloadMods",
"helpText":"",
"returnTypeString":"void",
@@ -724,12 +737,6 @@
"returnTypeString":"bool",
"argTypes":"string path"
},
- {
- "name":"NSPushUIPresence",
- "helpText":"",
- "returnTypeString":"void",
- "argTypes":"struct presence"
- },
{
"name":"NSGetMasterServerAuthResult",
"helpText":"",
diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml
index 3a1d1c9a..773a52b8 100644
--- a/.github/workflows/add-to-project.yml
+++ b/.github/workflows/add-to-project.yml
@@ -4,7 +4,7 @@ on:
issues:
types:
- opened
- pull_request:
+ pull_request_target:
types:
- opened
diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml
new file mode 100644
index 00000000..e237726a
--- /dev/null
+++ b/.github/workflows/merge-conflict-auto-label.yml
@@ -0,0 +1,16 @@
+name: Merge Conflict Auto Label
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ triage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: mschilde/auto-label-merge-conflicts@master
+ with:
+ CONFLICT_LABEL_NAME: "merge conflicts"
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ MAX_RETRIES: 5
+ WAIT_MS: 5000
diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json
index a22f49fd..44937a2b 100644
--- a/Northstar.Client/mod.json
+++ b/Northstar.Client/mod.json
@@ -6,6 +6,10 @@
"InitScript": "cl_northstar_client_init.nut",
"ConVars": [
{
+ "Name": "allow_mod_auto_download",
+ "DefaultValue": "0"
+ },
+ {
"Name": "filter_hide_empty",
"DefaultValue": "0"
},
@@ -83,6 +87,10 @@
}
},
{
+ "Path": "ui/menu_ns_moddownload.nut",
+ "RunOn": "UI"
+ },
+ {
"Path": "ui/menu_ns_serverbrowser.nut",
"RunOn": "UI",
"UICallback": {
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
index c7b25a70..e6518feb 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
@@ -304,6 +304,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"SHOW_ONLY_DISABLED" "Only Disabled"
"SHOW_ONLY_NOT_REQUIRED" "Only Optional Mods"
"SHOW_ONLY_REQUIRED" "Only Required Mods"
+ "MOD_REQUIRED_WARNING" " : This mod may get (un)loaded when joining a server"
// Maps menu
"HIDE_LOCKED" "Hide locked"
@@ -366,5 +367,26 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby."
"PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time."
+
+ // Mod downloading
+ "MISSING_MOD" "Missing mod \"%s1\" v%s2"
+ "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3"
+ "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)"
+ "MOD_DL_DISABLED" "(automatic mod downloading is disabled)"
+ "DOWNLOADING_MOD_TITLE" "Downloading mod"
+ "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)"
+ "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..."
+ "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Downloading %s1 v%s2...\n(%s3/%s4 MB)"
+ "CHECKSUMING_TITLE" "Checksuming mod"
+ "CHECKSUMING_TEXT" "Verifying contents of %s1 v%s2..."
+ "EXTRACTING_MOD_TITLE" "Extracting mod (%s1%)"
+ "EXTRACTING_MOD_TEXT" "Extracting %s1 v%s2...\n(%s3/%s4 MB)"
+ "FAILED_DOWNLOADING" "Failed downloading mod"
+ "FAILED_READING_ARCHIVE" "An error occurred while reading mod archive."
+ "FAILED_WRITING_TO_DISK" "An error occurred while extracting mod files to the filesystem."
+ "MOD_FETCHING_FAILED" "Mod archive could not be downloaded from Thunderstore."
+ "MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature."
+ "NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk."
+ "MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
index 377f6917..b0e579cf 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
@@ -353,5 +353,9 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"TOGGLE_PROGRESSION" "Activer la progression"
"Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression"
"PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment."
+ "AUTHENTICATION_FAILED_HEADER" "Échec de l'authentification"
+ "AUTHENTICATION_FAILED_HELP" "Aide"
+ "AUTHENTICATION_FAILED_ERROR_CODE" "Code d'erreur : ^DB6F2C00%s1^"
+ "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt
index 18634668..50d1ef17 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt
@@ -319,5 +319,35 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e
"INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido"
"JSON_PARSE_ERROR" "Error procesando respuesta json"
"UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada"
+ "SHOW_ONLY_REQUIRED" "Solo Mods requeridos"
+ "player_force_respawn" "Reaparición Forzada"
+ "TOGGLE_PROGRESSION" "Alternar Progreso"
+ "PROGRESSION_TOGGLE_ENABLED_HEADER" "Desactivar Progreso?"
+ "NO_RESULTS" "No hay resultados."
+ "NO_MODS" "No hay configuraciones disponibles! Instala mas mods en: ^5588FF00northstar.thunderstore.io^0."
+ "AUTHENTICATION_FAILED_HEADER" "Verificacion fallida"
+ "AUTHENTICATION_FAILED_BODY" "Autenticación fallada con Atlas!"
+ "AUTHENTICATION_FAILED_ERROR_CODE" "Codigo de error: ^DB6F2C00%s1^"
+ "AUTHENTICATION_FAILED_HELP" "Ayuda"
+ "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las configuraciones de categoría\nEsto no es reversible"
+ "WILL_RESET_SETTING" "Esto revertirá %s1 a la configuracion por defecto. \n \nEsto no es revertible."
+ "MOD_SETTINGS_SERVER" "Servidor"
+ "MOD_SETTINGS_RESET" "Reiniciar"
+ "MOD_SETTINGS_RESET_ALL" "Reiniciar todo"
+ "MOD_REQUIRED_WARNING" " Este mod puede ser deshabilitado al entrar a un servidor"
+ "MOD_SETTINGS" "Configuracion de Mods"
+ "NORTHSTAR_BASE_SETTINGS" "Configuracion base de Northstar"
+ "ONLY_HOST_MATCH_SETTINGS" "Solo el Host puede cambiar ajustes de partida"
+ "ONLY_HOST_CAN_START_MATCH" "Solo el host puede iniciar la partida"
+ "MATCH_COUNTDOWN_LENGTH" "Cuenta Atrás de partida privada"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Registro desconocido de comandos de cliente"
+ "DISALLOWED_TACTICALS" "Tactica Prohibida"
+ "TACTICAL_REPLACEMENT" "Reemplazo de Tactica"
+ "DISALLOWED_WEAPONS" "Arma Prohibida"
+ "REPLACEMENT_WEAPON" "Arma de Reemplazo"
+ "SHOULD_RETURN_TO_LOBBY" "Volver al lobby al finalizar partida"
+ "ARE_YOU_SURE" "Seguro?"
+ "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Alternar Progreso"
+ "SHOW_ONLY_NOT_REQUIRED" "Solo Mods Opcionales"
}
}
diff --git a/Northstar.Client/mod/resource/ui/menus/modlist.menu b/Northstar.Client/mod/resource/ui/menus/modlist.menu
index da59bcdd..bd350a33 100644
--- a/Northstar.Client/mod/resource/ui/menus/modlist.menu
+++ b/Northstar.Client/mod/resource/ui/menus/modlist.menu
@@ -488,8 +488,8 @@ resource/ui/menus/modlist.menu
{
ControlName Label
- labelText " : This mod gets (un)loaded automatically"
- wide 500
+ labelText "#MOD_REQUIRED_WARNING"
+ auto_wide_tocontents 1
tall 50
visible 0
diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
index a844478a..3560fd56 100644
--- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
+++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut
@@ -1,3 +1,11 @@
+global enum eDiscordGameState
+{
+ LOADING = 0
+ MAINMENU
+ LOBBY
+ INGAME
+}
+
global struct GameStateStruct {
string map
@@ -15,10 +23,7 @@ global struct GameStateStruct {
}
global struct UIPresenceStruct {
- bool isLoading
- bool isLobby
- string loadingLevel
- string loadedLevel
+ int gameState
}
global struct RequiredModInfo
@@ -48,3 +53,11 @@ global struct MasterServerAuthResult
string errorCode
string errorMessage
}
+
+global struct ModInstallState
+{
+ int status
+ int progress
+ int total
+ float ratio
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut
index c8a8274a..f17216fb 100644
--- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut
+++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut
@@ -1,10 +1,8 @@
untyped
globalize_all_functions
-void function NorthstarCodeCallback_GenerateGameState() {
-
- GameStateStruct gs
-
+GameStateStruct function DiscordRPC_GenerateGameState( GameStateStruct gs )
+{
int highestScore = 0
int secondHighest = 0
@@ -40,6 +38,5 @@ void function NorthstarCodeCallback_GenerateGameState() {
gs.timeEnd = expect float(level.nv.roundEndTime - Time())
else
gs.timeEnd = expect float(level.nv.gameEndTime - Time())
-
- NSPushGameStateData(gs)
-} \ No newline at end of file
+ return gs
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut
index cdf1c981..ce5abe86 100644
--- a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut
+++ b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut
@@ -1,12 +1,16 @@
untyped
globalize_all_functions
-void function NorthstarCodeCallback_GenerateUIPresence() {
- UIPresenceStruct uis
+UIPresenceStruct function DiscordRPC_GenerateUIPresence( UIPresenceStruct uis )
+{
+ if ( uiGlobal.isLoading )
+ uis.gameState = eDiscordGameState.LOADING;
+ else if ( uiGlobal.loadedLevel == "" )
+ uis.gameState = eDiscordGameState.MAINMENU;
+ else if ( IsLobby() || uiGlobal.loadedLevel == "mp_lobby" )
+ uis.gameState = eDiscordGameState.LOBBY;
+ else
+ uis.gameState = eDiscordGameState.INGAME;
- uis.isLoading = uiGlobal.isLoading
- uis.isLobby = IsLobby()
- uis.loadingLevel = uiGlobal.loadingLevel
- uis.loadedLevel = uiGlobal.loadedLevel
- NSPushUIPresence(uis)
-} \ No newline at end of file
+ return uis
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut
new file mode 100644
index 00000000..4d299362
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut
@@ -0,0 +1,117 @@
+global function DownloadMod
+global function DisplayModDownloadErrorDialog
+
+global enum eModInstallStatus
+{
+ DOWNLOADING,
+ CHECKSUMING,
+ EXTRACTING,
+ DONE,
+ FAILED,
+ FAILED_READING_ARCHIVE,
+ FAILED_WRITING_TO_DISK,
+ MOD_FETCHING_FAILED,
+ MOD_CORRUPTED,
+ NO_DISK_SPACE_AVAILABLE,
+ NOT_FOUND
+}
+
+const int MB = 1024*1000;
+
+bool function DownloadMod( RequiredModInfo mod )
+{
+ // Downloading mod UI
+ DialogData dialogData
+ dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" )
+ dialogData.message = Localize( "#DOWNLOADING_MOD_TEXT", mod.name, mod.version )
+ dialogData.showSpinner = true;
+
+ // Prevent user from closing dialog
+ dialogData.forceChoice = true;
+ OpenDialog( dialogData )
+
+ // Save reference to UI elements, to update their content
+ var menu = GetMenu( "Dialog" )
+ var header = Hud_GetChild( menu, "DialogHeader" )
+ var body = GetSingleElementByClassname( menu, "DialogMessageClass" )
+
+ // Start actual mod downloading
+ NSDownloadMod( mod.name, mod.version )
+
+ ModInstallState state = NSGetModInstallState()
+ while ( state.status < eModInstallStatus.DONE )
+ {
+ state = NSGetModInstallState()
+ UpdateModDownloadDialog( mod, state, menu, header, body )
+ WaitFrame()
+ }
+
+ printt( "Mod status:", state.status )
+
+ // Close loading dialog
+ CloseActiveMenu()
+
+ return state.status == eModInstallStatus.DONE
+}
+
+void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState state, var menu, var header, var body )
+{
+ switch ( state.status )
+ {
+ case eModInstallStatus.DOWNLOADING:
+ Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) )
+ Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) )
+ break
+ case eModInstallStatus.CHECKSUMING:
+ Hud_SetText( header, Localize( "#CHECKSUMING_TITLE" ) )
+ Hud_SetText( body, Localize( "#CHECKSUMING_TEXT", mod.name, mod.version ) )
+ break
+ case eModInstallStatus.EXTRACTING:
+ Hud_SetText( header, Localize( "#EXTRACTING_MOD_TITLE", string( state.ratio ) ) )
+ Hud_SetText( body, Localize( "#EXTRACTING_MOD_TEXT", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) )
+ break
+ default:
+ break
+ }
+}
+
+void function DisplayModDownloadErrorDialog( string modName )
+{
+ ModInstallState state = NSGetModInstallState()
+
+ DialogData dialogData
+ dialogData.header = Localize( "#FAILED_DOWNLOADING", modName )
+ dialogData.image = $"ui/menu/common/dialog_error"
+
+ switch ( state.status )
+ {
+ case eModInstallStatus.FAILED_READING_ARCHIVE:
+ dialogData.message = Localize( "#FAILED_READING_ARCHIVE" )
+ break
+ case eModInstallStatus.FAILED_WRITING_TO_DISK:
+ dialogData.message = Localize( "#FAILED_WRITING_TO_DISK" )
+ break
+ case eModInstallStatus.MOD_FETCHING_FAILED:
+ dialogData.message = Localize( "#MOD_FETCHING_FAILED" )
+ break
+ case eModInstallStatus.MOD_CORRUPTED:
+ dialogData.message = Localize( "#MOD_CORRUPTED" )
+ break
+ case eModInstallStatus.NO_DISK_SPACE_AVAILABLE:
+ dialogData.message = Localize( "#NO_DISK_SPACE_AVAILABLE" )
+ break
+ case eModInstallStatus.NOT_FOUND:
+ dialogData.message = Localize( "#NOT_FOUND" )
+ break
+ case eModInstallStatus.FAILED:
+ default:
+ dialogData.message = Localize( "#MOD_FETCHING_FAILED_GENERAL" )
+ break
+ }
+
+ AddDialogButton( dialogData, "#DISMISS" )
+ AddDialogFooter( dialogData, "#A_BUTTON_SELECT" )
+ AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" )
+
+ OpenDialog( dialogData )
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
index efc8d66c..1bc8e405 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut
@@ -952,32 +952,64 @@ string function FillInServerModsLabel( array<RequiredModInfo> mods )
void function OnServerSelected( var button )
{
+ thread OnServerSelected_Threaded( button )
+}
+
+void function OnServerSelected_Threaded( var button )
+{
if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed )
return
ServerInfo server = file.focusedServer
-
file.lastSelectedServer = server
+ // Count mods that have been successfully downloaded
+ bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" )
+ int downloadedMods = 0;
+
foreach ( RequiredModInfo mod in server.requiredMods )
{
if ( !NSGetModNames().contains( mod.name ) )
{
- DialogData dialogData
- dialogData.header = "#ERROR"
- dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version )
- dialogData.image = $"ui/menu/common/dialog_error"
+ // Check if mod can be auto-downloaded
+ bool modIsVerified = NSIsModDownloadable( mod.name, mod.version )
+
+ // Display an error message if not
+ if ( !modIsVerified || !autoDownloadAllowed )
+ {
+ DialogData dialogData
+ dialogData.header = "#ERROR"
+ dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version )
+ dialogData.image = $"ui/menu/common/dialog_error"
+
+ // Specify error (only if autoDownloadAllowed is set)
+ if ( autoDownloadAllowed )
+ {
+ dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" )
+ }
- #if PC_PROG
AddDialogButton( dialogData, "#DISMISS" )
AddDialogFooter( dialogData, "#A_BUTTON_SELECT" )
- #endif // PC_PROG
- AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" )
+ AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" )
- OpenDialog( dialogData )
+ OpenDialog( dialogData )
+
+ return
+ }
- return
+ else // Launch download
+ {
+ if ( DownloadMod( mod ) )
+ {
+ downloadedMods++
+ }
+ else
+ {
+ DisplayModDownloadErrorDialog( mod.name )
+ return
+ }
+ }
}
else
{
@@ -1001,7 +1033,7 @@ void function OnServerSelected( var button )
{
DialogData dialogData
dialogData.header = "#ERROR"
- dialogData.message = format( "Server has mod \"%s\" v%s while we have v%s", mod.name, mod.version, NSGetModVersionByModName( mod.name ) )
+ dialogData.message = Localize( "#WRONG_MOD_VERSION", mod.name, mod.version, NSGetModVersionByModName( mod.name ) )
dialogData.image = $"ui/menu/common/dialog_error"
#if PC_PROG
@@ -1018,6 +1050,13 @@ void function OnServerSelected( var button )
}
}
+ // Make Northstar aware new mods have been added
+ if ( downloadedMods > 0 )
+ {
+ print( "Some new mods have been downloaded or enabled, reloading mods." )
+ NSReloadMods();
+ }
+
if ( server.requiresPassword )
{
OnCloseServerBrowserMenu()
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
index c97c8cdc..2f1bcf02 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
@@ -81,8 +81,9 @@ void function InitMainMenuPanel()
headerIndex++
buttonIndex = 0
var multiplayerHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MULTIPLAYER_ALLCAPS" )
- file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" )
- Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate )
+ // "Launch Multiplayer" button removed because we don't support vanilla yet :clueless:
+ //file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" )
+ //Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate )
file.fdButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LAUNCH_NORTHSTAR" )
Hud_AddEventHandler( file.fdButton, UIE_CLICK, OnPlayFDButton_Activate )
Hud_SetLocked( file.fdButton, true )
@@ -169,7 +170,8 @@ void function OnShowMainMenuPanel()
#endif // PS4_PROG
UpdateSPButtons()
- thread UpdatePlayButton( file.mpButton )
+ // dont try and update the launch multiplayer button, because it doesn't exist
+ //thread UpdatePlayButton( file.mpButton )
thread UpdatePlayButton( file.fdButton )
thread MonitorTrialVersionChange()
@@ -459,7 +461,8 @@ void function UpdatePlayButton( var button )
message = ""
}
- ComboButton_SetText( file.mpButton, buttonText )
+ // dont try and update the launch multiplayer button, because it doesn't exist
+ //ComboButton_SetText( file.mpButton, buttonText )
ComboButton_SetText( file.fdButton, "#MENU_LAUNCH_NORTHSTAR" )
//Hud_SetEnabled( file.fdButton, false )
diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt
index 21934b31..c22e2174 100644
--- a/Northstar.Custom/keyvalues/playlists_v2.txt
+++ b/Northstar.Custom/keyvalues/playlists_v2.txt
@@ -47,8 +47,6 @@ playlists
max_teams 12
classic_mp 1
- scorelimit 21 // temp until we have a way of dynamically setting non-default scorelimit in code
-
gamemode_score_hint #GAMEMODE_SCORE_HINT_FFA
gamemode_bullet_001 #GAMEMODE_BULLET_FFA_001
gamemode_bullet_002 #GAMEMODE_BULLET_FFA_002
diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json
index 93f371bd..399311e4 100644
--- a/Northstar.Custom/mod.json
+++ b/Northstar.Custom/mod.json
@@ -24,6 +24,11 @@
{
"Name": "ns_force_melee",
"DefaultValue": ""
+ },
+ {
+ "Name": "ns_show_event_models",
+ "DefaultValue": "1",
+ "Flags": "ARCHIVE_PLAYERPROFILE"
}
],
"Scripts": [
@@ -434,6 +439,20 @@
{
"Path": "sh_northstar_safe_io.gnut",
"RunOn": "CLIENT || SERVER || UI"
+ },
+ {
+ "Path": "_event_models.gnut",
+ "RunOn": "SERVER && LOBBY",
+ "ServerCallback": {
+ "Before": "EventModelsInit"
+ }
+ },
+ {
+ "Path": "ui/ns_custom_mod_settings.gnut",
+ "RunOn": "UI",
+ "UICallback":{
+ "Before": "NSCustomModSettings"
+ }
}
],
diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt
new file mode 100644
index 00000000..22b81e9a
--- /dev/null
+++ b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt
@@ -0,0 +1,18 @@
+"UnlitTexture"
+{
+ $basetexture "models/northstartree/lightsflicker"
+ $color "[1.5 1.5 1.5]"
+
+ Proxies
+ {
+
+ TextureScroll
+ {
+ texturescrollvar $basetexturetransform
+ texturescrollrate 0.33
+ texturescrollangle 45
+ }
+
+ }
+
+}
diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf
new file mode 100644
index 00000000..227756be
--- /dev/null
+++ b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf
Binary files differ
diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl
new file mode 100644
index 00000000..aaf70363
--- /dev/null
+++ b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl
new file mode 100644
index 00000000..4690475f
--- /dev/null
+++ b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl
Binary files differ
diff --git a/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut
new file mode 100644
index 00000000..0802d769
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut
@@ -0,0 +1,21 @@
+global function EventModelsInit
+
+void function EventModelsInit()
+{
+ if( !GetConVarBool( "ns_show_event_models" ) )
+ return
+
+ table timeParts = GetUnixTimeParts()
+ int month = expect int( timeParts[ "month" ] )
+ int day = expect int( timeParts[ "day" ] )
+
+ // 18th December to 6th January
+ if( ( ( month == 12 ) && ( day >= 18 ) ) || ( ( month == 1 ) && ( day <= 6 ) ) )
+ {
+ PrecacheModel( $"models/northstartee/winter_holiday_tree.mdl" )
+ PrecacheModel( $"models/northstartree/winter_holiday_floor.mdl" )
+
+ CreatePropDynamic( $"models/northstartree/winter_holiday_tree.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 )
+ CreatePropDynamic( $"models/northstartree/winter_holiday_floor.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 )
+ }
+}
diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
index 8f34541b..ad46b42e 100644
--- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
+++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut
@@ -18,14 +18,6 @@ void function GamemodeGG_Init()
AddCallback_GameStateEnter( eGameState.WinnerDetermined, OnWinnerDetermined )
AddCallback_GGEarnMeterFull( OnGGEarnMeterFilled )
-
- // set scorelimit if it's wrong, sort of a jank way to do it but best i've got rn
- try
- {
- if ( GetCurrentPlaylistVarInt( "scorelimit", GetGunGameWeapons().len() ) != GetGunGameWeapons().len() )
- SetPlaylistVarOverride( "scorelimit", GetGunGameWeapons().len().tostring() )
- }
- catch ( ex ) {}
}
void function OnPlayerDisconnected(entity player)
diff --git a/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut
new file mode 100644
index 00000000..5a7d80b7
--- /dev/null
+++ b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut
@@ -0,0 +1,8 @@
+global function NSCustomModSettings
+
+void function NSCustomModSettings()
+{
+ ModSettings_AddModTitle( "Northstar Custom" , 2 )
+ ModSettings_AddModCategory( "Event Models" )
+ ModSettings_AddEnumSetting( "ns_show_event_models", "Show Event Models", [ "#SETTING_OFF", "#SETTING_ON" ], 2 )
+}
diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
index 01138967..defb1a56 100644
--- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
+++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut
@@ -536,12 +536,6 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam )
#if SERVER
- local isMissile = ( target.GetClassName() == "rpg_missile" )
- if ( !isMissile )
- wait ARC_CANNON_FORK_DELAY
- else
- wait 0.05
-
local deathPackage = damageTypes.arcCannon
float damageAmount
@@ -569,40 +563,20 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
bool hasFastPacitor = false
bool noArcing = false
- if ( IsValid( zapInfo.weapon ) )
- {
- entity weap = expect entity( zapInfo.weapon )
- hasFastPacitor = weap.GetWeaponInfoFileKeyField( "push_apart" ) != null && weap.GetWeaponInfoFileKeyField( "push_apart" ) == 1
- noArcing = weap.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weap.GetWeaponInfoFileKeyField( "no_arcing" ) == 1
- }
+ entity weapon = expect entity( zapInfo.weapon )
+ hasFastPacitor = weapon.GetWeaponInfoFileKeyField( "push_apart" ) != null && weapon.GetWeaponInfoFileKeyField( "push_apart" ) == 1
+ noArcing = weapon.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weapon.GetWeaponInfoFileKeyField( "no_arcing" ) == 1
+ float critScale = weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale )
if ( target.GetArmorType() == ARMOR_TYPE_HEAVY )
{
- if ( IsValid( zapInfo.weapon ) )
- {
- entity weapon = expect entity( zapInfo.weapon )
- damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor )
- damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor )
- }
- else
- {
- damageMin = 100
- damageMax = zapInfo.player.IsNPC() ? 1200 : 800
- }
+ damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor )
}
else
{
- if ( IsValid( zapInfo.weapon ) )
- {
- entity weapon = expect entity( zapInfo.weapon )
- damageMin = weapon.GetWeaponSettingInt( damageFarValue )
- damageMax = weapon.GetWeaponSettingInt( damageNearValue )
- }
- else
- {
- damageMin = 120
- damageMax = zapInfo.player.IsNPC() ? 140 : 275
- }
+ damageMin = weapon.GetWeaponSettingInt( damageFarValue )
+ damageMax = weapon.GetWeaponSettingInt( damageNearValue )
if ( target.IsNPC() )
{
@@ -612,11 +586,10 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
}
- local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon )
- if ( IsValid( zapInfo.weapon ) && !zapInfo.weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) )
+ local chargeRatio = GetArcCannonChargeFraction( weapon )
+ if ( !weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) )
{
// use distance for damage if the weapon auto-fires
- entity weapon = expect entity( zapInfo.weapon )
float nearDist = weapon.GetWeaponSettingFloat( damageNearDistance )
float farDist = weapon.GetWeaponSettingFloat( damageFarDistance )
@@ -629,10 +602,19 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax )
}
local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER
- if ( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) )
+ if ( weapon.HasMod( "splitter" ) )
damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER
damageAmount *= pow( damageFalloff, chainNum - 1 )
+ local isMissile = ( target.GetClassName() == "rpg_missile" )
+ if ( !isMissile )
+ wait ARC_CANNON_FORK_DELAY
+ else
+ wait 0.05
+
+ if ( !IsValid( target ) || !IsValid( zapInfo.player ) )
+ return
+
local dmgSourceID = zapInfo.dmgSourceID
// Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target
@@ -660,13 +642,13 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 )
// Do 3rd person effect on the body
asset effect
string tag
- target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = zapInfo.weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) } )
+ target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = critScale } )
//vector dir = Normalize( beamEndPos - beamStartPos )
//vector velocity = dir * 600
//PushPlayerAway( target, velocity )
//PushPlayerAway( expect entity( zapInfo.player ), -velocity )
- if ( IsValid( zapInfo.weapon ) && hasFastPacitor )
+ if ( IsValid( weapon ) && hasFastPacitor )
{
if ( IsAlive( target ) && IsAlive( expect entity( zapInfo.player ) ) && target.IsTitan() )
{
diff --git a/Northstar.Custom/paks/bt.rpak b/Northstar.Custom/paks/bt.rpak
new file mode 100644
index 00000000..7a4b9e31
--- /dev/null
+++ b/Northstar.Custom/paks/bt.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/bt.starpak b/Northstar.Custom/paks/bt.starpak
new file mode 100644
index 00000000..70549d51
--- /dev/null
+++ b/Northstar.Custom/paks/bt.starpak
Binary files differ
diff --git a/Northstar.Custom/paks/giftwrap.rpak b/Northstar.Custom/paks/giftwrap.rpak
new file mode 100644
index 00000000..7b9200b3
--- /dev/null
+++ b/Northstar.Custom/paks/giftwrap.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/giftwrap.starpak b/Northstar.Custom/paks/giftwrap.starpak
new file mode 100644
index 00000000..46ea6d8d
--- /dev/null
+++ b/Northstar.Custom/paks/giftwrap.starpak
Binary files differ
diff --git a/Northstar.Custom/paks/leaves.rpak b/Northstar.Custom/paks/leaves.rpak
new file mode 100644
index 00000000..b17346dd
--- /dev/null
+++ b/Northstar.Custom/paks/leaves.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/leaves.starpak b/Northstar.Custom/paks/leaves.starpak
new file mode 100644
index 00000000..b37aa523
--- /dev/null
+++ b/Northstar.Custom/paks/leaves.starpak
Binary files differ
diff --git a/Northstar.Custom/paks/rpak.json b/Northstar.Custom/paks/rpak.json
index 743468b4..522c558b 100644
--- a/Northstar.Custom/paks/rpak.json
+++ b/Northstar.Custom/paks/rpak.json
@@ -1,5 +1,10 @@
{
"Postload": {
- "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak"
+ "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak",
+ "leaves.rpak": "common.rpak",
+ "tree_stump.rpak": "common.rpak",
+ "bt.rpak": "common.rpak",
+ "giftwrap.rpak": "common.rpak",
+ "snow.rpak": "common.rpak"
}
-} \ No newline at end of file
+}
diff --git a/Northstar.Custom/paks/snow.rpak b/Northstar.Custom/paks/snow.rpak
new file mode 100644
index 00000000..4756b6c7
--- /dev/null
+++ b/Northstar.Custom/paks/snow.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/snow.starpak b/Northstar.Custom/paks/snow.starpak
new file mode 100644
index 00000000..7f3dbf19
--- /dev/null
+++ b/Northstar.Custom/paks/snow.starpak
Binary files differ
diff --git a/Northstar.Custom/paks/tree_stump.rpak b/Northstar.Custom/paks/tree_stump.rpak
new file mode 100644
index 00000000..3cdf1866
--- /dev/null
+++ b/Northstar.Custom/paks/tree_stump.rpak
Binary files differ
diff --git a/Northstar.Custom/paks/tree_stump.starpak b/Northstar.Custom/paks/tree_stump.starpak
new file mode 100644
index 00000000..b233176e
--- /dev/null
+++ b/Northstar.Custom/paks/tree_stump.starpak
Binary files differ
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
index a5c3e270..a23a68b0 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut
@@ -10231,6 +10231,10 @@ void function StatUnlock_Unlocked( entity player, string itemRef, string parentR
if ( IsItemNew( player, itemRef, parentRef ) )
return
+ // early out if the player has progression disabled
+ if ( !ProgressionEnabledForPlayer( player ) )
+ return
+
int refGuid = file.itemRefToGuid[itemRef]
int parentRefGuid = parentRef == "" ? 0 : file.itemRefToGuid[parentRef]
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
index 24dbb62d..103efe6f 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
@@ -201,6 +201,10 @@ bool function ClientCommandCallback_SwapSecondaryAndWeapon3PersistentLoadoutData
// get loadout
int index = args[0].tointeger()
+
+ if ( !IsValidPilotLoadoutIndex(index) )
+ return false
+
PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, index )
// swap loadouts
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 bab7eaed..9288f75e 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
@@ -295,6 +295,10 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga
})
entity attacker = DamageInfo_GetAttacker( damageInfo )
+ entity inflictor = DamageInfo_GetInflictor( damageInfo )
+ int eHandle = attacker.GetEncodedEHandle()
+ if ( inflictor && ShouldTryUseProjectileReplay( player, attacker, damageInfo, false ) )
+ eHandle = inflictor.GetEncodedEHandle()
int methodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo )
table<int, bool> alreadyAssisted
@@ -374,7 +378,7 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga
if ( "respawnTime" in attacker.s )
respawnTime = Time() - expect float ( attacker.s.respawnTime )
- thread PlayerWatchesKillReplayWrapper( player, attacker, respawnTime, timeOfDeath, beforeTime, replayTracker )
+ thread PlayerWatchesKillReplayWrapper( player, attacker, eHandle, respawnTime, timeOfDeath, beforeTime, replayTracker )
}
player.SetPlayerSettings( "spectator" ) // prevent a crash with going from titan => pilot on respawn
@@ -432,7 +436,7 @@ void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 )
player.Signal( "RespawnMe" )
}
-void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker )
+void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, int eHandle, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker )
{
player.EndSignal( "RespawnMe" )
player.EndSignal( "OnRespawned" )
@@ -455,7 +459,7 @@ void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, fl
})
player.SetPredictionEnabled( false )
- PlayerWatchesKillReplay( player, attacker.GetEncodedEHandle(), attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker )
+ PlayerWatchesKillReplay( player, eHandle, attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker )
}
void function DecideRespawnPlayer( entity player )
@@ -628,6 +632,10 @@ void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref
bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo )
{
+ // dropships are immune to being crushed
+ if ( ( IsDropship( ent ) || IsEvacDropship( ent ) ) && IsTitanCrushDamage( damageInfo ) )
+ return false
+
return true
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
index 3426cec5..4c52a9bf 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
@@ -13,6 +13,8 @@ global function SetTimerBased
global function SetShouldUseRoundWinningKillReplay
global function SetRoundWinningKillReplayKillClasses
global function SetRoundWinningKillReplayAttacker
+global function SetCallback_TryUseProjectileReplay
+global function ShouldTryUseProjectileReplay
global function SetWinner
global function SetTimeoutWinnerDecisionFunc
global function AddTeamScore
@@ -48,13 +50,28 @@ struct {
float roundWinningKillReplayTime
entity roundWinningKillReplayVictim
entity roundWinningKillReplayAttacker
+ int roundWinningKillReplayInflictorEHandle // this is either the inflictor or the attacker
int roundWinningKillReplayMethodOfDeath
float roundWinningKillReplayTimeOfDeath
float roundWinningKillReplayHealthFrac
array<void functionref()> roundEndCleanupCallbacks
+ 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()
{
// todo: using the pin telemetry function here, weird and was done veeery early on before i knew how this all worked, should use a different one
@@ -319,6 +336,7 @@ void function GameStateEnter_WinnerDetermined_Threaded()
WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay
file.roundWinningKillReplayAttacker = null // clear this
+ file.roundWinningKillReplayInflictorEHandle = -1
if ( killcamsWereEnabled )
SetKillcamsEnabled( true )
@@ -394,7 +412,7 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLe
if ( IsValid( attacker ) )
{
player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS )
- player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() )
+ player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle )
player.SetKillReplayVictim( file.roundWinningKillReplayVictim )
player.SetViewIndex( attacker.GetIndexForEntity() )
player.SetIsReplayRoundWinning( true )
@@ -460,6 +478,7 @@ void function GameStateEnter_SwitchingSides_Threaded()
svGlobal.levelEnt.Signal( "RoundEnd" ) // might be good to get a new signal for this? not 100% necessary tho i think
SetServerVar( "switchedSides", 1 )
file.roundWinningKillReplayAttacker = null // reset this after replay
+ file.roundWinningKillReplayInflictorEHandle = -1
if ( file.usePickLoadoutScreen )
SetGameState( eGameState.PickLoadout )
@@ -483,7 +502,7 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla
entity attacker = file.roundWinningKillReplayAttacker
player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS )
- player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() )
+ player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle )
player.SetKillReplayVictim( file.roundWinningKillReplayVictim )
player.SetViewIndex( attacker.GetIndexForEntity() )
player.SetIsReplayRoundWinning( true )
@@ -578,6 +597,9 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo )
return
}
+ entity inflictor = DamageInfo_GetInflictor( damageInfo )
+ bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, attacker, damageInfo, true )
+
// set round winning killreplay info here if we're tracking pilot kills
// todo: make this not count environmental deaths like falls, unsure how to prevent this
if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) )
@@ -587,6 +609,7 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo )
file.roundWinningKillReplayTime = Time()
file.roundWinningKillReplayVictim = victim
file.roundWinningKillReplayAttacker = attacker
+ file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle()
file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo )
file.roundWinningKillReplayTimeOfDeath = Time()
file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker )
@@ -637,6 +660,9 @@ void function OnTitanKilled( entity victim, var damageInfo )
return
}
+ entity inflictor = DamageInfo_GetInflictor( damageInfo )
+ bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, DamageInfo_GetAttacker( damageInfo ), damageInfo, true )
+
// set round winning killreplay info here if we're tracking titan kills
// todo: make this not count environmental deaths like falls, unsure how to prevent this
entity attacker = DamageInfo_GetAttacker( damageInfo )
@@ -647,6 +673,7 @@ void function OnTitanKilled( entity victim, var damageInfo )
file.roundWinningKillReplayTime = Time()
file.roundWinningKillReplayVictim = victim
file.roundWinningKillReplayAttacker = attacker
+ file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle()
file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo )
file.roundWinningKillReplayTimeOfDeath = Time()
file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker )
@@ -761,11 +788,12 @@ void function SetRoundWinningKillReplayKillClasses( bool pilot, bool titan )
file.roundWinningKillReplayTrackTitanKills = titan // player kills in titans should get tracked anyway, might be worth renaming this
}
-void function SetRoundWinningKillReplayAttacker( entity attacker )
+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()
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
index 0b55e9ff..be20982d 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
@@ -28,6 +28,10 @@ void function InitPlayerForScoreEvents( entity player )
player.s.currentKillstreak <- 0
player.s.lastKillTime <- 0.0
player.s.currentTimedKillstreak <- 0
+ player.s.lastKillTime_Mayhem <- 0.0
+ player.s.currentTimedKillstreak_Mayhem <- 0
+ player.s.lastKillTime_Onslaught <- 0.0
+ player.s.currentTimedKillstreak_Onslaught <- 0
}
void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity associatedEnt = null, string noideawhatthisis = "", int pointValueOverride = -1 )
@@ -93,6 +97,7 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag
victim.s.currentTimedKillstreak = 0
victim.p.numberOfDeathsSinceLastKill++ // this is reset on kill
+ victim.p.lastKiller = attacker
// have to do this early before we reset victim's player killstreaks
// nemesis when you kill a player that is dominating you
@@ -131,12 +136,20 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag
attacker.p.numberOfDeathsSinceLastKill = 0
}
+ // revenge + quick revenge
+ if ( attacker.p.lastKiller == victim )
+ {
+ if ( Time() - GetPlayerLastRespawnTime( attacker ) < QUICK_REVENGE_TIME_LIMIT )
+ AddPlayerScore( attacker, "QuickRevenge" )
+ else
+ AddPlayerScore( attacker, "Revenge" )
+ }
// untimed killstreaks
attacker.s.currentKillstreak++
- if ( attacker.s.currentKillstreak == 3 )
+ if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT )
AddPlayerScore( attacker, "KillingSpree" )
- else if ( attacker.s.currentKillstreak == 5 )
+ else if ( attacker.s.currentKillstreak == RAMPAGE_KILL_REQUIREMENT )
AddPlayerScore( attacker, "Rampage" )
// increment untimed killstreaks against specific players
@@ -202,18 +215,23 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage
AddPlayerScore( attacker, "KillTitan" )
}
- table<int, bool> alreadyAssisted
- foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory )
+ entity soul = victim.GetTitanSoul()
+ if ( IsValid( soul ) )
{
- if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim )
- continue
-
- bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false
- if( attackerInfo.attacker != attacker && !exists )
+ table<int, bool> alreadyAssisted
+
+ foreach( DamageHistoryStruct attackerInfo in soul.e.recentDamageHistory )
{
- alreadyAssisted[attackerInfo.attacker.GetEncodedEHandle()] <- true
- AddPlayerScore(attackerInfo.attacker, "TitanAssist" )
- Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), attackerInfo.time )
+ if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == soul )
+ continue
+
+ bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false
+ if( attackerInfo.attacker != attacker && !exists )
+ {
+ alreadyAssisted[attackerInfo.attacker.GetEncodedEHandle()] <- true
+ AddPlayerScore(attackerInfo.attacker, "TitanAssist" )
+ Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), soul.GetEncodedEHandle(), attackerInfo.time )
+ }
}
}
@@ -229,6 +247,39 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn
AddPlayerScore( attacker, ScoreEventForNPCKilled( victim, damageInfo ), victim )
}
catch ( ex ) {}
+
+ if ( !attacker.IsPlayer() )
+ return
+
+ // mayhem/onslaught (timed killstreaks vs AI)
+
+ // reset before checking
+ if ( Time() - attacker.s.lastKillTime_Mayhem > MAYHEM_REQUIREMENT_TIME )
+ {
+ attacker.s.currentTimedKillstreak_Mayhem = 0
+ attacker.s.lastKillTime_Mayhem = Time()
+ }
+ if ( Time() - attacker.s.lastKillTime_Mayhem <= MAYHEM_REQUIREMENT_TIME )
+ {
+ attacker.s.currentTimedKillstreak_Mayhem++
+
+ if ( attacker.s.currentTimedKillstreak_Mayhem == MAYHEM_REQUIREMENT_KILLS )
+ AddPlayerScore( attacker, "Mayhem" )
+ }
+
+ // reset before checking
+ if ( Time() - attacker.s.lastKillTime_Onslaught > ONSLAUGHT_REQUIREMENT_TIME )
+ {
+ attacker.s.currentTimedKillstreak_Onslaught = 0
+ attacker.s.lastKillTime_Onslaught = Time()
+ }
+ if ( Time() - attacker.s.lastKillTime_Onslaught <= ONSLAUGHT_REQUIREMENT_TIME )
+ {
+ attacker.s.currentTimedKillstreak_Onslaught++
+
+ if ( attacker.s.currentTimedKillstreak_Onslaught == ONSLAUGHT_REQUIREMENT_KILLS )
+ AddPlayerScore( attacker, "Onslaught" )
+ }
}
void function ScoreEvent_MatchComplete( int winningTeam )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut
index aa2fc108..510a9b7e 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut
@@ -170,6 +170,9 @@ void function SpectatorFunc_Default( entity player )
{
player.SetObserverTarget( target )
player.StartObserverMode( OBS_MODE_CHASE )
+ // the delay of 0.1 seems to fix the spec_mode command not working
+ // when using the keybind
+ player.SetSpecReplayDelay( 0.1 )
}
catch ( ex ) { }
}
@@ -215,9 +218,12 @@ bool function ClientCommandCallback_spec_mode( entity player, array<string> args
else if ( player.GetObserverMode() == OBS_MODE_IN_EYE )
{
// set to third person spectate
- player.SetSpecReplayDelay( 0.0 )
+
+ // the delay of 0.1 seems to fix the spec_mode command not working
+ // when using the keybind
+ player.SetSpecReplayDelay( 0.1 )
player.StartObserverMode( OBS_MODE_CHASE )
}
return true
-} \ No newline at end of file
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
index 208e6da1..bd64e4ca 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
@@ -264,7 +264,7 @@ void function Stats_IncrementStat( entity player, string statCategory, string st
// persistence string, we can't save the persistence so we have to just return
if ( str != saveVar )
{
- printt( ex )
+ //printt( ex, str, GetMapName(), mode ) // Commented out due to spamming logs on invalid modes (e.g. Gun Game, Infection, ...)
return
}
}
@@ -571,9 +571,11 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo )
// assistsTotal ( weapon_kill_stats )
// note: eww
table<int, bool> alreadyAssisted
- foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory )
+ // titans store their recentDamageHistory in the soul
+ entity assistVictim = ( victim.IsTitan() && IsValid( victim.GetTitanSoul() ) ) ? victim.GetTitanSoul() : victim
+ foreach( DamageHistoryStruct attackerInfo in assistVictim.e.recentDamageHistory )
{
- if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim )
+ if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == assistVictim )
continue
bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false
@@ -585,7 +587,7 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo )
string source = DamageSourceIDToString( attackerInfo.damageSourceId )
if ( IsValidStatItemString( source ) )
- Stats_IncrementStat( attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 )
+ Stats_IncrementStat( attackerInfo.attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 )
}
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut
index ceb5e837..2dc88d0d 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut
@@ -38,6 +38,7 @@ void function Progression_Init()
#if SERVER
AddCallback_OnClientDisconnected( OnClientDisconnected )
AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression )
+ AddClientCommandCallback( "ns_resettitanaegis", ClientCommand_ResetTitanAegis )
AddCallback_GameStateEnter( eGameState.Playing, OnPlaying )
#elseif CLIENT
AddCallback_OnClientScriptInit( OnClientScriptInit )
@@ -84,6 +85,28 @@ bool function ClientCommand_SetProgression( entity player, array<string> args )
return true
}
+
+/// 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.
+///
+/// Returns `true` on success and `false` on missing args.
+bool function ClientCommand_ResetTitanAegis( entity player, array<string> args )
+{
+ if ( !args.len() )
+ return false
+
+ int suitIndex = args[0].tointeger()
+ player.SetPersistentVar( "titanFDUnlockPoints[" + suitIndex + "]", 0 )
+ player.SetPersistentVar( "previousFDUnlockPoints[" + suitIndex + "]", 0 )
+ player.SetPersistentVar( "fdTitanXP[" + suitIndex + "]", 0 )
+ player.SetPersistentVar( "fdPreviousTitanXP[" + suitIndex + "]", 0 )
+
+ // Refresh Highest Aegis Titan since we might get all of them back to 1 if players wants
+ RecalculateHighestTitanFDLevel( player )
+
+ return true
+}
#endif
#if CLIENT
@@ -268,7 +291,7 @@ void function ValidateEquippedItems( entity player )
// camoIndex
if ( loadout.skinIndex == TITAN_SKIN_INDEX_CAMO )
{
- array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_TITAN )
if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 )
{
printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
@@ -363,7 +386,7 @@ void function ValidateEquippedItems( entity player )
// primeCamoIndex
if ( loadout.primeSkinIndex == TITAN_SKIN_INDEX_CAMO )
{
- array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN )
+ array<ItemData> camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_TITAN )
if ( loadout.primeCamoIndex >= camoSkins.len() || loadout.primeCamoIndex < 0 )
{
printt( " - INVALID TITAN CAMO/SKIN, RESETTING" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
index 9e762985..2ca051cf 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut
@@ -348,6 +348,14 @@ string function GetMapDisplayDesc( string mapname )
return "#" + mapname + "_CLASSIC_DESC"
}
+/// Sends a string message to player
+/// * `baseString` - The input string to search through
+/// * `searchString` - Find this substring...
+/// * `replaceString` - ...and replace with this substring
+/// * `replaceAll` - Whether to replace all occurences or just the first
+/// * `caseInsensitive` - Whether to consider casing (upper/lower)
+///
+/// Returns the updated string
string function StringReplace( string baseString, string searchString, string replaceString, bool replaceAll = false, bool caseInsensitive = false )
{
bool loopedOnce = false
@@ -1532,7 +1540,23 @@ array<string> function GetAvailableTitanRefs( entity player )
return availableTitanRefs
}
+/// Gets the highest Titan FD level and stores it in the corresponding persistent var.
+/// * `player` - The player entity to perform the action on
#if MP
+void function RecalculateHighestTitanFDLevel( entity player )
+{
+ int enumCount = PersistenceGetEnumCount( "titanClasses" )
+ int highestAegis = 0
+ for ( int i = 0; i < enumCount; i++ )
+ {
+ string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i )
+ int aegisLevel = FD_TitanGetLevelForXP( enumName, FD_TitanGetXP( player, enumName ) )
+ if ( highestAegis < aegisLevel )
+ highestAegis = aegisLevel
+ }
+ player.SetPersistentVar( "fdStats.highestTitanFDLevel", highestAegis )
+}
+
string function GetTitanRefForLoadoutIndex( entity player, int loadoutIndex )
{
TitanLoadoutDef loadout = GetTitanLoadoutFromPersistentData( player, loadoutIndex )
diff --git a/README.md b/README.md
index 5a180df9..7b6dfaf0 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
# NorthstarMods
+<a href="https://translate.harmony.tf/engage/northstar/">
+<img src="https://translate.harmony.tf/widgets/northstar/-/client/svg-badge.svg" alt="Translation status" />
+</a>
[Squirrel](http://www.squirrel-lang.org/squirreldoc/reference/index.html) scripts used to recreate server-side gamelogic and add [custom content](https://r2northstar.gitbook.io/r2northstar-wiki/using-northstar/gamemodes) to the game.
@@ -9,3 +12,11 @@ Issues in this repository should be created if they are related to these domains
- `Northstar.Coop` - Soon™.
- `Northstar.Custom` - Northstar custom content.
- `Northstar.CustomServer` - Server config files and scripts necessary for multiplayer.
+
+### Translating
+
+Translations can be submitted via [weblate](https://translate.harmony.tf/projects/northstar/client/).
+
+<a href="https://translate.harmony.tf/engage/northstar/">
+<img src="https://translate.harmony.tf/widgets/northstar/-/client/multi-auto.svg" alt="Translation status" />
+</a>