Condensing Spell List in Battle
09-17-2017, 04:01 AM
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.
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.
09-17-2017, 04:05 AM
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
09-17-2017, 04:58 AM
(This post was last modified: 09-17-2017, 05:44 AM by GrayShadows.)
(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.
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.
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)
• Gi Nattak (09-17-2017), SSJ Rick (09-18-2017), Warrax (09-17-2017)
09-17-2017, 04:34 PM
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.
09-17-2017, 05:34 PM
(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.
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.
09-17-2017, 06:54 PM
(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.
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.
09-17-2017, 08:48 PM
I've got the first function down to 90 bytes.
I'm open to suggestions on reducing the size of the MP Deduction function, too.
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
09-18-2017, 04:28 AM
Code:
BEQ .noMoreLores
BRA .checkLoreLoop
.noMoreLores
==> BNE .checkLoreLoop
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.
09-18-2017, 10:59 AM
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.
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."
09-18-2017, 12:45 PM
BNE replaces both instructions. read the 3 quoted lines in sequence.
« Next Oldest | Next Newest »
Users browsing this thread: 1 Guest(s)