Users browsing this thread: 1 Guest(s)
Condensing Spell List in Battle

#11
Posts: 200
Threads: 1
Thanks Received: 10
Thanks Given: 0
Joined: Oct 2015
Reputation: 18
Status
None
re optimization: haha; they are a bit opposite.  two paths to the same goal.  i went ahead and coded my method, borrowing from your code, out of curiosity and boredom.  can post if wanted, but don't think there's any (measurable) advantage to it.

from what i can tell, yours should work.  it'll definitely be faster than the first version.

-------

re C2/4F08 remedy: under .calculateSummon, i'd tend to do the Esper=>Spell ID conversion and verify the desired spell is in that first slot before proceeding, just to be robust.  extra space be damned.  but your assumption regarding Summons seems fairly sound.

-------

have you tried unifying the list condensing for Magic and Lore?  if you can find somewhere to store parameters/bounds, it shouldn't be too hard to make a more flexible function.  now, it'll be a little slower (e.g. the index always being in 16-bit mode), but it'll save a lot of space.
Quote  

#12
Posts: 259
Threads: 3
Thanks Received: 5
Thanks Given: 1
Joined: Jun 2013
Reputation: 6
Status
None
I'm keeping my eye on this one. It's a request I've made and have had every hacker I know throw up their arms at.


"You don't have to be a vampire to die like one... b*t*h." -Simon Belmont
Quote  

#13
Posts: 175
Threads: 11
Thanks Received: 10
Thanks Given: 8
Joined: May 2013
Reputation: 13
Status
Well-Fed
(09-17-2017, 04:01 AM)assassin Wrote: re optimization: haha; they are a bit opposite.  two paths to the same goal.  i went ahead and coded my method, borrowing from your code, out of curiosity and boredom.  can post if wanted, but don't think there's any (measurable) advantage to it.

from what i can tell, yours should work.  it'll definitely be faster than the first version.

I'd be curious to see yours, just to compare -- I learn more from seeing everyone else's coding than I do just by coding myself, half the time. Wink

Quote:your assumption regarding Summons seems fairly sound.
Realistically, I probably don't even need to include a check for #$FF/end of spells in the MP deduction function, because there shouldn't be a way to get to it with a spell the character doesn't know. XD But it's in the original function, so I figured it'd be better to be on the safe side with it.

Quote:have you tried unifying the list condensing for Magic and Lore?  if you can find somewhere to store parameters/bounds, it shouldn't be too hard to make a more flexible function.  now, it'll be a little slower (e.g. the index always being in 16-bit mode), but it'll save a lot of space.

... I hadn't, but now I'm thinking about it. I'll take a look at it tomorrow, after I get some sleep. (... Later today. Oops, it's 6AM.)


BTB said:
Quote:I'm keeping my eye on this one. It's a request I've made and have had every hacker I know throw up their arms at.


It's completely functional now, if you've got space for it! I still kinda can't believe I finally figured it out. XD Like I said above, though, I am going to take assassin's suggestion and try unifying the condensing code.


ETA:
Ooooor I could not sleep, and code the unified version instead. 

