Users browsing this thread: 1 Guest(s)
Condensing Spell List in Battle
10-05-2017, 10:17 PM
(This post was last modified: 10-05-2017, 10:40 PM by GrayShadows.)
Yeah, I think I can make this compatible without actually using any additional extra space, thanks to the optimisations that assassin's already done on the code for the Control MP fix. Working on it now.
Try this -- it seems to be working on my end, everything's still all deducting properly on the party side. I didn't bother tracking down the monster MP in RAM to see if it deducted properly, but Control is still working properly with nothing crashing, so... Here's hoping?
You should be fine to patch it right over the existing rom, including the one you patched with the last version of this code.
Try this -- it seems to be working on my end, everything's still all deducting properly on the party side. I didn't bother tracking down the monster MP in RAM to see if it deducted properly, but Control is still working properly with nothing crashing, so... Here's hoping?
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Condensed Spell Lists v1.5 -- Control MP Fix Variant
; Author: Gray Shadows (in.the.afterlight@gmail.com
; Applies to Final Fantasy 3/6us v1.0
;
; Urgency: Low - QoL enhancement
;
; Contributors: assassin (code support and optimisation)
; seibaby (testing and problem solving)
; Warrax (testing and bug identification)
;
; In vanilla FF6, because of the way the game builds spell lists in
; battle, if one character in battle knows a lot of spells and another
; character doesn't, that second character will have a lot of blank
; space in their Magic menu. Condensed Spell Lists adds some additional
; code to battle initialisation that takes a character's spell list
; and 'shuffles' it up, so that all of the blank spots are at the end.
; It also resorts the Lore list in the same manner.
;
; Version 1.5 update includes: bugfixes, including an error introduced
; wherein monster abilities were incorrectly costing MP, as well as a
; fatal crashing error caused by Interceptor counter-attacks. The hack
; should now properly account for all abilities that use the Magic
; command but do not cast from a character's spell list. (This should
; only be Interceptor counter-attacks, and possibly Desperation Attacks.)
;
; The Control MP Fix variant incorporates code from assassin's "Control
; Attacks ignore MP cost fix" patch, including some optimisations that
; let me fit both his code and mine into the vanila C2/4F08 function
; without taking up any more space than the base version of the patch does.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;
hirom
;header
print " "
!freespace_C2_0 = $C2A65A ; 77 bytes needed, used through $C2A6A6
!freespace_C2_1 = $C2FAB0 ; 64 bytes needed, used through $C2FAEF
org $C2256D
JSR condenseSpellLists
; This was originally a JSR to modify available commands; we'll be JMPing to
; that at the end of the modified code so that RTS comes back to the right spot.
org $C24EDF
loop:
org $C24EE3
; FF6j = org $C24ECB
print "Replacement Function updated_4F08 starts at: ",pc
reset bytes
BEQ skip
LDA $3184,Y
BPL loop ; oops! i wrongly had "F0 F5 BEQ $4EDF" in the first
; release of the patch, even though this was one of the
; simpler optimizations.. and even though I had an email
; from Imzogelmo containing the correct instruction, as
; he'd come up with same optimization on his own.
; ---- Rest of function is unchanged from original game, aside from the ----
; ---- JSR destination, but just shifted upwards. ------------
skip:
PLA
STA $3184,Y
ASL
TAY
JSR GetMPCost ; Determine MP cost of a spell/attack
STA $3620,Y ; save MP cost
REP #$20 ; Set 16-bit Accumulator
LDA $3A7A
STA $3420,Y ; save command #
LDA $B8
STA $3520,Y
PLP
PLY
RTS
;org $C24F24
GetMPCost:
PHX
PHP
TDC ; 16-bit A = 0. this means the returned spell cost will
; default to zero.
LDA #$40
TRB $B1 ; clear Bit 6 of $B1
BNE KeepZero ; branch if it was set, meaning we're on second Gem Box
; spell for Mimic, and return 0 as cost. no precaution
; needed for first Mimicked Gem Box spell, as we reach
; this function with $3A7A as 12h [Mimic] then.
REP #$10 ; Set 16-bit X and Y
LDA $3A7A ; get command #
CMP #$19
BEQ CommandUsesMP ; branch if it's Summon
CMP #$0C
BEQ CommandUsesMP ; branch if it's Lore
CMP #$02
BEQ CommandUsesMP ; branch if it's Magic
CMP #$17
BEQ CommandUsesMP ; branch if it's X-Magic
CMP #$0E
BNE KeepZero ; branch if it's not Control
ControlCheck:
LDA $3EF9,X ; status byte 4
BIT #$10
BEQ KeepZero ; branch if Controller not in "spell chant" yet. the
; first turn of Control just involves mentally violating
; the monster, so there won't be any MP cost [and the
; attack # should be undefined].
BRA GetAttack ; always get the MP cost from the spell data.
; while Control attacks may be launched *from* a
; character menu [which will make X < 8 in this function],
; they're performed *by* the monster, so that menu doesn't
; even have MP data.
;
; Why the dreadful obfuscation, you ask? If the command
; is Control, Carry will always be set by the "CMP #$0E"
; above, and the next branch (at C2/4F37) will ALWAYS be
; taken. Butt-ugly, but I really didn't feel like having
; a "LDA $3A7B" in two separate places.
CommandUsesMP:
CPX #$0008
GetAttack:
XBA ; [High byte is now command, low byte will be attack]
LDA $3A7B ; get attack #
BCS UseSpellData ; branch if it's a monster attacker. they don't have
; menus containing MP data, nor relics that can
; alter MP costs. OR always branch if command is Control.
XBA ; high is spell, low is command
CMP #$19
BEQ .summon
JMP calculateMPDeduction
.summon
CLC
TDC
REP #$20
ADC $302C,X ; add starting address of character's Esper menu
TAX
LDA $0002,X ; A.bottom = spell aiming from character's menu data.
; A.top = MP cost from character's menu data. it usually
; matches the spell data, but Gold Hairpin, Economizer,
; and Step Mine's special formula can make it vary.
BRA KeepZero ; put MP cost in bottom of A, clean up stack, and exit
UseSpellData:
; C2/4F52: 20 D8 51 JSR $51D8 (A = MP cost, read from spell data)
; C2/4F55: EB XBA
JSR $5723 ; From spell data, put MP cost in top of A, and aiming
; byte in bottom of A
; FF6j = JSR $570B
KeepZero:
XBA ; bottom of A = MP cost
ExitWithMP:
PLP
PLX
RTS
print "Replacement Function updated_4F08 ends at: ",pc," and used ",bytes," bytes of space."
print " "
;org $C24F47
;fka_4F47:
; This jumps in the middle of a function at C2/4F08 that grabs the MP cost for
; a spell. A character's individual spell list in battle stores a modified MP
; cost based on modifying relics, and as we're reshuffling the list, we need to
; add additional code to make sure that the game looks for MP costs in the right
; location.
org !freespace_C2_0
print "New function CondenseSpellLists starts at: ",pc
reset bytes
condenseSpellLists:
PHX ;
PHP
LDY #$04 ; The 0 index in the list holds the equipped esper, which we're not touching.
; Each entry is four bytes long, so the spell list starts at Y = 4.
.noMoreSpells ; We'll be branching back here to execute our Lore list
TYX ; X is going to be our 'write-space' index, whereas Y is our 'read-space' index.
REP #$10
.checkSpellLoop
LDA ($F2),Y
INC
BNE .checkNextSpell
.findNextSpell
INY #4
CPY #$00DC ; If we've hit the first Lore slot, there are no more spells to copy back,
BEQ .noMoreSpells ; so jump out, reset X to start sorting the Lore list instead.
CPY #$013C ; This is after the last Lore slot, so if we've gone that far, there are
BEQ .noMoreLores ; no more spells to copy back and we can exit the function entirely.
LDA ($F2),Y
INC
BEQ .findNextSpell
PHY ; we'll be pushing and pulling within the loop, but we need to know
; where it started so we can blank out the slot we copied from
CLC
REP #$20
.copyNextSpell
LDA ($F2),Y
PHY ; This stores our Y location, i.e. the next slot with a spell learned
TXY ; and pulls our X, or the blank slot we're writing to.
STA ($F2),Y
PLY ; back to our 'write from' location
INY #2 ; and gets the next bytes
INX #2
BCS .doneCopy
SEC
BPL .copyNextSpell ; if we haven't done four bytes, loop back and grab the next
.doneCopy
SEP #$20
PLY ; this is the first byte of the slot we copied from
TDC
STA ($F4),Y ; this zeroes out the MP cost
DEC
STA ($F2),Y ; and blanks out the spell we copied from
BRA .weCopiedASpell
.checkNextSpell
INX #4
.weCopiedASpell
TXY ; and then copy it over to Y for our next loop through
CPY #$0138
BNE .checkSpellLoop
.noMoreLores
PLP
PLX
JMP $532C
print "CondenseSpellLists ends at: ",pc," and used ",bytes," bytes of space."
print " "
org !freespace_C2_1
calculateMPDeduction:
print "New function CalculateMPDeduction starts at: ",pc
reset bytes
CMP #$0C ; coming in, low byte is command and high byte is spell ID
BEQ .calculateLore ; (branch if it's Lore)
.calculateMagic
XBA ; (get attack #), high byte is now command and low byte is attack ID
CMP #$F0 ; is it a Desperation Attack or an Interceptor counter?
BCS .returnZero ; if so, exit
STA $F0 ; save our spell ID in scratch memory
TDC
LDA #$04 ; four bytes per index, and we're starting at the second index in
; the list (i.e. the first Magic spell)
.loreEntersHere
REP #$20
CLC
ADC $302C,X ; get the start of our character's magic list (index #0 is esper)
STA $F2 ; this points out our first Magic slot
INC #3
STA $F4 ; and this points at our first MP cost slot
SEP #$20
PHY
LDY $00
.findSpell
LDA ($F2),Y
CMP $F0
BEQ .getMPCost
INY #4
BRA .findSpell
.getMPCost
LDA ($F4),Y
PLY
BRA .exitWithMP
.calculateLore
XBA ; (get attack #), high byte is command and low byte is attack ID
SEC
SBC #$8B ; turn our raw spell ID into a 0-23 Lore ID
STA $F0
TDC
LDA #$DC ; this is our first Lore slot in the character's spell list
BRA .loreEntersHere
.returnZero
TDC
.exitWithMP
JMP ExitWithMP ; (clean up stack and exit)
print "CalculateMPDeduction ends at: ",pc," and used ",bytes," bytes of space."
print " "
You should be fine to patch it right over the existing rom, including the one you patched with the last version of this code.
« Next Oldest | Next Newest »
Users browsing this thread: 1 Guest(s)