Mutators module reworking

1) Fixed delayed chat messages
2) mod:is_togglable()
3) Keybind action "toggle_mod" -> "toggle_mod_state"
4) mod:persistent_table("name")
5) Removed "enable" and "disable" methods
6) Now all mod data is stored in mod._data
7) New way of initialization mod and initialization data
8) Mutators will be run after reload (also note init_state)
9) Removed table.lua
10) Lots of small changes and fixes
This commit is contained in:
Unknown 2018-04-19 04:21:49 +03:00
parent 92005e0340
commit 4853ebccf4
26 changed files with 808 additions and 717 deletions

Binary file not shown.

View file

@ -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"
}
}

View file

@ -187,4 +187,85 @@ return {
en = "Developer console closed.", en = "Developer console closed.",
ru = "Консоль разработчика закрыта.", 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"
}
} }

View file

@ -1,33 +1,38 @@
-- Image Source: ../test -- Image Source:
return { return {
header_fav_arrow = { header_fav_arrow = {
size = { 48, 48, }, size = { 48, 48, },
uv00 = { 0.187500, 0.687500, }, uv00 = { 0.181641, 0.880859, },
uv11 = { 0.375000, 0.875000, }, uv11 = { 0.228516, 0.974609, },
}, },
header_fav_icon = { header_fav_icon = {
size = { 48, 48, }, size = { 48, 48, },
uv00 = { 0.187500, 0.500000, }, uv00 = { 0.130859, 0.880859, },
uv11 = { 0.375000, 0.687500, }, uv11 = { 0.177734, 0.974609, },
},
search_bar_icon = {
size = { 48, 48, },
uv00 = { 0.000000, 0.687500, },
uv11 = { 0.187500, 0.875000, },
}, },
header_fav_icon_lit = { header_fav_icon_lit = {
size = { 48, 48, }, size = { 48, 48, },
uv00 = { 0.000000, 0.500000, }, uv00 = { 0.052734, 0.880859, },
uv11 = { 0.187500, 0.687500, }, uv11 = { 0.099609, 0.974609, },
}, },
mutator_button = { search_bar_icon = {
size = { 128, 128, }, size = { 48, 48, },
uv00 = { 0.500000, 0.000000, }, uv00 = { 0.001953, 0.880859, },
uv11 = { 1.000000, 0.500000, }, uv11 = { 0.048828, 0.974609, },
}, },
mutator_button_hover = { map_view_party_button = {
size = { 128, 128, }, size = { 128, 128, },
uv00 = { 0.000000, 0.000000, }, uv00 = { 0.130859, 0.623047, },
uv11 = { 0.500000, 0.500000, }, 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, },
}, },
} }

View file

@ -14,7 +14,6 @@ lua = [
"localization/*" "localization/*"
"scripts/mods/vmf/*" "scripts/mods/vmf/*"
"scripts/mods/vmf/functions/*"
"scripts/mods/vmf/modules/*" "scripts/mods/vmf/modules/*"
"scripts/mods/vmf/modules/core/*" "scripts/mods/vmf/modules/core/*"
"scripts/mods/vmf/modules/debug/*" "scripts/mods/vmf/modules/debug/*"
@ -22,6 +21,7 @@ lua = [
"scripts/mods/vmf/modules/ui/options/*" "scripts/mods/vmf/modules/ui/options/*"
"scripts/mods/vmf/modules/ui/chat/*" "scripts/mods/vmf/modules/ui/chat/*"
"scripts/mods/vmf/modules/ui/mutators/*" "scripts/mods/vmf/modules/ui/mutators/*"
"scripts/mods/vmf/modules/ui/mutators/test/*"
"materials/vmf/vmf_atlas" "materials/vmf/vmf_atlas"
] ]

View file

@ -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

View file

@ -175,7 +175,7 @@ end
-- #################################################################################################################### -- ####################################################################################################################
-- ##### VMF internal functions and variables ######################################################################### -- ##### 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, ...) vmf.check_wrong_argument_type = function(mod, vmf_function_name, argument_name, argument, ...)
local allowed_types = {...} local allowed_types = {...}

View file

@ -1,34 +1,20 @@
-- @TODO: do I need to hook it at all?
local vmf = get_mod("VMF") local vmf = get_mod("VMF")
-- #################################################################################################################### -- ####################################################################################################################
-- ##### Hooks Functions ############################################################################################## -- ##### Hooks ########################################################################################################
-- #################################################################################################################### -- ####################################################################################################################
-- HOOK: [ChatManager.register_channel] vmf:hook("ChatManager.register_channel", function (func, self, channel_id, members_func)
local hook_send_unsent_messages = function (func, self, channel_id, members_func)
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 for _, message in ipairs(vmf.unsent_chat_messages) do
self:add_local_system_message(1, message, true) self:add_local_system_message(1, message, true)
end end
for i, _ in ipairs(vmf.unsent_chat_messages) do
vmf.unsent_chat_messages[i] = nil
end
end 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

View file

@ -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

View file

@ -14,6 +14,8 @@ local _RAW_KEYBINDS = {}
-- ["primary_key"] = {{"mod_name", "action_name", ctrl_used(bool), alt_used(bool), shift_used(bool)}, {}, {}, ...} -- ["primary_key"] = {{"mod_name", "action_name", ctrl_used(bool), alt_used(bool), shift_used(bool)}, {}, {}, ...}
local _OPTIMIZED_KEYBINDS = {} local _OPTIMIZED_KEYBINDS = {}
local _ACTIVATED_PRESSED_KEY
-- #################################################################################################################### -- ####################################################################################################################
-- ##### Local functions ############################################################################################## -- ##### Local functions ##############################################################################################
-- #################################################################################################################### -- ####################################################################################################################
@ -101,11 +103,11 @@ vmf.check_pressed_keybinds = function()
if input_service then if input_service then
-- don't check for the pressed keybindings until player will release already pressed keybind -- don't check for the pressed keybindings until player will release already pressed keybind
if vmf.activated_pressed_key then if _ACTIVATED_PRESSED_KEY then
if input_service:get(vmf.activated_pressed_key) then if input_service:get(_ACTIVATED_PRESSED_KEY) then
return return
else else
vmf.activated_pressed_key = nil _ACTIVATED_PRESSED_KEY = nil
end end
end end
@ -120,12 +122,12 @@ vmf.check_pressed_keybinds = function()
local mod = get_mod(binding_info[1]) 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()) vmf.mod_state_changed(mod:get_name(), not mod:is_enabled())
key_has_active_keybind = true key_has_active_keybind = true
vmf.activated_pressed_key = key _ACTIVATED_PRESSED_KEY = key
elseif mod:is_enabled() then elseif mod:is_enabled() then
@ -140,7 +142,7 @@ vmf.check_pressed_keybinds = function()
end end
key_has_active_keybind = true key_has_active_keybind = true
vmf.activated_pressed_key = key _ACTIVATED_PRESSED_KEY = key
end end
end end
end end