Code:
org !freespace_C2_0
condenseSpellLists:
PHX                ; This is our character ID coming in
PHP
REP #$10
LDY #$0004            ; this is the index of the first Spell slot in the character's spell list
STY $F0    
LDX #$004A            ; this is our main loop index; we're checking 53 spells and 23 lores, since we
                ; don't need to actually check the last slot of either list
    .checkLoreLoop    
    LDA ($F2),Y
    CMP #$FF
    BNE .checkNextLore

        .findNextLore
        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 $F0 to start our lores
        CPY #$013C        ; this is after the last Lore slot, so if we've gone that far, there are no more spells to copy back
        BEQ .noMoreLores
        LDA ($F2),Y
        CMP #$FF
        BEQ .findNextLore

    PHX            ; set aside the starting byte for the spell we found
    PHY            ; we'll be pushing and pulling within the loop, but we need to know
    LDX #$0003        ; where it started so we can blank out the slot we copied from
    
        .copyNextLore
        LDA ($F2),Y        ; Yes, we just did this, but we need to do it within this loop, too
        PHY            ; this stores our Y location, i.e. the next slot with a spell learned
        LDY $F0            ; and loads our index for slot to write to
        STA ($F2),Y
        PLY            ; back to our 'write from' location
        INY            ; and gets the next byte
        REP #$20
        INC $F0            ; while getting our next write-to byte, too.
        SEP #$20
        DEX            
        BPL .copyNextLore    ; if we haven't done four bytes, loop back and grab the next

    PLY            ; this is the first byte of the slot we copied from
    LDA #$FF
    STA ($F2),Y        ; this blanks out the spell we copied from
    LDA #$00
    STA ($F4),Y        ; and zeroes out the MP cost
        
    PLX            ; this gets our index for the loop -- how many spell slots we've checked
    BRA .weCopiedALore
    .checkNextLore
    REP #$20
    INC $F0            ; if we DIDN'T copy a spell, we need to increment our 'current slot' index
    INC $F0            ; but if we did, the loop already has it pointing to the next slot
    INC $F0
    INC $F0
    SEP #$20
    .weCopiedALore
    LDY $F0            ; and then copy it over to Y for our next loop through
    CPY #$00D8        ; if this is the last spell slot
    BEQ .checkNextLore    ; loop back up and INC again so we skip over it and point at our first Lore slot
    
    DEX
    BPL .checkLoreLoop
    .noMoreLores
    
PLP    
PLX
JMP $532C

.noMoreSpells
LDX #$0016            ; reset our index to cover just the Lores
STY $F0                ; and reset our working index for the first Lore slot
BRA .checkLoreLoop

Found a couple of other little places I could tidy up the code, too, including the placements of a PHX and such.


Current Project: FF6: Tensei | Discord ID: TristanGrayse
  Find
Quote  
[-] The following 3 users say Thank You to GrayShadows for this post:
  • Gi Nattak (09-17-2017), SSJ Rick (09-18-2017), Warrax (09-17-2017)

#14
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
Really nice work! I never really thought much of this issue, or rather thought it could even be corrected, but now looking back I realize how much it did suck to have to scroll down and all those blank spaces, it's definitely a major improvement. I definitely want to use this but my largest free space I have atm the code ran 3 bytes over >_< So close... I'm afraid I won't have anything else in C2 I can remove for the required space ;_; but I'm going to try!


We are born, live, die and then do the same thing over again.
Quote  

#15
Posts: 200
Threads: 1
Thanks Received: 10
Thanks Given: 0
Joined: Oct 2015
Reputation: 18
Status
None
(09-17-2017, 04:58 AM)GrayShadows Wrote: I'd be curious to see yours, just to compare -- I learn more from seeing everyone else's coding than I do just by coding myself, half the time. Wink

untested, hasn't been assembled:

Code:
phx

ldy #$04      ; full list index.  start at 1st Magic slot.
tyx           ; index of next spot to write in shortened list.  start at 1st
              ;  Magic slot.

mainLoop:
LDA ($F2),Y
CMP #$FF
BEQ checkNextSpell   ; branch if current entry null

stx $f0
cpy $f0       ; does full list index == output index?  yes, i use
              ;  this variable in a single place, because no other
              ;  easy way to compare X and Y. :/
beq noCopy    ; skip copying if so, but still advance

clc
rep #$20

copyLoop:
lda ($F2),Y   ; read two spell menu bytes from original position
phy
txy
sta ($F2),Y   ; save to new position
ply
iny
iny
inx
inx
bcs done      ; exit loop if we've iterated twice.  this
              ;  way lets us avoid using decrementor.
sec
bra copyLoop  ; otherwise, iterate that second time
done:

