Skip to content

Improving Fishing Rod Encounters

lotsobs edited this page Nov 26, 2025 · 1 revision

Introduction

As you probably know, fishing in the vanilla games is a largely fruitless endeavor, to the point that many experienced players ignore it almost entirely. The purpose of this tutorial is to show how to make fishing encounters far more viable for teambuilding during the average playthrough. First, for those who are curious, we'll go through exactly what makes the rods so awful. If that doesn't interest you, feel free to skip to the following section to get straight to the part where we update and improve the rods.

This is a fairly long process, so let's begin!

Why Are the Rods So Terrible?

To start things off, let's look at the code for the Old Rod. This can be found in engine\items\item_effects.asm; in an unmodified file it should be line 1826. The code looks like this:

ItemUseOldRod:
	call FishingInit
	jp c, ItemUseNotTime
	lb bc, 5, MAGIKARP
	ld a, $1 ; set bite
	jr RodResponse

Yep, that's it. The Old Rod is hard-coded to hook ONLY level 5 Magikarp. Terrible.

Next, let's take a peek at the code for the Good Rod (which immediately follows in the file, starting at line 1833):

ItemUseGoodRod:
	call FishingInit
	jp c, ItemUseNotTime
.RandomLoop
	call Random
	srl a
	jr c, .SetBite
	and %11
	cp 2
	jr nc, .RandomLoop
	; choose which monster appears
	ld hl, GoodRodMons
	add a
	ld c, a
	ld b, 0
	add hl, bc
	ld b, [hl]
	inc hl
	ld c, [hl]
	and a
.SetBite
	ld a, 0
	rla
	xor 1
	jr RodResponse

INCLUDE "data/wild/good_rod.asm"

Looks better, right? Well, if we head over to data/wild/good_rod.asm, we'll find that the Good Rod has a 50/50 chance of hooking either Goldeen or Poliwag at level 10, regardless of fishing location. Not quite as bad as the Old Rod, but still laughable.

Now let's move down to the Super Rod. The code for this is written in two chunks. The first chunk comes directly after the Good Rod code, starting on line 1861:

ItemUseSuperRod:
	call FishingInit
	jp c, ItemUseNotTime
	call ReadSuperRodData
	ld a, e
RodResponse:
	ld [wRodResponse], a

	dec a ; is there a bite?
	jr nz, .next
	; if yes, store level and species data
	ld a, 1
	ld [wMoveMissed], a
	ld a, b ; level
	ld [wCurEnemyLevel], a
	ld a, c ; species
	ld [wCurOpponent], a

.next
	ld hl, wWalkBikeSurfState
	ld a, [hl] ; store the value in a
	push af
	push hl
	ld [hl], 0
	farcall FishingAnim
	pop hl
	pop af
	ld [hl], a
	ret

The second chunk is actually near the very end of the file, starting at line 2843:

ReadSuperRodData:
; return e = 2 if no fish on this map
; return e = 1 if a bite, bc = level,species
; return e = 0 if no bite
	ld a, [wCurMap]
	ld de, 3 ; each fishing group is three bytes wide
	ld hl, SuperRodData
	call IsInArray
	jr c, .ReadFishingGroup
	ld e, $2 ; $2 if no fishing groups found
	ret

.ReadFishingGroup
; hl points to the fishing group entry in the index
	inc hl ; skip map id

	; read fishing group address
	ld a, [hli]
	ld h, [hl]
	ld l, a

	ld b, [hl] ; how many mons in group
	inc hl ; point to data
	ld e, $0 ; no bite yet

.RandomLoop
	call Random
	srl a
	ret c ; 50% chance of no battle

	and %11 ; 2-bit random number
	cp b
	jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate

	; get the mon
	add a
	ld c, a
	ld b, $0
	add hl, bc
	ld b, [hl] ; level
	inc hl
	ld c, [hl] ; species
	ld e, $1 ; $1 if there's a bite
	ret

INCLUDE "data/wild/super_rod.asm"

