mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 07:41:21 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3de45b671c | |||
| 4395792226 | |||
| 6f67292b0e | |||
| 78e8a31ead | |||
| b6388013ec | |||
| ba7cd8fabf |
@@ -178,7 +178,8 @@ M.PALLET_TOWN = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function enterLab()
|
local function enterLab(oak)
|
||||||
|
if oak then oak.stepFrames = nil end
|
||||||
Commands.hide_object(ctx, "PALLET_TOWN", "PALLETTOWN_OAK")
|
Commands.hide_object(ctx, "PALLET_TOWN", "PALLETTOWN_OAK")
|
||||||
Commands.show_object(ctx, "OAKS_LAB", "OAKSLAB_OAK2")
|
Commands.show_object(ctx, "OAKS_LAB", "OAKSLAB_OAK2")
|
||||||
ow.doorWarp = true
|
ow.doorWarp = true
|
||||||
@@ -187,12 +188,17 @@ M.PALLET_TOWN = {
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function walkToLab(oak)
|
local function walkToLab(oak)
|
||||||
|
-- lockstep half runs Oak on the player's own frames per cell
|
||||||
|
-- engine/overworld/movement.asm:737 (DoScriptedNPCMovement)
|
||||||
local i = 0
|
local i = 0
|
||||||
|
if oak then
|
||||||
|
oak.stepFrames = ow.player.stepFramesCur or ow.player.stepFrames
|
||||||
|
end
|
||||||
local function tick()
|
local function tick()
|
||||||
i = i + 1
|
i = i + 1
|
||||||
local playerStep = escort.playerSteps[i]
|
local playerStep = escort.playerSteps[i]
|
||||||
if not playerStep then
|
if not playerStep then
|
||||||
enterLab()
|
enterLab(oak)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if oak and escort.oakSteps[i] then
|
if oak and escort.oakSteps[i] then
|
||||||
|
|||||||
@@ -446,7 +446,7 @@ local function pewterGymEscort(game, ow)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function afterWalk()
|
local function afterWalk()
|
||||||
if guy then guy.facing = "left" end
|
if guy then guy.stepFrames, guy.facing = nil, "left" end
|
||||||
Music.playMap(game.data, "PEWTER_CITY")
|
Music.playMap(game.data, "PEWTER_CITY")
|
||||||
push(game, t._PewterCityYoungsterGoTakeOnBrockText
|
push(game, t._PewterCityYoungsterGoTakeOnBrockText
|
||||||
or "Go take on BROCK\nat the GYM first!", walkHome)
|
or "Go take on BROCK\nat the GYM first!", walkHome)
|
||||||
@@ -469,6 +469,11 @@ local function pewterGymEscort(game, ow)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function beginWalk()
|
local function beginWalk()
|
||||||
|
-- the escort runs the youngster on the player's own frames per cell
|
||||||
|
-- engine/overworld/movement.asm:737 (DoScriptedNPCMovement)
|
||||||
|
if guy then
|
||||||
|
guy.stepFrames = ow.player.stepFramesCur or ow.player.stepFrames
|
||||||
|
end
|
||||||
Music.play(game.data, "Music_MuseumGuy")
|
Music.play(game.data, "Music_MuseumGuy")
|
||||||
if guy and head > 0 then
|
if guy and head > 0 then
|
||||||
local h = 0
|
local h = 0
|
||||||
|
|||||||
@@ -12,6 +12,20 @@
|
|||||||
"tintColor": "3b5ca8",
|
"tintColor": "3b5ca8",
|
||||||
"category": "games",
|
"category": "games",
|
||||||
"versions": [
|
"versions": [
|
||||||
|
{
|
||||||
|
"version": "0.1.85",
|
||||||
|
"date": "2026-08-14",
|
||||||
|
"size": 11306462,
|
||||||
|
"downloadURL": "https://github.com/bryanthaboi/gen1recomp/releases/download/v0.1.85/gen1recomp++-0.1.85-ios.ipa",
|
||||||
|
"localizedDescription": "Download the correct version for your computer below.\n\n## Contributors\n\n- @bryanthaboi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "0.1.84",
|
||||||
|
"date": "2026-08-14",
|
||||||
|
"size": 11306462,
|
||||||
|
"downloadURL": "https://github.com/bryanthaboi/gen1recomp/releases/download/v0.1.84/gen1recomp++-0.1.84-ios.ipa",
|
||||||
|
"localizedDescription": "Download the correct version for your computer below.\n\n## Issues closed\n\n- #919 Bills House game save moves strangely after reload\n- #982 Trading QOL aspect missing from OG.\n- #1003 Land Pokemon Encounters while Surfing in Cerulean Cave\n- #1012 Multiple issues with text speed, animations, and audio\n- #1022 Cannot interact with small trees\n- #1028 Trainers not resetting on route change.\n- #1033 Some issues with Link battles.\n- #1243 Can't sell TMs at Poké Marts\n\n## Contributors\n\n- @1Jamie\n- @AverageConsumer\n- @bryanthaboi\n- @TheRealSolidusSnake\n- Myles Resnick\n- ShaneMcGovernIE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.1.83",
|
"version": "0.1.83",
|
||||||
"date": "2026-08-13",
|
"date": "2026-08-13",
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ build_autotools mpg123 "$MPG123_VERSION" "$MPG123_TARBALL" libmpg123.so.0 \
|
|||||||
# The symbol that was missing when this was bullseye's copy. Assert it, so a
|
# The symbol that was missing when this was bullseye's copy. Assert it, so a
|
||||||
# version bump that quietly regresses below the host's expectations fails the
|
# version bump that quietly regresses below the host's expectations fails the
|
||||||
# build instead of silently killing audio again.
|
# build instead of silently killing audio again.
|
||||||
objdump -T "$PREFIX/lib/libmpg123.so.0" | grep -q 'mpg123_info2' \
|
mpg123_syms="$(objdump -T "$PREFIX/lib/libmpg123.so.0")"
|
||||||
|
grep -q 'mpg123_info2' <<<"$mpg123_syms" \
|
||||||
|| fail "bundled libmpg123 lacks mpg123_info2; the host's libsndfile will fail to relocate"
|
|| fail "bundled libmpg123 lacks mpg123_info2; the host's libsndfile will fail to relocate"
|
||||||
|
|
||||||
# ------------------------------------------------------------ compile SDL2
|
# ------------------------------------------------------------ compile SDL2
|
||||||
@@ -128,8 +129,9 @@ fi
|
|||||||
# the host having that exact stack -- which is the bug this replaced.
|
# the host having that exact stack -- which is the bug this replaced.
|
||||||
sdl_lib="$PREFIX/lib/libSDL2-2.0.so.0"
|
sdl_lib="$PREFIX/lib/libSDL2-2.0.so.0"
|
||||||
[ -f "$sdl_lib" ] || fail "SDL2 build produced no libSDL2-2.0.so.0"
|
[ -f "$sdl_lib" ] || fail "SDL2 build produced no libSDL2-2.0.so.0"
|
||||||
|
sdl_needed="$(objdump -p "$sdl_lib")"
|
||||||
for forbidden in libpulse libasound libX11 libwayland libdrm libgbm libsndio; do
|
for forbidden in libpulse libasound libX11 libwayland libdrm libgbm libsndio; do
|
||||||
if objdump -p "$sdl_lib" | grep -q "NEEDED.*$forbidden"; then
|
if grep -q "NEEDED.*$forbidden" <<<"$sdl_needed"; then
|
||||||
fail "SDL2 hard-links $forbidden; it must dlopen its backends (--enable-*-shared)"
|
fail "SDL2 hard-links $forbidden; it must dlopen its backends (--enable-*-shared)"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -164,8 +166,9 @@ fi
|
|||||||
|
|
||||||
openal_lib="$PREFIX/lib/libopenal.so.1"
|
openal_lib="$PREFIX/lib/libopenal.so.1"
|
||||||
[ -f "$openal_lib" ] || fail "openal-soft build produced no libopenal.so.1"
|
[ -f "$openal_lib" ] || fail "openal-soft build produced no libopenal.so.1"
|
||||||
|
openal_needed="$(objdump -p "$openal_lib")"
|
||||||
for forbidden in libsndio libasound libpulse libjack; do
|
for forbidden in libsndio libasound libpulse libjack; do
|
||||||
if objdump -p "$openal_lib" | grep -q "NEEDED.*$forbidden"; then
|
if grep -q "NEEDED.*$forbidden" <<<"$openal_needed"; then
|
||||||
fail "openal hard-links $forbidden; backends must stay behind dlopen"
|
fail "openal hard-links $forbidden; backends must stay behind dlopen"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -196,7 +199,8 @@ fi
|
|||||||
|
|
||||||
theora_lib="$PREFIX/lib/libtheoradec.so.1"
|
theora_lib="$PREFIX/lib/libtheoradec.so.1"
|
||||||
[ -f "$theora_lib" ] || fail "libtheora build produced no libtheoradec.so.1"
|
[ -f "$theora_lib" ] || fail "libtheora build produced no libtheoradec.so.1"
|
||||||
if objdump -p "$theora_lib" | grep -q "NEEDED.*libcairo"; then
|
theora_needed="$(objdump -p "$theora_lib")"
|
||||||
|
if grep -q "NEEDED.*libcairo" <<<"$theora_needed"; then
|
||||||
fail "libtheoradec still links libcairo (--disable-examples stopped working)"
|
fail "libtheoradec still links libcairo (--disable-examples stopped working)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -231,16 +235,18 @@ love_bin="$PREFIX/bin/love"
|
|||||||
love_lib="$PREFIX/lib/liblove-$LOVE_VERSION.so"
|
love_lib="$PREFIX/lib/liblove-$LOVE_VERSION.so"
|
||||||
[ -x "$love_bin" ] || fail "LÖVE build produced no bin/love"
|
[ -x "$love_bin" ] || fail "LÖVE build produced no bin/love"
|
||||||
[ -f "$love_lib" ] || fail "LÖVE build produced no lib/liblove-$LOVE_VERSION.so"
|
[ -f "$love_lib" ] || fail "LÖVE build produced no lib/liblove-$LOVE_VERSION.so"
|
||||||
file "$love_bin" | grep -q 'ARM aarch64' \
|
love_file="$(file "$love_bin")"
|
||||||
|
grep -q 'ARM aarch64' <<<"$love_file" \
|
||||||
|| fail "built love is not an aarch64 ELF (got: $(file -b "$love_bin"))"
|
|| fail "built love is not an aarch64 ELF (got: $(file -b "$love_bin"))"
|
||||||
|
|
||||||
# A configure run that lost an optional dependency still exits 0 and still
|
# A configure run that lost an optional dependency still exits 0 and still
|
||||||
# builds -- the loss only shows up as a missing love module at runtime, i.e.
|
# builds -- the loss only shows up as a missing love module at runtime, i.e.
|
||||||
# in a shipped artifact. Assert the decoder/font/video libs really linked.
|
# in a shipped artifact. Assert the decoder/font/video libs really linked.
|
||||||
|
love_needed="$(objdump -p "$love_lib")"
|
||||||
for soname in libSDL2-2.0.so.0 libopenal.so.1 libfreetype.so.6 \
|
for soname in libSDL2-2.0.so.0 libopenal.so.1 libfreetype.so.6 \
|
||||||
libmodplug.so.1 libmpg123.so.0 libvorbisfile.so.3 \
|
libmodplug.so.1 libmpg123.so.0 libvorbisfile.so.3 \
|
||||||
libtheoradec.so.1 libluajit-5.1.so.2; do
|
libtheoradec.so.1 libluajit-5.1.so.2; do
|
||||||
objdump -p "$love_lib" | grep -q "NEEDED.*$soname" \
|
grep -q "NEEDED.*$soname" <<<"$love_needed" \
|
||||||
|| fail "liblove is not linked against $soname (a -dev package went missing)"
|
|| fail "liblove is not linked against $soname (a -dev package went missing)"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
-- Driver: Oak's Pallet Town escort. Logs the player/Oak separation the
|
||||||
|
-- whole way down and shoots the walk mid-street, so the formation is
|
||||||
|
-- checkable by eye as well as by number (the escort holds one cell,
|
||||||
|
-- ~16px; a desynced Oak drifts off by a cell per two steps).
|
||||||
|
return function(game)
|
||||||
|
local U = dofile("tests/drivers/util.lua")
|
||||||
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
||||||
|
U.teleport(game, "PALLET_TOWN", 10, 3, "up")
|
||||||
|
local ow = game.overworld
|
||||||
|
local function oak()
|
||||||
|
for _, n in ipairs(ow.npcs or {}) do
|
||||||
|
if n.def and n.def.name == "PALLETTOWN_OAK" then return n end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
U.hold(game, "up", 40)
|
||||||
|
local worst, samples = 0, 0
|
||||||
|
for _ = 1, 1200 do
|
||||||
|
if game.stack:top() ~= ow then U.tap(game, "a") end
|
||||||
|
local o = oak()
|
||||||
|
if o and #ow.scriptMoves > 0 and ow.map.id == "PALLET_TOWN" then
|
||||||
|
local d = math.abs(o.px - ow.player.px) + math.abs(o.py - ow.player.py)
|
||||||
|
if samples > 0 or d <= 20 then
|
||||||
|
samples = samples + 1
|
||||||
|
if d > worst then worst = d end
|
||||||
|
if samples == 60 then U.shot(game, DIR .. "/escort_midwalk.png") end
|
||||||
|
if samples % 24 == 1 then
|
||||||
|
U.log(("t=%d player=(%d,%d) oak=(%d,%d) dist=%dpx")
|
||||||
|
:format(samples, ow.player.cellX, ow.player.cellY,
|
||||||
|
o.cellX, o.cellY, d))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ow.map.id == "OAKS_LAB" then break end
|
||||||
|
U.wait(2)
|
||||||
|
end
|
||||||
|
U.log(("ESCORT worst separation: %dpx over %d samples"):format(worst, samples))
|
||||||
|
U.log("map:", ow.map.id, "flag:",
|
||||||
|
tostring(game.save.flags.EVENT_FOLLOWED_OAK_INTO_LAB))
|
||||||
|
love.event.quit()
|
||||||
|
end
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
-- Parity test: escort lockstep cadence. An NPC walking the player to a
|
||||||
|
-- destination moves under DoScriptedNPCMovement (engine/overworld/
|
||||||
|
-- movement.asm:737), whose wScriptedNPCWalkCounter is 8 ticks of 2px --
|
||||||
|
-- the player's own frames per cell, not MoveSprite's doubled NPC walk.
|
||||||
|
-- Self-contained: run via `luajit tests/parity_escort_lockstep.lua`; also
|
||||||
|
-- dofile'd by tests/run_tests.lua's aggregator.
|
||||||
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||||
|
if not _G.love then _G.love = require("tests.love_stub") end
|
||||||
|
local Data = require("src.core.Data")
|
||||||
|
if not (Data.maps and Data.maps.PALLET_TOWN) then Data:load() end
|
||||||
|
local S = require("tests.harness").suite("parity escort lockstep")
|
||||||
|
local check, eq = S.check, S.eq
|
||||||
|
|
||||||
|
local SaveData = require("src.core.SaveData")
|
||||||
|
local Game = require("src.core.Game")
|
||||||
|
local StateStack = require("src.core.StateStack")
|
||||||
|
local OverworldState = require("src.world.OverworldController")
|
||||||
|
|
||||||
|
local prev = { data = Game.data, save = Game.save, stack = Game.stack,
|
||||||
|
input = Game.input, renderer = Game.renderer,
|
||||||
|
overworld = Game.overworld }
|
||||||
|
Game.data = Data
|
||||||
|
Game.save = SaveData.newGame(Data)
|
||||||
|
Game.save.player.name = "RED"
|
||||||
|
StateStack:init()
|
||||||
|
Game.stack = StateStack
|
||||||
|
Game.input = {
|
||||||
|
isDown = function() return false end,
|
||||||
|
wasPressed = function() return false end,
|
||||||
|
step = function() end, state = {}, pressQueue = {},
|
||||||
|
}
|
||||||
|
Game.renderer = {
|
||||||
|
beginWorldPass = function() end, endWorldPass = function() end,
|
||||||
|
beginUIPass = function() end, endUIPass = function() end,
|
||||||
|
worldViewSize = function() return 160, 144 end,
|
||||||
|
setSGBZones = function() end,
|
||||||
|
}
|
||||||
|
StateStack:push(OverworldState, "PALLET_TOWN", 10, 5, "down")
|
||||||
|
local ow = OverworldState
|
||||||
|
Game.overworld = ow
|
||||||
|
|
||||||
|
-- A PALLET_TOWN object parked one cell ahead of the player, then walked
|
||||||
|
-- in the paired-step pattern the escorts use: the NPC's step is queued
|
||||||
|
-- without a callback and the player's carries the chain.
|
||||||
|
local function runEscort(sync, steps)
|
||||||
|
local npc = ow.npcs[1]
|
||||||
|
local p = ow.player
|
||||||
|
p.cellX, p.cellY, p.px, p.py = 10, 5, 160, 80
|
||||||
|
p.moving, p.progress, p.targetX, p.targetY = false, 0, nil, nil
|
||||||
|
npc.cellX, npc.cellY, npc.px, npc.py = 10, 4, 160, 64
|
||||||
|
npc.moving, npc.progress, npc.targetX, npc.targetY = false, 0, nil, nil
|
||||||
|
ow.scriptMoves = {}
|
||||||
|
npc.stepFrames = sync and (p.stepFramesCur or p.stepFrames) or nil
|
||||||
|
local worstDrift, done, i = 0, false, 0
|
||||||
|
local function tick()
|
||||||
|
i = i + 1
|
||||||
|
if i > steps then done = true; return end
|
||||||
|
ow:scriptMove(npc, "down", 1)
|
||||||
|
ow:scriptMove(p, "down", 1, tick)
|
||||||
|
end
|
||||||
|
tick()
|
||||||
|
-- NPCs update before updateScriptMoves and the player after, so a
|
||||||
|
-- paired step leaves the NPC one frame (1px) behind for its whole cell
|
||||||
|
for _ = 1, 60 * steps do
|
||||||
|
ow:update(1)
|
||||||
|
local drift = math.abs((p.py - npc.py) - 16)
|
||||||
|
if drift > worstDrift then worstDrift = drift end
|
||||||
|
if done then break end
|
||||||
|
end
|
||||||
|
npc.stepFrames = nil
|
||||||
|
return { done = done, drift = worstDrift,
|
||||||
|
npcY = npc.cellY, playerY = p.cellY }
|
||||||
|
end
|
||||||
|
|
||||||
|
local synced = runEscort(true, 6)
|
||||||
|
check(synced.done, "synced escort finishes")
|
||||||
|
check(synced.drift <= 2,
|
||||||
|
("synced NPC holds formation (worst drift %dpx)"):format(synced.drift))
|
||||||
|
eq(synced.playerY - synced.npcY, 1, "synced NPC stays one cell ahead")
|
||||||
|
|
||||||
|
-- The default NPC walk is MoveSprite's, half the player's rate: without
|
||||||
|
-- the sync the escort desyncs, which is the bug this guards.
|
||||||
|
local plain = runEscort(false, 6)
|
||||||
|
check(plain.drift >= 16,
|
||||||
|
("unsynced NPC lags a cell or more (worst drift %dpx)"):format(plain.drift))
|
||||||
|
|
||||||
|
for k, v in pairs(prev) do Game[k] = v end
|
||||||
|
S.finish()
|
||||||
Reference in New Issue
Block a user