sep #$20

bra alreadyInced

noCopy:
inx
inx
inx
inx           ; advance index of next place to write in shortened list

checkNextSpell:
iny
iny
iny
iny           ; advance full list index
alreadyInced:

cpy #$D8      ; have we processed end of Magic list?
bcc mainLoop  ; loop if not

; now blank out unused remainder of shortened list

txy
blankLoop:
cpy #$D8         ; have we reached Lore Land yet?
bcs nothingLeft  ; branch if so

LDA #$FF
STA ($F2),Y   ; this blanks out a spell
LDA #$00
STA ($F4),Y   ; and zeroes out the MP cost
iny
iny
iny
iny

bra blankLoop
nothingLeft:

plx


one strong point is i'm able to mostly keep the second index in a register.  but i do resort to using $F0 briefly to avoid stack jackassery.  that could pose problems if i wanted to use the variable for bounds or other parameters in a unified version.

for the zeroing+FF'ing of spell data, it'd be a little smaller (and maybe faster) to have a "TDC ... DEC", with the ($F4) write first.
Quote  

#16
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
(09-17-2017, 05:34 PM)assassin Wrote:
(09-17-2017, 04:58 AM)GrayShadows Wrote: I'd be curious to see yours, just to compare -- I learn more from seeing everyone else's coding than I do just by coding myself, half the time. Wink

untested, hasn't been assembled:

Code:
phx

ldy #$04      ; full list index.  start at 1st Magic slot.
tyx           ; index of next spot to write in shortened list.  start at 1st
              ;  Magic slot.

mainLoop:
LDA ($F2),Y
CMP #$FF
BEQ checkNextSpell   ; branch if current entry null

stx $f0
cpy $f0       ; does full list index == output index?  yes, i use
              ;  this variable in a single place, because no other
              ;  easy way to compare X and Y. :/
beq noCopy    ; skip copying if so, but still advance

clc
rep #$20

copyLoop:
lda ($F2),Y   ; read two spell menu bytes from original position
phy
txy
sta ($F2),Y   ; save to new position
ply
iny
iny
inx
inx
bcs done      ; exit loop if we've iterated twice.  this
              ;  way lets us avoid using decrementor.
sec
bra copyLoop  ; otherwise, iterate that second time
done:

sep #$20

bra alreadyInced

noCopy:
inx
inx
inx
inx           ; advance index of next place to write in shortened list

checkNextSpell:
iny
iny
iny
iny           ; advance full list index
alreadyInced:

cpy #$D8      ; have we processed end of Magic list?
bcc mainLoop  ; loop if not

; now blank out unused remainder of shortened list

txy
blankLoop:
cpy #$D8         ; have we reached Lore Land yet?
bcs nothingLeft  ; branch if so

LDA #$FF
STA ($F2),Y   ; this blanks out a spell
LDA #$00
STA ($F4),Y   ; and zeroes out the MP cost
iny
iny
iny
iny

bra blankLoop
nothingLeft:

plx


one strong point is i'm able to mostly keep the second index in a register.  but i do resort to using $F0 briefly to avoid stack jackassery.  that could pose problems if i wanted to use the variable for bounds or other parameters in a unified version.

for the zeroing+FF'ing of spell data, it'd be a little smaller (and maybe faster) to have a "TDC ... DEC", with the ($F4) write first.

Oh I like the sound of that! Hopefully at least 3 bytes smaller lol.


We are born, live, die and then do the same thing over again.
Quote  