Now THIS looks promising! If you open data/wild/super_rod.asm you'll find that Super Rod encounters are structured as follows:

  • There are 10 distinct Fishing Groups
  • Each area of the game with water tiles is assigned one of the groups
  • Each Fishing group is assigned up to four Pokemon encounter slots

If you look through the encounter groups at data/wild/super_rod.asm, you'll find that they're quite lackluster, but this still provides a great template to build on. Now let's get to work improving all the rods!

Making All the Rods Function Like the Super Rod, Part 1:

If you didn't read the preceding section, go ahead and open engine\items\item_effects.asm. We'll start by modifying the Old Rod code to match the functionality of the Super Rod code. The Old Rod code begins on line 1833 (in an unmodified file); you can also use your editor's Find function and search for "ItemUseOldRod". Once you find the spot, make the following changes:

ItemUseOldRod:
	call FishingInit
	jp c, ItemUseNotTime
-	lb bc, 5, MAGIKARP
-	ld a, $1 ; set bite
+	call ReadOldRodData
+	ld a, e
	jr RodResponse

Note: this change will render the game temporarily "unmakeable" due to the line call ReadOldRodData, which references something that doesn't exist... yet. We'll fix this in Part 2 below. For now, let's do the same update to the Good Rod code, located immediately after the stuff we just changed:

ItemUseGoodRod:
	call FishingInit
	jp c, ItemUseNotTime
-.RandomLoop
-	call Random
-	srl a
-	jr c, .SetBite
-	and %11
-	cp 2
-	jr nc, .RandomLoop
-	; choose which monster appears
-	ld hl, GoodRodMons
-	add a
-	ld c, a
-	ld b, 0
-	add hl, bc
-	ld b, [hl]
-	inc hl
-	ld c, [hl]
-	and a
-.SetBite
-	ld a, 0
-	rla
-	xor 1
+	call ReadGoodRodData
+	ld a, e
	jr RodResponse
-
-INCLUDE "data/wild/good_rod.asm"

Similarly, call ReadGoodRodData causes issues that will be solved shortly. But for now, we've reached the end of Part 1! There is no need to modify the Super Rod data; you may notice that the new code for the Old and Good Rod is actually modeled based directly on the Super Rod code.

Making All the Rods Function Like the Super Rod, Part 2:

We remain within the same file here (engine\item\item_effects.asm), but move down near the very end of the file. Around line 2817 you'll find the routine ReadSuperRodData:. We'll be inserting the following code directly preceding it:

...
 INCLUDE "data/tilesets/water_tilesets.asm"

+ReadOldRodData:
+; return e = 2 if no fish on this map
+; return e = 1 if a bite, bc = level,species
+; return e = 0 if no bite
+	ld a, [wCurMap]
+	ld de, 3 ; each fishing group is three bytes wide
+	ld hl, OldRodData
+	call IsInArray
+	jr c, .ReadFishingGroup
+	ld e, $2 ; $2 if no fishing groups found
+	ret
+
+.ReadFishingGroup
+; hl points to the fishing group entry in the index
+	inc hl ; skip map id
+
+	; read fishing group address
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+
+	ld b, [hl] ; how many mons in group
+	inc hl ; point to data
+	ld e, $0 ; no bite yet
+
+.RandomLoop
+	call Random
+	srl a
+	ret c ; 50% chance of no battle
+
+	and %11 ; 2-bit random number
+	cp b
+	jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
+
+	; get the mon
+	add a
+	ld c, a
+	ld b, $0
+	add hl, bc
+	ld b, [hl] ; level
+	inc hl
+	ld c, [hl] ; species
+	ld e, $1 ; $1 if there's a bite
+	ret
+
+INCLUDE "data/wild/old_rod.asm"
+
+ReadGoodRodData:
+; return e = 2 if no fish on this map
+; return e = 1 if a bite, bc = level,species
+; return e = 0 if no bite
+	ld a, [wCurMap]
+	ld de, 3 ; each fishing group is three bytes wide
+	ld hl, GoodRodData
+	call IsInArray
+	jr c, .ReadFishingGroup
+	ld e, $2 ; $2 if no fishing groups found
+	ret
+
+.ReadFishingGroup
+; hl points to the fishing group entry in the index
+	inc hl ; skip map id
+
+	; read fishing group address
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+
+	ld b, [hl] ; how many mons in group
+	inc hl ; point to data
+	ld e, $0 ; no bite yet
+
+.RandomLoop
+	call Random
+	srl a
+	ret c ; 50% chance of no battle
+
+	and %11 ; 2-bit random number
+	cp b
+	jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
+
+	; get the mon
+	add a
+	ld c, a
+	ld b, $0
+	add hl, bc
+	ld b, [hl] ; level
+	inc hl
+	ld c, [hl] ; species
+	ld e, $1 ; $1 if there's a bite
+	ret
+
+INCLUDE "data/wild/good_rod.asm"
+
ReadSuperRodData:
...

