- Pokémon Essentials Version
- v20.1 ➖
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, or download as a plugin for v20 here.
Ruby:
module ForeignPokemon
NPurrloin = {
:species => :PURRLOIN,
:level => 7,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :TIMID,
:moves => [:SCRATCH,:GROWL,:ASSIST],
:iv => {:HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NPidove = {
:species => :PIDOVE,
:level => 13,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :SASSY,
:moves => [:GUST,:QUICKATTACK,:LEER,:GROWL],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NTimburr = {
:species => :TIMBURR,
:level => 13,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :RASH,
:moves => [:LEER,:FOCUSENERGY,:BIDE,:LOWKICK],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NTympole = {
:species => :TYMPOLE,
:level => 13,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :MODEST,
:moves => [:GROWL,:SUPERSONIC,:ROUND,:BUBBLEBEAM],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NWoobat = {
:species => :WOOBAT,
:level => 55,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :TIMID,
:moves => [:AIRSLASH,:FUTURESIGHT,:PSYCHIC,:ENDEAVOR],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NSandile = {
:species => :SANDILE,
:level => 22,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :DOCILE,
:moves => [:SANDTOMB,:ASSURANCE,:MUDSLAP,:EMBARGO],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NDarumaka = {
:species => :DARUMAKA,
:level => 22,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :NAIVE,
:moves => [:HEADBUTT,:UPROAR,:FACADE,:FIREPUNCH],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NDarmanitan = {
:species => :DARMANITAN,
:level => 35,
:ability_index => 2,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :CALM,
:moves => [:THRASH,:BELLYDRUM,:FLAREBLITZ,:HAMMERARM],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NScraggy = {
:species => :SCRAGGY,
:level => 22,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :LAX,
:moves => [:FAINTATTACK,:HEADBUTT,:SWAGGER,:BRICKBREAK],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NSigilyph = {
:species => :SIGILYPH,
:level => 22,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :GENTLE,
:moves => [:TAILWIND,:WHIRLWIND,:PSYBEAM,:AIRCUTTER],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NBoldore = {
:species => :BOLDORE,
:level => 28,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :NAIVE,
:moves => [:MUDSLAP,:IRONDEFENSE,:SMACKDOWN,:POWERGEM],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NJoltik = {
:species => :JOLTIK,
:level => 28,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :DOCILE,
:moves => [:ELECTROWEB,:BUGBITE,:GASTROACID,:SLASH],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NFerroseed = {
:species => :FERROSEED,
:level => 28,
:shiny => false,
:gender => 0,
:ot => :N,
:happiness => 255,
:nature => :BASHFUL,
:moves => [:METALCLAW,:PINMISSILE,:GYROBALL,:IRONDEFENSE],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
NKlink = {
:species => :KLINK,
:level => 28,
:shiny => false,
:ot => :N,
:happiness => 255,
:nature => :RASH,
:moves => [:THUNDERSHOCK,:GEARGRIND,:BIND,:CHARGEBEAM],
:iv => { :HP => 30,
:ATTACK => 30,
:DEFENSE => 30,
:SPECIAL_ATTACK => 30,
:SPECIAL_DEFENSE => 30,
:SPEED => 30}
}
end
module ForeignOTs
N = {
:name => "N",
:gender => 0,
:id_number => 2
}
end
module Settings
# A set of arrays, each containing the details of a foreign Pokémon. The
# information within each array is as follows:
# * Module with Pokémon's data
# * Game Switch; the Pokémon can be encountered while this is ON.
# * Map(s) the Pokémon can be encountered on.
# * Encounter type (0=any, 1=grass/walking in cave, 2=surfing, 3=fishing,
# 4=surfing/fishing). See the bottom of PField_RoamingPokemon for lists.
# * Name of BGM to play for that encounter (optional).
# * Chance of being encountered. (out of 100)
FOREIGN_SPECIES = [
#[:NPurrloin,2,[66],1,"Battle Elite",100]
]
end
class PokemonGlobalMetadata
attr_accessor :foreignEncounter
attr_accessor :foreignPokemon
attr_writer :foreignPokemonCaught
def foreignPokemonCaught
return @foreignPokemonCaught || []
end
end
#===============================================================================
# Encountering a foreign Pokémon in a wild battle.
#===============================================================================
class Game_Temp
attr_accessor :foreign_index_for_encounter # Index of foreign Pokémon to encounter next
end
EventHandlers.add(:on_wild_species_chosen, :foreign_pokemon,
proc { |encounter|
$game_temp.foreign_index_for_encounter = nil
$PokemonGlobal.foreignPokemon = [] if !$PokemonGlobal.foreignPokemon
next if !encounter
# Give the regular encounter if encountering a foreign Pokémon isn't possible
next if $PokemonGlobal.partner
next if $game_temp.poke_radar_data
# Look at each foreign Pokémon in turn and decide whether it's possible to encounter it
currentRegion = pbGetCurrentRegion
currentMapName = $game_map.name
possible_foreign = []
Settings::FOREIGN_SPECIES.each_with_index do |data, i|
# data = [module, Game Switch, maps, encounter method, battle BGM, encounter chance]
pokedata = ForeignPokemon.const_get(data[0])
next if !GameData::Species.exists?(pokedata[:species])
next if data[1] > 0 && !$game_switches[data[1]] # Isn't active
next if $PokemonGlobal.foreignPokemon[i] == true # Foreign Pokémon has been caught
# Get possible maps
foreignMaps = data[2]
if foreignMaps.include?($game_map.map_id)
match = true
else
# If foreign mon isn't on the current map, check if it's on a map with the same
# name and in the same region
for i in 0...foreignMaps.length
testMap = foreignMaps[i]
map_metadata = GameData::MapMetadata.try_get(testMap)
if map_metadata && map_metadata.town_map_position &&
map_metadata.town_map_position[0] == currentRegion &&
pbGetMapNameFromId(testMap) == currentMapName
match = true
end
end
end
next if !match
# Check whether the encounter method is currently possible
next if !pbRoamingMethodAllowed(data[3])
next if !(rand(100) < data[5])
# Add this foreign Pokémon to the list of possible foreign Pokémon to encounter
possible_foreign.push([i, data[4]]) # [i, BGM]
end
# No encounterable foreign Pokémon were found, just have the regular encounter
next if possible_foreign.length == 0
# Pick a foreign Pokémon to encounter out of those available
foreign = possible_foreign.sample
$PokemonGlobal.foreignEncounter = foreign
$game_temp.foreign_index_for_encounter = foreign[0]
$PokemonGlobal.nextBattleBGM = foreign[1] if foreign[1] && !foreign[1].empty?
$game_temp.force_single_battle = true
}
)
EventHandlers.add(:on_calling_wild_battle, :foreign_pokemon,
proc { |species, level, handled|
# handled is an array: [nil]. If [true] or [false], the battle has already
# been overridden (the boolean is its outcome), so don't do anything that
# would override it again
next if !handled[0].nil?
next if !$PokemonGlobal.foreignEncounter || $game_temp.foreign_index_for_encounter.nil?
handled[0] = pbForeignPokemonBattle
}
)
def pbForeignPokemonBattle
# Get the foreign Pokémon to encounter; generate it based on the species and
# level if it doesn't already exist
idxForeign = $game_temp.foreign_index_for_encounter
if !$PokemonGlobal.foreignPokemon[idxForeign] ||
!$PokemonGlobal.foreignPokemon[idxForeign].is_a?(Pokemon)
pokedata = Settings::FOREIGN_SPECIES[idxForeign][0]
pokedata = ForeignPokemon.const_get(pokedata)
newpoke = pbGenerateWildPokemon(pokedata[:species],pokedata[:level])
newpoke.shiny = pokedata[:shiny] if pokedata[:shiny]
newpoke.name = pokedata[:name] if pokedata[:name]
newpoke.gender = pokedata[:gender] if pokedata[:gender]
newpoke.item = pokedata[:item] if pokedata[:item]
newpoke.nature = pokedata[:nature] if pokedata[:nature]
newpoke.form = pokedata[:form] if pokedata[:form]
newpoke.happiness = pokedata[:happiness] if pokedata[:happiness]
newpoke.sheen = pokedata[:sheen] if pokedata[:sheen]
newpoke.cool = pokedata[:cool] if pokedata[:cool]
newpoke.beauty = pokedata[:beauty] if pokedata[:beauty]
newpoke.cute = pokedata[:cute] if pokedata[:cute]
newpoke.smart = pokedata[:smart] if pokedata[:smart]
newpoke.tough = pokedata[:tough] if pokedata[:tough]
if pokedata[:ribbons]
for i in 0...pokedata[:ribbons].length
newpoke.giveRibbon(pokedata[:ribbons][i])
end
end
if pokedata[:pokerus]
if pokedata[:pokerus].is_a?(Integer)
newpoke.givePokerus(pokedata[:pokerus])
else
newpoke.givePokerus
end
end
newpoke.ability = pokedata[:ability] if pokedata[:ability]
newpoke.ability_index = pokedata[:ability_index] if pokedata[:ability_index]
if pokedata[:moves]
moves = []
for i in 0...pokedata[:moves].length
moves.push(Pokemon::Move.new(pokedata[:moves][i]))
end
newpoke.moves = moves
end
if pokedata[:newmoves]
for i in 0...pokedata[:newmoves].length
newpoke.learn_move(pokedata[:newmoves][i])
end
end
newpoke.ev = pokedata[:ev] if pokedata[:ev]
newpoke.iv = pokedata[:iv] if pokedata[:iv]
if pokedata[:perf_ivs]
stats = []
GameData::Stat.each_main { |s| stats.push(s.id)}
stats = stats.sample(pokedata[:perf_ivs])
stats.each do |s|
newpoke.iv[s] = Pokemon::IV_STAT_LIMIT
end
end
newpoke.memory = pokedata[:memory] if pokedata[:memory]
if pokedata[:ot]
trainerdata = ForeignOTs.const_get(pokedata[:ot])
newpoke.owner.name = trainerdata[:name] if trainerdata[:name]
newpoke.owner.gender = trainerdata[:gender] if trainerdata[:gender]
if trainerdata[:id_number]
id = trainerdata[:id_number]
newpoke.owner.id = id | (id << 16)
else
newpoke.owner.id = $player.make_foreign_ID
end
newpoke.owner.language = trainerdata[:language] if trainerdata[:language]
end
$PokemonGlobal.foreignPokemon[idxForeign] = newpoke
end
if $PokemonGlobal.foreignPokemon[idxForeign].is_a?(Pokemon)
$PokemonGlobal.foreignPokemon[idxForeign].heal if $PokemonGlobal.foreignPokemon[idxForeign].fainted?
end
# Set some battle rules
setBattleRule("single")
# Perform the battle
decision = WildBattle.start_core($PokemonGlobal.foreignPokemon[idxForeign])
species = $PokemonGlobal.foreignPokemon[idxForeign].species
level = $PokemonGlobal.foreignPokemon[idxForeign].level
# Update Foreign Pokémon data based on result of battle
if decision == 4 # Caught
$PokemonGlobal.foreignPokemon[idxForeign] = true
$PokemonGlobal.foreignPokemonCaught[idxForeign] = (decision == 4)
end
$PokemonGlobal.foreignEncounter = nil
$game_temp.foreign_index_for_encounter = nil
# Used by the Poké Radar to update/break the chain
EventHandlers.trigger(:on_wild_battle_end, 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
Now for the flavor text!
In Battle_StartAndEnd, find this line:
Ruby:
pbDisplayPaused(_INTL("Oh! A wild {1} appeared!", foeParty[0].name))
Ruby:
if foeParty[0].foreign?($player)
pbDisplayPaused(_INTL("A wild {1} appeared?!", foeParty[0].name))
else
pbDisplayPaused(_INTL("Oh! A wild {1} appeared!", foeParty[0].name))
end
In Battle_CatchAndStoreMixin, find this line:
Ruby:
pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.", pkmn.name))
Ruby:
pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.", pkmn.speciesName))
Finally, we'll unfortunately have to make a change in the v20.1 hotfixes plugin, because it overwrites changes in the base scripts in this section. (Don't worry, if you mess up, you can just download a new copy)
Find this lines in Battle bug fixes -
Ruby:
if $PokemonSystem.givenicknames == 0 &&
Ruby:
if pkmn.foreign?($player)
pbDisplay(_INTL("It seems like #{pkmn.name} has a different OT!"))
elsif $PokemonSystem.givenicknames == 0 &&
There is no v19 version of this script, I didn't get around to updating it in time. I currently do not have plans to offer v19 support.
The v18 version and instructions will be left here for posterity.
This is the main script, which you just paste as a new script section above Main,
In PokeBattle_BattleCommon, find
Below that, add
Alternatively, if your game allows renaming Pokémon that aren't yours, you could change it to:
To get around the awkwardness of "Give a nickname to this Pokémon that clearly has a nickname?"
Below that, find
Change it to:
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
Change "pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name))" to
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!"
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?
Ruby:
if pkmn.isForeign?
pbDisplayPaused(_INTL("It seems like {1} has a different OT!.",pkmn.name))
end
Ruby:
def pbStorePokemon(pkmn)
# Nickname the Pokémon (unless it's a Shadow or foreign Pokémon)
if !pkmn.shadowPokemon? && !pkmn.isForeign?
Below that, find
Ruby:
pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.",pkmn.name))
Ruby:
pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.",PBSpecies.getName(pkmn.species)))
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))
Ruby:
if $PokemonTemp.foreignIndex
pbDisplayPaused(_INTL("Huh? {1} appeared!",foeParty[0].name))
else
pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name))
end
Using this resource
You'll be setting up your data at the top of the script, or in 001_ForeignData.rb if you took the plugin.module ForeignPokemon is where you'll be setting up all the data with the Pokémon's attributes. Data will be organized in a hash. (Look at the examples if you're not familiar) You can change pretty much any attribute here. The only required values are species and level, everything else is optional. (Most of this follows the wiki article on Editing a Pokémon)
- species - Should be a symbol. (
:NAME
) - level - Should be an integer.
- ot - The name of a hash in module ForeignOTs. Should be a symbol. (
:Name
- capitalization can be what you want here, as long as it matches what you put in ForeignOTs) - name - Should be a string. (
"Name"
) - gender - 0 male, 1 female. Leave blank to randomize.
- shiny - true for guaranteed shiny, false for shiny-lock the Pokémon. Leave blank for standard odds.
- happiness, cool, beauty, cute, smart, tough, sheen - Sets the stat directly. Should be an integer.
- item - Should be a symbol
- pokerus - Can be true to guarantee Pokérus or a number 1-16 to guarantee a particular strain. No option to Pokérus-lock.
- nature - should be a symbol
- form - should be an integer
- ability_index - should be an integer.
- ability - should be a symbol. Abilities set by changing the ability value directly only last until a species/form change, according to the wiki, so you should only do this for a Pokémon that can't evolve or change form. (The main appeal is that it could be any ability you want, not just the usual species abilities)
- new_moves - Should be an array. (
[:MOVE,:MOVE]
) The Pokémon will learn these moves in addition to any level-up moves it would normally know. - moves - Should be an array. (
[:MOVE,:MOVE]
) The Pokémon will only know these moves - if you give an array with only two moves, the Pokémon will only have two moves. - perf_ivs - A number 1 to 6. Guarantees at least that many perfect IVs for the Pokémon, but not in any particular stat.
- ivs - Used to set all IVs directly. Should be a hash like this:
Ruby:{:HP => 30, :ATTACK => 30, :DEFENSE => 30, :SPECIAL_ATTACK => 30, :SPECIAL_DEFENSE => 30, :SPEED => 30}
- evs - Used to set all EVs directly. Should be a hash just like IVs.
- ribbons - Should be an array. (
[:RIBBON,:RIBBON]
). The Pokémon will have these ribbons attached in the same order. - memory is to be used with my Pokémon Memories script. Should be a string. (In quotes)
module ForeignOTs has hashes for the OT's information.
- name - Should be a string. (
"name"
) - gender - 0 male, 1 female, 2 neutral
- id_number - Should be an integer. Limit is 65535. Don't worry about converting it so it's displayed right, the script takes care of that.
- language - Based on the values in pbGetLanguage. See Editing a Pokémon to see what they usually are.
The array FOREIGN_SPECIES is where the actual encounter info will be set up. Unlike the others, it's in an array, similar to how roaming Pokémon are set up. Everything has to be in the right order, and you can't skip values. (But you can put
nil
in some cases.)[poke,switch,maps,enctype,theme,chance]
Where...
- poke is the name of a Pokémon in module ForeignPokemon. Should be a symbol. (
:Name
) - switch is the number of a Global Switch that must be turned on for the Pokémon to be encountered. Should be an integer. (Don't put 0s in front of it - switch 1 is just 1, not 001)
- maps is an array of map IDs the Pokémon can be encountered on. Should be an array. (
[1,2,3]
) - enctype is a number corresponding to an encounter type. It's the same list that's used for Roaming Pokemon.
- 0=any
- 1=grass/walking in cave
- 2=surfing
- 3=fishing
- 4=surfing/fishing
- theme is the filename of a song in Audio/BGM to be played during the encounter. Should be a string. (
"name"
) Can be left as nil to just play the standard theme. - chance is the % chance that this encounter overrides a normal encounter. Should be an integer between 1 and 100, inclusive.
I've got examples of all of N's Pokémon from canon in here, as well as N himself and an array in FOREIGN_SPECIES I was using to playtest. (N's Purrloin appearing in the Safari Zone-outside map when switch 2 was on)
To add a Pokémon to this, just find this section at the top:
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
13-18 Battle Properties
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!
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:
And just make "switch" and "number" match up with the ones for my Pokémon!
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]
]
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 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 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- what about an ancient king's team, a mad scientist's experiments gone rogue, or a fallen adventurer's Pokémon?
- 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!
Future Goals
- Create the animation that plays for N's Pokémon
- Double-check and 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.
- 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, and ThatWelshOne_, because the hashes were based on how he organized his quest system!