Users browsing this thread: 1 Guest(s)
Espers teaching Stat gains

#1
Posts: 22
Threads: 11
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
Hi again everyone! I've got a live one for you here. Been staring at it for a couple of days, but my coding level is too low to get there. I know just enough about hacking this game to dive headfirst into the wrong thing for a few hours and get nowhere. Lol. 

I'm working on a hack in which I'd like Espers to do something new. Instead of teaching magic, I'd like for them to permanently increase a given stat, i.e. Ramuh teaches Stamina+1....x10, Stamina+3....x2, etc. No magic. Just stat gains. Everything else about the process can stay the same: Growth rate, AP gain from battles, etc. Physically increasing the stat shouldn't be too difficult. Espers already give you stat boosts at level-up (at C26198, with pointers from C2614E). I can hijack that code to do all of the math for me. The issue is getting the game to recognize this new set of instructions. How can I accomplish this? 

First, I looked at C2 in the code where we progress towards learning spells taught by Espers (C2602A-C2606C), but nothing there looked particularly useful. Then, I looked at the Esper data, but they just have one byte of info for each spell slot corresponding to the spell index. I thought about creating my own index of stat gains similar to the spell index where 00 would be Stamina+1 instead of Fire, etc. and this seems promising, but how can I get the game to recognize that list as the target? I can't find any pointers that associate Espers with spells. I tell ya, it's tricky!

Any suggestions? All help is appreciated.
  Find
Quote  

#2
Posts: 89
Threads: 11
Thanks Received: 3
Thanks Given: 1
Joined: Dec 2015
Reputation: 3
Status
Debrave
(09-09-2020, 04:28 PM)Morendo Wrote: Hi again everyone! I've got a live one for you here. Been staring at it for a couple of days, but my coding level is too low to get there. I know just enough about hacking this game to dive headfirst into the wrong thing for a few hours and get nowhere. Lol. 

I'm working on a hack in which I'd like Espers to do something new. Instead of teaching magic, I'd like for them to permanently increase a given stat, i.e. Ramuh teaches Stamina+1....x10, Stamina+3....x2, etc. No magic. Just stat gains. Everything else about the process can stay the same: Growth rate, AP gain from battles, etc. Physically increasing the stat shouldn't be too difficult. Espers already give you stat boosts at level-up (at C26198, with pointers from C2614E). I can hijack that code to do all of the math for me. The issue is getting the game to recognize this new set of instructions. How can I accomplish this? 

First, I looked at C2 in the code where we progress towards learning spells taught by Espers (C2602A-C2606C), but nothing there looked particularly useful. Then, I looked at the Esper data, but they just have one byte of info for each spell slot corresponding to the spell index. I thought about creating my own index of stat gains similar to the spell index where 00 would be Stamina+1 instead of Fire, etc. and this seems promising, but how can I get the game to recognize that list as the target? I can't find any pointers that associate Espers with spells. I tell ya, it's tricky!

Any suggestions? All help is appreciated.

I'm surprised no one has replied to this thread until now.

Unfortunately, you won't be able to hijack the existing code in order to do what you seek. Stat gains are limited to one at a time and although they can stack, the code is designed to increase one attribute per character upon levelling up. By contrast the varying nested subroutines concerning learning a spell are designed to work with the spell index to first skip a spell if it is learned, then mark a spell as just learned and to mark the spell as unhidden/accessible. There is no mechanism for learning a spell over and over again, so the subroutine you would eventually create would have to be completely new.

Creating your own stat gain index is an interesting work around but you would have to reconfigure every single loop concerning learning magic from Espers to account for that index. At the bare minimum you would have to replace the called subroutine at C2/6020. That still doesn't address certain problems such as how to apply gains of multiple types.

Thinking about this made my head hurt. That's probably because I'm at too low of a coding level myself to explain.
  Find
Quote  

#3
Posts: 22
Threads: 11
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
Cool! I was hoping somebody would respond. Thanks! I think what might be happening is that I know just barely enough about romhacking this game to misunderstand everything about romhacking this game. LOL.

Quote:Stat gains are limited to one at a time and although they can stack, the code is designed to increase one attribute per character upon levelling up. By contrast the varying nested subroutines concerning learning a spell are designed to work with the spell index to first skip a spell if it is learned, then mark a spell as just learned and to mark the spell as unhidden/accessible. There is no mechanism for learning a spell over and over again, so the subroutine you would eventually create would have to be completely new.

Oh, I didn't have any interest in increasing an attribute multiple times or learning the attribute over and over again. It would work exactly the same as learning spells. Once you've gotten Shiva's "Speed+2...x4" or whatever the skill is to 100%, that's it. It's at 100%. You'd get Speed+2 permanently, but it wouldn't start over.
Regardless, you're still totally right that I'd need to build a new subroutine. The tantalizing part is that so much of the existing code is already doing what I want! The only part I'm looking to change is the result. If I better understood the moment the code says: "Alright. They got to 100%. Go flick the on/off switch in the RAM to make that spell available", I could potentially intercept it and push it to a new subroutine that goes to the stat gain formula instead. At the moment, I don't understand how to do that. I mean, aren't the percentage points just a value stored in the RAM that's counting to 100? How "tied-in" is that number to the spell index?

