# Foreign Pokémon in the Wild

Pokémon Essentials Version
Nobody ever talks about N's Pokémon, which is a shame, because I thought it was a really cool feature! This script lets you generate wild Pokémon with specific traits, including a different OT, then send them out into maps for the player to encounter in the wild!

Installing this resource
It's very nearly plug-and-play! (Technically, it's perfectly functional with just the one script, but there's a few flourishes to put in so that messages don't look goofy.

This is the main script, which you just paste as a new script section above Main:
Ruby:
class PokemonGlobalMetadata
attr_accessor :foreignEncounter
attr_accessor :foreignPokemon
attr_writer   :foreignPokemonCaught

def foreignPokemonCaught
return @foreignPokemonCaught || []
end
end

# 0-5 are about encountering the Pokémon
#0-Species, 1-lvl, 2-switch, 3-encounter type, 4-battle BGM, 5-map ID
#Encounter types are the same as for Roaming Pokémon

#6-8 affect cosmetic info
#6-shiny (true/false), 7-gender (0M, 1F), 8- Nickname

#9-12 affect OT info
#9-name, 10-gender (0M,1F,2N), 11-ID#, 12-language
#The trainer ID# can be anywhere from 1 to 55555
#You can go higher, but it won't come out how you write it.
#(For example, 555555 doesn't display as "55555", but instead 31267)

#13-18 affect battle properties
#13-form, 14-nature, 15-IVs (an array of six numbers or one number),
#16-EVs (has to be six numbers), 17-moves (as an array), 18-ability#

#19 is currently reserved for items, but items sadly don't work yet.
#If you're using Pokémon Memories, you can uncomment part of the code
#and use 20 to set memory.

foreignSpecies = [
[:PIKACHU, 10, 8, 1, nil, 66, true, 0, "Pika", "Red", 0, 1, 1, 0, :HASTY,
[1,2,3,4,5,6], nil, [:TACKLE, :SPARK], 0],
[:BULBASAUR, 10, 8, 1, nil, 66, true, 0, "Saur", "Red", 0, 55554, 1, 0, :TIMID,
[31], nil, [:TACKLE, :FRENZYPLANT], 0]
]

#===============================================================================
# Encountering a foreign Pokémon in a wild battle.
#===============================================================================
class PokemonTemp
attr_accessor :foreignIndex   # Index of foreign Pokémon to encounter next
end

