Track LocalMods as part of monolith

This commit is contained in:
2026-06-08 18:50:16 +03:00
parent 143f2fed7c
commit 1b214b44c2
1287 changed files with 139255 additions and 1 deletions
@@ -0,0 +1,56 @@
-- why barotrauma's GUI libraries don't have this implemented by default? this is stupid
local function updateServerMessageScrollBasedOnCaret(textBox, listBox)
local caretY = textBox.CaretScreenPos.Y
local bottomCaretExtent = textBox.Font.LineHeight * 1.5
local topCaretExtent = -textBox.Font.LineHeight * 0.5
if caretY + bottomCaretExtent > listBox.Rect.Bottom then
listBox.ScrollBar.BarScroll = (caretY - textBox.Rect.Top - listBox.Rect.Height + bottomCaretExtent)
/ (textBox.Rect.Height - listBox.Rect.Height)
elseif caretY + topCaretExtent < listBox.Rect.Top then
listBox.ScrollBar.BarScroll = (caretY - textBox.Rect.Top + topCaretExtent)
/ (textBox.Rect.Height - listBox.Rect.Height)
end
end
local function CreateMultiLineTextBox(rectransform, text, size)
local multineListBox = GUI.ListBox(GUI.RectTransform(Vector2(1, size or 0.2), rectransform))
local textBox = GUI.TextBox(
GUI.RectTransform(Vector2(1, 1), multineListBox.Content.RectTransform),
text,
nil,
nil,
nil,
true,
"GUITextBoxNoBorder"
)
textBox.add_OnSelected(function()
updateServerMessageScrollBasedOnCaret(textBox, multineListBox)
end)
textBox.OnTextChangedDelegate = function()
local textSize = textBox.Font.MeasureString(textBox.WrappedText)
textBox.RectTransform.NonScaledSize =
Point(textBox.RectTransform.NonScaledSize.X, math.max(multineListBox.Content.Rect.Height, textSize.Y + 10))
multineListBox.UpdateScrollBarSize()
return true
end
textBox.OnEnterPressed = function()
local str = textBox.Text
local caretIndex = textBox.CaretIndex
textBox.Text = str:sub(1, caretIndex) .. "\n" .. str:sub(caretIndex + 1)
textBox.CaretIndex = caretIndex + 1
return true
end
return textBox
end
return CreateMultiLineTextBox
+580
View File
@@ -0,0 +1,580 @@
--easysettings by Evil Factory
local easySettings = dofile(NT.Path .. "/Lua/Scripts/Client/easysettings.lua")
local MultiLineTextBox = dofile(NT.Path .. "/Lua/Scripts/Client/MultiLineTextBox.lua")
local GUIComponent = LuaUserData.CreateStatic("Barotrauma.GUIComponent")
local configUI
local BaseConfigPages = {
{ name = "Item Prices", key = "prices" },
{ name = "Item Availability", key = "availability" },
}
-- Did you know the default background colour is not true black?
local Transparent = Color(2, 2, 2)
-- Barotrauma beige
local DefaultTextColour = Color(210, 200, 154)
local ExpansionNameForUI = {}
local function CommaStringToTable(str)
local tbl = {}
for word in string.gmatch(str, "([^,]+)") do
table.insert(tbl, word)
end
return tbl
end
-- Function that autofills the addon dropdown
-- We also automatically make the UI display the names as "NT [mod]" to match their Content Package / Steam Workhop name to minimise confusion.
local function PopulateDropdown(dropdown)
ExpansionNameForUI = {}
-- Goofy but it works!
-- Ensure Neurotrauma is on top by just loading it first
for _, expansion in ipairs(NTConfig.Expansions) do
if expansion.Name == "Neurotrauma" then
local name = tostring(expansion.Name)
local uiName = name
table.insert(ExpansionNameForUI, { uiName, name, type = "expansion" })
dropdown.AddItem(uiName)
end
end
-- Then get all the base pages (expansion proof!)
for _, page in ipairs(BaseConfigPages) do
table.insert(ExpansionNameForUI, { page.name, page.key, type = "page" })
dropdown.AddItem(page.name)
end
-- Then dump all other expansions in there
for _, expansion in ipairs(NTConfig.Expansions) do
if expansion.Name ~= "Neurotrauma" then
local name = tostring(expansion.Name)
-- First, we make the UI Name the same as their expansion name
local uiName = name
-- Add NT at the front if it does not already have that
if not string.find(uiName, "^NT%s") then uiName = "NT " .. uiName end
-- Add them to a lookup table for later
table.insert(ExpansionNameForUI, { uiName, name, type = "expansion" })
-- Finally, add it to the dropdown menu
dropdown.AddItem(uiName)
end
end
end
-- TODO: Readd the difficulty calculation I kinda dont care about it right now so it can fuck off
-- Function to determine how the layout should be structured
local function PrebuildConfigLayout(entries, selectedExpansion)
-- This table will contain subtables that determine how the ConstructUI function actually 'constructs' the UI.
-- These chunks can be gone over using Ipairs to ensure the order is correct (a previous test made unrelated settings render together)
local LayoutChunks = {}
local CurrentGroup = nil
local lastType = nil
local selectedKey = nil
local selectedType = nil
-- Grab actual expansion name based on their UIName
for _, uiEntry in ipairs(ExpansionNameForUI) do
if uiEntry[1] == selectedExpansion then
selectedKey = uiEntry[2]
selectedType = uiEntry.type
break
end
end
for key, entry in pairs(entries) do
if selectedType == "page" then
-- Get entries with this page set
if not entry.page or entry.page ~= selectedKey then goto continue end
elseif selectedType == "expansion" then
-- Get expansion entries that do NOT have a page set (so other expansion can force their price changes into the combined page, for example)
if entry.expansion ~= selectedKey or entry.page ~= nil then goto continue end
end
-- Automatically add some white space between unique item types to prevent bleeding
if entry.type ~= lastType and lastType ~= nil then table.insert(LayoutChunks, { type = "spacer" }) end
lastType = entry.type
-- Categories are always standalone and should be put above the settings they govern
-- Interrupt a group if it exists
if entry.type == "category" then
CurrentGroup = nil
table.insert(LayoutChunks, { type = "category", entry = entry })
-- Floats / Strings until now were just using up way too much screen space. We want to put these into a LayoutGroup together to maximise screen usage.
-- If entries have 'group=true', then all entries of the same type that follow one another will be grouped together. If there are other entry types (like categories) in-between, they will not.
-- This prevents unrelated settings from merging together + adds reverse-compat
elseif entry.type == "float" and entry.group then
-- Make a group and keep adding config entries that come after this as long as the criteria stands
if not CurrentGroup or CurrentGroup.type ~= "float_group" then
CurrentGroup = { type = "float_group", items = {} }
table.insert(LayoutChunks, CurrentGroup)
end
table.insert(CurrentGroup.items, { key = key, entry = entry })
elseif entry.type == "string" and entry.group then
if not CurrentGroup or CurrentGroup.type ~= "string_group" then
CurrentGroup = { type = "string_group", items = {} }
table.insert(LayoutChunks, CurrentGroup)
end
table.insert(CurrentGroup.items, { key = key, entry = entry })
-- Anything else is anything that shouldn't be grouped. Interrupt a group if it exists and add the setting as standalone.
else
CurrentGroup = nil
table.insert(LayoutChunks, { type = "standalone", key = key, entry = entry })
end
::continue::
end
return LayoutChunks
end
local function PopulateSettingsIntoUI(list, selectedExpansion)
list.Content:ClearChildren()
-- Infotext (should always be shown)
local tb_BasicConfigInfo = GUI.TextBlock(
GUI.RectTransform(Vector2(1, 0.1), list.Content.RectTransform),
"Server config can be changed by owner or a client with manage settings permission. If the server doesn't allow writing into the config folder, then it must be edited manually.",
DefaultTextColour,
nil,
GUI.Alignment.Center,
true,
nil,
Transparent
)
-- Prevent textblocks from lighting up the background when clicked / changing the cursor on hover.
tb_BasicConfigInfo.CanBeFocused = false
local LayoutChunks = PrebuildConfigLayout(NTConfig.Entries, selectedExpansion)
-- Go over the pre-generated Layout table and construct settings procedurally
for _, chunk in ipairs(LayoutChunks) do
-- Categories
if chunk.type == "category" then
local tb_ProceduralCategoryHeader = GUI.TextBlock(
GUI.RectTransform(Vector2(1, 0.09), list.Content.RectTransform),
chunk.entry.name,
DefaultTextColour,
GUI.GUIStyle.LargeFont,
GUI.Alignment.BottomCenter,
true,
nil,
Transparent
)
tb_ProceduralCategoryHeader.CanBeFocused = false
-- Standalone items
elseif chunk.type == "standalone" then
local key = chunk.key
local entry = chunk.entry
-- Ungrouped float
if entry.type == "float" then
local minrange = (entry.range and entry.range[1]) or ""
-- This is fucking stupid. If the default value is the same as the minimum value of a scalar, it bugs and displays 0.
-- So, we set the minimum to 0.99 and just render it like it were 1
if minrange == 0.99 then minrange = 1 end
local maxrange = (entry.range and entry.range[2]) or ""
local rect = GUI.RectTransform(Vector2(1, 0.04), list.Content.RectTransform)
local tb_EntryInformation = GUI.TextBlock(
rect,
entry.name .. " (" .. minrange .. "-" .. maxrange .. ")",
DefaultTextColour,
nil,
GUI.Alignment.Center,
true,
nil,
Transparent
)
tb_EntryInformation.CanBeFocused = false
if entry.description then tb_EntryInformation.ToolTip = entry.description end
local scalar =
GUI.NumberInput(GUI.RectTransform(Vector2(1, 0.08), list.Content.RectTransform), NumberType.Float)
scalar.valueStep = 0.1
scalar.MinValueFloat = entry.range and entry.range[1] or 0
scalar.MaxValueFloat = entry.range and entry.range[2] or 100
scalar.FloatValue = NTConfig.Get(key, 1)
scalar.OnValueChanged = function()
NTConfig.Set(key, scalar.FloatValue)
end
-- Bool
elseif entry.type == "bool" then
local rect = GUI.RectTransform(Vector2(0.5, 1), list.Content.RectTransform)
local toggle = GUI.TickBox(rect, entry.name)
if entry.description then toggle.ToolTip = entry.description end
toggle.Selected = NTConfig.Get(key, false)
toggle.OnSelected = function()
NTConfig.Set(key, toggle.State == GUIComponent.ComponentState.Selected)
end
-- String (a textblock to input)
elseif entry.type == "string" then
local style = ""
if entry.style ~= nil then style = " (" .. entry.style .. ")" end
local rect = GUI.RectTransform(Vector2(1, 0.05), list.Content.RectTransform)
local tb_StringInformation = GUI.TextBlock(
rect,
entry.name .. style,
DefaultTextColour,
nil,
GUI.Alignment.Center,
true,
nil,
Transparent
)
-- By default, don't change cursor on hovering
tb_StringInformation.CanBeFocused = false
-- If there's a tooltip, set it and re-enable hovering
if entry.description then
tb_StringInformation.ToolTip = entry.description
tb_StringInformation.CanBeFocused = true
end
local stringinput
-- Make MultiLineTextBox the default, but now allow normal ones too. A single line entry does not need a multi-line textblock.
if entry.noMLTB == true then
stringinput = GUI.TextBox(
GUI.RectTransform(Vector2(1, entry.boxsize), list.Content.RectTransform),
"",
nil,
nil,
nil,
true
)
else
stringinput = MultiLineTextBox(list.Content.RectTransform, "", entry.boxsize)
end
stringinput.Text = table.concat(entry.value, ",")
stringinput.OnTextChangedDelegate = function(textBox)
entry.value = CommaStringToTable(textBox.Text)
end
end
-- Auto-added empty space
elseif chunk.type == "spacer" then
GUI.LayoutGroup(GUI.RectTransform(Vector2(1, 0.02), list.Content.RectTransform), false)
-- Grouped Floats
elseif chunk.type == "float_group" then
local MaxPerRow = 2
local row = nil
local count = 0
for _, item in ipairs(chunk.items) do
-- Make a new LayoutGroup to add entries into everytime the MaxPerRow is hit (default of 2)
if not row or (count % MaxPerRow == 0) then
row = GUI.LayoutGroup(GUI.RectTransform(Vector2(1, 0.09), list.Content.RectTransform), true)
end
-- Safety check!
if not row then return end
-- This determines how the space in the UI is used, tied together to make fucking around a bit easier
row.RelativeSpacing = 0.01
local Text_space = 0.53
local Scalar_space = 0.30
local Reset_space = 0.07
local baseWidth = 1 / MaxPerRow
local textcellwidth = baseWidth * Text_space
local scalarcellwidth = baseWidth * Scalar_space
local resetcellwidth = baseWidth * Reset_space
local key = item.key
local entry = item.entry
local resetButton
-- Make each subdivided part of the group their own
-- Part of the group that holds text
local textcell = GUI.LayoutGroup(GUI.RectTransform(Vector2(textcellwidth, 1), row.RectTransform), false)
-- Part of the group that holds the numberinput box
local scalarcell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(scalarcellwidth, 1), row.RectTransform), false)
-- In case a reset button is set
local resetbuttoncell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(resetcellwidth, 0.59), row.RectTransform), false)
-- Relativespacing but larger space for the center instead of everywhere
local additionalspacecell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(resetcellwidth, 0.59), row.RectTransform), false)
local minrange = entry.range and entry.range[1] or ""
if minrange == 0.99 then minrange = 1 end
local maxrange = entry.range and entry.range[2] or ""
local tb_EntryInformation = GUI.TextBlock(
GUI.RectTransform(Vector2(1, 0.7), textcell.RectTransform),
entry.name .. " (" .. minrange .. "-" .. maxrange .. ")",
DefaultTextColour,
nil,
GUI.Alignment.Center,
true,
nil,
Transparent
)
tb_EntryInformation.CanBeFocused = false
local scalar =
GUI.NumberInput(GUI.RectTransform(Vector2(1, 0.6), scalarcell.RectTransform), NumberType.Float)
scalar.PlusButton.RectTransform.RelativeSize = Vector2(1, 0.5)
scalar.MinusButton.RectTransform.RelativeSize = Vector2(1, 0.5)
scalar.valueStep = 0.1
scalar.MinValueFloat = entry.range and entry.range[1] or 0
scalar.MaxValueFloat = entry.range and entry.range[2] or 100
scalar.FloatValue = NTConfig.Get(key, 1)
scalar.OnValueChanged = function()
NTConfig.Set(key, scalar.FloatValue)
end
-- Leftover space in the Row goes to the reset button if enabled
if entry.resettable then
resetButton = GUI.Button(
GUI.RectTransform(Vector2(1, 1), resetbuttoncell.RectTransform, GUI.Anchor.BottomLeft),
GUI.Alignment.BottomLeft,
nil,
Transparent
)
-- Give the reset button a sprite that matches its function (yoinked from basegame)
local resetButtonStyle =
GUI.Image(GUI.RectTransform(Vector2(1, 1), resetButton.RectTransform), "GUIButtonRefresh")
resetButtonStyle.ToolTip = "Reset to default"
-- On button press, fetch default value.
resetButton.OnClicked = function()
local defaultValue = entry.default
scalar.FloatValue = defaultValue
NTConfig.Set(key, defaultValue)
end
end
count = count + 1
end
-- Grouped Strings
elseif chunk.type == "string_group" then
local MaxPerRow = 2
local row = nil
local count = 0
for _, item in ipairs(chunk.items) do
-- Make a new LayoutGroup to add entries into everytime the MaxPerRow is hit (default of 2)
if not row or (count % MaxPerRow == 0) then
row = GUI.LayoutGroup(GUI.RectTransform(Vector2(1, 0.09), list.Content.RectTransform), true)
end
-- Safety check!
if not row then return end
row.RelativeSpacing = 0.01
local Text_space = 0.50
-- Any less than 0.33 per string and the max value (255,255,255) or 3 digits per value will bleed (at 1920 * 1080 default)
local String_space = 0.33
local Reset_space = 0.07
local baseWidth = 1 / MaxPerRow
local textcellwidth = baseWidth * Text_space
local scalarcellwidth = baseWidth * String_space
local resetcellwidth = baseWidth * Reset_space
local key = item.key
local entry = item.entry
local resetButton
-- Make each subdivided part of the group their own
-- Part of the group that holds text
local textcell = GUI.LayoutGroup(GUI.RectTransform(Vector2(textcellwidth, 1), row.RectTransform), false)
-- Part of the group that holds the input box
local stringinputcell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(scalarcellwidth, 1), row.RectTransform), false)
-- In case a reset button is set
local resetbuttoncell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(resetcellwidth, 0.45), row.RectTransform), false)
-- Relativespacing but larger space for the center instead of everywhere
local additionalspacecell =
GUI.LayoutGroup(GUI.RectTransform(Vector2(resetcellwidth, 0.59), row.RectTransform), false)
local style = ""
if entry.style ~= nil then style = " (" .. entry.style .. ")" end
local tb_StringInformation = GUI.TextBlock(
GUI.RectTransform(Vector2(1, 0.4), textcell.RectTransform),
entry.name .. style,
DefaultTextColour,
nil,
GUI.Alignment.Center,
true,
nil,
Transparent
)
tb_StringInformation.CanBeFocused = false
if entry.description then
tb_StringInformation.ToolTip = entry.description
tb_StringInformation.CanBeFocused = true
end
local stringinput
-- Not all strings need a MultiLineTextBox, especially since they can just yoink the mouse cursor while scrolling.
-- Make MLTB's a toggleable option
if entry.noMLTB == true then
stringinput = GUI.TextBox(
GUI.RectTransform(
Vector2(1, entry.boxsize),
stringinputcell.RectTransform,
GUI.Anchor.CenterLeft
),
"",
nil,
nil,
nil,
true
)
else
stringinput = MultiLineTextBox(stringinputcell.RectTransform, "", entry.boxsize)
end
stringinput.Text = table.concat(entry.value, ",")
stringinput.OnTextChangedDelegate = function(textBox)
entry.value = CommaStringToTable(textBox.Text)
end
-- Leftover space in the Row goes to the reset button if enabled
if entry.resettable then
resetButton = GUI.Button(
GUI.RectTransform(Vector2(1, 1), resetbuttoncell.RectTransform),
GUI.Alignment.CenterRight,
nil,
Transparent
)
-- Give the reset button a sprite that matches its function (yoinked from basegame)
local resetButtonStyle =
GUI.Image(GUI.RectTransform(Vector2(1, 1), resetButton.RectTransform), "GUIButtonRefresh")
resetButtonStyle.ToolTip = "Reset to default"
-- On button press, fetch default value.
resetButton.OnClicked = function()
entry.value = entry.default
stringinput.Text = table.concat(entry.value, ",")
end
end
count = count + 1
end
end
end
if Game.IsMultiplayer and not Game.Client.HasPermission(ClientPermissions.ManageSettings) then
for guicomponent in list.GetAllChildren() do
guicomponent.enabled = false
end
end
return list
end
-- Base UI construction
local function ConstructUI(parent)
-- Set the default to display (Neurotrauma, duh)
local selectedExpansion = BaseConfigPages[1].name
local list = easySettings.BasicList(parent)
-- Get the Title block to put the drop down menu into (could be moved tbh)
local innerLayout = list.Parent
local children = innerLayout.RectTransform.Children
local title = children[1].GUIComponent
-- Get the amount of loaded expansions + seperate pages
local dropdownheight = #NTConfig.Expansions + #BaseConfigPages
-- Don't show the dropdown if we only have Neurotrauma or no other addons that have settings to show
if dropdownheight > 1 then
local dropdown_AddonSelection = GUI.DropDown(
GUI.RectTransform(Vector2(0.18, 1), title.RectTransform),
"",
dropdownheight - 2,
nil,
false,
false,
GUI.Alignment.CenterLeft
)
dropdown_AddonSelection.ListBox.RectTransform.RelativeOffset = (Vector2(0, 0.5))
PopulateDropdown(dropdown_AddonSelection)
dropdown_AddonSelection.Select(0)
selectedExpansion = dropdown_AddonSelection.Text
dropdown_AddonSelection.ToolTip = "Choose which mod's settings to display."
-- Using the dropdown changes a variable so we can change the page accordingly; only do so if we're not already on that page
dropdown_AddonSelection.OnSelected = function(guiComponent)
local newSelection = tostring(guiComponent.Text)
-- Check if changed
if newSelection == selectedExpansion then return end
selectedExpansion = newSelection
-- Redo content based on new selection
PopulateSettingsIntoUI(list, selectedExpansion)
end
end
-- Default
PopulateSettingsIntoUI(list, selectedExpansion)
end
Networking.Receive("NT.ConfigUpdate", function(msg)
NTConfig.ReceiveConfig(msg)
if configUI == nil then return end
if configUI.RectTransform == nil then return end
local parent = configUI.RectTransform.Parent
configUI = nil
configUI = ConstructUI(parent)
end)
easySettings.AddMenu("Neurotrauma", function(parent)
if Game.IsMultiplayer then
local msg = Networking.Start("NT.ConfigRequest")
Networking.Send(msg)
end
configUI = ConstructUI(parent)
end)
+114
View File
@@ -0,0 +1,114 @@
local _Int32 = LuaUserData.RegisterType("System.Int32")
-- Stack specific items together; if you want only the left leg to be cheaper than a right one go fuck yourself
local ItemVariants = {
antibloodloss2 = "NT_ItemPrice_bloodpacks",
bloodpackoplus = "NT_ItemPrice_bloodpacks",
bloodpackaminus = "NT_ItemPrice_bloodpacks",
bloodpackaplus = "NT_ItemPrice_bloodpacks",
bloodpackbminus = "NT_ItemPrice_bloodpacks",
bloodpackbplus = "NT_ItemPrice_bloodpacks",
bloodpackabminus = "NT_ItemPrice_bloodpacks",
bloodpackabplus = "NT_ItemPrice_bloodpacks",
rarm = "NT_ItemPrice_arms",
larm = "NT_ItemPrice_arms",
rleg = "NT_ItemPrice_legs",
lleg = "NT_ItemPrice_legs",
rarmp = "NT_ItemPrice_bionicarms",
larmp = "NT_ItemPrice_bionicarms",
rlegp = "NT_ItemPrice_bioniclegs",
llegp = "NT_ItemPrice_bioniclegs",
}
-- Fetch config multipliers
local function GetItemMultiplier(identifier)
if identifier == nil then return 1.0 end
-- Add grouping so blood bags don't fucking kill me
local configKey = ItemVariants[identifier] or ("NT_ItemPrice_" .. identifier)
if NTConfig.Entries[configKey] == nil then return 1.0 end
local value = NTConfig.Get(configKey, 1.0)
return tonumber(value) or 1.0
end
-- PRICE CHANGING
-- Hook into the price-determining function and add a multiplier
Hook.Patch("Barotrauma.Location+StoreInfo", "GetAdjustedItemBuyPrice", function(instance, ptable)
local item = ptable["item"]
if item == nil or item.Identifier == nil then return end
local id = item.Identifier.Value
local mult = GetItemMultiplier(id)
-- Don't do extra math if the item value is unchanged
if mult == 1.0 then return end
-- Get the 'actual price' after the game is done with it's calculations
local base = ptable.OriginalReturnValue
if base == nil then return end
-- Apply config-determined multiplier
local result = math.floor(base * mult + 0.5)
ptable.ReturnValue = LuaUserData.CreateUserDataFromDescriptor(result, _Int32)
end, Hook.HookMethodType.After)
-- FABRICATOR CHANGES
-- You cannot fabricate the item; this is accomplished by taking the Filter that gets made whenever you open a fabricator, and hiding the specific item IDs we want to hide.
local fabricatorType = LuaUserData.RegisterType("Barotrauma.Items.Components.Fabricator")
LuaUserData.MakeFieldAccessible(fabricatorType, "itemList")
Hook.Patch("Barotrauma.Items.Components.Fabricator", "FilterEntities", function(instance, ptable)
Timer.Wait(function()
local blockedItems = HF.DynamicUnavailableItems()
for child in instance.itemList.Content.Children do
local recipe = child.UserData
if recipe and LuaUserData.IsTargetType(recipe, "Barotrauma.FabricationRecipe") then
local id = recipe.TargetItem.Identifier.Value
if blockedItems[id] then child.Visible = false end
end
end
end, 1)
end, Hook.HookMethodType.After)
-- STORE CHANGES
-- You cannot buy the item; we simply hook into store availability and hide the item.
-- Ensure the items CANNOT be specials.
local storeType = LuaUserData.RegisterType("Barotrauma.Store")
LuaUserData.MakeFieldAccessible(storeType, "storeBuyList")
LuaUserData.MakeFieldAccessible(storeType, "storeDailySpecialsGroup")
Hook.Patch("Barotrauma.Store", "FilterStoreItems", {
"Barotrauma.MapEntityCategory",
"System.String",
}, function(instance, ptable)
Timer.Wait(function()
-- Fetch items to hide
local blockedItems = HF.DynamicUnavailableItems()
local storeList = instance.storeBuyList
if storeList then
for child in storeList.Content.Children do
local item = child.UserData
if item and item.ItemPrefab then
local id = item.ItemPrefab.Identifier.Value
-- Hide items within the table every refresh
if blockedItems[id] then child.Visible = false end
end
end
end
end, 10)
end, Hook.HookMethodType.After)
-- Force config sync on level swap to ensure things go properly
Hook.Add("roundStart", "forcesyncconfig", function()
if Game.IsMultiplayer then
local msg = Networking.Start("NT.ConfigRequest")
Networking.Send(msg)
end
end)
+209
View File
@@ -0,0 +1,209 @@
-- Original code by Evil Factory,
-- Adapted for Neurotrauma
local easySettings = {}
easySettings.Settings = {}
local GUIComponent = LuaUserData.CreateStatic("Barotrauma.GUIComponent")
local function GetChildren(comp)
local tbl = {}
for value in comp.GetAllChildren() do
table.insert(tbl, value)
end
return tbl
end
easySettings.SaveTable = function(path, tbl)
File.Write(path, json.serialize(tbl))
end
easySettings.LoadTable = function(path)
if not File.Exists(path) then return {} end
return json.parse(File.Read(path))
end
easySettings.AddMenu = function(name, onOpen)
table.insert(easySettings.Settings, { Name = name, OnOpen = onOpen })
end
-- Overhauled Config GUI
easySettings.BasicList = function(parent, size)
-- Menu Frame
local menuContent =
GUI.Frame(GUI.RectTransform(size or Vector2(0.5, 0.8), parent.RectTransform, GUI.Anchor.Center), "GUIFrame")
-- Main Layout
local mainLayout = GUI.LayoutGroup(
GUI.RectTransform(Vector2(0.95, 0.95), menuContent.RectTransform, GUI.Anchor.Center, GUI.Pivot.Center),
false
)
-- Background
local configBackground = GUI.Frame(GUI.RectTransform(Vector2(1, 0.95), mainLayout.RectTransform), "InnerFrame")
-- Shrink Inner layout
local innerLayout = GUI.LayoutGroup(
GUI.RectTransform(Vector2(0.95, 0.95), configBackground.RectTransform, GUI.Anchor.TopCenter),
false
)
-- Title block
local title = GUI.TextBlock(
GUI.RectTransform(Vector2(1, 0.07), innerLayout.RectTransform),
"Neurotrauma Config Settings",
nil,
GUI.GUIStyle.LargeFont
)
title.TextAlignment = GUI.Alignment.TopCenter
-- Setting list
local menuList = GUI.ListBox(GUI.RectTransform(Vector2(1, 0.97), innerLayout.RectTransform))
menuList.Padding = Vector4(10, 15, 10, 10)
menuList.UpdateDimensions()
-- Button row
local buttonRow = GUI.LayoutGroup(GUI.RectTransform(Vector2(1, 0.1), mainLayout.RectTransform), true)
buttonRow.RelativeSpacing = 0.02
easySettings.SaveButton(buttonRow)
easySettings.CloseButton(buttonRow)
easySettings.ResetButton(buttonRow)
return menuList
end
-- Function for a Tickbox
easySettings.TickBox = function(parent, text, onSelected, state)
if state == nil then state = true end
local tickBox = GUI.TickBox(GUI.RectTransform(Vector2(1, 0.2), parent.RectTransform), text)
tickBox.Selected = state
tickBox.OnSelected = function()
onSelected(tickBox.State == GUIComponent.ComponentState.Selected)
end
return tickBox
end
-- Function for a Slider
easySettings.Slider = function(parent, min, max, onSelected, value)
local scrollBar = GUI.ScrollBar(GUI.RectTransform(Vector2(1, 0.1), parent.RectTransform), 0.1, nil, "GUISlider")
scrollBar.Range = Vector2(min, max)
scrollBar.BarScrollValue = value or max / 2
scrollBar.OnMoved = function()
onSelected(scrollBar.BarScrollValue)
end
return scrollBar
end
-- Function for the Save and Exit button
easySettings.SaveButton = function(parent)
local button = GUI.Button(
GUI.RectTransform(Vector2(0.32, 0.05), parent.RectTransform, GUI.Anchor.BottomLeft),
"Save and Exit",
GUI.Alignment.Center,
"GUIButton"
)
button.OnClicked = function()
if Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings) then
NTConfig.SendConfig()
elseif Game.IsSingleplayer then
NTConfig.SaveConfig()
end
GUI.GUI.TogglePauseMenu()
end
return button
end
-- Function for the Discard and Exit button
easySettings.CloseButton = function(parent)
local button = GUI.Button(
GUI.RectTransform(Vector2(0.32, 0.05), parent.RectTransform, GUI.Anchor.BottomCenter),
"Discard and Exit",
GUI.Alignment.Center,
"GUIButton"
)
button.OnClicked = function()
GUI.GUI.TogglePauseMenu()
NTConfig.LoadConfig()
end
return button
end
-- Function for the Reset and Exit button
easySettings.ResetButton = function(parent)
local button = GUI.Button(
GUI.RectTransform(Vector2(0.32, 0.05), parent.RectTransform, GUI.Anchor.BottomRight),
"Reset Config",
GUI.Alignment.Center,
"GUIButton"
)
button.OnClicked = function()
if
Game.IsSingleplayer or (Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings))
then
easySettings.ResetMessage(parent)
end
end
return button
end
-- Confirmation popup for config reset
easySettings.ResetMessage = function(parent)
local ResetMessage = GUI.MessageBox(
"Reset neurotrauma settings",
"Are you sure you want to reset neurotrauma settings to default values?",
{ "Yes", "No" }
)
ResetMessage.DrawOnTop = true
ResetMessage.Text.TextAlignment = GUI.Alignment.Center
ResetMessage.Buttons[1].OnClicked = function()
NTConfig.ResetConfig()
if Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings) then
NTConfig.SendConfig()
elseif Game.IsSingleplayer then
NTConfig.SaveConfig()
end
GUI.GUI.TogglePauseMenu()
ResetMessage.Close()
end
ResetMessage.Buttons[2].OnClicked = function()
ResetMessage.Close()
end
return ResetMessage
end
-- Add button on pause menu for NT Settings
Hook.Patch("Barotrauma.GUI", "TogglePauseMenu", {}, function()
if GUI.GUI.PauseMenuOpen then
local frame = GUI.GUI.PauseMenu
local list = GetChildren(GetChildren(frame)[2])[1]
for key, value in pairs(easySettings.Settings) do
local PauseMenuButton = GUI.Button(
GUI.RectTransform(Vector2(1, 0.1), list.RectTransform),
value.Name,
GUI.Alignment.Center,
"GUIButtonSmall"
)
PauseMenuButton.OnClicked = function()
value.OnOpen(frame)
end
end
end
end, Hook.HookMethodType.After)
return easySettings