To put it in FF terms, my coding level is also "too weak to be worthwhile". I suppose I'm not doing a great job of explaining my confusion.

Quote:Creating your own stat gain index is an interesting work around but you would have to reconfigure every single loop concerning learning magic from Espers to account for that index. 

This was my idea for a second option if the above "intercept the moment of spell learning" was functionally impossible or just straight-up dumb. We know the Espers have spell index values in the Esper data at $D86E00. I thought maybe creating a new index for stat gains (a ton of additional work) might be a good Plan B.
  Find
Quote  

#4
Posts: 22
Threads: 11
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
I think I might be making some headway on how I might be able to do this. Here's what I've got. I'll try and explain it as best I can. I'm still new to this, and I probably misunderstand and misexplain a lot!

In the vanilla game, Ramuh looks like this:
Ramuh 
Bolt     x10
Bolt2   x2
Poison x5
At level up ... Stamina +1

In my romhack, I plan to make Ramuh look like this:
Ramuh
Vigor+1   x10
Speed+2  x2
Stam+1   x5
No level-up bonus

- Everything else is vanilla.
- Right now, each character has RAM assigned to which spells they've learned. ($1A6E-$1CF4 Spells Known (12 characters, 54 spells each, 1 byte per spell)
- My romhack will only use 24 spells. The other 30 spots in RAM can be devoted exclusively to these skill-ups.
- This way I need to touch as little code as possible from the vanilla game. You fight monsters. Monsters give Magic Point(s). They calculate the exact same way. They save to the exact same RAM. Everything is the same.
- I set Ramuh to teach Slow x10 instead of Bolt x10. Easy. FFusME can do that with no trouble.
- Slow is spell index 25. 

