Gain experience from catching Pokémon - pret/pokecrystal GitHub Wiki

This tutorial is for how to make it so that your party Pokémon get experience points from capturing wild Pokémon, as in generation VI onward. As you'll soon see, it's a pretty easy addition.

Contents

  1. Add a new function
  2. Call the function

1. Add a new function

Luckily for us, the UpdateBattleStateAndExperienceAfterEnemyFaint function in engine/battle/core.asm already does what we want, specifically the final part of it. This routine is called when your Pokémon knocks out an opposing Pokémon (either wild or a Trainer's). So we'll make use of it!

Edit engine/battle/core.asm:

 UpdateBattleStateAndExperienceAfterEnemyFaint:
 	call UpdateBattleMonInParty
  	...
 	ld a, [wBattleResult]
 	and BATTLERESULT_BITMASK
 	ld [wBattleResult], a ; WIN
+	; fallthrough
+ApplyExperienceAfterEnemyCaught:
 	call IsAnyMonHoldingExpShare
 	jr z, .skip_exp
 	ld hl, wEnemyMonBaseStats
 	ld b, wEnemyMonEnd - wEnemyMonBaseStats
 .loop
 	srl [hl]
 	inc hl
 	dec b
 	jr nz, .loop
 	...

Here we added a new label called ApplyExperienceAfterEnemyCaught, positioned just when the code starts dealing with battle experience and Stat Experience distribution among those who participated in battle (and those who have an Exp. Share equipped).

2. Call the function

We have a new function but we need to call it at the appropriate place. This is done in the file that dictates how a ball operates. Since these are in different banks, a farcall needs to be made instead of a regular call. But is that enough? Not really, we need to be a bit more careful with it.

Edit engine/items/item_effects.asm:

 PokeBallEffect:
 	ld a, [wBattleMode]
 	dec a
 	jp nz, UseBallInTrainerBattle
 	...
 .Transformed:
 	ld a, [wEnemyMonSpecies]
 	...
 	ld hl, Text_GotchaMonWasCaught
 	call PrintText

 	call ClearSprites
 
+	ld a, [wTempSpecies]
+	ld l, a
+	ld a, [wCurPartyLevel]
+	ld h, a
+	push hl
+	farcall ApplyExperienceAfterEnemyCaught
+	pop hl
+	ld a, l
+	ld [wCurPartySpecies], a
+	ld [wTempSpecies], a
+	ld a, h
+	ld [wCurPartyLevel], a
 
 	ld a, [wTempSpecies]
 	dec a
 	call CheckCaughtMon
 	...

Here we placed the code right after the game determines that the wild Pokémon has been caught, and is about to switch to the Pokédex/naming screen. Turns out just doing the farcall isn't enough. Indeed, if your Pokémon happens to level up, wCurPartyLevel gets overwritten. Even worse, wCurPartySpecies also gets overwritten which would cause you to capture the wrong species at a wrong level! To get the intended result, we need to store the values the game needs to add the proper Pokémon to your collection, and then retrieve them after the experience routine is over with.

And just like that, you're ready to catch 'em all and raise your Pokémon in one fell swoop.

Screenshot