mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-18 03:35:56 +02:00
squashy squash (#127)
This commit is contained in:
@@ -148,6 +148,17 @@ function Font.advanceOf(code)
|
||||
return page and page.advance or GLYPH
|
||||
end
|
||||
|
||||
-- Pixel width of a string (glyph advances, not UTF-8 byte length).
|
||||
-- Multi-byte charmap entries like "¥" are one glyph; callers that
|
||||
-- right-align with `#text * 8` mis-place them.
|
||||
function Font.width(text)
|
||||
local w = 0
|
||||
for _, code in ipairs(Font.encode(text)) do
|
||||
w = w + Font.advanceOf(code)
|
||||
end
|
||||
return w
|
||||
end
|
||||
|
||||
-- Draw a plain single-line string at pixel (x, y). Returns the width
|
||||
-- drawn, which is #codes * 8 for every fixed-width page.
|
||||
function Font.draw(text, x, y)
|
||||
|
||||
@@ -62,6 +62,9 @@ end
|
||||
function Renderer:beginFrame(transparent)
|
||||
self.worldActive = false
|
||||
self.uprightActive = false
|
||||
-- warp-fade overlay from Transition (issue #121); cleared each frame so
|
||||
-- a popped transition cannot leave a sticky black veil
|
||||
self.worldFadeAlpha = nil
|
||||
-- last frame's trueColor rects and sprite redraws go before anything
|
||||
-- draws this one
|
||||
PaletteFX.clearTrueColor()
|
||||
@@ -414,6 +417,16 @@ function Renderer:endFrame(zones, worldZones)
|
||||
love.graphics.draw(self.uprightCanvas, wox - M * s, woy - M * s, 0, s, s)
|
||||
love.graphics.setScissor()
|
||||
end
|
||||
-- Screen-space warp fade (Transition) over the full world composite so
|
||||
-- survey zoom / tilt edges darken with the center, not only the 160x144
|
||||
-- UI letterbox. Drawn before the UI blit so menus above a fade still
|
||||
-- composite normally if one is ever stacked that way.
|
||||
local fade = self.worldFadeAlpha
|
||||
if fade and fade > 0 then
|
||||
love.graphics.setColor(0, 0, 0, fade)
|
||||
love.graphics.rectangle("fill", 0, 0, ww, wh)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
-- UI stays in the classic centered GB letterbox
|
||||
blit(self.canvas, S, zones, S, ox, oy, ox, oy, vpw, vph)
|
||||
|
||||
@@ -57,6 +57,16 @@ end
|
||||
function Transition:draw()
|
||||
local alpha = self.t / self.frames
|
||||
if self.phase == "in" then alpha = 1 - alpha end
|
||||
-- Survey zoom draws the overworld into a window-filling world canvas
|
||||
-- while the UI pass stays the classic 160x144 letterbox. A rect on the
|
||||
-- UI canvas only darkens that center box (issue #121); when the world
|
||||
-- pass ran this frame, hand the alpha to Renderer:endFrame so it paints
|
||||
-- a screen-space overlay over the full composite instead.
|
||||
local r = self.game and self.game.renderer
|
||||
if r and r.worldActive then
|
||||
r.worldFadeAlpha = alpha
|
||||
return
|
||||
end
|
||||
love.graphics.setColor(0, 0, 0, alpha)
|
||||
love.graphics.rectangle("fill", 0, 0, 160, 144)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
@@ -438,6 +438,12 @@ function Commands.play_sound(ctx, soundId)
|
||||
require("src.core.Sound").play(ctx.game.data, soundId)
|
||||
end
|
||||
|
||||
-- play_once <songId>: one-shot jingle (Music_PkmnHealed, etc.); the map
|
||||
-- theme resumes when it ends (Music.playOnce / pendingRestore)
|
||||
function Commands.play_once(ctx, songId)
|
||||
require("src.core.Music").playOnce(ctx.game.data, songId)
|
||||
end
|
||||
|
||||
-- play_cry <species>: PlayCry (home/audio.asm). The text_asm bodies that
|
||||
-- use it run text_far (a no-button-wait "...@" string) -> PlayCry ->
|
||||
-- WaitForSoundToFinish, all within the same text ID -- the cry only starts
|
||||
|
||||
+5
-1
@@ -145,6 +145,10 @@ end
|
||||
|
||||
function BoxMenu.new(game)
|
||||
Boxes.ensure(game.save)
|
||||
-- bills_pc.asm BillsPCMenu: TextBoxBorder at (0,0) with interior
|
||||
-- 12x10 → total 14x12. "CHANGE BOX" is 10 tiles and needs the
|
||||
-- full interior (cursor col + label); the old tw=12 right-side box
|
||||
-- drew the final glyph on the border.
|
||||
return Menu.new(game, {
|
||||
{ label = "WITHDRAW", onSelect = function() withdraw(game) end },
|
||||
{ label = "DEPOSIT", onSelect = function() deposit(game) end },
|
||||
@@ -153,7 +157,7 @@ function BoxMenu.new(game)
|
||||
{ label = "SEE YA!" },
|
||||
-- Bill's PC runs silent end to end (BIT_NO_MENU_BUTTON_SOUND,
|
||||
-- engine/menus/pokemon_pc.asm)
|
||||
}, { tx = 8, ty = 0, tw = 12, th = 12, noSound = true })
|
||||
}, { tx = 0, ty = 0, tw = 14, th = 12, noSound = true })
|
||||
end
|
||||
|
||||
return BoxMenu
|
||||
|
||||
+13
-3
@@ -117,7 +117,7 @@ function ListMenu:draw()
|
||||
love.graphics.setColor(0, 0, 0, 1)
|
||||
end
|
||||
if item.right then
|
||||
Font.draw(item.right, 160 - 8 - #item.right * 8, y)
|
||||
Font.draw(item.right, 160 - 8 - Font.width(item.right), y)
|
||||
end
|
||||
if i == self.index then
|
||||
-- hollowIndex: a chosen row keeps the hollow '▷' left behind by
|
||||
@@ -136,7 +136,7 @@ function ListMenu:draw()
|
||||
Font.drawBox(11, 0, 9, 3)
|
||||
love.graphics.setColor(0, 0, 0, 1)
|
||||
local money = ("¥%d"):format(self.money and self.money() or 0)
|
||||
Font.draw(money, 152 - #money * 8, 8)
|
||||
Font.draw(money, 152 - Font.width(money), 8)
|
||||
-- the clerk's line in the standard bottom text box; long prompts
|
||||
-- wrap and keep their last two lines, like the GB's scrolled box
|
||||
Font.drawBox(0, 12, 20, 6)
|
||||
@@ -153,7 +153,17 @@ function ListMenu:draw()
|
||||
end
|
||||
end
|
||||
elseif self.footer then
|
||||
Font.draw(self.footer, 8, 136)
|
||||
-- PC deposit/withdraw footers use "\n"; draw the last two lines so
|
||||
-- long item names are not clipped at the screen edge (#115).
|
||||
local flat = {}
|
||||
for _, page in ipairs(require("src.render.TextBox").paginate(self.footer)) do
|
||||
for _, line in ipairs(page) do flat[#flat + 1] = line end
|
||||
end
|
||||
local y = (#flat >= 2) and 120 or 136
|
||||
for i = math.max(1, #flat - 1), #flat do
|
||||
Font.draw(flat[i], 8, y)
|
||||
y = y + 16
|
||||
end
|
||||
end
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
@@ -182,12 +182,13 @@ function PartyMenu:update(dt)
|
||||
-- and music return first (PlayDefaultMusic +
|
||||
-- LoadWalkingPlayerSpriteGraphics), the menu closes with the
|
||||
-- GBPalWhiteOutWithDelay3 blink, and the simulated pad press
|
||||
-- steps the player forward onto land
|
||||
-- steps the player forward onto land (or across a connection
|
||||
-- strip when the shore is the next map's edge)
|
||||
self.game.stack:pop()
|
||||
ow.player.surfing = false
|
||||
require("src.core.Music").setSurfing(self.game.data, false)
|
||||
self.game.stack:push(Transition.whiteFlash(self.game, nil, function()
|
||||
ow:scriptMove(ow.player, ow.player.facing, 1)
|
||||
ow:stepForwardOrCrossEdge(ow.player.facing)
|
||||
end))
|
||||
return
|
||||
end
|
||||
|
||||
+7
-3
@@ -84,13 +84,17 @@ local function buy(game, stock)
|
||||
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) .. " x" .. game.save.inventory[id],
|
||||
right = ("¥%d"):format(def and math.floor(def.price / 2) or 0),
|
||||
label = def and def.name or id,
|
||||
right = "x" .. game.save.inventory[id],
|
||||
})
|
||||
end
|
||||
local greet = txt(game, "_PokemartBuyingGreetingText", "Take your time.")
|
||||
@@ -128,7 +132,7 @@ local function sell(game)
|
||||
Bag.remove(game.save, item.value, qty)
|
||||
local left = game.save.inventory[item.value]
|
||||
if left then
|
||||
item.label = def.name .. " x" .. left
|
||||
item.right = "x" .. left
|
||||
else
|
||||
list:removeCurrent()
|
||||
end
|
||||
|
||||
@@ -115,12 +115,16 @@ function SummaryMenu:draw()
|
||||
drawLineBox(19, 1, 6, 10)
|
||||
Font.draw("EXP POINTS", 72, 24)
|
||||
Font.draw(("%d"):format(mon.exp), 96, 32)
|
||||
Font.draw("LEVEL UP", 72, 44)
|
||||
-- StatusScreen2: "LEVEL UP" at (9,5); next-exp PrintNumber 7 cols
|
||||
-- at (7,6); space at (14,6); PrintLevel at (16,6). The old
|
||||
-- "%d to L%d" string at x=88 overflowed the DrawLineBox edge.
|
||||
Font.draw("LEVEL UP", 72, 40)
|
||||
local Growth = require("src.pokemon.Growth")
|
||||
local nextExp = mon.level < 100
|
||||
and (Growth.expForLevel(def.growthRate, mon.level + 1) - mon.exp) or 0
|
||||
Font.draw(("%d to L%d"):format(math.max(0, nextExp),
|
||||
math.min(100, mon.level + 1)), 88, 52)
|
||||
Font.draw(("%7d"):format(math.max(0, nextExp)), 56, 48)
|
||||
HudTiles.tile(0x6E, 128, 48) -- <LV>
|
||||
Font.draw(tostring(math.min(100, mon.level + 1)), 136, 48)
|
||||
Font.drawBox(0, 8, 20, 10)
|
||||
for i = 1, 4 do
|
||||
local mv = mon.moves[i]
|
||||
|
||||
+47
-26
@@ -38,6 +38,51 @@ local function hashSet(list, into)
|
||||
return into
|
||||
end
|
||||
|
||||
-- Collision tile (bottom-left 8x8) of a cell on an UNLOADED map def --
|
||||
-- the connected neighbor during an edge crossing. pokered's
|
||||
-- GetTileAndCoordsInFrontOfPlayer / collision checks read the neighbor
|
||||
-- strip's tile bytes the same way.
|
||||
function Map.defCellTile(def, tilesetDef, cx, cy)
|
||||
if not (def and tilesetDef and tilesetDef.blocks) then return nil end
|
||||
local tx, ty = cx * 2, cy * 2 + 1
|
||||
local bx, by = math.floor(tx / 4), math.floor(ty / 4)
|
||||
local id
|
||||
if bx < 0 or by < 0 or bx >= def.width or by >= def.height then
|
||||
id = def.borderBlock
|
||||
else
|
||||
id = def.blocks[by * def.width + bx + 1]
|
||||
end
|
||||
local block = tilesetDef.blocks[(id or 0) + 1]
|
||||
if not block then return nil end
|
||||
return block[(ty % 4) * 4 + (tx % 4) + 1]
|
||||
end
|
||||
|
||||
local function defWaterTileSet(def, tilesetDef)
|
||||
local water = {}
|
||||
hashSet(tilesetDef.waterTiles or WATER_TILES, water)
|
||||
local shore = tilesetDef.shoreTiles
|
||||
if shore == nil and not NO_SHORE_TILESETS[def.tileset] then shore = SHORE_TILES end
|
||||
hashSet(shore or {}, water)
|
||||
return water
|
||||
end
|
||||
|
||||
-- Water/shore on an unloaded map def (same tile ids as Map:isWaterCell).
|
||||
function Map.defIsWaterCell(def, tilesetDef, cx, cy)
|
||||
local tile = Map.defCellTile(def, tilesetDef, cx, cy)
|
||||
if tile == nil then return false end
|
||||
return defWaterTileSet(def, tilesetDef)[tile] or false
|
||||
end
|
||||
|
||||
function Map.defIsWalkableCell(def, tilesetDef, cx, cy)
|
||||
if not (tilesetDef and tilesetDef.walkable) then return false end
|
||||
local tile = Map.defCellTile(def, tilesetDef, cx, cy)
|
||||
if tile == nil then return false end
|
||||
for _, t in ipairs(tilesetDef.walkable) do
|
||||
if t == tile then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Passability of a cell of an UNLOADED map def -- the connected neighbor
|
||||
-- during an edge crossing. pokered's collision check reads the neighbor
|
||||
-- strip's tile bytes, so a step off the map edge onto a solid tile of
|
||||
@@ -52,32 +97,8 @@ function Map.defPassable(def, tilesetDef, cx, cy, surfing)
|
||||
if not (def and tilesetDef and tilesetDef.blocks and tilesetDef.walkable) then
|
||||
return false
|
||||
end
|
||||
local tx, ty = cx * 2, cy * 2 + 1
|
||||
local bx, by = math.floor(tx / 4), math.floor(ty / 4)
|
||||
local id
|
||||
if bx < 0 or by < 0 or bx >= def.width or by >= def.height then
|
||||
id = def.borderBlock
|
||||
else
|
||||
id = def.blocks[by * def.width + bx + 1]
|
||||
end
|
||||
local block = tilesetDef.blocks[(id or 0) + 1]
|
||||
if not block then return false end
|
||||
local tile = block[(ty % 4) * 4 + (tx % 4) + 1]
|
||||
for _, t in ipairs(tilesetDef.walkable) do
|
||||
if t == tile then return true end
|
||||
end
|
||||
if surfing then
|
||||
for _, t in ipairs(tilesetDef.waterTiles or WATER_TILES) do
|
||||
if t == tile then return true end
|
||||
end
|
||||
local shore = tilesetDef.shoreTiles
|
||||
if shore == nil and not NO_SHORE_TILESETS[def.tileset] then
|
||||
shore = SHORE_TILES
|
||||
end
|
||||
for _, t in ipairs(shore or {}) do
|
||||
if t == tile then return true end
|
||||
end
|
||||
end
|
||||
if Map.defIsWalkableCell(def, tilesetDef, cx, cy) then return true end
|
||||
if surfing and Map.defIsWaterCell(def, tilesetDef, cx, cy) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@@ -338,10 +338,13 @@ function OverworldState:setMap(mapId, x, y, facing, opts)
|
||||
or (fromMapId and "warp" or "boot"),
|
||||
})
|
||||
|
||||
-- map-enter hooks (hand-ported map scripts, e.g. Victory Road barriers)
|
||||
-- map-enter hooks (hand-ported map scripts, e.g. Victory Road barriers).
|
||||
-- fromMapId lets elevators seed a valid walk-out floor when the ROM
|
||||
-- car warps still point at a missing map (Silph's UNUSED_MAP_ED) and
|
||||
-- the player B-cancels the floor menu without .UpdateWarp.
|
||||
local hooks = mapScripts.get(mapId)
|
||||
if hooks and hooks.onEnter then
|
||||
hooks.onEnter(Game, self)
|
||||
hooks.onEnter(Game, self, fromMapId)
|
||||
end
|
||||
|
||||
self:rebuildNeighbors()
|
||||
@@ -1000,20 +1003,19 @@ function OverworldState:checkEdgeExit(dir)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Map connections: the connected map's strip offset is in blocks; arriving
|
||||
-- coordinates follow destX = curX - offset*2 (see docs/extraction-notes.md).
|
||||
-- The crossing scrolls continuously: the map data swaps while the player
|
||||
-- is placed one cell before the entry point (their old world position,
|
||||
-- which the neighbor strips render identically) and walks the seam step.
|
||||
function OverworldState:crossConnection(dir, conn)
|
||||
-- Landing cell on the connected map for a step off this map's edge in
|
||||
-- `dir` (same math as crossConnection). Returns destDef, tilesetDef, x, y
|
||||
-- or nil when there is no usable connection.
|
||||
function OverworldState:connectionLanding(dir)
|
||||
local conn = self.map:connection(COMPASS[dir])
|
||||
if not conn then return nil end
|
||||
local dest = Game.data.maps[conn.map]
|
||||
if not dest then
|
||||
Logger.warn("connection to unknown map %s", tostring(conn.map))
|
||||
return false
|
||||
end
|
||||
if not dest then return nil end
|
||||
local ts = Game.data.tilesets[dest.tileset]
|
||||
if not ts then return nil end
|
||||
local p = self.player
|
||||
local x, y = p.cellX, p.cellY
|
||||
local destW, destH = dest.width * 2, dest.height * 2
|
||||
local x, y
|
||||
if dir == "up" then
|
||||
x, y = p.cellX - conn.offset * 2, destH - 1
|
||||
elseif dir == "down" then
|
||||
@@ -1025,13 +1027,27 @@ function OverworldState:crossConnection(dir, conn)
|
||||
end
|
||||
x = math.max(0, math.min(destW - 1, x))
|
||||
y = math.max(0, math.min(destH - 1, y))
|
||||
return dest, ts, x, y, conn
|
||||
end
|
||||
|
||||
-- Map connections: the connected map's strip offset is in blocks; arriving
|
||||
-- coordinates follow destX = curX - offset*2 (see docs/extraction-notes.md).
|
||||
-- The crossing scrolls continuously: the map data swaps while the player
|
||||
-- is placed one cell before the entry point (their old world position,
|
||||
-- which the neighbor strips render identically) and walks the seam step.
|
||||
function OverworldState:crossConnection(dir, conn)
|
||||
local dest, ts, x, y = self:connectionLanding(dir)
|
||||
if not dest then
|
||||
Logger.warn("connection to unknown map %s", tostring(conn and conn.map))
|
||||
return false
|
||||
end
|
||||
local p = self.player
|
||||
-- pokered's collision check reads the NEIGHBOR strip's tile bytes, so
|
||||
-- stepping off the edge onto a solid tile of the connected map bumps
|
||||
-- exactly like an in-map wall. Without this read, Pallet's south
|
||||
-- shore (land at x2-3) walked straight onto ROUTE_21 (3,0) -- a
|
||||
-- collision tile -- stranding the player on a cell no walk can leave.
|
||||
if not Map.defPassable(dest, Game.data.tilesets[dest.tileset], x, y,
|
||||
p.surfing) then
|
||||
if not Map.defPassable(dest, ts, x, y, p.surfing) then
|
||||
return false
|
||||
end
|
||||
self:setMap(conn.map, x, y, p.facing, { seamless = true })
|
||||
@@ -1054,6 +1070,53 @@ function OverworldState:crossConnection(dir, conn)
|
||||
return true
|
||||
end
|
||||
|
||||
-- ItemUseSurfboard's simulated pad press: step onto the facing cell, or
|
||||
-- cross a map connection when that cell is off this map's edge (Cinnabar
|
||||
-- east coast -> Route 20 water, and the reverse dismount ashore).
|
||||
function OverworldState:stepForwardOrCrossEdge(dir)
|
||||
dir = dir or self.player.facing
|
||||
local fx, fy = Collision.target(self.player.cellX, self.player.cellY, dir)
|
||||
if not self.map:inBounds(fx, fy) then
|
||||
return self:checkEdgeExit(dir)
|
||||
end
|
||||
self:scriptMove(self.player, dir, 1)
|
||||
return true
|
||||
end
|
||||
|
||||
-- IsNextTileShoreOrWater across a connection strip: pokered loads the
|
||||
-- neighbor's tiles into the border, so wTileInFrontOfPlayer is the
|
||||
-- connected map's tile even when the facing cell is off this map.
|
||||
-- Shore/water classification still uses THIS map's tileset rules
|
||||
-- (SHIP_PORT's $32 dock exception), matching the asm.
|
||||
function OverworldState:facingIsShoreOrWater()
|
||||
if not self:tilesetHasWater() then return false end
|
||||
local fx, fy = self.player:facingCell()
|
||||
if self.map:inBounds(fx, fy) then
|
||||
return self.map:isWaterCell(fx, fy)
|
||||
end
|
||||
local dest, ts, x, y = self:connectionLanding(self.player.facing)
|
||||
if not dest then return false end
|
||||
local tile = Map.defCellTile(dest, ts, x, y)
|
||||
if tile == nil then return false end
|
||||
return self.map.waterTiles[tile] or false
|
||||
end
|
||||
|
||||
-- tryToStopSurfing land check, including a land landing across a map
|
||||
-- connection (surf off Cinnabar's east coast water back onto the coast).
|
||||
function OverworldState:facingIsLandDismount()
|
||||
local p = self.player
|
||||
local fx, fy = p:facingCell()
|
||||
if self.map:inBounds(fx, fy) then
|
||||
return self.map:isWalkableCell(fx, fy)
|
||||
and Collision.canMove(self.map, self.entities, p, p.facing)
|
||||
end
|
||||
local dest, ts, x, y = self:connectionLanding(p.facing)
|
||||
if not dest then return false end
|
||||
if not Map.defIsWalkableCell(dest, ts, x, y) then return false end
|
||||
-- IsSpriteInFrontOfPlayer2: no current-map sprite can sit past the edge
|
||||
return not Collision.occupied(self.entities, fx, fy, p)
|
||||
end
|
||||
|
||||
-- -------------------------------------------------------------------------
|
||||
-- interactions
|
||||
-- -------------------------------------------------------------------------
|
||||
@@ -1571,16 +1634,21 @@ function OverworldState:trashCanSwitch(canIndex)
|
||||
end
|
||||
|
||||
-- Bill's House PC (engine/events/hidden_events/bills_house_pc.asm
|
||||
-- BillsHousePC): once Bill-the-Pokémon has climbed into the machine
|
||||
-- (EVENT_BILL_SAID_USE_CELL_SEPARATOR), running the PC plays the cell
|
||||
-- separator's SFX sequence, sets EVENT_USED_CELL_SEPARATOR_ON_BILL and
|
||||
-- Bill steps back out of the machine human again
|
||||
-- (BillsHouseBillExitsMachineScript / CleanupScript set EVENT_MET_BILL).
|
||||
-- BillsHousePC). Check order matches pokered:
|
||||
-- 1) EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING -> Eevee collection list
|
||||
-- 2) EVENT_USED_CELL_SEPARATOR_ON_BILL -> teleporter monitor text
|
||||
-- 3) EVENT_BILL_SAID_USE_CELL_SEPARATOR -> cell-separator cutscene
|
||||
-- 4) else -> teleporter monitor text
|
||||
-- Leaving after the SS Ticket (Route25ToggleBillsScript) arms (1).
|
||||
function OverworldState:billsHousePC()
|
||||
local t = Game.data.text
|
||||
local flags = Game.save.flags
|
||||
if not (flags.EVENT_BILL_SAID_USE_CELL_SEPARATOR
|
||||
and not flags.EVENT_USED_CELL_SEPARATOR_ON_BILL) then
|
||||
if flags.EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING then
|
||||
self:billsHousePokemonList()
|
||||
return
|
||||
end
|
||||
if flags.EVENT_USED_CELL_SEPARATOR_ON_BILL
|
||||
or not flags.EVENT_BILL_SAID_USE_CELL_SEPARATOR then
|
||||
Game.stack:push(TextBox.new(Game, t._BillsHouseMonitorText
|
||||
or "TELEPORTER is\ndisplayed on the\nPC monitor."))
|
||||
return
|
||||
@@ -1604,9 +1672,40 @@ function OverworldState:billsHousePC()
|
||||
end))
|
||||
end
|
||||
|
||||
-- BillsHousePokemonList: EEVEE / FLAREON / JOLTEON / VAPOREON + CANCEL;
|
||||
-- picking one runs DisplayPokedex (DexEntryMenu) and returns to the list.
|
||||
function OverworldState:billsHousePokemonList()
|
||||
local t = Game.data.text
|
||||
local Menu = require("src.ui.Menu")
|
||||
local function openList()
|
||||
local species = { "EEVEE", "FLAREON", "JOLTEON", "VAPOREON" }
|
||||
local items = {}
|
||||
for _, id in ipairs(species) do
|
||||
local def = Game.data.pokemon[id]
|
||||
table.insert(items, {
|
||||
label = (def and def.name) or id,
|
||||
keepOpen = true,
|
||||
onSelect = function()
|
||||
local dex = Game.save.pokedex
|
||||
if dex then dex.seen[id] = true end
|
||||
Screens.push(Game, "DexEntryMenu", id)
|
||||
end,
|
||||
})
|
||||
end
|
||||
table.insert(items, { label = "CANCEL" })
|
||||
-- TextBoxBorder b=10,c=9 at (0,0) -> total tw=11, th=12
|
||||
Game.stack:push(Menu.new(Game, items,
|
||||
{ tx = 0, ty = 0, tw = 11, th = 12 }))
|
||||
end
|
||||
Game.stack:push(TextBox.new(Game, t._BillsHousePokemonListText1
|
||||
or "BILL's favorite\nPOKéMON list!", openList))
|
||||
end
|
||||
|
||||
-- BillsHouseBillExitsMachineScript: human Bill appears inside the machine
|
||||
-- at (1,2) and walks out to his spot at (4,4); the map music resumes and
|
||||
-- EVENT_MET_BILL / EVENT_MET_BILL_2 arm the SS-Ticket dialogue.
|
||||
-- EVENT_MET_BILL / EVENT_MET_BILL_2 arm the SS-Ticket dialogue. The Eevee
|
||||
-- PC list arms later, on the first Route 25 load after the ticket
|
||||
-- (EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING).
|
||||
function OverworldState:billsHouseBillExits()
|
||||
local Commands = require("src.script.Commands")
|
||||
local ctx = { game = Game, save = Game.save, overworld = self }
|
||||
@@ -1698,14 +1797,15 @@ function OverworldState:trySurf(fx, fy)
|
||||
Game.stack:push(TextBox.new(Game, text, function()
|
||||
-- start_sub_menus.asm .surf: UseItem returns (mount + text done),
|
||||
-- then GBPalWhiteOutWithDelay3 blinks before the simulated forward
|
||||
-- press steps onto the water
|
||||
-- press steps onto the water (or across a connection strip, like
|
||||
-- Cinnabar's east coast onto Route 20)
|
||||
local Transition = require("src.render.Transition")
|
||||
if Transition.whiteFlash then
|
||||
Game.stack:push(Transition.whiteFlash(Game, nil, function()
|
||||
self:scriptMove(p, p.facing, 1)
|
||||
self:stepForwardOrCrossEdge(p.facing)
|
||||
end))
|
||||
else
|
||||
self:scriptMove(p, p.facing, 1)
|
||||
self:stepForwardOrCrossEdge(p.facing)
|
||||
end
|
||||
end))
|
||||
end
|
||||
@@ -1805,20 +1905,20 @@ function OverworldState:useSurfFieldMove()
|
||||
-- until both EVENT_SEAFOAM4_BOULDER*_DOWN_HOLE events are set.
|
||||
if Game.save.forcedBike then return "forced_bike" end
|
||||
if self:surfBlockedHere() then return "current" end
|
||||
local fx, fy = p:facingCell()
|
||||
if p.surfing then
|
||||
-- ItemUseSurfboard .tryToStopSurfing: blocked by a sprite in front
|
||||
-- (IsSpriteInFrontOfPlayer2), a water tile-pair collision, or a
|
||||
-- facing tile that isn't in the tileset's land-passable list;
|
||||
-- otherwise the player walks forward off the water.
|
||||
if self.map:inBounds(fx, fy) and self.map:isWalkableCell(fx, fy)
|
||||
and Collision.canMove(self.map, self.entities, p, p.facing) then
|
||||
-- otherwise the player walks forward off the water. Facing a land
|
||||
-- cell across a map connection (Cinnabar east coast) counts too --
|
||||
-- pokered reads that landing from the connection strip.
|
||||
if self:facingIsLandDismount() then
|
||||
return "dismount"
|
||||
end
|
||||
return "no_place"
|
||||
end
|
||||
if not self.map:inBounds(fx, fy)
|
||||
or not self.map:isWaterCell(fx, fy) or not self:tilesetHasWater() then
|
||||
-- IsNextTileShoreOrWater, including connection-strip water (issue #125)
|
||||
if not self:facingIsShoreOrWater() then
|
||||
return "no_water"
|
||||
end
|
||||
return "ok"
|
||||
|
||||
Reference in New Issue
Block a user