These notes exist because I know it’s possible to add custom logic to the FFV rom that enables custom icon assignments in the Equip menu. I didn’t figure this out, Serity did when she hacked the English translation of “FF5R”, and she graciously shared her commented code with me.
So I’m typing this out in order to understand what she did, and to build off it. She created some new subroutines that the game uses to show the Equipment options for each Job, and this is seen in her translation of ff5aki’s “FF5r” romhack. It’s needed because Red Mages can equip Bows, which is unexpected and unlike the original game. However Serity went several extra miles on this and added logic to represent 5 new icons not seen in the original FFV!
When I fully understand how she did this, I’d like to add the Boomerang icon, and maybe more…
;; ASM by Serity, cc 2022
;; double semicolon comments by Serity
; single semicolon comment by xJ4cks
;; 6FF99 - sort list (be careful not to touch 6FF98)
;; code reads from 6FF98 tho @ 2E021
;; 2E02B = icon count
; new in this hack for FF5R
C6 <shuriken> ; only used in Item menu
E7 <knife>
E3 <sword>
B6 knightsword
B7 ninjasword
E8 <spear>
E9 <axe>
BF <hammer>
EA <katana>
EB <rod>
EC <staff>
ED <bow>
EE <harp>
EF <whip>
F0 <bell>
BE <misc> ; XXX fully unused
F1 <shield> ; unused in Job & Equip menus
B5 heavyhelm ; unused in Job & Equip menus
F2 <helmet> ; unused in Job & Equip menus
B4 mage hat ; unused in Job & Equip menus
C1 <ribbon> ; unused in Job & Equip menus
F3 <armor> ; unused in Job & Equip menus
B3 medarmor ; unused in Job & Equip menus
C3 <suit> ; unused in Job & Equip menus
BD <shoe> ; unused in Job & Equip menus
CC <glove> ; unused in Job & Equip menus
CA <claw> ; only used in Equip menu
F4 <ring> ; unused in Job & Equip menus
BC <key> ; XXX fully unused
CF : ; only used by Monk? a blank icon
; 29 icon assignment options
[0xB3] = [[<medarmor>]],
[0xB4] = [[<hat>]],
[0xB5] = [[<heavyhelm>]],
[0xB6] = [[<knightsword>]],
[0xB7] = [[<ninjasword>]],
;; C2d7f2 - calls the 'display top row' code for job eq screen/eq menu
;; 2ca2c - calls it for elsewhere ; (status menu)
;; 0x7E01D8 - contains the class ID we're looking into ; class = Job
;; 20 = paladin, 21 = freelancer
; $02D7F6, code to convert equippables to icons
02/D7F6: A9 0A 00 LDA #$000A ; bottom row of status screen
02/D7F9: 85 85 STA $85 ;; JML MORE SHIT
; ^ 5C 1E ^ actually seen at this location in rom
02/D7FB: A2 50 00 LDX #$0050 ;; ea
; ^ A5 EF EA ^ actually seen at this location in rom
02/D7FE: 20 0D D8 JSR $D80D ;; JML BACK
02/D801: 60 RTS
02/D802: A9 10 00 LDA #$0010 ;; top row of status screen, eq, Job change screen
02/D805: 85 85 STA $85 ;; JML SOME SHIT
; ^ 5C 00 ^ actually seen at this location in rom
02/D807: A6 8E LDX $8E
; ^ A5 EF ^ actually seen at this location in rom
02/D809: 20 0D D8 JSR $D80D ;; JML BACK
02/D80C: 60 RTS
; main loop
02/D80D: A5 F9 LDA $F9 ; Loads equipment flags
02/D80F: 3F AD F7 C0 AND $C0F7AD,x ; AND w Job compatibility table
; ^ 3F 00 A6 EF ^ actually seen at this location in rom, what gives?
02/D813: 85 FD STA $FD ; Stores result
02/D815: A5 FB LDA $FB ; Loads more flags
02/D817: 3F AF F7 C0 AND $C0F7AF,x ; AND w extra compatibility
; ^ 3F 02 A6 EF ^ actually seen at this location in rom, what gives?
02/D81B: 05 FD ORA $FD ; Combine these results
02/D81D: F0 0E BEQ $D82D ; If zero, skip this slot/icon
02/D81F: BF B1 F7 C0 LDA $C0F7B1,x ; Loads icon tile value
; ^ BF 04 A6 EF ^ actually seen at this location in rom, what gives?
02/D823: 29 FF 00 AND #$00FF ; Masks to low byte (8-bit)
02/D826: F0 05 BEQ $D82D ; If no icon, skip
02/D828: 99 00 00 STA $0000,y ; * writes icon to vram *
02/D82B: C8 INY ; increment Y
02/D82C: C8 INY ; increment Y, now at next icon's ram index
02/D82D: E8 INX ; offset skipped to
02/D82E: E8 INX
02/D82F: E8 INX
02/D830: E8 INX
02/D831: E8 INX
02/D832: C6 85 DEC $85
02/D834: D0 D7 BNE $D80D
02/D836: 60 RTS
;; F7AD start -> F7EE start of second one (0x41 diff)
; ^ seems to mean the 2 Job compatibility tables
; @ $2FA500
; status menu
2F/A500: 85 85 STA $85
2F/A502: AD D8 01 LDA $01D8 ; loads current Job ID ($01D8 in wram)
2F/A505: 29 FF 00 AND #$00FF ; masks down to 8-bit
2F/A508: C9 14 00 CMP #$0014 ; compares to $14 (aka 20)
2F/A50B: B0 06 BCS 06 ; branches if >= 20 (paladin, freelancer)
2F/A50D: A6 8E LDX $8E
2F/A50F: 5C 09 D8 C2 JML $C2D809 ; not sure what happens at this offset
2F/A513: A9 0D 00 LDA #$000D
2F/A516: 85 85 STA $85
2F/A518: A6 8E LDX $8E
2F/A51A: 5C 09 D8 C2 JML $C2D809 ; not sure what happens at this offset
2F/A51E: 85 85 STA $85
2F/A520: AD D8 01 LDA $01D8
2F/A523: 29 FF 00 AND #$00FF ; masks down to 8-bit
2F/A526: C9 14 00 CMP #$0014 ; paladin or freelancer
2F/A529: B0 07 BCS 07 ; branches if >= 21 (if Job number is wrong?)
2F/A52B: A2 50 00 LDX #$0050 ; start at armor
2F/A52E: 5C FE D7 C2 JML $C2D7FE ; not sure what happens at this offset
2F/A532: A2 41 00 LDX #$0041 ; start at knightsword
2F/A535: A9 0D 00 LDA #$000D
2F/A538: 85 85 STA $85
2F/A53A: 5C FE D7 C2 JML $C2D7FE ; not sure what happens at this offset
;; -- 2FA600 -- icon data for 'can i equip'
01 00 00 00 ; E7 / knife = knife
04 00 00 00 ; E3 / sword = sword
10 00 00 00 ; E8 / spear = spear
20 00 00 00 ; E9 / axe = axe
80 00 00 00 ; EA / katana = katana
00 01 00 00 ; EB / rod = rod
00 06 00 00 ; EC / flail + staff = staff
00 08 00 00 ; ED / bow = bow
00 10 00 00 ; EE / harp = harp
00 20 00 00 ; EF / whip = whip
00 40 00 00 ; F0 / bell = bell
00 80 00 00 ; 00 / none = none
00 00 01 00 ; F1 / shield = shield
08 00 00 00 ; B6 > knightsword = knightsword < NEW ASSIGNMENT
02 00 00 00 ; B7 > ninjasword = ninjasword < NEW ASSIGNMENT
40 00 00 00 ; BF / hammer = hammer
00 00 02 00 ; B5 > heavy helmet < NEW ASSIGNMENT
00 00 04 00 ; F2 / light helmet
00 00 00 10 ; B4 > mage hat = hat < NEW ASSIGNMENT
00 00 08 00 ; C1 / dancer helm = ribbon
00 00 10 00 ; F3 / heavy armor = armor
00 00 20 00 ; B3 > medium armor = medarmor < NEW ASSIGNMENT
00 00 40 00 ; C3 / mage robe = robe
00 00 80 00 ; 00 / common = none
00 00 00 03 ; F4 / ring/glove = ring
00 00 00 04 ; 00 / thief glove = none
; the above bytes in sequence, found at $2FA600
01 00 00 00 E7 04 00 00 00 E3 10 00 00 00 E8 20
00 00 00 E9 80 00 00 00 EA 00 01 00 00 EB 00 06
00 00 EC 00 08 00 00 ED 00 10 00 00 EE 00 20 00
00 EF 00 40 00 00 F0 00 80 00 00 00 00 00 01 00
F1 08 00 00 00 B6 02 00 00 00 B7 40 00 00 00 BF
00 00 02 00 B5 00 00 04 00 F2 00 00 00 10 B4 00
00 08 00 C1 00 00 10 00 F3 00 00 20 00 B3 00 00
40 00 C3 00 00 80 00 00 00 00 00 03 F4 00 00 00
04 00
; 0x82 bytes (130)
; (green for weapons (11), orange for weapons listed w armor (3),
; red for armor (15): armor starts at $2FA636)
; I wonder if merely rearranging the table data would allow me to place
; the 3 weapons that show up with the armor back with the other weapons??
; The bitmask data is independent of the order these are listed in...
;; the bitmask encoding for FF5R icons, shown above
80 Katana Common
40 Hammer Bell Mage robe
20 Axe Whip Light a.
10 Spear Harp Heavy a. Mage hat
08 Knight s. Bow Dancer g. Chemist g.
04 Sword Flail Light h. Thief g.
02 Ninja s. Staff Heavy h. Ring
01 Knife Rod Shield Glove
Serity’s subroutines use a new array of icon assignments, @ $2FA600. The “old” setup above shows how the original game code decides which icon to show, based on the 4 bytes used per Job to calculate the icons.
The new assignments offer 5 extra icons:
<aside> ⭐
Adding 2 more hats and 1 more armor icon to the game aligns it with more modern FF titles, particularly “FF Dimensions” which is considered an unofficial sequel to FFV.
</aside>
Giving the Knight Swords their own icon is appealing as they are more restricted than Swords, and the same goes for Ninja Swords versus having them indistinguishable from Knives.
Hammers have their own assignment, yet it seems moot with the current FF5R Jobs, as the only one than can use Axes can always use Hammers. 🤷♂️ It’s great to have the icon given its own bitmask value, for future custom options though.

The ASM notes say that Rings and Gloves are both given the Ring icon. This seems inaccurate to the current FF5R tho, as seen here:
