Skeetendo

’Cause all games were better on the GBC

You are not logged in.

#1 2012-11-22 20:10:43

Fireburn
New member
Registered: 2012-08-29
Post 4/5

Turn Off Stat Experience

As you know, stat experience is what makes trained Pokemon better than the wilds and enemy trainers. What I'd like to know, however, is how to turn that off. I feel it would add a nice amount of challenge to the game by leveling the playing field between the player and the CPU opponent. How would I do that? Would it just be a simple ASM edit?

Offline

#2 2012-11-22 23:38:39

comet
Member
Registered: 2012-04-09
Post 35/679

Re: Turn Off Stat Experience

Yes. Stat exp is dealt with directly during stat calculation. The function that does this, GetStat, is at $e17b in Crystal ($e181 in Gold).

There are a couple ways this can be done. The simplest is to hijack the statexp switch to totally disable it. This is already built in since wildmons don't have stat exp.

For our purposes we only need the first part:

GetStat: ; e17b
; input:
;    b: nonzero if stat exp

...

; put stat exp flag in d
    ld a, b
    ld d, a

GetStat asks later on if the stat exp flag is on, so all we need to do is make sure it's always off. The easiest way to do this is to replace the part that moves the flag from b to d with something that always makes d zero. It would look something like this:

GetStat: ; e17b
; input:
;    b: nonzero if stat exp

...

; put stat exp flag in d
; disable stat exp
    ld d, 0

This command uses the same amount of bytes as the two commands we replaced it with. You can see this is very quick and dirty but it does the job.

In a hex editor, this would mean going to $e17e (Crystal) / $e184 (Gold) and replacing

78 57

with

16 00

And that's all! Keep in mind this keeps stat exp from affecting stats at all no matter what.



If you're curious, here's the whole function (Crystal):

GetStat: ; e17b
; input:
;    b: nonzero if stat exp
;    c: stat id
;    hl: start of stat exp ; BufferMonStatExp (preserved)
; output:
;    $ffb5-6 (big endian)
    push hl
    push de
    push bc
; store b in d
    ld a, b
    ld d, a
    
; get base stat
    push hl
    ld hl, $d237 ; CurBaseStats + 1
    dec hl
; add stat id to hl
    ld b, $0
    add hl, bc
; store base stat in e
    ld a, [hl]
    ld e, a
    pop hl
    
; sdef shares special stat exp w/ satk
    push hl
    ld a, c
    cp $6 ; STAT_SPC_DEF
    jr nz, .getstatexp
    
    dec hl
    dec hl
    
.getstatexp
; double stat id
    sla c
    
; stat exp?
    ld a, d
    and a
    jr z, .getdv
    
; goto stat exp
    add hl, bc
; get stat exp
    push de
    ld a, [hld]
    ld e, a
    ld d, [hl]
; square root (result in b)
    callba GetSquareRoot
    pop de
    
.getdv
; halve (restore) stat id
    srl c
    pop hl
    
; at this point:
;    b = sqrt(stat exp)
;    c = stat id
;    d = stat exp on/off
;    e = base stat
;    hl = start of stat exp ; BufferMonStatExp

; goto dvs
    push bc
    ld bc, $000b ; BufferMonDVs - BufferMonStatExp
    add hl, bc
    pop bc
    
; which stat is this?
    ld a, c
    cp 2 ; STAT_ATK
    jr z, .attackdv
    cp 3 ; STAT_DEF
    jr z, .defensedv
    cp 4 ; STAT_SPD
    jr z, .speeddv
    cp 5 ; STAT_SATK
    jr z, .specialdv
    cp 6 ; STAT_SDEF
    jr z, .specialdv
    
; otherwise it's hp
; take the bottom bit of each dv and place them in order
    push bc
; attack
    ld a, [hl]
    swap a ; hi
    and 1
    ; << 3
    add a
    add a
    add a
    ld b, a
; defense
    ld a, [hli]
    and 1
    ; << 2
    add a
    add a
    add b
    ld b, a
; speed
    ld a, [hl]
    swap a
    and 1
    ; << 1
    add a
    add b
    ld b, a
