Files
gen1recomp/tools/save-editor/panels/Items.lua
T
bryanthaboi f5e02b8dbe CLOSES #2619
2026-10-02 07:07:05 -04:00

302 lines
9.9 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local Ops = require("Ops")
local Gen = require("Gen")
local Bag = require("src.inventory.Bag")
local M = {}
local Touch = require("TouchEditor")
local Motion = require("Motion")
local Chooser = require("Chooser")
local function drawView(S, Kit, x, y, w, h)
local s, pad, gap, row = Kit.scale, 12 * Kit.scale, 8 * Kit.scale, Kit.controlH()
Kit.card(x, y, w, h)
Ops.pcItems(S)
local cx, cy, inner = x + pad, y + pad, w - 2 * pad
S.itemView = S.itemView or "bag"
local compact = Kit.desktop or h < 430 * s
local views = { { "bag", "Bag" }, { "pc", "PC" }, { "wallet", "Wallet" }, { "badges", "Badges" } }
if compact then
local addW = Kit.desktop and Kit.buttonWidth("Add", { font = "small" }, row)
or math.max(row, Kit.textWidth("small", "Add") + 20 * s)
local toolsW = Kit.desktop and Kit.buttonWidth("Tools", { font = "small", trailingIcon = "chevron-down" }, row)
or math.max(row, Kit.textWidth("small", "Tools") + 20 * s)
local viewW = inner - addW - toolsW - 2 * gap
if Kit.desktop then viewW = math.min(viewW, 240 * s) end
local toolsX = Kit.desktop and cx + viewW + addW + 2 * gap or cx + inner - toolsW
Chooser.navigation(S, Kit, "itemView", "Inventory view", views, cx, cy, viewW, row, function()
S.itemMenu = nil
end)
local storage = S.itemView == "bag" or S.itemView == "pc"
if
Kit.button(cx + viewW + gap, cy, addW, row, "Add", { font = "small", enabled = storage })
then
Ops.openItemPicker(S, Kit, S.itemView)
end
if Kit.desktop and storage then
local dest = S.itemView == "pc" and "pc" or "bag"
Chooser.actions(S, Kit, "itemTools", "Tools", {
{ id = "max", label = "Max all stacks", icon = "chevrons-up", fn = function(state) Ops[dest .. "MaxAll"](state) end },
{ id = "name", label = "Sort by name", icon = "arrow-up-down", fn = function(state) Ops[dest .. "Sort"](state, "name") end },
{ id = "index", label = "Sort by item number", icon = "list-filter", fn = function(state) Ops[dest .. "Sort"](state, "index") end },
}, toolsX, cy, toolsW, row)
elseif
Kit.button(
toolsX,
cy,
toolsW,
row,
"Tools",
{ font = "small", enabled = storage }
)
then
if S.itemMenu == "tools" then
S.itemMenu = nil
else
S.itemMenu = "tools"
end
Kit.blur()
end
cy = cy + row + gap
else
Chooser.navigation(
S,
Kit,
"itemView",
"Inventory view",
views,
cx,
cy,
math.min(inner, 360 * s),
row,
function()
S.itemMenu = nil
end
)
cy = cy + row + gap
end
if S.itemView == "wallet" then
local bodyH = math.max(0, y + h - pad - cy)
S.walletScroll =
Kit.scrollPixels(cx, cy, inner, bodyH, S.walletScroll or 0, S._walletHeight or 0)
Kit.pushClip(cx, cy, inner, bodyH)
local start = cy - S.walletScroll
cy = start
for _, f in ipairs({
{ "money", "Money", Gen.money(S.save), 999999 },
{ "coins", "Coins", Gen.coins(S.save), 9999 },
}) do
cy = cy
+ Touch.value(
S,
Kit,
"wallet-" .. f[1],
f[2],
f[3],
{ lo = 0, hi = f[4], help = "Max fills it. Type a value for an exact amount." },
cx,
cy,
inner,
function(v)
return Ops.setTrainerProperty(S, f[1], v)
end
)
+ gap
end
S._walletHeight = cy - start
Kit.popClip()
return
elseif S.itemView == "badges" then
local ids = Ops.badgeIds(S)
local bc = inner >= 480 * s and 4 or 2
local bw = (inner - (bc - 1) * gap) / bc
local bodyH = math.max(0, y + h - pad - cy)
S.badgeScroll =
Kit.scrollPixels(cx, cy, inner, bodyH, S.badgeScroll or 0, math.ceil(#ids / bc) * (row + gap))
Kit.pushClip(cx, cy, inner, bodyH)
for i, id in ipairs(ids) do
if
Kit.chip(
cx + (i - 1) % bc * (bw + gap),
cy + math.floor((i - 1) / bc) * (row + gap) - S.badgeScroll,
bw,
row,
id:gsub("BADGE$", ""),
Gen.hasBadge(S.save, id)
)
then
Ops.toggleBadge(S, id)
end
end
Kit.popClip()
return
end
local pc = S.itemView == "pc"
local prefix = pc and "pc" or "bag"
local function call(verb, id, value)
return Ops[prefix .. verb](S, id, value)
end
if not compact then
local half = (inner - gap) / 2
if Kit.button(cx, cy, half, row, "Add item", { kind = "good", font = "small" }) then
Ops.openItemPicker(S, Kit, pc and "pc" or "bag")
end
if
Kit.button(cx + half + gap, cy, half, row, "Max all", { kind = "accent", font = "small" })
then
call("MaxAll")
end
cy = cy + row + gap
if Kit.button(cx, cy, half, row, "Sort A-Z", { font = "small" }) then
call("Sort", "name")
end
if Kit.button(cx + half + gap, cy, half, row, "Sort #", { font = "small" }) then
call("Sort", "index")
end
cy = cy + row + gap
elseif S.itemMenu == "tools" and not Kit.desktop then
local tools = {
{
"Max all",
function()
call("MaxAll")
end,
},
{
"Sort A-Z",
function()
call("Sort", "name")
end,
},
{
"Sort #",
function()
call("Sort", "index")
end,
},
}
local bw = (inner - 2 * gap) / 3
for i, a in ipairs(tools) do
if Kit.button(cx + (i - 1) * (bw + gap), cy, bw, row, a[1], { font = "small" }) then
a[2]()
S.itemMenu = nil
end
end
return
end
local order = pc and Ops.pcOrder(S) or Bag.order(S.save, S.data)
local quantities = pc and S.save.pcItems or S.save.inventory
local pagerY = y + h - pad - row
local bodyH = math.max(0, pagerY - gap - cy)
-- Reserve the complete confirmation label before arming Drop, so its
-- button never shrinks or changes the surrounding layout on a second tap.
local actionMin = Kit.buttonWidth("Confirm?", { font = "small", iconStack = true }, row)
local actionCols = inner >= 5 * actionMin + 4 * gap and 5 or 3
local actionRows = math.ceil(5 / actionCols)
local desktopWidths, desktopActionsW = {}, 4 * gap
if Kit.desktop then
for j, label in ipairs({ "Decrease", "Increase", "Max", pc and "Bag" or "PC", "Confirm?" }) do
desktopWidths[j] = Kit.buttonWidth(label, {
font = "small", iconOnly = j <= 2,
icon = ({ "minus", "plus", "chevrons-up", pc and "backpack" or "package", "trash" })[j],
}, row)
desktopActionsW = desktopActionsW + desktopWidths[j]
end
end
local itemH = Kit.desktop and row + gap or actionRows * row + (actionRows - 1) * gap + row + 3 * gap
local visible = math.max(1, math.floor(bodyH / itemH))
local offsetKey = prefix .. "Offset"
local drawn, shift = Kit.list(S, offsetKey, cx, cy, inner, bodyH, #order, itemH)
Kit.pushClip(cx, cy, inner, bodyH)
for i = 1, drawn do
local id = order[S[offsetKey] + i]
if id == nil then
break
end
local by = cy + (i - 1) * itemH - shift
local def = S.data.items[id]
local count = quantities[id] or 0
local max = Ops.itemMax(S, id, pc)
local issue = not require("Legality").integer(count, 1, max)
and ("Saved stack must be a whole number from 1 to " .. max) or nil
local opts = { font = "small", align = "left", trailingIcon = "pencil", face = "invert", invalid = issue ~= nil }
if
Kit.button(
cx,
by,
Kit.desktop and inner - desktopActionsW - gap or inner,
row,
tostring(def and def.name or id):gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
.. " ×"
.. count,
opts
)
then
Touch.open(S, Kit, {
mode = "number",
id = "item-" .. tostring(id),
title = def and def.name or tostring(id),
value = count,
savedValue = count,
issue = issue,
limits = {
lo = 1,
hi = max,
help = "Set the stack size. Max fills it; Drop removes it.",
},
apply = function(v)
return call("Adjust", id, v - count)
end,
})
end
if not Kit.desktop then by = by + row + gap end
local actionX = cx + inner - desktopActionsW
local labels = {
"Decrease",
"Increase",
"Max",
pc and "Bag" or "PC",
Ops.armLabel(S, prefix .. "-drop-" .. tostring(id), "Drop"),
}
for j, label in ipairs(labels) do
local actionRow = math.floor((j - 1) / actionCols)
local first = actionRow * actionCols + 1
local cols = math.min(actionCols, #labels - first + 1)
local bw = (inner - (cols - 1) * gap) / cols
if Kit.desktop then bw = desktopWidths[j] end
if
Kit.button(Kit.desktop and actionX or cx + (j - first) * (bw + gap), by + (Kit.desktop and 0 or actionRow * (row + gap)), bw, row, label, {
font = "small",
icon = ({ "minus", "plus", "chevrons-up", pc and "backpack" or "package", "trash" })[j],
iconOnly = j == 1 or j == 2,
iconStack = not Kit.desktop and j >= 3,
kind = j == 5 and "danger" or "ghost",
enabled = j ~= 4 or Ops.moveCount(S, not pc, id) > 0,
})
then
if j == 1 then
call("Adjust", id, -1)
elseif j == 2 then
call("Adjust", id, 1)
elseif j == 3 then
call("Max", id)
elseif j == 4 then
call(pc and "ToBag" or "ToPc", id)
elseif
Ops.arm(
S,
prefix .. "-drop-" .. tostring(id),
"Drop this entire stack? Tap again to confirm"
)
then
call("Drop", id)
end
end
actionX = actionX + bw + gap
end
end
Kit.popClip()
S[offsetKey] = Kit.pager(cx, pagerY, inner, S[offsetKey], #order, visible)
end
function M.draw(S, Kit, x, y, w, h)
Motion.pages(S, Kit, "itemView", x, y, w, h, drawView)
end
return M