# Returns whether the given category of encounter contains the actual encounter
# method that will occur in the player's current position.
def pbForeignMethodAllowed(encType)
encounter = $PokemonEncounters.pbEncounterType case encType when 0 # Any encounter method (except triggered ones and Bug Contest) return true if encounter==EncounterTypes::Land || encounter==EncounterTypes::LandMorning || encounter==EncounterTypes::LandDay || encounter==EncounterTypes::LandNight || encounter==EncounterTypes::Water || encounter==EncounterTypes::Cave when 1 # Grass (except Bug Contest)/walking in caves only return true if encounter==EncounterTypes::Land || encounter==EncounterTypes::LandMorning || encounter==EncounterTypes::LandDay || encounter==EncounterTypes::LandNight || encounter==EncounterTypes::Cave when 2 # Surfing only return true if encounter==EncounterTypes::Water when 3 # Fishing only return true if encounter==EncounterTypes::OldRod || encounter==EncounterTypes::GoodRod || encounter==EncounterTypes::SuperRod when 4 # Water-based only return true if encounter==EncounterTypes::Water || encounter==EncounterTypes::OldRod || encounter==EncounterTypes::GoodRod || encounter==EncounterTypes::SuperRod end return false end EncounterModifier.register(proc { |encounter|$PokemonTemp.foreignIndex = nil
next nil if !encounter
# Give the regular encounter if encountering a foreign Pokémon isn't possible
next encounter if $PokemonGlobal.partner next encounter if$PokemonTemp.pokeradar
next encounter if rand(100)<50   # 50% chance of encountering a foreign Pokémon
# Look at each foreign Pokémon in turn and decide whether it's possible to
# encounter it
$PokemonGlobal.foreignPokemon = [] if !$PokemonGlobal.foreignPokemon
foreignChoices = []
for i in 0...foreignSpecies.length
# [species symbol, level, Game Switch, encounter type, battle BGM, area maps hash]
foreignData = foreignSpecies[i]
next if $PokemonGlobal.foreignPokemon[i]==true # Foreign Pokémon has been caught # Ensure species is a number rather than a string/symbol species = getID(PBSpecies,foreignData[0]) next if !species || species<=0 # Makes sure the relevant switch is on switch=foreignData[2] next if$game_switches[switch]==false
# Get the foreign Pokémon's map
foreignMap=foreignData[5]
# Check if foreign Pokémon is on the current map. If not, check if foreign
# Pokémon is on a map with the same name as the current map and both maps
# are in the same region
if foreignMap!=$game_map.map_id currentRegion = pbGetCurrentRegion next if pbGetMetadata(foreignMap,MetadataMapPosition)[0]!=currentRegion currentMapName = pbGetMessage(MessageTypes::MapNames,$game_map.map_id)
next if pbGetMessage(MessageTypes::MapNames,foreignMap)!=currentMapName
end
# Check whether the roaming Pokémon's category of encounter is currently possible
next if !pbForeignMethodAllowed(foreignData[3])
# Add this foreign Pokémon to the list of possible foreign Pokémon to encounter
foreignChoices.push([i,species,foreignData[1],foreignData[4],0,0,
foreignData[6],foreignData[7],foreignData[8],foreignData[9],foreignData[10],
foreignData[11],foreignData[12],foreignData[13],foreignData[14],foreignData[15],
foreignData[16],foreignData[17],foreignData[18],foreignData[19]#,foreignData[20]
])
end
# No encounterable roaming Pokémon were found, just have the regular encounter
next encounter if foreignChoices.length==0
# Pick a roaming Pokémon to encounter out of those available
chosenForeign = foreignChoices[rand(foreignChoices.length)]
$PokemonGlobal.foreignEncounter = chosenForeign$PokemonTemp.foreignIndex     = chosenForeign[0]   # Foreign Pokémon's index
if chosenForeign[3] && chosenForeign[3]!=""
$PokemonGlobal.nextBattleBGM = chosenForeign[3] end$PokemonTemp.forceSingleBattle = true
next [chosenForeign[1],chosenForeign[2]]   # Species, level
})

Events.onWildBattleOverride += proc { |_sender,e|
species = e[0]
level   = e[1]
handled = e[2]
next if handled[0]!=nil
next if !$PokemonGlobal.foreignEncounter next if$PokemonTemp.foreignIndex==nil
handled[0] = pbForeignPokemonBattle(species,level)
}