; special
    ld a, [hl]
    and 1
    add b
    pop bc
    jr .calc
    
.attackdv
; 1st dv
    ld a, [hl]
; hi nybble
    swap a
    and %1111
    jr .calc
    
.defensedv
; 1st dv
    ld a, [hl]
; lo nybble
    and %1111
    jr .calc
    
.speeddv
; 2nd dv
    inc hl
    ld a, [hl]
; hi nybble
    swap a
    and %1111
    jr .calc
    
.specialdv
; 2nd dv
    inc hl
    ld a, [hl]
; lo nybble
    and %1111

;    a = dv
;    b = sqrt(stat exp)
;    c = stat id
;    de = base stat
;    hl = BufferMonSpdSpcDV

; put it all together

.calc
; dv + base stat
    ld d, $0
    add e
    ld e, a
    jr nc, .double ; don't carry
    inc d
    
.double
; double dv + base stat
    sla e
    rl d
    
; quarter sqrt(stat exp)
    srl b
    srl b
    
; de = 2*(dv + base stat) + sqrt(stat exp)/4
    ld a, b
    add e
    jr nc, .mult ; don't carry
    inc d
    
.mult
; multiplicand = de
    ld [$ff00+$b6], a
    ld a, d
    ld [$ff00+$b5], a
    xor a
    ld [$ff00+$b4], a
; multiply by level
    ld a, [$d143] ; level
    ld [$ff00+$b7], a
    call Multiply

; divide by 100
; dividend = result
    ld a, [$ff00+$b4]
    ld [$ff00+$b3], a
    ld a, [$ff00+$b5]
    ld [$ff00+$b4], a
    ld a, [$ff00+$b6]
    ld [$ff00+$b5], a

; divide by 100
    ld a, 100
    ld [$ff00+$b7], a
    ld a, $3 ; 3 byte dividend
    ld b, a
    call Divide
    
; skip this part if we aren't dealing with hp
    ld a, c
    cp 1 ; STAT_HP
; get min stat
    ld a, 5 ; STAT_MIN_NORMAL
    jr nz, .addmin

; add level to result
    ld a, [$d143] ; level
    ld b, a
    ld a, [$ff00+$b6]
    add b
    ld [$ff00+$b6], a
; carry if applicable
    jr nc, .hpmin
    ld a, [$ff00+$b5]
    inc a
    ld [$ff00+$b5], a
.hpmin
    ld a, 10 ; STAT_MIN_HP
    
.addmin
; add min to result
    ld b, a
    ld a, [$ff00+$b6]
    add b
    ld [$ff00+$b6], a
; carry if applicable
    jr nc, .checkcap
    ld a, [$ff00+$b5]
    inc a
    ld [$ff00+$b5], a
    
.checkcap
; check if the stat is 999 or lower
    ld a, [$ff00+$b5]
; if below $400 we know it's too high
    cp $4 ; hi(1024)
    jr nc, .setcap
; if below 1000, we're good
    cp $3 ; hi(1000)
    jr c, .end
    ld a, [$ff00+$b6]
    cp $e8 ; lo(1000)
    jr c, .end
; otherwise, cap it at 999
.setcap
; output = 999
    ld a, $3 ; hi(999)
    ld [$ff00+$b5], a
    ld a, $e7 ; lo(999)
    ld [$ff00+$b6], a
    
.end
; stat in $ffb5-6
    pop bc
    pop de
    pop hl
    ret
; e277

Offline

#3 2018-11-17 16:36:54

herbarium
New member
Registered: 2018-07-23
Post 3/3

Re: Turn Off Stat Experience

comet wrote:

Keep in mind this keeps stat exp from affecting stats at all no matter what.

Comet, I'm wondering if stopping the exp stat also stops DV gains? From the Crystal code you showed, it seems that DV's are still calculated and stored.

Asking in relation to this thread: https://hax.iimarckus.org/topic/7495/

Offline

#4 2018-11-20 19:32:35

rbroab
Member
Registered: 2017-06-13
Post 86/86

Re: Turn Off Stat Experience

I could be wrong, but I was under the impression that DVs weren’t applied until level up. Or am I thinking of EVs

Offline

Board footer

Powered by FluxBB