View file

@ -82,11 +82,11 @@ VMFMod.localize = function (self, text_id, ...)
end end
end end
end end
return "<" .. tostring(text_id) .. ">"
else else
self:error("(localize): localization file was not loaded for this mod") self:error("(localize): localization file was not loaded for this mod")
end end
return "<" .. tostring(text_id) .. ">"
end end
-- #################################################################################################################### -- ####################################################################################################################

View file

@ -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")

View file

@ -1,77 +1,60 @@
local vmf = get_mod("VMF") local vmf = get_mod("VMF")
local _DISABLED_MODS_LIST = vmf:get("disabled_mods_list") or {} local _DISABLED_MODS = 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
-- #################################################################################################################### -- ####################################################################################################################
-- ##### VMF internal functions and variables ######################################################################### -- ##### 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) vmf.mod_state_changed = function (mod_name, is_enabled)
local mod = get_mod(mod_name) local mod = get_mod(mod_name)
if is_enabled then if not mod:is_togglable() or is_enabled == mod:is_enabled() then
mod:enable() return
end
if mod:is_mutator() then
vmf.set_mutator_state(mod, is_enabled, false)
else else
mod:disable() vmf.set_mod_state(mod, is_enabled, false)
end end
end end

View file

@ -38,11 +38,39 @@ end
VMFMod = class(VMFMod) VMFMod = class(VMFMod)
VMFMod.init = function (self, mod_name) 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 end
-- DATA
VMFMod.get_name = function (self) 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 end
-- #################################################################################################################### -- ####################################################################################################################

View file