def pbForeignPokemonBattle(species, level)
# Get the foreign Pokémon to encounter; generate it based on the species and
# level if it doesn't already exist
idxForeign = $PokemonTemp.foreignIndex if !$PokemonGlobal.foreignPokemon[idxForeign] ||
!$PokemonGlobal.foreignPokemon[idxForeign].is_a?(PokeBattle_Pokemon)$PokemonGlobal.foreignPokemon[idxForeign] = pbGenerateWildPokemon(species,level,false)
end
#Edits to Pokemon
chosenForeign=$PokemonGlobal.foreignEncounter pokemon=$PokemonGlobal.foreignPokemon[idxForeign]
#Cosmetics
#shiny
case chosenForeign[6]
when true
pokemon.makeShiny
when false
pokemon.makeNotShiny
end
#gender
case chosenForeign[7]
when 0
pokemon.makeMale
when 1
pokemon.makeFemale
end
#name
if chosenForeign[8] && chosenForeign[8]!=""
pokemon.name=chosenForeign[8]
end
#OT protperties
#name
if chosenForeign[9] && chosenForeign[9]!=""
pokemon.ot=chosenForeign[9]
end
#gender
if chosenForeign[10] && chosenForeign[10]!=""
pokemon.otgender=chosenForeign[10]
end
#ID
if chosenForeign[11] && chosenForeign[11]!=""
pokemon.trainerID=chosenForeign[11]
end
#language
if chosenForeign[12] && chosenForeign[12]!=""
pokemon.language=chosenForeign[12]
end
#battle properties
#form
if chosenForeign[13] && chosenForeign[13]!=""
pokemon.form=chosenForeign[13]
end
#nature
if chosenForeign[14] && chosenForeign[14]!=""
pokemon.setNature(chosenForeign[14])
end
#ivs
if chosenForeign[15] && chosenForeign[15]!=""
newIVs=chosenForeign[15]
case newIVs.length
when 1
newIV=newIVs[0]
pokemon.iv[PBStats::HP]=newIV
pokemon.iv[PBStats::ATTACK]=newIV
pokemon.iv[PBStats::DEFENSE]=newIV
pokemon.iv[PBStats::SPATK]=newIV
pokemon.iv[PBStats::SPDEF]=newIV
pokemon.iv[PBStats::SPEED]=newIV
when 6
$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::HP]=newIVs[0]$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::ATTACK]=newIVs[1]
$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::DEFENSE]=newIVs[2]$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::SPATK]=newIVs[3]
$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::SPDEF]=newIVs[4]$PokemonGlobal.foreignPokemon[idxForeign].iv[PBStats::SPEED]=newIVs[5]
end
end
if chosenForeign[16] && chosenForeign[16]!=""
newEVs=chosenForeign[16]
pokemon.ev[PBStats::HP]=newEVs[0]
pokemon.ev[PBStats::ATTACK]=newEVs[1]
pokemon.ev[PBStats::DEFENSE]=newEVs[2]
pokemon.ev[PBStats::SPATK]=newEVs[3]
pokemon.ev[PBStats::SPDEF]=newEVs[4]
pokemon.ev[PBStats::SPEED]=newEVs[5]
end
if chosenForeign[17] && chosenForeign[17]!=""
newMoves=chosenForeign[17]
for i in 0...newMoves.length
move=newMoves[i]
pokemon.pbLearnMove(move)
end
end
if chosenForeign[18] && chosenForeign[18]!=""
pokemon.setAbility(chosenForeign[18])
end
#memories
# if chosenForeign[20] && chosenForeign[20]!=""
# $PokemonGlobal.foreignPokemon[idxForeign].memory=chosenForeign[20] # end$PokemonGlobal.foreignPokemon[idxForeign]=pokemon
# Set some battle rules
setBattleRule("single")
# Perform the battle
decision = pbWildBattleCore($PokemonGlobal.foreignPokemon[idxForeign]) # Update Foreign Pokémon data based on result of battle if decision==1 || decision==4 # Defeated or caught$PokemonGlobal.foreignPokemon[idxForeign]       = true
$PokemonGlobal.foreignPokemonCaught[idxForeign] = (decision==4) end$PokemonGlobal.foreignEncounter = nil
# Used by the Poké Radar to update/break the chain
Events.onWildBattleEnd.trigger(nil,species,level,decision)
# Return false if the player lost or drew the battle, and true if any other result
return (decision!=2 && decision!=5)
end

