ref: 5cbff21a0dc8f1bbf8c9de289506d25d5ee8c78e
dir: /engine/overworld/wildmons.asm/
LoadWildMonData: ; 29ff8 call _GrassWildmonLookup jr c, .copy ld hl, wMornEncounterRate xor a ld [hli], a ld [hli], a ld [hl], a jr .done_copy .copy inc hl inc hl ld de, wMornEncounterRate 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 [wWaterEncounterRate], a ret FindNest: ; 2a01f ; Parameters: ; e: 0 = Johto, 1 = Kanto ; wNamedObjectIndexBuffer: species 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 .FindGrass ld hl, JohtoWaterWildMons call .FindWater call .RoamMon1 call .RoamMon2 ret .kanto decoord 0, 0 ld hl, KantoGrassWildMons call .FindGrass ld hl, KantoWaterWildMons jp .FindWater ; 2a052 .FindGrass: ; 2a052 ld a, [hl] cp -1 ret z push hl ld a, [hli] ld b, a ld a, [hli] ld c, a inc hl inc hl inc hl ld a, NUM_GRASSMON * 3 call .SearchMapForMon jr nc, .next_grass ld [de], a inc de .next_grass pop hl ld bc, GRASS_WILDDATA_LENGTH add hl, bc jr .FindGrass ; 2a06e .FindWater: ; 2a06e ld a, [hl] cp -1 ret z push hl ld a, [hli] ld b, a ld a, [hli] ld c, a inc hl ld a, 3 call .SearchMapForMon jr nc, .next_water ld [de], a inc de .next_water pop hl ld bc, 3 * 3 add hl, bc jr .FindWater ; 2a088 .SearchMapForMon: ; 2a088 inc hl .ScanMapLoop: push af ld a, [wNamedObjectIndexBuffer] cp [hl] jr z, .found inc hl inc hl pop af dec a jr nz, .ScanMapLoop and a ret .found pop af jp .AppendNest ; 2a09c .AppendNest: ; 2a09c push de call GetWorldMapLocation ld c, a hlcoord 0, 0 ld de, SCREEN_WIDTH * SCREEN_HEIGHT .AppendNestLoop: ld a, [hli] cp c jr z, .found_nest dec de ld a, e or d jr nz, .AppendNestLoop ld a, c pop de scf ret .found_nest pop de and a ret ; 2a0b7 .RoamMon1: ; 2a0b7 ld a, [wRoamMon1Species] ld b, a ld a, [wNamedObjectIndexBuffer] cp b ret nz ld a, [wRoamMon1MapGroup] ld b, a ld a, [wRoamMon1MapNumber] ld c, a call .AppendNest ret nc ld [de], a inc de ret ; 2a0cf .RoamMon2: ; 2a0cf ld a, [wRoamMon2Species] ld b, a ld a, [wNamedObjectIndexBuffer] cp b ret nz ld a, [wRoamMon2MapGroup] ld b, a ld a, [wRoamMon2MapNumber] ld c, a call .AppendNest 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 [wTempWildMonSpecies], a ld [wBattleType], 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, wMornEncounterRate call CheckOnWater ld a, wWaterEncounterRate - wMornEncounterRate jr z, .ok ld a, [wTimeOfDay] .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, wPartyMon1Item ld de, PARTYMON_STRUCT_LENGTH ld a, [wPartyCount] 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 inc hl inc hl inc hl call CheckOnWater ld de, WaterMonProbTable jr z, .watermon inc hl inc hl ld a, [wTimeOfDay] ld bc, $e call AddNTimes ld de, GrassMonProbTable .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 [wCurPartyLevel], 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, [wUnlockedUnowns] and a jr z, .nowildbattle .done jr .loadwildmon .nowildbattle ld a, 1 and a ret .loadwildmon ld a, b ld [wTempWildMonSpecies], a .startwildbattle xor a ret ; 2a1cb INCLUDE "data/wild/probabilities.asm" 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, wPartyMon1HP 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, [wCurPartyLevel] 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, wSwarmFlags bit SWARMFLAGS_DUNSPARCE_SWARM_F, [hl] pop hl jr z, .CheckYanma ld a, [wDunsparceMapGroup] cp d jr nz, .CheckYanma ld a, [wDunsparceMapNumber] cp e jr nz, .CheckYanma call LookUpWildmonsForMapDE jr nc, _NoSwarmWildmon scf ret .CheckYanma: push hl ld hl, wSwarmFlags bit SWARMFLAGS_YANMA_SWARM_F, [hl] pop hl jr z, _NoSwarmWildmon ld a, [wYanmaMapGroup] cp d jr nz, _NoSwarmWildmon ld a, [wYanmaMapNumber] 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, [wMapGroup] ld d, a ld a, [wMapNumber] ld e, a ret ; 2a288 LookUpWildmonsForMapDE: ; 2a288 .loop 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 .loop .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 ; level ld a, 40 ld [wRoamMon1Level], a ld [wRoamMon2Level], 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 ; hp xor a ; generate new stats ld [wRoamMon1HP], a ld [wRoamMon2HP], 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 roam_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. dec hl dec hl dec hl ld a, [hli] ld [wTempWildMonSpecies], a ld a, [hl] ld [wCurPartyLevel], a ld a, BATTLETYPE_ROAMING ld [wBattleType], 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, .Finished ld b, a ld a, [wRoamMon3MapNumber] ld c, a call .Update ld a, b ld [wRoamMon3MapGroup], a ld a, c ld [wRoamMon3MapNumber], a .Finished: 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 %00011111 ; 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 %11 cp [hl] jr nc, .update_loop ; invalid index, try again inc hl ld c, a ld b, $0 add hl, bc add hl, bc ld a, [wRoamMons_LastMapGroup] cp [hl] jr nz, .done inc hl ld a, [wRoamMons_LastMapNumber] 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, .Finished call JumpRoamMon ld a, b ld [wRoamMon3MapGroup], a ld a, c ld [wRoamMon3MapNumber], a .Finished: jp _BackUpMapIndices JumpRoamMon: ; 2a3cd .loop ld hl, RoamMaps .innerloop1 ; This loop happens to be unnecessary. call Random ; Choose a random number. maskbits NUM_ROAMMON_MAPS ; Mask the number to limit it between 0 and 15. cp NUM_ROAMMON_MAPS ; If the number is not less than 16, 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, [wMapGroup] cp [hl] jr nz, .done inc hl ld a, [wMapNumber] 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, [wRoamMons_CurrentMapNumber] ld [wRoamMons_LastMapNumber], a ld a, [wRoamMons_CurrentMapGroup] ld [wRoamMons_LastMapGroup], a ld a, [wMapNumber] ld [wRoamMons_CurrentMapNumber], a ld a, [wMapGroup] ld [wRoamMons_CurrentMapGroup], a ret ; 2a40f INCLUDE "data/wild/roammon_maps.asm" 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 ; Finds a rare wild Pokemon in the route of the trainer calling, then checks if it's been Seen already. ; The trainer will then tell you about the Pokemon if you haven't seen it. RandomUnseenWildMon: ; 2a4ab farcall 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, [wTimeOfDay] ld bc, NUM_GRASSMON * 2 call AddNTimes .randloop1 call Random and %11 jr z, .randloop1 dec a ld c, a ld b, $0 add hl, bc add hl, bc ; 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, wStringBuffer1 call CopyName1 ld a, c ld [wNamedObjectIndexBuffer], a call GetPokemonName ld hl, .SawRareMonText call PrintText xor a ld [wScriptVar], a ret .done ld a, $1 ld [wScriptVar], a ret .SawRareMonText: ; 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 farcall 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, [wTimeOfDay] inc a ld bc, NUM_GRASSMON * 2 .loop dec a jr z, .done add hl, bc jr .loop .done call Random and %11 ld c, a ld b, $0 add hl, bc add hl, bc inc hl ld a, [hl] ld [wNamedObjectIndexBuffer], a call GetPokemonName ld hl, wStringBuffer1 ld de, wStringBuffer4 ld bc, MON_NAME_LENGTH jp CopyBytes ; 2a567 RandomPhoneMon: ; 2a567 ; Get a random monster owned by the trainer who's calling. farcall GetCallerLocation ld hl, TrainerGroups ld a, d dec a ld c, a ld b, 0 add hl, bc add hl, bc 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 ; level, species cp TRAINERTYPE_NORMAL jr z, .got_mon_length ld bc, 2 + NUM_MOVES ; level, species, moves cp TRAINERTYPE_MOVES jr z, .got_mon_length ld bc, 2 + 1 ; level, species, item cp TRAINERTYPE_ITEM jr z, .got_mon_length ; TRAINERTYPE_ITEM_MOVES ld bc, 2 + 1 + NUM_MOVES ; level, species, item, 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 maskbits PARTY_LENGTH 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 [wNamedObjectIndexBuffer], a call GetPokemonName ld hl, wStringBuffer1 ld de, wStringBuffer4 ld bc, MON_NAME_LENGTH jp CopyBytes ; 2a5e9 INCLUDE "data/wild/johto_grass.asm" INCLUDE "data/wild/johto_water.asm" INCLUDE "data/wild/kanto_grass.asm" INCLUDE "data/wild/kanto_water.asm" INCLUDE "data/wild/swarm_grass.asm" INCLUDE "data/wild/swarm_water.asm"