Now we've eliminated the call issues, but there's one final problem to address: INCLUDE "data/wild/old_rod.asm" breaks things because we're trying to include a file that doesn't exist... yet. Fortunately, we'll fix that in the next section.

Making All the Rods Function Like the Super Rod, Part 3:

Still with me? Good... here's the part where we restore full functionality to all the rods. Go open the following two files:

  • data\wild\super_rod.asm
  • data\wild\good_rod.asm

The simplest thing to do here is to highlight all the text in data\wild\super_rod.asm and copy it. Move over to data\wild\good_rod.asm, highlight all the text, and paste over it. Finally, change all occurrences of the word 'Super' to 'Good' (mind your capital and lower case letters!). Your Good Rod file should now look like this (presented in its entirety):

; good rod encounters
GoodRodData:
	; map, fishing group
	dbw PALLET_TOWN,         .Group1
	dbw VIRIDIAN_CITY,       .Group1
	dbw CERULEAN_CITY,       .Group3
	dbw VERMILION_CITY,      .Group4
	dbw CELADON_CITY,        .Group5
	dbw FUCHSIA_CITY,        .Group10
	dbw CINNABAR_ISLAND,     .Group8
	dbw ROUTE_4,             .Group3
	dbw ROUTE_6,             .Group4
	dbw ROUTE_10,            .Group5
	dbw ROUTE_11,            .Group4
	dbw ROUTE_12,            .Group7
	dbw ROUTE_13,            .Group7
	dbw ROUTE_17,            .Group7
	dbw ROUTE_18,            .Group7
	dbw ROUTE_19,            .Group8
	dbw ROUTE_20,            .Group8
	dbw ROUTE_21,            .Group8
	dbw ROUTE_22,            .Group2
	dbw ROUTE_23,            .Group9
	dbw ROUTE_24,            .Group3
	dbw ROUTE_25,            .Group3
	dbw CERULEAN_GYM,        .Group3
	dbw VERMILION_DOCK,      .Group4
	dbw SEAFOAM_ISLANDS_B3F, .Group8
	dbw SEAFOAM_ISLANDS_B4F, .Group8
	dbw SAFARI_ZONE_EAST,    .Group6
	dbw SAFARI_ZONE_NORTH,   .Group6
	dbw SAFARI_ZONE_WEST,    .Group6
	dbw SAFARI_ZONE_CENTER,  .Group6
	dbw CERULEAN_CAVE_2F,    .Group9
	dbw CERULEAN_CAVE_B1F,   .Group9
	dbw CERULEAN_CAVE_1F,    .Group9
	db -1 ; end

; fishing groups
; number of monsters, followed by level/monster pairs

.Group1:
	db 2
	db 15, TENTACOOL
	db 15, POLIWAG

.Group2:
	db 2
	db 15, GOLDEEN
	db 15, POLIWAG

.Group3:
	db 3
	db 15, PSYDUCK
	db 15, GOLDEEN
	db 15, KRABBY

.Group4:
	db 2
	db 15, KRABBY
	db 15, SHELLDER

.Group5:
	db 2
	db 23, POLIWHIRL
	db 15, SLOWPOKE

.Group6:
	db 4
	db 15, DRATINI
	db 15, KRABBY
	db 15, PSYDUCK
	db 15, SLOWPOKE

