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 ```diff ; 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`. ```diff .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. ```diff .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. ```diff .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 ```diff 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. ```diff 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. ```diff 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 ```diff .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 ```diff .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 ```