@ -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", ["setting_name"] = "game_mode",
["widget_type"] = "dropdown", ["widget_type"] = "dropdown",
@ -106,8 +111,7 @@ local options_widgets = {
["default_value"] = 0 ["default_value"] = 0
} }
} }
mod:initialize_data(mod_data)
mod:create_options(options_widgets, true, "Test", "Mod description")
mod:command("whatever", "description whatever", function() mod:echo("whatever") end) mod:command("whatever", "description whatever", function() mod:echo("whatever") end)
mod:command("what", "description what", function() mod:echo("what") 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("whoa", "description whoa", function() mod:echo("whoa") end)
mod:command("wheat", "description wheat", function() mod:echo("wheat") 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) 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 -- 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.whatever = function ()
--mod:echo("whatever") --mod:echo("whatever")
@ -154,6 +175,27 @@ mod.whatever = function ()
--mod.custom_mod_rpc() --mod.custom_mod_rpc()
end end
--ingame_ui.handle_transition(ingame_ui, "leave_group") --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(...) 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.bla", mod.game_state_changed)
--mod:hook("bla.bla2", mod.game_state_changed) --mod:hook("bla.bla2", mod.game_state_changed)
--mod:hook("bla.bla3", 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.bla", mod.game_state_changed)
--mod3:hook("bla.bla2", mod.game_state_changed) --mod3:hook("bla.bla2", mod.game_state_changed)
--mod3:hook("bla.bla3", 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) mod:hook("ChatManager.rpc_chat_message", function (func, self, sender, channel_id, message_sender, message, localization_param, is_system_message, pop_chat, is_dev)

View file

@ -4,8 +4,7 @@ return {
tomes = 0, tomes = 0,
bonus = 0 bonus = 0
}, },
title = "", short_title = "", --@TODO: rename it?
short_title = "",
title_placement = "after", title_placement = "after",
description = "No description provided", description = "No description provided",
difficulty_levels = { difficulty_levels = {

View file

@ -1,6 +1,5 @@
--[[ Add additional dice to end game roll --]] --[[ Add additional dice to end game roll --]]
local vmf = get_mod("VMF")
local manager = get_mod("vmf_mutator_manager")
-- List of all die types -- List of all die types
local missions = { local missions = {
@ -16,7 +15,7 @@ local num_dice_per_mission = {
grimoire_hidden_mission = 0 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 num_dice = 0
local max_dice = 7 local max_dice = 7
local mission_system = Managers.state.entity:system("mission_system") 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 -- Get total number of dice
for name, obj in pairs(active_mission) do 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 num_dice = num_dice + obj.current_amount
end end
end end

View file

@ -1,14 +1,15 @@
--[[ Add mutators panel to the map view --]] --[[ 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 = vmf.mutators
local mutators = manager.mutators
--manager:custom_textures("mutator_button", "mutator_button_hover") --vmf:custom_textures("mutator_button", "mutator_button_hover")
--manager:inject_materials("ingame_ui", "materials/vmf/mutator_button", "materials/vmf/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 = { local mutators_view = {
@ -29,17 +30,17 @@ local mutators_view = {
self:update_mutator_list() self:update_mutator_list()
-- Recreate the map_view scenegraph defs -- 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 -- Setup custom widgets
self.widgets = { self.widgets = {
banner_mutators = UIWidget.init(definitions.new_widgets.banner_mutators_widget), banner_mutators = UIWidget.init(_DEFINITIONS.new_widgets.banner_mutators_widget),
mutators_button = UIWidget.init(definitions.new_widgets.mutators_button_widget), mutators_button = UIWidget.init(_DEFINITIONS.new_widgets.mutators_button_widget),
no_mutators_text = UIWidget.init(definitions.new_widgets.no_mutators_text_widget) no_mutators_text = UIWidget.init(_DEFINITIONS.new_widgets.no_mutators_text_widget)
} }
for i = 1, PER_PAGE do for i = 1, _PER_PAGE do
table.insert(self.mutator_checkboxes, UIWidget.init(definitions.new_widgets["mutator_checkbox_" .. i])) table.insert(self.mutator_checkboxes, UIWidget.init(_DEFINITIONS.new_widgets["mutator_checkbox_" .. i]))
end end
-- Save widgets we're gonna mess with -- Save widgets we're gonna mess with
@ -102,8 +103,8 @@ local mutators_view = {
-- Sorts mutators by title -- Sorts mutators by title
update_mutator_list = function(self) update_mutator_list = function(self)
self.mutators_sorted = {} self.mutators_sorted = {}
for _, mutator in ipairs(mutators) do for _, mutator in ipairs(_MUTATORS) do
table.insert(self.mutators_sorted, {mutator:get_name(), mutator:get_config().title or mutator:get_name()}) table.insert(self.mutators_sorted, {mutator:get_name(), mutator:get_readable_name()})
end end
table.sort(self.mutators_sorted, function(a, b) return string.lower(a[2]) < string.lower(b[2]) end) table.sort(self.mutators_sorted, function(a, b) return string.lower(a[2]) < string.lower(b[2]) end)
end, end,
@ -160,9 +161,9 @@ local mutators_view = {
local widgets = self.map_view.normal_settings_widget_types 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 checkbox = self.mutator_checkboxes[i]
local hotspot = checkbox.content.button_hotspot local hotspot = checkbox.content.button_hotspot
@ -189,7 +190,7 @@ local mutators_view = {
widgets.survival["mutator_checkbox_" .. i] = checkbox widgets.survival["mutator_checkbox_" .. i] = checkbox
-- Set colors based on whether mutator can be enabled -- 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 = active and "cheeseburger" or "slate_gray"
local color_hover = active and "white" 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) 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 if hotspot.on_release then
self.map_view:play_sound("Play_hud_select") self.map_view:play_sound("Play_hud_select")
if mutator:is_enabled() then if mutator:is_enabled() then
mutator:disable() vmf.mod_state_changed(mutator:get_name(), false)
else else
mutator:enable() vmf.mod_state_changed(mutator:get_name(), true)
end end
end end
@ -215,7 +216,7 @@ local mutators_view = {
end end
end end
if #mutators == 0 then if #_MUTATORS == 0 then
widgets.adventure["no_mutators_text"] = self.widgets.no_mutators_text widgets.adventure["no_mutators_text"] = self.widgets.no_mutators_text
widgets.survival["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 -- Update steppers
local level_stepper_widget = self.map_view.steppers.level.widget 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.setting_text.offset[2] = -10000
level_stepper_widget.style.hover_texture.offset[2] = -10000 level_stepper_widget.style.hover_texture.offset[2] = -10000
level_stepper_widget.content.left_button_hotspot.disable_button = num_pages <= 1 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() self.map_view:update_level_stepper()
-- Mutator checkboxes -- Mutator checkboxes
for i = 1, PER_PAGE do for i = 1, _PER_PAGE do
widgets.adventure["mutator_checkbox_" .. i] = nil widgets.adventure["mutator_checkbox_" .. i] = nil
widgets.survival["mutator_checkbox_" .. i] = nil widgets.survival["mutator_checkbox_" .. i] = nil
end end
@ -300,7 +301,7 @@ local mutators_view = {
if self.active then if self.active then
local current_index = self.current_page local current_index = self.current_page
local new_index = current_index + index_change 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 if new_index < 1 then
new_index = num_pages new_index = num_pages
@ -316,48 +317,47 @@ local mutators_view = {
-- Creates and return text for checkbox tooltip -- Creates and return text for checkbox tooltip
generate_tooltip_for = function(self, mutator) generate_tooltip_for = function(self, mutator)
local config = mutator:get_config() local config = vmf.get_mutator_config(mutator)
local text = "" local text = ""
-- Show supported difficulty when can't be enabled due to difficulty level -- 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 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 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
end end
-- Show enabled incompatible -- 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 local currently_compatible = #incompatible_mutators == 0
-- Or all incompatible if difficulty is compatible -- Or all incompatible if difficulty is compatible
if supports_difficulty and #incompatible_mutators == 0 then if supports_difficulty and #incompatible_mutators == 0 then
incompatible_mutators = mutator:get_incompatible_mutators() incompatible_mutators = vmf.get_incompatible_mutators(mutator)
end end
if #incompatible_mutators > 0 then 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 -- 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 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 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 ", ") .. other_mutator:get_readable_name()
text = text .. (i == 1 and " " or ", ") .. name
end end
end end
elseif config.compatible_with_all then elseif config.compatible_with_all then
-- Special message when compatible with all -- 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 end
-- Special message if switched to unsupported difficulty level -- Special message if switched to unsupported difficulty level
if mutator:is_enabled() and not supports_difficulty then 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 end
-- Description -- Description
@ -372,13 +372,13 @@ local mutators_view = {
setup_hooks = function(self) setup_hooks = function(self)
-- Update the view after map_view has updated -- 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) func(map_view, dt, t)
self:update(dt, t) self:update(dt, t)
end) end)
-- Activate the view on enter if it was active on exit -- 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) func(map_view)
if self.was_active then if self.was_active then
self.widgets.mutators_button.content.toggled = true self.widgets.mutators_button.content.toggled = true
@ -387,47 +387,47 @@ local mutators_view = {
end) end)
-- Deactivate the view on exit -- 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) func(map_view)
self:deactivate() self:deactivate()
end) end)
-- We don't want to let the game disable steppers when mutators view is active -- 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 if not self.active then
func(map_view) func(map_view)
end end
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, ...) func(map_view, ...)
print("on_level_index_changed") print("on_level_index_changed")
manager.disable_impossible_mutators(true) vmf.disable_impossible_mutators(true)
end) 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, ...) func(map_view, ...)
print("on_difficulty_index_changed") print("on_difficulty_index_changed")
manager.disable_impossible_mutators(true) vmf.disable_impossible_mutators(true)
end) 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, ...) func(map_view, ...)
print("set_difficulty_stepper_index") print("set_difficulty_stepper_index")
manager.disable_impossible_mutators(true) vmf.disable_impossible_mutators(true)
end) end)
--]] --]]
end, end,
reset_hooks = function(self) reset_hooks = function(self)
manager:hook_remove("MapView.update") vmf:hook_remove("MapView.update")
manager:hook_remove("MapView.on_enter") vmf:hook_remove("MapView.on_enter")
manager:hook_remove("MapView.on_exit") vmf:hook_remove("MapView.on_exit")
manager:hook_remove("MapView.update_level_stepper") vmf:hook_remove("MapView.update_level_stepper")
-- manager:hook_remove("MapView.on_level_index_changed") -- vmf:hook_remove("MapView.on_level_index_changed")
-- manager:hook_remove("MapView.on_difficulty_index_changed") -- vmf:hook_remove("MapView.on_difficulty_index_changed")
-- manager:hook_remove("MapView.set_difficulty_stepper_index") -- vmf:hook_remove("MapView.set_difficulty_stepper_index")
end, end,
get_map_view = function(self) get_map_view = function(self)
@ -437,13 +437,13 @@ local mutators_view = {
} }
-- Initialize mutators view after map view -- Initialize mutators view after map view
manager:hook("MapView.init", function(func, self, ...) vmf:hook("MapView.init", function(func, self, ...)
func(self, ...) func(self, ...)
mutators_view:init(self) mutators_view:init(self)
end) end)
-- Destroy mutators view after map view -- Destroy mutators view after map view
manager:hook("MapView.destroy", function(func, ...) vmf:hook("MapView.destroy", function(func, ...)
mutators_view:deinitialize() mutators_view:deinitialize()
func(...) func(...)
end) end)

