- Pokémon Essentials Version
- v16.2 ➖
Introduction
This is a crosspost of DoesntKnowHowToPlay's post from Pokecommunity, with his permissionsince I don't think he'll be making an account here, and this script is far too useful to not have be more public.
Original Post
I doubt anyone who knows what they're doing would have a hard time with this, but I'm led to believe this is harder than it looks so I'm going to post it anyway; it's quite possible I've forgotten something important.
Replace the set of definitions and first function at the top of "PTrainer_NPCTrainers" with this:
Then open the "Compilers" script and replace function pbCompileTrainers with the following:
These will allow you to give custom EV spreads to trainers. The EVs come after everything else, and in the usual order for Essentials (speed/satk/sdef), so you'd define a trainer's mon like this for a 252 Atk/Speed mon:
As with the other fields, you don't have to give every trainer's pokemon specially defined EVs, or even extend commas that far. They'll default to 0 in every EV instead of the weird inflated formula vanilla Essentials uses, though.
This is a crosspost of DoesntKnowHowToPlay's post from Pokecommunity, with his permission
Original Post
I doubt anyone who knows what they're doing would have a hard time with this, but I'm led to believe this is harder than it looks so I'm going to post it anyway; it's quite possible I've forgotten something important.
Replace the set of definitions and first function at the top of "PTrainer_NPCTrainers" with this:
Code:
TPSPECIES = 0
TPLEVEL = 1
TPITEM = 2
TPMOVE1 = 3
TPMOVE2 = 4
TPMOVE3 = 5
TPMOVE4 = 6
TPABILITY = 7
TPGENDER = 8
TPFORM = 9
TPSHINY = 10
TPNATURE = 11
TPIV = 12
TPHAPPINESS = 13
TPNAME = 14
TPSHADOW = 15
TPBALL = 16
TPHPEV = 17
TPATKEV = 18
TPDEFEV = 19
TPSPEEDEV = 20
TPSATKEV = 21
TPSDEFEV = 22
TPDEFAULTS = [0,10,0,0,0,0,0,nil,nil,0,false,nil,10,70,nil,false,0,0,0,0,0,0,0]
def pbLoadTrainer(trainerid,trainername,partyid=0)
if trainerid.is_a?(String) || trainerid.is_a?(Symbol)
if !hasConst?(PBTrainers,trainerid)
raise _INTL("Trainer type does not exist ({1}, {2}, ID {3})",trainerid,trainername,partyid)
end
trainerid=getID(PBTrainers,trainerid)
end
success=false
items=[]
party=[]
opponent=nil
trainers=load_data("Data/trainers.dat")
for trainer in trainers
name=trainer[1]
thistrainerid=trainer[0]
thispartyid=trainer[4]
next if trainerid!=thistrainerid || name!=trainername || partyid!=thispartyid
items=trainer[2].clone
name=pbGetMessageFromHash(MessageTypes::TrainerNames,name)
for i in RIVALNAMES
if isConst?(trainerid,PBTrainers,i[0]) && $game_variables[i[1]]!=0
name=$game_variables[i[1]]
end
end
opponent=PokeBattle_Trainer.new(name,thistrainerid)
opponent.setForeignID($Trainer) if $Trainer
for poke in trainer[3]
species=poke[TPSPECIES]
level=poke[TPLEVEL]
pokemon=PokeBattle_Pokemon.new(species,level,opponent)
pokemon.formNoCall=poke[TPFORM]
pokemon.resetMoves
pokemon.setItem(poke[TPITEM])
if poke[TPMOVE1]>0 || poke[TPMOVE2]>0 || poke[TPMOVE3]>0 || poke[TPMOVE4]>0
k=0
for move in [TPMOVE1,TPMOVE2,TPMOVE3,TPMOVE4]
pokemon.moves[k]=PBMove.new(poke[move])
k+=1
end
pokemon.moves.compact!
end
pokemon.setAbility(poke[TPABILITY])
pokemon.setGender(poke[TPGENDER])
if poke[TPSHINY] # if this is a shiny Pokémon
pokemon.makeShiny
else
pokemon.makeNotShiny
end
pokemon.setNature(poke[TPNATURE])
iv=poke[TPIV]
for i in 0...6
pokemon.iv[i]=iv&0x1F
end
pokemon.happiness=poke[TPHAPPINESS]
pokemon.name=poke[TPNAME] if poke[TPNAME] && poke[TPNAME]!=""
if poke[TPSHADOW] # if this is a Shadow Pokémon
pokemon.makeShadow rescue nil
pokemon.pbUpdateShadowMoves(true) rescue nil
pokemon.makeNotShiny
end
pokemon.ballused=poke[TPBALL]
pokemon.ev[0]=poke[TPHPEV]
pokemon.ev[1]=poke[TPATKEV]
pokemon.ev[2]=poke[TPDEFEV]
pokemon.ev[3]=poke[TPSPEEDEV]
pokemon.ev[4]=poke[TPSATKEV]
pokemon.ev[5]=poke[TPSDEFEV]
pokemon.calcStats
party.push(pokemon)
end
success=true
break
end
return success ? [opponent,items,party] : nil
end
Then open the "Compilers" script and replace function pbCompileTrainers with the following:
Code:
def pbCompileTrainers
# Trainer types
records=[]
trainernames=[]
count=0
maxValue=0
pbCompilerEachPreppedLine("PBS/trainertypes.txt"){|line,lineno|
record=pbGetCsvRecord(line,lineno,[0,"unsUSSSeUs", # ID can be 0
nil,nil,nil,nil,nil,nil,nil,{
""=>2,"Male"=>0,"M"=>0,"0"=>0,"Female"=>1,"F"=>1,"1"=>1,"Mixed"=>2,"X"=>2,"2"=>2
},nil,nil]
)
if record[3] && (record[3]<0 || record[3]>255)
raise _INTL("Bad money amount (must be from 0 through 255)\r\n{1}",FileLineData.linereport)
end
record[3]=30 if !record[3]
if record[8] && (record[8]<0 || record[8]>255)
raise _INTL("Bad skill value (must be from 0 through 255)\r\n{1}",FileLineData.linereport)
end
record[8]=record[3] if !record[8]
record[9]="" if !record[9]
trainernames[record[0]]=record[2]
if records[record[0]]
raise _INTL("Two trainer types ({1} and {2}) have the same ID ({3}), which is not allowed.\r\n{4}",
records[record[0]][1],record[1],record[0],FileLineData.linereport)
end
records[record[0]]=record
maxValue=[maxValue,record[0]].max
}
count=records.compact.length
MessageTypes.setMessages(MessageTypes::TrainerTypes,trainernames)
code="class PBTrainers\r\n"
for rec in records
next if !rec
code+="#{rec[1]}=#{rec[0]}\r\n"
end
code+="\r\ndef PBTrainers.getName(id)\r\nreturn pbGetMessage(MessageTypes::TrainerTypes,id)\r\nend"
code+="\r\ndef PBTrainers.getCount\r\nreturn #{count}\r\nend"
code+="\r\ndef PBTrainers.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
eval(code)
pbAddScript(code,"PBTrainers")
File.open("Data/trainertypes.dat","wb"){|f|
Marshal.dump(records,f)
}
# Individual trainers
lines=[]
linenos=[]
lineno=1
File.open("PBS/trainers.txt","rb"){|f|
FileLineData.file="PBS/trainers.txt"
f.each_line {|line|
if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
line=line[3,line.length-3]
end
line=prepline(line)
if line!=""
lines.push(line)
linenos.push(lineno)
end
lineno+=1
}
}
nameoffset=0
trainers=[]
trainernames.clear
i=0; loop do break unless i<lines.length
FileLineData.setLine(lines[i],linenos[i])
trainername=parseTrainer(lines[i])
FileLineData.setLine(lines[i+1],linenos[i+1])
nameline=strsplit(lines[i+1],/\s*,\s*/)
name=nameline[0]
raise _INTL("Trainer name too long\r\n{1}",FileLineData.linereport) if name.length>=0x10000
trainernames.push(name)
partyid=0
if nameline[1] && nameline[1]!=""
raise _INTL("Expected a number for the trainer battle ID\r\n{1}",FileLineData.linereport) if !nameline[1][/^\d+$/]
partyid=nameline[1].to_i
end
FileLineData.setLine(lines[i+2],linenos[i+2])
items=strsplit(lines[i+2],/\s*,\s*/)
items[0].gsub!(/^\s+/,"") # Number of Pokémon
raise _INTL("Expected a number for the number of Pokémon\r\n{1}",FileLineData.linereport) if !items[0][/^\d+$/]
numpoke=items[0].to_i
realitems=[]
for j in 1...items.length # Items held by Trainer
realitems.push(parseItem(items[j])) if items[j] && items[j]!=""
end
pkmn=[]
for j in 0...numpoke
FileLineData.setLine(lines[i+j+3],linenos[i+j+3])
poke=strsplit(lines[i+j+3],/\s*,\s*/)
begin
# Species
poke[TPSPECIES]=parseSpecies(poke[TPSPECIES])
rescue
raise _INTL("Expected a species name: {1}\r\n{2}",poke[0],FileLineData.linereport)
end
# Level
poke[TPLEVEL]=poke[TPLEVEL].to_i
raise _INTL("Bad level: {1} (must be from 1-{2})\r\n{3}",poke[TPLEVEL],
PBExperience::MAXLEVEL,FileLineData.linereport) if poke[TPLEVEL]<=0 || poke[TPLEVEL]>PBExperience::MAXLEVEL
# Held item
if !poke[TPITEM] || poke[TPITEM]==""
poke[TPITEM]=TPDEFAULTS[TPITEM]
else
poke[TPITEM]=parseItem(poke[TPITEM])
end
# Moves
moves=[]
for j in [TPMOVE1,TPMOVE2,TPMOVE3,TPMOVE4]
moves.push(parseMove(poke[j])) if poke[j] && poke[j]!=""
end
for j in 0...4
index=[TPMOVE1,TPMOVE2,TPMOVE3,TPMOVE4][j]
if moves[j] && moves[j]!=0
poke[index]=moves[j]
else
poke[index]=TPDEFAULTS[index]
end
end
# Ability
if !poke[TPABILITY] || poke[TPABILITY]==""
poke[TPABILITY]=TPDEFAULTS[TPABILITY]
else
poke[TPABILITY]=poke[TPABILITY].to_i
raise _INTL("Bad abilityflag: {1} (must be 0 or 1 or 2-5)\r\n{2}",poke[TPABILITY],FileLineData.linereport) if poke[TPABILITY]<0 || poke[TPABILITY]>5
end
# Gender
if !poke[TPGENDER] || poke[TPGENDER]==""
poke[TPGENDER]=TPDEFAULTS[TPGENDER]
else
if poke[TPGENDER]=="M"
poke[TPGENDER]=0
elsif poke[TPGENDER]=="F"
poke[TPGENDER]=1
else
poke[TPGENDER]=poke[TPGENDER].to_i
raise _INTL("Bad genderflag: {1} (must be M or F, or 0 or 1)\r\n{2}",poke[TPGENDER],FileLineData.linereport) if poke[TPGENDER]<0 || poke[TPGENDER]>1
end
end
# Form
if !poke[TPFORM] || poke[TPFORM]==""
poke[TPFORM]=TPDEFAULTS[TPFORM]
else
poke[TPFORM]=poke[TPFORM].to_i
raise _INTL("Bad form: {1} (must be 0 or greater)\r\n{2}",poke[TPFORM],FileLineData.linereport) if poke[TPFORM]<0
end
# Shiny
if !poke[TPSHINY] || poke[TPSHINY]==""
poke[TPSHINY]=TPDEFAULTS[TPSHINY]
elsif poke[TPSHINY]=="shiny"
poke[TPSHINY]=true
else
poke[TPSHINY]=csvBoolean!(poke[TPSHINY].clone)
end
# Nature
if !poke[TPNATURE] || poke[TPNATURE]==""
poke[TPNATURE]=TPDEFAULTS[TPNATURE]
else
poke[TPNATURE]=parseNature(poke[TPNATURE])
end
# IVs
if !poke[TPIV] || poke[TPIV]==""
poke[TPIV]=TPDEFAULTS[TPIV]
else
poke[TPIV]=poke[TPIV].to_i
raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPIV],FileLineData.linereport) if poke[TPIV]<0 || poke[TPIV]>31
end
# Happiness
if !poke[TPHAPPINESS] || poke[TPHAPPINESS]==""
poke[TPHAPPINESS]=TPDEFAULTS[TPHAPPINESS]
else
poke[TPHAPPINESS]=poke[TPHAPPINESS].to_i
raise _INTL("Bad happiness: {1} (must be from 0-255)\r\n{2}",poke[TPHAPPINESS],FileLineData.linereport) if poke[TPHAPPINESS]<0 || poke[TPHAPPINESS]>255
end
# Nickname
if !poke[TPNAME] || poke[TPNAME]==""
poke[TPNAME]=TPDEFAULTS[TPNAME]
else
poke[TPNAME]=poke[TPNAME].to_s
raise _INTL("Bad nickname: {1} (must be 1-20 characters)\r\n{2}",poke[TPNAME],FileLineData.linereport) if (poke[TPNAME].to_s).length>20
end
# Shadow
if !poke[TPSHADOW] || poke[TPSHADOW]==""
poke[TPSHADOW]=TPDEFAULTS[TPSHADOW]
else
poke[TPSHADOW]=csvBoolean!(poke[TPSHADOW].clone)
end
# Ball
if !poke[TPBALL] || poke[TPBALL]==""
poke[TPBALL]=TPDEFAULTS[TPBALL]
else
poke[TPBALL]=poke[TPBALL].to_i
raise _INTL("Bad form: {1} (must be 0 or greater)\r\n{2}",poke[TPBALL],FileLineData.linereport) if poke[TPBALL]<0
end
# EVs
# HP
if !poke[TPHPEV] || poke[TPHPEV]==""
poke[TPHPEV]=TPDEFAULTS[TPHPEV]
else
poke[TPHPEV]=poke[TPHPEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPHPEV],FileLineData.linereport) if poke[TPHPEV]<0 || poke[TPHPEV]>255
end
# Atk
if !poke[TPATKEV] || poke[TPATKEV]==""
poke[TPATKEV]=TPDEFAULTS[TPATKEV]
else
poke[TPATKEV]=poke[TPATKEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPATKEV],FileLineData.linereport) if poke[TPATKEV]<0 || poke[TPATKEV]>255
end
# Def
if !poke[TPDEFEV] || poke[TPDEFEV]==""
poke[TPDEFEV]=TPDEFAULTS[TPDEFEV]
else
poke[TPDEFEV]=poke[TPDEFEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPDEFEV],FileLineData.linereport) if poke[TPDEFEV]<0 || poke[TPDEFEV]>255
end
# Speed
if !poke[TPSPEEDEV] || poke[TPSPEEDEV]==""
poke[TPSPEEDEV]=TPDEFAULTS[TPSPEEDEV]
else
poke[TPSPEEDEV]=poke[TPSPEEDEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPSPEEDEV],FileLineData.linereport) if poke[TPSPEEDEV]<0 || poke[TPSPEEDEV]>255
end
# Sp.Atk
if !poke[TPSATKEV] || poke[TPSATKEV]==""
poke[TPSATKEV]=TPDEFAULTS[TPSATKEV]
else
poke[TPSATKEV]=poke[TPSATKEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPSATKEV],FileLineData.linereport) if poke[TPSATKEV]<0 || poke[TPSATKEV]>255
end
# Sp.Def
if !poke[TPSDEFEV] || poke[TPSDEFEV]==""
poke[TPSDEFEV]=TPDEFAULTS[TPSDEFEV]
else
poke[TPSDEFEV]=poke[TPSDEFEV].to_i
raise _INTL("Bad EV: {1} (must be from 0-255)\r\n{2}",poke[TPSDEFEV],FileLineData.linereport) if poke[TPSDEFEV]<0 || poke[TPSDEFEV]>255
end
pkmn.push(poke)
end
i+=3+numpoke
MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames,trainernames)
trainers.push([trainername,name,realitems,pkmn,partyid])
nameoffset+=name.length
end
save_data(trainers,"Data/trainers.dat")
end
These will allow you to give custom EV spreads to trainers. The EVs come after everything else, and in the usual order for Essentials (speed/satk/sdef), so you'd define a trainer's mon like this for a 252 Atk/Speed mon:
Code:
GYARADOS,50,CHOICEBAND,AQUATAIL,EARTHQUAKE,STONEEDGE,BOUNCE,0,F,,,ADAMANT,31,,kogasa,,,0,252,0,252,0,0
As with the other fields, you don't have to give every trainer's pokemon specially defined EVs, or even extend commas that far. They'll default to 0 in every EV instead of the weird inflated formula vanilla Essentials uses, though.
- Credits
- DoesntKnowHowToPlay is responsible for making and posting it publicly, all credit goes to him.