summaryrefslogtreecommitdiff
path: root/engine/wildmons.asm
diff options
context:
space:
mode:
Diffstat (limited to 'engine/wildmons.asm')
-rwxr-xr-xengine/wildmons.asm1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/engine/wildmons.asm b/engine/wildmons.asm
new file mode 100755
index 000000000..6f39e19dc
--- /dev/null
+++ b/engine/wildmons.asm
@@ -0,0 +1,1057 @@
+LoadWildMonData: ; 29ff8
+ call _GrassWildmonLookup
+ jr c, .copy
+ ld hl, wd25a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ jr .done_copy
+.copy
+ inc hl
+ inc hl
+ ld de, wd25a
+ ld bc, $3
+ call CopyBytes
+.done_copy
+ call _WaterWildmonLookup
+ ld a, $0
+ jr nc, .no_copy
+ inc hl
+ inc hl
+ ld a, [hl]
+.no_copy
+ ld [wd25d], a
+ ret
+
+Function2a01f: ; 2a01f
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call ByteFill
+ ld a, e
+ and a
+ jr nz, .kanto
+ decoord 0, 0
+ ld hl, JohtoGrassWildMons
+ call Function2a052
+ ld hl, JohtoWaterWildMons
+ call Function2a06e
+ call Function2a0b7
+ call Function2a0cf
+ ret
+
+.kanto
+ decoord 0, 0
+ ld hl, KantoGrassWildMons
+ call Function2a052
+ ld hl, KantoWaterWildMons
+ jp Function2a06e
+; 2a052
+
+Function2a052: ; 2a052
+.loop
+ ld a, [hl]
+ cp $ff
+ ret z
+ push hl
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+rept 3
+ inc hl
+endr
+ ld a, $15
+ call Function2a088
+ jr nc, .next
+ ld [de], a
+ inc de
+
+.next
+ pop hl
+ ld bc, $2f
+ add hl, bc
+ jr .loop
+; 2a06e
+
+Function2a06e: ; 2a06e
+.loop
+ ld a, [hl]
+ cp $ff
+ ret z
+ push hl
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ inc hl
+ ld a, $3
+ call Function2a088
+ jr nc, .next
+ ld [de], a
+ inc de
+
+.next
+ pop hl
+ ld bc, 9
+ add hl, bc
+ jr .loop
+; 2a088
+
+Function2a088: ; 2a088
+ inc hl
+.loop
+ push af
+ ld a, [wd265]
+ cp [hl]
+ jr z, .found
+rept 2
+ inc hl
+endr
+ pop af
+ dec a
+ jr nz, .loop
+ and a
+ ret
+
+.found
+ pop af
+ jp Function2a09c
+; 2a09c
+
+Function2a09c: ; 2a09c
+ push de
+ call GetWorldMapLocation
+ ld c, a
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH * SCREEN_HEIGHT
+.loop
+ ld a, [hli]
+ cp c
+ jr z, .found
+ dec de
+ ld a, e
+ or d
+ jr nz, .loop
+ ld a, c
+ pop de
+ scf
+ ret
+
+.found
+ pop de
+ and a
+ ret
+; 2a0b7
+
+Function2a0b7: ; 2a0b7
+ ld a, [wRoamMon1Species]
+ ld b, a
+ ld a, [wd265]
+ cp b
+ ret nz
+ ld a, [wRoamMon1MapGroup]
+ ld b, a
+ ld a, [wRoamMon1MapNumber]
+ ld c, a
+ call Function2a09c
+ ret nc
+ ld [de], a
+ inc de
+ ret
+; 2a0cf
+
+Function2a0cf: ; 2a0cf
+ ld a, [wRoamMon2Species]
+ ld b, a
+ ld a, [wd265]
+ cp b
+ ret nz
+ ld a, [wRoamMon2MapGroup]
+ ld b, a
+ ld a, [wRoamMon2MapNumber]
+ ld c, a
+ call Function2a09c
+ ret nc
+ ld [de], a
+ inc de
+ ret
+; 2a0e7
+
+TryWildEncounter:: ; 2a0e7
+; Try to trigger a wild encounter.
+ call .EncounterRate
+ jr nc, .no_battle
+ call ChooseWildEncounter
+ jr nz, .no_battle
+ call CheckRepelEffect
+ jr nc, .no_battle
+ xor a
+ ret
+
+.no_battle
+ xor a ; BATTLETYPE_NORMAL
+ ld [TempWildMonSpecies], a
+ ld [BattleType], a
+ ld a, 1
+ and a
+ ret
+; 2a103
+
+.EncounterRate: ; 2a103
+ call GetMapEncounterRate
+ call ApplyMusicEffectOnEncounterRate
+ call ApplyCleanseTagEffectOnEncounterRate
+ call Random
+ cp b
+ ret
+; 2a111
+
+GetMapEncounterRate: ; 2a111
+ ld hl, wd25a
+ call CheckOnWater
+ ld a, 3
+ jr z, .ok
+ ld a, [TimeOfDay]
+.ok
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ ret
+; 2a124
+
+ApplyMusicEffectOnEncounterRate:: ; 2a124
+; Pokemon March and Ruins of Alph signal double encounter rate.
+; Pokemon Lullaby halves encounter rate.
+ ld a, [wMapMusic]
+ cp MUSIC_POKEMON_MARCH
+ jr z, .double
+ cp MUSIC_RUINS_OF_ALPH_RADIO
+ jr z, .double
+ cp MUSIC_POKEMON_LULLABY
+ ret nz
+ srl b
+ ret
+
+.double
+ sla b
+ ret
+; 2a138
+
+ApplyCleanseTagEffectOnEncounterRate:: ; 2a138
+; Cleanse Tag halves encounter rate.
+ ld hl, PartyMon1Item
+ ld de, PARTYMON_STRUCT_LENGTH
+ ld a, [PartyCount]
+ ld c, a
+.loop
+ ld a, [hl]
+ cp CLEANSE_TAG
+ jr z, .cleansetag
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+.cleansetag
+ srl b
+ ret
+; 2a14f
+
+ChooseWildEncounter: ; 2a14f
+ call LoadWildMonDataPointer
+ jp nc, .nowildbattle
+ call CheckEncounterRoamMon
+ jp c, .startwildbattle
+
+rept 3
+ inc hl
+endr
+ call CheckOnWater
+ ld de, .WaterMonTable
+ jr z, .watermon
+rept 2
+ inc hl
+endr
+ ld a, [TimeOfDay]
+ ld bc, $e
+ call AddNTimes
+ ld de, .GrassMonTable
+
+.watermon
+; hl contains the pointer to the wild mon data, let's save that to the stack
+ push hl
+.randomloop
+ call Random
+ cp 100
+ jr nc, .randomloop
+ inc a ; 1 <= a <= 100
+ ld b, a
+ ld h, d
+ ld l, e
+; This next loop chooses which mon to load up.
+.prob_bracket_loop
+ ld a, [hli]
+ cp b
+ jr nc, .got_it
+ inc hl
+ jr .prob_bracket_loop
+
+.got_it
+ ld c, [hl]
+ ld b, 0
+ pop hl
+ add hl, bc ; this selects our mon
+ ld a, [hli]
+ ld b, a
+; If the Pokemon is encountered by surfing, we need to give the levels some variety.
+ call CheckOnWater
+ jr nz, .ok
+; Check if we buff the wild mon, and by how much.
+ call Random
+ cp 35 percent
+ jr c, .ok
+ inc b
+ cp 65 percent
+ jr c, .ok
+ inc b
+ cp 85 percent
+ jr c, .ok
+ inc b
+ cp 95 percent
+ jr c, .ok
+ inc b
+; Store the level
+.ok
+ ld a, b
+ ld [CurPartyLevel], a
+ ld b, [hl]
+ ; ld a, b
+ call ValidateTempWildMonSpecies
+ jr c, .nowildbattle
+
+ ld a, b ; This is in the wrong place.
+ cp UNOWN
+ jr nz, .done
+
+ ld a, [UnlockedUnowns]
+ and a
+ jr z, .nowildbattle
+
+.done
+ jr .loadwildmon
+
+.nowildbattle
+ ld a, 1
+ and a
+ ret
+
+.loadwildmon
+ ld a, b
+ ld [TempWildMonSpecies], a
+
+.startwildbattle
+ xor a
+ ret
+; 2a1cb
+
+.GrassMonTable: ; 2a1cb
+ db 30, $0 ; 30% chance
+ db 60, $2 ; 30% chance
+ db 80, $4 ; 20% chance
+ db 90, $6 ; 10% chance
+ db 95, $8 ; 5% chance
+ db 99, $a ; 4% chance
+ db 100, $c ; 1% chance
+; 2a1d9
+
+.WaterMonTable: ; 2a1d9
+ db 60, $0 ; 60% chance
+ db 90, $2 ; 30% chance
+ db 100, $4 ; 10% chance
+; 2a1df
+
+CheckRepelEffect:: ; 2a1df
+; If there is no active Repel, there's no need to be here.
+ ld a, [wRepelEffect]
+ and a
+ jr z, .encounter
+; Get the first Pokemon in your party that isn't fainted.
+ ld hl, PartyMon1HP
+ ld bc, PARTYMON_STRUCT_LENGTH - 1
+.loop
+ ld a, [hli]
+ or [hl]
+ jr nz, .ok
+ add hl, bc
+ jr .loop
+
+.ok
+; to PartyMonLevel
+rept 4
+ dec hl
+endr
+
+ ld a, [CurPartyLevel]
+ cp [hl]
+ jr nc, .encounter
+ and a
+ ret
+
+.encounter
+ scf
+ ret
+; 2a200
+
+LoadWildMonDataPointer: ; 2a200
+ call CheckOnWater
+ jr z, _WaterWildmonLookup
+
+_GrassWildmonLookup: ; 2a205
+ ld hl, SwarmGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call _SwarmWildmonCheck
+ ret c
+ ld hl, JohtoGrassWildMons
+ ld de, KantoGrassWildMons
+ call _JohtoWildmonCheck
+ ld bc, GRASS_WILDDATA_LENGTH
+ jr _NormalWildmonOK
+
+_WaterWildmonLookup: ; 2a21d
+ ld hl, SwarmWaterWildMons
+ ld bc, WATER_WILDDATA_LENGTH
+ call _SwarmWildmonCheck
+ ret c
+ ld hl, JohtoWaterWildMons
+ ld de, KantoWaterWildMons
+ call _JohtoWildmonCheck
+ ld bc, WATER_WILDDATA_LENGTH
+ jr _NormalWildmonOK
+
+_JohtoWildmonCheck
+ call IsInJohto
+ and a
+ ret z
+ ld h, d
+ ld l, e
+ ret
+
+_SwarmWildmonCheck
+ call CopyCurrMapDE
+ push hl
+ ld hl, SwarmFlags
+ bit 2, [hl]
+ pop hl
+ jr z, .CheckYanma
+ ld a, [wdfcc]
+ cp d
+ jr nz, .CheckYanma
+ ld a, [wdfcd]
+ cp e
+ jr nz, .CheckYanma
+ call LookUpWildmonsForMapDE
+ jr nc, _NoSwarmWildmon
+ scf
+ ret
+
+.CheckYanma
+ push hl
+ ld hl, SwarmFlags
+ bit 3, [hl]
+ pop hl
+ jr z, _NoSwarmWildmon
+ ld a, [wdc5a]
+ cp d
+ jr nz, _NoSwarmWildmon
+ ld a, [wdc5b]
+ cp e
+ jr nz, _NoSwarmWildmon
+ call LookUpWildmonsForMapDE
+ jr nc, _NoSwarmWildmon
+ scf
+ ret
+
+_NoSwarmWildmon
+ and a
+ ret
+
+_NormalWildmonOK
+ call CopyCurrMapDE
+ jr LookUpWildmonsForMapDE
+; 2a27f
+
+CopyCurrMapDE: ; 2a27f
+ ld a, [MapGroup]
+ ld d, a
+ ld a, [MapNumber]
+ ld e, a
+ ret
+; 2a288
+
+LookUpWildmonsForMapDE: ; 2a288
+ push hl
+ ld a, [hl]
+ inc a
+ jr z, .nope
+ ld a, d
+ cp [hl]
+ jr nz, .next
+ inc hl
+ ld a, e
+ cp [hl]
+ jr z, .yup
+
+.next
+ pop hl
+ add hl, bc
+ jr LookUpWildmonsForMapDE
+
+.nope
+ pop hl
+ and a
+ ret
+
+.yup
+ pop hl
+ scf
+ ret
+; 2a2a0
+
+
+InitRoamMons: ; 2a2a0
+; initialize wRoamMon structs
+
+; species
+ ld a, RAIKOU
+ ld [wRoamMon1Species], a
+ ld a, ENTEI
+ ld [wRoamMon2Species], a
+; ld a, SUICUNE
+; ld [wRoamMon3Species], a
+
+; level
+ ld a, 40
+ ld [wRoamMon1Level], a
+ ld [wRoamMon2Level], a
+; ld [wRoamMon3Level], a
+
+; raikou starting map
+ ld a, GROUP_ROUTE_42
+ ld [wRoamMon1MapGroup], a
+ ld a, MAP_ROUTE_42
+ ld [wRoamMon1MapNumber], a
+
+; entei starting map
+ ld a, GROUP_ROUTE_37
+ ld [wRoamMon2MapGroup], a
+ ld a, MAP_ROUTE_37
+ ld [wRoamMon2MapNumber], a
+
+; suicune starting map
+; ld a, GROUP_ROUTE_38
+; ld [wRoamMon3MapGroup], a
+; ld a, MAP_ROUTE_38
+; ld [wRoamMon3MapNumber], a
+
+; hp
+ xor a ; generate new stats
+ ld [wRoamMon1HP], a
+ ld [wRoamMon2HP], a
+; ld [wRoamMon3HP], a
+
+ ret
+; 2a2ce
+
+
+CheckEncounterRoamMon: ; 2a2ce
+ push hl
+; Don't trigger an encounter if we're on water.
+ call CheckOnWater
+ jr z, .DontEncounterRoamMon
+; Load the current map group and number to de
+ call CopyCurrMapDE
+; Randomly select a beast.
+ call Random
+ cp 100 ; 25/64 chance
+ jr nc, .DontEncounterRoamMon
+ and %00000011 ; Of that, a 3/4 chance. Running total: 75/256, or around 29.3%.
+ jr z, .DontEncounterRoamMon
+ dec a ; 1/3 chance that it's Entei, 1/3 chance that it's Raikou
+; Compare its current location with yours
+ ld hl, wRoamMon1MapGroup
+ ld c, a
+ ld b, 0
+ ld a, 7 ; length of the RoamMon struct
+ call AddNTimes
+ ld a, d
+ cp [hl]
+ jr nz, .DontEncounterRoamMon
+ inc hl
+ ld a, e
+ cp [hl]
+ jr nz, .DontEncounterRoamMon
+; We've decided to take on a beast, so stage its information for battle.
+rept 3
+ dec hl
+endr
+ ld a, [hli]
+ ld [TempWildMonSpecies], a
+ ld a, [hl]
+ ld [CurPartyLevel], a
+ ld a, BATTLETYPE_ROAMING
+ ld [BattleType], a
+
+ pop hl
+ scf
+ ret
+
+.DontEncounterRoamMon
+ pop hl
+ and a
+ ret
+; 2a30d
+
+
+UpdateRoamMons: ; 2a30d
+ ld a, [wRoamMon1MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipRaikou
+ ld b, a
+ ld a, [wRoamMon1MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon1MapGroup], a
+ ld a, c
+ ld [wRoamMon1MapNumber], a
+
+.SkipRaikou
+ ld a, [wRoamMon2MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipEntei
+ ld b, a
+ ld a, [wRoamMon2MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon2MapGroup], a
+ ld a, c
+ ld [wRoamMon2MapNumber], a
+
+.SkipEntei
+ ld a, [wRoamMon3MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipSuicune
+ ld b, a
+ ld a, [wRoamMon3MapNumber]
+ ld c, a
+ call .Update
+ ld a, b
+ ld [wRoamMon3MapGroup], a
+ ld a, c
+ ld [wRoamMon3MapNumber], a
+
+.SkipSuicune
+ jp _BackUpMapIndices
+; 2a355
+
+
+.Update: ; 2a355
+ ld hl, RoamMaps
+.loop
+; Are we at the end of the table?
+ ld a, [hl]
+ cp -1
+ ret z
+; Is this the correct entry?
+ ld a, b
+ cp [hl]
+ jr nz, .next
+ inc hl
+ ld a, c
+ cp [hl]
+ jr z, .yes
+; We don't have the correct entry yet, so let's continue. A 0 terminates each entry.
+.next
+ ld a, [hli]
+ and a
+ jr nz, .next
+ jr .loop
+
+; We have the correct entry now, so let's choose a random map from it.
+.yes
+ inc hl
+ ld d, h
+ ld e, l
+.update_loop
+ ld h, d
+ ld l, e
+; Choose which map to warp to.
+ call Random
+ and $1f ; 1/8n chance it moves to a completely random map, where n is the number of roaming connections from the current map.
+ jr z, JumpRoamMon
+ and 3
+ cp [hl]
+ jr nc, .update_loop ; invalid index, try again
+ inc hl
+ ld c, a
+ ld b, $0
+rept 2
+ add hl, bc
+endr
+ ld a, [wdfe7]
+ cp [hl]
+ jr nz, .done
+ inc hl
+ ld a, [wdfe6]
+ cp [hl]
+ jr z, .update_loop
+ dec hl
+
+.done
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ret
+
+JumpRoamMons: ; 2a394
+ ld a, [wRoamMon1MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipRaikou
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon1MapGroup], a
+ ld a, c
+ ld [wRoamMon1MapNumber], a
+.SkipRaikou
+
+ ld a, [wRoamMon2MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipEntei
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon2MapGroup], a
+ ld a, c
+ ld [wRoamMon2MapNumber], a
+.SkipEntei
+
+ ld a, [wRoamMon3MapGroup]
+ cp GROUP_N_A
+ jr z, .SkipSuicune
+ call JumpRoamMon
+ ld a, b
+ ld [wRoamMon3MapGroup], a
+ ld a, c
+ ld [wRoamMon3MapNumber], a
+.SkipSuicune
+
+ jp _BackUpMapIndices
+
+JumpRoamMon: ; 2a3cd
+.loop
+ ld hl, RoamMaps
+.innerloop1 ; This loop is completely unnecessary.
+ call Random ; Choose a random number
+ and $f ; Take the lower nybble only. This gives a number between 0 and 15.
+ cp $10 ; If the number is greater than or equal to 16, loop back and try again.
+ jr nc, .innerloop1 ; I'm sure you can guess why this check is bogus.
+ inc a
+ ld b, a
+.innerloop2 ; Loop to get hl to the address of the chosen roam map.
+ dec b
+ jr z, .ok
+.innerloop3 ; Loop to skip the current roam map, which is terminated by a 0.
+ ld a, [hli]
+ and a
+ jr nz, .innerloop3
+ jr .innerloop2
+; Check to see if the selected map is the one the player is currently in. If so, try again.
+.ok
+ ld a, [MapGroup]
+ cp [hl]
+ jr nz, .done
+ inc hl
+ ld a, [MapNumber]
+ cp [hl]
+ jr z, .loop
+ dec hl
+; Return the map group and number in bc.
+.done
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ret
+; 2a3f6
+
+_BackUpMapIndices: ; 2a3f6
+ ld a, [wdfe4]
+ ld [wdfe6], a
+ ld a, [wdfe5]
+ ld [wdfe7], a
+ ld a, [MapNumber]
+ ld [wdfe4], a
+ ld a, [MapGroup]
+ ld [wdfe5], a
+ ret
+; 2a40f
+
+RoamMaps: ; 2a40f
+; Maps that roaming monsters can be on,
+; and possible maps they can jump to.
+; Notably missing are Route 40 and
+; Route 41, which are water routes.
+ roam_map ROUTE_29, 2, ROUTE_30, ROUTE_46
+ roam_map ROUTE_30, 2, ROUTE_29, ROUTE_31
+ roam_map ROUTE_31, 3, ROUTE_30, ROUTE_32, ROUTE_36
+ roam_map ROUTE_32, 3, ROUTE_36, ROUTE_31, ROUTE_33
+ roam_map ROUTE_33, 2, ROUTE_32, ROUTE_34
+ roam_map ROUTE_34, 2, ROUTE_33, ROUTE_35
+ roam_map ROUTE_35, 2, ROUTE_34, ROUTE_36
+ roam_map ROUTE_36, 4, ROUTE_35, ROUTE_31, ROUTE_32, ROUTE_37
+ roam_map ROUTE_37, 3, ROUTE_36, ROUTE_38, ROUTE_42
+ roam_map ROUTE_38, 3, ROUTE_37, ROUTE_39, ROUTE_42
+ roam_map ROUTE_39, 1, ROUTE_38
+ roam_map ROUTE_42, 4, ROUTE_43, ROUTE_44, ROUTE_37, ROUTE_38
+ roam_map ROUTE_43, 2, ROUTE_42, ROUTE_44
+ roam_map ROUTE_44, 3, ROUTE_42, ROUTE_43, ROUTE_45
+ roam_map ROUTE_45, 2, ROUTE_44, ROUTE_46
+ roam_map ROUTE_46, 2, ROUTE_45, ROUTE_29
+ db -1
+; 2a4a0
+
+ValidateTempWildMonSpecies: ; 2a4a0
+; Due to a development oversight, this function is called with the wild Pokemon's level, not its species, in a.
+ and a
+ jr z, .nowildmon ; = 0
+ cp NUM_POKEMON + 1 ; 252
+ jr nc, .nowildmon ; >= 252
+ and a ; 1 <= Species <= 251
+ ret
+
+.nowildmon
+ scf
+ ret
+; 2a4ab
+
+RandomPhoneRareWildMon: ; 2a4ab
+; Related to the phone?
+ callba GetCallerLocation
+ ld d, b
+ ld e, c
+ ld hl, JohtoGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call LookUpWildmonsForMapDE
+ jr c, .GetGrassmon
+ ld hl, KantoGrassWildMons
+ call LookUpWildmonsForMapDE
+ jr nc, .done
+
+.GetGrassmon
+ push hl
+ ld bc, 5 + 4 * 2 ; Location of the level of the 5th wild Pokemon in that map
+ add hl, bc
+ ld a, [TimeOfDay]
+ ld bc, 7 * 2
+ call AddNTimes
+.randloop1
+ call Random
+ and $3
+ jr z, .randloop1
+ dec a
+ ld c, a
+ ld b, $0
+rept 2
+ add hl, bc
+endr
+; We now have the pointer to one of the last (rarest) three wild Pokemon found in that area.
+ inc hl
+ ld c, [hl] ; Contains the species index of this rare Pokemon
+ pop hl
+ ld de, 5 + 0 * 2
+ add hl, de
+ inc hl ; Species index of the most common Pokemon on that route
+ ld b, 4
+.loop2
+ ld a, [hli]
+ cp c ; Compare this most common Pokemon with the rare one stored in c.
+ jr z, .done
+ inc hl
+ dec b
+ jr nz, .loop2
+; This Pokemon truly is rare.
+ push bc
+ dec c
+ ld a, c
+ call CheckSeenMon
+ pop bc
+ jr nz, .done
+; Since we haven't seen it, have the caller tell us about it.
+ ld de, StringBuffer1
+ call CopyName1
+ ld a, c
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, UnknownText_0x2a51a
+ call PrintText
+ xor a
+ ld [ScriptVar], a
+ ret
+
+.done
+ ld a, $1
+ ld [ScriptVar], a
+ ret
+; 2a51a
+
+UnknownText_0x2a51a: ; 0x2a51a
+ ; I just saw some rare @ in @ . I'll call you if I see another rare #MON, OK?
+ text_jump UnknownText_0x1bd34b
+ db "@"
+; 0x2a51f
+
+RandomPhoneWildMon: ; 2a51f
+ callba GetCallerLocation
+ ld d, b
+ ld e, c
+ ld hl, JohtoGrassWildMons
+ ld bc, GRASS_WILDDATA_LENGTH
+ call LookUpWildmonsForMapDE
+ jr c, .ok
+ ld hl, KantoGrassWildMons
+ call LookUpWildmonsForMapDE
+
+.ok
+ ld bc, 5 + 0 * 2
+ add hl, bc
+ ld a, [TimeOfDay]
+ inc a
+ ld bc, 7 * 2
+.loop
+ dec a
+ jr z, .done
+ add hl, bc
+ jr .loop
+
+.done
+ call Random
+ and $3
+ ld c, a
+ ld b, $0
+rept 2
+ add hl, bc
+endr
+ inc hl
+ ld a, [hl]
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, StringBuffer1
+ ld de, StringBuffer4
+ ld bc, PKMN_NAME_LENGTH
+ jp CopyBytes
+; 2a567
+
+RandomPhoneMon: ; 2a567
+; Get a random monster owned by the trainer who's calling.
+ callba GetCallerLocation
+ ld hl, TrainerGroups
+ ld a, d
+ dec a
+ ld c, a
+ ld b, 0
+rept 2
+ add hl, bc
+endr
+ ld a, BANK(TrainerGroups)
+ call GetFarHalfword
+
+.skip_trainer
+ dec e
+ jr z, .skipped
+.skip
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ cp -1
+ jr nz, .skip
+ jr .skip_trainer
+.skipped
+
+.skip_name
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ cp "@"
+ jr nz, .skip_name
+
+ ld a, BANK(Trainers)
+ call GetFarByte
+ inc hl
+ ld bc, 2
+ cp 0
+ jr z, .got_mon_length
+ ld bc, 2 + NUM_MOVES
+ cp 1
+ jr z, .got_mon_length
+ ld bc, 2 + 1
+ cp 2
+ jr z, .got_mon_length
+ ld bc, 2 + 1 + NUM_MOVES
+.got_mon_length
+
+ ld e, 0
+ push hl
+.count_mon
+ inc e
+ add hl, bc
+ ld a, BANK(Trainers)
+ call GetFarByte
+ cp -1
+ jr nz, .count_mon
+ pop hl
+
+.rand
+ call Random
+ and 7
+ cp e
+ jr nc, .rand
+
+ inc a
+.get_mon
+ dec a
+ jr z, .got_mon
+ add hl, bc
+ jr .get_mon
+.got_mon
+
+ inc hl ; species
+ ld a, BANK(Trainers)
+ call GetFarByte
+ ld [wd265], a
+ call GetPokemonName
+ ld hl, StringBuffer1
+ ld de, StringBuffer4
+ ld bc, PKMN_NAME_LENGTH
+ jp CopyBytes
+; 2a5e9
+
+
+JohtoGrassWildMons: ; 0x2a5e9
+INCLUDE "data/wild/johto_grass.asm"
+
+JohtoWaterWildMons: ; 0x2b11d
+INCLUDE "data/wild/johto_water.asm"
+
+KantoGrassWildMons: ; 0x2b274
+INCLUDE "data/wild/kanto_grass.asm"
+
+KantoWaterWildMons: ; 0x2b7f7
+INCLUDE "data/wild/kanto_water.asm"
+
+SwarmGrassWildMons: ; 0x2b8d0
+INCLUDE "data/wild/swarm_grass.asm"
+
+SwarmWaterWildMons: ; 0x2b92f
+INCLUDE "data/wild/swarm_water.asm"