EncounterModifier.registerEncounterEnd(proc {
$PokemonTemp.foreignIndex = nil }) In PokeBattle_BattleCommon, find Ruby:  def pbStorePokemon(pkmn) # Nickname the Pokémon (unless it's a Shadow Pokémon) if !pkmn.shadowPokemon? Below that, add Ruby:  if pkmn.isForeign? pbDisplayPaused(_INTL("It seems like {1} has a different OT!.",pkmn.name)) end Alternatively, if your game allows renaming Pokémon that aren't yours, you could change it to: Ruby:  def pbStorePokemon(pkmn) # Nickname the Pokémon (unless it's a Shadow or foreign Pokémon) if !pkmn.shadowPokemon? && !pkmn.isForeign? To get around the awkwardness of "Give a nickname to this Pokémon that clearly has a nickname?" Below that, find Ruby: pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.",pkmn.name)) Change it to: Ruby:  pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.",PBSpecies.getName(pkmn.species))) This makes sure the game says "Added (species)'s data to the PokeDex", rather than saying "Added (nickname)'s data to the PokeDex". In Battle_StartAndEnd, find Ruby:  if wildBattle? foeParty = pbParty(1) case foeParty.length when 1 pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name)) Change "pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name))" to Ruby:  if$PokemonTemp.foreignIndex
pbDisplayPaused(_INTL("Huh? {1} appeared!",foeParty[0].name))
else
pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name))
end
This will make battles display "Huh? (Pokémon) appeared!" for Pokémon generated with this script, while regular encounters still say "Oh! A wild (Pokémon) appeared!"