.Group7:
	db 4
	db 5, TENTACOOL
	db 15, KRABBY
	db 15, GOLDEEN
	db 15, MAGIKARP

.Group8:
	db 4
	db 15, STARYU
	db 15, HORSEA
	db 15, SHELLDER
	db 15, GOLDEEN

.Group9:
	db 4
	db 23, SLOWBRO
	db 23, SEAKING
	db 23, KINGLER
	db 23, SEADRA

.Group10:
	db 4
	db 23, SEAKING
	db 15, KRABBY
	db 15, GOLDEEN
	db 15, MAGIKARP

Next, we'll open a fresh new file. Once again, paste all the text from data\wild\super_rod.asm, then edit every occurrence of the word 'Super' to say 'Old' instead. Your file should look like this:

; old rod encounters
OldRodData:
	; map, fishing group
	dbw PALLET_TOWN,         .Group1
	dbw VIRIDIAN_CITY,       .Group1
	dbw CERULEAN_CITY,       .Group3
	dbw VERMILION_CITY,      .Group4
	dbw CELADON_CITY,        .Group5
	dbw FUCHSIA_CITY,        .Group10
	dbw CINNABAR_ISLAND,     .Group8
	dbw ROUTE_4,             .Group3
	dbw ROUTE_6,             .Group4
	dbw ROUTE_10,            .Group5
	dbw ROUTE_11,            .Group4
	dbw ROUTE_12,            .Group7
	dbw ROUTE_13,            .Group7
	dbw ROUTE_17,            .Group7
	dbw ROUTE_18,            .Group7
	dbw ROUTE_19,            .Group8
	dbw ROUTE_20,            .Group8
	dbw ROUTE_21,            .Group8
	dbw ROUTE_22,            .Group2
	dbw ROUTE_23,            .Group9
	dbw ROUTE_24,            .Group3
	dbw ROUTE_25,            .Group3
	dbw CERULEAN_GYM,        .Group3
	dbw VERMILION_DOCK,      .Group4
	dbw SEAFOAM_ISLANDS_B3F, .Group8
	dbw SEAFOAM_ISLANDS_B4F, .Group8
	dbw SAFARI_ZONE_EAST,    .Group6
	dbw SAFARI_ZONE_NORTH,   .Group6
	dbw SAFARI_ZONE_WEST,    .Group6
	dbw SAFARI_ZONE_CENTER,  .Group6
	dbw CERULEAN_CAVE_2F,    .Group9
	dbw CERULEAN_CAVE_B1F,   .Group9
	dbw CERULEAN_CAVE_1F,    .Group9
	db -1 ; end

; fishing groups
; number of monsters, followed by level/monster pairs

.Group1:
	db 2
	db 15, TENTACOOL
	db 15, POLIWAG

.Group2:
	db 2
	db 15, GOLDEEN
	db 15, POLIWAG

.Group3:
	db 3
	db 15, PSYDUCK
	db 15, GOLDEEN
	db 15, KRABBY

.Group4:
	db 2
	db 15, KRABBY
	db 15, SHELLDER

.Group5:
	db 2
	db 23, POLIWHIRL
	db 15, SLOWPOKE

.Group6:
	db 4
	db 15, DRATINI
	db 15, KRABBY
	db 15, PSYDUCK
	db 15, SLOWPOKE

.Group7:
	db 4
	db 5, TENTACOOL
	db 15, KRABBY
	db 15, GOLDEEN
	db 15, MAGIKARP

.Group8:
	db 4
	db 15, STARYU
	db 15, HORSEA
	db 15, SHELLDER
	db 15, GOLDEEN

.Group9:
	db 4
	db 23, SLOWBRO
	db 23, SEAKING
	db 23, KINGLER
	db 23, SEADRA

.Group10:
	db 4
	db 23, SEAKING
	db 15, KRABBY
	db 15, GOLDEEN
	db 15, MAGIKARP

Now save this file with the file name old_rod.asm. Make sure it has the .asm file extension, and save it in the same folder alongside the other two rods' encounter data.

Congratulations! All three fishing rods are now fully functional!

