Level cap - nickjwilde/pokecrystal GitHub Wiki
This tutorial guides you through changing the max level. You will add a new variable, modify level cap logic, and optionally remove gaining exp. once a pokemon is the max level.
TODO:
Investigate wether one is able to set the level cap by modifying MAX_LEVEL EQU [0-255]
in constants/battle_constants.asm
.
1. Add Level Cap variable
First, we want to add a wLevelCap
variable to wram.asm
in the root folder.
In wram.asm
, go to line 2668, wBeverlyFightCount:: db ; unused
.
Since this byte is unused, you can replace it.
Replace this line with wLevelCap:: db
.
This is the value we'll be checking for the level cap
; fight counts
wJackFightCount:: db ; d9f2
- wBeverlyFightCount:: db ; unused
+ wLevelCap:: db
wHueyFightCount:: db
wGavenFightCount:: db
To set the level cap, write this in a script:
loadmem wLevelCap, [0-255] ; number from 0 to 255 representing what your level cap should be
2. Replace first level cap check
In engine/pokemon/experience.asm
, go to line 9: cp LOW(MAX_LEVEL + 1)
.
This is what we first need to change.
Before the ld a, d
on the line before it, add code to load the new level cap into register b
.
.next_level
inc d
+ ld a, [wLevelCap]
+ inc a
+ push bc
+ ld b, a
ld a, d
+ cp b
+ pop bc
cp LOW(MAX_LEVEL + 1)
jr z, .got_level
call CalcExpAtLevel
3. Replace the rest of the cap checks
There are now five more instances of MAX_LEVEL
that you'll need to change.
First, go to the .no_exp_overflow
label located in engine/battle/core.asm
.
Instead of storing the MAX_LEVEL
value, we load our custom max level.
.no_exp_overflow
ld a, [wCurPartyMon]
ld e, a
ld d, 0
ld hl, wPartySpecies
add hl, de
ld a, [hl]
ld [wCurSpecies], a
call GetBaseData
push bc
- ld d, MAX_LEVEL
+ push af
+ ld a, [wLevelCap]
+ ld d, a
+ pop af
callfar CalcExpAtLevel
Next, ctrl + f
for the next instance of MAX_LEVEL
, located in the .not_max_exp
label. You'll notice that the line before this reads ld a, [hl]
Before this line, load the level cap into register b. Then, after ld a, [hl]
, add a comparison and restore the bc
register. Here we use the comparison to control the jump.
.not_max_exp
; Check if the mon leveled up
xor a ; PARTYMON
ld [wMonType], a
predef CopyMonToTempMon
callfar CalcLevel
pop bc
ld hl, MON_LEVEL
add hl, bc
+ ld a, [wLevelCap]
+ push bc
+ ld b, a
ld a, [hl]
+ cp b
+ pop bc
- cp MAX_LEVEL
jp nc, .next_mon
Third, ctrl + f for the next instance of MAX_LEVEL, located in the AnimateExpBar
label. You'll notice there's a ld a, [wBattleMonLevel]
before it. Before this, add
AnimateExpBar:
push bc
ld hl, wCurPartyMon
ld a, [wCurBattleMon]
cp [hl]
jp nz, .finish
+ ld a, [wLevelCap]
+ push bc
+ ld b, a
ld a, [wBattleMonLevel]
+ cp b
+ pop bc
- cp MAX_LEVEL
jp nc, .finish
Fourth, ctrl + f for the next instance of MAX_LEVEL. Replace ld d, MAX_LEVEL
with loading the custom max level.
ld [hli], a
ld [hl], a
.NoOverflow:
+ push af
+ ld a, [wLevelCap]
+ ld d, a
+ pop af
callfar CalcExpAtLevel
ldh a, [hProduct + 1]
ld b, a
Fifth, ctrl + f for the final instance of MAX_LEVEL. You'll notice before it reads ld a, e
. Before this, lod the level cap into b, then do the comparison on that.
ld a, e
ld d, a
.LoopLevels:
+ ld a, [wLevelCap]
+ push bc
+ ld b, a
ld a, e
- cp MAX_LEVEL
+ cp b
+ pop bc
jr nc, .FinishExpBar
cp d
jr z, .FinishExpBar
inc a
Now you're done with replacing the max level checks with the level cap checks.
4. Optional: Remove exp. gain text at max level
You'll notice that the exp. gain text still displays when you reach the level cap.
To remove this, go to line 7059 in engine/battle/core.asm
, which should be about the lines of
.stat_exp_awarded
inc de
inc de
dec c
jr nz, .stat_exp_loop
+ pop bc
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [wLevelCap]
+ push bc
+ ld b, a
+ ld a, [hl]
+ cp b
+ pop bc
+ jp nc, .next_mon
+ push bc
xor a
ldh [hMultiplicand + 0], a
ldh [hMultiplicand + 1], a
ld a, [wEnemyMonBaseExp]
Next, go to
.EvenlyDivideExpAmongParticipants:
; count number of battle participants
ld a, [wBattleParticipantsNotFainted]
ld b, a
ld c, PARTY_LENGTH
ld d, 0
.count_loop
+ push bc
+ push de
+ ld a, [wLevelCap]
+ ld b, a
+ ld a, [wPartyCount]
+ cp c
+ jr c, .no_mon
+ ld a, c
+ dec a
+ ld hl, wPartyMon1Level
+ call GetPartyLocation
+ ld a, [hl]
+.no_mon
+ cp b
+ pop de
+ pop bc
+ jr nz, .gains_exp
+ srl b
+ ld a, d
+ jr .no_exp
+.gains_exp
xor a
srl b
adc d
ld d, a
+.no_exp
dec c
jr nz, .count_loop