diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/default_config.lua b/vmf_source/scripts/mods/vmf/modules/mutators/default_config.lua index 6f07938..4c4d85c 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/default_config.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/default_config.lua @@ -5,8 +5,8 @@ return { bonus = 0 }, server_name = "", - title = "default_title", - --short_title = "", + title = "", + short_title = "", difficulties = { "easy", "normal", diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/gui.lua b/vmf_source/scripts/mods/vmf/modules/mutators/gui.lua new file mode 100644 index 0000000..9bfe2cd --- /dev/null +++ b/vmf_source/scripts/mods/vmf/modules/mutators/gui.lua @@ -0,0 +1,176 @@ +local vmf = get_mod("VMF") +local mutators = vmf.mutators + + +local window = nil +local button = nil +local window_opened = false + +local function update_window_visibility(map_view) + if not window then return end + button.visible = map_view and map_view.friends and not map_view.friends:is_active() + window.visible = window_opened and button.visible +end + +local function destroy_window(map_view) + if window then + window:destroy() + window = nil + button:destroy() + map_view.ui_scenegraph.settings_button.position[1] = map_view.ui_scenegraph.settings_button.position[1] - 50 + map_view.ui_scenegraph.friends_button.position[1] = map_view.ui_scenegraph.friends_button.position[1] - 50 + map_view.ui_scenegraph.lobby_button.position[1] = map_view.ui_scenegraph.lobby_button.position[1] - 50 + end +end + +local function create_window(map_view) + destroy_window(map_view) + + vmf.sort_mutators() + vmf.disable_impossible_mutators() + + local window_size = {0, 0} + local window_position = {50, 500} + + window = get_mod("gui").create_window("mutators_window", window_position, window_size) + + for i, mutator in ipairs(mutators) do + window:create_checkbox("label" .. mutator:get_name(), {10, 40 * i}, {30, 30}, mutator:get_config().title, mutator:is_enabled(), function() + if not mutator:is_enabled() and mutator:can_be_enabled() then + mutator:enable() + elseif mutator:is_enabled() then + mutator:disable() + else + create_window(map_view) + end + end) + end + + window:init() + + button = get_mod("gui").create_window("mutators_button", window_position, window_size) + button:create_button("mutators", {55, -75}, {65, 65}, "Mut", function() + window_opened = not window_opened + end) + button:init() + + map_view.ui_scenegraph.settings_button.position[1] = map_view.ui_scenegraph.settings_button.position[1] + 50 + map_view.ui_scenegraph.friends_button.position[1] = map_view.ui_scenegraph.friends_button.position[1] + 50 + map_view.ui_scenegraph.lobby_button.position[1] = map_view.ui_scenegraph.lobby_button.position[1] + 50 + + update_window_visibility(map_view) +end + +vmf:hook("MapView.on_enter", function(func, self, ...) + func(self, ...) + print("on_enter") + vmf:pcall(function() create_window(self) end) +end) + +vmf:hook("MapView.on_level_index_changed", function(func, self, ...) + func(self, ...) + print("on_level_index_changed") + vmf:pcall(function() create_window(self) end) +end) + +vmf:hook("MapView.on_difficulty_index_changed", function(func, self, ...) + func(self, ...) + print("on_difficulty_index_changed") + vmf:pcall(function() create_window(self) end) +end) + +vmf:hook("MapView.set_difficulty_stepper_index", function(func, self, ...) + func(self, ...) + print("set_difficulty_stepper_index") + vmf:pcall(function() create_window(self) end) +end) + +vmf:hook("MapView.on_exit", function(func, self, ...) + func(self, ...) + print("on_exit") + vmf:pcall(function() destroy_window(self) end) + window_opened = false +end) + +vmf:hook("MapView.suspend", function(func, self, ...) + func(self, ...) + print("suspend") + vmf:pcall(function() destroy_window(self) end) +end) + +vmf:hook("MapView.update", function(func, self, dt, t) + func(self, dt, t) + vmf:pcall(function() update_window_visibility(self) end) +end) + +vmf:hook("MapView.draw", function(func, self, input_service, gamepad_active, dt) + local ui_renderer = self.ui_renderer + local ui_scenegraph = self.ui_scenegraph + + UIRenderer.begin_pass(ui_renderer, ui_scenegraph, input_service, dt, nil, self.render_settings) + + for _, widget in ipairs(self.background_widgets) do + UIRenderer.draw_widget(ui_renderer, widget) + end + + local number_of_player = self.number_of_player or 0 + + for i = 1, number_of_player, 1 do + local widget = self.player_list_widgets[i] + + UIRenderer.draw_widget(ui_renderer, widget) + end + + if not window_opened then + if self.settings_button_widget.content.toggled then + for widget_name, widget in pairs(self.advanced_settings_widgets) do + UIRenderer.draw_widget(ui_renderer, widget) + end + else + for widget_name, widget in pairs(self.normal_settings_widgets) do + UIRenderer.draw_widget(ui_renderer, widget) + end + end + end + + UIRenderer.draw_widget(ui_renderer, self.player_list_conuter_text_widget) + UIRenderer.draw_widget(ui_renderer, self.description_field_widget) + UIRenderer.draw_widget(ui_renderer, self.title_text_widget) + UIRenderer.draw_widget(ui_renderer, self.game_mode_selection_bar_widget) + UIRenderer.draw_widget(ui_renderer, self.game_mode_selection_bar_bg_widget) + UIRenderer.draw_widget(ui_renderer, self.private_checkbox_widget) + + if not gamepad_active then + UIRenderer.draw_widget(ui_renderer, self.friends_button_widget) + UIRenderer.draw_widget(ui_renderer, self.settings_button_widget) + UIRenderer.draw_widget(ui_renderer, self.confirm_button_widget) + UIRenderer.draw_widget(ui_renderer, self.cancel_button_widget) + UIRenderer.draw_widget(ui_renderer, self.lobby_button_widget) + + if not self.confirm_button_widget.content.button_hotspot.disabled then + UIRenderer.draw_widget(ui_renderer, self.button_eye_glow_widget) + else + UIRenderer.draw_widget(ui_renderer, self.confirm_button_disabled_tooltip_widget) + end + else + UIRenderer.draw_widget(ui_renderer, self.background_overlay_console_widget) + UIRenderer.draw_widget(ui_renderer, self.gamepad_button_selection_widget) + end + + local draw_intro_description = self.draw_intro_description + + if draw_intro_description then + for key, text_widget in pairs(self.description_text_widgets) do + UIRenderer.draw_widget(ui_renderer, text_widget) + end + end + + UIRenderer.end_pass(ui_renderer) + + local friends_menu_active = self.friends:is_active() + + if gamepad_active and not friends_menu_active and not self.popup_id and not draw_intro_description then + self.menu_input_description:draw(ui_renderer, dt) + end + +end) diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/info.lua b/vmf_source/scripts/mods/vmf/modules/mutators/info.lua index 77c657d..c938fb0 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/info.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/info.lua @@ -1,12 +1,19 @@ local vmf = get_mod("VMF") local mutators = vmf.mutators +local were_enabled_before = false + local function get_enabled_mutators_names(short) - local name = "" + local name = nil for _, mutator in ipairs(mutators) do local config = mutator:get_config() if mutator:is_enabled() then - name = name .. " " .. (short and config.short_title or config.title) + local added_name = (short and config.short_title or config.title or mutator:get_name()) + if name then + name = name .. " " .. added_name + else + name = added_name + end end end return name @@ -63,6 +70,14 @@ end) vmf:hook("MatchmakingStateHostGame.host_game", function(func, self, ...) func(self, ...) set_lobby_data() + local names = get_enabled_mutators_names() + if names then + Managers.chat:send_system_chat_message(1, "ENABLED MUTATORS: " .. names, 0, true) + were_enabled_before = true + elseif were_enabled_before then + Managers.chat:send_system_chat_message(1, "ALL MUTATORS DISABLED", 0, true) + were_enabled_before = false + end end) vmf:hook("MatchmakingManager.rpc_matchmaking_request_join_lobby", function(func, self, sender, client_cookie, host_cookie, lobby_id, friend_join) diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutators.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutators.lua index e0ad34a..d9b03fd 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutators.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutators.lua @@ -3,8 +3,8 @@ local vmf = get_mod("VMF") -- List of mods that are also mutators in order in which they should be enabled -- This is populated via VMFMod.register_as_mutator -local mutators = {} -vmf.mutators = mutators +vmf.mutators = {} +local mutators = vmf.mutators local mutators_config = {} local default_config = dofile("scripts/mods/vmf/modules/mutators/default_config") @@ -25,31 +25,13 @@ local mutators_sorted = false --[[ - PRIVATE METHODS + PUBLIC METHODS ]]-- -local addDice, removeDice = dofile("scripts/mods/vmf/modules/mutators/dice") -local set_lobby_data = dofile("scripts/mods/vmf/modules/mutators/info") - --- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name -local function update_mutators_sequence(mutator_name, enable_these_after) - if not mutators_sequence[mutator_name] then - mutators_sequence[mutator_name] = {} - end - for _, other_mutator_name in ipairs(enable_these_after) do - - if mutators_sequence[other_mutator_name] and table.has_item(mutators_sequence[other_mutator_name], mutator_name) then - vmf:error("Mutators '" .. mutator_name .. "' and '" .. other_mutator_name .. "' are both set to load after the other one.") - elseif not table.has_item(mutators_sequence[mutator_name], other_mutator_name) then - table.insert(mutators_sequence[mutator_name], other_mutator_name) - end - - end - table.combine(mutators_sequence[mutator_name], enable_these_after) -end - -- Sorts mutators in order they should be enabled -local function sort_mutators() +vmf.sort_mutators = function() + + if mutators_sorted then return end -- LOG -- vmf:dump(mutators_sequence, "seq", 5) @@ -105,16 +87,48 @@ local function sort_mutators() -- /LOG -- end -local function mutator_can_be_enabled(mutator) - return (not Managers.state or not Managers.state.difficulty:get_difficulty()) or table.has_item(mutator:get_config().difficulties, Managers.state.difficulty:get_difficulty()) +-- Disables mutators that cannot be enabled right now +vmf.disable_impossible_mutators = function() + for _, mutator in pairs(mutators) do + if mutator:is_enabled() and not mutator:can_be_enabled() then + mutator:disable() + end + end end + +--[[ + PRIVATE METHODS +]]-- + +local addDice, removeDice = dofile("scripts/mods/vmf/modules/mutators/dice") +local set_lobby_data = dofile("scripts/mods/vmf/modules/mutators/info") + +-- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name +local function update_mutators_sequence(mutator_name, enable_these_after) + if not mutators_sequence[mutator_name] then + mutators_sequence[mutator_name] = {} + end + for _, other_mutator_name in ipairs(enable_these_after) do + + if mutators_sequence[other_mutator_name] and table.has_item(mutators_sequence[other_mutator_name], mutator_name) then + vmf:error("Mutators '" .. mutator_name .. "' and '" .. other_mutator_name .. "' are both set to load after the other one.") + elseif not table.has_item(mutators_sequence[mutator_name], other_mutator_name) then + table.insert(mutators_sequence[mutator_name], other_mutator_name) + end + + end + table.combine(mutators_sequence[mutator_name], enable_these_after) +end + +-- Called after mutator is enabled local function on_enabled(mutator) local config = mutator:get_config() addDice(config.dice) set_lobby_data() end +-- Called after mutator is disabled local function on_disabled(mutator) local config = mutator:get_config() removeDice(config.dice) @@ -130,14 +144,17 @@ local function set_mutator_state(mutator, state) return end - if state and not mutator_can_be_enabled(mutator) then - mutator:error("Can't enable mutator - incorrect difficulty") + if state == mutator:is_enabled() then + return + end + + if state and not mutator:can_be_enabled() then return end -- Sort mutators if this is the first call if not mutators_sorted then - sort_mutators() + vmf.sort_mutators() end local disabled_mutators = {} @@ -179,6 +196,11 @@ local function set_mutator_state(mutator, state) print("---------") end + +--[[ + MUTATOR'S OWN METHODS +]]-- + -- Enables mutator (pcall for now) local function enable_mutator(self) vmf:pcall(function() set_mutator_state(self, true) end) @@ -189,15 +211,35 @@ local function disable_mutator(self) vmf:pcall(function() set_mutator_state(self, false) end) end +-- Checks current difficulty and map selection screen settings to determine if a mutator can be enabled +local function can_be_enabled(self) + + local mutator_difficulties = self:get_config().difficulties + + local actual_difficulty = Managers.state and Managers.state.difficulty:get_difficulty() + local right_difficulty = not actual_difficulty or table.has_item(mutator_difficulties, actual_difficulty) + + local ingame_ui = Managers.matchmaking and Managers.matchmaking.ingame_ui + local map_view = ingame_ui and ingame_ui.views and ingame_ui.views.map_view + local map_view_active = map_view and map_view.active + local right_unapplied_difficulty = false + + if map_view_active then + + local difficulty_data = map_view.selected_level_index and map_view:get_difficulty_data(map_view.selected_level_index) + local difficulty_layout = difficulty_data and difficulty_data[map_view.selected_difficulty_stepper_index] + local difficulty_key = difficulty_layout and difficulty_layout.key + right_unapplied_difficulty = difficulty_key and table.has_item(mutator_difficulties, difficulty_key) + end + + return (map_view_active and right_unapplied_difficulty) or (not map_view_active and right_difficulty) +end + +-- Returns the config object for mutator from mutators_config local function get_config(self) return mutators_config[self:get_name()] end - ---[[ - PUBLIC METHODS -]]-- - -- Turns a mod into a mutator VMFMod.register_as_mutator = function(self, config) if not config then config = {} end @@ -220,6 +262,7 @@ VMFMod.register_as_mutator = function(self, config) end end if _config.short_title == "" then _config.short_title = nil end + if _config.title == "" then _config.title = nil end if config.enable_before_these then update_mutators_sequence(mod_name, config.enable_before_these) @@ -233,6 +276,7 @@ VMFMod.register_as_mutator = function(self, config) self.enable = enable_mutator self.disable = disable_mutator + self.can_be_enabled = can_be_enabled self.get_config = get_config @@ -242,19 +286,21 @@ VMFMod.register_as_mutator = function(self, config) self:init_state(false) end + --[[ HOOKS ]]-- vmf:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) - for _, mutator in ipairs(mutators) do - if mutator:is_enabled() and not mutator_can_be_enabled(mutator:get_config()) then - mutator:disable() - end - end + vmf.disable_impossible_mutators() return func(self, difficulty) end) +--[[ + GUI +]]-- +dofile("scripts/mods/vmf/modules/mutators/gui") + @@ -283,7 +329,8 @@ local mutator_whatever = new_mod("mutator_whatever") mutator555:register_as_mutator({ enable_after_these = { "mutation" - } + }, + title = "mutator555" }) mutator555:create_options({}, true, "mutator555", "mutator555 description") mutator555.on_enabled = function() end @@ -298,7 +345,8 @@ deathwish:register_as_mutator({ }, difficulties = { "hardest" - } + }, + title = "deathwish" }) deathwish:create_options({}, true, "deathwish", "deathwish description") deathwish.on_enabled = function() @@ -312,6 +360,11 @@ local breeds mutation:register_as_mutator({ enable_after_these = { "deathwish" + }, + title = "mutation", + dice = { + grims = 5, + tomes = 1 } }) mutation:create_options({}, true, "mutation", "mutation description") @@ -333,13 +386,21 @@ end mutator3:register_as_mutator({ enable_before_these = { "mutator555" + }, + title = "mutator3", + dice = { + grims = 5, + tomes = 1, + bonus = 22 } }) mutator3:create_options({}, true, "mutator3", "mutator3 description") mutator3.on_enabled = function() end mutator3.on_disabled = function() end -mutator_whatever:register_as_mutator() +mutator_whatever:register_as_mutator({ + title = "mutator_whatever" +}) mutator_whatever:create_options({}, true, "mutator_whatever", "mutator_whatever description") mutator_whatever.on_enabled = function() end mutator_whatever.on_disabled = function() end