1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
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
```
|