One small snag you may have picked up on... all the rods now fish up the EXACT same sets of encounters. In the next (and final!) section we'll cover how to modify the encounters so you can customize them to your liking!

Modifying the Encounters

Rest assured; all the heavy stuff is now behind us. All the remaining work is very simple, if perhaps tedious. Let's look at data\wild\old_rod.asm to get started. We can see that the encounter data is structured as follows (repeated from the explanation section at the beginning):

  • There are 10 distinct Fishing Groups
  • Each area of the game with water tiles is assigned one of the groups
  • Each Fishing group is assigned up to four Pokemon encounter slots

We'll start by messing with the encounters in Group 1. Each entry contains a number (for level) and name (for species). Try making the following changes:

.Group1:
	db 2
-	db 15, TENTACOOL
-	db 15, POLIWAG
+	db 10, MAGIKARP
+	db 10, GOLDEEN

Looking at the top section of this file, where the maps and fishing groups are listed, we can see that Group 1 is associated with the water in Pallet Town and Viridian City. This means that the Old Rod will catch either a level 10 Magikarp or Goldeen in either of these locations. Prior to this edit you would catch a level 15 Tentacool or Poliwag instead. Go make your game and give it a try.

But what if we want to expand the list of Pokemon in a specific group? Sticking with Group 1, we'll edit the line that says db 2. The 2, as you may guess, tells us how many group members there are. Let's make the following edits:

.Group1:
-	db 2
+	db 4
	db 10, MAGIKARP
	db 10, GOLDEEN
+	db 10, HORSEA
+	db 10, PSYDUCK

Now, once you make the game, your fishing encounters in Pallet Town and Viridian City will include Horsea and Psyduck alongside the Magikarp and Goldeen that were already there. With this knowledge you can now edit each group however you desire.

Note: To the best of my knowledge, each group has a maximum size of 4. Higher numbers and longer lists will not create any errors when you make the game, but group entries beyond the 4th Pokemon just seem to be ignored entirely. They'll never be encountered despite being listed.

Changing an area's Fishing Group assignment is extremely simple. Try the following edit:

...
	dbw PALLET_TOWN,         .Group1
	dbw VIRIDIAN_CITY,       .Group1
	dbw CERULEAN_CITY,       .Group3
-	dbw VERMILION_CITY,      .Group4
+	dbw VERMILION_CITY,      .Group1
	dbw CELADON_CITY,        .Group5
	dbw FUCHSIA_CITY,        .Group10
...

With this change, Vermilion City will now have identical fishing encounters to Pallet Town and Viridian City, since Group 1 is assigned to all three locations.

Finally, we'll wrap things up by creating an entirely new fishing group. Again, this process is actually really easy. We're at the end of the tutorial, so let's try something silly and fun with these edits. Go to the very end of the file and insert your new group:

...
.Group10:
	db 4
	db 23, SEAKING
	db 15, KRABBY
	db 15, GOLDEEN
	db 15, MAGIKARP

+.Group11:
+	db 4
+	db 2, RHYDON
+	db 2, DITTO
+	db 2, DIGLETT
+	db 2, MAGMAR

Now scroll up and assign your new group to a location... let's say, Fuchsia City. Why not?

...
	dbw CELADON_CITY,        .Group6
-	dbw FUCHSIA_CITY,        .Group6
+	dbw FUCHSIA_CITY,        .Group11
	dbw CINNABAR_ISLAND,     .Group8
...

With this edit, you can use your Old Rod in the Fuchsia Fishing Guru's backyard pond to hook Rhydon, Ditto, Diglett, or Magmar... all at level 2!

Note: I have not found whether there is a maximum number of fishing groups you can create. Given that there are only 32 fishable areas in the game (There are 33 listed locations, but Cerulean Cave 2F has no water...), you could perhaps create a customized list for each area, for each rod, if you're industrious enough.

With that, we've FINALLY reached the end of the tutorial. Best of luck to you as you edit all these encounters; it's certainly a commitment.

Thanks for sticking around through this long process, and I hope it's helpful to you.

Clone this wiki locally