#17
Posts: 175
Threads: 11
Thanks Received: 10
Thanks Given: 8
Joined: May 2013
Reputation: 13
Status
Well-Fed
I've got the first function down to 90 bytes. Laugh 
Code:
condenseSpellLists:
PHX                ; This is our character ID coming in
PHP
REP #$10
LDY #$0004        ; this is the index of the first Spell slot in the character's spell list
TYX                ; X is going to be our 'write-space' index

    .checkLoreLoop        ; don't need to actually check the last slot of either list
    LDA ($F2),Y
    CMP #$FF
    BNE .checkNextLore

        .findNextLore
        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 $F0 to start our lores
        CPY #$013C    ; this is after the last Lore slot, so if we've gone that far, there are no more spells to copy back
        BEQ .noMoreLores
        LDA ($F2),Y
        CMP #$FF
        BEQ .findNextLore

    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
    
        .copyNextLore
        LDA ($F2),Y    ; Yes, we just did this, but we need to do it within this loop, too
        PHY            ; this stores our Y location, i.e. the next slot with a spell learned
        TXY
        STA ($F2),Y
        PLY            ; back to our 'write from' location
        INY    #2        ; and gets the next byte
        INX #2
        BCS .doneCopy
        SEC
        BPL .copyNextLore    ; 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 .weCopiedALore
    .checkNextLore
    INX #4
    .weCopiedALore
    TXY                ; and then copy it over to Y for our next loop through
    CPY #$00D8        ; if this is the last spell slot
    BEQ .checkNextLore    ;loop back up and INX again so we skip over it and point at our first Lore slot
    CPY #$0138
    BEQ .noMoreLores
    BRA .checkLoreLoop
    .noMoreLores
    
PLP    
PLX
JMP $532C

.noMoreSpells
TYX            ; reset our write-space index for the first Lore slot
BRA .checkLoreLoop
I'm open to suggestions on reducing the size of the MP Deduction function, too.


Current Project: FF6: Tensei | Discord ID: TristanGrayse
  Find
Quote  
[-] The following 1 user says Thank You to GrayShadows for this post:
  • Gi Nattak (09-17-2017)

#18
Posts: 200
Threads: 1
Thanks Received: 10
Thanks Given: 0
Joined: Oct 2015
Reputation: 18
Status
None
Code:
   BEQ .noMoreLores
   BRA .checkLoreLoop
   .noMoreLores

==> BNE .checkLoreLoop
Tongue

also, i think both "CMP #$FF"s can be shrunk to INCs, provided nothing after the tests+branches reads A without overwriting it first.

iirc, if you move the "REP #$10" forward two instructions (or one), it'll zero the top halves of X and Y, meaning you can do a smaller, 8-bit LDY.  (and that and the TYX might be a hair faster.). but best doublecheck the 65816 documentation.
Quote  

#19
Posts: 175
Threads: 11
Thanks Received: 10
Thanks Given: 8
Joined: May 2013
Reputation: 13
Status
Well-Fed
Well, I mean, BNE would work just as well, but BRA is working as intended there -- .checkLoreLoop is self-contained, and will ALWAYS loop unless it meets one of its two exit requirements: X/Y = #$0138 (and therefore we've checked every single slot), or, in .findNextSpell, Y = #$013C, in which case there are no more spells to shuffle up to fill empty slots with.

The other suggestions are definitely good, though! CondenseSpellLists is now down to 87 bytes, and with that and a little other tidying up, calculateMPDeduction is now down to 97.


Code:
hirom
;header

