mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
222 lines
6.6 KiB
Lua
222 lines
6.6 KiB
Lua
-- Events panel: flags, defeated trainers, taken items, and per-map object
|
|
-- visibility toggles. All four sections read/write directly into S.save so
|
|
-- edits show up immediately on the next Save.
|
|
--
|
|
-- Layout is a fixed grid (sub-tabs -> info row -> paged checkbox list ->
|
|
-- pagination/actions) so it stays predictable for both mouse hit-testing
|
|
-- and headless tests.
|
|
|
|
local M = {}
|
|
|
|
local ROW_H = 22
|
|
local VISIBLE_ROWS = 10
|
|
|
|
local SUB_TABS = {
|
|
{ id = "flags", label = "Flags" },
|
|
{ id = "trainers", label = "Trainers" },
|
|
{ id = "items", label = "Items taken" },
|
|
{ id = "toggles", label = "Object toggles" },
|
|
}
|
|
|
|
local function mark(S)
|
|
S.dirty = true
|
|
end
|
|
|
|
local function sortedKeys(t)
|
|
local keys = {}
|
|
for k in pairs(t) do table.insert(keys, k) end
|
|
table.sort(keys)
|
|
return keys
|
|
end
|
|
|
|
local function contains(haystack, needle)
|
|
if needle == "" then return true end
|
|
return haystack:lower():find(needle:lower(), 1, true) ~= nil
|
|
end
|
|
|
|
-- Simple free-text capture for the flags filter field. Kit has no text
|
|
-- widget, so we edge-detect a-z/0-9/backspace against love.keyboard each
|
|
-- frame this panel is drawn (only while the Flags sub-tab is active).
|
|
local FILTER_KEYS = {}
|
|
for c = string.byte("a"), string.byte("z") do
|
|
local ch = string.char(c)
|
|
FILTER_KEYS[ch] = ch
|
|
end
|
|
for c = string.byte("0"), string.byte("9") do
|
|
local ch = string.char(c)
|
|
FILTER_KEYS[ch] = ch
|
|
end
|
|
FILTER_KEYS["-"] = "_"
|
|
|
|
local prevDown = {}
|
|
|
|
local function pollFilterInput(S)
|
|
S.eventFilter = S.eventFilter or ""
|
|
for key, ch in pairs(FILTER_KEYS) do
|
|
local down = love.keyboard.isDown(key)
|
|
if down and not prevDown[key] then
|
|
S.eventFilter = S.eventFilter .. ch
|
|
end
|
|
prevDown[key] = down
|
|
end
|
|
local backspaceDown = love.keyboard.isDown("backspace")
|
|
if backspaceDown and not prevDown.backspace then
|
|
S.eventFilter = S.eventFilter:sub(1, -2)
|
|
end
|
|
prevDown.backspace = backspaceDown
|
|
end
|
|
|
|
local function clampScroll(S, total)
|
|
S.eventsScroll = S.eventsScroll or 0
|
|
local maxScroll = math.max(0, total - VISIBLE_ROWS)
|
|
if S.eventsScroll > maxScroll then S.eventsScroll = maxScroll end
|
|
if S.eventsScroll < 0 then S.eventsScroll = 0 end
|
|
return S.eventsScroll
|
|
end
|
|
|
|
-- Draws up to VISIBLE_ROWS checkbox rows starting at rows[scroll+1], calling
|
|
-- onToggle(row, newChecked) when a row's box is clicked. `checkedOf(row)`
|
|
-- and `labelOf(row)` extract display state from whatever row shape the
|
|
-- caller uses (plain strings for Flags/Trainers/Items, tables for Toggles).
|
|
local function drawRows(S, Kit, x, listY, rows, scroll, checkedOf, labelOf, onToggle)
|
|
for i = 1, math.min(VISIBLE_ROWS, #rows - scroll) do
|
|
local row = rows[scroll + i]
|
|
local ry = listY + (i - 1) * ROW_H
|
|
local checked = checkedOf(row)
|
|
if checked == nil then
|
|
Kit.label(x + 28, ry + 4, labelOf(row))
|
|
else
|
|
local newChecked, changed = Kit.checkbox(x, ry, checked, labelOf(row))
|
|
if changed then
|
|
onToggle(row, newChecked)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function drawPager(S, Kit, x, y, total, scroll)
|
|
local maxScroll = math.max(0, total - VISIBLE_ROWS)
|
|
if Kit.button(x, y, 90, 26, "Prev") then
|
|
S.eventsScroll = math.max(0, scroll - VISIBLE_ROWS)
|
|
end
|
|
if Kit.button(x + 100, y, 90, 26, "Next") then
|
|
S.eventsScroll = math.min(maxScroll, scroll + VISIBLE_ROWS)
|
|
end
|
|
local shown = math.min(VISIBLE_ROWS, math.max(0, total - scroll))
|
|
Kit.label(x + 210, y + 5, string.format("%d-%d of %d",
|
|
total > 0 and scroll + 1 or 0, scroll + shown, total))
|
|
end
|
|
|
|
local function drawFlagsTab(S, Kit, x, y)
|
|
pollFilterInput(S)
|
|
|
|
Kit.label(x, y + 4, "Filter: " .. S.eventFilter .. "_")
|
|
if Kit.button(x + 320, y, 110, 26, "Clear filter") then
|
|
S.eventFilter = ""
|
|
end
|
|
|
|
local filtered = {}
|
|
for _, name in ipairs(S.events or {}) do
|
|
if contains(name, S.eventFilter) then
|
|
table.insert(filtered, name)
|
|
end
|
|
end
|
|
|
|
local listY = y + 32
|
|
local scroll = clampScroll(S, #filtered)
|
|
drawRows(S, Kit, x, listY, filtered, scroll,
|
|
function(name) return S.save.flags[name] == true end,
|
|
function(name) return name end,
|
|
function(name, newChecked)
|
|
S.save.flags[name] = newChecked and true or nil
|
|
mark(S)
|
|
end)
|
|
|
|
drawPager(S, Kit, x, listY + VISIBLE_ROWS * ROW_H + 8, #filtered, scroll)
|
|
end
|
|
|
|
local function drawKeyToggleTab(S, Kit, x, y, note, tableKey, clearLabel)
|
|
Kit.label(x, y + 4, note)
|
|
|
|
S.save[tableKey] = S.save[tableKey] or {}
|
|
local t = S.save[tableKey]
|
|
local keys = sortedKeys(t)
|
|
|
|
local listY = y + 32
|
|
local scroll = clampScroll(S, #keys)
|
|
drawRows(S, Kit, x, listY, keys, scroll,
|
|
function(k) return t[k] == true end,
|
|
function(k) return k end,
|
|
function(k, newChecked)
|
|
t[k] = newChecked
|
|
mark(S)
|
|
end)
|
|
|
|
local pagerY = listY + VISIBLE_ROWS * ROW_H + 8
|
|
drawPager(S, Kit, x, pagerY, #keys, scroll)
|
|
if Kit.button(x + 400, pagerY, 190, 26, clearLabel) then
|
|
S.save[tableKey] = {}
|
|
mark(S)
|
|
end
|
|
end
|
|
|
|
local function drawTogglesTab(S, Kit, x, y)
|
|
Kit.label(x, y + 4, "Per-map object visibility overrides")
|
|
|
|
S.save.objectToggles = S.save.objectToggles or {}
|
|
local toggles = S.save.objectToggles
|
|
|
|
local rows = {}
|
|
for _, mapId in ipairs(sortedKeys(toggles)) do
|
|
table.insert(rows, { header = true, mapId = mapId })
|
|
for _, objName in ipairs(sortedKeys(toggles[mapId])) do
|
|
table.insert(rows, { header = false, mapId = mapId, name = objName })
|
|
end
|
|
end
|
|
|
|
local listY = y + 32
|
|
local scroll = clampScroll(S, #rows)
|
|
drawRows(S, Kit, x, listY, rows, scroll,
|
|
function(row)
|
|
if row.header then return nil end
|
|
return toggles[row.mapId][row.name] == true
|
|
end,
|
|
function(row) return row.header and ("[" .. row.mapId .. "]") or row.name end,
|
|
function(row, newChecked)
|
|
toggles[row.mapId][row.name] = newChecked
|
|
mark(S)
|
|
end)
|
|
|
|
drawPager(S, Kit, x, listY + VISIBLE_ROWS * ROW_H + 8, #rows, scroll)
|
|
end
|
|
|
|
function M.draw(S, Kit, x, y)
|
|
S.eventFilter = S.eventFilter or ""
|
|
S.eventsTab = S.eventsTab or "flags"
|
|
|
|
Kit.label(x, y, "Events")
|
|
|
|
local newTab = Kit.tabs(x, y + 24, SUB_TABS, S.eventsTab)
|
|
if newTab then
|
|
S.eventsTab = newTab
|
|
S.eventsScroll = 0
|
|
end
|
|
|
|
local contentY = y + 64
|
|
if S.eventsTab == "flags" then
|
|
drawFlagsTab(S, Kit, x, contentY)
|
|
elseif S.eventsTab == "trainers" then
|
|
drawKeyToggleTab(S, Kit, x, contentY,
|
|
"Keys look like MAP_obj_N (defeatedTrainers)",
|
|
"defeatedTrainers", "Clear all trainers")
|
|
elseif S.eventsTab == "items" then
|
|
drawKeyToggleTab(S, Kit, x, contentY,
|
|
"Keys look like MAP_obj_N (itemsTaken)",
|
|
"itemsTaken", "Clear all items taken")
|
|
elseif S.eventsTab == "toggles" then
|
|
drawTogglesTab(S, Kit, x, contentY)
|
|
end
|
|
end
|
|
|
|
return M
|