You are not logged in.
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?
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
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
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/