Hey, welcotar! Fantastic find!
I've gone to work on the NA version, trying to see what we can accomplish with it. You're probably well ahead of me, but what I've got is not especially promising so far. I've copied my notes below. In particular, notice the list of opcodes that are available to us (I've listed them as hex/mnemonic/corresponding character/description):
Player 2 name stored in $312.
8A 8B 8C 8D 8E 8F 90 91 92 93
94 95 96 97 98 99 9A 9B 9C 9D
9E 9F A0 A1 A2 A3 BE BF C0 FF
80 81 82 83 84 85 86 87 88 89
A4 A5 A6 A7 A8 A9 AA AB AC AD
AE AF B0 B1 B2 B3 B4 B5 B6 B7
B8 B9 BA BB BC BD C2 C3 C4 C5
80-8F
90-9F
A0-AF
B0-BF
C0
C2-C5
FF
0123456789ABCDEF
GHIJKLMNOPQRSTUV
WXYZabcdefghijkl
mnopqrstuvwxyz',
.*-|!?
HEX MNM CHR DSC
$90 BCC G (branch on carry clear)
$B0 BCS m (branch on carry set)
$c5 CMP ? (compare accumulator, zero page)
$c0 CPY . (comapre Y, immediate)
$c4 CPY ! (comapre Y, zero page)
$B8 CLV u (clear overflow)
$A9 LDA f (load accumulator, immediate)
$A5 LDA b (load accumulator, zero page)
$B5 LDA r (load accumulator, zero page, X)
$AD LDA j (load accumulator, absolute)
$BD LDA z (load accumulator, absolute, X)
$B9 LDA v (load accumulator, absolute, Y)
$A1 LDA X (load accumulator, indirect, X)
$B1 LDA n (load accumulator, indirect, Y)
$A2 LDX Y (load X, immediate)
$A6 LDX c (load X, zero page)
$B6 LDX s (load X, zero page, Y)
$AE LDX k (load X, absolute)
$BE LDX ' (load X, absolute, Y)
$A0 LDY W (load Y, immediate)
$A4 LDY a (load Y, zero page)
$B4 LDY q (load Y, zero page, X)
$AC LDY i (load Y, absolute)
$BC LDY y (load Y, absolute, X)
$8A TXA A (transfer X to A)
$88 DEY 8 (Decrement Y)
$85 STA 5 (store A, zero page)
$95 STA L (store A, zero page, X)
$8D STA D (store A, absolute)
$9D STA T (store A, absolute, X)
$99 STA P (store A, absolute, Y)
$81 STA 1 (store A, indirect, X)
$91 STA H (store A, indirect, Y)
$9A TXS Q (transfer X to stack pointer)
$BA TSX g (transfer stack pointer to X)
$86 STX 6 (store X, zero page)
$96 STX M (store X, zero page, Y)
$8E STX E (store X, absolute)
$84 STY 4 (store Y, zero page)
$94 STY K (store Y, zero page, X)
$8C STY C (store Y, absolute)
The good news is that we have access to $90 and $B0, branch on carry clear and branch on carry set, respectively. This means we should almost certainly be able to jump around somewhere within the game's code. The bad news is that the character set is mapped mostly to hex values $80 to $C5, which means we have to jump backward. I guess that's not bad news if the RAM there can be manipulated, but I have some information on that...
Character 2's name is stored in address $312. I verified directly by running a trace that, indeed, that is where the code is executed from. Using the BCS instruction, the only addresses we have access to are $294 (corresponding to character 2 name "m0**") up to $2D9 (corresponding to character 2 name "m?**"). (You may want to check my arithmetic for both of those.) Unfortunately, RAM in that range seems to be stuck with values like $F8 and $F0 most of the time. I fired up TheAxeMan's current publication to see if those values change at all and so far I've only seen them change appreciably when he enters the Circle of Sages, after which they go bonkers. If we can manipulate the values there, it will still obliterate half the game. As yet, however, I still don't understand what's being stored there.
So my questions/comments for welcotar are as follows:
1) I'd very much like to see the disassembled ROM! PM me or post it publicly.
2) If you happen to know, what is stored in address range $294-$2D9? I'll research it myself in the meantime, but so far I'm stumped.
3) What happens if you climb the stairs, say, another 70 times? Since 256 and 7 are coprime, maybe we have some leeway as to where the stack corruption takes us. I'm not very good with assembly language and it's hard for me to interpret what you've written, so I'm exploring that very slowly.
4) The glitch actually sets the program counter to $30A and it eventually increments to $312. What is in the $30A-$311 range? In my latest test, the first three instructions were garbage ($80) but the instruction at $310 happened to be $01 00 corresponding to ORA ($00, X). If as many as 8 more bytes can be directly manipulated, I'm confident we can get arbitrary code execution to work.
For anyone who would like to experiment with a modified version of welcotar's script that works on the NA version of Final Fantasy, you may find a copy here:
Download FF_ACE.luaLanguage: lua
-- 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", 28);
-- 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 8F 90 91 92 93
-- 94 95 96 97 98 99 9A 9B 9C 9D
-- 9E 9F A0 A1 A2 A3 BE BF C0 FF
-- 80 81 82 83 84 85 86 87 88 89
-- A4 A5 A6 A7 A8 A9 AA AB AC AD
-- AE AF B0 B1 B2 B3 B4 B5 B6 B7
-- B8 B9 BA BB BC BD C2 C3 C4 C5
-- some examples:
-- 4c ae 95: class change
-- 4c 84 b2: give airship
press("right", 2);
press("up", 2);
press("A", 1);
press("left", 2);
press("up", 2);
press("A", 1);
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;
Edit: Here's a quick update to report on what I thought was a promising lead. I discovered that a flag at $62CA dictates whether the black orb is present in the Temple of Fiends. I cheated it to 0 (corresponding to it being gone) and the tile is not traversible. I suppose you really do need the four orbs shining to step forward through the altar. Oh well.
Of the other skips we might reasonably execute, I'm wondering whether it would be better to get the early airship (it may depend where it shows up) or skip the air orb, which would also obsolete the Waterfall, Leffein, and parts of the Sea Shrine and the return to Melmond.