The SwdTech charging mechanic in FF3us is often criticized for its slow charge time and the inability for other characters to receive commands while charging. This patch modifies the mechanic by allowing the player to switch characters mid-charge.
While the SwdTech gauge is charging for a character, the player may now press the X or Y button to switch between characters. The gauge position is held in the background while other characters receive commands. Once input returns to the charging character, the SwdTech gauge window automatically reopens. The gauge will resume from the next tier number past its previous position.
The feature is disabled if there are no other characters ready for input. A character's SwdTech gauge resets if the player cancels the gauge window or the character becomes incapacitated.
Archive includes an *.ips patch for both headered and non-headered ROMs.
Title: SwdTech Suspend
Author: SilentEnigma
Version: 1.0
Release Date: 2023-04-23
Applies to: Final Fantasy III (v1.0) (U)
Archive Contents
-------------------------------
readme.txt = this file
SwdTechSuspend_H.ips = patch for headered ROMs
SwdTechSuspend_H_Anti.ips = anti-patch for headered ROMs
SwdTechSuspend_NH.ips = patch for unheadered ROMs
SwdTechSuspend_NH_Anti.ips = anti-patch for unheadered ROMs
ROM Addresses
-------------------------------
C1/0253 - C1/0256, C1/561B - C1/561D, C1/5A45 - C1/5A49, C1/7D41 - C1/7D44,
C1/7D56 - C1/7D5D, C2/258D - C2/258F
Free Space Used
-------------------------------
C2/A6A8 - C2/A735, C2/A784 - C2/A7B5 (192 bytes)
Additional RAM used
-------------------------------
$7EECFC - $7EECFF (4 bytes)
TABLE OF CONTENTS
-------------------------------
0. Description
1. Relevant Offsets & Disassembly
2. Credits
3. Revision History
4. Legal
________________________________________________________________________________
0. DESCRIPTION
________________________________________________________________________________
This patch modifies the SwdTech charging mechanic in FF3us (FF6) for SNES.
SwdTech is often criticized for its slow charge time and the inability for other
characters to receive commands while charging. Modern rereleases of FF6 address
this by allowing the gauge to charge in the background.
This patch is intended to improve the mechanic in the SNES version by adding
character switching support to the SwdTech gauge window.
While the SwdTech gauge is charging for a character, the player may now press
the X or Y button to switch between characters. The gauge position is held in
the background while other characters receive commands. Once input returns to
the charging character, the SwdTech gauge window automatically reopens. The
gauge will resume from the next tier number past its previous position.
This allows the player to give other characters commands without losing progress
on any charging SwdTech gauge(s).
The feature is disabled if there are no other characters ready for input.
A character's SwdTech gauge resets if the player cancels the gauge window or
the character becomes incapacitated.
This patch uses 4 additional bytes of RAM to hold the value of each character's
SwdTech gauge progress.
________________________________________________________________________________
1. RELEVANT OFFSETS & DISASSEMBLY
________________________________________________________________________________
Incapacitated character check
-------------------------------
Original:
C1/0253: 9D 01 40 STA $4001,X ; battle menu order for ally at index x
C1/0256: 6B RTL
Modified:
C1/0253: 5C A8 A6 C2 JML $C2A6A8 ; new subroutine C2/A6A8
New Subroutine C2/A6A8:
C2/A6A8: 9D 01 40 STA $4001,X ; original C1/0253
C2/A6AB: 9E FC EC STZ $ECFC,X ; UNUSED RAM for ally's held SwdTech timer
C2/A6AE: 6B RTL
SwdTech command
-------------------------------
Original:
C1/561B: 9C 82 7B STZ $7B82 ; (from C1/5529, X = 35) reset SwdTech gauge
Modified:
C1/561B: EA NOP ; typical reset moved to C2/A72A
C1/561C: EA NOP
C1/561D: EA NOP
Top menu - button check
-------------------------------
Original:
C1/5A44: D0 03 BNE $5A49
C1/5A46: 4C 4A 5A JMP $5A4A
C1/5A49: 60 RTS
Modified:
C1/5A44: D0 FA BNE $5A40 ; to RTS at C1/5A40
C1/5A46: 5C 09 A7 C2 JML $C2A709 ; new subroutine C2/A709
New Subroutine C2/A709:
; X holds ally ID (0 - 3)
C2/A709: AD C3 7B LDA $7BC3 ; pending menu state
C2/A70C: C9 05 CMP #$05 ; top menu?
C2/A70E: D0 22 BNE $A732 ; Branch if not
C2/A710: AD CB 7B LDA $7BCB ; should be closing menu?
C2/A713: D0 1D BEQ $A732 ; If so, branch
C2/A715: AE CA 62 LDX $62CA ; current character
C2/A718: BD FC EC LDA $ECFC,X ; UNUSED RAM held SwdTech gauge value
C2/A71B: F0 12 BEQ $A72F ; branch if zero
C2/A71D: 29 E0 AND #$E0 ; snap counter to start of current number
C2/A71F: 18 CLC
C2/A720: 69 20 ADC #$20 ; gauge bonus
C2/A722: 8D 82 7B STA $7B82 ; SwdTech counter
C2/A725: 8A TXA ; current character
C2/A726: 85 22 STA $22 ; multiplier function input
C2/A728: A9 0C LDA #$0C ; cmd info size per ally (4 cmds x 3 bytes)
C2/A72A: 85 24 STA $24 ; multiplier function input
C2/A72C: 4C 84 A7 JMP $A784 ; new subroutine C2/A784
C2/A72F: 9C 82 7B STZ $7B82 ; reset SwdTech gauge from original C1/561B
C2/A732: 5C 4A 5A C1 JML $C15A4A ; replaces original C1/5A46
New Subroutine C2/A784:
C2/A784: DA PHX
C2/A785: 22 D5 18 C1 JSL $C118D5 ; multiplier function
C2/A789: A6 26 LDX $26 ; product
C2/A78B: A4 00 LDY $00 ; loop init
C2/A78D: BD 2E 20 LDA $2E20,X ; command ID for this ally & command
C2/A790: C9 07 CMP #$07 ; SwdTech?
C2/A792: F0 0C BEQ $A7A0 ; if so, break
C2/A794: E8 INX ; 3 info bytes per command
C2/A795: E8 INX
C2/A796: E8 INX
C2/A797: C8 INY
c2/A798: C0 04 00 CPY #$0004 ; 4 commands
C2/A79B: D0 F0 BNE $A78D ; loop management
C2/A79D: 4C 2F A7 JMP $A72F ; something went wrong - abort
C2/A7A0: 98 TYA ; SwdTech command position for current ally
C2/A7A1: EE 41 2F INC $2F41 ; flag - Command has been selected
C2/A7A4: FA PLX
C2/A7A5: 9D 0F 89 STA $890F,X ; cursor position for this character
C2/A7A8: 5C C8 7C C1 JML $C17CC8 ; C1/7CC9 - top menu cmd has been selected
Upon confirming SwdTech number
-------------------------------
Original:
C1/7D41: 4A LSR A
C1/7D42: 4A LSR A
C1/7D43: 4A LSR A
C1/7D44: 4A LSR A
Modified:
C1/7D41: 22 F8 A6 C2 JSL $C2A6F8 ; new subroutine C2/A6F8
New Subroutine C2/A6EF:
; Reset held gauge value for current ally
C2/A6EF: DA PHX
C2/A6F0: AE 01 02 LDX $0201 ; current ally ID (0 - 3)
C2/A6F3: 9E FC EC STZ $ECFC,X ; UNUSED RAM reset held SwdTech gauge value
C2/A6F6: FA PLX
C2/A6F7: 60 RTS
New Subroutine C2/A6F8:
; Reset held gauge, etc.
C2/A6F8: 20 EF A6 JSR $A6EF ; new subroutine C2/A6EF - reset held gauge
C2/A6FB: 4A LSR A ; original C1/7D41
C2/A6FC: 4A LSR A ; original C1/7D42
C2/A6FD: 4A LSR A ; original C1/7D43
C2/A6FE: 4A LSR A ; original C1/7D44
C2/A6FF: 6B RTL
In SwdTech gauge - button check
-------------------------------
Original:
C1/7D56: A5 09 LDA $09 ; Pressed mapped B this frame (& not last)?
C1/7D58: 10 05 BPL $7D5F ; Branch if not
Modified:
C1/7D56: 5C B9 A6 C2 JML $C2A6B9 ; new subroutine C2/A6B9
New Subroutine C2/A6AF:
; hold current gauge value
C2/A6AF: AE 01 02 LDX $0201 ; current ally ID (0 - 3)
C2/A6B2: AD 82 7B LDA $7B82 ; SwdTech counter
C2/A6B5: 9D FC EC STA $ECFC,X ; UNUSED RAM hold SwdTech counter value
C2/A6B8: 60 RTS
New Subroutine C2/A7A3:
; check for available allies & X/Y button press
C2/A6B9: A5 09 LDA $09 ; original C1/7D56
C2/A6BB: 10 04 BPL $A7AB ; replaces original C1/7D58
C2/A6BD: 5C 5A 7D C1 JML $C17D5A ; Player has canceled SwdTech gauge
C2/A6C1: DA PHX
C2/A6C2: A2 03 00 LDX #$0003 ; loop init
C2/A6C5: BD 01 40 LDA $4001,X ; character order
C2/A6C8: 3A DEA ; Is ally current (00) or inactive (FF)?
C2/A6C9: 10 05 BPL $A6D0 ; If not, branch to button check
C2/A6CB: CA DEX
C2/A6CC: 10 F7 BPL $A6C5 ; loop management
C2/A6CE: 80 1A BRA $A6EA ; No ally available; branch to abort
C2/A6D0: A5 09 LDA $09 ; buttons just pressed this frame (incl. Y)
C2/A6D2: 0A ASL A ; Y pressed this frame (but not last)?
C2/A6D3: 10 08 BPL $A6DD ; Branch if not
C2/A6D5: 20 AF A6 JSR $A6AF ; new subroutine C2/A6AF - hold gauge value
C2/A6D8: FA PLX
C2/A6D9: 5C C0 7A C1 JML $C17AC0 ; C1/7AC0 - Y press at top menu
C2/A6DD: A5 08 LDA $08 ; buttons just pressed this frame (incl. X)
C2/A6DF: 0A ASL A ; X pressed this frame (but not last)?
C2/A6E0: 10 08 BPL $A6EA ; Branch if not
C2/A6E2: 20 AF A6 JSR $A6AF ; new subroutine C2/A6AF - Hold gauge value
C2/A6E5: FA PLX
C2/A6E6: 5C AF 7A C1 JML $C17AB1 ; C1/7AB1 - X press at top menu
C2/A6EA: FA PLX
C2/A6EB: 5C 5F 7D C1 JML $C17D5F ; C1/7D5F - abort
Upon canceling SwdTech gauge
-------------------------------
Original:
C1/7D5A: E6 96 INC $96 ; player has canceled SwdTech gauge
C1/7D5C: 4C 28 56 JMP $5628 ; close SwdTech gauge window
Modified:
C1/7D5A: 5C 00 A7 C2 JML $C2A700 ; new subroutine C2/A700
New Subroutine C2/A700:
C2/A700: 20 EF A6 JSR $A6EF ; new subroutine C2/A6EF - reset held gauge
C2/A703: E6 96 INC $96 ; original C1/7D5A
C2/A705: 5C 28 56 C1 JML $C15628 ; replaces original C1/7D5C
Battle initialization
-------------------------------
Original:
C2/258D: A9 FF 03 LDA #$03FF ; 10 bits set, 10 possible entities in battle
Modified:
C2/258D: 20 AC A7 JSR $A7AC ; new subroutine C2/A7AC
New Subroutine C2/A7AC:
C2/A7AC: 9C FC EC STZ #$ECFC ; UNUSED RAM held SwdTech gauge (slot 1 & 2)
C2/A7AF: 9C FE EC STZ #$ECFE ; UNUSED RAM held SwdTech gauge (slot 3 & 4)
C2/A7B2: A9 FF 03 LDA #$03FF ; original C2/258D
C2/A7B5: 60 RTS
________________________________________________________________________________
2. CREDITS
________________________________________________________________________________
Special Thanks:
Imzogelmo, for his disassembly of bank C1
http://www.angelfire.com/al2/imzogelmo/patches.html
C-Dude, for pointing out a plethora of unused battle RAM
________________________________________________________________________________
3. REVISION HISTORY
________________________________________________________________________________
2023-04-23 : Version 1.0 released
________________________________________________________________________________
4. LEGAL
________________________________________________________________________________
Copyright (C) 2023 David R. Thompson (SilentEnigma).
The copyright holder ("author") permits the free use of the attributed work
referenced by this document exclusively for non-commercial purposes, provided
that the following conditions are met:
1. The author and all contributors credited in this readme document shall be
given credit for their respective contributions wherever the attributed work is
reused, redistributed, or modified.
2. This readme document shall accompany any of the files comprising the
attributed work wherever they are redistributed in unmodified form.
The work(s) and file(s) distributed with this document are provided "AS-IS",
WITHOUT ANY WARRANTY. The author shall not be held responsible for any damages
related to the use of work(s) and file(s) distributed with this document.
Database match: Final Fantasy III (USA)
Database: No-Intro: Super Nintendo Entertainment System (v. 20210222-050638)
File SHA-1: 2F3959057B2AB3664A564C467FBE4B81227CB0F3
File CRC32: 7D91FDF2
ROM SHA-1: 4F37E4274AC3B2EA1BEDB08AA149D8FC5BB676E7
ROM CRC32: A27F1C7A