197 lines
7.8 KiB
Lua
197 lines
7.8 KiB
Lua
local matrix_engine = require("backend.calculation.matrix_engine")
|
|
|
|
-- ** LOCAL UTIL **
|
|
local function show_linearly_dependent_recipes(modal_data, recipe_protos)
|
|
local flow_recipes = modal_data.modal_elements.content_frame.add{type="flow", direction="vertical"}
|
|
local label_title = flow_recipes.add{type="label", caption={"fp.matrix_linearly_dependent_recipes"}}
|
|
label_title.style.font = "heading-2"
|
|
|
|
local frame_recipes = flow_recipes.add{type="frame", direction="horizontal", style="slot_button_deep_frame"}
|
|
local table_recipes = frame_recipes.add{type="table", column_count=8, style="filter_slot_table"}
|
|
for _, recipe_proto in ipairs(recipe_protos) do
|
|
table_recipes.add{type="sprite", sprite=recipe_proto.sprite, tooltip=recipe_proto.localised_name}
|
|
end
|
|
end
|
|
|
|
local function update_dialog_submit_button(modal_data, matrix_metadata)
|
|
local num_needed_free_items = matrix_metadata.num_rows - matrix_metadata.num_cols + #matrix_metadata.free_items
|
|
local curr_free_items = #modal_data["free_items"]
|
|
|
|
local message = nil
|
|
if num_needed_free_items > curr_free_items then
|
|
message = {"fp.matrix_constrained_items", num_needed_free_items, {"fp.pl_item", num_needed_free_items}}
|
|
end
|
|
modal_dialog.set_submit_button_state(modal_data.modal_elements, (message == nil), message)
|
|
end
|
|
|
|
local function refresh_item_category(modal_data, type)
|
|
local table_items = modal_data.modal_elements[type .. "_table"]
|
|
table_items.clear()
|
|
|
|
-- order items by the natural Factorio order
|
|
local display_order = {}
|
|
for index, proto in ipairs(modal_data[type .. "_items"]) do
|
|
display_order[index] = {
|
|
key = { proto.group.order, proto.subgroup.order, proto.order, proto.name, index },
|
|
index = index, proto = proto }
|
|
end
|
|
table.sort(display_order, function (item_1, item_2)
|
|
local key_1 = item_1.key
|
|
local key_2 = item_2.key
|
|
assert(#key_1 == #key_2)
|
|
|
|
for i = 1, #key_1 do
|
|
if key_1[i] ~= key_2[i] then
|
|
return key_1[i] < key_2[i]
|
|
end
|
|
end
|
|
|
|
return false -- identical items
|
|
end)
|
|
|
|
for _, item in pairs(display_order) do
|
|
local index = item.index
|
|
local proto = item.proto
|
|
local button = table_items.add{type="sprite-button", sprite=proto.sprite, tooltip=proto.localised_name,
|
|
tags={mod="fp", on_gui_click="swap_item_category", type=type, index=index}, style="flib_slot_button_default",
|
|
mouse_button_filter={"left"}}
|
|
button.style.size = 48
|
|
end
|
|
end
|
|
|
|
local function create_item_category(modal_data, type, label_arg)
|
|
local flow_category = modal_data.modal_elements.content_frame.add{type="flow", direction="vertical"}
|
|
|
|
local title_string = (type == "free") and {"fp.matrix_free_items"}
|
|
or {"fp.matrix_constrained_items", label_arg, {"fp.pl_item", label_arg}}
|
|
local label_title = flow_category.add{type="label", caption=title_string}
|
|
label_title.style.single_line = false
|
|
|
|
local frame_items = flow_category.add{type="frame", direction="horizontal", style="slot_button_deep_frame"}
|
|
local table_items = frame_items.add{type="table", column_count=8, style="filter_slot_table"}
|
|
modal_data.modal_elements[type .. "_table"] = table_items
|
|
|
|
refresh_item_category(modal_data, type)
|
|
end
|
|
|
|
local function swap_item_category(player, tags, _)
|
|
local ui_state = util.globals.ui_state(player)
|
|
local subfactory = ui_state.context.subfactory
|
|
local modal_data = ui_state.modal_data
|
|
|
|
-- update the free items here, set the constrained items based on linear dependence data
|
|
if tags.type == "free" then
|
|
-- note this assumes the gui's list has the same order as the subfactory
|
|
table.remove(subfactory.matrix_free_items, tags.index)
|
|
else -- "constrained"
|
|
local item_proto = modal_data["constrained_items"][tags.index]
|
|
table.insert(subfactory.matrix_free_items, item_proto)
|
|
end
|
|
|
|
local matrix_metadata = matrix_engine.get_matrix_solver_metadata(modal_data.subfactory_data)
|
|
local linear_dependence_data = matrix_engine.get_linear_dependence_data(modal_data.subfactory_data, matrix_metadata)
|
|
modal_data.constrained_items = linear_dependence_data.allowed_free_items
|
|
modal_data.free_items = matrix_metadata.free_items
|
|
|
|
refresh_item_category(modal_data, "constrained")
|
|
refresh_item_category(modal_data, "free")
|
|
update_dialog_submit_button(modal_data, matrix_metadata)
|
|
end
|
|
|
|
|
|
local function matrix_early_abort_check(player, modal_data)
|
|
local ui_state = util.globals.ui_state(player)
|
|
local subfactory = ui_state.context.subfactory
|
|
|
|
if subfactory.selected_floor.Line.count == 0 then return true end
|
|
|
|
local subfactory_data = solver.generate_subfactory_data(player, subfactory)
|
|
local matrix_metadata = matrix_engine.get_matrix_solver_metadata(subfactory_data)
|
|
|
|
modal_data.subfactory_data = subfactory_data
|
|
|
|
local linear_dependence_data = matrix_engine.get_linear_dependence_data(subfactory_data, matrix_metadata)
|
|
|
|
if next(linear_dependence_data.linearly_dependent_recipes) then -- too many ways to create the products
|
|
modal_data.linearly_dependent_recipes = linear_dependence_data.linearly_dependent_recipes
|
|
subfactory.linearly_dependant = true
|
|
return false
|
|
end
|
|
subfactory.linearly_dependant = false -- TODO not the proper way to signal this, but it works
|
|
|
|
modal_data.constrained_items = linear_dependence_data.allowed_free_items
|
|
modal_data.free_items = matrix_metadata.free_items
|
|
|
|
local num_needed_free_items = matrix_metadata.num_rows - matrix_metadata.num_cols + #matrix_metadata.free_items
|
|
if num_needed_free_items == 0 then -- User doesn't need to select any free items, just run the matrix solver
|
|
if modal_data.configuration then
|
|
util.messages.raise(player, "warning", {"fp.warning_no_matrix_configuration_needed"}, 1)
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- If it gets to here, the dialog should open normally
|
|
modal_data.num_needed_free_items = num_needed_free_items
|
|
modal_data.matrix_metadata = matrix_metadata
|
|
return false
|
|
end
|
|
|
|
local function open_matrix_dialog(player, modal_data)
|
|
if util.globals.context(player).subfactory.linearly_dependant then
|
|
show_linearly_dependent_recipes(modal_data, modal_data.linearly_dependent_recipes)
|
|
modal_dialog.set_submit_button_state(modal_data.modal_elements, false, {"fp.matrix_linearly_dependent_recipes"})
|
|
|
|
-- Dispose of the temporary GUI-opening variables
|
|
modal_data.linearly_dependent_recipes = nil
|
|
else
|
|
create_item_category(modal_data, "constrained", modal_data.num_needed_free_items)
|
|
create_item_category(modal_data, "free")
|
|
update_dialog_submit_button(modal_data, modal_data.matrix_metadata)
|
|
|
|
-- Dispose of the temporary GUI-opening variables
|
|
modal_data.num_needed_free_items = nil
|
|
modal_data.matrix_metadata = nil
|
|
end
|
|
end
|
|
|
|
local function close_matrix_dialog(player, action)
|
|
if action == "submit" then
|
|
local ui_state = util.globals.ui_state(player)
|
|
local subfactory = ui_state.context.subfactory
|
|
subfactory.matrix_free_items = ui_state.modal_data.free_items
|
|
|
|
solver.update(player, subfactory)
|
|
util.raise.refresh(player, "subfactory", nil)
|
|
|
|
elseif action == "cancel" then
|
|
util.raise.refresh(player, "production_detail", nil)
|
|
end
|
|
end
|
|
|
|
|
|
-- ** EVENTS **
|
|
local listeners = {}
|
|
|
|
listeners.gui = {
|
|
on_gui_click = {
|
|
{
|
|
name = "swap_item_category",
|
|
handler = swap_item_category
|
|
}
|
|
}
|
|
}
|
|
|
|
listeners.dialog = {
|
|
dialog = "matrix",
|
|
metadata = (function(_) return {
|
|
caption = {"fp.matrix_solver"},
|
|
create_content_frame = true,
|
|
show_submit_button = true
|
|
} end),
|
|
early_abort_check = matrix_early_abort_check,
|
|
open = open_matrix_dialog,
|
|
close = close_matrix_dialog
|
|
}
|
|
|
|
return { listeners }
|