summaryrefslogtreecommitdiff
path: root/Level-cap.md
blob: fbe21ffe3b6ab806de7aec6ce1edeb87bc7ba369 (plain)
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
```