mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 07:41:21 +02:00
186 lines
6.6 KiB
Lua
186 lines
6.6 KiB
Lua
-- Mart shop (engine/events/pokemart.asm DisplayPokemartDialogue_):
|
|
-- the BUY/SELL/QUIT menu loops until QUIT -- BUY and SELL keep it on
|
|
-- the stack underneath their list, and QUIT hands control back to the
|
|
-- caller (open_mart resumes its yielded script runner there). Both
|
|
-- lists run in dialogue mode: the clerk speaks the real _Pokemart*
|
|
-- strings in the bottom text box with the money box top-right, then
|
|
-- the 1-99 quantity selector (DisplayChooseQuantityMenu) and a YES/NO
|
|
-- price confirm. Key items and HMs can't be sold (.unsellableItem).
|
|
|
|
local Bag = require("src.inventory.Bag")
|
|
local ChoiceBox = require("src.ui.ChoiceBox")
|
|
local ListMenu = require("src.ui.ListMenu")
|
|
local Menu = require("src.ui.Menu")
|
|
local QuantityBox = require("src.ui.QuantityBox")
|
|
local Strings = require("src.core.Strings")
|
|
|
|
local ShopMenu = {}
|
|
|
|
local function txt(game, key, fallback)
|
|
return game.data.text[key] or fallback
|
|
end
|
|
|
|
local function buy(game, stock)
|
|
local items = {}
|
|
for _, id in ipairs(stock) do
|
|
local def = game.data.items[id]
|
|
if def then
|
|
table.insert(items, {
|
|
value = id,
|
|
label = def.name,
|
|
right = ("¥%d"):format(def.price),
|
|
})
|
|
end
|
|
end
|
|
local greet = txt(game, "_PokemartBuyingGreetingText", "Take your time.")
|
|
local notEnough = txt(game, "_PokemartNotEnoughMoneyText",
|
|
Strings("You don't have\nenough money."))
|
|
local list
|
|
list = ListMenu.new(game, "BUY", items, {
|
|
dialogue = true,
|
|
money = function() return game.save.money end,
|
|
footer = greet,
|
|
onChoose = function(item)
|
|
local def = game.data.items[item.value]
|
|
if game.save.money < def.price then
|
|
list.footer = notEnough
|
|
return
|
|
end
|
|
local affordable = math.min(99, math.floor(game.save.money / math.max(1, def.price)))
|
|
game.stack:push(QuantityBox.new(game, {
|
|
max = affordable,
|
|
unitPrice = def.price,
|
|
onDone = function(qty)
|
|
if not qty then
|
|
list.footer = greet
|
|
return
|
|
end
|
|
local cost = qty * def.price
|
|
-- _PokemartTellBuyPriceText + yes/no confirm
|
|
list.footer = Strings("%s?\nThat will be\n¥%d. OK?", def.name, cost)
|
|
game.stack:push(ChoiceBox.new(game, function(yes)
|
|
if not yes then
|
|
list.footer = greet
|
|
return
|
|
end
|
|
if game.save.money < cost then
|
|
list.footer = notEnough
|
|
return
|
|
end
|
|
if not Bag.add(game.save, item.value, qty, game.data) then
|
|
list.footer = txt(game, "_PokemartItemBagFullText",
|
|
Strings("You can't carry\nany more items."))
|
|
return
|
|
end
|
|
require("src.core.Sound").play(game.data, "Purchase")
|
|
game.save.money = game.save.money - cost
|
|
list.footer = txt(game, "_PokemartBoughtItemText",
|
|
Strings("Here you are!\nThank you!"))
|
|
end))
|
|
end,
|
|
}))
|
|
end,
|
|
})
|
|
game.stack:push(list)
|
|
end
|
|
|
|
local function sell(game)
|
|
-- Sell list is ITEMLISTMENU with wPrintItemPrices cleared
|
|
-- (pokemart.asm .sellMenuLoop): name + quantity only. Price shows
|
|
-- in the quantity chooser. Stuffing "xN" into the label next to a
|
|
-- right-aligned ¥ price made long names overlap (issue #116).
|
|
local items = {}
|
|
for _, id in ipairs(Bag.order(game.save)) do
|
|
local def = game.data.items[id]
|
|
table.insert(items, {
|
|
value = id,
|
|
label = def and def.name or id,
|
|
right = "x" .. game.save.inventory[id],
|
|
})
|
|
end
|
|
local greet = txt(game, "_PokemartBuyingGreetingText", "Take your time.")
|
|
local list
|
|
list = ListMenu.new(game, "SELL", items, {
|
|
dialogue = true,
|
|
money = function() return game.save.money end,
|
|
footer = greet,
|
|
onSelectKey = function(item, l)
|
|
if not item then return end
|
|
if not l.swapIndex then
|
|
l.swapIndex = l.index
|
|
return
|
|
end
|
|
local order = Bag.order(game.save)
|
|
order[l.swapIndex], order[l.index] = order[l.index], order[l.swapIndex]
|
|
l.swapIndex = nil
|
|
require("src.core.Sound").play(game.data, "Swap")
|
|
local rebuilt = {}
|
|
for _, id in ipairs(order) do
|
|
local def = game.data.items[id]
|
|
rebuilt[#rebuilt + 1] = {
|
|
value = id,
|
|
label = def and def.name or id,
|
|
right = "x" .. game.save.inventory[id],
|
|
}
|
|
end
|
|
l.items = rebuilt
|
|
end,
|
|
onChoose = function(item)
|
|
local def = game.data.items[item.value]
|
|
-- only key items and HMs are unsellable (pokemart.asm IsKeyItem /
|
|
-- IsItemHM); zero-price items like ETHER sell for ¥0. An unknown id
|
|
-- (nil def) has no price, so treat it as unsellable too rather than
|
|
-- indexing nil below -- guards saves that already picked up a bogus
|
|
-- ITEM_NONE "0" from Blue's House before that pickup was fixed (#11).
|
|
if not def or def.keyItem or item.value:find("^HM_") then
|
|
list.footer = txt(game, "_PokemartUnsellableItemText",
|
|
Strings("I can't put a\nprice on that."))
|
|
return
|
|
end
|
|
local unit = math.floor(def.price / 2)
|
|
game.stack:push(QuantityBox.new(game, {
|
|
max = game.save.inventory[item.value] or 1,
|
|
unitPrice = unit,
|
|
onDone = function(qty)
|
|
if not qty then
|
|
list.footer = greet
|
|
return
|
|
end
|
|
-- _PokemartTellSellPriceText + yes/no confirm
|
|
list.footer = Strings("I can pay you\n¥%d for that.", unit * qty)
|
|
game.stack:push(ChoiceBox.new(game, function(yes)
|
|
if not yes then
|
|
list.footer = greet
|
|
return
|
|
end
|
|
game.save.money = game.save.money + unit * qty
|
|
Bag.remove(game.save, item.value, qty)
|
|
local left = game.save.inventory[item.value]
|
|
if left then
|
|
item.right = "x" .. left
|
|
else
|
|
list:removeCurrent()
|
|
end
|
|
list.footer = txt(game, "_PokemartThankYouText", "Thank you!")
|
|
end))
|
|
end,
|
|
}))
|
|
end,
|
|
})
|
|
game.stack:push(list)
|
|
end
|
|
|
|
function ShopMenu.new(game, stock, onQuit)
|
|
-- keepOpen: the mart menu stays underneath its list so closing the
|
|
-- list lands back here; only QUIT (or B) leaves and fires onQuit
|
|
local menu = Menu.new(game, {
|
|
{ label = Strings("BUY"), keepOpen = true, onSelect = function() buy(game, stock) end },
|
|
{ label = Strings("SELL"), keepOpen = true, onSelect = function() sell(game) end },
|
|
{ label = Strings("QUIT"), onSelect = onQuit },
|
|
}, { tx = 0, ty = 0, tw = 8, th = 8 })
|
|
menu.onCancel = onQuit
|
|
return menu
|
|
end
|
|
|
|
return ShopMenu
|