http://youtu.be/TRANAM0udLk
A stack corruption bug lets you run the second character's name as machine code. The bug exists in both the NA and J releases, but is easier to exploit in the J release due to the extra characters (including $4c for JMP). Things that I've tested: ice cave skip (early airship), early class change, early xcalbur, save file hacking (by jumping into the save routine with controlled offsets).
I have not yet managed to get a credit warp to work because the character set is just short of including the address you'd need. I have a complete, thoroughly commented NA disassembly if anyone is interested in exploring more. J is almost identical except for some minor message printing changes.
Details:
The game implements stairs in a funny way. Stair tiles can either be "push" tiles that call the dungeon subroutine with a new map and start location, pushing the current position onto the hardware subroutine stack; or "pop" tiles which return from the current invocation of the dungeon subroutine to go back.
Two "pop" tiles in the same connected region of a map both go to the same place. This is useful to make all tiles on the edges of towns return to the world map, but doesn't work well in buildings. If there were two separate staircases landing in the same hallway, you'd expect walking down the left one to take you to the left, even if you happened to walk up the right before. So most maps are simple trees, segmented into regions with at most one "pop".
But some maps have cycles of warps, like the column maze in ordeals 2 and the ice cave L2->L3 holes. Also, coneria castle uses a push warp from L1->L2 and from L2->L1---otherwise when you warped there from ToF after saving the princess, the stairs down from L2 would go back to ToF not L1. (In these cases you can't pop to go back to the world map, so there's a limited third type of warp tile which looks up and sets one of 16 world positions, jumps just before the main loop and resets the stack pointer. This is why you always end up on the right of coneria castle when leaving even if you entered from the left.)
7 bytes are pushed onto the stack per push warp. The 6502 can only address 256 bytes of stack. So if there's any path with more than 256/7 push warps, the stack pointer will wrap around and start overwriting old stack entries. This could result in corruption if the nested dungeon subroutine calls tried to return, so the game is careful to ensure they don't. Repeatable pop warps after a cycle of pushes are avoided by design. The warp spell also effectively returns from the dungeon subroutine, but only if the stack pointer is below ef. This should make it impossible to return to corrupted stack.
Alas for cleverness, the menu message printing subroutine at de36 needs some extra memory so it writes directly to the low part of the stack. To expand certain message placeholders, the subroutine invokes e03e to save its current position in its original message format string, calls itself with a different message, and then calls e04e to resume parsing the original string. e03e dumps the current message pointer and bank into 110, 111 and 112, on the stack. So doing a series of push warps and then entering the menu can cause corruption.
The easiest way to exploit this is to walk up and down the coneria stairs 70 times and then enter the menu. If all goes well, on exiting the menu your payload runs, then you get dumped into a glitch shop. You can safely exit la la land by walking out of the castle because of how the stack gets reset when you do that. Note entering the menu again is not a good idea even though my demo video does so to demonstrate the class change. It's also very easy to soft lock.
A simple lua script:
-- this is a sloppy little script to walk up and down the coneria castle stairs
-- a number of times and then enter the menu screen
emu.speedmode('maximum')
trips = 70
function walkToY(desty)
while true do
y = memory.readbyte(0x2a)
if y == desty then
break
elseif y == 0 or y > desty then
-- on the world map screen initially y is 0, since this y variable is
-- only used for inside maps. we need to go up initially to get into
-- the castle.
joypad.write(1, {up=true});
else
joypad.write(1, {down=true});
end;
emu.frameadvance();
end;
end;
function press(button, n)
mask = {}
for i=1,n do
emu.frameadvance()
mask[button] = false
joypad.write(1, mask)
emu.frameadvance()
mask[button] = true
joypad.write(1, mask)
end;
emu.frameadvance()
end;
-- hard boot
emu.poweron()
-- get through prophecy
press("A", 21);
-- enter whatever for character 1
press("A", 9);
-- use default thief for character 2
--press("right", 3);
press("A", 1);
-- enter a magical name
-- 8a 8b 8c 8d 8e 48 49 4a 4b 4c
-- 8f 90 91 92 93 4d 4e 4f 50 51
-- 94 95 96 97 98 52 53 54 55 56
-- 99 9a 9b 9c 9d 57 58 59 5a 5b
-- 9e 9f a0 a1 a2 70 71 72 73 74
-- a3 a4 a5 a6 a7 7d 7e 7f 7c b9
-- a8 a9 aa ab ac 80 81 82 83 84
-- b0 b1 b2 b3 b4 85 86 87 88 89
-- ad ae af b5 b6 c2 c4 c5 c3 ff
-- some examples:
-- 4c ae 95: class change
-- 4c 84 b2: give airship
press("right", 9);
press("A", 1);
press("down", 8);
press("right", 2);
press("A", 1);
press("up", 6);
press("A", 6);
-- select character 3
press("right", 8);
press("A", 12);
-- character 4
press("A", 15);
-- walk up to two tiles before stairs.
walkToY(13);
-- take trips flights of stairs
for i=1,trips do
-- the stairs are at y=11 on both the ground floor and the second floor.
-- first walk to one square away, then walk onto the stairs, then walk off.
walkToY(12);
walkToY(11);
walkToY(12);
end;
-- enter the menu screen
for i=1,15 do
emu.frameadvance();
end;
joypad.write(1, {start=true});
-- exit the menu screen and glitch shop
for i=1,25 do
emu.frameadvance();
end;
press("B", 100);
-- show menu for fun
for i=1,25 do
emu.frameadvance();
end;
joypad.write(1, {start=true});
while true do
emu.frameadvance();
end;