mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 04:31:09 +02:00
CLOSES #1396, CLOSES #1398, CLOSES #1400, CLOSES #1401, CLOSES #1406, CLOSES #1407, CLOSES #1411, CLOSES #1413, CLOSES #1415, CLOSES #1416, CLOSES #1417, CLOSES #1419, CLOSES #1421, CLOSES #1422, CLOSES #1423, CLOSES #1424, CLOSES #1425, CLOSES #1427, CLOSES #1428, CLOSES #1429, CLOSES #1431, CLOSES #1432, CLOSES #1433, CLOSES #1435, CLOSES #1437, CLOSES #1440, CLOSES #1441, CLOSES #1442, CLOSES #1443, CLOSES #1447, CLOSES #1449, CLOSES #1456, CLOSES #1464, CLOSES #1465, CLOSES #1468, CLOSES #1469, CLOSES #1470
This commit is contained in:
+9
-1
@@ -105,8 +105,16 @@ function NPC:update(map, entities)
|
||||
end
|
||||
end
|
||||
|
||||
-- UpdateNPCSprite branches to NotYetMoving while BIT_FONT_LOADED is set
|
||||
-- -- engine/overworld/movement.asm:139
|
||||
local function textBoxUp()
|
||||
local stack = require("src.core.Game").stack
|
||||
local top = stack and stack.top and stack:top()
|
||||
return top ~= nil and not top.isOverworld
|
||||
end
|
||||
|
||||
function NPC:walkPhase()
|
||||
if not self.moving then return 0 end
|
||||
if not self.moving or textBoxUp() then return 0 end
|
||||
-- engine/overworld/movement.asm:301
|
||||
local p = (self.animClock or 0) % 16
|
||||
return (p >= 4 and p < 12) and 1 or 0
|
||||
|
||||
@@ -20,6 +20,7 @@ local Player = require("src.world.Player")
|
||||
local Runtime = require("src.mods.Runtime")
|
||||
local Screens = require("src.ui.Screens")
|
||||
local ScriptRunner = require("src.script.ScriptRunner")
|
||||
local Theme = require("src.ui.Theme")
|
||||
local Tilt = require("src.render.Tilt")
|
||||
local TextBox = require("src.render.TextBox")
|
||||
local Transition = require("src.render.Transition")
|
||||
@@ -1109,6 +1110,13 @@ function OverworldState:update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
-- EnterMapAnim's .done tail re-enables the companion once the swoop or the
|
||||
-- spin-down has landed (player_animations.asm:40)
|
||||
if self.pikachuWarpHidden and not (self.flyAnim or self.flyArrive
|
||||
or self.teleportOut or self.transitioning or self.player.spinning) then
|
||||
self:showPikachuAfterWarp()
|
||||
end
|
||||
|
||||
-- Dig/Teleport/Escape-Rope departure spin (beginTeleportOut). The sprite
|
||||
-- spins UP out of the map before the fade (player_animations.asm
|
||||
-- _LeaveMapAnim -> PlayerSpinWhileMovingUp + SFX_TELEPORT_EXIT_1), the
|
||||
@@ -1190,7 +1198,9 @@ function OverworldState:update(dt)
|
||||
or self.engaging or self.emote or self.teleportOut
|
||||
or self.flyAnim or self.flyArrive
|
||||
end
|
||||
if not scripted and not self.transitioning then
|
||||
-- a scriptMove's onDone can push a text box on the frame it retires, and
|
||||
-- DisplayTextID owns the loop from there (home/text_script.asm:3)
|
||||
if not scripted and not self.transitioning and Game.stack:top() == self then
|
||||
self:handleInput()
|
||||
end
|
||||
|
||||
@@ -1716,6 +1726,28 @@ function OverworldState:syncSurfingPikachu()
|
||||
p.surfingPikachu = mon ~= nil and mon.species == "PIKACHU" or false
|
||||
end
|
||||
|
||||
-- _LeaveMapAnim drops the companion's sprite before the animation starts and
|
||||
-- EnterMapAnim only puts it back once landed -- home/pikachu.asm:1, :10
|
||||
function OverworldState:hidePikachuForWarp()
|
||||
self.pikachuWarpHidden = true
|
||||
require("src.world.PikachuFollower").setVisible(self, false)
|
||||
end
|
||||
|
||||
function OverworldState:showPikachuAfterWarp()
|
||||
self.pikachuWarpHidden = nil
|
||||
self.pikachuTrail = { x = self.player.cellX, y = self.player.cellY }
|
||||
local Follower = require("src.world.PikachuFollower")
|
||||
local npc = Follower.current(self)
|
||||
if npc then
|
||||
npc.cellX, npc.cellY = self.player.cellX, self.player.cellY
|
||||
npc.px, npc.py = npc.cellX * 16, npc.cellY * 16
|
||||
npc.targetX, npc.targetY = nil, nil
|
||||
npc.goalX, npc.goalY = nil, nil
|
||||
npc.moving = false
|
||||
end
|
||||
Follower.setVisible(self, true)
|
||||
end
|
||||
|
||||
-- The rejection loop shared by the Good and Super Rods
|
||||
-- (item_effects.asm ItemUseGoodRod .RandomLoop / ReadSuperRodData): an
|
||||
-- odd random byte is no bite; otherwise a 2-bit pick rerolls until it
|
||||
@@ -1822,6 +1854,7 @@ function OverworldState:flyTo(mapId)
|
||||
Game.save.forcedBike = nil -- HandleFlyWarpOrDungeonWarp res BIT_ALWAYS_ON_BIKE
|
||||
self.player.surfing = false
|
||||
self:syncSurfingPikachu()
|
||||
self:hidePikachuForWarp()
|
||||
-- _LeaveMapAnim .flyAnimation: the bird flaps in place (8 x Delay3),
|
||||
-- then SFX_FLY and the up-right path, a 40-frame beat off screen, and
|
||||
-- the exit over the top-left -- the warp fades only once the bird is
|
||||
@@ -1852,6 +1885,7 @@ function OverworldState:beginTeleportOut(onDone)
|
||||
require("src.core.Sound").play(Game.data, "Teleport_Exit1")
|
||||
self.player.surfing = false
|
||||
self:syncSurfingPikachu()
|
||||
self:hidePikachuForWarp()
|
||||
self.player.inputLocked = true
|
||||
-- rising spin: the mirror of the arrival spin-drop set in startWarpTo, so
|
||||
-- spinRise lifts the sprite (Player:pose) while spinFrames counts down
|
||||
@@ -3045,6 +3079,7 @@ function OverworldState:nurseHeal(onDone, npc)
|
||||
end
|
||||
-- Yellow's companion has its own beat threaded through this sequence
|
||||
local Follower = require("src.world.PikachuFollower")
|
||||
-- YesNoChoicePokeCenter draws HEAL/CANCEL, not YES/NO (home/yes_no.asm:21)
|
||||
Game.stack:push(TextBox.new(Game, hello, nil, { choice = function(yes)
|
||||
if not yes then
|
||||
Game.stack:push(TextBox.new(Game, bye, onDone))
|
||||
@@ -3093,7 +3128,7 @@ function OverworldState:nurseHeal(onDone, npc)
|
||||
end
|
||||
end))
|
||||
end)
|
||||
end }))
|
||||
end, choiceLabels = { "HEAL", "CANCEL" }, choiceBox = Theme.healCancelBox }))
|
||||
end
|
||||
|
||||
-- pokecenter.asm bows the nurse between the two PrintText calls (#995)
|
||||
@@ -4526,6 +4561,11 @@ function OverworldState:startWarpTo(mapId, x, y, facing, onDone, opts)
|
||||
-- down, so the player is never drawable mid-fade nor standing bare on the
|
||||
-- landing frame (#916)
|
||||
self.playerHidden = false
|
||||
-- setMap respawned a follower under the player; _LeaveMapAnim's Func_1510
|
||||
-- suppression runs until EnterMapAnim lands (home/pikachu.asm:1)
|
||||
if self.pikachuWarpHidden then
|
||||
require("src.world.PikachuFollower").setVisible(self, false)
|
||||
end
|
||||
-- The warp we land ON stays inert for the completed-step check until we
|
||||
-- physically step off it, so a warp whose destination cell is itself a
|
||||
-- warp cannot bounce us straight back (elevator cars, stacked stair/door
|
||||
|
||||
@@ -226,7 +226,16 @@ function Player:facingCell()
|
||||
return Collision.target(self.cellX, self.cellY, self.facing)
|
||||
end
|
||||
|
||||
-- UpdatePlayerSprite jumps to .notMoving while BIT_FONT_LOADED is set
|
||||
-- -- engine/overworld/movement.asm:57
|
||||
local function textBoxUp()
|
||||
local stack = require("src.core.Game").stack
|
||||
local top = stack and stack.top and stack:top()
|
||||
return top ~= nil and not top.isOverworld
|
||||
end
|
||||
|
||||
function Player:walkPhase()
|
||||
if textBoxUp() then return 0 end
|
||||
-- moving, the land-frame after a completed step, or an active wall-bonk
|
||||
-- (issue #230) animate; a standing sprite otherwise
|
||||
if not self.moving and not self.stepLanded
|
||||
|
||||
@@ -10,10 +10,10 @@ local PixelCanvas = require("src.render.PixelCanvas")
|
||||
|
||||
local MapPreview = {}
|
||||
|
||||
-- home/map.asm:1739-1748 LoadTilesetGFX
|
||||
local ROOF_TILESETS = {
|
||||
TILESET_JOHTO = true,
|
||||
TILESET_JOHTO_MODERN = true,
|
||||
TILESET_KANTO = true,
|
||||
}
|
||||
|
||||
local function applyRoofOverlay(atlasPath, roofPath, tilesPerRow)
|
||||
|
||||
@@ -117,6 +117,15 @@ local VAR = {
|
||||
SPECIALPHONECALL = 0x14,
|
||||
}
|
||||
|
||||
-- constants/ram_constants.asm:293 wPlayerState. PLAYER_SKATE (2) has no row:
|
||||
-- nothing writes it, and FieldMoves has no string for it either.
|
||||
local PLAYER_STATE_BY_ID = {
|
||||
[0] = FieldMoves.PLAYER_NORMAL,
|
||||
[1] = FieldMoves.PLAYER_BIKE,
|
||||
[4] = FieldMoves.PLAYER_SURF,
|
||||
[8] = FieldMoves.PLAYER_SURF_PIKA,
|
||||
}
|
||||
|
||||
local BATTLETYPE = {
|
||||
CANLOSE = 1,
|
||||
FORCESHINY = 7,
|
||||
@@ -5207,6 +5216,7 @@ function World:dropMapImages(mapId)
|
||||
if key:sub(1, #prefix) == prefix then store[key] = nil end
|
||||
end
|
||||
end
|
||||
if self.connectionMaps then self.connectionMaps[mapId] = nil end
|
||||
end
|
||||
|
||||
-- LoadMapAttributes' refill, for every map the session has edited. Neighbour
|
||||
@@ -7480,13 +7490,10 @@ function World:zoomScale()
|
||||
return Zoom.scale(self:fitScale())
|
||||
end
|
||||
|
||||
-- Outdoor Johto/Kanto town tilesets are the only ones that swap in roof
|
||||
-- tiles $0a-$12 (mapgroup_roofs.asm). Applying roofs to indoor tilesets
|
||||
-- in the same map group (lab, houses) corrupts their GFX.
|
||||
-- home/map.asm:1739 LoadTilesetGFX
|
||||
local ROOF_TILESETS = {
|
||||
TILESET_JOHTO = true,
|
||||
TILESET_JOHTO_MODERN = true,
|
||||
TILESET_KANTO = true,
|
||||
}
|
||||
|
||||
function World:atlasFor(mapDef)
|
||||
@@ -8724,6 +8731,44 @@ function World:spawnFacing()
|
||||
end
|
||||
end
|
||||
|
||||
-- A neighbour map, built once and kept for its collision alone: the seam
|
||||
-- queries below run on the per-step path.
|
||||
function World:connectionMap(mapId)
|
||||
self.connectionMaps = self.connectionMaps or {}
|
||||
local cached = self.connectionMaps[mapId]
|
||||
if cached ~= nil then return cached or nil end
|
||||
local def = self.maps[mapId]
|
||||
local tileset = def and self.tilesets[def.tileset]
|
||||
local map = (def and tileset) and Map.new(def, tileset) or false
|
||||
self.connectionMaps[mapId] = map
|
||||
return map or nil
|
||||
end
|
||||
|
||||
-- home/map.asm:1908 GetMovementPermissions
|
||||
function World:cellCollisionAcross(map, cx, cy)
|
||||
if map:inBounds(cx, cy) then return map:cellCollision(cx, cy) end
|
||||
local dir
|
||||
if cy < 0 then dir = "up"
|
||||
elseif cy >= map.heightCells then dir = "down"
|
||||
elseif cx < 0 then dir = "left"
|
||||
elseif cx >= map.widthCells then dir = "right"
|
||||
end
|
||||
local conn = dir and map:connection(DIR_CONN[dir])
|
||||
local dest = conn and conn.mapId and self.maps[conn.mapId]
|
||||
local destMap = dest and self:connectionMap(conn.mapId)
|
||||
if destMap then
|
||||
local x, y = Map.connectionLanding(dest, conn, dir, cx, cy)
|
||||
local vertical = dir == "up" or dir == "down"
|
||||
local want = (vertical and cx or cy) - (conn.offset or 0) * 2
|
||||
-- connectionLanding clamps into the destination; past the end of the strip
|
||||
-- the buffer still holds this map's own border block
|
||||
if x and (vertical and x or y) == want then
|
||||
return destMap:cellCollision(x, y)
|
||||
end
|
||||
end
|
||||
return map:cellCollision(cx, cy)
|
||||
end
|
||||
|
||||
-- Seamless edge cross: swap map data, park the player one cell before the
|
||||
-- landing (same world pixels the neighbor strip already showed), and keep
|
||||
-- the step running so the seam does not hitch.
|
||||
@@ -8736,7 +8781,13 @@ function World:tryConnection(dir)
|
||||
local x, y = Map.connectionLanding(
|
||||
dest, conn, dir, self.player.cellX, self.player.cellY)
|
||||
if not x then return false end
|
||||
local destMap = Map.new(dest, self.tilesets[dest.tileset])
|
||||
local destMap = self:connectionMap(conn.mapId)
|
||||
if not destMap then return false end
|
||||
-- home/map.asm:1946 GetMovementPermissions side-wall arm
|
||||
if dir == "down"
|
||||
and Permissions.neighborBlocksDown(dir, destMap:cellCollision(x, y)) then
|
||||
return false
|
||||
end
|
||||
-- A surfing crossing lands on water, which isWalkable refuses; the arm the
|
||||
-- step would have taken is what decides, the same as it does inside the map.
|
||||
local landable
|
||||
@@ -8869,7 +8920,8 @@ function World:movePlayer(dir)
|
||||
-- .CheckLandPerms and .CheckSurfPerms read the same wTilePermissions, so the
|
||||
-- veto applies to walking and surfing alike.
|
||||
local permitted = Permissions.stepPermitted(
|
||||
function(x, y) return map:cellCollision(x, y) end, p.cellX, p.cellY, dir)
|
||||
function(x, y) return self:cellCollisionAcross(map, x, y) end,
|
||||
p.cellX, p.cellY, dir)
|
||||
-- `.CheckNPC`'s IsNPCAtCoord answers for a BIG_OBJECT's whole 2x2 blob, and
|
||||
-- Player:tryMove's entity scan only ever compares the one cell an object
|
||||
-- stands on -- so the three cells the Vermilion Snorlax overhangs are vetoed
|
||||
|
||||
Reference in New Issue
Block a user