Set DVs to 0 for all your Pokemon - pret/pokecrystal GitHub Wiki

In generations 1 and 2, the equivalent of Individual Values (IVs) are Determinant values (DVs), and only four DVs are stored for each Pokémon: Attack, Defense, Speed, and Special (used for both Sp.Atk and Sp.Def); the HP DV is determined from the DVs stored for the other four. Unlike IVs, DVs range from 0-15.

If you want to make it so that the player can only get Pokémon with 0 DVs, this tutorial will teach you how do to it.

Contents

  1. Force gift Pokémon to have 0 DVs
  2. Force regular wild Pokémon to have 0 DVs
  3. Force roaming Pokémon to have 0 DVs
  4. Force the shiny Gyarados to have 0 DVs

1. Force gift Pokémon to have 0 DVs

The routine TryAddMonToParty, as the name suggests, tries to add a Pokémon to either the player's or the opponent's party depending on some parameters, and it contains a subroutine called GeneratePartyMonStats that generates the Pokémon's stats. If the player gets a Pokémon as a gift, it randomly generates its DVs, so we'll force the subroutine to set them to 0. For that, let's edit engine/pokemon/move_mon.asm:

GeneratePartyMonStats:
 	...
 .registerpokedex
 	ld a, [wCurPartySpecies]
 	ld [wTempSpecies], a
 	dec a
 	push de
 	call CheckCaughtMon
 	ld a, [wTempSpecies]
 	dec a
 	call SetSeenAndCaughtMon
 	pop de
 
 	pop hl
 	push hl
 	ld a, [wBattleMode]
 	and a
 	jr nz, .copywildmonDVs
 
-	call Random
-	ld b, a
-	call Random
-	ld c, a
+	ld b, 0
+	ld c, 0
 .initializeDVs
 	ld a, b
 	ld [de], a
 	inc de
 	ld a, c
 	ld [de], a
 	inc de
	...

Register b stores both the Attack (high nibble) and Defense (low nibble) DVs, while c stores both the Speed (high nibble) and Special (low nibble) DVs, so loading 0 affects both nibbles of a byte (if you don't know what a nibble is, Wikipedia is your best friend).

In any case, this is all for gift Pokémon, but wild and roaming Pokémon use another routine called LoadEnemyMon to determine their DVs.

2. Force regular wild Pokémon to have 0 DVs

Edit engine/battle/core.asm:

 LoadEnemyMon:
 ; Initialize enemy monster parameters
 ; To do this we pull the species from wTempEnemyMonSpecies
	...
 .GenerateDVs:
; Generate new random DVs
-	call BattleRandom
-	ld b, a
-	call BattleRandom
-       ld c, a
+       ld b, 0
+       ld c, 0
 .UpdateDVs:
 ; Input DVs in register bc
 	ld hl, wEnemyMonDVs
 	ld a, b
 	ld [hli], a
 	ld [hl], c
	...

3. Force roaming Pokémon to have 0 DVs

Edit engine/battle/core.asm:

 LoadEnemyMon:
 	...
 ; If it hasn't, we need to initialize the DVs
 ; (HP is initialized at the end of the battle)
 	call GetRoamMonDVs
 	inc hl
-	call BattleRandom
+	ld a, 0
 	ld [hld], a
 	ld c, a
-	call BattleRandom
 	ld [hl], a
 	ld b, a
 ; We're done with DVs
 	jr .UpdateDVs
	...

If you want to optimize this, you can replace ld a, 0 with xor a.

4. Force shiny Gyarados to have 0 DVs

In generation 2, shininess used to be determined by DVs, so the shiny Gyarados from the Lake of Rage has fixed DVs corresponding to valid shiny values. However, if you edit these values, this Gyarados won't be shiny anymore, so it's up to your discretion. Providing possible solutions is out of the scope of this tutorial.

Let's edit constants/battle_constants.asm:

 ; shiny dvs
-DEF ATKDEFDV_SHINY EQU $EA
-DEF SPDSPCDV_SHINY EQU $AA
+DEF ATKDEFDV_SHINY EQU 0
+DEF SPDSPCDV_SHINY EQU 0

And that's it! All the Pokémon the player can get will have 0 DVs. Enjoy your challenging Pokémon game!