- When you learn a "spell" from an Esper (which will now actually be our skill-up), it checks to see if the spell you've learned reaches 100% ($C2604B). I can add a subroutine here. (see below)
- All I need this subroutine to do is to turn my spell index (25) into a value between $00 and $10. (Incidentally, the correct value for Vigor+1 is $09. You can see this here: https://www.ff6hacking.com/wiki/doku.php...fmt:espers)
- Why a number between $00 and $10? 
Because I can run a number between $00 and $10 through the Level-Up bonus subroutine at $C260C2. The vanilla game already knows what to do once I give it the correct value.

- So now I just need to turn the number 25 into $09.
- I... don't know how to do this... Moreover, if I plan on turning all spell indexes from 25-54 into these skill-ups, it would be more complex than just turning 25 into $09. I'd need 25, 26, 27 to turn into $09; 28, 29, 30 to turn into $0A, etc. This way Ramuh could teach Vigor+1, and Shiva could teach a *different* Vigor+1. Using spell index 25 on both Espers would just cause both Espers to teach the same bonus.

I suppose it would look something like this:
Code:
C2604B:            BEQ C2606C            ;branch if no learn rate, i.e. no spell to learn - This first part is vanilla code
                         XBA
                         LDA $FB                 ;Magic points gained from the battle
                         JSR C24781          ;Multiply by spell learn rate
                         STA $EE                  ;Store this amount in $EE
                         LDA ($F4),Y           ;what % of spell is known
                         CMP #$FF
                         BEQ C2606C            ;Branch if spell already known
                         CLC
                         ADC $EE                   ;Add amount learned to % known for spell
                         BCS C26064
                         CMP #$64
                         BCC C26066            ;branch if % known didn't reach 100 - Vanilla Code interrupted here by my skill1 subroutine
                        JSR skill1            ;new skill-up subroutine - this is the only line of code I'm adding
C26064:           LDA #$80                 ;this is vanilla code again
C26066:            STA ($F4),Y            ;if it did, mark spell as just learned - this is also vanilla code




skill1:     PHA            
             PHY            
             LDA $D86E01,X        ; Find out which skill-up we just leveled up to 100% (X from earlier code helps us find this)
                                        ; Skill-ups and spells come from a shared index. This will load the result to the Accumulator.
             CMP #$25                 ; Compare it to #$25. Anything lower than #$25 is a spell and not a skill-up.
                                        ; Maybe unneeded, but I've added this in case we get here by accident.
             BCC C261B0                ; If it IS less than #$25, pop everything back where we found it and RTS the heck outta here.
                                                       ; Now the accumulator has our spell index in it (25 if it's the slow spell from our example above)
                PHX
        ::Turn 25 into $09 somehow::
                 ASL                                 ; the level-up bonus code does this to prepare the bonus for calculation
                 TAX                                  ; Transfer Accumulator to X
                JSR (C2614E,X)               ; Calculate Skill-up as if we had leveled up while equipped with an esper that gives Vigor+1 as a level-up bonus
                PLX
                PLY
                 PLA
                 RTS

Sorry about the formatting. My typing got eaten somehow. Also, there might be more to it after the bonus is calculated. I honestly haven't gotten that far just in case the first part doesn't work.
Am I crazy? Misinformed? Misunderstanding how life works? Not explaining it well? Please let me know! Any help would be appreciated.
  Find
Quote  

#5
Posts: 178
Threads: 2
Thanks Received: 23
Thanks Given: 4
Joined: Apr 2015
Reputation: 18
Status
None
If I understand correctly, I think you can do this with a lookup table. Put your spell index in the accumulator, subtract $25 then transfer to x and load from the lookup table. Your lookup table will be an array of bytes, one for each skill-up value. You can put the table anywhere that you have free space.

Code:
; turn $25 into $09, etc.
   sec
   sbc #$25
   tax
   lda lookup_table,x

; somewhere in free space
lookup_table:
   .db $09,$09,$09,$0a,$0a,$0a,...

Alternatively, if the conversion from spell index to skill-up id is a simple mathematical function (i.e. skill-up = 9 + (spell - $25) * 3) you could write an algorithm to convert it. This might save a few bytes but it won't be as flexible.
  Find
Quote  
[-] The following 1 user says Thank You to Everything for this post:
  • Morendo (11-12-2020)

#6
Posts: 16
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
Hey, not sure if this would help, but I wrote this code to replace the vanilla stat-gain routine to make it easier to update and work with. It fits in the same space, and may have room for a large lookup table, if you want.

What you might do is replace the spell IDs in the esper learning data with bytes that represent the exact stat gains you want to give. The hard part is dynamically generating the boost text inside the esper menu. I do have some code that does this, but it might be tricky to implement it in a different context. Let me know if you'd like it.


Code:
hirom
; header

; BNW - Simplified Esper Levels
; Bropedio (April 26, 2019)
; Last modified: June 11, 2019
;
; This overhauls the handling of esper boosts to enable faster changes:
; * Use a table of data rather than pointers to subroutines
; * Encode each bonus into a single byte (bits: 76543210)
;   * Bit 0 indicates stat versus HP/MP
;   * If stat, bits 2 and 1 provide stat index (7-3 are zero)
;   * If stat, assume change of 1 (could support more w/ unused bits)
;   * If HP/MP, bit 1 indicates MP (over HP)
;   * If HP/MP, bits 7-2 indicate amount to change (max 63)

; NOTE: This patch does not handle esper level text display, though I
; imagine it could be rewritten to programmatically determine the EL
; description based on the table below.

org $C2612C
ELJump:
    REP #$20         ; 16-bit A
    JMP AddEL        ; handle esper levelups
    NOP #2

org $C2614E
ELTable:
    db $78,$78 ; 60HP - Terrato, Crusader
    db $52,$52 ; 40HP - Bahamut, Ragnarok
    db $78,$3E ; 30HP/15MP -  Phoenix, Seraph
    db $01,$50 ; 20HP/Vig - Golem
    db $52,$07 ; 20MP/Mag - Zoneseek
    db $01,$03 ; Vig/Spd - Palidor
    db $03,$07 ; Mag/Spd - Siren
    db $01,$05 ; Vig/Stm - Phantom
    db $05,$07 ; Mag/Stm - Maduin
    db $03,$05 ; Spd/Stm - Alexander
    db $78,$05 ; 30HP/Stm - Kirin, Unicorn
    db $05,$66 ; 25MP/Stm - Carbunkl
    db $01,$01 ; 2Vig - Ramuh, Bismark
    db $03,$03 ; 2Spd - Ifrit, Fenrir
    db $05,$05 ; 2Stm - Stray, Odin, Tritoch, Starlet
    db $07,$07 ; 2Mag - Shiva, Shoat
    db $00,$00 ; null - Raiden?

AddEL:
    LDA ELTable,X   ; A = full 2-byte boost
    SEP #$20        ; 8-bit A
.doone
    TYX             ; X = index to character stats
    XBA             ; swap A bytes
    BNE .bonus      ; if bonus, branch and handle (long-loop)
    RTL             ; return
.bonus
    LSR
    BCC .hpmp       ; if bit $01 not set, use HP/MP
.loop
    BEQ .stat       ; if no stat index, continue
    INX
    DEC
    BRA .loop       ; add X to A
.stat
    LDA $161A,X     ; A = stat
    CMP #$80
    BEQ .fin        ; if maxed already, skip increment
    INC
    STA $161A,X     ; store updated stat
.fin
    BRA .next       ; finish this bonus byte
.hpmp
    LSR             ; remainder is amount to add
    BCC .addhp      ; if MP bit not set, skip INX
    INX
    INX
    INX
    INX             ; X points to max MP now
    CLC
.addhp
    ADC $160B,X
    STA $160B,X     ; add HP/MP bonus
    BCC .next       ; if no overflow, continue
    INC $160C,X     ; carry to hi byte
.next
    LDA #$00        ; clear finished bonus
    BRA .doone      ; loop for second bonus byte

padbyte $FF
pad $C261E9
  Find
Quote  
[-] The following 3 users say Thank You to Bropedio for this post:
  • Gi Nattak (12-10-2020), Morendo (12-18-2020), Warrax (12-20-2020)



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite