aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Northstar.Client/mod.json11
-rw-r--r--Northstar.Client/mod/materials/vgui/reset.vmt12
-rw-r--r--Northstar.Client/mod/materials/vgui/reset.vtfbin0 -> 5712 bytes
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_english.txt21
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_french.txt18
-rw-r--r--Northstar.Client/mod/resource/northstar_client_localisation_italian.txt18
-rw-r--r--Northstar.Client/mod/resource/ui/menus/mod_settings.menu511
-rw-r--r--Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res183
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut15
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut9
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut1105
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut52
-rw-r--r--Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut4
13 files changed, 1952 insertions, 7 deletions
diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json
index 54834676..e9536d66 100644
--- a/Northstar.Client/mod.json
+++ b/Northstar.Client/mod.json
@@ -115,6 +115,17 @@
"RunOn": "UI"
},
{
+ "Path": "ui/ns_slider.nut",
+ "RunOn": "UI"
+ },
+ {
+ "Path": "ui/menu_mod_settings.nut",
+ "RunOn": "UI",
+ "UICallback":{
+ "Before": "AddModSettingsMenu"
+ }
+ },
+ {
"Path": "ui/ui_mouse_capture.nut",
"RunOn": "UI"
}
diff --git a/Northstar.Client/mod/materials/vgui/reset.vmt b/Northstar.Client/mod/materials/vgui/reset.vmt
new file mode 100644
index 00000000..84034586
--- /dev/null
+++ b/Northstar.Client/mod/materials/vgui/reset.vmt
@@ -0,0 +1,12 @@
+"Basic"
+{
+ "$basetexture" "vgui/reset"
+ "$translucent" 1
+ "$vertexcolor" 1
+ "$vertexalpha" 1
+ "$no_fullbright" 1
+ "$ignorez" 1
+ "$nolod" 1
+
+ "$SHADERSRGBREAD360" 1
+}
diff --git a/Northstar.Client/mod/materials/vgui/reset.vtf b/Northstar.Client/mod/materials/vgui/reset.vtf
new file mode 100644
index 00000000..5ffb86a9
--- /dev/null
+++ b/Northstar.Client/mod/materials/vgui/reset.vtf
Binary files differ
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
index c25708a6..5dabd539 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt
@@ -321,5 +321,26 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a
"INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token"
"JSON_PARSE_ERROR" "Error parsing json response"
"UNSUPPORTED_VERSION" "The version you are using is no longer supported"
+
+ // Mod Settings
+ "MOD_SETTINGS" "Mod Settings"
+ "NORTHSTAR_BASE_SETTINGS" "Northstar Base Settings"
+ "ONLY_HOST_MATCH_SETTINGS" "Only Host can change Private Match settings"
+ "ONLY_HOST_CAN_START_MATCH" "Only Host can Start the Match"
+ "MATCH_COUNTDOWN_LENGTH" "Private Match Countdown Duration"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Log Unknown Client Commands"
+ "DISALLOWED_TACTICALS" "Prohibited Tacticals"
+ "TACTICAL_REPLACEMENT" "Replacement Tactical"
+ "DISALLOWED_WEAPONS" "Prohibited Weapons"
+ "REPLACEMENT_WEAPON" "Replacement Weapon"
+ "SHOULD_RETURN_TO_LOBBY" "Return To Lobby After Match End"
+ "ARE_YOU_SURE" "Are you sure?"
+ "WILL_RESET_ALL_SETTINGS" "This will reset ALL settings that belong to this category.\n\nThis is not revertable."
+ "WILL_RESET_SETTING" "This will reset the %s1 setting to it's default value.\n\nThis is not revertable."
+ "MOD_SETTINGS_SERVER" "Server"
+ "MOD_SETTINGS_RESET" "Reset"
+ "MOD_SETTINGS_RESET_ALL" "Reset All"
+ "NO_RESULTS" "No results."
+ "NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0."
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
index 2a199186..d90cea05 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt
@@ -319,5 +319,23 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst
"INVALID_MASTERSERVER_TOKEN" "Jeton du server maître invalide ou expiré"
"JSON_PARSE_ERROR" "Une erreur est survenue durant l'analyse JSON"
"UNSUPPORTED_VERSION" "La version que vous utilisez n'est plus supportée"
+
+ "MOD_SETTINGS" "Paramètres de mod"
+ "NORTHSTAR_BASE_SETTINGS" "Paramètres de base de Northstar"
+ "ONLY_HOST_MATCH_SETTINGS" "Seul l'hôte peut changer les paramètres de match privé"
+ "ONLY_HOST_CAN_START_MATCH" "Seul l'hôte peut lancer le match"
+ "MATCH_COUNTDOWN_LENGTH" "Durée du compte à rebours de match privé"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Enregistrer les commandes client inconnues"
+ "DISALLOWED_TACTICALS" "Capacités interdites"
+ "TACTICAL_REPLACEMENT" "Capacités de remplacement"
+ "DISALLOWED_WEAPONS" "Armes interdites"
+ "REPLACEMENT_WEAPON" "Armes de remplacement"
+ "SHOULD_RETURN_TO_LOBBY" "Retour au lobby après la fin du match"
+ "ARE_YOU_SURE" "Êtes-vous certain ?"
+ "WILL_RESET_ALL_SETTINGS" "Ceci réinitialisera tous les paramètres de cette catégorie.\n\nCette action est irréversible."
+ "WILL_RESET_SETTING" "Ceci réinitialisera le paramètre %s1 à sa valeur par défaut.\n\nCette action est irréversible."
+ "MOD_SETTINGS_SERVER" "Serveur"
+ "MOD_SETTINGS_RESET" "Réinitialiser"
+ "MOD_SETTINGS_RESET_ALL" "Tout réinitialiser"
}
}
diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
index 72bf7030..13835b8b 100644
--- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
+++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt
@@ -319,5 +319,23 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo
"INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto"
"JSON_PARSE_ERROR" "Errore nell'analisi di risposta json"
"UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata"
+
+ "MOD_SETTINGS" "Impostazioni Mod"
+ "NORTHSTAR_BASE_SETTINGS" "Impostazioni base Northstar"
+ "ONLY_HOST_MATCH_SETTINGS" "Solo l'Host può modificare le impostazioni della Partita Privata"
+ "ONLY_HOST_CAN_START_MATCH" "Solo l'Host può Iniziare la Partita"
+ "MATCH_COUNTDOWN_LENGTH" "Durata Countdown della Partita Privata"
+ "LOG_UNKNOWN_CLIENTCOMMANDS" "Registra Comandi Client Sconosciuti"
+ "DISALLOWED_TACTICALS" "Abilità Proibite"
+ "TACTICAL_REPLACEMENT" "Sostituzione Abilità"
+ "DISALLOWED_WEAPONS" "Armi Proibite"
+ "REPLACEMENT_WEAPON" "Sostituzione Armi"
+ "SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita"
+ "ARE_YOU_SURE" "Sei sicuro?"
+ "WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato."
+ "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1.
+ "MOD_SETTINGS_SERVER" "Server"
+ "MOD_SETTINGS_RESET" "Ripristina"
+ "MOD_SETTINGS_RESET_ALL" "Ripristina Tutto"
}
}
diff --git a/Northstar.Client/mod/resource/ui/menus/mod_settings.menu b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu
new file mode 100644
index 00000000..2fed2bd1
--- /dev/null
+++ b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu
@@ -0,0 +1,511 @@
+"resource/ui/menus/mods_browse.menu"
+{
+ "menu"
+ {
+ "ControlName" "Frame"
+ "xpos" "0"
+ "ypos" "0"
+ "zpos" "3"
+ "wide" "f0"
+ "tall" "f0"
+ "autoResize" "1"
+ "visible" "1"
+ "enabled" "1"
+ "pinCorner" "0"
+ "PaintBackgroundType" "0"
+ "infocus_bgcolor_override" "0 0 0 0"
+ "outoffocus_bgcolor_override" "0 0 0 0"
+ "Vignette"
+ {
+ "ControlName" "ImagePanel"
+ "InheritProperties" "MenuVignette"
+ }
+ "Title"
+ {
+ "ControlName" "Label"
+ "InheritProperties" "MenuTitle"
+ "labelText" "#MOD_SETTINGS"
+ }
+ "ImgTopBar"
+ {
+ "ControlName" "ImagePanel"
+ "InheritProperties" "MenuTopBar"
+ }
+ "DarkenBackground"
+ {
+ "ControlName" "Label"
+ "classname" "ConnectingHUD"
+ "xpos" "0"
+ "ypos" "0"
+ "zpos" "99"
+ "wide" "%100"
+ "tall" "%100"
+ "labelText" ""
+ "bgcolor_override" "0 0 0 0"
+ "visible" "0"
+ "paintbackground" "1"
+ }
+ "ButtonRowAnchor"
+ {
+ "ControlName" "Label"
+ "labelText" ""
+ "pin_to_sibling" "DarkenBackground"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ "pin_corner_to_sibling" "BOTTOM_LEFT"
+ "xpos" "-150"
+ "ypos" "-200"
+ }
+ "FilterButtonsRowAnchor"
+ {
+ "ControlName" "Label"
+ "pin_to_sibling" "LabelDetails"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "labelText" ""
+ "ypos" "12"
+ }
+ "NoResultLabel"
+ {
+ "ControlName" "Label"
+ "xpos" "0"
+ ypos "0"
+ wide "1200"
+ tall "675"
+ //auto_tall_tocontents 1
+ visible "1"
+ enabled "1"
+ //auto_wide_tocontents 1
+ labelText "No results."
+ textAlignment "center"
+ //auto_wide_tocontents "1"
+ //auto_tall_tocontents "1"
+ //fgcolor_override "255 255 255 255"
+ //bgcolor_override "0 0 0 200"
+ font Default_41
+
+ pin_to_sibling ButtonRowAnchor
+ pin_to_sibling_corner TOP_LEFT
+ pin_corner_to_sibling TOP_LEFT
+ }
+ // pain //
+ "BtnMod1"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "pin_to_sibling" "ButtonRowAnchor"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ "navUp" "BtnMod15"
+ "navDown" "BtnMod2"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "scriptID" "0"
+ }
+ "BtnMod2"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "pin_to_sibling" "BtnMod1"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod1"
+ "navDown" "BtnMod3"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "scriptID" "1"
+ }
+ "BtnMod3"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "2"
+ "pin_to_sibling" "BtnMod2"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod2"
+ "navDown" "BtnMod4"
+ }
+ "BtnMod4"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "3"
+ "pin_to_sibling" "BtnMod3"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod3"
+ "navDown" "BtnMod5"
+ }
+ "BtnMod5"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "4"
+ "pin_to_sibling" "BtnMod4"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod4"
+ "navDown" "BtnMod6"
+ }
+ "BtnMod6"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "5"
+ "pin_to_sibling" "BtnMod5"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod5"
+ "navDown" "BtnMod7"
+ }
+ "BtnMod7"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "6"
+ "pin_to_sibling" "BtnMod6"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod6"
+ "navDown" "BtnMod8"
+ }
+ "BtnMod8"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "7"
+ "pin_to_sibling" "BtnMod7"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod7"
+ "navDown" "BtnMod9"
+ }
+ "BtnMod9"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "8"
+ "pin_to_sibling" "BtnMod8"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod8"
+ "navDown" "BtnMod10"
+ }
+ "BtnMod10"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "9"
+ "pin_to_sibling" "BtnMod9"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod9"
+ "navDown" "BtnMod11"
+ }
+ "BtnMod11"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "10"
+ "pin_to_sibling" "BtnMod10"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod10"
+ "navDown" "BtnMod12"
+ }
+ "BtnMod12"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "11"
+ "pin_to_sibling" "BtnMod11"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod11"
+ "navDown" "BtnMod13"
+ }
+ "BtnMod13"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "12"
+ "pin_to_sibling" "BtnMod12"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod12"
+ "navDown" "BtnMod14"
+ }
+ "BtnMod14"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "13"
+ "pin_to_sibling" "BtnMod13"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod13"
+ "navDown" "BtnMod15"
+ }
+ "BtnMod15"
+ {
+ "ControlName" "CNestedPanel"
+ "classname" "ModButton"
+ "tall" "45"
+ "wide" "1200"
+ "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res"
+ "classname" "ModButton"
+ "scriptID" "14"
+ "pin_to_sibling" "BtnMod14"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ "navUp" "BtnMod14"
+ "navDown" "BtnMod1"
+ }
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ "FilterPanel"
+ {
+ "ControlName" "RuiPanel"
+ "wide" "1220"
+ "tall" "112"
+ //"xpos" "-8"
+ "classname" "FilterPanelChild"
+ "rui" "ui/knowledgebase_panel.rpak"
+ "visible" "1"
+ "zpos" "-1"
+ "pin_to_sibling" "FilterButtonsRowAnchor"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "LabelDetails"
+ {
+ "ControlName" "RuiPanel"
+ "tall" "695"
+ "wide" "1220"
+ "xpos" "10"
+ "ypos" "10"
+ "pin_to_sibling" "ButtonRowAnchor"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ "rui" "ui/knowledgebase_panel.rpak"
+ "wrap" "1"
+ "visible" "1"
+ "zpos" "-1"
+ }
+ "BtnSearchLabel"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" "#SEARCHBAR_LABEL"
+ "textAlignment" "west"
+ "classname" "FilterPanelChild"
+ "wide" "500"
+ "xpos" "-23"
+ "ypos" "-16"
+ "wrap" "1"
+ "visible" "1"
+ "zpos" "0"
+ "pin_to_sibling" "FilterButtonsRowAnchor"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModsSearch"
+ {
+ "ControlName" "TextEntry"
+ "classname" "FilterPanelChild"
+ "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox.
+ "xpos" "-400"
+ "ypos" "-5"
+ "wide" "390"
+ "tall" "30"
+ "textHidden" "0"
+ "editable" "1"
+ "font" "Default_21"
+ "allowRightClickMenu" "0"
+ "allowSpecialCharacters" "1"
+ "unicode" "1"
+ "pin_to_sibling" "BtnSearchLabel"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_RIGHT"
+ }
+ "BtnFiltersClear"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" "#CLEAR_FILTERS"
+ "classname" "FilterPanelChild"
+ "wide" "100"
+ "xpos" "0"
+ "ypos" "0"
+ "zpos" "90"
+ "scriptID" "999"
+ "pin_to_sibling" "BtnSearchLabel"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_RIGHT"
+ }
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ "BtnModListUpArrow"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ // labelText "A"F
+ "wide" "40"
+ "tall" "40"
+ "xpos" "2"
+ "ypos" "0"
+ "image" "vgui/hud/white"
+ "drawColor" "255 255 255 128"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModListUpArrowPanel"
+ {
+ "ControlName" "RuiPanel"
+ "wide" "40"
+ "tall" "40"
+ "xpos" "2"
+ "ypos" "0"
+ "rui" "ui/knowledgebase_panel.rpak"
+ "visible" "1"
+ "zpos" "-1"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModListDownArrow"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ // labelText "V"
+ "wide" "40"
+ "tall" "40"
+ "xpos" "2"
+ "ypos" "-655"
+ "image" "vgui/hud/white"
+ "drawColor" "255 255 255 128"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModListDownArrowPanel"
+ {
+ "ControlName" "RuiPanel"
+ "wide" "40"
+ "tall" "40"
+ "xpos" "2"
+ "ypos" "-655"
+ "rui" "ui/knowledgebase_panel.rpak"
+ "visible" "1"
+ "zpos" "-1"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModListSlider"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ // labelText "V"
+ "wide" "40"
+ "tall" "420"
+ "xpos" "2"
+ "ypos" "-40"
+ "zpos" "0"
+ "image" "vgui/hud/white"
+ "drawColor" "255 255 255 128"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "BtnModListSliderPanel"
+ {
+ "ControlName" "RuiPanel"
+ "wide" "40"
+ "tall" "420"
+ "xpos" "2"
+ "ypos" "-40"
+ "rui" "ui/knowledgebase_panel.rpak"
+ "visible" "1"
+ "zpos" "-1"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ // sh_menu_models.gnut has a global function which gets called when
+ // left mouse button gets called while hovering and has mouse
+ // deltaX; deltaY which we can yoink for ourselfes
+ "MouseMovementCapture"
+ {
+ "ControlName" "CMouseMovementCapturePanel"
+ "wide" "40"
+ "tall" "604"
+ "xpos" "2"
+ "ypos" "-40"
+ "zpos" "1"
+ "pin_to_sibling" "LabelDetails"
+ "pin_corner_to_sibling" "TOP_RIGHT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "ButtonTooltip"
+ {
+ "ControlName" "CNestedPanel"
+ "InheritProperties" "ButtonTooltip"
+ }
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ "FooterButtons"
+ {
+ "ControlName" "CNestedPanel"
+ "InheritProperties" "FooterButtons"
+ }
+ }
+}
diff --git a/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res
new file mode 100644
index 00000000..92dce922
--- /dev/null
+++ b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res
@@ -0,0 +1,183 @@
+"resource/ui/menus/panels/mod_setting.res"
+{
+ "FULL"
+ {
+ "ControlName" "Label"
+ "classname" "ConnectingHUD"
+ "xpos" "0"
+ "ypos" "0"
+ "zpos" "99"
+ "wide" "1200"
+ "tall" "45"
+ "labelText" ""
+ "bgcolor_override" "0 0 0 0"
+ "visible" "0"
+ "paintbackground" "1"
+ }
+ "BtnMod"
+ {
+ "ControlName" "Label"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" "Mod"
+ //"auto_wide_tocontents" "1"
+ "navRight" "EnumSelectButton"
+ "navLeft" "TextEntrySetting"
+ "wide" "390"
+ "tall" "45"
+ }
+ // we're getting to the top of this :)
+ "TopLine"
+ {
+ "ControlName" "ImagePanel"
+ "InheritProperties" "MenuTopBar"
+ "ypos" "0"
+ "wide" "%100"
+ "pin_to_sibling" "BtnMod"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_LEFT"
+ }
+ "ModTitle"
+ {
+ "ControlName" "Label"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" "Mod"
+ "font" "DefaultBold_43"
+ //"auto_wide_tocontents" "1"
+ "zpos" "-999"
+ "textAlignment" "center"
+ "navRight" "EnumSelectButton"
+ "navLeft" "TextEntrySetting"
+ "wide" "1200"
+ "tall" "45"
+
+ }
+ "Slider"
+ {
+ "ControlName" "SliderControl"
+ //"InheritProperties" "RuiSmallButton"
+ minValue 0.0
+ maxValue 2.0
+ stepSize 0.05
+ "pin_to_sibling" "BtnMod"
+ "pin_corner_to_sibling" "TOP_LEFT"
+ "pin_to_sibling_corner" "TOP_RIGHT"
+ "navRight" "ResetModToDefault"
+ "navLeft" "TextEntrySetting"
+ //isValueClampedToStepSize 1
+ BtnDropButton
+ {
+ ControlName RuiButton
+ //InheritProperties WideButton
+ style SliderButton
+ "wide" "320"
+ "tall" "45"
+ "labelText" ""
+ "auto_wide_tocontents" "0"
+ }
+ "wide" "320"
+ "tall" "45"
+ }
+ "EnumSelectButton"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ "style" "DialogListButton"
+ "labelText" ""
+ "zpos" "4"
+ "wide" "225"
+ "tall" "45"
+ //"xpos" "10"
+ "scriptID" "0"
+ "pin_to_sibling" "FULL"
+ "pin_corner_to_sibling" "RIGHT"
+ "pin_to_sibling_corner" "RIGHT"
+ "navLeft" "ResetModToDefault"
+ "navRight" "TextEntrySetting"
+ }
+ "ResetModToDefault"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" ""
+ "zpos" "0"
+ "xpos" "10"
+ "wide" "45"
+ "tall" "45"
+ "scriptID" "0"
+ "pin_to_sibling" "EnumSelectButton"
+ "pin_corner_to_sibling" "RIGHT"
+ "pin_to_sibling_corner" "LEFT"
+ "navLeft" "Slider"
+ "navRight" "TextEntrySetting"
+ }
+ "ResetModImage"
+ {
+ "ControlName" "ImagePanel"
+ "image" "vgui/reset"
+ "scaleImage" "1"
+ "drawColor" "180 180 180 255" // vanilla label color
+ "visible" "0"
+ "wide" "30"
+ "tall" "30"
+ "enabled" "0"
+
+ "pin_to_sibling" "ResetModToDefault"
+ "pin_corner_to_sibling" "CENTER"
+ "pin_to_sibling_corner" "CENTER"
+ }
+ "OpenCustomMenu"
+ {
+ "ControlName" "RuiButton"
+ "InheritProperties" "RuiSmallButton"
+ "labelText" "Open"
+ //"auto_wide_tocontents" "1"
+ "zpos" "4"
+ "wide" "1200"
+ "textAlignment" "center"
+ //"font" "Default_41"
+ //"xpos" "10"
+ "tall" "40"
+ "scriptID" "0"
+ "visible" "0"
+ "pin_to_sibling" "FULL"
+ "pin_corner_to_sibling" "RIGHT"
+ "pin_to_sibling_corner" "RIGHT"
+ "navLeft" "TextEntrySetting"
+ "navRight" "TextEntrySetting"
+ }
+ "TextEntrySetting"
+ {
+ "ControlName" "TextEntry"
+ "classname" "MatchSettingTextEntry"
+ //"xpos" "-35"
+ //"ypos" "-5"
+ "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox.
+ "wide" "160"
+ "tall" "30"
+ "scriptID" "0"
+ "textHidden" "0"
+ "editable" "1"
+ // NumericInputOnly 1
+ "font" "Default_21"
+ "allowRightClickMenu" "0"
+ "allowSpecialCharacters" "1"
+ "unicode" "0"
+ "pin_to_sibling" "EnumSelectButton"
+ "pin_corner_to_sibling" "CENTER"
+ "pin_to_sibling_corner" "CENTER"
+ "navLeft" "EnumSelectButton"
+ "navRight" "EnumSelectButton"
+ }
+ // we're getting to the bottom of this :)
+ "BottomLine"
+ {
+ "ControlName" "ImagePanel"
+ "InheritProperties" "MenuTopBar"
+ "ypos" "5"
+ "wide" "%100"
+ //"tall" "0"
+ "pin_to_sibling" "FULL"
+ "pin_corner_to_sibling" "BOTTOM_LEFT"
+ "pin_to_sibling_corner" "BOTTOM_LEFT"
+ }
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut
index 03bd8959..35c9e9ba 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut
@@ -112,8 +112,13 @@ void function InitInGameMPMenu()
Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) )
#endif
- file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" )
- Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) )
+ // MOD SETTINGS
+ var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" )
+ Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) )
+
+ // Nobody reads the FAQ so we replace it with ModSettings because of the limited combobutton space available
+ //file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" )
+ //Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) )
//var dataCenterButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#DATA_CENTER" )
//Hud_AddEventHandler( dataCenterButton, UIE_CLICK, OpenDataCenterDialog )
@@ -133,7 +138,7 @@ void function OnInGameMPMenu_Open()
bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes()
RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew )
- ComboButton_SetNew( file.faqButton, faqIsNew )
+ //ComboButton_SetNew( file.faqButton, faqIsNew )
UpdateLoadoutButtons()
RefreshCreditsAvailable()
@@ -255,6 +260,10 @@ void function InitInGameSPMenu()
var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" )
Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) )
#endif
+
+ // MOD SETTINGS
+ var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" )
+ Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) )
array<var> orderedButtons
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
index 3c868aab..2bef0e20 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut
@@ -352,8 +352,9 @@ void function SetupComboButtonTest( var menu )
var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" )
Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) )
#endif
- file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" )
- Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) )
+ // MOD SETTINGS
+ var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" )
+ Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) )
comboStruct.navUpButtonDisabled = true
comboStruct.navDownButton = file.genUpButton
@@ -635,9 +636,9 @@ void function OnLobbyMenu_Open()
ComboButton_SetNew( file.factionButton, anyNewFactions )
}
- bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes()
+ /*bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes()
RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew )
- ComboButton_SetNew( file.faqButton, faqIsNew )
+ ComboButton_SetNew( file.faqButton, faqIsNew )*/
TryUnlockSRSCallsign()
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut
new file mode 100644
index 00000000..a45082c7
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut
@@ -0,0 +1,1105 @@
+untyped
+global function AddModSettingsMenu
+global function ModSettings_AddSetting
+global function ModSettings_AddEnumSetting
+global function ModSettings_AddSliderSetting
+global function ModSettings_AddButton
+global function ModSettings_AddModTitle
+global function ModSettings_AddModCategory
+global function PureModulo
+
+// Legacy functions for backwards compatability. These will be removed eventually
+global function AddConVarSetting
+global function AddConVarSettingEnum
+global function AddConVarSettingSlider
+global function AddModSettingsButton
+global function AddModTitle
+global function AddModCategory
+
+const int BUTTONS_PER_PAGE = 15
+const string SETTING_ITEM_TEXT = " " // this is long enough to be the same size as the textentry field
+
+enum eEmptySpaceType
+{
+ None,
+ TopBar,
+ BottomBar
+}
+
+struct ConVarData {
+ string displayName
+ bool isEnumSetting = false
+ string conVar
+ string type
+
+ string modName
+ string catName
+ bool isCategoryName = false
+ bool isModName = false
+
+ bool isEmptySpace = false
+ int spaceType = 0
+
+ // SLIDER BULLSHIT
+ bool sliderEnabled = false
+ float min = 0.0
+ float max = 1.0
+ float stepSize = 0.05
+ bool forceClamp = false
+
+ bool isCustomButton = false
+ void functionref() onPress
+
+ array<string> values
+ var customMenu
+ bool hasCustomMenu = false
+}
+
+struct {
+ var menu
+ int scrollOffset = 0
+ bool updatingList = false
+ bool isOpen
+
+ array<ConVarData> conVarList
+ // if people use searches - i hate them but it'll do : )
+ array<ConVarData> filteredList
+ string filterText = ""
+ table<int, int> enumRealValues
+ table<string, bool> setFuncs
+ array<var> modPanels
+ array<var> resetModButtons
+ array<MS_Slider> sliders
+ string currentMod = ""
+ string currentCat = ""
+} file
+
+struct {
+ int deltaX = 0
+ int deltaY = 0
+} mouseDeltaBuffer
+
+void function AddModSettingsMenu()
+{
+ AddMenu( "ModSettings", $"resource/ui/menus/mod_settings.menu", InitModMenu )
+}
+
+void function InitModMenu()
+{
+ file.menu = GetMenu( "ModSettings" )
+ // DumpStack(2)
+ AddMenuFooterOption( file.menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" )
+
+ /////////////////////////////
+ // BASE NORTHSTAR SETTINGS //
+ /////////////////////////////
+
+ /*
+ ModSettings_AddModTitle( "^FF000000EXAMPLE" )
+ ModSettings_AddModCategory( "I wasted way too much time on this..." )
+ ModSettings_AddButton( "This is a custom button you can click on!", void function() : ()
+ {
+ print( "HELLOOOOOO" )
+ } )
+ ModSettings_AddEnumSetting( "filter_mods", "Very Huge Enum Example", split( "Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you", " " ) )
+ */
+ // Nuke weird rui on filter switch :D
+ // RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnShowFilter" ) ), "buttonText", "" )
+
+ file.modPanels = GetElementsByClassname( file.menu, "ModButton" )
+
+ AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened )
+ AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnModMenuClosed )
+
+ int len = file.modPanels.len()
+ for ( int i = 0; i < len; i++ )
+ {
+
+ // AddButtonEventHandler( button, UIE_CHANGE, OnSettingButtonPressed )
+ // get panel
+ var panel = file.modPanels[i]
+
+ // reset to default nav
+ var child = Hud_GetChild( panel, "BtnMod" )
+
+
+ child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "BtnMod" ) )
+ child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "BtnMod" ) )
+
+ // Enum button nav
+ child = Hud_GetChild( panel, "EnumSelectButton" )
+ Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "main" )
+ Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "next" )
+ Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "prev" )
+
+ child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "EnumSelectButton" ) )
+ child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "EnumSelectButton" ) )
+ Hud_AddEventHandler( child, UIE_CLICK, UpdateEnumSetting )
+
+ // reset button nav
+
+ child = Hud_GetChild( panel, "ResetModToDefault" )
+ Hud_AddEventHandler( child, UIE_GET_FOCUS, void function( var child ) : (panel)
+ {
+ Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 0, 0, 0, 255 )
+ })
+ Hud_AddEventHandler( child, UIE_LOSE_FOCUS, void function( var child ) : (panel)
+ {
+ Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 180, 180, 180, 180 )
+ })
+
+ child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "ResetModToDefault" ) )
+ child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "ResetModToDefault" ) )
+
+ Hud_AddEventHandler( child, UIE_CLICK, ResetConVar )
+ file.resetModButtons.append(child)
+
+ // text field nav
+ child = Hud_GetChild( panel, "TextEntrySetting" )
+
+ Hud_AddEventHandler( child, UIE_LOSE_FOCUS, SendTextPanelChanges )
+
+ child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "TextEntrySetting" ) )
+ child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "TextEntrySetting" ) )
+
+ child = Hud_GetChild( panel, "Slider" )
+
+ child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "Slider" ) )
+ child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "Slider" ) )
+
+ file.sliders.append( MS_Slider_Setup( child ) )
+
+ Hud_AddEventHandler( child, UIE_CHANGE, OnSliderChange )
+
+ child = Hud_GetChild( panel, "OpenCustomMenu" )
+
+ Hud_AddEventHandler( child, UIE_CLICK, CustomButtonPressed )
+ }
+
+ // Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_LOSE_FOCUS, OnFilterTextPanelChanged )
+ Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear" ), UIE_CLICK, OnClearButtonPressed )
+ // mouse delta
+ AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer )
+
+ Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_CHANGE, void function ( var inputField ) : ()
+ {
+ file.filterText = Hud_GetUTF8Text( inputField )
+ OnFiltersChange()
+ } )
+}
+
+// "PureModulo"
+// Used instead of modulo in some places.
+// Why? beacuse PureModulo loops back onto positive numbers instead of going into the negatives.
+// DO NOT TOUCH.
+// a / b != floor( float( a ) / b )
+// int( float( a ) / b ) != floor( float( a ) / b )
+// Examples:
+// -1 % 5 = -1
+// PureModulo( -1, 5 ) = 4
+float function PureModulo( int a, int b )
+{
+ return b * ( ( float( a ) / b ) - floor( float( a ) / b ) )
+}
+
+void function ResetConVar( var button )
+{
+ ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ]
+
+ if ( conVar.isCategoryName )
+ ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetAllConVarsForModEventHandler( conVar.catName ), "#WILL_RESET_ALL_SETTINGS" )
+ else
+ ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetConVarEventHandler( int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ), Localize( "#WILL_RESET_SETTING", Localize( conVar.displayName ) ) )
+}
+
+void function ShowAreYouSureDialog( string header, void functionref() func, string details )
+{
+ DialogData dialogData
+ dialogData.header = header
+ dialogData.message = details
+
+ AddDialogButton( dialogData, "#NO" )
+ AddDialogButton( dialogData, "#YES", func )
+
+ AddDialogFooter( dialogData, "#A_BUTTON_SELECT" )
+ AddDialogFooter( dialogData, "#B_BUTTON_BACK" )
+
+ OpenDialog( dialogData )
+}
+
+void functionref() function ResetAllConVarsForModEventHandler( string catName )
+{
+ return void function() : ( catName )
+ {
+ for ( int i = 0; i < file.conVarList.len(); i++ )
+ {
+ ConVarData c = file.conVarList[ i ]
+ if ( c.catName != catName || c.isCategoryName || c.isEmptySpace || c.isCustomButton )
+ continue
+ SetConVarToDefault( c.conVar )
+
+ int index = file.filteredList.find( c )
+ if ( file.filteredList.find( c ) < 0 )
+ continue
+
+ if ( min( BUTTONS_PER_PAGE - 1, max( 0, index - file.scrollOffset ) ) == index - file.scrollOffset )
+ {
+ Hud_SetText( Hud_GetChild( file.modPanels[ index - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) )
+ if( c.sliderEnabled )
+ MS_Slider_SetValue( file.sliders[ index - file.scrollOffset ], GetConVarFloat( c.conVar ) )
+ }
+ }
+ }
+}
+
+void functionref() function ResetConVarEventHandler( int modIndex )
+{
+ return void function() : ( modIndex )
+ {
+ ConVarData c = file.filteredList[ modIndex ]
+ SetConVarToDefault( c.conVar )
+ if ( min( BUTTONS_PER_PAGE - 1, max( 0, modIndex - file.scrollOffset ) ) == modIndex - file.scrollOffset )
+ {
+ Hud_SetText( Hud_GetChild( file.modPanels[ modIndex - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) )
+ if( c.sliderEnabled )
+ MS_Slider_SetValue( file.sliders[ modIndex - file.scrollOffset ], GetConVarFloat( c.conVar ) )
+ }
+ }
+}
+
+////////////
+// slider //
+////////////
+void function UpdateMouseDeltaBuffer( int x, int y )
+{
+ mouseDeltaBuffer.deltaX += x
+ mouseDeltaBuffer.deltaY += y
+
+ SliderBarUpdate()
+}
+
+void function FlushMouseDeltaBuffer()
+{
+ mouseDeltaBuffer.deltaX = 0
+ mouseDeltaBuffer.deltaY = 0
+}
+
+void function SliderBarUpdate()
+{
+ if ( file.filteredList.len() <= 15 )
+ {
+ FlushMouseDeltaBuffer()
+ return
+ }
+
+ var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" )
+ var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" )
+ var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" )
+
+ Hud_SetFocused( sliderButton )
+
+ float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded positions?!?!?!?!?!
+ float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 )
+ float maxYPos = minYPos - ( maxHeight - Hud_GetHeight( sliderPanel ) )
+ float useableSpace = ( maxHeight - Hud_GetHeight( sliderPanel ) )
+
+ float jump = minYPos - ( useableSpace / ( float( file.filteredList.len() ) ) )
+
+ int pos = expect int( expect array( Hud_GetPos( sliderButton ) )[1] )
+ float newPos = float( pos - mouseDeltaBuffer.deltaY )
+ FlushMouseDeltaBuffer()
+
+ if ( newPos < maxYPos ) newPos = maxYPos
+ if ( newPos > minYPos ) newPos = minYPos
+
+ Hud_SetPos( sliderButton, 2, newPos )
+ Hud_SetPos( sliderPanel, 2, newPos )
+ Hud_SetPos( movementCapture, 2, newPos )
+
+ file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.filteredList.len() - BUTTONS_PER_PAGE ) )
+ UpdateList()
+}
+
+void function UpdateListSliderHeight()
+{
+ var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" )
+ var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" )
+ var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" )
+
+ float mods = float ( file.filteredList.len() )
+
+ float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded 320/80???
+ float minHeight = 80.0 * ( GetScreenSize()[1] / 1080.0 )
+
+ float height = maxHeight * ( float( BUTTONS_PER_PAGE ) / mods )
+
+ if ( height > maxHeight ) height = maxHeight
+ if ( height < minHeight ) height = minHeight
+
+ Hud_SetHeight( sliderButton, height )
+ Hud_SetHeight( sliderPanel, height )
+ Hud_SetHeight( movementCapture, height )
+}
+
+void function UpdateList()
+{
+ Hud_SetFocused( Hud_GetChild( file.menu, "BtnModsSearch" ) )
+ file.updatingList = true
+
+ array<ConVarData> filteredList = []
+
+ array<string> filters = split( file.filterText, "," )
+ array<ConVarData> list = file.conVarList
+ if ( filters.len() <= 0 )
+ filters.append( "" )
+ foreach( string f in filters )
+ {
+ string filter = strip( f )
+ string lastCatNameInFilter = ""
+ string lastModNameInFilter = ""
+ int curCatIndex = 0
+ int curModTitleIndex = -1
+ for ( int i = 0; i < list.len(); i++ )
+ {
+ ConVarData prev = list[ maxint( 0, i - 1 ) ]
+ ConVarData c = list[i]
+ ConVarData next = list[ minint( list.len() - 1, i + 1 ) ]
+ if ( c.isEmptySpace )
+ continue
+
+ string displayName = c.displayName
+ if ( c.isModName )
+ {
+ displayName = c.modName
+ curModTitleIndex = i
+ }
+ if ( c.isCategoryName )
+ {
+ displayName = c.catName
+ curCatIndex = i
+ }
+ if ( filter == "" || SanitizeDisplayName( Localize( displayName ) ).tolower().find( filter.tolower() ) != null )
+ {
+ if ( c.isModName )
+ {
+ lastModNameInFilter = c.modName
+ array<ConVarData> modVars = GetAllVarsInMod( list, c.modName )
+ if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None )
+ filteredList.extend( modVars.slice( 1, modVars.len() ) )
+ else filteredList.extend( modVars )
+
+ i += modVars.len() - 1
+ }
+ else if ( c.isCategoryName )
+ {
+ if ( lastModNameInFilter != c.modName )
+ {
+ array<ConVarData> modVars = GetModConVarDatas( list, curModTitleIndex )
+ if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None )
+ filteredList.extend( modVars.slice( 1, modVars.len() ) )
+ else filteredList.extend( modVars )
+
+ lastModNameInFilter = c.modName
+ }
+ filteredList.extend( GetAllVarsInCategory( list, c.catName ) )
+ i += GetAllVarsInCategory( list, c.catName ).len() - 1
+ lastCatNameInFilter = c.catName
+ }
+ else
+ {
+ if ( lastModNameInFilter != c.modName )
+ {
+ array<ConVarData> modVars = GetModConVarDatas( list, curModTitleIndex )
+ if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None )
+ filteredList.extend( modVars.slice( 1, modVars.len() ) )
+ else filteredList.extend( modVars )
+
+ lastModNameInFilter = c.modName
+ }
+ if ( lastCatNameInFilter != c.catName )
+ {
+ filteredList.extend( GetCatConVarDatas( curCatIndex ) )
+ lastCatNameInFilter = c.catName
+ }
+ filteredList.append( c )
+ }
+ }
+ }
+ list = filteredList
+ filteredList = []
+ }
+ filteredList = list
+
+
+ file.filteredList = filteredList
+
+ int j = int( min( file.filteredList.len() + file.scrollOffset, BUTTONS_PER_PAGE ) )
+
+ for ( int i = 0; i < BUTTONS_PER_PAGE; i++ )
+ {
+ Hud_SetEnabled( file.modPanels[i], i < j )
+ Hud_SetVisible( file.modPanels[i], i < j )
+
+ if ( i < j )
+ SetModMenuNameText( file.modPanels[i] )
+ }
+ file.updatingList = false
+
+ if ( file.conVarList.len() <= 0 )
+ {
+ Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true )
+ Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_MODS" )
+ }
+ else if ( file.filteredList.len() <= 0 )
+ {
+ Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true )
+ Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_RESULTS" )
+ }
+ else
+ {
+ Hud_Hide( Hud_GetChild( file.menu, "NoResultLabel" ) )
+ }
+}
+
+array<ConVarData> function GetModConVarDatas( array<ConVarData> arr, int index )
+{
+ if ( index <= 1 )
+ return [ arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ]
+ return [ arr[ index - 2 ], arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ]
+}
+
+array<ConVarData> function GetCatConVarDatas( int index )
+{
+ if ( file.conVarList[ index - 1 ].spaceType != eEmptySpaceType.None )
+ return [ file.conVarList[ index ] ]
+ return [ file.conVarList[ index - 1 ], file.conVarList[ index ] ]
+}
+
+array<ConVarData> function GetAllVarsInCategory( array<ConVarData> arr, string catName )
+{
+ array<ConVarData> vars = []
+ for ( int i = 0; i < arr.len(); i++ )
+ {
+ ConVarData c = arr[i]
+ if ( c.catName == catName )
+ {
+ vars.append( arr[i] )
+ }
+ }
+ return vars
+}
+
+array<ConVarData> function GetAllVarsInMod( array<ConVarData> arr, string modName )
+{
+ array<ConVarData> vars = []
+ for ( int i = 0; i < arr.len(); i++ )
+ {
+ ConVarData c = arr[i]
+ if ( c.modName == modName )
+ {
+ vars.append( arr[i] )
+ }
+ }
+ return vars
+}
+
+void function SetModMenuNameText( var button )
+{
+ int index = int ( Hud_GetScriptID( button ) ) + file.scrollOffset
+ ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ]
+
+ var panel = file.modPanels[ int ( Hud_GetScriptID( button ) ) ]
+
+ var label = Hud_GetChild( panel, "BtnMod" )
+ var textField = Hud_GetChild( panel, "TextEntrySetting" )
+ var enumButton = Hud_GetChild( panel, "EnumSelectButton" )
+ var resetButton = Hud_GetChild( panel, "ResetModToDefault" )
+ var resetVGUI = Hud_GetChild( panel, "ResetModImage" )
+ var bottomLine = Hud_GetChild( panel, "BottomLine" )
+ var topLine = Hud_GetChild( panel, "TopLine" )
+ var modTitle = Hud_GetChild( panel, "ModTitle" )
+ var customMenuButton = Hud_GetChild( panel, "OpenCustomMenu")
+ var slider = Hud_GetChild( panel, "Slider" )
+ Hud_SetVisible( slider, false )
+ Hud_SetEnabled( slider, true )
+
+
+ if ( conVar.isEmptySpace )
+ {
+ string s = ""
+ Hud_SetPos( label, 0, 0 )
+ Hud_SetVisible( label, false )
+ Hud_SetVisible( textField, false )
+ Hud_SetVisible( enumButton, false )
+ Hud_SetVisible( resetButton, false )
+ Hud_SetVisible( resetVGUI, false )
+ Hud_SetVisible( modTitle, false )
+ Hud_SetVisible( customMenuButton, false )
+ Hud_SetVisible( bottomLine, false )
+ Hud_SetVisible( topLine, false )
+ switch ( conVar.spaceType )
+ {
+ case eEmptySpaceType.TopBar:
+ Hud_SetVisible( topLine, true )
+ return
+
+ case eEmptySpaceType.BottomBar:
+ Hud_SetVisible( bottomLine, true )
+ return
+
+ case eEmptySpaceType.None:
+ return
+ }
+ }
+
+ Hud_SetVisible( textField, !conVar.isCategoryName )
+ Hud_SetVisible( bottomLine, conVar.isCategoryName || conVar.spaceType == eEmptySpaceType.BottomBar )
+ Hud_SetVisible( topLine, false )
+ Hud_SetVisible( enumButton, !conVar.isCategoryName && conVar.isEnumSetting )
+ Hud_SetVisible( modTitle, conVar.isModName )
+ Hud_SetVisible( customMenuButton, false )
+ float scaleX = GetScreenSize()[1] / 1080.0
+ float scaleY = GetScreenSize()[1] / 1080.0
+ if ( conVar.sliderEnabled )
+ {
+ Hud_SetSize( slider, int( 320 * scaleX ), int( 45 * scaleY ) )
+ MS_Slider s = file.sliders[ int ( Hud_GetScriptID( button ) ) ]
+ MS_Slider_SetMin( s, conVar.min )
+ MS_Slider_SetMax( s, conVar.max )
+ MS_Slider_SetStepSize( s, conVar.stepSize )
+ MS_Slider_SetValue( s, GetConVarFloat( conVar.conVar ) )
+ }
+ else Hud_SetSize( slider, 0, int( 45 * scaleY ) )
+ if ( conVar.isCustomButton )
+ {
+ Hud_SetVisible( label, false )
+ Hud_SetVisible( textField, false )
+ Hud_SetVisible( enumButton, false )
+ Hud_SetVisible( resetButton, false )
+ Hud_SetVisible( modTitle, false )
+ Hud_SetVisible( resetVGUI, false )
+ Hud_SetVisible( customMenuButton, true )
+ Hud_SetText( customMenuButton, conVar.displayName )
+ }
+ else if ( conVar.isModName )
+ {
+ Hud_SetText( modTitle, conVar.modName )
+ Hud_SetPos( label, 0, 0 )
+ Hud_SetVisible( label, false )
+ Hud_SetVisible( textField, false )
+ Hud_SetVisible( enumButton, false )
+ Hud_SetVisible( resetButton, false )
+ Hud_SetVisible( resetVGUI, false )
+ Hud_SetVisible( bottomLine, false )
+ Hud_SetVisible( topLine, false )
+ }
+ else if ( conVar.isCategoryName )
+ {
+ Hud_SetText( label, conVar.catName )
+ Hud_SetPos( label, 0, 0 )
+ Hud_SetSize( label, int( scaleX * ( 1180 - 420 - 85 ) ), int( scaleY * 40 ) )
+ Hud_SetVisible( label, true )
+ Hud_SetVisible( textField, false )
+ Hud_SetVisible( enumButton, false )
+ Hud_SetVisible( resetButton, true )
+ Hud_SetVisible( resetVGUI, true )
+
+ Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) )
+ }
+ else {
+ Hud_SetVisible( slider, conVar.sliderEnabled )
+
+ Hud_SetText( label, conVar.displayName )
+ if (conVar.type == "float")
+ Hud_SetText( textField, string( GetConVarFloat(conVar.conVar) ) )
+ else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) )
+ Hud_SetPos( label, int(scaleX * 25), 0 )
+ Hud_SetText( resetButton, "" )
+ if (conVar.sliderEnabled)
+ Hud_SetSize( label, int(scaleX * (375 + 85)), int(scaleY * 40) )
+ else Hud_SetSize( label, int(scaleX * (375 + 405)), int(scaleY * 40) )
+ if ( conVar.type == "float" )
+ Hud_SetText( textField, string( GetConVarFloat( conVar.conVar ) ) )
+ else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) )
+ Hud_SetPos( label, int( scaleX * 25 ), 0 )
+ Hud_SetText( resetButton, "" )
+ Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) )
+ if ( conVar.sliderEnabled )
+ Hud_SetSize( label, int( scaleX * ( 375 + 85 ) ), int( scaleY * 40 ) )
+ else Hud_SetSize( label, int( scaleX * ( 375 + 405 ) ), int( scaleY * 40 ) )
+ Hud_SetVisible( label, true )
+ Hud_SetVisible( textField, true )
+ Hud_SetVisible( resetButton, true )
+ Hud_SetVisible( resetVGUI, true )
+ }
+}
+
+void function CustomButtonPressed( var button )
+{
+ var panel = Hud_GetParent( button )
+ ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ]
+ c.onPress()
+}
+
+void function OnScrollDown( var button )
+{
+ if ( file.filteredList.len() <= BUTTONS_PER_PAGE ) return
+ file.scrollOffset += 5
+ if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredList.len() )
+ {
+ file.scrollOffset = file.filteredList.len() - BUTTONS_PER_PAGE
+ }
+ UpdateList()
+ UpdateListSliderPosition()
+}
+
+void function OnScrollUp( var button )
+{
+ file.scrollOffset -= 5
+ if ( file.scrollOffset < 0 )
+ {
+ file.scrollOffset = 0
+ }
+ UpdateList()
+ UpdateListSliderPosition()
+}
+
+void function UpdateListSliderPosition()
+{
+ var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" )
+ var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" )
+ var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" )
+
+ float mods = float ( file.filteredList.len() )
+
+ float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 )
+ float useableSpace = ( 615.0 * ( GetScreenSize()[1] / 1080.0 ) - Hud_GetHeight( sliderPanel ) )
+
+ float jump = minYPos - ( useableSpace / ( mods - float( BUTTONS_PER_PAGE ) ) * file.scrollOffset )
+
+
+ if ( jump > minYPos ) jump = minYPos
+
+ Hud_SetPos( sliderButton , 2, jump )
+ Hud_SetPos( sliderPanel , 2, jump )
+ Hud_SetPos( movementCapture , 2, jump )
+}
+
+void function OnModMenuOpened()
+{
+ if( !file.isOpen )
+ {
+ file.scrollOffset = 0
+ file.filterText = ""
+
+ RegisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp )
+ RegisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown )
+ RegisterButtonPressedCallback( MOUSE_LEFT , OnClick )
+
+ OnFiltersChange()
+ file.isOpen = true
+ }
+}
+
+void function OnClick( var button )
+{
+ if (file.resetModButtons.contains(GetFocus()))
+ thread CheckFocus(GetFocus())
+ if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel"))
+ thread CheckFocus(GetFocus())
+}
+
+void function CheckFocus( var button )
+{
+ wait 0.05
+ if (file.resetModButtons.contains(GetFocus()))
+ {
+ thread ResetConVar(GetFocus())
+ }
+ if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel"))
+ LaunchExternalWebBrowser( "https://northstar.thunderstore.io/", WEBBROWSER_FLAG_FORCEEXTERNAL )
+}
+
+void function OnFiltersChange()
+{
+ file.scrollOffset = 0
+
+ UpdateList()
+
+ UpdateListSliderHeight()
+}
+
+void function OnModMenuClosed()
+{
+ DeregisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp )
+ DeregisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown )
+ DeregisterButtonPressedCallback( MOUSE_LEFT , OnClick )
+
+ file.scrollOffset = 0
+ UpdateListSliderPosition()
+ file.isOpen = false
+}
+
+void function ModSettings_AddModTitle( string modName, int stackPos = 2 )
+{
+ file.currentMod = modName
+ if ( file.conVarList.len() > 0 )
+ {
+ ConVarData catData
+
+ catData.isEmptySpace = true
+ catData.modName = file.currentMod
+
+ file.conVarList.append( catData )
+ }
+ ConVarData topBar
+ topBar.isEmptySpace = true
+ topBar.modName = modName
+ topBar.spaceType = eEmptySpaceType.TopBar
+
+
+ ConVarData modData
+
+ modData.modName = modName
+ modData.displayName = modName
+ modData.isModName = true
+
+
+ ConVarData botBar
+ botBar.isEmptySpace = true
+ botBar.modName = modName
+ botBar.spaceType = eEmptySpaceType.BottomBar
+ file.conVarList.extend( [ topBar, modData, botBar ] )
+ file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] <- false
+}
+
+void function AddModTitle( string modName, int stackPos = 2 )
+{
+ ModSettings_AddModTitle( modName, stackPos + 1 )
+}
+
+void function ModSettings_AddModCategory( string catName, int stackPos = 2 )
+{
+ if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) )
+ throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a category before a mod title!"
+
+ ConVarData space
+ space.isEmptySpace = true
+ space.modName = file.currentMod
+ space.catName = catName
+ file.conVarList.append( space )
+
+ ConVarData catData
+
+ catData.catName = catName
+ catData.displayName = catName
+ catData.modName = file.currentMod
+ catData.isCategoryName = true
+
+ file.conVarList.append( catData )
+
+ file.currentCat = catName
+ file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] = true
+}
+
+void function AddModCategory( string catName, int stackPos = 2 )
+{
+ ModSettings_AddModCategory( catName, stackPos + 1 )
+}
+
+void function ModSettings_AddButton( string buttonLabel, void functionref() onPress, int stackPos = 2 )
+{
+ if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] )
+ throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a button before a category and mod title!"
+
+ ConVarData data
+
+ data.isCustomButton = true
+ data.displayName = buttonLabel
+ data.modName = file.currentMod
+ data.catName = file.currentCat
+ data.onPress = onPress
+
+ file.conVarList.append( data )
+}
+
+void function AddModSettingsButton( string buttonLabel, void functionref() onPress, int stackPos = 2 )
+{
+ ModSettings_AddButton( buttonLabel, onPress, stackPos + 1 )
+}
+
+void function ModSettings_AddSetting( string conVar, string displayName, string type = "", int stackPos = 2 )
+{
+ if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] )
+ throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!"
+ ConVarData data
+
+ data.catName = file.currentCat
+ data.conVar = conVar
+ data.modName = file.currentMod
+ data.displayName = displayName
+ data.type = type
+
+ file.conVarList.append( data )
+}
+
+void function AddConVarSetting( string conVar, string displayName, string type = "", int stackPos = 2 )
+{
+ ModSettings_AddSetting( conVar, displayName, type, stackPos + 1 )
+}
+
+void function ModSettings_AddSliderSetting( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 )
+{
+ if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] )
+ throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!"
+ ConVarData data
+
+ data.catName = file.currentCat
+ data.conVar = conVar
+ data.modName = file.currentMod
+ data.displayName = displayName
+ data.type = "float"
+ data.sliderEnabled = true
+ data.forceClamp = false
+ data.min = min
+ data.max = max
+ data.stepSize = stepSize
+
+ file.conVarList.append( data )
+}
+
+void function AddConVarSettingSlider( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 )
+{
+ ModSettings_AddSliderSetting( conVar, displayName, min, max, stepSize, forceClamp, stackPos + 1 )
+}
+
+void function ModSettings_AddEnumSetting( string conVar, string displayName, array<string> values, int stackPos = 2 )
+{
+ if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] )
+ throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!"
+ ConVarData data
+
+ data.catName = file.currentCat
+ data.modName = file.currentMod
+ data.conVar = conVar
+ data.displayName = displayName
+ data.values = values
+ data.isEnumSetting = true
+ data.min = 0
+ data.max = values.len() - 1.0
+ data.sliderEnabled = values.len() > 2
+ data.forceClamp = true
+ data.stepSize = 1
+
+ file.conVarList.append( data )
+}
+
+void function AddConVarSettingEnum( string conVar, string displayName, array<string> values, int stackPos = 2 )
+{
+ ModSettings_AddEnumSetting( conVar, displayName, values, stackPos + 1 )
+}
+
+void function OnSliderChange( var button )
+{
+ if ( file.updatingList )
+ return
+ var panel = Hud_GetParent( button )
+ ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ]
+ var textPanel = Hud_GetChild( panel, "TextEntrySetting" )
+
+ if ( c.isEnumSetting )
+ {
+ int val = int( RoundToNearestInt( Hud_SliderControl_GetCurrentValue( button ) ) )
+ SetConVarInt( c.conVar, val )
+ Hud_SetText( textPanel, ( c.values[ GetConVarInt( c.conVar ) ] ) )
+ MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], float( val ) )
+
+ return
+ }
+ float val = Hud_SliderControl_GetCurrentValue( button )
+ if ( c.forceClamp )
+ {
+ int mod = int( RoundToNearestInt( val % c.stepSize / c.stepSize ) )
+ val = ( int( val / c.stepSize ) + mod ) * c.stepSize
+ }
+ SetConVarFloat( c.conVar, val )
+ MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], val )
+
+ Hud_SetText( textPanel, string( GetConVarFloat( c.conVar ) ) )
+}
+
+void function SendTextPanelChanges( var textPanel )
+{
+ ConVarData c = file.filteredList[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) + file.scrollOffset ]
+ if ( c.conVar == "" ) return
+ // enums don't need to do this
+ if ( !c.isEnumSetting )
+ {
+ string newSetting = Hud_GetUTF8Text( textPanel )
+
+ switch ( c.type )
+ {
+ case "int":
+ try
+ {
+ SetConVarInt( c.conVar, newSetting.tointeger() )
+ }
+ catch ( ex )
+ {
+ ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." )
+ Hud_SetText( textPanel, GetConVarString( c.conVar ) )
+ }
+ case "bool":
+ if ( newSetting != "0" && newSetting != "1" )
+ {
+ ThrowInvalidValue( "This setting is a boolean, and only accepts values of 0 or 1." )
+
+ // set back to previous value : )
+ Hud_SetText( textPanel, string( GetConVarBool( c.conVar ) ) )
+
+ break
+ }
+ SetConVarBool( c.conVar, newSetting == "1" )
+ break
+ case "float":
+ try
+ {
+ SetConVarFloat( c.conVar, newSetting.tofloat() )
+ }
+ catch ( ex )
+ {
+ printt( ex )
+ ThrowInvalidValue( "This setting is a float, and only accepts a number - we could not parse this!\n\n( Use \".\" for the floating point, not \",\". )" )
+ }
+ if ( c.sliderEnabled )
+ {
+ var panel = Hud_GetParent( textPanel )
+ MS_Slider s = file.sliders[ int ( Hud_GetScriptID( panel ) ) ]
+
+ MS_Slider_SetValue( s, GetConVarFloat( c.conVar ) )
+ }
+ break
+ case "float2":
+ try
+ {
+ array<string> split = split( newSetting, " " )
+ if ( split.len() != 2 )
+ {
+ ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put in " + split.len() + "!" )
+ Hud_SetText( textPanel, GetConVarString( c.conVar ) )
+ break
+ }
+ vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 >
+
+ SetConVarString( c.conVar, newSetting )
+ }
+ catch ( ex )
+ {
+ ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" )
+ Hud_SetText( textPanel, GetConVarString( c.conVar ) )
+ }
+ break
+ // idk sometimes it's called Float3 most of the time it's called vector, I am not complaining.
+ case "vector":
+ case "float3":
+ try
+ {
+ array<string> split = split( newSetting, " " )
+ if ( split.len() != 3 )
+ {
+ ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put in " + split.len() + "!" )
+ Hud_SetText( textPanel, GetConVarString( c.conVar ) )
+ break
+ }
+ vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 >
+
+ SetConVarString( c.conVar, newSetting )
+ }
+ catch ( ex )
+ {
+ ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" )
+ Hud_SetText( textPanel, GetConVarString( c.conVar ) )
+ }
+ break
+ default:
+ SetConVarString( c.conVar, newSetting )
+ break;
+ }
+ }
+ else Hud_SetText( textPanel, Localize( c.values[ GetConVarInt( c.conVar ) ] ) )
+}
+
+void function ThrowInvalidValue( string desc )
+{
+ DialogData dialogData
+ dialogData.header = "Invalid Value"
+ dialogData.image = $"ui/menu/common/dialog_error"
+ dialogData.message = desc
+ AddDialogButton( dialogData, "#OK" )
+ OpenDialog( dialogData )
+}
+
+void function UpdateEnumSetting( var button )
+{
+ int scriptId = int( Hud_GetScriptID( Hud_GetParent( button ) ) )
+ ConVarData c = file.filteredList[ scriptId + file.scrollOffset ]
+
+ var panel = file.modPanels[ scriptId ]
+
+ var textPanel = Hud_GetChild( panel, "TextEntrySetting" )
+
+ string selectionVal = Hud_GetDialogListSelectionValue( button )
+
+ if ( selectionVal == "main" )
+ return
+
+ int enumVal = GetConVarInt( c.conVar )
+ if ( selectionVal == "next" ) // enum val += 1
+ enumVal = ( enumVal + 1 ) % c.values.len()
+ else // enum val -= 1
+ {
+ enumVal--
+ if ( enumVal == -1 )
+ enumVal = c.values.len() - 1
+ }
+
+ SetConVarInt( c.conVar, enumVal )
+ Hud_SetText( textPanel, c.values[ enumVal ] )
+
+ Hud_SetDialogListSelectionValue( button, "main" )
+}
+
+void function OnClearButtonPressed( var button )
+{
+ file.filterText = ""
+ Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" )
+
+ OnFiltersChange()
+}
+
+string function SanitizeDisplayName( string displayName )
+{
+ array<string> parts = split( displayName, "^" )
+ string result = ""
+ if ( parts.len() == 1 )
+ return parts[0]
+ foreach ( string p in parts )
+ {
+ if ( p == "" )
+ {
+ result += "^"
+ continue
+ }
+ int i = 0
+ for ( i = 0; i < 8 && i < p.len(); i++ )
+ {
+ var c = p[i]
+ if ( ( c < 'a' || c > 'f' ) && ( c < 'A' || c > 'F' ) && ( c < '0' || c > '9' ) )
+ break
+ }
+ if ( i == 0 )
+ result += p
+ else result += p.slice( i, p.len() )
+ }
+ return result
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut
new file mode 100644
index 00000000..33a79cdc
--- /dev/null
+++ b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut
@@ -0,0 +1,52 @@
+// ModSettings_Slider
+// since we are missing some utility functions (e.g. GetMax, GetMin, SetValue), this is basically a collection of workarounds.
+global struct MS_Slider
+{
+ var slider
+ float min = 0.0
+ float max = 1.0
+ float stepSize = 0.05
+}
+
+globalize_all_functions
+
+MS_Slider function MS_Slider_Setup( var slider, float min = 0.0, float max = 1.0, float startVal = 0.0, float stepSize = 0.05 )
+{
+ MS_Slider result
+ result.slider = slider
+ result.min = min
+ result.max = max
+ result.stepSize = stepSize
+ Hud_SliderControl_SetMin( slider, startVal )
+ Hud_SliderControl_SetMax( slider, startVal )
+ Hud_SliderControl_SetStepSize( slider, stepSize )
+ Hud_SliderControl_SetMin( slider, min )
+ Hud_SliderControl_SetMax( slider, max )
+ return result
+}
+
+void function MS_Slider_SetValue( MS_Slider slider, float val )
+{
+ Hud_SliderControl_SetMin( slider.slider, val )
+ Hud_SliderControl_SetMax( slider.slider, val )
+ Hud_SliderControl_SetMin( slider.slider, slider.min )
+ Hud_SliderControl_SetMax( slider.slider, slider.max )
+}
+
+void function MS_Slider_SetMin( MS_Slider slider, float min )
+{
+ slider.min = min
+ Hud_SliderControl_SetMin( slider.slider, min )
+}
+
+void function MS_Slider_SetMax( MS_Slider slider, float max )
+{
+ slider.max = max
+ Hud_SliderControl_SetMax( slider.slider, max )
+}
+
+void function MS_Slider_SetStepSize( MS_Slider slider, float stepSize )
+{
+ slider.stepSize = stepSize
+ Hud_SliderControl_SetStepSize( slider.slider, stepSize )
+}
diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
index 53d85387..eef19b5e 100644
--- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
+++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut
@@ -101,6 +101,10 @@ void function InitMainMenuPanel()
var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" )
Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) )
#endif
+
+ // MOD SETTINGS
+ var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" )
+ Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) )
var spotlightLargeButton = Hud_GetChild( file.spotlightPanel, "SpotlightLarge" )
spotlightLargeButton.SetNavLeft( file.spButtons[0] )