diff --git a/vmf/gui/vmf/vmf_atlas.dds b/vmf/gui/vmf/vmf_atlas.dds index a085acd..a801211 100644 Binary files a/vmf/gui/vmf/vmf_atlas.dds and b/vmf/gui/vmf/vmf_atlas.dds differ diff --git a/vmf/localization/mutator_manager.lua b/vmf/localization/mutator_manager.lua deleted file mode 100644 index 6331bbe..0000000 --- a/vmf/localization/mutator_manager.lua +++ /dev/null @@ -1,78 +0,0 @@ -return { - easy = { - en = "Easy" - }, - normal = { - en = "Normal" - }, - hard = { - en = "Hard" - }, - harder = { - en = "Nightmare" - }, - hardest = { - en = "Cataclysm" - }, - survival_hard = { - en = "Veteran" - }, - survival_harder = { - en = "Champion" - }, - survival_hardest = { - en = "Heroic" - }, - - broadcast_enabled_mutators = { - en = "ENABLED MUTATORS" - }, - broadcast_all_disabled = { - en = "ALL MUTATORS DISABLED" - }, - broadcast_disabled_mutators = { - en = "MUTATORS DISABLED" - }, - local_disabled_mutators = { - en = "Mutators disabled" - }, - whisper_enabled_mutators = { - en = "[Automated message] This lobby has the following mutators active" - }, - - disabled_reason_not_server = { - en = "because you're no longer the host" - }, - disabled_reason_difficulty_change = { - en = "DUE TO CHANGE IN DIFFICULTY" - }, - - mutators_title = { - en = "Mutators" - }, - mutators_banner_tooltip = { - en = "Enable and disable mutators" - }, - no_mutators = { - en = "No mutators installed" - }, - no_mutators_tooltip = { - en = "Subscribe to mods and mutators on the workshop" - }, - - tooltip_supported_difficulty = { - en = "Supported difficulty levels" - }, - tooltip_incompatible_with_all = { - en = "Incompatible with all other mutators" - }, - tooltip_incompatible_with = { - en = "Incompatible with" - }, - tooltip_compatible_with_all = { - en = "Compatible with all other mutators" - }, - tooltip_will_be_disabled = { - en = "Will be disabled when Play is pressed" - } -} \ No newline at end of file diff --git a/vmf/localization/vmf.lua b/vmf/localization/vmf.lua index 36c470b..3c667be 100644 --- a/vmf/localization/vmf.lua +++ b/vmf/localization/vmf.lua @@ -187,4 +187,85 @@ return { en = "Developer console closed.", ru = "Консоль разработчика закрыта.", }, + + + -- MUTATORS + + + easy = { + en = "Easy" + }, + normal = { + en = "Normal" + }, + hard = { + en = "Hard" + }, + harder = { + en = "Nightmare" + }, + hardest = { + en = "Cataclysm" + }, + survival_hard = { + en = "Veteran" + }, + survival_harder = { + en = "Champion" + }, + survival_hardest = { + en = "Heroic" + }, + + broadcast_enabled_mutators = { + en = "ENABLED MUTATORS" + }, + broadcast_all_disabled = { + en = "ALL MUTATORS DISABLED" + }, + broadcast_disabled_mutators = { + en = "MUTATORS DISABLED" + }, + local_disabled_mutators = { + en = "Mutators disabled" + }, + whisper_enabled_mutators = { + en = "[Automated message] This lobby has the following mutators active" + }, + + disabled_reason_not_server = { + en = "because you're no longer the host" + }, + disabled_reason_difficulty_change = { + en = "DUE TO CHANGE IN DIFFICULTY" + }, + + mutators_title = { + en = "Mutators" + }, + mutators_banner_tooltip = { + en = "Enable and disable mutators" + }, + no_mutators = { + en = "No mutators installed" + }, + no_mutators_tooltip = { + en = "Subscribe to mods and mutators on the workshop" + }, + + tooltip_supported_difficulty = { + en = "Supported difficulty levels" + }, + tooltip_incompatible_with_all = { + en = "Incompatible with all other mutators" + }, + tooltip_incompatible_with = { + en = "Incompatible with" + }, + tooltip_compatible_with_all = { + en = "Compatible with all other mutators" + }, + tooltip_will_be_disabled = { + en = "Will be disabled when Play is pressed" + } } \ No newline at end of file diff --git a/vmf/materials/vmf/vmf_atlas.lua b/vmf/materials/vmf/vmf_atlas.lua index f5eab19..f206505 100644 --- a/vmf/materials/vmf/vmf_atlas.lua +++ b/vmf/materials/vmf/vmf_atlas.lua @@ -1,33 +1,38 @@ --- Image Source: ../test +-- Image Source: return { header_fav_arrow = { size = { 48, 48, }, - uv00 = { 0.187500, 0.687500, }, - uv11 = { 0.375000, 0.875000, }, + uv00 = { 0.181641, 0.880859, }, + uv11 = { 0.228516, 0.974609, }, }, header_fav_icon = { size = { 48, 48, }, - uv00 = { 0.187500, 0.500000, }, - uv11 = { 0.375000, 0.687500, }, - }, - search_bar_icon = { - size = { 48, 48, }, - uv00 = { 0.000000, 0.687500, }, - uv11 = { 0.187500, 0.875000, }, + uv00 = { 0.130859, 0.880859, }, + uv11 = { 0.177734, 0.974609, }, }, header_fav_icon_lit = { size = { 48, 48, }, - uv00 = { 0.000000, 0.500000, }, - uv11 = { 0.187500, 0.687500, }, + uv00 = { 0.052734, 0.880859, }, + uv11 = { 0.099609, 0.974609, }, }, - mutator_button = { - size = { 128, 128, }, - uv00 = { 0.500000, 0.000000, }, - uv11 = { 1.000000, 0.500000, }, + search_bar_icon = { + size = { 48, 48, }, + uv00 = { 0.001953, 0.880859, }, + uv11 = { 0.048828, 0.974609, }, }, - mutator_button_hover = { + map_view_party_button = { size = { 128, 128, }, - uv00 = { 0.000000, 0.000000, }, - uv11 = { 0.500000, 0.500000, }, + uv00 = { 0.130859, 0.623047, }, + uv11 = { 0.255859, 0.873047, }, + }, + map_view_party_button_lit = { + size = { 128, 128, }, + uv00 = { 0.001953, 0.623047, }, + uv11 = { 0.126953, 0.873047, }, + }, + map_view_mutators_area = { + size = { 547, 313, }, + uv00 = { 0.001953, 0.003906, }, + uv11 = { 0.536133, 0.615234, }, }, } diff --git a/vmf/resource_packages/vmf.package b/vmf/resource_packages/vmf.package index f963a6e..a762ebf 100644 --- a/vmf/resource_packages/vmf.package +++ b/vmf/resource_packages/vmf.package @@ -14,7 +14,6 @@ lua = [ "localization/*" "scripts/mods/vmf/*" - "scripts/mods/vmf/functions/*" "scripts/mods/vmf/modules/*" "scripts/mods/vmf/modules/core/*" "scripts/mods/vmf/modules/debug/*" @@ -22,6 +21,7 @@ lua = [ "scripts/mods/vmf/modules/ui/options/*" "scripts/mods/vmf/modules/ui/chat/*" "scripts/mods/vmf/modules/ui/mutators/*" + "scripts/mods/vmf/modules/ui/mutators/test/*" "materials/vmf/vmf_atlas" ] \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/functions/table.lua b/vmf/scripts/mods/vmf/functions/table.lua deleted file mode 100644 index f4464b2..0000000 --- a/vmf/scripts/mods/vmf/functions/table.lua +++ /dev/null @@ -1,176 +0,0 @@ -table.pack = function(...) - return { n = select("#", ...); ... } -end - -table.combine = function(a, b) - local r = {unpack(a)} - - for i = 1, #b do - r[#a + i] = b[i] - end - - return r; -end - --- Check item exist in table -table.has_item = function(tbl, item) - for _, value in ipairs(tbl) do - if value == item then - return true - end - end - return false -end - -table.has_item2 = function(tbl, item) - for _, value in pairs(tbl) do - if value == item then - return true - end - end - return false -end - -table.index_of = function(t, o) - if type(t) ~= "table" then - return nil - end - for i,v in ipairs(t) do - if o == v then - return i - end - end - return nil -end - -table.adress = function(tbl) - local str = tostring(tbl) - - return string.sub(str, 8, str:len()) -end - --- Serialization and deserialization -local serialization = function(key, value) - local str = "" - - if type(value) == "string" then - str = str .. tostring(key) .. "=\"" .. value .. "\"," - elseif type(value) == "number" then - str = str .. tostring(key) .. "=" .. tostring(value) .. "," - elseif type(value) == "boolean" then - str = str .. tostring(key) .. "=" - - if value then - str = str .. "true" - else - str = str .. "false" - end - - str = str .. "," - - elseif type(value) == "table" then - str = str .. tostring(key) .. "=" .. table.serialization(value) .. "," - end - - return str -end - -local deserialization = function(str) - for i = 1, string.len(str) do - local value = string.sub(str, i, i) - - if value == "=" then - local key = string.sub(str, 1, i - 1) - local value = string.sub(str, i + 1, string.len(str)) - - -- Check key - if string.sub(key, 1, 1) == "[" then - key = string.sub(key, 3, string.len(key) - 2) - else - key = tonumber(key) - end - - -- Check value - if value == "true" then - value = true - elseif value == "false" then - value = false - elseif string.sub(value, 1, 1) == "\"" then - value = string.sub(value, 2, string.len(value) - 1) - elseif string.sub(value, 1, 1) == "{" then - value = table.deserialization(value) - else - value = tonumber(value) - end - - return key, value - end - end - - return nil, nil -end - -table.serialization = function(tbl) - local str = "{" - - for key, value in ipairs(tbl) do - str = str .. serialization(key, value) - end - for key, value in pairs(tbl) do - if type(key) ~= "number" then - str = str .. serialization("[\"" .. key .. "\"]", value) - end - end - - str = str .. "}" - - return str -end - -table.deserialization = function(str) - local tbl = {} - - -- Collected data - local data = "" - - -- Checks - local c_list = 0 - local c_str = false - - for i = 2, string.len(str) do - local before_value = string.sub(str, i - 1, i - 1) - local value = string.sub(str, i, i) - - -- If not inside a list or string - if value == "," and c_list == 0 then - -- Save propety - local key, val = deserialization(data) - - if key then - tbl[key] = val - end - - -- Search for new propety - data = "" - else - -- Detect string type - if value == "\"" and not before_value ~= "\\" then - c_str = not c_str - end - - -- Detect list type - if not c_str then - if value == "{" then - c_list = c_list + 1 - elseif value == "}" then - c_list = c_list - 1 - end - end - - -- save value - data = data .. value - end - end - - return tbl -end \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/core/core_functions.lua b/vmf/scripts/mods/vmf/modules/core/core_functions.lua index 2f047bc..9f681d9 100644 --- a/vmf/scripts/mods/vmf/modules/core/core_functions.lua +++ b/vmf/scripts/mods/vmf/modules/core/core_functions.lua @@ -175,7 +175,7 @@ end -- #################################################################################################################### -- ##### VMF internal functions and variables ######################################################################### -- #################################################################################################################### --- @TODO: maybe it doesn't belong in here +-- @TODO: rename it (get rid of "wrong") vmf.check_wrong_argument_type = function(mod, vmf_function_name, argument_name, argument, ...) local allowed_types = {...} diff --git a/vmf/scripts/mods/vmf/modules/core/delayed_chat_messages.lua b/vmf/scripts/mods/vmf/modules/core/delayed_chat_messages.lua index 80e2881..0e4f8ff 100644 --- a/vmf/scripts/mods/vmf/modules/core/delayed_chat_messages.lua +++ b/vmf/scripts/mods/vmf/modules/core/delayed_chat_messages.lua @@ -1,34 +1,20 @@ --- @TODO: do I need to hook it at all? - local vmf = get_mod("VMF") -- #################################################################################################################### --- ##### Hooks Functions ############################################################################################## +-- ##### Hooks ######################################################################################################## -- #################################################################################################################### --- HOOK: [ChatManager.register_channel] -local hook_send_unsent_messages = function (func, self, channel_id, members_func) +vmf:hook("ChatManager.register_channel", function (func, self, channel_id, members_func) func(self, channel_id, members_func) - if channel_id == 1 then + if (channel_id == 1) and (#vmf.unsent_chat_messages > 0) then for _, message in ipairs(vmf.unsent_chat_messages) do self:add_local_system_message(1, message, true) end + + for i, _ in ipairs(vmf.unsent_chat_messages) do + vmf.unsent_chat_messages[i] = nil + end end -end - --- #################################################################################################################### --- ##### VMF internal functions and variables ######################################################################### --- #################################################################################################################### - --- at the moment of loading VMF Chat Manager is not initialized yet, --- so it should be hooked with some delay -vmf.hook_chat_manager = function() - - if not vmf.is_chat_manager_hooked then - vmf.is_chat_manager_hooked = true - - vmf:hook("ChatManager.register_channel", hook_send_unsent_messages) - end -end \ No newline at end of file +end) \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/core/initialization.lua b/vmf/scripts/mods/vmf/modules/core/initialization.lua new file mode 100644 index 0000000..da9f11f --- /dev/null +++ b/vmf/scripts/mods/vmf/modules/core/initialization.lua @@ -0,0 +1,43 @@ +local vmf = get_mod("VMF") + +--@TODO: array where I track if data was already initialized (initialize and initialize_data can be called only once) + +-- #################################################################################################################### +-- ##### VMFMod ####################################################################################################### +-- #################################################################################################################### + +VMFMod.initialize = function (self, script_path) + + local success, error_details = pcall(dofile, script_path) + if not success then + if error_details.error then + self:error("(initialize): %s", error_details.error) + print("\nTRACEBACK:\n\n" .. error_details.traceback .. "\nLOCALS:\n\n" .. error_details.locals) + else + self:error("(initialize): %s", tostring(error_details)) + end + return + end + + if self:is_togglable() then + vmf.initialize_mod_state(self) + end +end + +VMFMod.initialize_data = function (self, mod_data) + + if mod_data.name then + self._data.readable_name = mod_data.name + end + self._data.description = mod_data.description + self._data.is_togglable = mod_data.is_togglable or mod_data.is_mutator + self._data.is_mutator = mod_data.is_mutator + + if mod_data.is_mutator then + vmf.register_mod_as_mutator(self, mod_data.mutator_setting) + end + + if mod_data.options_widgets or (mod_data.is_togglable and not mod_data.is_mutator) then + vmf.create_options(self, mod_data.options_widgets) + end +end \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/core/keybindings.lua b/vmf/scripts/mods/vmf/modules/core/keybindings.lua index 14cc752..a3fe070 100644 --- a/vmf/scripts/mods/vmf/modules/core/keybindings.lua +++ b/vmf/scripts/mods/vmf/modules/core/keybindings.lua @@ -14,6 +14,8 @@ local _RAW_KEYBINDS = {} -- ["primary_key"] = {{"mod_name", "action_name", ctrl_used(bool), alt_used(bool), shift_used(bool)}, {}, {}, ...} local _OPTIMIZED_KEYBINDS = {} +local _ACTIVATED_PRESSED_KEY + -- #################################################################################################################### -- ##### Local functions ############################################################################################## -- #################################################################################################################### @@ -101,11 +103,11 @@ vmf.check_pressed_keybinds = function() if input_service then -- don't check for the pressed keybindings until player will release already pressed keybind - if vmf.activated_pressed_key then - if input_service:get(vmf.activated_pressed_key) then + if _ACTIVATED_PRESSED_KEY then + if input_service:get(_ACTIVATED_PRESSED_KEY) then return else - vmf.activated_pressed_key = nil + _ACTIVATED_PRESSED_KEY = nil end end @@ -120,12 +122,12 @@ vmf.check_pressed_keybinds = function() local mod = get_mod(binding_info[1]) - if binding_info[2] == "toggle_mod" then + if binding_info[2] == "toggle_mod_state" and not mod:is_mutator() then vmf.mod_state_changed(mod:get_name(), not mod:is_enabled()) key_has_active_keybind = true - vmf.activated_pressed_key = key + _ACTIVATED_PRESSED_KEY = key elseif mod:is_enabled() then @@ -140,7 +142,7 @@ vmf.check_pressed_keybinds = function() end key_has_active_keybind = true - vmf.activated_pressed_key = key + _ACTIVATED_PRESSED_KEY = key end end end diff --git a/vmf/scripts/mods/vmf/modules/core/localization.lua b/vmf/scripts/mods/vmf/modules/core/localization.lua index 888282d..63a4c2e 100644 --- a/vmf/scripts/mods/vmf/modules/core/localization.lua +++ b/vmf/scripts/mods/vmf/modules/core/localization.lua @@ -82,11 +82,11 @@ VMFMod.localize = function (self, text_id, ...) end end end - - return "<" .. tostring(text_id) .. ">" else self:error("(localize): localization file was not loaded for this mod") end + + return "<" .. tostring(text_id) .. ">" end -- #################################################################################################################### diff --git a/vmf/scripts/mods/vmf/modules/core/persistent_tables.lua b/vmf/scripts/mods/vmf/modules/core/persistent_tables.lua new file mode 100644 index 0000000..516da1c --- /dev/null +++ b/vmf/scripts/mods/vmf/modules/core/persistent_tables.lua @@ -0,0 +1,32 @@ +local vmf = get_mod("VMF") + +Managers.vmf.persistent_tables = Managers.vmf.persistent_tables or {} + +local _PERSISTENT_TABLES = Managers.vmf.persistent_tables + +-- #################################################################################################################### +-- ##### VMFMod ####################################################################################################### +-- #################################################################################################################### + +VMFMod.persistent_table = function (self, table_name) + + if vmf.check_wrong_argument_type(self, "persistent_table", "table_name", table_name, "string") then + return + end + + local mod_name = self:get_name() + + _PERSISTENT_TABLES[mod_name] = _PERSISTENT_TABLES[mod_name] or {} + + local mod_tables = _PERSISTENT_TABLES[mod_name] + + mod_tables[table_name] = mod_tables[table_name] or {} + + return mod_tables[table_name] +end + +-- #################################################################################################################### +-- ##### Script ####################################################################################################### +-- #################################################################################################################### + +vmf.persistent_data = vmf:persistent_table("persistent_data") \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/core/toggling.lua b/vmf/scripts/mods/vmf/modules/core/toggling.lua index 2ab124c..53bc690 100644 --- a/vmf/scripts/mods/vmf/modules/core/toggling.lua +++ b/vmf/scripts/mods/vmf/modules/core/toggling.lua @@ -1,77 +1,60 @@ local vmf = get_mod("VMF") -local _DISABLED_MODS_LIST = vmf:get("disabled_mods_list") or {} - --- #################################################################################################################### --- ##### Local functions ############################################################################################## --- #################################################################################################################### - -local function change_mod_state(mod, enable, initial_call) - - if enable then - - _DISABLED_MODS_LIST[mod:get_name()] = nil - - vmf.mod_enabled_event(mod, initial_call) - else - - _DISABLED_MODS_LIST[mod:get_name()] = true - - vmf.mod_disabled_event(mod, initial_call) - end - - if initial_call then - return - end - - vmf:set("disabled_mods_list", _DISABLED_MODS_LIST) -end - --- #################################################################################################################### --- ##### VMFMod ####################################################################################################### --- #################################################################################################################### - -VMFMod.is_enabled = function (self) - - return not _DISABLED_MODS_LIST[self:get_name()] -end - -VMFMod.disable = function (self) - - if not _DISABLED_MODS_LIST[self:get_name()] then - - change_mod_state(self, false, false) - end -end - -VMFMod.enable = function (self) - - if _DISABLED_MODS_LIST[self:get_name()] then - - change_mod_state(self, true, false) - end -end - -VMFMod.init_state = function (self, state) - if type(state) ~= "boolean" then - state = not _DISABLED_MODS_LIST[self:get_name()] - end - change_mod_state(self, state, true) -end +local _DISABLED_MODS = vmf:get("disabled_mods_list") or {} -- #################################################################################################################### -- ##### VMF internal functions and variables ######################################################################### -- #################################################################################################################### -vmf.disabled_mods_list = _DISABLED_MODS_LIST +vmf.set_mod_state = function (mod, is_enabled, initial_call) + + mod._data.is_enabled = is_enabled + + if is_enabled then + vmf.mod_enabled_event(mod, initial_call) + else + vmf.mod_disabled_event(mod, initial_call) + end + + if not (initial_call or mod:is_mutator()) then + if is_enabled then + _DISABLED_MODS[mod:get_name()] = nil + else + _DISABLED_MODS[mod:get_name()] = true + end + vmf:set("disabled_mods_list", _DISABLED_MODS) + end +end + +-- Called when mod is loaded for the first time using mod:initialize() +vmf.initialize_mod_state = function (mod) + + local state + if mod:is_mutator() then + -- if VMF was reloaded and mutator was activated + if vmf.is_mutator_enabled(mod:get_name()) then + state = true + else + state = false + end + vmf.set_mutator_state(mod, state, true) + else + state = not _DISABLED_MODS[mod:get_name()] + vmf.set_mod_state(mod, state, true) + end +end vmf.mod_state_changed = function (mod_name, is_enabled) local mod = get_mod(mod_name) - if is_enabled then - mod:enable() + if not mod:is_togglable() or is_enabled == mod:is_enabled() then + return + end + + if mod:is_mutator() then + vmf.set_mutator_state(mod, is_enabled, false) else - mod:disable() + vmf.set_mod_state(mod, is_enabled, false) end end \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/mods.lua b/vmf/scripts/mods/vmf/modules/mods.lua index 58dc3d8..e6c3f0c 100644 --- a/vmf/scripts/mods/vmf/modules/mods.lua +++ b/vmf/scripts/mods/vmf/modules/mods.lua @@ -38,11 +38,39 @@ end VMFMod = class(VMFMod) VMFMod.init = function (self, mod_name) - self._name = mod_name + self._data = {} + -- @TODO: forbid changing _data table + self._data.name = mod_name + self._data.readable_name = mod_name + self._data.is_enabled = true + self._data.is_togglable = false + self._data.is_mutator = false end +-- DATA + VMFMod.get_name = function (self) - return self._name + return self._data.name +end + +VMFMod.get_readable_name = function (self) + return self._data.readable_name +end + +VMFMod.get_description = function (self) + return self._data.description +end + +VMFMod.is_enabled = function (self) + return self._data.is_enabled +end + +VMFMod.is_togglable = function (self) + return self._data.is_togglable +end + +VMFMod.is_mutator = function (self) + return self._data.is_mutator end -- #################################################################################################################### diff --git a/vmf/scripts/mods/vmf/modules/testing_stuff_here.lua b/vmf/scripts/mods/vmf/modules/testing_stuff_here.lua index e4d444f..3e5e049 100644 --- a/vmf/scripts/mods/vmf/modules/testing_stuff_here.lua +++ b/vmf/scripts/mods/vmf/modules/testing_stuff_here.lua @@ -1,6 +1,11 @@ -local mod = new_mod("test_mod") +local mod = get_mod("test_mod") -local options_widgets = { +local mod_data = {} +mod_data.name = "Test" +mod_data.description = "Test mod description" +mod_data.is_togglable = true +--mod_data.mutator_setting = nil +mod_data.options_widgets = { { ["setting_name"] = "game_mode", ["widget_type"] = "dropdown", @@ -106,8 +111,7 @@ local options_widgets = { ["default_value"] = 0 } } - -mod:create_options(options_widgets, true, "Test", "Mod description") +mod:initialize_data(mod_data) mod:command("whatever", "description whatever", function() mod:echo("whatever") end) mod:command("what", "description what", function() mod:echo("what") end) @@ -115,7 +119,24 @@ mod:command("wh", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Susp mod:command("whoa", "description whoa", function() mod:echo("whoa") end) mod:command("wheat", "description wheat", function() mod:echo("wheat") end) mod:command("test", "short command description\n params: [parameter1] [parameter2]\nparameter1 - string\nparameter2 - number", function(p1, p2) mod:echo("Test function executed.\nParameter1: " .. tostring(p1) .. "\nParameter2: " .. tostring(p2)) end) + -- chat_broadcast + +--[[ + local what = 1337 + local loadstring_function = assert( loadstring( "return UIAtlasHelper.has_atlas_settings_by_texture_name" ) ) + local loadstring_locals = { what = what} + setfenv(loadstring_function, setmetatable(loadstring_locals, { __index = _G })) + mod:echo(loadstring_function()) + mod:echo(getfenv(loadstring_function).what) +]] + +-- for serialization: +-- table.maxn (table) + + + + mod.whatever = function () --mod:echo("whatever") @@ -154,6 +175,27 @@ mod.whatever = function () --mod.custom_mod_rpc() end --ingame_ui.handle_transition(ingame_ui, "leave_group") +--[[ + + mod.update = function() + local experience = ScriptBackendProfileAttribute.get("experience") + local level = 30 + + if level ~= ExperienceSettings.get_level(experience) then + local new_experience = experience + + while level > ExperienceSettings.get_level(new_experience) do + new_experience = new_experience + 500 + end + + while level < ExperienceSettings.get_level(new_experience) do + new_experience = new_experience - 500 + end + + ScriptBackendProfileAttribute.set("experience", new_experience) + end + end + ]] function mod.simulate(...) @@ -229,19 +271,16 @@ mod:pcall( ) -mod:network_register("rpc_whatever", mod.game_state_changed) -mod:network_register("yo",mod.game_state_changed) -mod:network_register("test", mod.game_state_changed) --mod:hook("bla.bla", mod.game_state_changed) --mod:hook("bla.bla2", mod.game_state_changed) --mod:hook("bla.bla3", mod.game_state_changed) -local mod3 = new_mod("test_mod3") +--local mod3 = new_mod("test_mod3") --mod3:hook("bla.bla", mod.game_state_changed) --mod3:hook("bla.bla2", mod.game_state_changed) --mod3:hook("bla.bla3", mod.game_state_changed) -mod3:network_register("what", mod.game_state_changed) +--mod3:network_register("what", mod.game_state_changed) --[[ mod:hook("ChatManager.rpc_chat_message", function (func, self, sender, channel_id, message_sender, message, localization_param, is_system_message, pop_chat, is_dev) diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_default_config.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_default_config.lua index 744b8d9..c7ff678 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_default_config.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_default_config.lua @@ -4,8 +4,7 @@ return { tomes = 0, bonus = 0 }, - title = "", - short_title = "", + short_title = "", --@TODO: rename it? title_placement = "after", description = "No description provided", difficulty_levels = { diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua index 4c912ce..26018fe 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua @@ -1,6 +1,5 @@ --[[ Add additional dice to end game roll --]] - -local manager = get_mod("vmf_mutator_manager") +local vmf = get_mod("VMF") -- List of all die types local missions = { @@ -16,7 +15,7 @@ local num_dice_per_mission = { grimoire_hidden_mission = 0 } -manager:hook("GameModeManager.complete_level", function(func, self) +vmf:hook("GameModeManager.complete_level", function(func, self) local num_dice = 0 local max_dice = 7 local mission_system = Managers.state.entity:system("mission_system") @@ -32,7 +31,7 @@ manager:hook("GameModeManager.complete_level", function(func, self) -- Get total number of dice for name, obj in pairs(active_mission) do - if table.has_item(missions, name) then + if table.contains(missions, name) then num_dice = num_dice + obj.current_amount end end diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui.lua index 7dd8ad8..c6984e1 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui.lua @@ -1,14 +1,15 @@ --[[ Add mutators panel to the map view --]] +--@TODO: button highlighted incorrectly +local vmf = get_mod("VMF") -local manager = get_mod("vmf_mutator_manager") -local mutators = manager.mutators +local _MUTATORS = vmf.mutators ---manager:custom_textures("mutator_button", "mutator_button_hover") ---manager:inject_materials("ingame_ui", "materials/vmf/mutator_button", "materials/vmf/mutator_button_hover") +--vmf:custom_textures("mutator_button", "mutator_button_hover") +--vmf:inject_materials("ingame_ui", "materials/vmf/mutator_button", "materials/vmf/mutator_button_hover") -local definitions = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions") +local _DEFINITIONS = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions") -local PER_PAGE = definitions.PER_PAGE +local _PER_PAGE = _DEFINITIONS.PER_PAGE local mutators_view = { @@ -29,17 +30,17 @@ local mutators_view = { self:update_mutator_list() -- Recreate the map_view scenegraph defs - self.map_view.scenegraph_definition = UISceneGraph.init_scenegraph(definitions.scenegraph_definition) + self.map_view.scenegraph_definition = UISceneGraph.init_scenegraph(_DEFINITIONS.scenegraph_definition) -- Setup custom widgets self.widgets = { - banner_mutators = UIWidget.init(definitions.new_widgets.banner_mutators_widget), - mutators_button = UIWidget.init(definitions.new_widgets.mutators_button_widget), - no_mutators_text = UIWidget.init(definitions.new_widgets.no_mutators_text_widget) + banner_mutators = UIWidget.init(_DEFINITIONS.new_widgets.banner_mutators_widget), + mutators_button = UIWidget.init(_DEFINITIONS.new_widgets.mutators_button_widget), + no_mutators_text = UIWidget.init(_DEFINITIONS.new_widgets.no_mutators_text_widget) } - for i = 1, PER_PAGE do - table.insert(self.mutator_checkboxes, UIWidget.init(definitions.new_widgets["mutator_checkbox_" .. i])) + for i = 1, _PER_PAGE do + table.insert(self.mutator_checkboxes, UIWidget.init(_DEFINITIONS.new_widgets["mutator_checkbox_" .. i])) end -- Save widgets we're gonna mess with @@ -102,8 +103,8 @@ local mutators_view = { -- Sorts mutators by title update_mutator_list = function(self) self.mutators_sorted = {} - for _, mutator in ipairs(mutators) do - table.insert(self.mutators_sorted, {mutator:get_name(), mutator:get_config().title or mutator:get_name()}) + for _, mutator in ipairs(_MUTATORS) do + table.insert(self.mutators_sorted, {mutator:get_name(), mutator:get_readable_name()}) end table.sort(self.mutators_sorted, function(a, b) return string.lower(a[2]) < string.lower(b[2]) end) end, @@ -160,9 +161,9 @@ local mutators_view = { local widgets = self.map_view.normal_settings_widget_types - for i = 1, PER_PAGE do + for i = 1, _PER_PAGE do - local current_index = PER_PAGE * (self.current_page - 1) + i + local current_index = _PER_PAGE * (self.current_page - 1) + i local checkbox = self.mutator_checkboxes[i] local hotspot = checkbox.content.button_hotspot @@ -189,7 +190,7 @@ local mutators_view = { widgets.survival["mutator_checkbox_" .. i] = checkbox -- Set colors based on whether mutator can be enabled - local active = mutator:can_be_enabled() + local active = vmf.mutator_can_be_enabled(mutator) local color = active and "cheeseburger" or "slate_gray" local color_hover = active and "white" or "slate_gray" checkbox.style.setting_text.text_color = Colors.get_color_table_with_alpha(color, 255) @@ -205,9 +206,9 @@ local mutators_view = { if hotspot.on_release then self.map_view:play_sound("Play_hud_select") if mutator:is_enabled() then - mutator:disable() + vmf.mod_state_changed(mutator:get_name(), false) else - mutator:enable() + vmf.mod_state_changed(mutator:get_name(), true) end end @@ -215,7 +216,7 @@ local mutators_view = { end end - if #mutators == 0 then + if #_MUTATORS == 0 then widgets.adventure["no_mutators_text"] = self.widgets.no_mutators_text widgets.survival["no_mutators_text"] = self.widgets.no_mutators_text @@ -245,7 +246,7 @@ local mutators_view = { -- Update steppers local level_stepper_widget = self.map_view.steppers.level.widget - local num_pages = math.ceil(#mutators/PER_PAGE) + local num_pages = math.ceil(#_MUTATORS/_PER_PAGE) level_stepper_widget.style.setting_text.offset[2] = -10000 level_stepper_widget.style.hover_texture.offset[2] = -10000 level_stepper_widget.content.left_button_hotspot.disable_button = num_pages <= 1 @@ -285,7 +286,7 @@ local mutators_view = { self.map_view:update_level_stepper() -- Mutator checkboxes - for i = 1, PER_PAGE do + for i = 1, _PER_PAGE do widgets.adventure["mutator_checkbox_" .. i] = nil widgets.survival["mutator_checkbox_" .. i] = nil end @@ -300,7 +301,7 @@ local mutators_view = { if self.active then local current_index = self.current_page local new_index = current_index + index_change - local num_pages = math.ceil(#mutators/PER_PAGE) + local num_pages = math.ceil(#_MUTATORS/_PER_PAGE) if new_index < 1 then new_index = num_pages @@ -316,48 +317,47 @@ local mutators_view = { -- Creates and return text for checkbox tooltip generate_tooltip_for = function(self, mutator) - local config = mutator:get_config() + local config = vmf.get_mutator_config(mutator) local text = "" -- Show supported difficulty when can't be enabled due to difficulty level - local supports_difficulty = mutator:supports_current_difficulty() + local supports_difficulty = vmf.mutator_supports_current_difficulty(mutator) if not supports_difficulty then - text = text .. "\n" .. manager:localize("tooltip_supported_difficulty") .. ":" + text = text .. "\n" .. vmf:localize("tooltip_supported_difficulty") .. ":" for i, difficulty in ipairs(config.difficulty_levels) do - text = text .. (i == 1 and " " or ", ") .. manager:localize(difficulty) + text = text .. (i == 1 and " " or ", ") .. vmf:localize(difficulty) end end -- Show enabled incompatible - local incompatible_mutators = mutator:get_incompatible_mutators(true) + local incompatible_mutators = vmf.get_incompatible_mutators(mutator, true) local currently_compatible = #incompatible_mutators == 0 -- Or all incompatible if difficulty is compatible if supports_difficulty and #incompatible_mutators == 0 then - incompatible_mutators = mutator:get_incompatible_mutators() + incompatible_mutators = vmf.get_incompatible_mutators(mutator) end if #incompatible_mutators > 0 then - if currently_compatible and config.incompatible_with_all or #incompatible_mutators == #mutators - 1 then + if currently_compatible and config.incompatible_with_all or #incompatible_mutators == #_MUTATORS - 1 then -- Show special message when incompatible with all - text = text .. "\n" .. manager:localize("tooltip_incompatible_with_all") + text = text .. "\n" .. vmf:localize("tooltip_incompatible_with_all") else - text = text .. "\n" .. manager:localize("tooltip_incompatible_with") .. ":" + text = text .. "\n" .. vmf:localize("tooltip_incompatible_with") .. ":" for i, other_mutator in ipairs(incompatible_mutators) do - local name = (other_mutator:get_config().title or other_mutator:get_name()) - text = text .. (i == 1 and " " or ", ") .. name + text = text .. (i == 1 and " " or ", ") .. other_mutator:get_readable_name() end end elseif config.compatible_with_all then -- Special message when compatible with all - text = text .. "\n" .. manager:localize("tooltip_compatible_with_all") + text = text .. "\n" .. vmf:localize("tooltip_compatible_with_all") end -- Special message if switched to unsupported difficulty level if mutator:is_enabled() and not supports_difficulty then - text = text .. "\n" .. manager:localize("tooltip_will_be_disabled") + text = text .. "\n" .. vmf:localize("tooltip_will_be_disabled") end -- Description @@ -372,13 +372,13 @@ local mutators_view = { setup_hooks = function(self) -- Update the view after map_view has updated - manager:hook("MapView.update", function(func, map_view, dt, t) + vmf:hook("MapView.update", function(func, map_view, dt, t) func(map_view, dt, t) self:update(dt, t) end) -- Activate the view on enter if it was active on exit - manager:hook("MapView.on_enter", function(func, map_view) + vmf:hook("MapView.on_enter", function(func, map_view) func(map_view) if self.was_active then self.widgets.mutators_button.content.toggled = true @@ -387,47 +387,47 @@ local mutators_view = { end) -- Deactivate the view on exit - manager:hook("MapView.on_exit", function(func, map_view) + vmf:hook("MapView.on_exit", function(func, map_view) func(map_view) self:deactivate() end) -- We don't want to let the game disable steppers when mutators view is active - manager:hook("MapView.update_level_stepper", function(func, map_view) + vmf:hook("MapView.update_level_stepper", function(func, map_view) if not self.active then func(map_view) end end) --[[ - manager:hook("MapView.on_level_index_changed", function(func, map_view, ...) + vmf:hook("MapView.on_level_index_changed", function(func, map_view, ...) func(map_view, ...) print("on_level_index_changed") - manager.disable_impossible_mutators(true) + vmf.disable_impossible_mutators(true) end) - manager:hook("MapView.on_difficulty_index_changed", function(func, map_view, ...) + vmf:hook("MapView.on_difficulty_index_changed", function(func, map_view, ...) func(map_view, ...) print("on_difficulty_index_changed") - manager.disable_impossible_mutators(true) + vmf.disable_impossible_mutators(true) end) - manager:hook("MapView.set_difficulty_stepper_index", function(func, map_view, ...) + vmf:hook("MapView.set_difficulty_stepper_index", function(func, map_view, ...) func(map_view, ...) print("set_difficulty_stepper_index") - manager.disable_impossible_mutators(true) + vmf.disable_impossible_mutators(true) end) --]] end, reset_hooks = function(self) - manager:hook_remove("MapView.update") - manager:hook_remove("MapView.on_enter") - manager:hook_remove("MapView.on_exit") - manager:hook_remove("MapView.update_level_stepper") - -- manager:hook_remove("MapView.on_level_index_changed") - -- manager:hook_remove("MapView.on_difficulty_index_changed") - -- manager:hook_remove("MapView.set_difficulty_stepper_index") + vmf:hook_remove("MapView.update") + vmf:hook_remove("MapView.on_enter") + vmf:hook_remove("MapView.on_exit") + vmf:hook_remove("MapView.update_level_stepper") + -- vmf:hook_remove("MapView.on_level_index_changed") + -- vmf:hook_remove("MapView.on_difficulty_index_changed") + -- vmf:hook_remove("MapView.set_difficulty_stepper_index") end, get_map_view = function(self) @@ -437,13 +437,13 @@ local mutators_view = { } -- Initialize mutators view after map view -manager:hook("MapView.init", function(func, self, ...) +vmf:hook("MapView.init", function(func, self, ...) func(self, ...) mutators_view:init(self) end) -- Destroy mutators view after map view -manager:hook("MapView.destroy", function(func, ...) +vmf:hook("MapView.destroy", function(func, ...) mutators_view:deinitialize() func(...) end) diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions.lua index 08451e9..b362130 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_gui_definitions.lua @@ -1,4 +1,4 @@ -local manager = get_mod("vmf_mutator_manager") +local vmf = get_mod("VMF") local definitions = local_require("scripts/ui/views/map_view_definitions") local scenegraph_definition = definitions.scenegraph_definition @@ -58,8 +58,8 @@ local new_widgets = { -- This will replace the banner behind the Mission text banner_mutators_widget = UIWidgets.create_texture_with_text_and_tooltip( "title_bar", - manager:localize("mutators_title"), - manager:localize("mutators_banner_tooltip"), + vmf:localize("mutators_title"), + vmf:localize("mutators_banner_tooltip"), "banner_level", "banner_mutators_text", { vertical_alignment = "center", @@ -96,10 +96,10 @@ local new_widgets = { toggle_texture = "octagon_button_toggled", hover_texture = "octagon_button_hover", normal_texture = "octagon_button_normal", - icon_texture = "mutator_button", - icon_hover_texture = "mutator_button_hover", - tooltip_text = manager:localize("mutators_title"), - toggled_tooltip_text = manager:localize("mutators_title"), + icon_texture = "map_view_party_button", + icon_hover_texture = "map_view_party_button_lit", + tooltip_text = vmf:localize("mutators_title"), + toggled_tooltip_text = vmf:localize("mutators_title"), button_hotspot = {} }, style = { @@ -224,8 +224,8 @@ local new_widgets = { } }, content = { - text = manager:localize("no_mutators"), - tooltip_text = manager:localize("no_mutators_tooltip"), + text = vmf:localize("no_mutators"), + tooltip_text = vmf:localize("no_mutators_tooltip"), tooltip_hotspot = {}, color = Colors.get_color_table_with_alpha("slate_gray", 255) }, diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua index 63a3b97..c1e4c04 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua @@ -1,7 +1,7 @@ --[[ Notify players of enabled mutators via chat and tab menu --]] +local vmf = get_mod("VMF") -local manager = get_mod("vmf_mutator_manager") -local mutators = manager.mutators +local mutators = vmf.mutators local were_enabled_before = false @@ -13,17 +13,17 @@ local function add_enabled_mutators_titles_to_string(str, separator, short) table.insert(_mutators, mutator) end end - return manager.add_mutator_titles_to_string(_mutators, str, separator, short) + return vmf.add_mutator_titles_to_string(_mutators, str, separator, short) end -- Sets the lobby name local function set_lobby_data() if ( - not Managers.matchmaking or - not Managers.matchmaking.lobby or + not Managers.matchmaking or + not Managers.matchmaking.lobby or not Managers.matchmaking.lobby.set_lobby_data or - not Managers.matchmaking.lobby.get_stored_lobby_data + not Managers.matchmaking.lobby.get_stored_lobby_data ) then return end local name = add_enabled_mutators_titles_to_string("", " ", true) @@ -41,6 +41,7 @@ local function set_lobby_data() Managers.matchmaking.lobby:set_lobby_data(lobby_data) end +--@TODO: maybe rewrite? local function get_peer_id_from_cookie(client_cookie) local peer_id = tostring(client_cookie) for _ = 1, 3 do @@ -55,12 +56,20 @@ local function get_peer_id_from_cookie(client_cookie) end -- Append difficulty name with enabled mutators' titles -manager:hook("IngamePlayerListUI.update_difficulty", function(func, self) +vmf:hook("IngamePlayerListUI.update_difficulty", function(func, self) local difficulty_settings = Managers.state.difficulty:get_difficulty_settings() local difficulty_name = difficulty_settings.display_name - local name = not self.is_in_inn and Localize(difficulty_name) or "" - name = add_enabled_mutators_titles_to_string(name, " ", true) + --local name = not self.is_in_inn and Localize(difficulty_name) or "" + --name = add_enabled_mutators_titles_to_string(name, ", ", true) + + local name = add_enabled_mutators_titles_to_string("", ", ", true) + local localized_difficulty_name = not self.is_in_inn and Localize(difficulty_name) or "" + if name == "" then -- no mutators + name = localized_difficulty_name + elseif localized_difficulty_name ~= "" then -- no difficulty (inn) + name = name .. " (" .. localized_difficulty_name .. ")" + end self.set_difficulty_name(self, name) @@ -68,25 +77,25 @@ manager:hook("IngamePlayerListUI.update_difficulty", function(func, self) end) -- Notify everybody about enabled/disabled mutators when Play button is pressed on the map screen -manager:hook("MatchmakingStateHostGame.host_game", function(func, self, ...) +vmf:hook("MatchmakingStateHostGame.host_game", function(func, self, ...) func(self, ...) set_lobby_data() local names = add_enabled_mutators_titles_to_string("", ", ") if string.len(names) > 0 then - manager:chat_broadcast(manager:localize("broadcast_enabled_mutators") .. ": " .. names) + vmf:chat_broadcast(vmf:localize("broadcast_enabled_mutators") .. ": " .. names) were_enabled_before = true elseif were_enabled_before then - manager:chat_broadcast(manager:localize("broadcast_all_disabled")) + vmf:chat_broadcast(vmf:localize("broadcast_all_disabled")) were_enabled_before = false end end) -- Send special messages with enabled mutators list to players just joining the lobby -manager:hook("MatchmakingManager.rpc_matchmaking_request_join_lobby", function(func, self, sender, client_cookie, host_cookie, lobby_id, friend_join) +vmf:hook("MatchmakingManager.rpc_matchmaking_request_join_lobby", function(func, self, sender, client_cookie, host_cookie, lobby_id, friend_join) local name = add_enabled_mutators_titles_to_string("", ", ") if string.len(name) > 0 then - local message = manager:localize("whisper_enabled_mutators") .. ": " .. name - manager:chat_whisper(get_peer_id_from_cookie(client_cookie), message) + local message = vmf:localize("whisper_enabled_mutators") .. ": " .. name + vmf:chat_whisper(get_peer_id_from_cookie(client_cookie), message) end func(self, sender, client_cookie, host_cookie, lobby_id, friend_join) end) diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua index a69aa5b..12de60d 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua @@ -1,21 +1,17 @@ --[[ Add ability to turn mods into mutators --]] - -local manager = new_mod("vmf_mutator_manager") - -manager:localization("localization/mutator_manager") +local vmf = get_mod("VMF") -- List of mods that are also mutators in order in which they should be enabled --- This is populated via VMFMod.register_as_mutator -manager.mutators = {} -local mutators = manager.mutators +-- This is populated via vmf.register_mod_as_mutator +local _MUTATORS = {} -- Table of mutators' configs by name -local mutators_config = {} -local default_config = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config") +local _MUTATORS_CONFIG = {} +local _DEFAULT_CONFIG -- This lists mutators and which ones should be enabled after them --- This is populated via VMFMod.register_as_mutator -local mutators_sequence = { +-- This is populated via vmf.register_mod_as_mutator +local _MUTATORS_SEQUENCE = { --[[ this_mutator = { "will be enabled", @@ -25,59 +21,71 @@ local mutators_sequence = { } -- So we don't sort after each one is added -local mutators_sorted = false +local _MUTATORS_SORTED = false -- So we don't have to check when player isn't hosting -local all_mutators_disabled = false +local _ALL_MUTATORS_DISABLED = false +-- External modules +local _MUTATORS_VIEW +local _DICE_MANAGER +local _SET_LOBBY_DATA ---[[ - PRIVATE METHODS -]]-- +local _MUTATORS_GUI -local mutators_view = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui") -local dice_manager = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_dice") -local set_lobby_data = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_info") +-- List of enabled mutators in case VMF is reloaded in the middle of the game +local _ENABLED_MUTATORS = vmf:persistent_table("enabled_mutators") + +-- #################################################################################################################### +-- ##### Local functions ############################################################################################## +-- #################################################################################################################### + +local function get_index(tbl, o) + for i, v in ipairs(tbl) do + if o == v then + return i + end + end + return nil +end -- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name local function update_mutators_sequence(mutator_name, enable_these_after) - if not mutators_sequence[mutator_name] then - mutators_sequence[mutator_name] = {} + if not _MUTATORS_SEQUENCE[mutator_name] then + _MUTATORS_SEQUENCE[mutator_name] = {} end for _, other_mutator_name in ipairs(enable_these_after) do - if mutators_sequence[other_mutator_name] and table.has_item(mutators_sequence[other_mutator_name], mutator_name) then - manager:error("Mutators '" .. mutator_name .. "' and '" .. other_mutator_name .. "' are both set to load after the other one.") - elseif not table.has_item(mutators_sequence[mutator_name], other_mutator_name) then - table.insert(mutators_sequence[mutator_name], other_mutator_name) + if _MUTATORS_SEQUENCE[other_mutator_name] and table.contains(_MUTATORS_SEQUENCE[other_mutator_name], mutator_name) then + vmf:error("(mutators): Mutators '%s' and '%s' are both set to load after each other.", mutator_name, other_mutator_name) + elseif not table.contains(_MUTATORS_SEQUENCE[mutator_name], other_mutator_name) then + table.insert(_MUTATORS_SEQUENCE[mutator_name], other_mutator_name) end - end - table.combine(mutators_sequence[mutator_name], enable_these_after) end -- Checks if mutators are compatible both ways local function is_compatible(mutator, other_mutator) - local config = mutator:get_config() + local config = vmf.get_mutator_config(mutator) local name = mutator:get_name() - local other_config = other_mutator:get_config() + local other_config = vmf.get_mutator_config(other_mutator) local other_name = other_mutator:get_name() local incompatible_specifically = ( #config.incompatible_with > 0 and ( - table.has_item(config.incompatible_with, other_name) + table.contains(config.incompatible_with, other_name) ) or #other_config.incompatible_with > 0 and ( - table.has_item(other_config.incompatible_with, name) + table.contains(other_config.incompatible_with, name) ) ) local compatible_specifically = ( #config.compatible_with > 0 and ( - table.has_item(config.compatible_with, other_name) + table.contains(config.compatible_with, other_name) ) or #other_config.compatible_with > 0 and ( - table.has_item(other_config.compatible_with, name) + table.contains(other_config.compatible_with, name) ) ) @@ -99,79 +107,22 @@ end -- Called after mutator is enabled local function on_enabled(mutator) - local config = mutator:get_config() - dice_manager.addDice(config.dice) - set_lobby_data() - print("[MUTATORS] Enabled " .. mutator:get_name() .. " (" .. tostring(table.index_of(mutators, mutator)) .. ")") + local config = vmf.get_mutator_config(mutator) + _DICE_MANAGER.addDice(config.dice) + _SET_LOBBY_DATA() + print("[MUTATORS] Enabled " .. mutator:get_name() .. " (" .. tostring(get_index(_MUTATORS, mutator)) .. ")") + + _ENABLED_MUTATORS[mutator:get_name()] = true end -- Called after mutator is disabled local function on_disabled(mutator) - local config = mutator:get_config() - dice_manager.removeDice(config.dice) - set_lobby_data() - print("[MUTATORS] Disabled " .. mutator:get_name() .. " (" .. tostring(table.index_of(mutators, mutator)) .. ")") -end + local config = vmf.get_mutator_config(mutator) + _DICE_MANAGER.removeDice(config.dice) + _SET_LOBBY_DATA() + print("[MUTATORS] Disabled " .. mutator:get_name() .. " (" .. tostring(get_index(_MUTATORS, mutator)) .. ")") --- Enables/disables mutator while preserving the sequence in which they were enabled -local function set_mutator_state(mutator, state) - - local i = table.index_of(mutators, mutator) - if i == nil then - mutator:error("Mutator isn't in the list") - return - end - - if state == mutator:is_enabled() then - return - end - - if state and ( - not mutator:can_be_enabled() or - Managers.state and Managers.state.game_mode and Managers.state.game_mode._game_mode_key ~= "inn" - ) then - return - end - - -- Sort mutators if this is the first call - if not mutators_sorted then - manager.sort_mutators() - end - - local disabled_mutators = {} - local enable_these_after = mutators_sequence[mutator:get_name()] - - -- Disable mutators that were and are required to be enabled after the current one - -- This will be recursive so that if mutator2 requires mutator3 to be enabled after it, mutator3 will be disabled before mutator2 - -- Yeah this is super confusing - if enable_these_after and #mutators > i then - for j = #mutators, i + 1, -1 do - if mutators[j]:is_enabled() and table.has_item(enable_these_after, mutators[j]:get_name()) then - --print("Disabled ", mutators[j]:get_name()) - mutators[j]:disable() - table.insert(disabled_mutators, 1, mutators[j]) - end - end - end - - -- Enable/disable current mutator - -- We're calling methods on the class object because we've overwritten them on the current one - if state then - VMFMod.enable(mutator) - on_enabled(mutator) - else - VMFMod.disable(mutator) - on_disabled(mutator) - end - - -- Re-enable disabled mutators - -- This will be recursive - if #disabled_mutators > 0 then - for j = #disabled_mutators, 1, -1 do - --print("Enabled ", disabled_mutators[j]:get_name()) - disabled_mutators[j]:enable() - end - end + _ENABLED_MUTATORS[mutator:get_name()] = nil end -- Checks if the player is server in a way that doesn't incorrectly return false during loading screens @@ -181,18 +132,14 @@ local function player_is_server() return not player or player.is_server or not state or state.game_mode == nil end ---[[ - PUBLIC METHODS -]]-- - -- Sorts mutators in order they should be enabled -manager.sort_mutators = function() +local function sort_mutators() - if mutators_sorted then return end + if _MUTATORS_SORTED then return end --[[ -- LOG -- - manager:dump(mutators_sequence, "seq", 5) + vmf:dump(_MUTATORS_SEQUENCE, "seq", 5) for i, v in ipairs(mutators) do print(i, v:get_name()) end @@ -201,26 +148,26 @@ manager.sort_mutators = function() --]] -- Preventing endless loops (worst case is n*(n+1)/2 I believe) - local maxIter = #mutators * (#mutators + 1)/2 + local maxIter = #_MUTATORS * (#_MUTATORS + 1) / 2 local numIter = 0 -- The idea is that all mutators before the current one are already in the right order -- Starting from second mutator local i = 2 - while i <= #mutators do - local mutator = mutators[i] + while i <= #_MUTATORS do + local mutator = _MUTATORS[i] local mutator_name = mutator:get_name() - local enable_these_after = mutators_sequence[mutator_name] or {} + local enable_these_after = _MUTATORS_SEQUENCE[mutator_name] or {} -- Going back from the previous mutator to the start of the list local j = i - 1 while j > 0 do - local other_mutator = mutators[j] + local other_mutator = _MUTATORS[j] -- Moving it after the current one if it is to be enabled after it - if table.has_item(enable_these_after, other_mutator:get_name()) then - table.remove(mutators, j) - table.insert(mutators, i, other_mutator) + if table.contains(enable_these_after, other_mutator:get_name()) then + table.remove(_MUTATORS, j) + table.insert(_MUTATORS, i, other_mutator) -- This will shift the current mutator back, so adjust the index i = i - 1 @@ -232,47 +179,40 @@ manager.sort_mutators = function() numIter = numIter + 1 if numIter > maxIter then - manager:error("Mutators: too many iterations. Check for loops in 'enable_before_these'/'enable_after_these'.") + vmf:error("(mutators): too many iterations. Check for loops in 'enable_before_these'/'enable_after_these'.") return end end - mutators_sorted = true + _MUTATORS_SORTED = true -- LOG -- print("[MUTATORS] Sorted") - for k, v in ipairs(mutators) do + for k, v in ipairs(_MUTATORS) do print(" ", k, v:get_name()) end -- /LOG -- end --- Disables mutators that cannot be enabled right now -manager.disable_impossible_mutators = function(notify, everybody, reason) - local disabled_mutators = {} - for i = #mutators, 1, -1 do - local mutator = mutators[i] - if mutator:is_enabled() and not mutator:can_be_enabled() then - mutator:disable() - table.insert(disabled_mutators, mutator) - end - end - if #disabled_mutators > 0 and notify then - if not reason then reason = "" end - local loc = everybody and "broadcast_disabled_mutators" or "local_disabled_mutators" - local message = manager:localize(loc) .. " " .. manager:localize(reason) .. ":" - message = message .. " " .. manager.add_mutator_titles_to_string(disabled_mutators, "", ", ", false) - if everybody then - manager:chat_broadcast(message) - else - manager:echo(message) - end - end - return disabled_mutators +-- #################################################################################################################### +-- ##### VMF internal functions and variables ######################################################################### +-- #################################################################################################################### + +vmf.mutators = _MUTATORS + +-- ######### +-- # LOCAL # +-- ######### + +-- Checks current difficulty, map selection screen settings (optionally), incompatible mutators and whether player is server +-- to determine if a mutator can be enabled +function vmf.mutator_can_be_enabled(mutator) + if #vmf.get_incompatible_mutators(mutator, true) > 0 then return false end + return player_is_server() and vmf.mutator_supports_current_difficulty(mutator) end -- Appends, prepends and replaces the string with mutator titles -manager.add_mutator_titles_to_string = function(_mutators, str, separator, short) - +-- M, I +function vmf.add_mutator_titles_to_string(_mutators, str, separator, short) if #_mutators == 0 then return str end local before = nil @@ -280,8 +220,8 @@ manager.add_mutator_titles_to_string = function(_mutators, str, separator, short local replace = nil for _, mutator in ipairs(_mutators) do - local config = mutator:get_config() - local added_name = (short and config.short_title or config.title or mutator:get_name()) + local config = vmf.get_mutator_config(mutator) + local added_name = (short and config.short_title or mutator:get_readable_name()) if config.title_placement == "before" then if before then before = added_name .. separator .. before @@ -312,44 +252,55 @@ manager.add_mutator_titles_to_string = function(_mutators, str, separator, short return new_str end --- Check if player is still hosting -manager.update = function() - if not all_mutators_disabled and not player_is_server() then - manager.disable_impossible_mutators(true, false, "disabled_reason_not_server") - all_mutators_disabled = true +-- Returns a list of incompatible with self mutators, all or only enabled ones +-- M, G +function vmf.get_incompatible_mutators(mutator, enabled_only) + local incompatible_mutators = {} + for _, other_mutator in ipairs(_MUTATORS) do + if ( + other_mutator ~= mutator and + (not enabled_only or other_mutator:is_enabled()) and + not is_compatible(mutator, other_mutator) + ) then + table.insert(incompatible_mutators, other_mutator) + end end + return incompatible_mutators end - ---[[ - MUTATOR'S OWN METHODS -]]-- - --- Enables mutator -local function enable_mutator(self) - set_mutator_state(self, true) - all_mutators_disabled = false -end - --- Disables mutator -local function disable_mutator(self) - set_mutator_state(self, false) -end - --- Checks current difficulty, map selection screen settings (optionally), incompatible mutators and whether player is server --- to determine if a mutator can be enabled -local function can_be_enabled(self, ignore_map) - if #self:get_incompatible_mutators(true) > 0 then return false end - return player_is_server() and self:supports_current_difficulty(ignore_map) +-- Disables mutators that cannot be enabled right now +-- M, G +function vmf.disable_impossible_mutators(notify, everybody, reason) + local disabled_mutators = {} + for i = #_MUTATORS, 1, -1 do + local mutator = _MUTATORS[i] + if mutator:is_enabled() and not vmf.mutator_can_be_enabled(mutator) then + vmf.mod_state_changed(mutator:get_name(), false) + table.insert(disabled_mutators, mutator) + end + end + if #disabled_mutators > 0 and notify then + if not reason then reason = "" end + local loc = everybody and "broadcast_disabled_mutators" or "local_disabled_mutators" + local message = vmf:localize(loc) .. " " .. vmf:localize(reason) .. ":" + message = message .. " " .. vmf.add_mutator_titles_to_string(disabled_mutators, "", ", ", false) + if everybody then + vmf:chat_broadcast(message) + else + vmf:echo(message) + end + end + return disabled_mutators end -- Only checks difficulty -local function supports_current_difficulty(self, ignore_map) - local mutator_difficulty_levels = self:get_config().difficulty_levels +-- M, G +function vmf.mutator_supports_current_difficulty(mutator) + local mutator_difficulty_levels = vmf.get_mutator_config(mutator).difficulty_levels local actual_difficulty = Managers.state and Managers.state.difficulty:get_difficulty() - local right_difficulty = not actual_difficulty or table.has_item(mutator_difficulty_levels, actual_difficulty) + local right_difficulty = not actual_difficulty or table.contains(mutator_difficulty_levels, actual_difficulty) - local map_view = not ignore_map and mutators_view.map_view + local map_view = _MUTATORS_VIEW.map_view local map_view_active = map_view and map_view.active local right_unapplied_difficulty = false @@ -358,55 +309,39 @@ local function supports_current_difficulty(self, ignore_map) local difficulty_data = map_view.selected_level_index and map_view:get_difficulty_data(map_view.selected_level_index) local difficulty_layout = difficulty_data and difficulty_data[map_view.selected_difficulty_stepper_index] local difficulty_key = difficulty_layout and difficulty_layout.key - right_unapplied_difficulty = difficulty_key and table.has_item(mutator_difficulty_levels, difficulty_key) + right_unapplied_difficulty = difficulty_key and table.contains(mutator_difficulty_levels, difficulty_key) end return (map_view_active and right_unapplied_difficulty) or (not map_view_active and right_difficulty) end --- Returns the config object for mutator from mutators_config -local function get_config(self) - return mutators_config[self:get_name()] +-- Returns the config object for mutator from _MUTATORS_CONFIG +-- M, G +function vmf.get_mutator_config(mutator) + return _MUTATORS_CONFIG[mutator:get_name()] end --- Returns a list of incompatible with self mutators, all or only enabled ones -local function get_incompatible_mutators(self, enabled_only) - local incompatible_mutators = {} - for _, other_mutator in ipairs(mutators) do - if ( - other_mutator ~= self and - (not enabled_only or other_mutator:is_enabled()) and - not is_compatible(self, other_mutator) - ) then - table.insert(incompatible_mutators, other_mutator) - end - end - return incompatible_mutators -end +-- ########## +-- # GLOBAL # +-- ########## -- Turns a mod into a mutator -VMFMod.register_as_mutator = function(self, config) +function vmf.register_mod_as_mutator(mod, config) if not config then config = {} end - local mod_name = self:get_name() + table.insert(_MUTATORS, mod) - if table.has_item(mutators, self) then - self:error("Mod is already registered as mutator") - return - end - - table.insert(mutators, self) + local mod_name = mod:get_name() -- Save config - mutators_config[mod_name] = table.clone(default_config) - local _config = mutators_config[mod_name] + _MUTATORS_CONFIG[mod_name] = table.clone(_DEFAULT_CONFIG) + local _config = _MUTATORS_CONFIG[mod_name] for k, _ in pairs(_config) do if config[k] ~= nil then _config[k] = config[k] end end if _config.short_title == "" then _config.short_title = nil end - if _config.title == "" then _config.title = nil end if config.enable_before_these then update_mutators_sequence(mod_name, config.enable_before_these) @@ -418,42 +353,94 @@ VMFMod.register_as_mutator = function(self, config) end end - self.enable = enable_mutator - self.disable = disable_mutator - self.can_be_enabled = can_be_enabled - self.supports_current_difficulty = supports_current_difficulty + _MUTATORS_SORTED = false - self.get_config = get_config - self.get_incompatible_mutators = get_incompatible_mutators - - mutators_sorted = false - - -- Always init in the off state - self:init_state(false) - - mutators_view:update_mutator_list() + _MUTATORS_VIEW:update_mutator_list() end +-- Enables/disables mutator while preserving the sequence in which they were enabled +function vmf.set_mutator_state(mutator, state, initial_call) ---[[ - HOOKS -]]-- -manager:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) - manager.disable_impossible_mutators(true, true, "disabled_reason_difficulty_change") + -- Sort mutators if this is the first call + if not _MUTATORS_SORTED then + sort_mutators() + end + + local disabled_mutators = {} + local enable_these_after = _MUTATORS_SEQUENCE[mutator:get_name()] + + local i = get_index(_MUTATORS, mutator) + -- Disable mutators that were and are required to be enabled after the current one + -- This will be recursive so that if mutator2 requires mutator3 to be enabled after it, mutator3 will be disabled before mutator2 + -- Yeah this is super confusing + if enable_these_after and #_MUTATORS > i then + for j = #_MUTATORS, i + 1, -1 do + if _MUTATORS[j]:is_enabled() and table.contains(enable_these_after, _MUTATORS[j]:get_name()) then + --print("Disabled ", _MUTATORS[j]:get_name()) + vmf.set_mutator_state(_MUTATORS[j], false, false) + table.insert(disabled_mutators, 1, _MUTATORS[j]) + end + end + end + + -- Enable/disable current mutator + -- We're calling methods on the class object because we've overwritten them on the current one + vmf.set_mod_state(mutator, state, initial_call) + if state then + _ALL_MUTATORS_DISABLED = false + on_enabled(mutator) + else + on_disabled(mutator) + end + + -- Re-enable disabled mutators + -- This will be recursive + if #disabled_mutators > 0 then + for j = #disabled_mutators, 1, -1 do + --print("Enabled ", disabled_mutators[j]:get_name()) + vmf.set_mutator_state(disabled_mutators[j], true, false) + end + end +end + +-- Check if player is still hosting (on update) +function vmf.check_mutators_state() + if not _ALL_MUTATORS_DISABLED and not player_is_server() then + vmf.disable_impossible_mutators(true, false, "disabled_reason_not_server") + _ALL_MUTATORS_DISABLED = true + end +end + +-- Called only after VMF reloading to check if some mutators were enabled before reloading +function vmf.is_mutator_enabled(mutator_name) + return _ENABLED_MUTATORS[mutator_name] +end + +-- #################################################################################################################### +-- ##### Hooks ######################################################################################################## +-- #################################################################################################################### + +vmf:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) + vmf.disable_impossible_mutators(true, true, "disabled_reason_difficulty_change") return func(self, difficulty) end) +-- #################################################################################################################### +-- ##### Script ####################################################################################################### +-- #################################################################################################################### ---[[ - INITIALIZE ---]] +_DEFAULT_CONFIG = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config") + +_MUTATORS_VIEW = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui") +_DICE_MANAGER = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_dice") +_SET_LOBBY_DATA = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_info") + +_MUTATORS_GUI = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutators_gui") -- Initialize mutators view when map_view has been initialized already -mutators_view:init(mutators_view:get_map_view()) +_MUTATORS_VIEW:init(_MUTATORS_VIEW:get_map_view()) ---[[ - Testing ---]] --- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_test") --- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/mutation") --- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/deathwish") +-- Testing +--vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/mutator_test") +--vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/mutation") +--vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/deathwish") \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui.lua new file mode 100644 index 0000000..e69de29 diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/test/mutator_test.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/test/mutator_test.lua new file mode 100644 index 0000000..dccb67d --- /dev/null +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/test/mutator_test.lua @@ -0,0 +1,145 @@ +local vmf = get_mod("VMF") + +local mod_data + +---------------------------------------------------------------------------------- + +local mutator555 = new_mod("mutator555") +mod_data = {} +mod_data.name = "Legendary" +mod_data.description = "Legendary description" +mod_data.is_mutator = true +mod_data.mutator_setting = { + incompatible_with_all = true, + compatible_with = { + --"mutator3" + } + --title = "Legendary" +} +mutator555:initialize_data(mod_data) +mutator555.on_enabled = function(init_call) mutator555:echo("Legendary on_enabled(" .. (init_call and "init)" or ")")) end +mutator555.on_disabled = function(init_call) mutator555:echo("Legendary on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(mutator555) +---------------------------------------------------------------------------------- + +local mutator3 = new_mod("mutator3") +mod_data = {} +mod_data.name = "Something" +mod_data.is_mutator = true +mod_data.mutator_setting = { + incompatible_with = { + "mutator4" + }, + --title = "Something" +} +mutator3:initialize_data(mod_data) +mutator3.on_enabled = function(init_call) mutator3:echo("Something on_enabled(" .. (init_call and "init)" or ")")) end +mutator3.on_disabled = function(init_call) mutator3:echo("Something on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(mutator3) + +---------------------------------------------------------------------------------- + +local mutator2 = new_mod("mutator2") +mod_data = {} +mod_data.name = "?Deathwish" +mod_data.is_mutator = true +mod_data.mutator_setting = { + difficulty_levels = { + "hardest", + "survival_hardest" + }, + --title = "?Deathwish", + title_placement = "after" +} +mutator2:initialize_data(mod_data) +mutator2.on_enabled = function(init_call) mutator3:echo("?Deathwish on_enabled(" .. (init_call and "init)" or ")")) end +mutator2.on_disabled = function(init_call) mutator3:echo("?Deathwish on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(mutator2) + +---------------------------------------------------------------------------------- + +local slayer = new_mod("slayer") +mod_data = {} +mod_data.name = "Slayer's Oath" +mod_data.is_mutator = true +mod_data.mutator_setting = { + difficulty_levels = { + "survival_hard", + "survival_harder", + "survival_hardest" + }, + --title = "Slayer's Oath" +} +slayer:initialize_data(mod_data) +slayer.on_enabled = function(init_call) mutator3:echo("Slayer's Oath on_enabled(" .. (init_call and "init)" or ")")) end +slayer.on_disabled = function(init_call) mutator3:echo("Slayer's Oath on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(slayer) + +---------------------------------------------------------------------------------- + +local true_solo = new_mod("true_solo") +mod_data = {} +mod_data.name = "True Solo" +mod_data.is_mutator = true +mod_data.mutator_setting = { + compatible_with_all = true, + --title = "True Solo", + title_placement = "before" +} +true_solo:initialize_data(mod_data) +true_solo.on_enabled = function(init_call) mutator3:echo("True Solo on_enabled(" .. (init_call and "init)" or ")")) end +true_solo.on_disabled = function(init_call) mutator3:echo("True Solo on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(true_solo) + +---------------------------------------------------------------------------------- + +local onslaught = new_mod("onslaught") +mod_data = {} +mod_data.name = "Onslaught" +mod_data.is_mutator = true +--mod_data.mutator_setting = { +-- title = "Onslaught" +--} +onslaught:initialize_data(mod_data) +onslaught.on_enabled = function(init_call) mutator3:echo("Onslaught on_enabled(" .. (init_call and "init)" or ")")) end +onslaught.on_disabled = function(init_call) mutator3:echo("Onslaught on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(onslaught) + +---------------------------------------------------------------------------------- + +local one_hit_one_kill = new_mod("one_hit_one_kill") +mod_data = {} +mod_data.name = "One Hit One Kill" +mod_data.is_mutator = true +mod_data.mutator_setting = { + --title = "One Hit One Kill", + difficulty_levels = {"hardest"}, + enable_after_these = {"more_rat_weapons"} +} +one_hit_one_kill:initialize_data(mod_data) +one_hit_one_kill.on_enabled = function(init_call) mutator3:echo("One Hit One Kill on_enabled(" .. (init_call and "init)" or ")")) end +one_hit_one_kill.on_disabled = function(init_call) mutator3:echo("One Hit One Kill on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(one_hit_one_kill) + +---------------------------------------------------------------------------------- + +local more_rat_weapons = new_mod("more_rat_weapons") +mod_data = {} +mod_data.name = "More Rat Weapons" +mod_data.is_mutator = true +mod_data.mutator_setting = { + compatible_with_all = true, + --title = "More Rat Weapons", + difficulty_levels = {"hardest"} +} +more_rat_weapons:initialize_data(mod_data) +more_rat_weapons.on_enabled = function(init_call) mutator3:echo("More Rat Weapons on_enabled(" .. (init_call and "init)" or ")")) end +more_rat_weapons.on_disabled = function(init_call) mutator3:echo("More Rat Weapons on_disabled(" .. (init_call and "init)" or ")")) end +vmf.initialize_mod_state(more_rat_weapons) + +--[[for i=4,17 do + local mutator = new_mod("mutator" .. i) + mutator:register_as_mutator({}) + mutator.on_enabled = function(init_call) end + mutator.on_disabled = function(init_call) end +end--]] \ No newline at end of file diff --git a/vmf/scripts/mods/vmf/modules/ui/options/vmf_options_view.lua b/vmf/scripts/mods/vmf/modules/ui/options/vmf_options_view.lua index 647bf86..5d03a7d 100644 --- a/vmf/scripts/mods/vmf/modules/ui/options/vmf_options_view.lua +++ b/vmf/scripts/mods/vmf/modules/ui/options/vmf_options_view.lua @@ -3424,7 +3424,7 @@ VMFOptionsView.update_picked_option_for_settings_list_widgets = function (self) elseif widget_type == "header" then - widget_content.is_checkbox_checked = not vmf.disabled_mods_list[widget_content.mod_name] + widget_content.is_checkbox_checked = get_mod(widget_content.mod_name):is_enabled() elseif widget_type == "keybind" then @@ -3881,7 +3881,7 @@ vmf.load_vmf_options_view_settings() -- #################################################################################################################### -VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, readable_mod_name, mod_description) +vmf.create_options = function (mod, widgets_definition) local mod_settings_list_widgets_definitions = {} @@ -3892,7 +3892,7 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea local options_menu_collapsed_widgets = vmf:get("options_menu_collapsed_widgets") local mod_collapsed_widgets = nil if options_menu_collapsed_widgets then - mod_collapsed_widgets = options_menu_collapsed_widgets[self:get_name()] + mod_collapsed_widgets = options_menu_collapsed_widgets[mod:get_name()] end -- defining header widget @@ -3903,19 +3903,19 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea new_widget_definition.widget_type = "header" new_widget_definition.widget_index = new_widget_index - new_widget_definition.mod_name = self:get_name() - new_widget_definition.readable_mod_name = readable_mod_name or self:get_name() - new_widget_definition.tooltip = mod_description + new_widget_definition.mod_name = mod:get_name() + new_widget_definition.readable_mod_name = mod:get_readable_name() + new_widget_definition.tooltip = mod:get_description() new_widget_definition.default = true - new_widget_definition.is_mod_toggable = is_mod_toggable + new_widget_definition.is_mod_toggable = mod:is_togglable() and not mod:is_mutator() if mod_collapsed_widgets then - new_widget_definition.is_widget_collapsed = mod_collapsed_widgets[self:get_name()] + new_widget_definition.is_widget_collapsed = mod_collapsed_widgets[mod:get_name()] end if options_menu_favorite_mods then for _, current_mod_name in pairs(options_menu_favorite_mods) do - if current_mod_name == self:get_name() then + if current_mod_name == mod:get_name() then new_widget_definition.is_favorited = true break end @@ -3950,7 +3950,7 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea new_widget_definition.widget_type = current_widget.widget_type -- all new_widget_definition.widget_index = new_widget_index -- all [gen] new_widget_definition.widget_level = level -- all [gen] - new_widget_definition.mod_name = self:get_name() -- all [gen] + new_widget_definition.mod_name = mod:get_name() -- all [gen] new_widget_definition.setting_name = current_widget.setting_name -- all new_widget_definition.text = current_widget.text -- all new_widget_definition.tooltip = current_widget.tooltip -- all [optional] @@ -3967,15 +3967,15 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea new_widget_definition.is_widget_collapsed = mod_collapsed_widgets[current_widget.setting_name] end - if type(self:get(current_widget.setting_name)) == "nil" then - self:set(current_widget.setting_name, current_widget.default_value) + if type(mod:get(current_widget.setting_name)) == "nil" then + mod:set(current_widget.setting_name, current_widget.default_value) end if current_widget.widget_type == "keybind" then - local keybind = self:get(current_widget.setting_name) + local keybind = mod:get(current_widget.setting_name) new_widget_definition.keybind_text = build_keybind_string(keybind) if current_widget.action then - self:keybind(current_widget.setting_name, current_widget.action, keybind) + mod:keybind(current_widget.setting_name, current_widget.action, keybind) end end @@ -4034,7 +4034,7 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea end if new_widget_index == 257 then - self:error("(vmf_options_view) The limit of 256 options widgets was reached. You can't add any more widgets.") + mod:error("(vmf_options_view) The limit of 256 options widgets was reached. You can't add any more widgets.") end end @@ -4135,6 +4135,7 @@ vmf.disable_mods_options_button = function () change_mods_options_button_state("disable") end +-- @BUG: Game crashes occasionaly here. See attached log -- create mods options menu button in Esc-menu vmf:hook("IngameView.setup_button_layout", function (func, self, layout_data) diff --git a/vmf/scripts/mods/vmf/modules/vmf_options.lua b/vmf/scripts/mods/vmf/modules/vmf_options.lua index ca662a2..504e426 100644 --- a/vmf/scripts/mods/vmf/modules/vmf_options.lua +++ b/vmf/scripts/mods/vmf/modules/vmf_options.lua @@ -1,6 +1,8 @@ local vmf = get_mod("VMF") -local options_widgets = { +local vmf_mod_data = {} +vmf_mod_data.name = "Vermintide Mod Framework" +vmf_mod_data.options_widgets = { { ["setting_name"] = "open_vmf_options", ["widget_type"] = "keybind", @@ -268,7 +270,7 @@ end -- ##### Script ####################################################################################################### -- #################################################################################################################### -vmf:create_options(options_widgets, false, "Vermintide Mod Framework") +vmf:initialize_data(vmf_mod_data) -- first VMF initialization -- it will be run only 1 time, when the player launch the game with VMF for the first time diff --git a/vmf/scripts/mods/vmf/vmf_loader.lua b/vmf/scripts/mods/vmf/vmf_loader.lua index 49c9a4f..d8439b5 100644 --- a/vmf/scripts/mods/vmf/vmf_loader.lua +++ b/vmf/scripts/mods/vmf/vmf_loader.lua @@ -1,12 +1,14 @@ return { init = function(object) - dofile("scripts/mods/vmf/functions/table") + Managers.vmf = Managers.vmf or {} dofile("scripts/mods/vmf/modules/mods") dofile("scripts/mods/vmf/modules/core/events") dofile("scripts/mods/vmf/modules/core/settings") dofile("scripts/mods/vmf/modules/core/core_functions") + dofile("scripts/mods/vmf/modules/core/initialization") + dofile("scripts/mods/vmf/modules/core/persistent_tables") dofile("scripts/mods/vmf/modules/debug/dev_console") dofile("scripts/mods/vmf/modules/debug/table_dump") dofile("scripts/mods/vmf/modules/core/hooks") @@ -35,7 +37,8 @@ return { end) -- temporary solution: - dofile("scripts/mods/vmf/modules/testing_stuff_here") + local mod = new_mod("test_mod") + mod:initialize("scripts/mods/vmf/modules/testing_stuff_here") end, update = function(object, dt) @@ -43,6 +46,7 @@ return { object.vmf.mods_update_event(dt) object.vmf.check_pressed_keybinds() object.vmf.check_custom_menus_close_keybinds(dt) + object.vmf.check_mutators_state() if not object.vmf.all_mods_were_loaded and Managers.mod._state == "done" then @@ -79,9 +83,9 @@ return { object.vmf.save_unsaved_settings_to_file() object.vmf.apply_delayed_hooks() - if status == "exit" and state == "StateTitleScreen" then - object.vmf.hook_chat_manager() - end + --if status == "exit" and state == "StateTitleScreen" then + -- object.vmf.hook_chat_manager() + --end if status == "enter" and state == "StateIngame" then object.vmf.initialize_keybinds()