ref: 67d38da5b01173d2a78a3e083aff505f40276f2e
dir: /engine/wildmons.asm/
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"