mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-03 16:16:38 -04:00
2699 lines
92 KiB
Lua
2699 lines
92 KiB
Lua
-- Party menu — pret PARTY_LAYOUT_SINGLE (windows + FONT_SMALL + OAM sprites).
|
|
|
|
local Stack = require("src.ui.game3.stack")
|
|
local Chrome = require("src.ui.game3.chrome")
|
|
local Window = require("src.ui.game3.window")
|
|
local FrlgFont = require("src.ui.game3.frlg_font")
|
|
local PartyChrome = require("src.ui.game3.party_chrome")
|
|
local Pokemon = require("src.core.game3.pokemon")
|
|
local Display = require("src.core.game3.display")
|
|
local Oam = require("src.core.game3.oam")
|
|
local SummaryMenu = require("src.ui.game3.summary_menu")
|
|
local ItemUse = require("src.core.game3.item_use")
|
|
local ItemsData = require("src.core.game3.items_data")
|
|
local Bag = require("src.core.game3.bag")
|
|
local Strings = require("src.core.Strings")
|
|
local RomText = require("src.core.game3.rom_text")
|
|
local TextIR = require("src.core.game3.scripting.text_ir")
|
|
|
|
local PartyMenu = {}
|
|
|
|
PartyMenu.open = false
|
|
PartyMenu.cursor = 1
|
|
PartyMenu.mode = "list" -- "list" | "action" | "item_action" | "switch" | "summary" | "use" | "give" | "message"
|
|
PartyMenu.actionCursor = 1
|
|
PartyMenu.itemActionCursor = 1
|
|
PartyMenu.switchFrom = nil
|
|
PartyMenu.summaryPage = 1
|
|
PartyMenu.ACTIONS = { "SUMMARY", "SWITCH", "ITEM", "CANCEL" }
|
|
PartyMenu.ITEM_ACTIONS = { "GIVE", "TAKE", "CANCEL" }
|
|
PartyMenu._oam = nil -- per-slot { mon, ball, status } sprite ids
|
|
PartyMenu._summaryIcon = nil
|
|
PartyMenu._messageText = nil
|
|
PartyMenu._onMessageDismiss = nil
|
|
PartyMenu._item = nil
|
|
PartyMenu._bag = nil
|
|
|
|
-- pokefirered/src/data/party_menu.h:1059
|
|
local CURSOR_OPTION = {
|
|
SUMMARY = 0, SWITCH = 1, CANCEL = 2, ITEM = 3, GIVE = 4, TAKE = 5,
|
|
SHIFT = 10, ["SEND OUT"] = 11, ENTER = 12, ["NO ENTRY"] = 13, STORE = 14,
|
|
}
|
|
local CURSOR_OPTION_FIELD_MOVES = 18
|
|
-- pokefirered/src/data/party_menu.h:1158
|
|
local FIELD_MOVES = {
|
|
"FLASH", "CUT", "FLY", "STRENGTH", "SURF", "ROCK_SMASH", "WATERFALL", "TELEPORT",
|
|
"DIG", "MILK_DRINK", "SOFTBOILED", "SWEET_SCENT",
|
|
}
|
|
local FIELD_MOVE_INDEX = {}
|
|
for j, name in ipairs(FIELD_MOVES) do FIELD_MOVE_INDEX[name:gsub("_", " ")] = j - 1 end
|
|
|
|
-- pokefirered/src/data/party_menu.h:634
|
|
local DESC = { NO_USE = 0, ABLE_3 = 1, FIRST = 2, SECOND = 3, THIRD = 4, ABLE = 5,
|
|
NOT_ABLE = 6, ABLE_2 = 7, NOT_ABLE_2 = 8, LEARNED = 9 }
|
|
|
|
local function cursor_option_text(act)
|
|
local fm = FIELD_MOVE_INDEX[act]
|
|
if fm then return RomText.at("sCursorOptions", CURSOR_OPTION_FIELD_MOVES + fm) end
|
|
return RomText.at("sCursorOptions", (assert(CURSOR_OPTION[act], act)))
|
|
end
|
|
|
|
local function desc_text(id)
|
|
return RomText.at("sDescriptionStringTable", DESC[id])
|
|
end
|
|
|
|
local function se(id)
|
|
pcall(function() require("src.core.game3.audio").playSe(id) end)
|
|
end
|
|
|
|
-- pokefirered/src/item_use.c:614
|
|
local function mapHeaderFlag(mapDef, key)
|
|
if mapDef == nil then return false end
|
|
return (tonumber(mapDef[key]) or 0) ~= 0
|
|
end
|
|
|
|
-- pokefirered/include/constants/items.h:97
|
|
function PartyMenu.itemIsEvolutionStone(item)
|
|
if item == nil or ItemsData.isTm(item) then return false end
|
|
return ItemsData.fieldUseKind(item) == "evo"
|
|
end
|
|
local is_evolution_stone = PartyMenu.itemIsEvolutionStone
|
|
|
|
local function nav_up(cur, n)
|
|
if cur == 1 then
|
|
return 7
|
|
elseif cur == 7 then
|
|
return n
|
|
else
|
|
return cur - 1
|
|
end
|
|
end
|
|
|
|
local function nav_down(cur, n)
|
|
if cur == 7 then
|
|
return 1
|
|
elseif cur == n then
|
|
return 7
|
|
else
|
|
return cur + 1
|
|
end
|
|
end
|
|
|
|
local function nav_left(cur, n, lastSlot)
|
|
if cur ~= 1 and cur ~= 7 then
|
|
return 1, cur
|
|
end
|
|
return cur, lastSlot
|
|
end
|
|
|
|
local function nav_right(cur, n, lastSlot)
|
|
if cur == 1 and n > 1 then
|
|
local target = lastSlot or 2
|
|
if target < 2 then target = 2 end
|
|
if target > n then target = n end
|
|
return target, lastSlot
|
|
end
|
|
return cur, lastSlot
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:86
|
|
local SLOT_CONFIRM = 7
|
|
local SLOT_CANCEL_MULTI = 8
|
|
|
|
-- pokefirered/src/party_menu.c:1359 UpdatePartySelectionSingleLayout
|
|
local function multi_nav_up(cur, n)
|
|
if cur == 1 then
|
|
return SLOT_CANCEL_MULTI
|
|
elseif cur == SLOT_CONFIRM then
|
|
return n
|
|
elseif cur == SLOT_CANCEL_MULTI then
|
|
return SLOT_CONFIRM
|
|
else
|
|
return cur - 1
|
|
end
|
|
end
|
|
|
|
local function multi_nav_down(cur, n)
|
|
if cur == SLOT_CANCEL_MULTI then
|
|
return 1
|
|
elseif cur == n then
|
|
return SLOT_CONFIRM
|
|
else
|
|
return cur + 1
|
|
end
|
|
end
|
|
|
|
local function multi_nav_left(cur, lastSlot)
|
|
if cur ~= 1 and cur ~= SLOT_CONFIRM and cur ~= SLOT_CANCEL_MULTI then
|
|
return 1, cur
|
|
end
|
|
return cur, lastSlot
|
|
end
|
|
|
|
local function get_mon_stats(mon)
|
|
return {
|
|
maxHp = tonumber(mon and (mon.maxHp or mon.maxhp)) or 1,
|
|
atk = tonumber(mon and (mon.attack or mon.atk)) or 1,
|
|
def = tonumber(mon and (mon.defense or mon.def)) or 1,
|
|
spa = tonumber(mon and (mon.spAtk or mon.spa or mon.spatk)) or 1,
|
|
spd = tonumber(mon and (mon.spDef or mon.spd or mon.spdef)) or 1,
|
|
spe = tonumber(mon and (mon.speed or mon.spe)) or 1,
|
|
}
|
|
end
|
|
|
|
function PartyMenu.showStatGrowth(mon, oldStats, newStats, onDone)
|
|
PartyMenu._statGrowthMon = mon
|
|
PartyMenu._statGrowthOld = oldStats
|
|
PartyMenu._statGrowthNew = newStats
|
|
PartyMenu._statGrowthPage = 1
|
|
PartyMenu._statGrowthDone = onDone
|
|
PartyMenu.mode = "stat_growth"
|
|
end
|
|
|
|
-- pret sSinglePartyMenuWindowTemplate
|
|
local SLOT_WIN = {
|
|
{ left = 1, top = 3, w = 10, h = 7, kind = "main" },
|
|
{ left = 12, top = 1, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 4, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 7, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 10, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 13, w = 18, h = 3, kind = "wide" },
|
|
}
|
|
|
|
-- pret sPartyMenuSpriteCoords[PARTY_LAYOUT_SINGLE]
|
|
-- monX, monY, itemX, itemY, statusX, statusY, ballX, ballY (CENTER coords)
|
|
local SLOT_SPRITES = {
|
|
{ 16, 40, 20, 50, 56, 52, 16, 34 },
|
|
{ 104, 18, 108, 28, 144, 27, 102, 25 },
|
|
{ 104, 42, 108, 52, 144, 51, 102, 49 },
|
|
{ 104, 66, 108, 76, 144, 75, 102, 73 },
|
|
{ 104, 90, 108, 100, 144, 99, 102, 97 },
|
|
{ 104, 114, 108, 124, 144, 123, 102, 121 },
|
|
}
|
|
|
|
-- pret sPartyBoxInfoRects — x,y relative to window
|
|
local INFO_LEFT = {
|
|
nick = { 24, 11 }, level = { 32, 20 }, gender = { 64, 20 },
|
|
hp = { 38, 36 }, hpMax = { 53, 36 }, hpBar = { 24, 35 },
|
|
desc = { 12, 34 },
|
|
}
|
|
local INFO_RIGHT = {
|
|
nick = { 22, 3 }, level = { 32, 12 }, gender = { 64, 12 },
|
|
hp = { 102, 12 }, hpMax = { 117, 12 }, hpBar = { 88, 10 },
|
|
desc = { 77, 4 },
|
|
}
|
|
|
|
-- pokefirered/src/data/party_menu.h:192
|
|
local SLOT_WIN_DOUBLE = {
|
|
{ left = 1, top = 1, w = 10, h = 7, kind = "main" },
|
|
{ left = 1, top = 8, w = 10, h = 7, kind = "main" },
|
|
{ left = 12, top = 1, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 5, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 9, w = 18, h = 3, kind = "wide" },
|
|
{ left = 12, top = 13, w = 18, h = 3, kind = "wide" },
|
|
}
|
|
|
|
-- pokefirered/src/data/party_menu.h:81
|
|
local SLOT_SPRITES_DOUBLE = {
|
|
{ 16, 24, 20, 34, 56, 36, 16, 18 },
|
|
{ 16, 80, 20, 90, 56, 92, 16, 74 },
|
|
{ 104, 18, 108, 28, 144, 27, 102, 25 },
|
|
{ 104, 50, 108, 60, 144, 59, 102, 57 },
|
|
{ 104, 82, 108, 92, 144, 91, 102, 89 },
|
|
{ 104, 114, 108, 124, 144, 123, 102, 121 },
|
|
}
|
|
|
|
local function is_double()
|
|
return PartyMenu._layout == "double"
|
|
end
|
|
|
|
local function slot_win(i)
|
|
return (is_double() and SLOT_WIN_DOUBLE or SLOT_WIN)[i]
|
|
end
|
|
|
|
local function slot_sprites(i)
|
|
return (is_double() and SLOT_SPRITES_DOUBLE or SLOT_SPRITES)[i]
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:735
|
|
local function slot_info(i)
|
|
if i == 1 or (i == 2 and is_double()) then return INFO_LEFT end
|
|
return INFO_RIGHT
|
|
end
|
|
|
|
local function slot_filled(i)
|
|
local mon = PartyMenu._party and PartyMenu._party[i]
|
|
return mon ~= nil and (tonumber(mon.species or mon.speciesId) or 1) ~= 0
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1499
|
|
local function double_next_slot(slot, dir)
|
|
while true do
|
|
slot = slot + dir
|
|
if slot < 1 or slot > 6 then return nil end
|
|
if slot_filled(slot) then return slot end
|
|
end
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1402
|
|
local function nav_double(cur, dir)
|
|
local last = PartyMenu._lastSelectedSlot
|
|
if dir == "up" then
|
|
if cur == 1 then return 7 end
|
|
local from = cur
|
|
if cur == 7 then from = 7 end
|
|
return double_next_slot(from, -1) or cur
|
|
elseif dir == "down" then
|
|
if cur == 7 then return 1 end
|
|
return double_next_slot(cur, 1) or 7
|
|
elseif dir == "right" then
|
|
if cur == 1 then
|
|
if last == 4 then
|
|
if slot_filled(4) then return 4 end
|
|
elseif slot_filled(3) then
|
|
return 3
|
|
end
|
|
elseif cur == 2 then
|
|
if last == 6 then
|
|
if slot_filled(6) then return 6 end
|
|
elseif slot_filled(5) then
|
|
return 5
|
|
end
|
|
end
|
|
return cur
|
|
elseif dir == "left" then
|
|
if cur == 3 or cur == 4 then
|
|
PartyMenu._lastSelectedSlot = cur
|
|
return 1
|
|
elseif cur == 5 or cur == 6 then
|
|
PartyMenu._lastSelectedSlot = cur
|
|
return 2
|
|
end
|
|
end
|
|
return cur
|
|
end
|
|
|
|
local function battle_nav_double(input)
|
|
local oldCur = PartyMenu.cursor
|
|
for _, dir in ipairs({ "up", "down", "left", "right" }) do
|
|
if input:wasPressed(dir) then
|
|
PartyMenu.cursor = nav_double(PartyMenu.cursor, dir)
|
|
break
|
|
end
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then se(5) end
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5905
|
|
local function open_battle_actions_double(prevMode)
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
se(5)
|
|
if not slot_filled(2) or (mon and mon.isEgg) then
|
|
PartyMenu.ACTIONS = { "SUMMARY", "CANCEL" }
|
|
elseif prevMode == "battle_faint" then
|
|
PartyMenu.ACTIONS = { "SEND OUT", "SUMMARY", "CANCEL" }
|
|
else
|
|
PartyMenu.ACTIONS = { "SHIFT", "SUMMARY", "CANCEL" }
|
|
end
|
|
PartyMenu._previousMode = prevMode
|
|
PartyMenu.mode = "action"
|
|
PartyMenu.actionCursor = 1
|
|
end
|
|
|
|
local function party_print(text, px, py, maxW)
|
|
FrlgFont.draw(tostring(text or ""), px, py, {
|
|
maxWidth = maxW or 56,
|
|
colors = FrlgFont.COLOR.PARTY,
|
|
small = true,
|
|
})
|
|
end
|
|
|
|
local function right_align_3(n)
|
|
n = math.floor(tonumber(n) or 0)
|
|
if n < 0 then n = 0 end
|
|
if n > 999 then n = 999 end
|
|
return string.format("%3d", n)
|
|
end
|
|
|
|
local function destroy_id(id)
|
|
if id ~= nil then Oam.destroySprite(id) end
|
|
end
|
|
|
|
local function destroy_party_oam()
|
|
local slots = PartyMenu._oam
|
|
if slots then
|
|
for i = 1, 6 do
|
|
local s = slots[i]
|
|
if s then
|
|
destroy_id(s.mon)
|
|
destroy_id(s.ball)
|
|
destroy_id(s.status)
|
|
destroy_id(s.item)
|
|
end
|
|
end
|
|
end
|
|
destroy_id(PartyMenu._summaryIcon)
|
|
PartyMenu._oam = nil
|
|
PartyMenu._summaryIcon = nil
|
|
end
|
|
|
|
local SUB_STATUS = 0
|
|
local SUB_ITEM = 0
|
|
local SUB_BALL = 4
|
|
local SUB_MON = 8
|
|
|
|
local HOLD_ICONS_SUB = "/pokemon/party/"
|
|
|
|
local function read_cache(rel)
|
|
local Dataset = require("src.core.game3.dataset")
|
|
local okR, d = pcall(function() return Dataset.cache():read(rel) end)
|
|
if okR and type(d) == "string" and #d > 0 then return d end
|
|
return nil
|
|
end
|
|
|
|
PartyMenu._holdIcons = nil
|
|
|
|
-- pokefirered/src/party_menu.c:2779
|
|
function PartyMenu.heldItemSheet()
|
|
if PartyMenu._holdIcons then return PartyMenu._holdIcons end
|
|
if not (love and love.graphics and love.graphics.newImage) then return nil end
|
|
local Extract = require("src.import.gba.extract_island1")
|
|
local root = (Extract.CACHE_ROOT or "data/generated/gba") .. HOLD_ICONS_SUB
|
|
local src = read_cache(root .. "manifest.lua")
|
|
local chunk = src and load(src, "@party/manifest.lua", "t", {})
|
|
local okM, man = false, nil
|
|
if chunk then okM, man = pcall(chunk) end
|
|
local w = okM and type(man) == "table" and tonumber(man.holdIconW)
|
|
local h = w and tonumber(man.holdIconSheetH)
|
|
local frames = h and tonumber(man.holdIconFrames)
|
|
local rgba = frames and read_cache(root .. "hold_icons.rgba")
|
|
if not (rgba and #rgba >= w * h * 4) then
|
|
error("party_menu: pokemon/party/hold_icons.rgba is not in the cache", 0)
|
|
end
|
|
local image = love.graphics.newImage(love.image.newImageData(w, h, "rgba8", rgba))
|
|
image:setFilter("nearest", "nearest")
|
|
local fh = math.floor(h / frames)
|
|
local quads = {}
|
|
for f = 0, frames - 1 do
|
|
quads[f] = love.graphics.newQuad(0, f * fh, w, fh, w, h)
|
|
end
|
|
PartyMenu._holdIcons = { image = image, quads = quads, w = w, h = fh }
|
|
return PartyMenu._holdIcons
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:2763
|
|
function PartyMenu.heldItemFrame(mon)
|
|
local raw = mon and (mon.item or mon.heldItem)
|
|
local item = tonumber(raw) or (raw ~= nil and tonumber(ItemsData.toNumericId(raw))) or 0
|
|
if item == 0 then return nil end
|
|
return require("src.core.game3.mail").isMailItem(item) and 1 or 0
|
|
end
|
|
|
|
local MON_ICON_ANIM_DELAYS = {
|
|
[0] = 6, -- HP_BAR_FULL (100% HP)
|
|
[1] = 8, -- HP_BAR_GREEN (>50% HP)
|
|
[2] = 14, -- HP_BAR_YELLOW (>20% HP)
|
|
[3] = 22, -- HP_BAR_RED (>0% HP)
|
|
[4] = 0, -- HP_BAR_EMPTY (0 HP / fainted: still)
|
|
}
|
|
|
|
local MON_ICON_ANIM_DURATIONS = {
|
|
[0] = 6 / 60, -- HP_BAR_FULL (100% HP): 6 frames = 0.100s
|
|
[1] = 8 / 60, -- HP_BAR_GREEN (>50% HP): 8 frames = 0.1333s
|
|
[2] = 14 / 60, -- HP_BAR_YELLOW (>20% HP): 14 frames = 0.2333s
|
|
[3] = 22 / 60, -- HP_BAR_RED (>0% HP): 22 frames = 0.3667s
|
|
[4] = 0, -- HP_BAR_EMPTY (0 HP / fainted: still)
|
|
}
|
|
|
|
local function get_hp_bar_level(hp, maxHp, isEgg)
|
|
if isEgg then return 4 end
|
|
hp = tonumber(hp) or 0
|
|
maxHp = tonumber(maxHp) or 1
|
|
if maxHp < 1 then maxHp = 1 end
|
|
if hp >= maxHp then return 0 end
|
|
if hp > maxHp * 0.5 then return 1 end
|
|
if hp > maxHp * 0.2 then return 2 end
|
|
if hp > 0 then return 3 end
|
|
return 4
|
|
end
|
|
|
|
local function idle_mon_offset(slotIndex)
|
|
local spr = slot_sprites(slotIndex)
|
|
if spr and spr[1] == 16 then
|
|
return 0, -4
|
|
end
|
|
return -4, 0
|
|
end
|
|
|
|
local function advance_sprite_anim(sprite)
|
|
local animNum = sprite.data[3] or 0
|
|
local duration = MON_ICON_ANIM_DURATIONS[animNum] or (8 / 60)
|
|
if duration <= 0 then
|
|
sprite.data[2] = 0
|
|
return 0
|
|
end
|
|
|
|
if love.timer and love.timer.getTime then
|
|
local now = love.timer.getTime()
|
|
local last = sprite._lastAnimTime or now
|
|
local dt = now - last
|
|
sprite._lastAnimTime = now
|
|
if dt < 0 then dt = 0 elseif dt > 0.1 then dt = 0.1 end
|
|
sprite._animElapsed = (sprite._animElapsed or 0) + dt
|
|
while sprite._animElapsed >= duration do
|
|
sprite._animElapsed = sprite._animElapsed - duration
|
|
sprite.data[2] = 1 - (sprite.data[2] or 0)
|
|
end
|
|
else
|
|
local delay = MON_ICON_ANIM_DELAYS[animNum] or 8
|
|
sprite.data[1] = (sprite.data[1] or 0) + 1
|
|
if sprite.data[1] >= delay then
|
|
sprite.data[1] = 0
|
|
sprite.data[2] = 1 - (sprite.data[2] or 0)
|
|
end
|
|
end
|
|
|
|
return sprite.data[2] or 0
|
|
end
|
|
|
|
local function SpriteCB_BouncePartyMonIcon(sprite)
|
|
local f = advance_sprite_anim(sprite)
|
|
sprite.x2 = 0
|
|
if (sprite.data[3] or 0) == 4 then
|
|
sprite.y2 = 0
|
|
elseif f == 0 then
|
|
sprite.y2 = -3
|
|
else
|
|
sprite.y2 = 1
|
|
end
|
|
if sprite._quads and sprite._quads[f] then
|
|
sprite.quad = sprite._quads[f]
|
|
end
|
|
end
|
|
|
|
local function SpriteCB_UpdatePartyMonIcon(sprite)
|
|
local f = advance_sprite_anim(sprite)
|
|
local slotIdx = sprite.data[4] or 1
|
|
local x2, y2 = idle_mon_offset(slotIdx)
|
|
sprite.x2 = x2
|
|
sprite.y2 = y2
|
|
if sprite._quads and sprite._quads[f] then
|
|
sprite.quad = sprite._quads[f]
|
|
end
|
|
end
|
|
|
|
local function ensure_slot_sprites(i, mon, selected)
|
|
PartyMenu._oam = PartyMenu._oam or {}
|
|
local slot = PartyMenu._oam[i]
|
|
if not slot then
|
|
slot = {}
|
|
PartyMenu._oam[i] = slot
|
|
end
|
|
local spr = slot_sprites(i)
|
|
if not spr or not mon then
|
|
destroy_id(slot.mon); slot.mon = nil
|
|
destroy_id(slot.ball); slot.ball = nil
|
|
destroy_id(slot.status); slot.status = nil
|
|
destroy_id(slot.item); slot.item = nil
|
|
return
|
|
end
|
|
|
|
local mx, my = spr[1], spr[2]
|
|
local bx, by = spr[7], spr[8]
|
|
local sx, sy = spr[5], spr[6]
|
|
|
|
local hp = tonumber(mon.hp) or 0
|
|
local maxHp = tonumber(mon.maxHp) or tonumber(mon.maxhp) or 1
|
|
local hpLevel = get_hp_bar_level(hp, maxHp, mon.isEgg)
|
|
|
|
local icon = Pokemon.monIcon(mon)
|
|
local q0 = icon and icon.quads and icon.quads[0]
|
|
if not slot.mon then
|
|
local id = select(1, Oam.createSprite({
|
|
dims = Oam.SQUARE_32,
|
|
priority = 1,
|
|
image = icon and icon.image,
|
|
quad = q0,
|
|
animPaused = true,
|
|
}, mx, my, SUB_MON))
|
|
slot.mon = id
|
|
else
|
|
Oam.setPos(slot.mon, mx, my)
|
|
local ms = Oam.get(slot.mon)
|
|
if ms then
|
|
ms.image = icon and icon.image
|
|
ms.subpriority = SUB_MON
|
|
end
|
|
end
|
|
if slot.mon then
|
|
local s = Oam.get(slot.mon)
|
|
if s then
|
|
s._quads = icon and icon.quads
|
|
s.data[3] = hpLevel
|
|
s.data[4] = i
|
|
end
|
|
if selected then
|
|
Oam.setCallback(slot.mon, SpriteCB_BouncePartyMonIcon)
|
|
if not slot._wasSelected then
|
|
if s then
|
|
s.data[1] = 0
|
|
s.x2, s.y2 = 0, ((s.data[2] or 0) == 1 and 1 or -3)
|
|
end
|
|
end
|
|
slot._wasSelected = true
|
|
else
|
|
Oam.setCallback(slot.mon, SpriteCB_UpdatePartyMonIcon)
|
|
if slot._wasSelected then
|
|
if s then
|
|
s.data[1] = 0
|
|
local x2, y2 = idle_mon_offset(i)
|
|
s.x2, s.y2 = x2, y2
|
|
end
|
|
end
|
|
slot._wasSelected = false
|
|
end
|
|
Oam.setInvisible(slot.mon, PartyMenu.mode == "summary")
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:2743
|
|
local holdFrame = PartyMenu.heldItemFrame(mon)
|
|
local hold = holdFrame and PartyMenu.heldItemSheet()
|
|
if hold then
|
|
local hq = hold.quads[holdFrame]
|
|
if not slot.item then
|
|
slot.item = select(1, Oam.createSprite({
|
|
dims = Oam.SQUARE_8,
|
|
priority = 1,
|
|
image = hold.image,
|
|
quad = hq,
|
|
}, spr[3], spr[4], SUB_ITEM))
|
|
else
|
|
Oam.setPos(slot.item, spr[3], spr[4])
|
|
Oam.setImage(slot.item, hold.image, hq)
|
|
end
|
|
if slot.item then
|
|
Oam.setInvisible(slot.item, PartyMenu.mode == "summary")
|
|
end
|
|
else
|
|
destroy_id(slot.item)
|
|
slot.item = nil
|
|
end
|
|
|
|
local balls = PartyChrome.ballEntry()
|
|
local ballFrame = selected and 1 or 0
|
|
local bq = balls and balls.quads and balls.quads[ballFrame]
|
|
if not slot.ball then
|
|
local id = select(1, Oam.createSprite({
|
|
dims = Oam.SQUARE_32,
|
|
priority = 1,
|
|
image = balls and balls.image,
|
|
quad = bq,
|
|
}, bx, by, SUB_BALL))
|
|
slot.ball = id
|
|
else
|
|
Oam.setPos(slot.ball, bx, by)
|
|
if balls and balls.image then Oam.setImage(slot.ball, balls.image, bq) end
|
|
local bs = Oam.get(slot.ball)
|
|
if bs then bs.subpriority = SUB_BALL end
|
|
end
|
|
if slot.ball then
|
|
Oam.setOffset(slot.ball, 0, 0)
|
|
Oam.setInvisible(slot.ball, PartyMenu.mode == "summary")
|
|
end
|
|
|
|
local SummaryData = require("src.core.game3.summary_data")
|
|
local statusFr = SummaryData.statusAilment(mon)
|
|
local stImg, stQ = PartyChrome.statusEntry(statusFr)
|
|
if statusFr > 0 and statusFr ~= 6 and stImg then
|
|
if not slot.status then
|
|
local id = select(1, Oam.createSprite({
|
|
dims = Oam.HRECT_32x8,
|
|
priority = 1,
|
|
image = stImg,
|
|
quad = stQ,
|
|
}, sx, sy, SUB_STATUS))
|
|
slot.status = id
|
|
else
|
|
Oam.setPos(slot.status, sx, sy)
|
|
Oam.setImage(slot.status, stImg, stQ)
|
|
local ss = Oam.get(slot.status)
|
|
if ss then ss.subpriority = SUB_STATUS end
|
|
end
|
|
if slot.status then
|
|
Oam.setInvisible(slot.status, PartyMenu.mode == "summary")
|
|
end
|
|
else
|
|
destroy_id(slot.status)
|
|
slot.status = nil
|
|
end
|
|
end
|
|
|
|
local function sync_all_oam()
|
|
local party = PartyMenu._party or {}
|
|
for i = 1, 6 do
|
|
local mon = party[i]
|
|
local selected = (i == PartyMenu.cursor or PartyMenu.switchFrom == i)
|
|
ensure_slot_sprites(i, mon, selected)
|
|
end
|
|
end
|
|
|
|
local FLUSHED_CLIP = { x = 0, y = 0, w = 0, h = 0 }
|
|
|
|
local function each_party_sprite(fn)
|
|
for _, slot in pairs(PartyMenu._oam or {}) do
|
|
for _, key in ipairs({ "mon", "ball", "status", "item" }) do
|
|
local s = slot[key] and Oam.get(slot[key])
|
|
if s then fn(s) end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function unflush_party_sprites()
|
|
each_party_sprite(function(s)
|
|
if s.clip == FLUSHED_CLIP then s.clip = nil end
|
|
end)
|
|
end
|
|
|
|
-- pokefirered/src/data/party_menu.h:1
|
|
local function flush_party_sprites()
|
|
local mine = {}
|
|
each_party_sprite(function(s) mine[s] = true end)
|
|
for _, s in ipairs(Oam.buildOamBuffer()) do
|
|
if mine[s] and s.clip ~= FLUSHED_CLIP then
|
|
Oam.flushOne(s)
|
|
s.clip = FLUSHED_CLIP
|
|
end
|
|
end
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:6005
|
|
function PartyMenu.battleOrder(st)
|
|
local party = st and st.playerParty or {}
|
|
local n = 0
|
|
for i = 1, 6 do if party[i] then n = i end end
|
|
local order = st._partyOrder
|
|
local valid = type(order) == "table" and #order == n
|
|
if valid then
|
|
local seen = {}
|
|
for i = 1, n do
|
|
local v = order[i]
|
|
if type(v) ~= "number" or v < 1 or v > n or seen[v] then valid = false break end
|
|
seen[v] = true
|
|
end
|
|
end
|
|
local b0 = (st.battlers and st.battlers[0]) or st.player
|
|
local b2 = st.double and st.battlers and st.battlers[2] or nil
|
|
if not valid then
|
|
order = {}
|
|
local used = {}
|
|
for _, b in ipairs({ b0, b2 }) do
|
|
local pi = b and tonumber(b.partyIndex)
|
|
if pi and pi >= 1 and pi <= n and not used[pi] then
|
|
order[#order + 1] = pi
|
|
used[pi] = true
|
|
end
|
|
end
|
|
for i = 1, n do
|
|
if not used[i] then order[#order + 1] = i end
|
|
end
|
|
st._partyOrder = order
|
|
end
|
|
-- pokefirered/src/party_menu.c:5972
|
|
for pos, b in ipairs({ b0, b2 }) do
|
|
local want = b and tonumber(b.partyIndex)
|
|
if want and order[pos] ~= want then
|
|
for j = 1, n do
|
|
if order[j] == want then
|
|
order[pos], order[j] = order[j], order[pos]
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return order
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:6199
|
|
local function apply_battle_order(party, overlay, opts)
|
|
local order = opts.battleOrder
|
|
if order == nil then
|
|
local Battle = package.loaded["src.core.game3.battle"]
|
|
local st = Battle and Battle._st
|
|
if not (st and st.playerParty and st.playerParty == party) then return party, overlay, opts end
|
|
order = PartyMenu.battleOrder(st)
|
|
end
|
|
local view = {}
|
|
for i, pi in ipairs(order) do view[i] = party[pi] end
|
|
local viewOverlay = overlay
|
|
if type(overlay) == "table" then
|
|
viewOverlay = {}
|
|
for i, pi in ipairs(order) do viewOverlay[i] = overlay[pi] end
|
|
end
|
|
local o = {}
|
|
for k, v in pairs(opts) do o[k] = v end
|
|
local active = opts.activeSlot
|
|
for i, pi in ipairs(order) do
|
|
if pi == active then o.activeSlot = i break end
|
|
end
|
|
local onSelect, validate = opts.onSelect, opts.validate
|
|
if onSelect then
|
|
o.onSelect = function(d, mon) return onSelect(d and order[d], mon) end
|
|
end
|
|
if validate then
|
|
o.validate = function(d) return validate(d and order[d]) end
|
|
end
|
|
PartyMenu._order = order
|
|
return view, viewOverlay, o
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1944
|
|
local OAK_DIM_TARGET = 6
|
|
local OAK_DIM_DELAY = 4
|
|
local OAK_TEXT_OPTS = { maxWidth = Chrome.DLG_W * 8, linePitch = 15, colors = FrlgFont.COLOR.NORMAL }
|
|
|
|
local function set_oak_page(page)
|
|
PartyMenu._oakPage = page
|
|
local text = (PartyMenu._oakPages or {})[page]
|
|
PartyMenu._oakWrapped = text and FrlgFont.wrap(text, Chrome.DLG_W * 8) or nil
|
|
end
|
|
|
|
local function end_oak_advice()
|
|
PartyMenu._oakPages = nil
|
|
PartyMenu._oakWrapped = nil
|
|
PartyMenu._oakFx = nil
|
|
PartyMenu.mode = PartyMenu._oakReturn or "list"
|
|
PartyMenu._oakReturn = nil
|
|
end
|
|
|
|
local function oak_ramp(fx, key, target)
|
|
if fx[key] == target then return true end
|
|
fx.counter = fx.counter + 1
|
|
if fx.counter > OAK_DIM_DELAY then
|
|
fx.counter = 0
|
|
fx[key] = fx[key] + ((fx[key] < target) and 1 or -1)
|
|
end
|
|
return fx[key] == target
|
|
end
|
|
|
|
local function tick_oak_advice()
|
|
local fx = PartyMenu._oakFx
|
|
if not fx then return end
|
|
if fx.phase == "darken" then
|
|
if oak_ramp(fx, "y", OAK_DIM_TARGET) then fx.phase = "text" end
|
|
elseif fx.phase == "lighten" then
|
|
-- pokefirered/src/party_menu.c:1970
|
|
if oak_ramp(fx, "slot", 0) then
|
|
fx.phase = "text"
|
|
set_oak_page((PartyMenu._oakPage or 1) + 1)
|
|
end
|
|
elseif fx.phase == "normal" then
|
|
-- pokefirered/src/party_menu.c:2001
|
|
fx.slot = math.min(fx.slot, fx.y)
|
|
if oak_ramp(fx, "y", 0) then end_oak_advice() end
|
|
end
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5832
|
|
local function begin_oak_advice(opts)
|
|
PartyMenu._oakPages = nil
|
|
PartyMenu._oakPage = 1
|
|
PartyMenu._oakReturn = nil
|
|
PartyMenu._oakWrapped = nil
|
|
PartyMenu._oakFx = nil
|
|
if not (opts and opts.battle) then return end
|
|
local BattleUi = package.loaded["src.core.game3.battle.ui"]
|
|
local st = BattleUi and BattleUi._st
|
|
if not st then return end
|
|
local okOak, Oak = pcall(require, "src.core.game3.battle.oak_advice")
|
|
if not okOak or not Oak then return end
|
|
local pages = Oak.take(st, Oak.FLAG_PARTY_MENU, "partyMenu")
|
|
if not pages then return end
|
|
PartyMenu._oakPages = pages
|
|
PartyMenu._oakReturn = PartyMenu.mode
|
|
PartyMenu.mode = "oak"
|
|
PartyMenu._oakFx = { phase = "darken", y = 0, slot = OAK_DIM_TARGET, counter = 0 }
|
|
set_oak_page(1)
|
|
end
|
|
|
|
function PartyMenu.show(sessionParty, moveOverlay, opts)
|
|
if type(moveOverlay) == "table" and opts == nil and (moveOverlay.mode or moveOverlay.session or moveOverlay.battle or moveOverlay.onSelect or moveOverlay.activeSlot) then
|
|
opts = moveOverlay
|
|
moveOverlay = nil
|
|
end
|
|
opts = opts or {}
|
|
PartyMenu._order = nil
|
|
if opts.mode == "battle_switch" or opts.mode == "battle_faint" or (opts.mode == "use" and opts.battleOrder) then
|
|
local party0 = sessionParty or (opts.session and opts.session.party)
|
|
local ov0 = moveOverlay or (opts.session and (opts.session.move_overlay or opts.session.moveOverlay))
|
|
if party0 then
|
|
sessionParty, moveOverlay, opts = apply_battle_order(party0, ov0, opts)
|
|
end
|
|
end
|
|
destroy_party_oam()
|
|
PartyMenu.open = true
|
|
PartyMenu._flyReturn = nil
|
|
PartyMenu._party = sessionParty or (opts.session and opts.session.party)
|
|
PartyMenu._overlay = moveOverlay or (opts.session and (opts.session.move_overlay or opts.session.moveOverlay))
|
|
PartyMenu._session = opts.session
|
|
PartyMenu._bag = opts.bag or (opts.session and (opts.session.bag or opts.session.inventory))
|
|
PartyMenu._item = opts.item
|
|
PartyMenu._giveSource = opts.giveSource
|
|
PartyMenu._activeSlot = opts.activeSlot or 1
|
|
PartyMenu._layout = (opts.layout == "double") and "double" or "single"
|
|
PartyMenu._multi = type(opts.multi) == "table" and opts.multi or nil
|
|
PartyMenu._minigameEligible = opts.minigameEligible
|
|
PartyMenu._battle = opts.battle or (opts.mode == "battle_switch" or opts.mode == "battle_faint")
|
|
PartyMenu.cursor = 1
|
|
PartyMenu.mode = opts.mode or "list"
|
|
-- pokefirered/src/party_menu.c:5651 InitChooseMonsForBattle
|
|
PartyMenu._chooseMax = nil
|
|
PartyMenu._chooseOrder = nil
|
|
PartyMenu._chooseEligible = nil
|
|
local wantCount = tonumber(opts.count) or 0
|
|
if opts.mode == "choose_multi" or (opts.mode == "choose" and wantCount > 1) then
|
|
PartyMenu.mode = "choose_multi"
|
|
PartyMenu._chooseMax = (wantCount > 0) and wantCount or 3
|
|
PartyMenu._chooseOrder = {}
|
|
PartyMenu._chooseEligible = opts.eligible
|
|
end
|
|
-- pokefirered/src/party_menu.c:5793 ChooseMonForMoveTutor
|
|
PartyMenu._tutor = nil
|
|
PartyMenu._tutorResult = nil
|
|
PartyMenu._tutorAutoSlot = nil
|
|
if PartyMenu.mode == "move_tutor" then
|
|
PartyMenu._tutor = tonumber(opts.tutor)
|
|
PartyMenu._tutorResult = false
|
|
local auto = tonumber(opts.autoSlot)
|
|
if auto and auto >= 1 then
|
|
PartyMenu.cursor = auto
|
|
PartyMenu._tutorAutoSlot = auto
|
|
end
|
|
end
|
|
PartyMenu._previousMode = PartyMenu.mode
|
|
PartyMenu.summaryPage = 1
|
|
PartyMenu.switchFrom = nil
|
|
PartyMenu._onClose = opts.onClose
|
|
PartyMenu._onSelect = opts.onSelect
|
|
PartyMenu._validate = opts.validate
|
|
PartyMenu._messageText = nil
|
|
PartyMenu._onMessageDismiss = nil
|
|
PartyMenu.actionCursor = 1
|
|
PartyMenu.itemActionCursor = 1
|
|
PartyMenu._lastSelectedSlot = 1
|
|
if not Pokemon._names then Pokemon.install(nil) end
|
|
PartyChrome.install(nil)
|
|
begin_oak_advice(opts)
|
|
Stack.push("party", PartyMenu, { hideBelow = true, fullscreen = true })
|
|
sync_all_oam()
|
|
end
|
|
|
|
-- pokefirered/src/region_map.c:4019
|
|
function PartyMenu.returnFromFlyMap()
|
|
local ret = PartyMenu._flyReturn
|
|
PartyMenu._flyReturn = nil
|
|
if not ret or PartyMenu.open then return false end
|
|
PartyMenu.show(ret.party, nil, { session = ret.session })
|
|
PartyMenu.cursor = ret.slot or 1
|
|
return true
|
|
end
|
|
|
|
function PartyMenu.close()
|
|
PartyMenu.open = false
|
|
PartyMenu.mode = "list"
|
|
PartyMenu._pokedude = nil
|
|
destroy_party_oam()
|
|
Stack.pop("party")
|
|
local cb = PartyMenu._onClose
|
|
PartyMenu._onClose = nil
|
|
if cb then cb() end
|
|
end
|
|
|
|
function PartyMenu.movesFor(slot)
|
|
local mon = PartyMenu._party and PartyMenu._party[slot]
|
|
if not mon then return {} end
|
|
local moves = {}
|
|
local ov = PartyMenu._overlay and PartyMenu._overlay[slot]
|
|
for i = 1, 4 do
|
|
local o = ov and ov[i]
|
|
if o and o.frlgMoveId then
|
|
moves[i] = { id = o.frlgMoveId, pp = o.pp, quarantined = true }
|
|
else
|
|
local rawM = mon.moves and mon.moves[i]
|
|
local mid = type(rawM) == "table" and (rawM.id or rawM.move or rawM.num or rawM.moveId or rawM.name or rawM[1]) or rawM
|
|
local mpp = type(rawM) == "table" and (rawM.pp or (mon.pp and mon.pp[i])) or (mon.pp and mon.pp[i])
|
|
moves[i] = {
|
|
id = mid,
|
|
pp = mpp,
|
|
quarantined = false,
|
|
}
|
|
end
|
|
end
|
|
return moves
|
|
end
|
|
|
|
function PartyMenu.isOpen()
|
|
return PartyMenu.open
|
|
end
|
|
|
|
local function party_count()
|
|
return #(PartyMenu._party or {})
|
|
end
|
|
|
|
-- pokefirered/src/evolution_scene.c:640 EVOSTATE_CANCEL
|
|
local function level_evolution_target(mon, session)
|
|
local Evolution = require("src.core.game3.evolution")
|
|
local target = Evolution.levelTarget(mon, session)
|
|
if target then return target, false end
|
|
local raw = Evolution.targetSpecies(mon, Evolution.EVO_MODE_NORMAL)
|
|
if raw and raw ~= 0 and not Evolution.nationalAllows(raw, session) then
|
|
return raw, true
|
|
end
|
|
return nil, false
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5674 GetBattleEntryEligibility
|
|
local function entry_eligible(slot)
|
|
local mon = PartyMenu._party and PartyMenu._party[slot]
|
|
if not mon or mon.isEgg then return false end
|
|
local rule = PartyMenu._chooseEligible
|
|
if type(rule) == "function" then
|
|
return rule(slot, mon) and true or false
|
|
elseif type(rule) == "table" then
|
|
for _, s in ipairs(rule) do
|
|
if (tonumber(s) or -1) + 1 == slot then return true end
|
|
end
|
|
return false
|
|
end
|
|
return (tonumber(mon.hp) or 0) > 0
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5736 HasPartySlotAlreadyBeenSelected
|
|
local function order_index(slot)
|
|
for i, s in ipairs(PartyMenu._chooseOrder or {}) do
|
|
if s == slot then return i end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:413 gSelectedOrderFromParty
|
|
function PartyMenu.chosenOrder()
|
|
local out = {}
|
|
for i, s in ipairs(PartyMenu._chooseOrder or {}) do out[i] = s end
|
|
return out
|
|
end
|
|
|
|
local function swap_slots(a, b)
|
|
if not PartyMenu._party or a == b then return end
|
|
if not PartyMenu._battle then
|
|
local Pokemon=require("src.core.game3.pokemon")
|
|
require("src.core.game3.quest_log_recorder").event(PartyMenu._session,"SwitchMon1WithMon2",
|
|
{Pokemon.displayMonName(PartyMenu._party[a]),Pokemon.displayMonName(PartyMenu._party[b])})
|
|
end
|
|
PartyMenu._party[a], PartyMenu._party[b] = PartyMenu._party[b], PartyMenu._party[a]
|
|
if PartyMenu._overlay then
|
|
PartyMenu._overlay[a], PartyMenu._overlay[b] =
|
|
PartyMenu._overlay[b], PartyMenu._overlay[a]
|
|
end
|
|
end
|
|
|
|
function PartyMenu.dismissMessage()
|
|
if PartyMenu.mode == "message" then
|
|
local cb = PartyMenu._onMessageDismiss
|
|
PartyMenu._messageText = nil
|
|
PartyMenu._onMessageDismiss = nil
|
|
PartyMenu.mode = "list"
|
|
if cb then
|
|
cb()
|
|
end
|
|
end
|
|
end
|
|
|
|
function PartyMenu.showMessage(text, onDismiss)
|
|
local pages = TextIR.splitPages(tostring(text), true)
|
|
local function show(i)
|
|
PartyMenu.mode = "message"
|
|
PartyMenu._messageText = pages[i]
|
|
if i >= #pages then
|
|
PartyMenu._onMessageDismiss = onDismiss
|
|
else
|
|
PartyMenu._onMessageDismiss = function() show(i + 1) end
|
|
end
|
|
end
|
|
show(1)
|
|
end
|
|
|
|
local function show_rom_message(key, vars, onDismiss)
|
|
PartyMenu.showMessage(RomText.box(key, { stringVars = vars, maxWidth = 216 }), onDismiss)
|
|
end
|
|
|
|
PartyMenu._yesNoPrompt = nil
|
|
PartyMenu._yesNoCallback = nil
|
|
PartyMenu._yesNoCursor = 1
|
|
PartyMenu._forgetPrompt = nil
|
|
PartyMenu._forgetMoves = nil
|
|
PartyMenu._forgetCallback = nil
|
|
PartyMenu._forgetCursor = 1
|
|
|
|
function PartyMenu.showYesNo(promptText, cb)
|
|
PartyMenu.mode = "yesno"
|
|
PartyMenu._yesNoPrompt = promptText
|
|
PartyMenu._yesNoCallback = cb
|
|
PartyMenu._yesNoCursor = 1
|
|
end
|
|
|
|
function PartyMenu.showForgetPrompt(promptText, moveNames, cb)
|
|
PartyMenu.mode = "forget"
|
|
PartyMenu._forgetPrompt = promptText
|
|
PartyMenu._forgetMoves = moveNames
|
|
PartyMenu._forgetCallback = cb
|
|
PartyMenu._forgetCursor = 1
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:4548 ShowMoveSelectWindow
|
|
function PartyMenu.pickPpMove(mon, item, cb)
|
|
local names, slots = {}, {}
|
|
for i = 1, 4 do
|
|
local id = Pokemon.moveIdAt(mon, i)
|
|
if id and id > 0 then
|
|
names[#names + 1] = Pokemon.moveName(id) or Strings("MOVE %s", id)
|
|
slots[#slots + 1] = i
|
|
end
|
|
end
|
|
-- pokefirered/src/strings.c:319 gText_RestoreWhichMove, :320 gText_BoostPp
|
|
local prompt = ItemUse.ppItemBoosts(item) and RomText.plain("gText_BoostPp")
|
|
or RomText.plain("gText_RestoreWhichMove")
|
|
PartyMenu.showForgetPrompt(prompt, names, function(idx)
|
|
if idx == nil then
|
|
-- pokefirered/src/party_menu.c:4628 ReturnToUseOnWhichMon
|
|
PartyMenu.mode = "use"
|
|
return
|
|
end
|
|
cb(slots[idx + 1])
|
|
end)
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:4841 Task_LearnNextMoveOrClosePartyMenu
|
|
local function tutor_learned(moveLearned)
|
|
if moveLearned then PartyMenu._tutorResult = true end
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5391 TryTutorSelectedMon
|
|
local function try_tutor_selected_mon(slot)
|
|
local mon = PartyMenu._party and PartyMenu._party[slot]
|
|
local tutor = PartyMenu._tutor
|
|
local MoveLearn = require("src.core.game3.move_learn")
|
|
local moveId = tutor and MoveLearn.tutorMove(tutor)
|
|
if not mon or not moveId then
|
|
PartyMenu.close()
|
|
return
|
|
end
|
|
local monName = Pokemon.displayMonName(mon)
|
|
local moveName = Pokemon.moveName(moveId) or ""
|
|
local status = MoveLearn.canMonLearnTutorMove(mon, tutor)
|
|
if status == MoveLearn.CANNOT_LEARN_MOVE or status == MoveLearn.CANNOT_LEARN_MOVE_IS_EGG then
|
|
-- pokefirered/src/party_menu.c:5407
|
|
show_rom_message("gText_PkmnCantLearnMove", { monName, moveName }, function()
|
|
PartyMenu.close()
|
|
end)
|
|
return
|
|
end
|
|
if status == MoveLearn.ALREADY_KNOWS_MOVE then
|
|
-- pokefirered/src/party_menu.c:5410
|
|
show_rom_message("gText_PkmnAlreadyKnows", { monName, moveName }, function()
|
|
PartyMenu.close()
|
|
end)
|
|
return
|
|
end
|
|
if Pokemon.moveSlotCount(mon) < 4 then
|
|
if Pokemon.teachMove(mon, moveId) then
|
|
pcall(function() require("src.core.game3.audio").playFanfare(257) end)
|
|
-- pokefirered/src/party_menu.c:4817
|
|
show_rom_message("gText_PkmnLearnedMove3", { monName, moveName }, function()
|
|
tutor_learned(true)
|
|
PartyMenu.close()
|
|
end)
|
|
else
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
local LearnMove = require("src.core.game3.battle.learn_move")
|
|
LearnMove.begin({
|
|
mon = mon,
|
|
moveId = moveId,
|
|
displayName = monName,
|
|
pushMsg = function(t, cb) PartyMenu.showMessage(t, cb) end,
|
|
askYesNo = function(a, b)
|
|
local cb = (type(a) == "function") and a or b
|
|
local prompt = (type(a) == "string") and a or PartyMenu._messageText or ""
|
|
PartyMenu.showYesNo(prompt, function(yes)
|
|
if cb then cb(yes == true) end
|
|
end)
|
|
end,
|
|
askForget = function(a, b, c)
|
|
local cb = (type(b) == "function") and b or c
|
|
local SummaryMenu = require("src.ui.game3.summary_menu")
|
|
destroy_party_oam()
|
|
SummaryMenu.openMenu(PartyMenu._party, slot, {
|
|
mode = "select_move",
|
|
moveToLearn = moveId,
|
|
onSelectMove = function(slotIdx)
|
|
sync_all_oam()
|
|
if cb then cb(slotIdx) end
|
|
end,
|
|
})
|
|
end,
|
|
onDone = function(learned)
|
|
tutor_learned(learned)
|
|
PartyMenu.close()
|
|
end,
|
|
})
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:2990 GetPartyMenuActionsType
|
|
function PartyMenu.multiActions(slot)
|
|
if not entry_eligible(slot) then
|
|
return { "SUMMARY", "CANCEL" }
|
|
elseif order_index(slot) then
|
|
return { "NO ENTRY", "SUMMARY", "CANCEL" }
|
|
end
|
|
return { "ENTER", "SUMMARY", "CANCEL" }
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:3760 CursorCB_Enter
|
|
function PartyMenu.enterChosenMon(slot)
|
|
local order = PartyMenu._chooseOrder or {}
|
|
local max = PartyMenu._chooseMax or 3
|
|
if #order >= max then
|
|
se(26)
|
|
-- pokefirered/src/party_menu.c:3769
|
|
local key = (max == 2) and "gText_NoMoreThanTwoMayEnter" or "gText_NoMoreThanThreeMayEnter"
|
|
show_rom_message(key, nil, function() PartyMenu.mode = "choose_multi" end)
|
|
return false
|
|
end
|
|
se(5)
|
|
order[#order + 1] = slot
|
|
PartyMenu.mode = "choose_multi"
|
|
if #order == max then
|
|
-- pokefirered/src/party_menu.c:3797 MoveCursorToConfirm
|
|
PartyMenu.cursor = SLOT_CONFIRM
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:3804 CursorCB_NoEntry
|
|
function PartyMenu.removeChosenMon(slot)
|
|
se(5)
|
|
local idx = order_index(slot)
|
|
if idx then table.remove(PartyMenu._chooseOrder, idx) end
|
|
PartyMenu.mode = "choose_multi"
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5746 Task_ValidateChosenMonsForBattle
|
|
function PartyMenu.confirmChosenMons()
|
|
local order = PartyMenu._chooseOrder or {}
|
|
if #order == 0 then
|
|
se(26)
|
|
-- pokefirered/src/strings.c:322
|
|
PartyMenu.showMessage(RomText.plain("gText_NoPokemonForBattle"), function()
|
|
PartyMenu.mode = "choose_multi"
|
|
end)
|
|
return false
|
|
end
|
|
se(5)
|
|
local picked = PartyMenu.chosenOrder()
|
|
local cb = PartyMenu._onSelect
|
|
PartyMenu.close()
|
|
if cb then cb(picked) end
|
|
return true
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1261 DisplayCancelChooseMonYesNo
|
|
function PartyMenu.askCancelChooseMons()
|
|
se(5)
|
|
-- pokefirered/src/strings.c:370
|
|
PartyMenu.showYesNo(RomText.plain("gText_CancelBattle"), function(yes)
|
|
if not yes then
|
|
PartyMenu.mode = "choose_multi"
|
|
return
|
|
end
|
|
-- pokefirered/src/party_menu.c:1285 ClearSelectedPartyOrder
|
|
PartyMenu._chooseOrder = {}
|
|
local cb = PartyMenu._onSelect
|
|
PartyMenu.close()
|
|
if cb then cb(nil) end
|
|
end)
|
|
end
|
|
|
|
function PartyMenu.reloadSprites()
|
|
destroy_party_oam()
|
|
sync_all_oam()
|
|
end
|
|
|
|
PartyMenu._hpAnim = nil
|
|
|
|
function PartyMenu.startHpAnim(slot, startHp, targetHp, maxHp, onDone)
|
|
PartyMenu._hpAnim = {
|
|
slot = slot,
|
|
current = startHp,
|
|
target = targetHp,
|
|
maxHp = maxHp,
|
|
speed = math.max(25, math.abs(targetHp - startHp) * 2.5),
|
|
onDone = onDone,
|
|
}
|
|
end
|
|
|
|
function PartyMenu.update(dt)
|
|
if PartyMenu.mode == "oak" then tick_oak_advice() end
|
|
-- pokefirered/src/party_menu.c:5805
|
|
if PartyMenu._tutorAutoSlot and PartyMenu.mode == "move_tutor" then
|
|
local slot = PartyMenu._tutorAutoSlot
|
|
PartyMenu._tutorAutoSlot = nil
|
|
try_tutor_selected_mon(slot)
|
|
end
|
|
local anim = PartyMenu._hpAnim
|
|
if anim then
|
|
dt = dt or (1 / 60)
|
|
if anim.current < anim.target then
|
|
anim.current = math.min(anim.target, anim.current + anim.speed * dt)
|
|
elseif anim.current > anim.target then
|
|
anim.current = math.max(anim.target, anim.current - anim.speed * dt)
|
|
end
|
|
if anim.current == anim.target then
|
|
local cb = anim.onDone
|
|
PartyMenu._hpAnim = nil
|
|
if cb then cb() end
|
|
end
|
|
end
|
|
|
|
local LearnMove = package.loaded["src.core.game3.battle.learn_move"]
|
|
if LearnMove and LearnMove.busy and LearnMove.busy() and LearnMove.pump then
|
|
LearnMove.pump()
|
|
end
|
|
end
|
|
|
|
local function pokedude_press(key)
|
|
return { wasPressed = function(_, k) return k == key end, isDown = function() return false end }
|
|
end
|
|
|
|
PartyMenu.POKEDUDE_PLANS = {
|
|
-- pokefirered/src/party_menu.c:2028 Task_PartyMenu_PokedudeStep
|
|
switch = { { at = 80, key = "right" }, { at = 160, key = "a" }, { at = 240, key = "a" } },
|
|
-- pokefirered/src/party_menu.c:2080 Task_PartyMenuFromBag_PokedudeStep
|
|
item = { { at = 80, use = true } },
|
|
}
|
|
|
|
local function pokedude_tick(input)
|
|
local pd = PartyMenu._pokedude
|
|
-- pokefirered/src/party_menu.c:2052 PartyMenuPokedudeIsCancelled
|
|
if input and input.wasPressed and input:wasPressed("b") then
|
|
local onCancel = pd.onCancel
|
|
PartyMenu.close()
|
|
if onCancel then onCancel() end
|
|
return
|
|
end
|
|
local entry = pd.plan[pd.index]
|
|
if entry and pd.frames == entry.at then
|
|
pd.index = pd.index + 1
|
|
if entry.use then
|
|
pd.used = true
|
|
local slot = PartyMenu._order and PartyMenu._order[PartyMenu.cursor] or PartyMenu.cursor
|
|
-- pokefirered/src/party_menu.c:4464 ItemUseCB_MedicineStep
|
|
local text = pd.onUse and pd.onUse(slot)
|
|
se(1)
|
|
PartyMenu.reloadSprites()
|
|
local onSelect = pd.onSelect
|
|
PartyMenu.showMessage(text or "", function()
|
|
-- pokefirered/src/party_menu.c:4538 Task_ClosePartyMenuAfterText
|
|
PartyMenu.close()
|
|
if onSelect then onSelect(slot) end
|
|
end)
|
|
return
|
|
end
|
|
pd.feeding = true
|
|
PartyMenu.handleInput(pokedude_press(entry.key))
|
|
if PartyMenu._pokedude == pd then pd.feeding = false end
|
|
end
|
|
pd.frames = pd.frames + 1
|
|
end
|
|
|
|
function PartyMenu.isPokedude()
|
|
return PartyMenu._pokedude ~= nil
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:5859 Pokedude_OpenPartyMenuInBattle
|
|
-- pokefirered/src/party_menu.c:5866 Pokedude_ChooseMonForInBattleItem
|
|
function PartyMenu.showPokedude(party, opts)
|
|
opts = opts or {}
|
|
local plan = PartyMenu.POKEDUDE_PLANS[opts.plan]
|
|
if not plan then error("no pokedude party plan " .. tostring(opts.plan)) end
|
|
local session = opts.session
|
|
if opts.plan == "switch" then
|
|
PartyMenu.show(party, nil, {
|
|
mode = "battle_switch",
|
|
session = session,
|
|
activeSlot = opts.activeSlot or 1,
|
|
battle = true,
|
|
validate = opts.validate,
|
|
onSelect = function(slot)
|
|
if opts.onSelect then opts.onSelect(slot) end
|
|
end,
|
|
})
|
|
else
|
|
PartyMenu.show(party, session and session.move_overlay, {
|
|
mode = "use",
|
|
session = session,
|
|
bag = opts.bag,
|
|
item = opts.item,
|
|
battle = true,
|
|
battleOrder = opts.battleOrder,
|
|
activeSlot = opts.activeSlot or 1,
|
|
})
|
|
end
|
|
PartyMenu._pokedude = {
|
|
plan = plan, index = 1, frames = 0,
|
|
onUse = opts.onUse, onSelect = opts.onSelect, onCancel = opts.onCancel,
|
|
}
|
|
end
|
|
|
|
function PartyMenu.handleInput(input)
|
|
local pdm = PartyMenu._pokedude
|
|
if pdm and not pdm.used and not pdm.feeding then
|
|
return pokedude_tick(input)
|
|
end
|
|
local n = party_count()
|
|
if n < 1 then
|
|
if input:wasPressed("b") or input:wasPressed("start") or input:wasPressed("a") then
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Fast-forward / complete HP animation on button press
|
|
if PartyMenu._hpAnim then
|
|
if input:wasPressed("a") or input:wasPressed("b") or input:wasPressed("start") then
|
|
local anim = PartyMenu._hpAnim
|
|
anim.current = anim.target
|
|
local cb = anim.onDone
|
|
PartyMenu._hpAnim = nil
|
|
if cb then cb() end
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "message" then
|
|
if input:wasPressed("a") or input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5)
|
|
PartyMenu.dismissMessage()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1936
|
|
if PartyMenu.mode == "oak" then
|
|
local fx = PartyMenu._oakFx
|
|
if not fx then
|
|
end_oak_advice()
|
|
elseif fx.phase == "text" and (input:wasPressed("a") or input:wasPressed("b")) then
|
|
se(5)
|
|
local page = (PartyMenu._oakPage or 1) + 1
|
|
if page > #(PartyMenu._oakPages or {}) then
|
|
PartyMenu._oakWrapped = nil
|
|
fx.phase = "normal"
|
|
elseif page == 2 and fx.slot > 0 then
|
|
fx.phase = "lighten"
|
|
else
|
|
set_oak_page(page)
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "yesno" then
|
|
if input:wasPressed("up") or input:wasPressed("down") then
|
|
PartyMenu._yesNoCursor = (PartyMenu._yesNoCursor == 1) and 2 or 1
|
|
se(5)
|
|
elseif input:wasPressed("a") then
|
|
se(5)
|
|
local cb = PartyMenu._yesNoCallback
|
|
local yes = (PartyMenu._yesNoCursor == 1)
|
|
PartyMenu._yesNoCallback = nil
|
|
PartyMenu._yesNoPrompt = nil
|
|
if cb then cb(yes) end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:5001
|
|
local cb = PartyMenu._yesNoCallback
|
|
PartyMenu._yesNoCallback = nil
|
|
PartyMenu._yesNoPrompt = nil
|
|
if cb then cb(false) end
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "forget" then
|
|
local moves = PartyMenu._forgetMoves or {}
|
|
local total = #moves
|
|
if total > 0 then
|
|
if input:wasPressed("up") then
|
|
PartyMenu._forgetCursor = ((PartyMenu._forgetCursor - 2) % total) + 1
|
|
se(5)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu._forgetCursor = (PartyMenu._forgetCursor % total) + 1
|
|
se(5)
|
|
elseif input:wasPressed("a") then
|
|
se(5)
|
|
local cb = PartyMenu._forgetCallback
|
|
local idx = PartyMenu._forgetCursor
|
|
PartyMenu._forgetCallback = nil
|
|
PartyMenu._forgetMoves = nil
|
|
PartyMenu._forgetPrompt = nil
|
|
if cb then cb(idx - 1) end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:5001
|
|
local cb = PartyMenu._forgetCallback
|
|
PartyMenu._forgetCallback = nil
|
|
PartyMenu._forgetMoves = nil
|
|
PartyMenu._forgetPrompt = nil
|
|
if cb then cb(nil) end
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "summary" then
|
|
if not SummaryMenu.isOpen() then
|
|
destroy_party_oam()
|
|
SummaryMenu.openMenu(PartyMenu._party, PartyMenu.cursor, {
|
|
session = PartyMenu._session,
|
|
onClose = function()
|
|
PartyMenu.mode = "list"
|
|
sync_all_oam()
|
|
end,
|
|
})
|
|
end
|
|
SummaryMenu.handleInput(input)
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "switch" then
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.switchFrom = nil
|
|
PartyMenu.mode = "list"
|
|
else
|
|
se(5)
|
|
swap_slots(PartyMenu.switchFrom or PartyMenu.cursor, PartyMenu.cursor)
|
|
PartyMenu.switchFrom = nil
|
|
PartyMenu.mode = "list"
|
|
end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.switchFrom = nil
|
|
PartyMenu.mode = "list"
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "item_action" then
|
|
local actions = PartyMenu.ITEM_ACTIONS
|
|
if input:wasPressed("up") then
|
|
PartyMenu.itemActionCursor = ((PartyMenu.itemActionCursor - 2) % #actions) + 1
|
|
se(5)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.itemActionCursor = (PartyMenu.itemActionCursor % #actions) + 1
|
|
se(5)
|
|
elseif input:wasPressed("a") then
|
|
local act = actions[PartyMenu.itemActionCursor]
|
|
if act == "TAKE" then
|
|
local ok, reason, msgText = ItemUse.takeFromMon(PartyMenu._session, PartyMenu._bag, PartyMenu.cursor)
|
|
se(5) -- pokefirered/src/party_menu.c:3594
|
|
PartyMenu.showMessage(msgText, function()
|
|
PartyMenu.mode = "list"
|
|
end)
|
|
elseif act == "GIVE" then
|
|
local BagMenu = require("src.ui.game3.bag_menu")
|
|
-- pokefirered/src/party_menu.c:3424
|
|
BagMenu.show(PartyMenu._session, {
|
|
bag = PartyMenu._bag,
|
|
location = "party",
|
|
onClose = function()
|
|
PartyMenu.mode = "list"
|
|
end,
|
|
})
|
|
else
|
|
se(5) -- pokefirered/src/party_menu.c:3733
|
|
PartyMenu.mode = "list"
|
|
end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:3083
|
|
PartyMenu.mode = "list"
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "stat_growth" then
|
|
if input:wasPressed("a") or input:wasPressed("b") or input:wasPressed("start") then
|
|
if PartyMenu._statGrowthPage == 1 then
|
|
se(5)
|
|
PartyMenu._statGrowthPage = 2
|
|
else
|
|
se(5)
|
|
PartyMenu.mode = "message"
|
|
local cb = PartyMenu._statGrowthDone
|
|
PartyMenu._statGrowthDone = nil
|
|
if cb then cb() end
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "action" then
|
|
local actions = PartyMenu.ACTIONS
|
|
if input:wasPressed("up") then
|
|
PartyMenu.actionCursor = ((PartyMenu.actionCursor - 2) % #actions) + 1
|
|
se(5)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.actionCursor = (PartyMenu.actionCursor % #actions) + 1
|
|
se(5)
|
|
elseif input:wasPressed("a") then
|
|
local act = actions[PartyMenu.actionCursor]
|
|
if act == "ENTER" then
|
|
-- pokefirered/src/party_menu.c:3760
|
|
PartyMenu.enterChosenMon(PartyMenu.cursor)
|
|
elseif act == "NO ENTRY" then
|
|
-- pokefirered/src/party_menu.c:3804
|
|
PartyMenu.removeChosenMon(PartyMenu.cursor)
|
|
elseif act == "SHIFT" or act == "SEND OUT" or (PartyMenu._previousMode == "battle_switch" and act == "SWITCH") then
|
|
se(5)
|
|
local cb = PartyMenu._onSelect
|
|
local chosen = PartyMenu.cursor
|
|
local why = PartyMenu._validate and PartyMenu._validate(chosen)
|
|
if why then
|
|
local back = PartyMenu._previousMode
|
|
PartyMenu.showMessage(why, function() PartyMenu.mode = back end)
|
|
return
|
|
end
|
|
PartyMenu.close()
|
|
if cb then cb(chosen, PartyMenu._party and PartyMenu._party[chosen]) end
|
|
elseif act == "SUMMARY" then
|
|
local prevMode = PartyMenu._previousMode or "list"
|
|
PartyMenu.mode = "list"
|
|
destroy_party_oam()
|
|
SummaryMenu.openMenu(PartyMenu._party, PartyMenu.cursor, {
|
|
session = PartyMenu._session,
|
|
onClose = function()
|
|
PartyMenu.mode = prevMode
|
|
sync_all_oam()
|
|
end,
|
|
})
|
|
elseif act == "SWITCH" then
|
|
se(5)
|
|
PartyMenu.switchFrom = PartyMenu.cursor
|
|
PartyMenu.mode = "switch"
|
|
elseif act == "ITEM" then
|
|
se(5)
|
|
PartyMenu.mode = "item_action"
|
|
PartyMenu.itemActionCursor = 1
|
|
elseif PartyMenu._fieldMoveNames and PartyMenu._fieldMoveNames[act] then
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
if act == "SOFTBOILED" or act == "MILK DRINK" then
|
|
local maxHp = mon and (mon.maxHp or (mon.stats and mon.stats.hp)) or 0
|
|
local cost = math.floor(maxHp / 5)
|
|
local curHp = mon and (mon.hp or 0) or 0
|
|
if curHp <= cost or cost <= 0 then
|
|
se(5) -- pokefirered/src/party_menu.c:3910
|
|
show_rom_message("gText_NotEnoughHp", nil, function()
|
|
PartyMenu.mode = "list"
|
|
end)
|
|
return
|
|
end
|
|
se(5)
|
|
PartyMenu._softboiledDonorSlot = PartyMenu.cursor
|
|
PartyMenu.mode = "softboiled"
|
|
return
|
|
else
|
|
local P = package.loaded["src.core.game3.player"] or require("src.core.game3.player")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Map = require("src.core.game3.map")
|
|
local Space = package.loaded["src.core.game3.scripting.space"]
|
|
local DELTA = { up = { 0, -1 }, down = { 0, 1 }, left = { -1, 0 }, right = { 1, 0 } }
|
|
local d = DELTA[P.facing or "down"] or DELTA.down
|
|
local fx, fy = P.cellX + d[1], P.cellY + d[2]
|
|
local facingObj = Objects.at(fx, fy)
|
|
local isWater = Collision.isWater and Collision.isWater(fx, fy)
|
|
-- pokefirered/src/fldeff_cut.c:140
|
|
local function hasCuttableGrass3x3(px, py)
|
|
if not Collision.isGrass then return false end
|
|
-- pokefirered/src/fldeff_rocksmash.c:31
|
|
local elev = P.elevation
|
|
for y = py - 1, py + 1 do
|
|
for x = px - 1, px + 1 do
|
|
local e = Collision.elevationAt and Collision.elevationAt(x, y)
|
|
if (elev == nil or e == elev) and Collision.isGrass(x, y) then return true end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
local mapDef = Map.currentDef()
|
|
-- pokefirered/src/party_menu.c:4118
|
|
local facingBeh = Collision.behavior and Collision.behavior(fx, fy)
|
|
local ctx = {
|
|
party = PartyMenu._party,
|
|
mon = mon,
|
|
store = Space and Space.store,
|
|
session = PartyMenu._session,
|
|
facingObject = facingObj,
|
|
isFacingWater = isWater,
|
|
isFacingWaterfall = FieldMoves.isWaterfallBehavior(facingBeh),
|
|
facing = P.facing,
|
|
isSurfing = P.surfing == true,
|
|
hasCuttableGrass = hasCuttableGrass3x3(P.cellX, P.cellY),
|
|
mapType = mapDef and mapDef.mapType,
|
|
isCave = mapHeaderFlag(mapDef, "cave"),
|
|
canEscapeRope = mapHeaderFlag(mapDef, "allowEscaping"),
|
|
-- pokefirered/src/field_effect.c:2126 SetWarpDestinationToEscapeWarp
|
|
escapeWarp = PartyMenu._session and PartyMenu._session.escapeWarp,
|
|
}
|
|
local res = FieldMoves.fromMenu(act, ctx)
|
|
if not res or not res.ok then
|
|
se(5) -- pokefirered/src/party_menu.c:3910
|
|
PartyMenu.showMessage((res and res.text) or RomText.plain("gText_CantUseHere"), function()
|
|
PartyMenu.mode = "list"
|
|
end)
|
|
else
|
|
se(5)
|
|
local Field = package.loaded["src.core.game3.field"] or require("src.core.game3.field")
|
|
local function run()
|
|
-- pokefirered/src/party_menu.c:3953
|
|
local flyReturn = nil
|
|
if res.action == "fly" then
|
|
flyReturn = {
|
|
party = PartyMenu._party,
|
|
session = PartyMenu._session,
|
|
slot = PartyMenu.cursor,
|
|
}
|
|
end
|
|
PartyMenu.close()
|
|
PartyMenu._flyReturn = flyReturn
|
|
-- pokefirered/src/party_menu.c:3958
|
|
local StartMenu = package.loaded["src.ui.game3.start_menu"]
|
|
if StartMenu and StartMenu.isOpen and StartMenu.isOpen() then
|
|
StartMenu.close(true)
|
|
end
|
|
if Field.executeFieldMove then
|
|
Field.executeFieldMove(res)
|
|
end
|
|
end
|
|
if res.action == "teleport" or res.action == "dig" then
|
|
local session = PartyMenu._session or {}
|
|
-- pokefirered/src/party_menu.c:3939
|
|
local destMap = session.healMap
|
|
local key = "gText_ReturnToHealingSpot"
|
|
if res.action == "dig" then
|
|
-- pokefirered/src/party_menu.c:3946
|
|
destMap = session.escapeWarp and session.escapeWarp.map
|
|
key = "gText_EscapeFromHereAndReturnTo"
|
|
end
|
|
local game = Field._game
|
|
local def = game and game.data and game.data.maps and game.data.maps[destMap]
|
|
local Sections = require("src.import.gba.map_sections_extract")
|
|
-- pokefirered/src/region_map.c:3828 GetMapNameGeneric
|
|
local placeName = Sections.getPlaceName(destMap, def and def.regionMapSectionId)
|
|
-- pokefirered/src/party_menu.c:3984 DisplayFieldMoveExitAreaMessage
|
|
PartyMenu.showYesNo(RomText.box(key, { stringVars = { placeName }, maxWidth = 216 }), function(yes)
|
|
if yes then
|
|
run()
|
|
else
|
|
-- pokefirered/src/party_menu.c:4014 Task_ReturnToChooseMonAfterText
|
|
PartyMenu.mode = "list"
|
|
end
|
|
end)
|
|
return
|
|
end
|
|
run()
|
|
end
|
|
return
|
|
end
|
|
else
|
|
se(5) -- pokefirered/src/party_menu.c:3393
|
|
PartyMenu.mode = PartyMenu._previousMode or "list"
|
|
end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:3393
|
|
PartyMenu.mode = PartyMenu._previousMode or "list"
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "softboiled" then
|
|
local oldCur = PartyMenu.cursor
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.mode = "list"
|
|
else
|
|
local userMon = PartyMenu._party and PartyMenu._party[PartyMenu._softboiledDonorSlot]
|
|
local targetMon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
local ok, userHp, targetHp = FieldMoves.softboiledTransfer(userMon, targetMon)
|
|
if not ok then
|
|
se(5) -- pokefirered/src/party_menu.c:4490
|
|
show_rom_message("gText_WontHaveEffect", nil, function()
|
|
PartyMenu.mode = "softboiled"
|
|
end)
|
|
else
|
|
se(11)
|
|
PartyMenu.mode = "list"
|
|
end
|
|
end
|
|
elseif input:wasPressed("b") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.mode = "list"
|
|
end
|
|
return
|
|
end
|
|
|
|
if PartyMenu.mode == "battle_switch" or PartyMenu.mode == "battle_faint" then
|
|
local sendOut = PartyMenu.mode == "battle_faint"
|
|
if is_double() then
|
|
battle_nav_double(input)
|
|
else
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then se(5) end
|
|
end
|
|
local cancel = input:wasPressed("b") or (input:wasPressed("a") and PartyMenu.cursor == 7)
|
|
if cancel then
|
|
-- pokefirered/src/party_menu.c:1229
|
|
if sendOut then
|
|
se(26)
|
|
else
|
|
se(5)
|
|
PartyMenu.close()
|
|
end
|
|
elseif input:wasPressed("a") then
|
|
open_battle_actions_double(PartyMenu.mode)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Selection mode for item USE
|
|
if PartyMenu.mode == "use" then
|
|
local oldCur = PartyMenu.cursor
|
|
if is_double() then
|
|
battle_nav_double(input)
|
|
oldCur = PartyMenu.cursor
|
|
elseif input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
if PartyMenu._onSelect then
|
|
PartyMenu._onSelect(nil)
|
|
else
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
if PartyMenu._onSelect then
|
|
PartyMenu._onSelect(PartyMenu.cursor)
|
|
return
|
|
end
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
if not mon then return end
|
|
|
|
if mon.isEgg then
|
|
se(26) -- pokefirered/src/party_menu.c:1223
|
|
PartyMenu.showMessage(Strings("An EGG can't be used on."), function()
|
|
PartyMenu.mode = "use"
|
|
end)
|
|
return
|
|
end
|
|
|
|
-- Case 1: TM / HM
|
|
if ItemsData.isTm(PartyMenu._item) then
|
|
local status, preflightMsg, moveId, moveName = ItemUse.checkTmPreflight(mon, PartyMenu._item)
|
|
if status == "knows" or status == "incompatible" or status == "invalid" then
|
|
se(5) -- pokefirered/src/party_menu.c:5001
|
|
PartyMenu.showMessage(preflightMsg, function()
|
|
PartyMenu.mode = "use"
|
|
end)
|
|
elseif status == "ok" then
|
|
se(5)
|
|
do
|
|
local isHm = ItemsData.isHm(PartyMenu._item)
|
|
local monName = Pokemon.displayMonName(mon)
|
|
|
|
-- pokefirered/src/party_menu.c:4785
|
|
if Pokemon.moveSlotCount(mon) < 4 then
|
|
local ok = Pokemon.teachMove(mon, moveId)
|
|
if ok then
|
|
-- pokefirered/src/party_menu.c:4811
|
|
Pokemon.adjustFriendship(mon, Pokemon.FRIENDSHIP_EVENT_LEARN_TMHM,
|
|
{ mapSec = Pokemon.currentMapSec(PartyMenu._session) })
|
|
require("src.core.game3.quest_log_recorder").event(PartyMenu._session,
|
|
isHm and "MonLearnedMoveFromHM" or "MonLearnedMoveFromTM",{monName,moveName})
|
|
if not isHm then
|
|
Bag.remove(PartyMenu._bag, PartyMenu._item, 1)
|
|
end
|
|
pcall(function() require("src.core.game3.audio").playFanfare(257) end)
|
|
-- pokefirered/src/party_menu.c:4817
|
|
show_rom_message("gText_PkmnLearnedMove3", { monName, moveName }, function()
|
|
PartyMenu.close()
|
|
end)
|
|
else
|
|
PartyMenu.mode = "use"
|
|
end
|
|
else
|
|
-- Full moveset: Forget Move flow
|
|
local LearnMove = require("src.core.game3.battle.learn_move")
|
|
LearnMove.begin({
|
|
mon = mon,
|
|
moveId = moveId,
|
|
displayName = monName,
|
|
pushMsg = function(t, cb) PartyMenu.showMessage(t, cb) end,
|
|
askYesNo = function(a, b)
|
|
local cb = (type(a) == "function") and a or b
|
|
local prompt = (type(a) == "string") and a or PartyMenu._messageText or ""
|
|
PartyMenu.showYesNo(prompt, function(yes)
|
|
if cb then cb(yes == true) end
|
|
end)
|
|
end,
|
|
askForget = function(a, b, c)
|
|
local cb = (type(b) == "function") and b or c
|
|
local SummaryMenu = require("src.ui.game3.summary_menu")
|
|
local LearnMove = require("src.core.game3.battle.learn_move")
|
|
local moveToLearn = (LearnMove and LearnMove._moveId) or moveId
|
|
destroy_party_oam()
|
|
SummaryMenu.openMenu(PartyMenu._party, PartyMenu.cursor, {
|
|
mode = "select_move",
|
|
moveToLearn = moveToLearn,
|
|
onSelectMove = function(slotIdx)
|
|
sync_all_oam()
|
|
if cb then cb(slotIdx) end
|
|
end,
|
|
})
|
|
end,
|
|
onDone = function(learned)
|
|
if learned then
|
|
-- pokefirered/src/party_menu.c:4811
|
|
Pokemon.adjustFriendship(mon, Pokemon.FRIENDSHIP_EVENT_LEARN_TMHM,
|
|
{ mapSec = Pokemon.currentMapSec(PartyMenu._session) })
|
|
require("src.core.game3.quest_log_recorder").event(PartyMenu._session,
|
|
isHm and "MonLearnedMoveFromHM" or "MonLearnedMoveFromTM",{monName,moveName})
|
|
if not isHm then
|
|
Bag.remove(PartyMenu._bag, PartyMenu._item, 1)
|
|
end
|
|
pcall(function() require("src.core.game3.audio").playFanfare(257) end)
|
|
PartyMenu.close()
|
|
else
|
|
PartyMenu.mode = "use"
|
|
end
|
|
end,
|
|
})
|
|
end
|
|
end
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Case 2: Rare Candy / Level up item
|
|
if ItemsData.fieldUseKind(PartyMenu._item) == "level" then
|
|
local lvl = tonumber(mon.level) or 1
|
|
local hp = tonumber(mon.hp) or 0
|
|
if lvl >= 100 or hp <= 0 then
|
|
se(5) -- pokefirered/src/party_menu.c:5028
|
|
show_rom_message("gText_WontHaveEffect", nil, function()
|
|
PartyMenu.mode = "use"
|
|
end)
|
|
return
|
|
end
|
|
|
|
se(1)
|
|
local oldStats = get_mon_stats(mon)
|
|
local oldMax = oldStats.maxHp
|
|
local oldHp = hp
|
|
|
|
Bag.remove(PartyMenu._bag, PartyMenu._item, 1)
|
|
require("src.core.game3.quest_log_recorder").event(PartyMenu._session,
|
|
"UsedItemOnMonAtThisLocation",{ItemsData.displayName(PartyMenu._item),Pokemon.displayMonName(mon)})
|
|
mon.level = lvl + 1
|
|
Pokemon.applyStats(mon)
|
|
local newStats = get_mon_stats(mon)
|
|
local newMax = newStats.maxHp
|
|
local newHp = math.min(newMax, oldHp + math.max(0, newMax - oldMax))
|
|
mon.hp = newHp
|
|
ItemUse.levelUpEvent(mon, mon.level)
|
|
|
|
pcall(function() require("src.core.game3.audio").playFanfare(257) end) -- MUS_LEVEL_UP (257)
|
|
|
|
local monName = Pokemon.displayMonName(mon)
|
|
-- pokefirered/src/party_menu.c:5059
|
|
local lvlMsg = RomText.plain("gText_PkmnElevatedToLvVar2", { stringVars = { monName, tostring(mon.level) } })
|
|
local slot = PartyMenu.cursor
|
|
|
|
local function check_evolution()
|
|
local toSpecies, blocked = level_evolution_target(mon, PartyMenu._session)
|
|
if toSpecies then
|
|
destroy_party_oam()
|
|
local EvolutionScene = require("src.ui.game3.evolution_scene")
|
|
local Audio = require("src.core.game3.audio")
|
|
EvolutionScene.start(mon, toSpecies, {
|
|
session = PartyMenu._session,
|
|
bag = PartyMenu._bag,
|
|
canStop = true,
|
|
autoCancel = blocked,
|
|
savedSong = Audio._mapSong,
|
|
onDone = function(result)
|
|
PartyMenu.reloadSprites()
|
|
PartyMenu.mode = "list"
|
|
end,
|
|
})
|
|
else
|
|
if Bag.has(PartyMenu._bag, PartyMenu._item, 1) then
|
|
PartyMenu.mode = "use"
|
|
else
|
|
PartyMenu.close()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function after_level_up()
|
|
local spId = Pokemon.speciesOf(mon) or tonumber(mon.species or mon.speciesId)
|
|
local newMoves = Pokemon.movesLearnedAt(spId, mon.level)
|
|
if #newMoves > 0 then
|
|
local LearnMove = require("src.core.game3.battle.learn_move")
|
|
local started = LearnMove.beginQueue(mon, { mon.level }, {
|
|
displayName = monName,
|
|
pushMsg = function(t, cb) PartyMenu.showMessage(t, cb) end,
|
|
askYesNo = function(a, b)
|
|
local cb = (type(a) == "function") and a or b
|
|
local prompt = (type(a) == "string") and a or PartyMenu._messageText or ""
|
|
PartyMenu.showYesNo(prompt, function(yes)
|
|
if cb then cb(yes == true) end
|
|
end)
|
|
end,
|
|
askForget = function(a, b, c)
|
|
local cb = (type(b) == "function") and b or c
|
|
local SummaryMenu = require("src.ui.game3.summary_menu")
|
|
local LearnMove = require("src.core.game3.battle.learn_move")
|
|
destroy_party_oam()
|
|
SummaryMenu.openMenu(PartyMenu._party, PartyMenu.cursor, {
|
|
mode = "select_move",
|
|
moveToLearn = LearnMove._moveId,
|
|
onSelectMove = function(slotIdx)
|
|
sync_all_oam()
|
|
if cb then cb(slotIdx) end
|
|
end,
|
|
})
|
|
end,
|
|
onDone = function()
|
|
check_evolution()
|
|
end,
|
|
})
|
|
if not started then
|
|
check_evolution()
|
|
end
|
|
else
|
|
check_evolution()
|
|
end
|
|
end
|
|
|
|
PartyMenu._messageText = lvlMsg
|
|
local function show_growth()
|
|
PartyMenu.showStatGrowth(mon, oldStats, newStats, after_level_up)
|
|
end
|
|
|
|
if newHp > oldHp then
|
|
PartyMenu.startHpAnim(slot, oldHp, newHp, newMax, show_growth)
|
|
else
|
|
show_growth()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Case 3: Evolution Stone
|
|
if is_evolution_stone(PartyMenu._item) then
|
|
local Evolution = require("src.core.game3.evolution")
|
|
local toSpecies = Evolution.itemTarget(mon, PartyMenu._item, PartyMenu._session)
|
|
if not toSpecies then
|
|
se(5) -- pokefirered/src/party_menu.c:4490
|
|
show_rom_message("gText_WontHaveEffect", nil, function()
|
|
PartyMenu.mode = "use"
|
|
end)
|
|
else
|
|
Bag.remove(PartyMenu._bag, PartyMenu._item, 1)
|
|
destroy_party_oam()
|
|
local EvolutionScene = require("src.ui.game3.evolution_scene")
|
|
local Audio = require("src.core.game3.audio")
|
|
EvolutionScene.start(mon, toSpecies, {
|
|
session = PartyMenu._session,
|
|
bag = PartyMenu._bag,
|
|
canStop = false,
|
|
savedSong = Audio._mapSong,
|
|
onDone = function(result)
|
|
PartyMenu.reloadSprites()
|
|
PartyMenu.mode = "list"
|
|
end,
|
|
})
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Case 4: General Medicine / Potions / Status
|
|
local function use_general(moveSlot)
|
|
local startHp = tonumber(mon and mon.hp) or 0
|
|
local maxHp = tonumber(mon and (mon.maxHp or mon.maxhp)) or 1
|
|
local realSlot = (PartyMenu._order and PartyMenu._order[PartyMenu.cursor]) or PartyMenu.cursor
|
|
local ok, reason, msgText = ItemUse.useField(PartyMenu._session, PartyMenu._bag, PartyMenu._item, realSlot, moveSlot)
|
|
local endHp = tonumber(mon and mon.hp) or startHp
|
|
if ok then
|
|
-- pokefirered/src/party_menu.c:4498
|
|
se(ItemUse.isFlute(PartyMenu._item) and 110 or 1)
|
|
local hasRemaining = Bag.has(PartyMenu._bag, PartyMenu._item, 1)
|
|
if endHp > startHp then
|
|
PartyMenu.startHpAnim(PartyMenu.cursor, startHp, endHp, maxHp, function()
|
|
PartyMenu.showMessage(msgText, function()
|
|
if hasRemaining then
|
|
PartyMenu.mode = "use"
|
|
else
|
|
PartyMenu.close()
|
|
end
|
|
end)
|
|
end)
|
|
else
|
|
PartyMenu.showMessage(msgText, function()
|
|
if hasRemaining then
|
|
PartyMenu.mode = "use"
|
|
else
|
|
PartyMenu.close()
|
|
end
|
|
end)
|
|
end
|
|
else
|
|
se(5) -- pokefirered/src/party_menu.c:4490
|
|
PartyMenu.showMessage(msgText or RomText.plain("gText_WontHaveEffect"), function()
|
|
PartyMenu.mode = "use"
|
|
end)
|
|
end
|
|
end
|
|
-- pokefirered/src/party_menu.c:4591 ItemUseCB_TryRestorePP
|
|
if ItemsData.fieldUseKind(PartyMenu._item) == "pp" and ItemUse.ppItemNeedsMove(PartyMenu._item) then
|
|
se(5)
|
|
PartyMenu.pickPpMove(mon, PartyMenu._item, use_general)
|
|
return
|
|
end
|
|
use_general(nil)
|
|
elseif input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1172
|
|
if PartyMenu.mode == "move_tutor" then
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
return
|
|
end
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
if not mon then return end
|
|
if mon.isEgg then
|
|
se(26) -- pokefirered/src/party_menu.c:1223
|
|
return
|
|
end
|
|
se(5) -- pokefirered/src/party_menu.c:1175
|
|
try_tutor_selected_mon(PartyMenu.cursor)
|
|
elseif input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Selection mode for item GIVE
|
|
if PartyMenu.mode == "give" then
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
else
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
if mon and mon.isEgg then
|
|
se(26) -- pokefirered/src/party_menu.c:1223
|
|
else
|
|
se(5) -- pokefirered/src/party_menu.c:1190
|
|
local session, bag, item, slot = PartyMenu._session, PartyMenu._bag, PartyMenu._item, PartyMenu.cursor
|
|
local source = PartyMenu._giveSource
|
|
local kind, _, msgText = ItemUse.checkGive(session, item, slot)
|
|
if kind == "give" then
|
|
msgText = ItemUse.giveHeld(session, bag, item, slot, source)
|
|
end
|
|
if kind == "switch" then
|
|
-- src/party_menu.c:5554 Task_SwitchItemsFromBagYesNo
|
|
local pages = TextIR.splitPages(tostring(msgText), true)
|
|
local last = pages[#pages]
|
|
local head = #pages > 1 and table.concat(pages, "\f", 1, #pages - 1) or nil
|
|
local function ask()
|
|
PartyMenu.showYesNo(last or msgText, function(yes)
|
|
if not yes then
|
|
PartyMenu.close()
|
|
return
|
|
end
|
|
local _, switched = ItemUse.switchHeld(session, bag, item, slot, source)
|
|
PartyMenu.showMessage(switched, function()
|
|
PartyMenu.close()
|
|
end)
|
|
end)
|
|
end
|
|
if head then PartyMenu.showMessage(head, ask) else ask() end
|
|
else
|
|
PartyMenu.showMessage(msgText, function()
|
|
PartyMenu.close()
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
elseif input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- pokefirered/src/party_menu.c:1119 Task_HandleChooseMonInput
|
|
if PartyMenu.mode == "choose_multi" then
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = multi_nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = multi_nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = multi_nav_left(PartyMenu.cursor, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("start") then
|
|
-- pokefirered/src/party_menu.c:1133
|
|
PartyMenu.cursor = SLOT_CONFIRM
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == SLOT_CONFIRM then
|
|
PartyMenu.confirmChosenMons()
|
|
elseif PartyMenu.cursor == SLOT_CANCEL_MULTI then
|
|
PartyMenu.askCancelChooseMons()
|
|
else
|
|
se(5)
|
|
PartyMenu.ACTIONS = PartyMenu.multiActions(PartyMenu.cursor)
|
|
PartyMenu._fieldMoveNames = nil
|
|
PartyMenu.mode = "action"
|
|
PartyMenu.actionCursor = 1
|
|
end
|
|
elseif input:wasPressed("b") then
|
|
-- pokefirered/src/party_menu.c:1261 DisplayCancelChooseMonYesNo
|
|
PartyMenu.askCancelChooseMons()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Selection mode for generic choose
|
|
if PartyMenu.mode == "choose" then
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
else
|
|
se(5)
|
|
local cb = PartyMenu._onSelect
|
|
local why = PartyMenu._validate and PartyMenu._validate(PartyMenu.cursor)
|
|
if why then
|
|
local back = PartyMenu._previousMode
|
|
PartyMenu.showMessage(why, function() PartyMenu.mode = back end)
|
|
return
|
|
end
|
|
PartyMenu.close()
|
|
if cb then cb(PartyMenu.cursor, PartyMenu._party and PartyMenu._party[PartyMenu.cursor]) end
|
|
end
|
|
elseif input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Default list mode
|
|
local oldCur = PartyMenu.cursor
|
|
if input:wasPressed("up") then
|
|
PartyMenu.cursor = nav_up(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("down") then
|
|
PartyMenu.cursor = nav_down(PartyMenu.cursor, n)
|
|
elseif input:wasPressed("left") then
|
|
PartyMenu.cursor, PartyMenu._lastSelectedSlot = nav_left(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
elseif input:wasPressed("right") then
|
|
PartyMenu.cursor = nav_right(PartyMenu.cursor, n, PartyMenu._lastSelectedSlot)
|
|
end
|
|
if PartyMenu.cursor ~= oldCur then
|
|
se(5)
|
|
end
|
|
if input:wasPressed("a") then
|
|
if PartyMenu.cursor == 7 then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
return
|
|
end
|
|
se(5)
|
|
local mon = PartyMenu._party and PartyMenu._party[PartyMenu.cursor]
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
-- pokefirered/src/party_menu.c:2963
|
|
local actions = { "SUMMARY" }
|
|
local fmNames = {}
|
|
if mon and not mon.isEgg and mon.moves then
|
|
for _, m in ipairs(mon.moves) do
|
|
local mId = FieldMoves.normalizeMoveId(m)
|
|
local mName = mId and FieldMoves.MOVE_NAME_BY_ID[mId]
|
|
local label = mName and mName:gsub("_", " ")
|
|
if label and FIELD_MOVE_INDEX[label] and not fmNames[label] then
|
|
actions[#actions + 1] = label
|
|
fmNames[label] = true
|
|
end
|
|
end
|
|
end
|
|
actions[#actions + 1] = "SWITCH"
|
|
if not (mon and mon.isEgg) then
|
|
actions[#actions + 1] = "ITEM"
|
|
end
|
|
actions[#actions + 1] = "CANCEL"
|
|
PartyMenu.ACTIONS = actions
|
|
PartyMenu._fieldMoveNames = fmNames
|
|
PartyMenu.mode = "action"
|
|
PartyMenu.actionCursor = 1
|
|
elseif input:wasPressed("b") or input:wasPressed("start") then
|
|
se(5) -- pokefirered/src/party_menu.c:1246
|
|
PartyMenu.close()
|
|
end
|
|
end
|
|
|
|
local function hp_bar(hp, maxHp, px, py, width)
|
|
width = width or 48
|
|
hp = tonumber(hp) or 0
|
|
maxHp = tonumber(maxHp) or 1
|
|
if maxHp < 1 then maxHp = 1 end
|
|
local ratio = math.max(0, math.min(1, hp / maxHp))
|
|
local w = math.floor(width * ratio)
|
|
if w <= 0 then return end
|
|
if ratio > 0.5 then
|
|
love.graphics.setColor(0.25, 0.85, 0.25, 1)
|
|
elseif ratio > 0.2 then
|
|
love.graphics.setColor(0.95, 0.85, 0.15, 1)
|
|
else
|
|
love.graphics.setColor(0.95, 0.2, 0.15, 1)
|
|
end
|
|
love.graphics.rectangle("fill", px, py, w, 3)
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
end
|
|
|
|
-- BG + text only; OAM sprites flushed by Display.present.
|
|
-- pokefirered/src/party_menu.c:848 DisplayPartyPokemonDataForMoveTutorOrEvolutionItem
|
|
local MULTI_ORDER_TEXT = { "FIRST", "SECOND", "THIRD" }
|
|
|
|
local function slot_description(slot, mon)
|
|
-- pokefirered/src/party_menu.c:839
|
|
if PartyMenu._minigameEligible then
|
|
return desc_text(PartyMenu._minigameEligible(slot, mon) and "ABLE" or "NOT_ABLE")
|
|
end
|
|
-- pokefirered/src/party_menu.c:812 DisplayPartyPokemonDataForChooseMultiple
|
|
if PartyMenu._chooseOrder then
|
|
if not entry_eligible(slot) then return desc_text("NOT_ABLE") end
|
|
local idx = order_index(slot)
|
|
if idx and MULTI_ORDER_TEXT[idx] then return desc_text(MULTI_ORDER_TEXT[idx]) end
|
|
return desc_text("ABLE_3")
|
|
end
|
|
-- pokefirered/src/party_menu.c:881 DisplayPartyPokemonDataToTeachMove
|
|
if PartyMenu._tutor then
|
|
local MoveLearn = require("src.core.game3.move_learn")
|
|
local status = MoveLearn.canMonLearnTutorMove(mon, PartyMenu._tutor)
|
|
if status == MoveLearn.ALREADY_KNOWS_MOVE then return desc_text("LEARNED") end
|
|
if status == MoveLearn.CAN_LEARN_MOVE then return desc_text("ABLE_2") end
|
|
return desc_text("NOT_ABLE_2")
|
|
end
|
|
local item = PartyMenu._item
|
|
if not item or PartyMenu._battle then return nil end
|
|
if PartyMenu.mode ~= "use" and PartyMenu.mode ~= "message" then return nil end
|
|
if not is_evolution_stone(item) then return nil end
|
|
local Evolution = require("src.core.game3.evolution")
|
|
if Evolution.itemCheck(mon, item) then return nil end
|
|
return desc_text("NO_USE")
|
|
end
|
|
|
|
function PartyMenu.slotDescription(slot)
|
|
local mon = PartyMenu._party and PartyMenu._party[slot]
|
|
if not mon then return nil end
|
|
return slot_description(slot, mon)
|
|
end
|
|
|
|
local function draw_filled_slot(i, mon, selected)
|
|
local win = slot_win(i)
|
|
if not win then return end
|
|
local T = Display.TILE or 8
|
|
local baseX, baseY = win.left * T, win.top * T
|
|
local info = slot_info(i)
|
|
local desc = slot_description(i, mon)
|
|
|
|
-- pokefirered/src/party_menu.c:781 DisplayPartyPokemonData: an egg's slot
|
|
-- has no HP frame and shows only its nickname (gText_EggNickname).
|
|
local isEgg = Pokemon.isEgg(mon)
|
|
-- pokefirered/src/party_menu.c:1040
|
|
local multiAlt = PartyMenu._multi ~= nil and PartyMenu._multi[i] == true and (tonumber(mon.hp) or 0) > 0
|
|
PartyChrome.drawSlot(win.kind, win.left, win.top, selected, desc ~= nil or isEgg, multiAlt)
|
|
|
|
local name = Pokemon.displayName(mon)
|
|
party_print(name, baseX + info.nick[1], baseY + info.nick[2], 56)
|
|
if isEgg then
|
|
if desc then party_print(desc, baseX + info.desc[1], baseY + info.desc[2], 64) end
|
|
return
|
|
end
|
|
local SummaryData = require("src.core.game3.summary_data")
|
|
local ailment = SummaryData.statusAilment(mon)
|
|
-- pokefirered/src/party_menu.c:2322 DisplayPartyPokemonLevelCheck:
|
|
-- Level is only shown when the mon is healthy (or PKRS); status ailments replace level.
|
|
if ailment == 0 or ailment == 6 then
|
|
-- pokefirered/src/party_menu.c:2335
|
|
party_print(RomText.plain("gText_Lv") .. tostring(mon.level or 0), baseX + info.level[1], baseY + info.level[2], 32)
|
|
end
|
|
|
|
local gender = mon.gender or (Pokemon.gender and Pokemon.gender(mon.species, mon.personality))
|
|
local isNidoran = (mon.species == 29 or mon.species == 32)
|
|
if gender and not isNidoran then
|
|
if gender == "M" then
|
|
FrlgFont.draw("♂", baseX + info.gender[1], baseY + info.gender[2], { colors = FrlgFont.COLOR.PARTY_MALE, small = true })
|
|
elseif gender == "F" then
|
|
FrlgFont.draw("♀", baseX + info.gender[1], baseY + info.gender[2], { colors = FrlgFont.COLOR.PARTY_FEMALE, small = true })
|
|
end
|
|
end
|
|
|
|
if desc then
|
|
party_print(desc, baseX + info.desc[1], baseY + info.desc[2], 64)
|
|
return
|
|
end
|
|
|
|
local hp = tonumber(mon.hp) or 0
|
|
local maxHp = tonumber(mon.maxHp) or tonumber(mon.maxhp) or 0
|
|
local anim = PartyMenu._hpAnim
|
|
local displayHp = hp
|
|
if anim and anim.slot == i then
|
|
displayHp = math.floor(anim.current + 0.5)
|
|
end
|
|
party_print(right_align_3(displayHp) .. "/", baseX + info.hp[1], baseY + info.hp[2], 24)
|
|
party_print("/" .. right_align_3(maxHp), baseX + info.hpMax[1], baseY + info.hpMax[2], 24)
|
|
hp_bar(displayHp, maxHp, baseX + info.hpBar[1], baseY + info.hpBar[2], 48)
|
|
end
|
|
|
|
function PartyMenu.draw()
|
|
if not PartyMenu.open then return end
|
|
local party = PartyMenu._party or {}
|
|
|
|
if PartyMenu.mode == "summary" or SummaryMenu.isOpen() then
|
|
destroy_party_oam()
|
|
if PartyMenu.mode == "summary" then
|
|
PartyChrome.drawBg()
|
|
SummaryMenu.draw()
|
|
end
|
|
return
|
|
end
|
|
|
|
PartyChrome.drawBg()
|
|
sync_all_oam()
|
|
unflush_party_sprites()
|
|
|
|
destroy_id(PartyMenu._summaryIcon)
|
|
PartyMenu._summaryIcon = nil
|
|
|
|
for i = 1, 6 do
|
|
local mon = party[i]
|
|
local win = slot_win(i)
|
|
if mon then
|
|
draw_filled_slot(i, mon, i == PartyMenu.cursor or PartyMenu.switchFrom == i)
|
|
elseif i > 1 and win and win.kind ~= "main" then
|
|
PartyChrome.drawSlot("empty", win.left, win.top, false)
|
|
end
|
|
end
|
|
|
|
if PartyMenu.mode ~= "oak" then flush_party_sprites() end
|
|
|
|
if PartyMenu.mode == "oak" then
|
|
-- pokefirered/src/party_menu.c:1944
|
|
local fx = PartyMenu._oakFx
|
|
local y = fx and fx.y or 0
|
|
local slotY = fx and math.min(fx.slot, y) or 0
|
|
local win = slot_win(1)
|
|
if y > 0 and win then
|
|
local T = Display.TILE or 8
|
|
local sx, sy, sw, sh = win.left * T, win.top * T, win.w * T, win.h * T
|
|
love.graphics.setColor(0, 0, 0, y / 16)
|
|
love.graphics.rectangle("fill", 0, 0, Display.W, sy)
|
|
love.graphics.rectangle("fill", 0, sy, sx, sh)
|
|
love.graphics.rectangle("fill", sx + sw, sy, Display.W - sx - sw, sh)
|
|
love.graphics.rectangle("fill", 0, sy + sh, Display.W, Display.H - sy - sh)
|
|
if slotY > 0 then
|
|
-- pokefirered/src/party_menu.c:1970
|
|
love.graphics.setColor(0, 0, 0, slotY / 16)
|
|
love.graphics.rectangle("fill", sx, sy, sw, sh)
|
|
end
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
end
|
|
flush_party_sprites()
|
|
if fx and fx.phase ~= "darken" and fx.phase ~= "normal" then
|
|
-- pokefirered/src/party_menu.c:2604
|
|
Chrome.dialogueFrame()
|
|
if PartyMenu._oakWrapped then
|
|
FrlgFont.draw(PartyMenu._oakWrapped, Chrome.DLG_LEFT * 8, Chrome.DLG_TOP * 8 + 1, OAK_TEXT_OPTS)
|
|
end
|
|
end
|
|
elseif PartyMenu.mode == "message" then
|
|
Window.stdFrame(Window.template(1, 15, 28, 4))
|
|
if PartyMenu._messageText then
|
|
local wrapped = FrlgFont.wrap(PartyMenu._messageText, 216)
|
|
FrlgFont.draw(wrapped, 1 * 8 + 6, 15 * 8 + 4, { maxWidth = 216, linePitch = 15, colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
elseif PartyMenu.mode == "stat_growth" then
|
|
Window.stdFrame(Window.template(1, 15, 28, 4))
|
|
if PartyMenu._messageText then
|
|
local wrapped = FrlgFont.wrap(PartyMenu._messageText, 216)
|
|
FrlgFont.draw(wrapped, 1 * 8 + 6, 15 * 8 + 4, { maxWidth = 216, linePitch = 15, colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
|
|
local winX, winY, winW, winH = 19, 1, 10, 11
|
|
Window.stdFrame(Window.template(winX, winY, winW, winH))
|
|
-- pokefirered/src/pokemon_special_anim_scene.c:1486
|
|
local statNames = RomText.list("sLevelUpWindowStatNames")
|
|
local oldS = PartyMenu._statGrowthOld or {}
|
|
local newS = PartyMenu._statGrowthNew or {}
|
|
local oldList = { oldS.maxHp or 0, oldS.atk or 0, oldS.def or 0, oldS.spa or 0, oldS.spd or 0, oldS.spe or 0 }
|
|
local newList = { newS.maxHp or 0, newS.atk or 0, newS.def or 0, newS.spa or 0, newS.spd or 0, newS.spe or 0 }
|
|
local isPage1 = (PartyMenu._statGrowthPage == 1)
|
|
|
|
for idx = 1, 6 do
|
|
local rowY = winY * 8 + 2 + (idx - 1) * 14
|
|
FrlgFont.draw(statNames[idx],winX * 8 + 2, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
if isPage1 then
|
|
local diff = newList[idx] - oldList[idx]
|
|
local sign = (diff >= 0) and "+" or "-"
|
|
local diffStr = string.format("%s%2d", sign, math.abs(diff))
|
|
FrlgFont.draw(diffStr, winX * 8 + 52, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
else
|
|
local valStr = string.format("%3d", newList[idx])
|
|
FrlgFont.draw(valStr, winX * 8 + 52, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
end
|
|
elseif PartyMenu.mode == "yesno" then
|
|
Window.stdFrame(Window.template(1, 15, 28, 4))
|
|
if PartyMenu._yesNoPrompt then
|
|
local wrapped = FrlgFont.wrap(PartyMenu._yesNoPrompt, 216)
|
|
FrlgFont.draw(wrapped, 1 * 8 + 6, 15 * 8 + 4, { maxWidth = 216, linePitch = 15, colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
-- Yes/No window overlay at tile X=21, Y=9, W=6, H=4
|
|
local ynX = 21
|
|
local ynY = 9
|
|
Window.stdFrame(Window.template(ynX, ynY, 6, 4))
|
|
local options = { RomText.plain("gText_Yes"), RomText.plain("gText_No") }
|
|
for i, opt in ipairs(options) do
|
|
local rowY = (ynY * 8) + (i - 1) * 16 + 2
|
|
if i == PartyMenu._yesNoCursor then
|
|
Window.cursorPx(ynX * 8 + 1, rowY)
|
|
end
|
|
FrlgFont.draw(opt, ynX * 8 + 9, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
elseif PartyMenu.mode == "forget" then
|
|
Window.stdFrame(Window.template(1, 17, 15, 2))
|
|
FrlgFont.draw(PartyMenu._forgetPrompt or Strings("Which move?"), 1 * 8 + 2, 17 * 8 + 2, { colors = FrlgFont.COLOR.NORMAL })
|
|
|
|
local moves = PartyMenu._forgetMoves or {}
|
|
local popW = 11
|
|
local popH = math.max(4, #moves * 2)
|
|
local popX = 18
|
|
local popY = 19 - popH
|
|
Window.stdFrame(Window.template(popX, popY, popW, popH))
|
|
for i, mv in ipairs(moves) do
|
|
local rowY = (popY * 8) + (i - 1) * 16 + 2
|
|
if i == PartyMenu._forgetCursor then
|
|
Window.cursorPx(popX * 8 + 1, rowY)
|
|
end
|
|
FrlgFont.draw(tostring(mv), popX * 8 + 9, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
elseif PartyMenu.mode == "item_action" then
|
|
Window.stdFrame(Window.template(1, 17, 18, 2))
|
|
FrlgFont.draw(RomText.plain("gText_DoWhatWithItem"), 1 * 8 + 2, 17 * 8 + 2, { colors = FrlgFont.COLOR.NORMAL })
|
|
|
|
local actCount = #PartyMenu.ITEM_ACTIONS
|
|
local popW = 7
|
|
local popH = actCount * 2
|
|
local popX = 22
|
|
local popY = 19 - popH
|
|
Window.stdFrame(Window.template(popX, popY, popW, popH))
|
|
for i, act in ipairs(PartyMenu.ITEM_ACTIONS) do
|
|
local rowY = (popY * 8) + (i - 1) * 16 + 2
|
|
if i == PartyMenu.itemActionCursor then
|
|
Window.cursorPx(popX * 8 + 1, rowY)
|
|
end
|
|
FrlgFont.draw(cursor_option_text(act), popX * 8 + 9, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
|
end
|
|
elseif PartyMenu.mode == "action" then
|
|
Window.stdFrame(Window.template(1, 17, 17, 2))
|
|
FrlgFont.draw(RomText.plain("gText_DoWhatWithPokemon"), 1 * 8 + 2, 17 * 8 + 2, { colors = FrlgFont.COLOR.NORMAL })
|
|
|
|
local actCount = #PartyMenu.ACTIONS
|
|
local popW = 10
|
|
local popH = actCount * 2
|
|
local popX = 19
|
|
local popY = 19 - popH
|
|
Window.stdFrame(Window.template(popX, popY, popW, popH))
|
|
for i, act in ipairs(PartyMenu.ACTIONS) do
|
|
local rowY = (popY * 8) + (i - 1) * 16 + 2
|
|
if i == PartyMenu.actionCursor then
|
|
Window.cursorPx(popX * 8 + 1, rowY)
|
|
end
|
|
local isFm = PartyMenu._fieldMoveNames and PartyMenu._fieldMoveNames[act]
|
|
local col = isFm and (FrlgFont.COLOR.BLUE or FrlgFont.COLOR.MALE_NPC) or FrlgFont.COLOR.NORMAL
|
|
FrlgFont.draw(cursor_option_text(act), popX * 8 + 9, rowY, { colors = col })
|
|
end
|
|
else
|
|
Window.stdFrame(Window.template(1, 17, 21, 2))
|
|
local promptKey = "gText_ChoosePokemon"
|
|
if PartyMenu.mode == "switch" then
|
|
promptKey = "gText_MoveToWhere"
|
|
elseif PartyMenu.mode == "use" then
|
|
if PartyMenu._item and ItemsData.isTm(PartyMenu._item) then
|
|
promptKey = "gText_TeachWhichPokemon"
|
|
else
|
|
promptKey = "gText_UseOnWhichPokemon"
|
|
end
|
|
elseif PartyMenu.mode == "give" then
|
|
promptKey = "gText_GiveToWhichPokemon"
|
|
elseif PartyMenu.mode == "move_tutor" then
|
|
-- pokefirered/src/data/party_menu.h:609
|
|
promptKey = "gText_TeachWhichPokemon"
|
|
end
|
|
local promptText = RomText.plain(promptKey)
|
|
FrlgFont.draw(promptText, 1 * 8 + 2, 17 * 8 + 2, { colors = FrlgFont.COLOR.NORMAL })
|
|
if PartyMenu.mode == "choose_multi" then
|
|
-- pokefirered/src/party_menu.c:1063 DrawCancelConfirmButtons
|
|
PartyChrome.drawConfirmButton(184, 128, PartyMenu.cursor == SLOT_CONFIRM)
|
|
PartyChrome.drawCancelButton(184, 144, PartyMenu.cursor == SLOT_CANCEL_MULTI)
|
|
else
|
|
PartyChrome.drawCancelButton(184, 136, PartyMenu.cursor == 7)
|
|
end
|
|
end
|
|
end
|
|
|
|
return PartyMenu
|