View file

@ -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 definitions = local_require("scripts/ui/views/map_view_definitions")
local scenegraph_definition = definitions.scenegraph_definition local scenegraph_definition = definitions.scenegraph_definition
@ -58,8 +58,8 @@ local new_widgets = {
-- This will replace the banner behind the Mission text -- This will replace the banner behind the Mission text
banner_mutators_widget = UIWidgets.create_texture_with_text_and_tooltip( banner_mutators_widget = UIWidgets.create_texture_with_text_and_tooltip(
"title_bar", "title_bar",
manager:localize("mutators_title"), vmf:localize("mutators_title"),
manager:localize("mutators_banner_tooltip"), vmf:localize("mutators_banner_tooltip"),
"banner_level", "banner_level",
"banner_mutators_text", { "banner_mutators_text", {
vertical_alignment = "center", vertical_alignment = "center",
@ -96,10 +96,10 @@ local new_widgets = {
toggle_texture = "octagon_button_toggled", toggle_texture = "octagon_button_toggled",
hover_texture = "octagon_button_hover", hover_texture = "octagon_button_hover",
normal_texture = "octagon_button_normal", normal_texture = "octagon_button_normal",
icon_texture = "mutator_button", icon_texture = "map_view_party_button",
icon_hover_texture = "mutator_button_hover", icon_hover_texture = "map_view_party_button_lit",
tooltip_text = manager:localize("mutators_title"), tooltip_text = vmf:localize("mutators_title"),
toggled_tooltip_text = manager:localize("mutators_title"), toggled_tooltip_text = vmf:localize("mutators_title"),
button_hotspot = {} button_hotspot = {}
}, },
style = { style = {
@ -224,8 +224,8 @@ local new_widgets = {
} }
}, },
content = { content = {
text = manager:localize("no_mutators"), text = vmf:localize("no_mutators"),
tooltip_text = manager:localize("no_mutators_tooltip"), tooltip_text = vmf:localize("no_mutators_tooltip"),
tooltip_hotspot = {}, tooltip_hotspot = {},
color = Colors.get_color_table_with_alpha("slate_gray", 255) color = Colors.get_color_table_with_alpha("slate_gray", 255)
}, },

View file

@ -1,7 +1,7 @@
--[[ Notify players of enabled mutators via chat and tab menu --]] --[[ Notify players of enabled mutators via chat and tab menu --]]
local vmf = get_mod("VMF")
local manager = get_mod("vmf_mutator_manager") local mutators = vmf.mutators
local mutators = manager.mutators
local were_enabled_before = false local were_enabled_before = false
@ -13,17 +13,17 @@ local function add_enabled_mutators_titles_to_string(str, separator, short)
table.insert(_mutators, mutator) table.insert(_mutators, mutator)
end end
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 end
-- Sets the lobby name -- Sets the lobby name
local function set_lobby_data() local function set_lobby_data()
if ( if (
not Managers.matchmaking or not Managers.matchmaking or
not Managers.matchmaking.lobby or not Managers.matchmaking.lobby or
not Managers.matchmaking.lobby.set_lobby_data 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 ) then return end
local name = add_enabled_mutators_titles_to_string("", " ", true) 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) Managers.matchmaking.lobby:set_lobby_data(lobby_data)
end end
--@TODO: maybe rewrite?
local function get_peer_id_from_cookie(client_cookie) local function get_peer_id_from_cookie(client_cookie)
local peer_id = tostring(client_cookie) local peer_id = tostring(client_cookie)
for _ = 1, 3 do for _ = 1, 3 do
@ -55,12 +56,20 @@ local function get_peer_id_from_cookie(client_cookie)
end end
-- Append difficulty name with enabled mutators' titles -- 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_settings = Managers.state.difficulty:get_difficulty_settings()
local difficulty_name = difficulty_settings.display_name local difficulty_name = difficulty_settings.display_name
local name = not self.is_in_inn and Localize(difficulty_name) or "" --local name = not self.is_in_inn and Localize(difficulty_name) or ""
name = add_enabled_mutators_titles_to_string(name, " ", true) --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) self.set_difficulty_name(self, name)
@ -68,25 +77,25 @@ manager:hook("IngamePlayerListUI.update_difficulty", function(func, self)
end) end)
-- Notify everybody about enabled/disabled mutators when Play button is pressed on the map screen -- 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, ...) func(self, ...)
set_lobby_data() set_lobby_data()
local names = add_enabled_mutators_titles_to_string("", ", ") local names = add_enabled_mutators_titles_to_string("", ", ")
if string.len(names) > 0 then 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 were_enabled_before = true
elseif were_enabled_before then 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 were_enabled_before = false
end end
end) end)
-- Send special messages with enabled mutators list to players just joining the lobby -- 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("", ", ") local name = add_enabled_mutators_titles_to_string("", ", ")
if string.len(name) > 0 then if string.len(name) > 0 then
local message = manager:localize("whisper_enabled_mutators") .. ": " .. name local message = vmf:localize("whisper_enabled_mutators") .. ": " .. name
manager:chat_whisper(get_peer_id_from_cookie(client_cookie), message) vmf:chat_whisper(get_peer_id_from_cookie(client_cookie), message)
end end
func(self, sender, client_cookie, host_cookie, lobby_id, friend_join) func(self, sender, client_cookie, host_cookie, lobby_id, friend_join)
end) end)

View file

@ -1,21 +1,17 @@
--[[ Add ability to turn mods into mutators --]] --[[ Add ability to turn mods into mutators --]]
local vmf = get_mod("VMF")
local manager = new_mod("vmf_mutator_manager")
manager:localization("localization/mutator_manager")
-- List of mods that are also mutators in order in which they should be enabled -- List of mods that are also mutators in order in which they should be enabled
-- This is populated via VMFMod.register_as_mutator -- This is populated via vmf.register_mod_as_mutator
manager.mutators = {} local _MUTATORS = {}
local mutators = manager.mutators
-- Table of mutators' configs by name -- Table of mutators' configs by name
local mutators_config = {} local _MUTATORS_CONFIG = {}
local default_config = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config") local _DEFAULT_CONFIG
-- This lists mutators and which ones should be enabled after them -- This lists mutators and which ones should be enabled after them
-- This is populated via VMFMod.register_as_mutator -- This is populated via vmf.register_mod_as_mutator
local mutators_sequence = { local _MUTATORS_SEQUENCE = {
--[[ --[[
this_mutator = { this_mutator = {
"will be enabled", "will be enabled",
@ -25,59 +21,71 @@ local mutators_sequence = {
} }
-- So we don't sort after each one is added -- 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 -- 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
--[[ local _MUTATORS_GUI
PRIVATE METHODS
]]--
local mutators_view = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_gui") -- List of enabled mutators in case VMF is reloaded in the middle of the game
local dice_manager = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_dice") local _ENABLED_MUTATORS = vmf:persistent_table("enabled_mutators")
local set_lobby_data = manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_info")
-- ####################################################################################################################
-- ##### 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 -- 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) local function update_mutators_sequence(mutator_name, enable_these_after)
if not mutators_sequence[mutator_name] then if not _MUTATORS_SEQUENCE[mutator_name] then
mutators_sequence[mutator_name] = {} _MUTATORS_SEQUENCE[mutator_name] = {}
end end
for _, other_mutator_name in ipairs(enable_these_after) do 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 if _MUTATORS_SEQUENCE[other_mutator_name] and table.contains(_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.") vmf:error("(mutators): Mutators '%s' and '%s' are both set to load after each other.", mutator_name, other_mutator_name)
elseif not table.has_item(mutators_sequence[mutator_name], other_mutator_name) then elseif not table.contains(_MUTATORS_SEQUENCE[mutator_name], other_mutator_name) then
table.insert(mutators_sequence[mutator_name], other_mutator_name) table.insert(_MUTATORS_SEQUENCE[mutator_name], other_mutator_name)
end end
end end
table.combine(mutators_sequence[mutator_name], enable_these_after)
end end
-- Checks if mutators are compatible both ways -- Checks if mutators are compatible both ways
local function is_compatible(mutator, other_mutator) 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 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 other_name = other_mutator:get_name()
local incompatible_specifically = ( local incompatible_specifically = (
#config.incompatible_with > 0 and ( #config.incompatible_with > 0 and (
table.has_item(config.incompatible_with, other_name) table.contains(config.incompatible_with, other_name)
) or ) or
#other_config.incompatible_with > 0 and ( #other_config.incompatible_with > 0 and (
table.has_item(other_config.incompatible_with, name) table.contains(other_config.incompatible_with, name)
) )
) )
local compatible_specifically = ( local compatible_specifically = (
#config.compatible_with > 0 and ( #config.compatible_with > 0 and (
table.has_item(config.compatible_with, other_name) table.contains(config.compatible_with, other_name)
) or ) or
#other_config.compatible_with > 0 and ( #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 -- Called after mutator is enabled
local function on_enabled(mutator) local function on_enabled(mutator)
local config = mutator:get_config() local config = vmf.get_mutator_config(mutator)
dice_manager.addDice(config.dice) _DICE_MANAGER.addDice(config.dice)
set_lobby_data() _SET_LOBBY_DATA()
print("[MUTATORS] Enabled " .. mutator:get_name() .. " (" .. tostring(table.index_of(mutators, mutator)) .. ")") print("[MUTATORS] Enabled " .. mutator:get_name() .. " (" .. tostring(get_index(_MUTATORS, mutator)) .. ")")
_ENABLED_MUTATORS[mutator:get_name()] = true
end end
-- Called after mutator is disabled -- Called after mutator is disabled
local function on_disabled(mutator) local function on_disabled(mutator)
local config = mutator:get_config() local config = vmf.get_mutator_config(mutator)
dice_manager.removeDice(config.dice) _DICE_MANAGER.removeDice(config.dice)
set_lobby_data() _SET_LOBBY_DATA()
print("[MUTATORS] Disabled " .. mutator:get_name() .. " (" .. tostring(table.index_of(mutators, mutator)) .. ")") print("[MUTATORS] Disabled " .. mutator:get_name() .. " (" .. tostring(get_index(_MUTATORS, mutator)) .. ")")
end
-- Enables/disables mutator while preserving the sequence in which they were enabled _ENABLED_MUTATORS[mutator:get_name()] = nil
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
end end
-- Checks if the player is server in a way that doesn't incorrectly return false during loading screens -- 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 return not player or player.is_server or not state or state.game_mode == nil
end end
--[[
PUBLIC METHODS
]]--
-- Sorts mutators in order they should be enabled -- 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 -- -- LOG --
manager:dump(mutators_sequence, "seq", 5) vmf:dump(_MUTATORS_SEQUENCE, "seq", 5)
for i, v in ipairs(mutators) do for i, v in ipairs(mutators) do
print(i, v:get_name()) print(i, v:get_name())
end end
@ -201,26 +148,26 @@ manager.sort_mutators = function()
--]] --]]
-- Preventing endless loops (worst case is n*(n+1)/2 I believe) -- 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 local numIter = 0
-- The idea is that all mutators before the current one are already in the right order -- The idea is that all mutators before the current one are already in the right order
-- Starting from second mutator -- Starting from second mutator
local i = 2 local i = 2
while i <= #mutators do while i <= #_MUTATORS do
local mutator = mutators[i] local mutator = _MUTATORS[i]
local mutator_name = mutator:get_name() 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 -- Going back from the previous mutator to the start of the list
local j = i - 1 local j = i - 1
while j > 0 do 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 -- 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 if table.contains(enable_these_after, other_mutator:get_name()) then
table.remove(mutators, j) table.remove(_MUTATORS, j)
table.insert(mutators, i, other_mutator) table.insert(_MUTATORS, i, other_mutator)
-- This will shift the current mutator back, so adjust the index -- This will shift the current mutator back, so adjust the index
i = i - 1 i = i - 1
@ -232,47 +179,40 @@ manager.sort_mutators = function()
numIter = numIter + 1 numIter = numIter + 1
if numIter > maxIter then 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 return
end end
end end
mutators_sorted = true _MUTATORS_SORTED = true
-- LOG -- -- LOG --
print("[MUTATORS] Sorted") print("[MUTATORS] Sorted")
for k, v in ipairs(mutators) do for k, v in ipairs(_MUTATORS) do
print(" ", k, v:get_name()) print(" ", k, v:get_name())
end end
-- /LOG -- -- /LOG --
end end
-- Disables mutators that cannot be enabled right now -- ####################################################################################################################
manager.disable_impossible_mutators = function(notify, everybody, reason) -- ##### VMF internal functions and variables #########################################################################
local disabled_mutators = {} -- ####################################################################################################################
for i = #mutators, 1, -1 do
local mutator = mutators[i] vmf.mutators = _MUTATORS
if mutator:is_enabled() and not mutator:can_be_enabled() then
mutator:disable() -- #########
table.insert(disabled_mutators, mutator) -- # LOCAL #
end -- #########
end
if #disabled_mutators > 0 and notify then -- Checks current difficulty, map selection screen settings (optionally), incompatible mutators and whether player is server
if not reason then reason = "" end -- to determine if a mutator can be enabled
local loc = everybody and "broadcast_disabled_mutators" or "local_disabled_mutators" function vmf.mutator_can_be_enabled(mutator)
local message = manager:localize(loc) .. " " .. manager:localize(reason) .. ":" if #vmf.get_incompatible_mutators(mutator, true) > 0 then return false end
message = message .. " " .. manager.add_mutator_titles_to_string(disabled_mutators, "", ", ", false) return player_is_server() and vmf.mutator_supports_current_difficulty(mutator)
if everybody then
manager:chat_broadcast(message)
else
manager:echo(message)
end
end
return disabled_mutators
end end
-- Appends, prepends and replaces the string with mutator titles -- 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 if #_mutators == 0 then return str end
local before = nil local before = nil
@ -280,8 +220,8 @@ manager.add_mutator_titles_to_string = function(_mutators, str, separator, short
local replace = nil local replace = nil
for _, mutator in ipairs(_mutators) do for _, mutator in ipairs(_mutators) do
local config = mutator:get_config() local config = vmf.get_mutator_config(mutator)
local added_name = (short and config.short_title or config.title or mutator:get_name()) local added_name = (short and config.short_title or mutator:get_readable_name())
if config.title_placement == "before" then if config.title_placement == "before" then
if before then if before then
before = added_name .. separator .. before before = added_name .. separator .. before
@ -312,44 +252,55 @@ manager.add_mutator_titles_to_string = function(_mutators, str, separator, short
return new_str return new_str
end end
-- Check if player is still hosting -- Returns a list of incompatible with self mutators, all or only enabled ones
manager.update = function() -- M, G
if not all_mutators_disabled and not player_is_server() then function vmf.get_incompatible_mutators(mutator, enabled_only)
manager.disable_impossible_mutators(true, false, "disabled_reason_not_server") local incompatible_mutators = {}
all_mutators_disabled = true 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 end
return incompatible_mutators
end end
-- Disables mutators that cannot be enabled right now
--[[ -- M, G
MUTATOR'S OWN METHODS function vmf.disable_impossible_mutators(notify, everybody, reason)
]]-- local disabled_mutators = {}
for i = #_MUTATORS, 1, -1 do
-- Enables mutator local mutator = _MUTATORS[i]
local function enable_mutator(self) if mutator:is_enabled() and not vmf.mutator_can_be_enabled(mutator) then
set_mutator_state(self, true) vmf.mod_state_changed(mutator:get_name(), false)
all_mutators_disabled = false table.insert(disabled_mutators, mutator)
end end
end
-- Disables mutator if #disabled_mutators > 0 and notify then
local function disable_mutator(self) if not reason then reason = "" end
set_mutator_state(self, false) local loc = everybody and "broadcast_disabled_mutators" or "local_disabled_mutators"
end local message = vmf:localize(loc) .. " " .. vmf:localize(reason) .. ":"
message = message .. " " .. vmf.add_mutator_titles_to_string(disabled_mutators, "", ", ", false)
-- Checks current difficulty, map selection screen settings (optionally), incompatible mutators and whether player is server if everybody then
-- to determine if a mutator can be enabled vmf:chat_broadcast(message)
local function can_be_enabled(self, ignore_map) else
if #self:get_incompatible_mutators(true) > 0 then return false end vmf:echo(message)
return player_is_server() and self:supports_current_difficulty(ignore_map) end
end
return disabled_mutators
end end
-- Only checks difficulty -- Only checks difficulty
local function supports_current_difficulty(self, ignore_map) -- M, G
local mutator_difficulty_levels = self:get_config().difficulty_levels 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 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 map_view_active = map_view and map_view.active
local right_unapplied_difficulty = false 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_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_layout = difficulty_data and difficulty_data[map_view.selected_difficulty_stepper_index]
local difficulty_key = difficulty_layout and difficulty_layout.key 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 end
return (map_view_active and right_unapplied_difficulty) or (not map_view_active and right_difficulty) return (map_view_active and right_unapplied_difficulty) or (not map_view_active and right_difficulty)
end end
-- Returns the config object for mutator from mutators_config -- Returns the config object for mutator from _MUTATORS_CONFIG
local function get_config(self) -- M, G
return mutators_config[self:get_name()] function vmf.get_mutator_config(mutator)
return _MUTATORS_CONFIG[mutator:get_name()]
end end
-- Returns a list of incompatible with self mutators, all or only enabled ones -- ##########
local function get_incompatible_mutators(self, enabled_only) -- # GLOBAL #
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
-- Turns a mod into a mutator -- 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 if not config then config = {} end
local mod_name = self:get_name() table.insert(_MUTATORS, mod)
if table.has_item(mutators, self) then local mod_name = mod:get_name()
self:error("Mod is already registered as mutator")
return
end
table.insert(mutators, self)
-- Save config -- Save config
mutators_config[mod_name] = table.clone(default_config) _MUTATORS_CONFIG[mod_name] = table.clone(_DEFAULT_CONFIG)
local _config = mutators_config[mod_name] local _config = _MUTATORS_CONFIG[mod_name]
for k, _ in pairs(_config) do for k, _ in pairs(_config) do
if config[k] ~= nil then if config[k] ~= nil then
_config[k] = config[k] _config[k] = config[k]
end end
end end
if _config.short_title == "" then _config.short_title = nil 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 if config.enable_before_these then
update_mutators_sequence(mod_name, config.enable_before_these) update_mutators_sequence(mod_name, config.enable_before_these)
@ -418,42 +353,94 @@ VMFMod.register_as_mutator = function(self, config)
end end
end end
self.enable = enable_mutator _MUTATORS_SORTED = false
self.disable = disable_mutator
self.can_be_enabled = can_be_enabled
self.supports_current_difficulty = supports_current_difficulty
self.get_config = get_config _MUTATORS_VIEW:update_mutator_list()
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()
end end
-- Enables/disables mutator while preserving the sequence in which they were enabled
function vmf.set_mutator_state(mutator, state, initial_call)
--[[ -- Sort mutators if this is the first call
HOOKS if not _MUTATORS_SORTED then
]]-- sort_mutators()
manager:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) end
manager.disable_impossible_mutators(true, true, "disabled_reason_difficulty_change")
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) return func(self, difficulty)
end) end)
-- ####################################################################################################################
-- ##### Script #######################################################################################################
-- ####################################################################################################################
--[[ _DEFAULT_CONFIG = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config")
INITIALIZE
--]] _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 -- 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
Testing --vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/mutator_test")
--]] --vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/mutation")
-- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_test") --vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/deathwish")
-- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/mutation")
-- manager:dofile("scripts/mods/vmf/modules/ui/mutators/mutators/deathwish")

View file

@ -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--]]

View file

@ -3424,7 +3424,7 @@ VMFOptionsView.update_picked_option_for_settings_list_widgets = function (self)
elseif widget_type == "header" then 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 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 = {} 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 options_menu_collapsed_widgets = vmf:get("options_menu_collapsed_widgets")
local mod_collapsed_widgets = nil local mod_collapsed_widgets = nil
if options_menu_collapsed_widgets then 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 end
-- defining header widget -- 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_type = "header"
new_widget_definition.widget_index = new_widget_index new_widget_definition.widget_index = new_widget_index
new_widget_definition.mod_name = self:get_name() new_widget_definition.mod_name = mod:get_name()
new_widget_definition.readable_mod_name = readable_mod_name or self:get_name() new_widget_definition.readable_mod_name = mod:get_readable_name()
new_widget_definition.tooltip = mod_description new_widget_definition.tooltip = mod:get_description()
new_widget_definition.default = true 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 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 end
if options_menu_favorite_mods then if options_menu_favorite_mods then
for _, current_mod_name in pairs(options_menu_favorite_mods) do 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 new_widget_definition.is_favorited = true
break break
end 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_type = current_widget.widget_type -- all
new_widget_definition.widget_index = new_widget_index -- all [gen] new_widget_definition.widget_index = new_widget_index -- all [gen]
new_widget_definition.widget_level = level -- 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.setting_name = current_widget.setting_name -- all
new_widget_definition.text = current_widget.text -- all new_widget_definition.text = current_widget.text -- all
new_widget_definition.tooltip = current_widget.tooltip -- all [optional] 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] new_widget_definition.is_widget_collapsed = mod_collapsed_widgets[current_widget.setting_name]
end end
if type(self:get(current_widget.setting_name)) == "nil" then if type(mod:get(current_widget.setting_name)) == "nil" then
self:set(current_widget.setting_name, current_widget.default_value) mod:set(current_widget.setting_name, current_widget.default_value)
end end
if current_widget.widget_type == "keybind" then 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) new_widget_definition.keybind_text = build_keybind_string(keybind)
if current_widget.action then 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
end end
@ -4034,7 +4034,7 @@ VMFMod.create_options = function (self, widgets_definition, is_mod_toggable, rea
end end
if new_widget_index == 257 then 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
end end
@ -4135,6 +4135,7 @@ vmf.disable_mods_options_button = function ()
change_mods_options_button_state("disable") change_mods_options_button_state("disable")
end end
-- @BUG: Game crashes occasionaly here. See attached log
-- create mods options menu button in Esc-menu -- create mods options menu button in Esc-menu
vmf:hook("IngameView.setup_button_layout", function (func, self, layout_data) vmf:hook("IngameView.setup_button_layout", function (func, self, layout_data)

View file

@ -1,6 +1,8 @@
local vmf = get_mod("VMF") 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", ["setting_name"] = "open_vmf_options",
["widget_type"] = "keybind", ["widget_type"] = "keybind",
@ -268,7 +270,7 @@ end
-- ##### Script ####################################################################################################### -- ##### Script #######################################################################################################
-- #################################################################################################################### -- ####################################################################################################################
vmf:create_options(options_widgets, false, "Vermintide Mod Framework") vmf:initialize_data(vmf_mod_data)
-- first VMF initialization -- first VMF initialization
-- it will be run only 1 time, when the player launch the game with VMF for the first time -- it will be run only 1 time, when the player launch the game with VMF for the first time

View file

@ -1,12 +1,14 @@
return { return {
init = function(object) 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/mods")
dofile("scripts/mods/vmf/modules/core/events") dofile("scripts/mods/vmf/modules/core/events")
dofile("scripts/mods/vmf/modules/core/settings") dofile("scripts/mods/vmf/modules/core/settings")
dofile("scripts/mods/vmf/modules/core/core_functions") 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/dev_console")
dofile("scripts/mods/vmf/modules/debug/table_dump") dofile("scripts/mods/vmf/modules/debug/table_dump")
dofile("scripts/mods/vmf/modules/core/hooks") dofile("scripts/mods/vmf/modules/core/hooks")
@ -35,7 +37,8 @@ return {
end) end)
-- temporary solution: -- 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, end,
update = function(object, dt) update = function(object, dt)
@ -43,6 +46,7 @@ return {
object.vmf.mods_update_event(dt) object.vmf.mods_update_event(dt)
object.vmf.check_pressed_keybinds() object.vmf.check_pressed_keybinds()
object.vmf.check_custom_menus_close_keybinds(dt) 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 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.save_unsaved_settings_to_file()
object.vmf.apply_delayed_hooks() object.vmf.apply_delayed_hooks()
if status == "exit" and state == "StateTitleScreen" then --if status == "exit" and state == "StateTitleScreen" then
object.vmf.hook_chat_manager() -- object.vmf.hook_chat_manager()
end --end
if status == "enter" and state == "StateIngame" then if status == "enter" and state == "StateIngame" then
object.vmf.initialize_keybinds() object.vmf.initialize_keybinds()