’Cause all games were better on the GBC

You are not logged in.

- Index
- → Generation II
- →
**Turn Off Stat Experience**

Pages: **1**

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

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

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

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

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

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

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

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

Pages: **1**

- Index
- → Generation II
- →
**Turn Off Stat Experience**