diff --git a/vmf_source/localization/mutator_manager.lua b/vmf_source/localization/mutator_manager.lua new file mode 100644 index 0000000..9c28c04 --- /dev/null +++ b/vmf_source/localization/mutator_manager.lua @@ -0,0 +1,26 @@ +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" + } +} \ No newline at end of file diff --git a/vmf_source/resource_packages/vmf.package b/vmf_source/resource_packages/vmf.package index bee278a..1981927 100644 --- a/vmf_source/resource_packages/vmf.package +++ b/vmf_source/resource_packages/vmf.package @@ -11,7 +11,7 @@ material = [ ] lua = [ - "localization/vmf" + "localization/*" "scripts/mods/vmf/*" "scripts/mods/vmf/functions/*" diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_default_config.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_default_config.lua index b36d451..3a0c4f9 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_default_config.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_default_config.lua @@ -6,6 +6,7 @@ return { }, title = "", short_title = "", + description = "No description provided", difficulties = { "easy", "normal", diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_dice.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_dice.lua index d34dcb2..4f258f0 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_dice.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_dice.lua @@ -63,4 +63,7 @@ local removeDice = function(dice) adjustDice(dice.grims, dice.tomes, dice.bonus, -1) end -return addDice, removeDice +return { + addDice = addDice, + removeDice = removeDice +} diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui.lua index 5826625..dca3245 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui.lua @@ -3,7 +3,7 @@ local mutators = manager.mutators local definitions = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_gui_definitions") -local PER_PAGE = 5 +local PER_PAGE = definitions.PER_PAGE local mutators_view = { @@ -12,6 +12,8 @@ local mutators_view = { was_active = false, map_view = nil, current_page = 1, + mutators_sorted = {}, + mutator_checkboxes = {}, init = function(self, map_view) if self.initialized then return end @@ -19,15 +21,21 @@ local mutators_view = { self.map_view = map_view if not self.map_view then return end + self:update_mutator_list() + -- Recreate the map_view scenegraph defs self.map_view.scenegraph_definition = UISceneGraph.init_scenegraph(definitions.scenegraph_definition) -- Setup custom widgets self.widgets = { banner_mutators = UIWidget.init(definitions.new_widgets.banner_mutators_widget), - mutators_button = UIWidget.init(definitions.new_widgets.mutators_button_widget), + mutators_button = UIWidget.init(definitions.new_widgets.mutators_button_widget) } + for i = 1, PER_PAGE do + table.insert(self.mutator_checkboxes, UIWidget.init(definitions.new_widgets["mutator_checkbox_" .. i])) + end + -- Save widgets we're gonna mess with local widgets = self.map_view.normal_settings_widget_types self.saved_widgets = { @@ -85,6 +93,15 @@ local mutators_view = { print("DEINIT") end, + -- Sorts mutators by title + update_mutator_list = function(self) + self.mutators_sorted = {} + for _, mutator in ipairs(mutators) do + table.insert(self.mutators_sorted, {mutator:get_name(), mutator:get_config().title or mutator:get_name()}) + end + table.sort(self.mutators_sorted, function(a, b) return string.lower(a[2]) < string.lower(b[2]) end) + end, + update = function(self) if not self.initialized then self:init() @@ -127,6 +144,54 @@ local mutators_view = { local widgets = self.map_view.normal_settings_widget_types widgets.adventure.banner_level.content.tooltip_hotspot.disabled = true widgets.survival.banner_level.content.tooltip_hotspot.disabled = true + + self:update_checkboxes() + end + end, + + update_checkboxes = function(self) + + local widgets = self.map_view.normal_settings_widget_types + + for i = 1, PER_PAGE do + local current_index = PER_PAGE * (self.current_page - 1) + i + local checkbox = self.mutator_checkboxes[i] + local hotspot = checkbox.content.button_hotspot + if #self.mutators_sorted < current_index then + checkbox.content.setting_text = "" + checkbox.content.tooltip_text = "" + widgets.adventure["mutator_checkbox_" .. i] = nil + widgets.survival["mutator_checkbox_" .. i] = nil + else + local mutator_info = self.mutators_sorted[current_index] + local mutator = get_mod(mutator_info[1]) + + checkbox.content.setting_text = mutator_info[2] + checkbox.content.tooltip_text = self:generate_tooltip_for(mutator) + widgets.adventure["mutator_checkbox_" .. i] = checkbox + widgets.survival["mutator_checkbox_" .. i] = checkbox + + local active = mutator:can_be_enabled() + local color = active and "cheeseburger" or "slate_gray" + local color_hover = active and "white" or "slate_gray" + checkbox.style.setting_text.text_color = Colors.get_color_table_with_alpha(color, 255) + checkbox.style.setting_text_hover.text_color = Colors.get_color_table_with_alpha(color_hover, 255) + checkbox.style.checkbox_style.color = Colors.get_color_table_with_alpha(color_hover, 255) + + if hotspot.on_hover_enter then + self.map_view:play_sound("Play_hud_hover") + end + + if hotspot.on_release then + self.map_view:play_sound("Play_hud_hover") + if mutator:is_enabled() then + mutator:disable() + else + mutator:enable() + end + end + checkbox.content.selected = mutator:is_enabled() + end end end, @@ -149,6 +214,7 @@ local mutators_view = { -- Update steppers self.map_view.steppers.level.widget.style.setting_text.offset[2] = -10000 + self.map_view.steppers.level.widget.style.hover_texture.offset[2] = -10000 local level_stepper_widget = self.map_view.steppers.level.widget local num_pages = math.ceil(#mutators/PER_PAGE) level_stepper_widget.content.left_button_hotspot.disable_button = num_pages <= 1 @@ -156,7 +222,7 @@ local mutators_view = { self.active = true - print("ACTIVE") + print("ACTIVE!") end, deactivate = function(self) @@ -178,8 +244,15 @@ local mutators_view = { -- Update steppers self.map_view.steppers.level.widget.style.setting_text.offset[2] = -120 + self.map_view.steppers.level.widget.style.hover_texture.offset[2] = -19.5 self.map_view:update_level_stepper() + -- Mutator checkboxes + for i = 1, PER_PAGE do + widgets.adventure["mutator_checkbox_" .. i] = nil + widgets.survival["mutator_checkbox_" .. i] = nil + end + self.active = false print("DEACTIVE") @@ -200,12 +273,49 @@ local mutators_view = { end self.current_page = new_index - print("TEST", tostring(new_index)) else self.map_view:on_level_index_changed(index_change) end end, + generate_tooltip_for = function(self, mutator) + local config = mutator:get_config() + local text = config.description + local supports_difficulty = mutator:supports_current_difficulty() + + if not supports_difficulty then + text = text .. "\nSupported difficulty levels:" + for i, difficulty in ipairs(config.difficulties) do + text = text .. (i == 1 and " " or ", ") .. manager:localize(difficulty) + end + end + + local incompatible_mutators = mutator:get_incompatible_mutators(true) + local currently_compatible = #incompatible_mutators == 0 + if supports_difficulty and #incompatible_mutators == 0 then + incompatible_mutators = mutator:get_incompatible_mutators() + end + if #incompatible_mutators > 0 then + if currently_compatible and config.incompatible_with_all or #incompatible_mutators == #mutators - 1 then + text = text .. "\nIncompatible with all other mutators" + else + text = text .. "\nIncompatible with:" + for i, other_mutator in ipairs(incompatible_mutators) do + local name = (other_mutator:get_config().title or other_mutator:get_name()) + text = text .. (i == 1 and " " or ", ") .. name + end + end + elseif config.compatible_with_all then + text = text .. "\nCompatible with all other mutators" + end + + if mutator:is_enabled() and not supports_difficulty then + text = text .. "\nWill be disabled when Play is pressed" + end + + return text + end, + setup_hooks = function(self) -- Update the view after map_view has updated @@ -235,6 +345,26 @@ local mutators_view = { func(map_view) end end) + + --[[ + manager:hook("MapView.on_level_index_changed", function(func, map_view, ...) + func(map_view, ...) + print("on_level_index_changed") + manager.disable_impossible_mutators(true) + end) + + manager:hook("MapView.on_difficulty_index_changed", function(func, map_view, ...) + func(map_view, ...) + print("on_difficulty_index_changed") + manager.disable_impossible_mutators(true) + end) + + manager:hook("MapView.set_difficulty_stepper_index", function(func, map_view, ...) + func(map_view, ...) + print("set_difficulty_stepper_index") + manager.disable_impossible_mutators(true) + end) + --]] end, reset_hooks = function(self) @@ -242,28 +372,15 @@ local mutators_view = { manager:hook_remove("MapView.on_enter") manager:hook_remove("MapView.on_exit") manager:hook_remove("MapView.update_level_stepper") + -- manager:hook_remove("MapView.on_level_index_changed") + -- manager:hook_remove("MapView.on_difficulty_index_changed") + -- manager:hook_remove("MapView.set_difficulty_stepper_index") end, + + get_map_view = function(self) + local ingame_ui = Managers.matchmaking and Managers.matchmaking.ingame_ui + return ingame_ui and ingame_ui.views and ingame_ui.views.map_view + end } --- Initialize mutators view after map view -manager:hook("MapView.init", function(func, self, ...) - func(self, ...) - manager:pcall(function() mutators_view:init(self) end) -end) - --- Destroy mutators view after map view -manager:hook("MapView.destroy", function(func, ...) - mutators_view:deinitialize() - func(...) -end) - - --- Initialize mutators view when map_view has been initialized already -local function get_map_view() - local ingame_ui = Managers.matchmaking and Managers.matchmaking.ingame_ui - return ingame_ui and ingame_ui.views and ingame_ui.views.map_view -end - -manager:pcall(function() mutators_view:init(get_map_view()) end) - return mutators_view \ No newline at end of file diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui_definitions.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui_definitions.lua index af3d4a4..7d620f0 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui_definitions.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_gui_definitions.lua @@ -1,6 +1,9 @@ local definitions = local_require("scripts/ui/views/map_view_definitions") +local scenegraph_definition = definitions.scenegraph_definition -definitions.scenegraph_definition.mutators_button = { +definitions.PER_PAGE = 6 + +scenegraph_definition.mutators_button = { vertical_alignment = "bottom", parent = "banner_party", horizontal_alignment = "center", @@ -14,8 +17,7 @@ definitions.scenegraph_definition.mutators_button = { 1 } } - -definitions.scenegraph_definition.banner_mutators_text = { +scenegraph_definition.banner_mutators_text = { vertical_alignment = "center", parent = "banner_level", horizontal_alignment = "center", @@ -30,7 +32,8 @@ definitions.scenegraph_definition.banner_mutators_text = { } } -definitions.new_widgets = { + +local new_widgets = { banner_mutators_widget = UIWidgets.create_texture_with_text_and_tooltip("title_bar", "Mutators", "Enable and disable mutators", "banner_level", "banner_mutators_text", { vertical_alignment = "center", scenegraph_id = "banner_mutators_text", @@ -169,4 +172,149 @@ definitions.new_widgets = { } } +for i = 1, definitions.PER_PAGE do + new_widgets["mutator_checkbox_" .. i] = { + scenegraph_id = "mutator_checkbox_" .. i, + element = { + passes = { + { + pass_type = "hotspot", + content_id = "button_hotspot" + }, + { + style_id = "tooltip_text", + pass_type = "tooltip_text", + text_id = "tooltip_text", + content_check_function = function (ui_content) + return ui_content.button_hotspot.is_hover + end + }, + { + style_id = "setting_text", + pass_type = "text", + text_id = "setting_text", + content_check_function = function (content) + return not content.button_hotspot.is_hover + end + }, + { + style_id = "setting_text_hover", + pass_type = "text", + text_id = "setting_text", + content_check_function = function (content) + return content.button_hotspot.is_hover + end + }, + { + pass_type = "texture", + style_id = "checkbox_style", + texture_id = "checkbox_unchecked_texture", + content_check_function = function (content) + return not content.selected + end + }, + { + pass_type = "texture", + style_id = "checkbox_style", + texture_id = "checkbox_checked_texture", + content_check_function = function (content) + return content.selected + end + } + } + }, + content = { + tooltip_text = "Mutator ajksad " .. i, + checkbox_unchecked_texture = "checkbox_unchecked", + checkbox_checked_texture = "checkbox_checked", + selected = false, + setting_text = "Mutator asdasasda " .. i * 3, + button_hotspot = {} + }, + style = { + checkbox_style = { + size = { + 20, + 20 + }, + offset = { + 0, + 6, + 1 + }, + color = { + 255, + 255, + 255, + 255 + } + }, + setting_text = { + vertical_alignment = "center", + font_size = 22, + localize = false, + horizontal_alignment = "left", + word_wrap = true, + font_type = "hell_shark", + text_color = Colors.get_color_table_with_alpha("cheeseburger", 255), + offset = { + 24, + 2, + 4 + } + }, + setting_text_hover = { + vertical_alignment = "center", + font_size = 22, + localize = false, + horizontal_alignment = "left", + word_wrap = true, + font_type = "hell_shark", + text_color = Colors.get_color_table_with_alpha("white", 255), + offset = { + 24, + 2, + 4 + } + }, + tooltip_text = { + font_size = 18, + max_width = 500, + localize = false, + cursor_side = "right", + horizontal_alignment = "left", + vertical_alignment = "top", + font_type = "hell_shark", + text_color = Colors.get_color_table_with_alpha("white", 255), + line_colors = {}, + offset = { + 0, + 0, + 50 + }, + cursor_offset = { + -10, + -27 + } + } + } + } + scenegraph_definition["mutator_checkbox_" .. i] = { + vertical_alignment = "center", + parent = "banner_party", + horizontal_alignment = "left", + size = { + 310, + 30 + }, + position = { + 30, + 520 - 40 * (i - 1), + 1 + } + } +end + +definitions.new_widgets = new_widgets + return definitions \ No newline at end of file diff --git a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_manager.lua b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_manager.lua index 7020c50..ecdd0e5 100644 --- a/vmf_source/scripts/mods/vmf/modules/mutators/mutator_manager.lua +++ b/vmf_source/scripts/mods/vmf/modules/mutators/mutator_manager.lua @@ -1,5 +1,6 @@ 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 -- This is populated via VMFMod.register_as_mutator @@ -88,7 +89,7 @@ manager.sort_mutators = function() end -- Disables mutators that cannot be enabled right now -manager.disable_impossible_mutators = function() +manager.disable_impossible_mutators = function(notify, everybody) local disabled_mutators = {} for _, mutator in pairs(mutators) do if mutator:is_enabled() and not mutator:can_be_enabled() then @@ -96,6 +97,17 @@ manager.disable_impossible_mutators = function() table.insert(disabled_mutators, mutator) end end + if #disabled_mutators > 0 and notify then + local message = everybody and "MUTATORS DISABLED DUE TO DIFFICULTY CHANGE:" or "Mutators disabled due to difficulty change:" + for _, mutator in ipairs(disabled_mutators) do + message = message .. " " .. (mutator:get_config().title or mutator:get_name()) + end + if everybody then + Managers.chat:send_system_chat_message(1, message, 0, true) + else + manager:echo(message) + end + end return disabled_mutators end @@ -105,7 +117,7 @@ end ]]-- local mutators_view = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_gui") -local addDice, removeDice = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_dice") +local dice_manager = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_dice") local set_lobby_data = manager:dofile("scripts/mods/vmf/modules/mutators/mutator_info") -- Adds mutator names from enable_these_after to the list of mutators that should be enabled after the mutator_name @@ -166,41 +178,17 @@ local function is_compatible(mutator, other_mutator) return compatible end --- Disables enabled mutators that aren't compatible with the specified -local function disable_incompatible_with(mutator) - local names = nil - for _, other_mutator in ipairs(mutators) do - if ( - other_mutator ~= mutator and - other_mutator:is_enabled() and - not is_compatible(mutator, other_mutator) - ) then - other_mutator:disable() - local name = other_mutator:get_config().title or other_mutator:get_name() - if names then - names = names .. " " .. name - else - names = name - end - end - end - if names then - -- TODO: output this to the menu instead of chat - manager:echo("These mutators are incompatible with " .. mutator:get_name() .. " and were disabled: " .. names) - end -end - -- Called after mutator is enabled local function on_enabled(mutator) local config = mutator:get_config() - addDice(config.dice) + dice_manager.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) + dice_manager.removeDice(config.dice) set_lobby_data() end @@ -221,16 +209,15 @@ local function set_mutator_state(mutator, state) return end + if state and #mutator:get_incompatible_mutators(true) > 0 then + return + end + -- Sort mutators if this is the first call if not mutators_sorted then manager.sort_mutators() end - -- Disable mutators that aren't compatible - if state then - disable_incompatible_with(mutator) - end - local disabled_mutators = {} local enable_these_after = mutators_sequence[mutator:get_name()] @@ -289,8 +276,13 @@ 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 + if #self:get_incompatible_mutators(true) > 0 then return false end + return self:supports_current_difficulty() +end + +local function supports_current_difficulty(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) @@ -314,6 +306,20 @@ local function get_config(self) return mutators_config[self:get_name()] end +local function get_incompatible_mutators(self, enabled_only) + local incompatible_mutators = {} + for _, other_mutator in ipairs(mutators) do + if ( + other_mutator ~= self and + (not enabled_only or other_mutator:is_enabled()) and + not is_compatible(self, other_mutator) + ) then + table.insert(incompatible_mutators, other_mutator) + end + end + return incompatible_mutators +end + -- Turns a mod into a mutator VMFMod.register_as_mutator = function(self, config) if not config then config = {} end @@ -351,13 +357,17 @@ VMFMod.register_as_mutator = function(self, config) self.enable = enable_mutator self.disable = disable_mutator self.can_be_enabled = can_be_enabled + self.supports_current_difficulty = supports_current_difficulty self.get_config = get_config + self.get_incompatible_mutators = get_incompatible_mutators mutators_sorted = false -- Always init in the off state self:init_state(false) + + mutators_view:update_mutator_list() end @@ -365,19 +375,26 @@ end HOOKS ]]-- manager:hook("DifficultyManager.set_difficulty", function(func, self, difficulty) - local disabled_mutators = manager.disable_impossible_mutators() - if #disabled_mutators > 0 then - local message = "MUTATORS DISABLED DUE TO DIFFICULTY CHANGE:" - for _, mutator in ipairs(disabled_mutators) do - message = message .. " " .. mutator:get_config().title or mutator:get_name() - end - Managers.chat:send_system_chat_message(1, message, 0, true) - end + manager.disable_impossible_mutators(true, true) return func(self, difficulty) end) +-- Initialize mutators view after map view +manager:hook("MapView.init", function(func, self, ...) + func(self, ...) + manager:pcall(function() mutators_view:init(self) end) +end) +-- Destroy mutators view after map view +manager:hook("MapView.destroy", function(func, ...) + mutators_view:deinitialize() + func(...) +end) + + +-- Initialize mutators view when map_view has been initialized already +manager:pcall(function() mutators_view:init(mutators_view:get_map_view()) end) @@ -401,10 +418,7 @@ local mutator3 = new_mod("mutator3") local mutator555 = new_mod("mutator555") mutator555:register_as_mutator({ - compatible_with_all = true, - incompatible_with = { - "mutator2" - } + incompatible_with_all = true }) mutator555:create_options({}, true, "mutator555", "mutator555 description") mutator555.on_enabled = function() end @@ -412,20 +426,25 @@ mutator555.on_disabled = function() end mutator3:register_as_mutator({ - compatible_with_all = true, incompatible_with = { - "mutator555" + "mutator4" } }) -mutator3:create_options({}, true, "mutator3", "mutator3 description") mutator3.on_enabled = function() end mutator3.on_disabled = function() end mutator2:register_as_mutator({ + compatible_with_all = true, difficulties = { "hardest" } }) -mutator2:create_options({}, true, "mutator2", "mutator2 description") mutator2.on_enabled = function() end -mutator2.on_disabled = function() end \ No newline at end of file +mutator2.on_disabled = function() end + +--[[for i=4,17 do + local mutator = new_mod("mutator" .. i) + mutator:register_as_mutator({}) + mutator.on_enabled = function() end + mutator.on_disabled = function() end +end--]] \ No newline at end of file