Using this resource
(When you release your game, don't forget to remove my example Pokémon!)

So, there's a lot that you can define for these Pokémon. (I tried to make pretty much every trait of a Pokémon editable through this script, so it could be easier to set up)

To add a Pokémon to this, just find this section at the top:
Ruby:
foreignSpecies = [
[:PIKACHU, 10, 8, 1, nil, 66, true, 0, "Pika", "Red", 0, 1, 1, 0, :HASTY,
[1,2,3,4,5,6], nil, [:TACKLE, :SPARK], 0],
[:BULBASAUR, 10, 8, 1, nil, 66, true, 0, "Saur", "Red", 0, 55554, 1, 0, :TIMID,
[31], nil, [:TACKLE, :FRENZYPLANT], 0]
]
You're going to create a new entry similar to what I've put here! There's a lot to these examples, but you actually only need the first six entries, the rest are all optional! Set any of them to nil, and it'll be generated the same as any other wild Pokémon!

0-5- Encountering the Pokémon
• 0 is the species, written as :SPECIES
• 1 is the level the Pokémon will be when encountered
• 2 is the number of the Global Switch that needs to be turned on for this encounter to happen
• 3 is the encounter type the Pokémon will spawn in. It's the same as it is for Roaming Pokémon :
• 0 - Walking in grass, walking in caves or surfing.
• 1 - Walking in grass or walking in caves.
• 2 - Surfing.
• 3 - Fishing.
• 4 - Surfing or fishing.
• 4 is a filename for BGM for this encounter, formatted as "name", if you'd like to change it from the standard encounters on the map
• 5 is the ID number of the map you can encounter this Pokémon on
6-8- Cosmetic info
• 6 is true if the Pokemon is a guaranteed Shiny and false if it's Shiny-locked. Set it to nil if you want the regular shiny chance.
• 7 is the gender of the Pokémon - 0 for male, 1 for female. You can leave it as nil to have the regular gender chance, and genderless Pokémon should also have it set to nil, because it might cause an error otherwise.
• 8 is the nickname of the Pokemon, formatted as "Name". Leave as nil to have the regular species name.
9-12- OT's info

• 9 is the name of the OT, written as "Name". Leave as nil to let the player be defined as the OT for this Pokémon. If you do, make sure anything else you use in this section is nil, too.
• 10 is the gender of the OT- 0 for male, 1 for female, 2 for other.
• 11 is the ID number of the OT. As far as I can tell, you can write in any number from 1 to 55555 and have it display those characters. Any higher and I think it calculates it differently somehow, so the digits won't display what you typed in.
• 12 is the OT's language.
• 0 = Unknown
• 1 = Japanese
• 2 = English
• 3 = French
• 4 = Italian
• 5 = German
• 7 = Spanish
• 8 = Korean

13-18 Battle Properties
• 13 is the number of this Pokémon's form.
• 14 is the nature of the Pokémon, written as :NATURE
• 15 is this Pokémon's IVs. You can either make this an array of six numbers, like [1,2,3,4,5,6], or an array of one number, like [1]. If it's just one number, then all six IVs will be set to that one number.
• 16 is this Pokémon's EVs. This one has to be an array of six numbers, because I didn't see the point in setting EVs to the same thing when you could only go up to 42 doing it that way.
• 17 is this Pokémon's moves. You have to set this an array, but it can be as long or short as you like- [:MOVE] to [:MOVE,:MOVE,:MOVE,:MOVE]. This script uses pbLearnMove to add these in, so it'll bump off the top move if the Pokémon has four moves, but the Pokémon will still have any remaining natural moves in its learnset.
• 18- The number of this Pokémon's ability slot.

Other
19 is currently reserved for items, but I unfortunately don't have it working yet.

20 is designed to work with my Pokémon Memories script! It's commented out so this resource doesn't cause any crashes on its own, but if you'd like to use them together, just remove the #s you see blocking it, and it should be pretty simply to use! Just use "text" to write the memory!

Probability
I had considered making probability an element of the Pokémon, but I couldn't get that to run smoothly. Right now, probability is defined by this line here:
Ruby:
  next encounter if rand(100)<50   # 50% chance of encountering a foreign Pokémon

That means that the game has a 50% chance of checking for a foreign Pokémon with every encounter.

If you'd like this to change depending on what Pokémon is being found, just add some conditionals around it! For example, if I want one specific Pokémon to be rarer than the others, I'd just change this to:

Ruby:
if $game_switches[switch]==true &&$game_map.map_id==number
next encounter if rand(100)<90   # 10% chance of encountering a foreign Pokémon
else
next encounter if rand(100)<50   # 50% chance of encountering a foreign Pokémon
end

And just make "switch" and "number" match up with the ones for my Pokémon!

Ideas for this resource
• Naturally, reformed villain's Pokémon out in the wild would be fun to catch! But it doesn't have to be villains- why not give some iconic characters a released Pokémon for the player to find? (The TCG's Owner's Pokémon could be a good source of inspiration!)
• But then, who says it has to be a character the player's met at all? There's a lot of scenarios where a player could find a long-gone trainer's Pokémon- an ancient king's team, a mad scientist's experiments gone rogue, a fallen adventurer's Pokémon- there's lot of ways the player could uncover a mysterious past!
• You don't even have to have an OT for these Pokémon, though, you could just make some special Pokémon for the player to find! A guaranteed shiny, high IVs, egg moves, maybe even a special species or form you can only catch once!
• This can also be used to replicate Ultra Beast encounters from the postgame Looker missions!

Known Issues
Unfortunately, I can't manage to get items set in this script. (I think the way the game handles wild items is throwing me off) I'll update this when I get a fix!

Future Goals
• Create the animation that plays for N's Pokémon
• Create a way to generate a random foreign ID, so you don't have to create an ID for each character.
• Create a way to guarantee X number of perfect IVs without requiring the specific stat to be set
• Fix the issue of being unable to set items.
• Make sure nothing tricky can go on with setting EVs.
• Create a limit to the length of memories.
• Figure out a way to combine this with phenomena, so it's more clear to the player that there's special Pokémon here.
• I might add options for Pokerus, Ribbons, and Contest stats.
• If I go genuinely crazy, I might consider working out a way to have this collect the data of released Pokémon and have them appear in the wild. That's a big if, though, I'm just putting it here so I remember the idea.
Credits
Credits to TechSkylander1518, please! And credit to the original devs of Pokémon Essentials, because the code for Roaming Pokémon was used as a base for a lot of this!
Author
TechSkylander1518
Views
952
First release
Last update
Rating
0 ratings