!freespace_C2_0 = $C2A65A        ; 90 bytes needed
!freespace_C2_1 = $C2FAB0        ; 103 bytes needed

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 $C24F11
REP #$10
LDA $3A7B                ; (get attack #) -- the new code will do this again in a bit, but
CPX #$0008                ; we need it in A now or we'll break monster casting
BCS fka_4F47            ; (branch if it's a monster attacker.  they don't have
                        ; menus containing MP data, nor relics that can
                        ; alter MP costs.)
                        ; This was originally in the middle of the code, but
                        ; there shouldn't be any issues doing this check first,
                        ; and it makes the new code MUCH smoother.
JMP calculateMPDeduction

org $C24F47
fka_4F47:

                            
org !freespace_C2_0
print "New code CondenseSpellLists starts at: ",pc
reset bytes

condenseSpellLists:
PHX                ; This is our character ID coming in
PHP
LDY #$04        ; this is the index of the first Spell slot in the character's spell list
TYX                ; X is going to be our 'write-space' indexREP
REP #$10

    .checkLoreLoop        ; don't need to actually check the last slot of either list
    LDA ($F2),Y
    INC
    BNE .checkNextLore

        .findNextLore
        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 $F0 to start our lores
        CPY #$013C    ; this is after the last Lore slot, so if we've gone that far, there are no more spells to copy back
        BEQ .noMoreLores
        LDA ($F2),Y
        INC
        BEQ .findNextLore

    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
    
        .copyNextLore
        LDA ($F2),Y    ; Yes, we just did this, but we need to do it within this loop, too
        PHY            ; this stores our Y location, i.e. the next slot with a spell learned
        TXY
        STA ($F2),Y
        PLY            ; back to our 'write from' location
        INY    #2        ; and gets the next byte
        INX #2
        BCS .doneCopy
        SEC
        BPL .copyNextLore    ; 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 .weCopiedALore
    .checkNextLore
    INX #4
    .weCopiedALore
    TXY                ; and then copy it over to Y for our next loop through
    CPY #$00D8        ; if this is the last spell slot
    BEQ .checkNextLore    ;loop back up and INX again so we skip over it and point at our first Lore slot
    CPY #$0138
    BEQ .noMoreLores
    BRA .checkLoreLoop
    
.noMoreLores
PLP    
PLX
JMP $532C

.noMoreSpells
TYX            ; reset our write-space index for the first Lore slot
BRA .checkLoreLoop

print "CondenseSpellLists ends at: ",pc," and used ",bytes," bytes of space."



org !freespace_C2_1
calculateMPDeduction:

print "New code CalculateMPDeduction starts at: ",pc
reset bytes

REP #$10            ; (Set 16-bit X and Y)
LDA $3A7A            ; (get command #)
CMP #$19
BEQ .calculateSummon    ; (branch if it's Summon)
CMP #$0C
BEQ .calculateLore    ; (branch if it's Lore)
CMP #$02
BEQ .calculateMagic    ; (branch if it's Magic)
CMP #$17
BNE fka_4F53        ; (branch if it's not X-Magic)

.calculateMagic
LDA $3A7B            ; (get attack #)
STA $F0                        ; save our spell ID in scratch memory
LDA #$04                    ; four bytes per index

.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
    INC
    BEQ fka_4F53
    INY #4
    BRA .findSpell
    
.getMPCost
LDA ($F4),Y
PLY
BRA fka_4F45

.calculateLore
LDA $3A7B                    ; (get attack #)
SEC
SBC #$8B                    ; turn our raw spell ID into a 0-23 Lore ID
STA $F0
LDA #$DC                    ; this is our first Lore slot in the character's spell list
BRA .loreEntersHere

.calculateSummon            ; rather than looking for the spell ID, I'm operating under
REP #$20                    ; the assumption that if someone is using Summon, it's already
LDA $302C,X                    ; checked for the equipped Esper, so I'm just loading the MP cost
TAX                            ; from the first entry in the character's list
SEP #$20
LDA $0003,X
BRA fka_4F45


fka_4F45: JMP $4F54            ; (clean up stack and exit)
fka_4F53: JMP $4F53

print "CalculateMPDeduction ends at: ",pc," and used ",bytes," bytes of space."


Current Project: FF6: Tensei | Discord ID: TristanGrayse
  Find
Quote  

#20
Posts: 200
Threads: 1
Thanks Received: 10
Thanks Given: 0
Joined: Oct 2015
Reputation: 18
Status
None
Finger  BNE replaces both instructions.  read the 3 quoted lines in sequence.
Quote  
[-] The following 1 user says Thank You to assassin for this post:
  • GrayShadows (09-18-2017)



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite