From 7efb7eca7442a461f613b4345e152e9bf92d1094 Mon Sep 17 00:00:00 2001 From: bi Date: Mon, 21 May 2018 18:49:37 +0300 Subject: [PATCH] Mutators: final refactoring --- .../ui/mutators/mutator_default_config.lua | 2 +- .../vmf/modules/ui/mutators/mutator_dice.lua | 58 ++- .../vmf/modules/ui/mutators/mutator_info.lua | 11 +- .../modules/ui/mutators/mutator_manager.lua | 464 +++++++++--------- .../vmf/modules/ui/mutators/mutators_gui.lua | 32 +- .../ui/mutators/mutators_gui_definitions.lua | 36 +- .../modules/ui/mutators/test/mutator_test.lua | 5 +- vmf/scripts/mods/vmf/vmf_loader.lua | 2 +- 8 files changed, 313 insertions(+), 297 deletions(-) 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 c2f5895..425800f 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,7 +4,7 @@ return { tomes = 0, bonus = 0 }, - short_title = "", --@TODO: rename it? + short_title = "", title_placement = "after", difficulty_levels = { "easy", 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 26018fe..1ad18fb 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_dice.lua @@ -1,4 +1,6 @@ ---[[ Add additional dice to end game roll --]] +--[[ + Add additional dice to end game roll +--]] local vmf = get_mod("VMF") -- List of all die types @@ -15,7 +17,29 @@ local num_dice_per_mission = { grimoire_hidden_mission = 0 } -vmf:hook("GameModeManager.complete_level", function(func, self) +-- #################################################################################################################### +-- ##### Local functions ############################################################################################## +-- #################################################################################################################### + +-- Adds/remove dice +local function adjustDice(grims, tomes, bonus, multiplier) + if grims then + num_dice_per_mission.grimoire_hidden_mission = num_dice_per_mission.grimoire_hidden_mission + grims * multiplier + end + if tomes then + num_dice_per_mission.tome_bonus_mission = num_dice_per_mission.tome_bonus_mission + tomes * multiplier + end + if bonus then + num_dice_per_mission.bonus_dice_hidden_mission = num_dice_per_mission.bonus_dice_hidden_mission + bonus * + multiplier + end +end + +-- #################################################################################################################### +-- ##### Hooks ######################################################################################################## +-- #################################################################################################################### + +vmf:hook("GameModeManager.complete_level", function(func, ...) local num_dice = 0 local max_dice = 7 local mission_system = Managers.state.entity:system("mission_system") @@ -50,27 +74,19 @@ vmf:hook("GameModeManager.complete_level", function(func, self) if num_dice <= max_dice then break end end - return func(self) + func(...) end) --- Adds/remove dice -local function adjustDice(grims, tomes, bonus, multiplier) - if grims then num_dice_per_mission.grimoire_hidden_mission = num_dice_per_mission.grimoire_hidden_mission + grims * multiplier end - if tomes then num_dice_per_mission.tome_bonus_mission = num_dice_per_mission.tome_bonus_mission + tomes * multiplier end - if bonus then num_dice_per_mission.bonus_dice_hidden_mission = num_dice_per_mission.bonus_dice_hidden_mission + bonus * multiplier end -end - -local addDice = function(dice) - dice = dice or {} - adjustDice(dice.grims, dice.tomes, dice.bonus, 1) -end - -local removeDice = function(dice) - dice = dice or {} - adjustDice(dice.grims, dice.tomes, dice.bonus, -1) -end +-- #################################################################################################################### +-- ##### Return ####################################################################################################### +-- #################################################################################################################### return { - addDice = addDice, - removeDice = removeDice + addDice = function(dice) + adjustDice(dice.grims, dice.tomes, dice.bonus, 1) + end, + + removeDice = function(dice) + adjustDice(dice.grims, dice.tomes, dice.bonus, -1) + end } 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 ff046b6..43dfe0c 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_info.lua @@ -3,14 +3,12 @@ --]] local vmf = get_mod("VMF") -local _MUTATORS = vmf.mutators - local _WERE_ENABLED_BEFORE = false -- Assembles a list of enabled mutators local function add_enabled_mutators_titles_to_string(separator, is_short) local enabled_mutators = {} - for _, mutator in ipairs(_MUTATORS) do + for _, mutator in ipairs(vmf.mutators) do if mutator:is_enabled() then table.insert(enabled_mutators, mutator) end @@ -55,6 +53,9 @@ local function get_peer_id_from_cookie(client_cookie) peer_id = string.sub(peer_id, 2) peer_id = string.reverse(peer_id) + vmf:echo("PEER ID FROM COOKIE #1: [" .. tostring(peer_id) .. "]") + vmf:echo("PEER ID FROM COOKIE #2: [" .. tostring(string.match(client_cookie, "%[(%a+)%]")) .. "]") + return peer_id end @@ -77,8 +78,8 @@ vmf:hook("IngamePlayerListUI.update_difficulty", function(func_, self) end) -- Notify everybody about enabled/disabled mutators when Play button is pressed on the map screen -vmf:hook("MatchmakingStateHostGame.host_game", function(func, self, ...) - func(self, ...) +vmf:hook("MatchmakingStateHostGame.host_game", function(func, ...) + func(...) set_lobby_data() local names = add_enabled_mutators_titles_to_string(", ") if names ~= "" then 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 a27a067..d620bcb 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutator_manager.lua @@ -1,15 +1,12 @@ --[[ - Converts mods into mutators + Manages everything related to mutators: loading order, enabling/disabling process, giving extra dice etc. --]] local vmf = get_mod("VMF") -- List of mods that are also mutators in order in which they should be enabled --- This is populated via vmf.register_mod_as_mutator local _MUTATORS = {} - -- This lists mutators and which ones should be enabled after them --- This is populated via vmf.register_mod_as_mutator local _MUTATORS_SEQUENCE = { --[[ this_mutator = { @@ -26,10 +23,10 @@ local _MUTATORS_SORTED = false local _ALL_MUTATORS_DISABLED = false -- External modules -local _DICE_MANAGER -local _SET_LOBBY_DATA +local _DICE_MANAGER = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_dice") +local _SET_LOBBY_DATA = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_info") -local _DEFAULT_CONFIG +local _DEFAULT_CONFIG = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config") -- List of enabled mutators in case VMF is reloaded in the middle of the game local _ENABLED_MUTATORS = vmf:persistent_table("enabled_mutators") @@ -48,138 +45,6 @@ local function get_index(tbl, o) 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) - - local config = mutator:get_config() - local enable_before_these = config.enable_before_these - local enable_after_these = config.enable_after_these - local mutator_name = mutator:get_name() - - if enable_before_these then - _MUTATORS_SEQUENCE[mutator_name] = _MUTATORS_SEQUENCE[mutator_name] or {} - - for _, other_mutator_name in ipairs(enable_before_these) do - 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 - - end - if enable_after_these then - for _, other_mutator_name in ipairs(enable_after_these) do - _MUTATORS_SEQUENCE[other_mutator_name] = _MUTATORS_SEQUENCE[other_mutator_name] or {} - - if _MUTATORS_SEQUENCE[mutator_name] and table.contains(_MUTATORS_SEQUENCE[mutator_name], other_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[other_mutator_name], mutator_name) then - table.insert(_MUTATORS_SEQUENCE[other_mutator_name], mutator_name) - end - end - end -end - - --- Checks if mutators are compatible both ways -local function is_compatible(mutator, other_mutator) - local config = mutator:get_config() - local name = mutator:get_name() - local other_config = other_mutator:get_config() - local other_name = other_mutator:get_name() - - local incompatible_specifically = ( - #config.incompatible_with > 0 and ( - table.contains(config.incompatible_with, other_name) - ) or - #other_config.incompatible_with > 0 and ( - table.contains(other_config.incompatible_with, name) - ) - ) - - local compatible_specifically = ( - #config.compatible_with > 0 and ( - table.contains(config.compatible_with, other_name) - ) or - #other_config.compatible_with > 0 and ( - table.contains(other_config.compatible_with, name) - ) - ) - - local compatible - if incompatible_specifically then - compatible = false - elseif compatible_specifically then - compatible = true - elseif config.compatible_with_all or other_config.compatible_with_all then - compatible = true - elseif config.incompatible_with_all or other_config.incompatible_with_all then - compatible = false - else - compatible = true - end - - return compatible -end - --- Creates 'compatibility' entry for the mutator, checks compatibility of given mutator with all other mutators. --- 'compatibility.is_mostly_compatible' is 'true' when mutator is not specifically set to be incompatible with --- all other mutators. All the incompatible mutators will be added to 'compatibility.except'. And vice versa, --- if 'is_mostly_compatible' is 'false', all the compatible mutators will be added to 'except'. --- Also, converts given difficulties compatibility to optimized form. -local function update_compatibility(mutator) - - -- Create default 'compatibility' entry - local config = mutator:get_config() - config.compatibility = {} - local compatibility = config.compatibility - - -- Compatibility with other mods - compatibility.is_mostly_compatible = not config.incompatible_with_all - compatibility.except = {} - - local is_mostly_compatible = compatibility.is_mostly_compatible - local except = compatibility.except - - for _, other_mutator in ipairs(_MUTATORS) do - - local other_config = other_mutator:get_config() - local other_mostly_compatible = other_config.compatibility.is_mostly_compatible - local other_except = other_config.compatibility.except - - if is_compatible(mutator, other_mutator) then - if not is_mostly_compatible then except[other_mutator] = true end - if not other_mostly_compatible then other_except[mutator] = true end - else - if is_mostly_compatible then except[other_mutator] = true end - if other_mostly_compatible then other_except[mutator] = true end - end - end - - -- Compatibility with current difficulty (This part works only for V1. Will see what to do with V2 later.) - compatibility.compatible_difficulties = { - easy = false, - normal = false, - hard = false, - harder = false, - hardest = false, - survival_hard = false, - survival_harder = false, - survival_hardest = false, - } - local compatible_difficulties = compatibility.compatible_difficulties - local compatible_difficulties_number = 0 - for _, difficulty_key in ipairs(config.difficulty_levels) do - if type(compatible_difficulties[difficulty_key]) ~= "nil" then - compatible_difficulties[difficulty_key] = true - compatible_difficulties_number = compatible_difficulties_number + 1 - end - end - compatibility.compatible_difficulties_number = compatible_difficulties_number -end - - -- Called after mutator is enabled local function on_enabled(mutator) local config = mutator:get_config() @@ -190,16 +55,22 @@ local function on_enabled(mutator) _ENABLED_MUTATORS[mutator:get_name()] = true end + -- Called after mutator is disabled -local function on_disabled(mutator) +local function on_disabled(mutator, initial_call) local config = mutator:get_config() - _DICE_MANAGER.removeDice(config.dice) - _SET_LOBBY_DATA() + + -- All mutators run on_disabled on initial call, so there's no need to remove dice and set lobby data + if not initial_call then + _DICE_MANAGER.removeDice(config.dice) + _SET_LOBBY_DATA() + end print("[MUTATORS] Disabled " .. mutator:get_name() .. " (" .. tostring(get_index(_MUTATORS, mutator)) .. ")") _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 local function player_is_server() local player = Managers.player @@ -207,6 +78,7 @@ local function player_is_server() return not player or player.is_server or not state or state.game_mode == nil end + -- Sorts mutators in order they should be enabled local function sort_mutators() @@ -250,25 +122,18 @@ local function sort_mutators() end _MUTATORS_SORTED = true + --[[ -- LOG -- print("[MUTATORS] Sorted") for k, v in ipairs(_MUTATORS) do print(" ", k, v:get_name()) end -- /LOG -- + --]] end --- #################################################################################################################### --- ##### VMF internal functions and variables ######################################################################### --- #################################################################################################################### -vmf.mutators = _MUTATORS - --- ######### --- # LOCAL # --- ######### - --- Determine if a mutator can be enabled +-- Check if a mutator can be enabled local function mutator_can_be_enabled(mutator) -- If conflicting mutators are enabled @@ -293,6 +158,211 @@ local function mutator_can_be_enabled(mutator) return not actual_difficulty or compatible_difficulties[actual_difficulty] end + +-- Disables mutators that cannot be enabled right now +local function disable_impossible_mutators(is_broadcast, reason_text_id) + local disabled_mutators = {} + for i = #_MUTATORS, 1, -1 do + local mutator = _MUTATORS[i] + if mutator:is_enabled() and not 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 then + local disabled_mutators_text_id = is_broadcast and "broadcast_disabled_mutators" or "local_disabled_mutators" + local message = vmf:localize(disabled_mutators_text_id) .. " " .. vmf:localize(reason_text_id) .. ":" + message = message .. " " .. vmf.add_mutator_titles_to_string(disabled_mutators, ", ", false) + if is_broadcast then + vmf:chat_broadcast(message) + else + vmf:echo(message) + end + end +end + + +-- INITIALIZING + + +-- 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) + + local raw_config = mutator:get_config().raw_config + local enable_before_these = raw_config.enable_before_these + local enable_after_these = raw_config.enable_after_these + local mutator_name = mutator:get_name() + + if enable_before_these then + _MUTATORS_SEQUENCE[mutator_name] = _MUTATORS_SEQUENCE[mutator_name] or {} + + for _, other_mutator_name in ipairs(enable_before_these) do + 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 + + end + if enable_after_these then + for _, other_mutator_name in ipairs(enable_after_these) do + _MUTATORS_SEQUENCE[other_mutator_name] = _MUTATORS_SEQUENCE[other_mutator_name] or {} + + if _MUTATORS_SEQUENCE[mutator_name] and table.contains(_MUTATORS_SEQUENCE[mutator_name], other_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[other_mutator_name], mutator_name) then + table.insert(_MUTATORS_SEQUENCE[other_mutator_name], mutator_name) + end + end + end +end + + +-- Uses raw_config to determine if mutators are compatible both ways +local function is_compatible(mutator, other_mutator) + local raw_config = mutator:get_config().raw_config + local other_raw_config = other_mutator:get_config().raw_config + + local mutator_name = mutator:get_name() + local other_mutator_name = other_mutator:get_name() + + local incompatible_specifically = ( + #raw_config.incompatible_with > 0 and ( + table.contains(raw_config.incompatible_with, other_mutator_name) + ) or + #other_raw_config.incompatible_with > 0 and ( + table.contains(other_raw_config.incompatible_with, mutator_name) + ) + ) + + local compatible_specifically = ( + #raw_config.compatible_with > 0 and ( + table.contains(raw_config.compatible_with, other_mutator_name) + ) or + #other_raw_config.compatible_with > 0 and ( + table.contains(other_raw_config.compatible_with, mutator_name) + ) + ) + + local compatible + if incompatible_specifically then + compatible = false + elseif compatible_specifically then + compatible = true + elseif raw_config.compatible_with_all or other_raw_config.compatible_with_all then + compatible = true + elseif raw_config.incompatible_with_all or other_raw_config.incompatible_with_all then + compatible = false + else + compatible = true + end + + return compatible +end + + +-- Creates 'compatibility' entry for the mutator, checks compatibility of given mutator with all other mutators. +-- 'compatibility.is_mostly_compatible' is 'true' when mutator is not specifically set to be incompatible with +-- all other mutators. All the incompatible mutators will be added to 'compatibility.except'. And vice versa, +-- if 'is_mostly_compatible' is 'false', all the compatible mutators will be added to 'except'. +-- Also, converts given difficulties compatibility to optimized form. +local function update_compatibility(mutator) + + -- Create default 'compatibility' entry + local config = mutator:get_config() + config.compatibility = {} + local compatibility = config.compatibility + + -- Compatibility with other mods + compatibility.is_mostly_compatible = not config.raw_config.incompatible_with_all + compatibility.except = {} + + local is_mostly_compatible = compatibility.is_mostly_compatible + local except = compatibility.except + + for _, other_mutator in ipairs(_MUTATORS) do + + local other_config = other_mutator:get_config() + local other_mostly_compatible = other_config.compatibility.is_mostly_compatible + local other_except = other_config.compatibility.except + + if is_compatible(mutator, other_mutator) then + if not is_mostly_compatible then except[other_mutator] = true end + if not other_mostly_compatible then other_except[mutator] = true end + else + if is_mostly_compatible then except[other_mutator] = true end + if other_mostly_compatible then other_except[mutator] = true end + end + end + + -- Compatibility with current difficulty (This part works only for VT1. Will see what to do with VT2 later.) + compatibility.compatible_difficulties = { + easy = false, + normal = false, + hard = false, + harder = false, + hardest = false, + survival_hard = false, + survival_harder = false, + survival_hardest = false, + } + local compatible_difficulties = compatibility.compatible_difficulties + local compatible_difficulties_number = 0 + for _, difficulty_key in ipairs(config.raw_config.difficulty_levels) do + if type(compatible_difficulties[difficulty_key]) ~= "nil" then + compatible_difficulties[difficulty_key] = true + compatible_difficulties_number = compatible_difficulties_number + 1 + end + end + compatibility.compatible_difficulties_number = compatible_difficulties_number +end + + +-- Converts user-made config to form used by mutators module +local function initialize_mutator_config(mutator, _raw_config) + + -- Shapes raw config, so it will have only elements that are intended to be in there. + -- Also, adds missing elements with their default values. + local raw_config = table.clone(_DEFAULT_CONFIG) + if type(_raw_config) == "table" then + for k, v in pairs(raw_config) do + if type(_raw_config[k]) == type(v) then + raw_config[k] = _raw_config[k] + end + end + end + if raw_config.short_title == "" then raw_config.short_title = nil end + + mutator._data.config = {} + + local config = mutator._data.config + + config.dice = raw_config.dice + config.short_title = raw_config.short_title + config.title_placement = raw_config.title_placement + + -- 'raw_config' will be used in 2 following functions to fill compatibility and mutator sequence tables. + -- It will be deleted after all mods are loaded and those 2 tables are formed. + config.raw_config = raw_config + + -- config.compatibility + update_compatibility(mutator) + + -- _MUTATORS_SEQUENCE + update_mutators_sequence(mutator) +end + +-- #################################################################################################################### +-- ##### VMF internal functions and variables ######################################################################### +-- #################################################################################################################### + +vmf.mutators = _MUTATORS + + -- Appends, prepends and replaces the string with mutator titles function vmf.add_mutator_titles_to_string(mutators, separator, is_short) @@ -338,56 +408,17 @@ function vmf.add_mutator_titles_to_string(mutators, separator, is_short) end --- Disables mutators that cannot be enabled right now -local function disable_impossible_mutators(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(mutator) then - vmf.mod_state_changed(mutator:get_name(), false) - table.insert(disabled_mutators, mutator) - end - end - if #disabled_mutators > 0 then - 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 -end - --- ########## --- # GLOBAL # --- ########## - -- Turns a mod into a mutator -function vmf.register_mod_as_mutator(mod, config) +function vmf.register_mod_as_mutator(mod, raw_config) - -- Form config - config = config or {} - local _config = table.clone(_DEFAULT_CONFIG) - 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 - - -- Save config inside the mod data - mod._data.config = _config - - update_compatibility(mod) - update_mutators_sequence(mod) + initialize_mutator_config(mod, raw_config) table.insert(_MUTATORS, mod) _MUTATORS_SORTED = false end + -- Enables/disables mutator while preserving the sequence in which they were enabled function vmf.set_mutator_state(mutator, state, initial_call) @@ -401,7 +432,8 @@ function vmf.set_mutator_state(mutator, state, initial_call) 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 + -- 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 @@ -420,7 +452,7 @@ function vmf.set_mutator_state(mutator, state, initial_call) _ALL_MUTATORS_DISABLED = false on_enabled(mutator) else - on_disabled(mutator) + on_disabled(mutator, initial_call) end -- Re-enable disabled mutators @@ -433,7 +465,8 @@ function vmf.set_mutator_state(mutator, state, initial_call) end end --- Check if player is still hosting (on update) + +-- Checks if player is still hosting (on update) function vmf.check_mutators_state() if not _ALL_MUTATORS_DISABLED and not player_is_server() then disable_impossible_mutators(false, "disabled_reason_not_server") @@ -441,50 +474,31 @@ function vmf.check_mutators_state() end end --- Called only after VMF reloading to check if some mutators were enabled before reloading + +-- Is 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 - -function vmf.temp_show_mutator_compatibility() - - print("MUTATORS COMPATIBILITY:") - print("") - +-- Removes all raw_configs which won't be used anymore +function vmf.mutators_delete_raw_config() for _, mutator in ipairs(_MUTATORS) do - local compatibility = mutator:get_config().compatibility - - print(mutator:get_readable_name() .. (compatibility.is_mostly_compatible and "[+]" or "[-]") .. ":") - - local ident = compatibility.is_mostly_compatible and " - " or " + " - - for other_mutator in pairs(compatibility.except) do - print(ident .. other_mutator:get_readable_name()) - end - - print("") + mutator:get_config().raw_config = nil end end + -- #################################################################################################################### -- ##### Hooks ######################################################################################################## -- #################################################################################################################### -vmf:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) +vmf:hook("DifficultyManager.set_difficulty", function(func, ...) + func(...) disable_impossible_mutators(true, "disabled_reason_difficulty_change") - return func(self, difficulty) end) -- #################################################################################################################### -- ##### Script ####################################################################################################### -- #################################################################################################################### -_DEFAULT_CONFIG = vmf:dofile("scripts/mods/vmf/modules/ui/mutators/mutator_default_config") - -_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") - -- 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 +vmf:dofile("scripts/mods/vmf/modules/ui/mutators/test/mutator_test") \ 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 index 0d5cab7..463707b 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui.lua @@ -11,8 +11,6 @@ local _PARTY_BUTTON_WIDGET local _NO_MUTATORS_TEXT_WIDGET local _OTHER_WIDGETS = {} -local _ORIGINAL_VALUES = {} -- @TODO: get rid of it? - local _IS_MUTATOR_LIST_VISIBLE -- 'true' if Mutator view is active, 'false' if Party view is active. local _CURRENT_PAGE_NUMBER local _TOTAL_PAGES_NUMBER @@ -71,23 +69,21 @@ local function show_mutator_list(map_view, is_visible) end end + local function change_map_view_look(map_view, is_vmf_look) if is_vmf_look then - _ORIGINAL_VALUES.settings_button_position_x = map_view.ui_scenegraph.settings_button.position[1] - _ORIGINAL_VALUES.friends_button_position_x = map_view.ui_scenegraph.friends_button.position[1] - _ORIGINAL_VALUES.lobby_button_position_x = map_view.ui_scenegraph.lobby_button.position[1] - map_view.ui_scenegraph.settings_button.position[1] = -50 map_view.ui_scenegraph.friends_button.position[1] = 50 map_view.ui_scenegraph.lobby_button.position[1] = 150 else - map_view.ui_scenegraph.settings_button.position[1] = _ORIGINAL_VALUES.settings_button_position_x - map_view.ui_scenegraph.friends_button.position[1] = _ORIGINAL_VALUES.friends_button_position_x - map_view.ui_scenegraph.lobby_button.position[1] = _ORIGINAL_VALUES.lobby_button_position_x + map_view.ui_scenegraph.settings_button.position[1] = -100 + map_view.ui_scenegraph.friends_button.position[1] = 0 + map_view.ui_scenegraph.lobby_button.position[1] = 100 end end + -- Used in the next function to calculate tooltip offset, since Fatshark's solution doesn't support -- tooltips with cursor being in the left-bottom corner. local function calculate_tooltip_offset (widget_content, widget_style, ui_renderer) @@ -119,12 +115,13 @@ local function calculate_tooltip_offset (widget_content, widget_style, ui_render end end + -- Callback function for mutator widgets. It's not defined in definitions file because it works with mutators array. +-- And it's easier to work with it from there. local function offset_function_callback(ui_scenegraph_, style, content, ui_renderer) local mutator = content.mutator - -- Find out if mutator can be enabled. local can_be_enabled = true @@ -143,17 +140,15 @@ local function offset_function_callback(ui_scenegraph_, style, content, ui_rende content.can_be_enabled = can_be_enabled - -- Enable/disable mutator. if content.highlight_hotspot.on_release then if mutator:is_enabled() then - vmf.set_mutator_state(mutator, false, false) --@TODO: change method? + vmf.mod_state_changed(mutator:get_name(), false) elseif can_be_enabled then - vmf.set_mutator_state(mutator, true, false) + vmf.mod_state_changed(mutator:get_name(), true) end end - -- Build tooltip (only for currently selected mutator widget). if content.highlight_hotspot.is_hover then @@ -235,7 +230,6 @@ local function offset_function_callback(ui_scenegraph_, style, content, ui_rende calculate_tooltip_offset(content, style.tooltip_text, ui_renderer) end - -- Visual changing (text color and checkboxes). local is_enabled = content.mutator:is_enabled() @@ -246,6 +240,7 @@ local function offset_function_callback(ui_scenegraph_, style, content, ui_rende content.checkbox_unchecked_texture end + local function initialize_scrollbar() local scrollbar_widget_content = _OTHER_WIDGETS.scrollbar.content @@ -258,6 +253,7 @@ local function initialize_scrollbar() end end + local function initialize_mutators_ui(map_view) -- Scenegraph @@ -327,6 +323,7 @@ local function draw(map_view, dt) UIRenderer.end_pass(ui_renderer) end + -- Sets new scrollbar position (called when user changes the current page number with mouse scroll input) local function update_scrollbar_position() local scrollbar_widget_content = _OTHER_WIDGETS.scrollbar.content @@ -335,6 +332,7 @@ local function update_scrollbar_position() scrollbar_widget_content.scroll_bar_info.old_value = percentage end + -- Reads scrollbar input and if it was changed, set current page according to the new scrollbar position local function update_scrollbar_input() local scrollbar_info = _OTHER_WIDGETS.scrollbar.content.scroll_bar_info @@ -346,6 +344,7 @@ local function update_scrollbar_input() end end + -- Reads mousewheel scrolls from corresponding widget and changes current page number, if possible. local function update_mousewheel_scroll_area_input() local widget_content = _OTHER_WIDGETS.mousewheel_scroll_area.content @@ -387,11 +386,13 @@ vmf:hook("MapView.init", function (func, self, ingame_ui_context) initialize_mutators_ui(self) end) + vmf:hook("MapView.update", function (func, self, dt, t) func(self, dt, t) if self.menu_active and _IS_MUTATORS_GUI_INITIALIZED then + -- Parse currently selected difficulty in the map_view local difficulty_data = self.selected_level_index and self:get_difficulty_data(self.selected_level_index) local difficulty_layout = difficulty_data and difficulty_data[self.selected_difficulty_stepper_index] _SELECTED_DIFFICULTY_KEY = difficulty_layout and difficulty_layout.key @@ -412,6 +413,7 @@ function vmf.modify_map_view() end end + -- Restores map_view to its defaults function vmf.reset_map_view() local map_view = get_map_view() diff --git a/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui_definitions.lua b/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui_definitions.lua index 6d180ca..14f72fb 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui_definitions.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/mutators_gui_definitions.lua @@ -10,7 +10,7 @@ local scenegraph_definition = { is_root = true, }, - -- fix for fullhd windowed (not fullscreen) mode (if everything else will inherit from sg_root, its children will + -- Fix for FullHD windowed (not fullscreen) mode (if everything else will inherit from sg_root, its children will -- stick to the window border instead of the black gap) sg_placeholder = { size = {1920, 1080}, @@ -107,26 +107,6 @@ local widgets_definition = { } } }, - --[[ - mutators_list_debug = { - scenegraph_id = "sg_mutators_list", - element = { - passes = { - { - pass_type = "rect", - style_id = "mutators_list_background", - } - } - }, - content = {}, - style = { - mutators_list_background = { - scenegraph_id = "sg_mutators_list", - color = {255, 0, 0, 0} - }, - } - }, - ]] -- Widgets that detects mousewheel scrolls inside itself mousewheel_scroll_area = { @@ -152,6 +132,7 @@ local widgets_definition = { } widgets_definition.scrollbar.content.disable_frame = true -- Hide scrollbar frame + -- The 4th button, which will toggle old "Party" view (which is replaced by "Mutators" view) local party_button_widget_defenition = UIWidgets.create_octagon_button( { @@ -165,6 +146,7 @@ local party_button_widget_defenition = UIWidgets.create_octagon_button( "sg_mutators_button" ) + -- Text displayed when user has 0 mutators local no_mutators_text_widget = { scenegraph_id = "sg_no_mutators_text", @@ -285,11 +267,11 @@ local function create_mutator_widget(mutator, offset_function_callback) highlight_hotspot = {}, - tooltip_text = "", -- is always being changed in local_offset pass + tooltip_text = "", -- always changes in local_offset pass hover_texture = "playerlist_hover", - checkbox_texture = "checkbox_unchecked", -- is always being changed in local_offset pass + checkbox_texture = "checkbox_unchecked", -- always changes in local_offset pass -- Presets checkbox_unchecked_texture = "checkbox_unchecked", @@ -306,7 +288,7 @@ local function create_mutator_widget(mutator, offset_function_callback) font_size = 24, font_type = "hell_shark", dynamic_font = true, - text_color = Colors.get_color_table_with_alpha("white", 255) -- is always being changed in local_offset pass + text_color = Colors.get_color_table_with_alpha("white", 255) -- always changes in local_offset pass }, hover_texture = { @@ -323,15 +305,13 @@ local function create_mutator_widget(mutator, offset_function_callback) tooltip_text = { font_type = "hell_shark", font_size = 18, - horizontal_alignment = "left", - vertical_alignment = "top", cursor_side = "right", max_width = 425, - cursor_offset = {0, 0}, -- is always being changed in local_offset pass + cursor_offset = {0, 0}, -- always changes in local_offset pass cursor_default_offset = {27, -27} }, - size = {370, 32}, + size = {370, 32} } } end 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 index e936d17..66dc45c 100644 --- a/vmf/scripts/mods/vmf/modules/ui/mutators/test/mutator_test.lua +++ b/vmf/scripts/mods/vmf/modules/ui/mutators/test/mutator_test.lua @@ -134,7 +134,10 @@ mod_data.name = "lmao" mod_data.is_mutator = true mod_data.mutator_settings = { difficulty_levels = {"hardest"}, - enable_after_these = {"ayyyy"} + enable_after_these = {"ayyyy"}, + dice = { + bonus = 2 + } } mod:initialize_data(mod_data) mod.on_enabled = function(init_call) mod:echo("lmao on_enabled(" .. (init_call and "init)" or ")")) end diff --git a/vmf/scripts/mods/vmf/vmf_loader.lua b/vmf/scripts/mods/vmf/vmf_loader.lua index d15e77f..829d07a 100644 --- a/vmf/scripts/mods/vmf/vmf_loader.lua +++ b/vmf/scripts/mods/vmf/vmf_loader.lua @@ -66,7 +66,7 @@ return { object.vmf.ping_vmf_users() if VT1 then object.vmf.modify_map_view() end - if VT1 then object.vmf.temp_show_mutator_compatibility() end + if VT1 then object.vmf.mutators_delete_raw_config() end object.vmf.all_mods_loaded_event()