Small changes that make the game easier to play, without changing what it asks of you.
#23 Hold B to dash in towns and dungeons, without needing Sprint Shoes.
- In 1.0
- Running faster in towns and dungeons needed the Sprint Shoes relic.
- Now
- Holding B on a town or dungeon map now makes the party run at the speed the Sprint Shoes used to give.
For ROM hackers 1.0 addresses
CheckPlayerMove (C0/4E16) sets the moving object's speed at $0875,y: 3 with Sprint Shoes (bit 5 of $11DF), otherwise 2, and always 2 when bit 1 of $1EB8 (events disable sprinting) is set. Insert before the Sprint Shoes test at C0/4E28 (4 bytes): test $07, the high byte of the mapped buttons held, whose bit 7 is B, and branch to the lda #$03 at C0/4E2F when it is set. The world map has its own speed and is not affected.
; before the Sprint Shoes test at C0/4E28
lda $07 ; held buttons, high byte
bmi Speed3 ; B held: branch to the lda #$03 at C0/4E2F
How to read these notes
Credit: previously fixed by Master ZED, my implementation
#25 Pressing Start now skips the title sequence and the opening march, just like A already did.
- In 1.0
- Pressing A skipped the title sequence and the opening march, but Start did nothing there.
- Now
- Start now skips them too, like A.
For ROM hackers 1.0 addresses
The title and opening code is part of the cutscene program, LZSS compressed at C2/686C and unpacked to $7E5000 by DecompCutsceneProg (C2/6828). TitleLoop ($7E50A8) and OpeningLoop ($7E5872) end the scene when bit 7 of $06 (A) is held. Insert after the bne at $7E50B6 and after the one at $7E5880 (6 bytes each) a test of bit 4 of $07 (Start) that branches to the same target. Recompress; if it grows, move it to free space and repoint.
; after the bne at $7E50B6 (title) and at $7E5880 (opening)
lda $07
bit #$10 ; Start
bne Skip ; the target of the bne just before
How to read these notes
Credit: my implementation
#33 Rage lists are now alphabetical and packed into two columns, in the menu and in battle.
- In 1.0
- The Skills menu listed Rages in the game's internal enemy order with a blank slot for every Rage Gau had not learned, and the battle Rage list left out the blanks but kept the unsorted order.
- Now
- Both lists are now alphabetical and hold only the Rages Gau has learned, packed from the top.
For ROM hackers 1.0 addresses
Both Rage lists walk a new 256-byte table of monster numbers sorted by English name instead of counting up. For each entry, test that monster's bit in the known-rage bits at $1D2C (byte number / 8, bit number AND 7). Battle: in InitSkills (C2/580C) replace the loop from C2/5847 to its rts; a known rage is written to WMDATA (the list at $257E) and counts in $3A9A. Menu: replace ExpandRageList (C3/53C1), which writes one slot per monster with $FF for an unknown one, by the same walk into $7E9D89, then pad the 256 slots with $FF. Both need free space; the table can sit in any bank. Leave monster 255 out unless #536 is also applied.
How to read these notes
Credit: previously fixed by Assassin, my implementation
#39 Cyan's Bushido level is now picked with the d-pad instead of a filling bar.
- In 1.0
- Choosing Bushido started a bar that filled by itself through Cyan's known techniques, and the player had to stop it at the right moment.
- Now
- The bar now stays still, and left and right, or up and down, move through the known techniques, with A performing the chosen one and B cancelling.
For ROM hackers 1.0 addresses
InitBushidoInput (C1/561B) clears the bar counter $7B82 with stz. Insert lda #$1F before it and make the stz a sta (2 bytes more): level 1, as the counter now holds level * 32 + 31. In the select state the block from C1/7D84 up to the inc at C1/7D9D raises $7B82 every 4 frames and wraps it at the count of known techniques in $36. Replace it with a jsl to a routine (about 60 bytes, any bank): level = $7B82 / 32; on newly pressed Down or Right ($09 bits 2 and 0) add 1, wrapping to 0 at $36; on Up or Left (bits 3 and 1) subtract 1, wrapping to $36 - 1; increment $94 (cursor sound) on either; store level * 32 + 31 in $7B82 and return the level in A. Gauge and confirm code stay.
How to read these notes
Credit: as in the 2014 mobile release, previously fixed by HatZen08 and LightPhoenix, my implementation
#40 The Colosseum now always names the prize you are playing for.
- In 1.0
- The Colosseum's wager screen showed '???' in place of the prize for some prizes, so the player had to wager an item without knowing what a win would bring.
- Now
- The wager screen now names every prize before you confirm.
For ROM hackers 1.0 addresses
LoadColosseumProp (C3/B22C) copies the fourth byte of the wagered item's ColosseumProp record, the hide-prize flag, to $0209, and DrawPrizeName prints ??? when it is set. Change the sta at C3/B249 to stz (opcode $9C, same size), so the flag is always clear and every prize is named. The table is untouched.
How to read these notes
Credit: previously fixed by HatZen08, my implementation
#236 Added a third Config page to turn random battles off and set exp, magic point and gil rates to 1x, 2x or 4x.
- In 1.0
- Random battles could only be stopped with a Moogle Charm or made rarer with a Charm Bangle, and experience, magic points and gil came at fixed rates, apart from the Exp. Egg and the Cat Hood.
- Now
- A third Config page, reached by moving down past page 2 or with L and R, turns random battles off and sets experience, magic point and gil rates. Settings save with the game, and scripted battles and the Veldt's still happen.
For ROM hackers Method
Config gets a third page of four rows, drawn over page 1's screen of the wrapping tilemap. The settings take one free byte of save RAM: bit 0 encounters off, bits 1-2 exp, 3-4 magic points, 5-6 gil, each 0 = 1x, 1 = 2x, 2 = 4x. Encounters: replace the charm reads at C0/C1FE (CheckBattleWorld) and C0/C397 (CheckBattleSub) with a jsr that also sets the Moogle Charm bit (bit 1) when bit 0 is set. Rewards, WinBattle: same-size jsr swaps at C2/5D9C (magic points, capped at 255), C2/5E08 (exp) and C2/5F95 (gil), the last two before their message; the morph gauge at C2/5E3C re-reads the unscaled points.
How to read these notes
Credit: as in the Pixel Remaster, previously fixed by madsiur, my implementation
#495 The Skills menu now describes each Rage: its second attack, the statuses it carries, and the elements it absorbs or is weak to.
- In 1.0
- The Rage list in the Skills menu gave only each enemy's name, with nothing about the attack or the statuses a Rage gives Gau.
- Now
- Each Rage now shows a description of its second attack, statuses and elements.
For ROM hackers Method
New text: a description for each of the 256 Rages, about 8 KB plus a 512-byte pointer table, in LoreDesc's format. Each is generated from the Rage table, the special attack and attack names, and the status and element bytes of the monster record that LoadRageProp copies onto Gau: line 1 the second attack, line 2 the statuses, absorbed and weak elements, cut to the box's width. Add LoadRageDesc, LoadLoreDesc (C3/56EB) with the new table's pointers, ending in jmp LoadBigText (C3/572A), which takes the monster under the cursor as the entry. In the Rage list state (C3/28BA) insert lda #$10 / trb $45 at the start, as the Lore state does, and jsr LoadRageDesc before C3/28C9.
How to read these notes
Credit: previously fixed by Lightning Hunter, my implementation
#627 Config's random battle setting gains Half, between On and Off: half the encounter rate, or a quarter with a Charm Bangle worn too.
- In 1.0
- Config's third page could turn random battles on or off, with nothing in between.
- Now
- A third setting, Half, halves the encounter rate; with a Charm Bangle worn as well, battles come at a quarter of the usual rate.
For ROM hackers Method
Builds on #236: its routine at the charm reads C0/C1FE (CheckBattleWorld) and C0/C397 (CheckBattleSub), and its save byte. Half is bit 7 of that byte. The routine now returns the rate group both callers index with: 0 normal, 1 half (Charm Bangle or Half), 2 none (Moogle Charm or Off), 3 a quarter (Charm Bangle and Half). Group 3 is the rows 1.0 gives a Moogle Charm worn with a Charm Bangle, all zero; a Moogle Charm now always returns 2, and those rows get quarter rates: WorldBattleRateTbl+$18 (C0/C2B7) $0030, $0018, $0060, $0000 and SubBattleRateTbl+$18 (C0/C2D7) $001C, $0010, $0058, $0080. Config page 3's first row offers On, Half and Off, the chosen word in white.
How to read these notes
Credit: my implementation
#628 The Skills menu leaves the Bushido, Blitz, Lore, Rage and Dance rows blank until Cyan, Sabin, Strago, Gau and Mog have joined.
- In 1.0
- The Skills menu listed Bushido, Blitz, Lore, Rage and Dance from the start of the game, naming the skills of party members still to come.
- Now
- Each of those rows stays blank until Cyan, Sabin, Strago, Gau or Mog has joined.
For ROM hackers 1.0 addresses
DrawSkillsWindow (C3/4C80) draws each row name as lda zSkillsTextColor (the row's colour) / sta zTextColor / ldy text / jsr DrawPosKana (C3/02F9). Replace the Bushido, Blitz, Lore, Rage and Dance rows, from C3/4CF2 to the jsr at C3/4D21 (50 bytes), with ldy text / lda #row (2 to 6) / jsr MyFix for each, 40 bytes, and nop the rest. MyFix (48 bytes of free space in bank C3 with its table) loads the row's colour and draws the name when it is white ($20, the chosen character has the command) or when the owner's bit of $1EDC, the characters who have joined, is set: Cyan, Sabin, Strago, Gau, Mog. Otherwise the row stays blank.
How to read these notes
Credit: my implementation
#633 In the World of Ruin, shops and an item's details screen show only the party members found again, not everyone who ever joined.
- In 1.0
- In the World of Ruin, shops and an item's details screen still showed every party member who had ever joined among those who could equip or use it, including those not yet found again.
- Now
- They now show only the party members found again, and Gau stays listed while a Leap keeps him away.
For ROM hackers 1.0 addresses
Eight lda $1EDC, the characters who have joined, each before an and CharEquipMaskTbl,x in 16-bit A: seven in the shop's party faces code (C3/BD4A, C3/BDAA, C3/BE3A, C3/BEC2, C3/BF1D, C3/BF7E, C3/C117) and one in the details' "can be used by" list, _c385d5 (C3/85F8). Replace each with jsr MyMask, same size. MyMask (116 bytes of free space in bank C3 with its table; X and Y kept) returns $1EDC outside the World of Ruin (switch $0A4, $1E94 bit 4). In it, it returns $1EDE, the roster now, plus each character whose World of Ruin recruitment switch is set (Terra $0BF, Locke $0D7, Cyan $0D2, Edgar $0C6, Sabin $28A, Setzer $0CA, Strago $0BA, Relm $240, Gau $0EB), and that with $1EDC. Gau's switch is new: replace the lda and tsb $1EDF at C2/1EA9, RECRUIT_GAU, with jsl MyGau / nop (code).
; C2/1EA9, AI command RECRUIT_GAU (5 bytes)
jsl MyGau
nop
; MyGau: 18 bytes of free space in any bank, 8-bit A
MyGau: lda #$08 ; the replaced two: Gau's roster bit
tsb $1edf
lda $1e94 ; switch $0A4: the World of Ruin
and #$10
beq :+
lda #$08
tsb $1e9d ; switch $0EB, free in 1.0
: rtl
How to read these notes
Credit: my implementation
#635 A party member's battle status indicators now take turns every two seconds, and two show at once while the battle is quiet, so Blind no longer hides Mute.
- In 1.0
- A party member with several statuses showed only one indicator, by a fixed order, so a member both Blind and Mute showed only the dark glasses.
- Now
- Every indicator takes a turn of about two seconds, and while the battle is quiet, with no attack or damage numbers showing, two show at once, so the glasses and the speech balloon appear together.
For ROM hackers Method
UpdateStatusSpriteIndex (C1/2F24), run per member, picks one sprite in a fixed order. MyPick (805 bytes of free space in any bank with a 512-byte table; X and Y kept) masks status 1 bits 0 to 2 (Blind, Zombie, Poison) and status 2 bits 3, 4, 5 and 7 (Mute, Berserk, Muddle, Sleep), Rage as Berserk. The turn is frame counter $0E over 128; the table gives it mod 64 mod the count: the nth set bit. Its sprite goes to StatusSpriteIndex, its body colour plus 1, or 0, to $CC + member (in Magitek mode, $64BA set, the first of Poison, Zombie, Berserk), and the next set bit with a sprite in another place to $D0 + member; $CB counts up to 16. $CB to $D3 are unused in 1.0. Insert stz $CB (2 bytes) at C1/9512, graphics command $04. MyCalm (76 bytes, the freed body, C1/2F29) calls DrawStatusSprites, then, if $CB is 16, no numeral shows, $71 below 115 and the $D0 byte 1 to 6, again with that sprite, restoring this turn's.
jsl MyPick ; C1/2F24, UpdateStatusSpriteIndex
rts
jsr MyCalm ; C1/29BF, was jsr DrawStatusSprites
lda $631a ; MyCalm's numeral test (17 bytes)
ora $631b
ora $631c
ora $631d
ora $7b3e
bne @done ; a numeral shows: no extra
lda $36 ; C1/2E45, UpdateCharPal: 31 bytes for its 38
and #STATUS1::POISON | STATUS1::ZOMBIE
bne @skin
lda $37
and #STATUS2::BERSERK
beq @2e6b ; none: the outlines
@skin: tya ; member * 32
lsr5
tax
lda $cc,x ; this turn's colour + 1
and #$03
beq @2eb4
dec
jsr UpdateStatusSkinColor
bra @2eb4
How to read these notes
Credit: my implementation