• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Defining trainer Pok?mon's EVs

DoesntKnowHowToPlay

Tiny Umbrella with Lots and Lots of Good
265
Posts
12
Years
  • Seen Feb 24, 2024
Defining trainer Pokémon's EVs

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.
 

Derxwna Kapsyla

Derxwna "The Badman" Kapsyla
437
Posts
12
Years
You picked up Pokemon Essentials less than 5 hours ago and this what you do with it.

Honestly I can't say I'm surprised, and I'm probably not the only one who's wanted to see a script like this for a long time now! I probably won't be adding it to Faith & Prayer Version (Unless I decide to rebalance the entire game), but I'm sure someone out there will want this.
 
7
Posts
14
Years
  • Seen Aug 7, 2016
This is very interesting and helpful!
I'm looking to put something like this in my game, so I'm glad I found a post about it. I will def check it out once I get to that point!

Woo!
 
199
Posts
14
Years
  • Seen Jul 6, 2022
Great!!
I think you could do something similar with Ivs (for Gyro Ball, Trick Room teams and Hidden Power) the problem is to change all trainers in Trainers.txt to be compatible, unless you can do so:

Code:
GYARADOS,50,CHOICEBAND,AQUATAIL,EARTHQUAKE,STONEEDGE,BOUNCE,0,F,,,ADAMANT,31,,kogasa,,,0,252,0,252,0,0,[B]31,31,31,31,31[/B]
Leaving the first 31(or other number 0-31) like HP IV, while the five last 31(or other number 0-31) are Atk, Def, SATK, SDef, Speed
But I do not know what should be changed in the script
 

Arkadious

Developer of Fragmentum
50
Posts
8
Years
Hi :) Just wondering if this still works in Essentials 16.2
I keep getting interpreter errors whenever I try to start a trainer battle, regardless of whether the print version is used or not.

Spoiler:
 

Derxwna Kapsyla

Derxwna "The Badman" Kapsyla
437
Posts
12
Years
I added the script to 16.2 when updating my game, and so far everything's been working fine? It required a few reworking iirc but, that's a simple work of comparing changes between v16, v16.2, and the script
 

WolfPP

Spriter/ Pixel Artist
1,309
Posts
5
Years
Excuse me, sorry to necropost but i edited to put IV's too.

in 'PTrainer_NPCTrainers' replace to:
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
TPHPIV      = 23
TPATKIV     = 24
TPDEFIV     = 25
TPSPEEDIV   = 26
TPSATKIV    = 27
TPSDEFIV    = 28
TPDEFAULTS = [0,10,0,0,0,0,0,nil,nil,0,false,nil,10,70,nil,false,0,0,0,0,0,0,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.iv[0]=poke[TPHPIV]
      pokemon.iv[1]=poke[TPATKIV]
      pokemon.iv[2]=poke[TPDEFIV]
      pokemon.iv[3]=poke[TPSPEEDIV]
      pokemon.iv[4]=poke[TPSATKIV]
      pokemon.iv[5]=poke[TPSDEFIV]
      pokemon.calcStats
      party.push(pokemon)
    end
    success=true
    break
  end
  return success ? [opponent,items,party] : nil
end

in 'def pbCompileTrainers' replace to:

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
#
      # IVs
      # HP
      if !poke[TPHPIV] || poke[TPHPIV]==""
        poke[TPHPIV]=TPDEFAULTS[TPHPIV]
      else
        poke[TPHPIV]=poke[TPHPIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPHPIV],FileLineData.linereport) if poke[TPHPIV]<0 || poke[TPHPIV]>31
      end
      # Atk
      if !poke[TPATKIV] || poke[TPATKIV]==""
        poke[TPATKIV]=TPDEFAULTS[TPATKIV]
      else
        poke[TPATKIV]=poke[TPATKIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPATKIV],FileLineData.linereport) if poke[TPATKIV]<0 || poke[TPATKIV]>31
      end
      # Def
      if !poke[TPDEFIV] || poke[TPDEFIV]==""
        poke[TPDEFIV]=TPDEFAULTS[TPDEFIV]
      else
        poke[TPDEFIV]=poke[TPDEFIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPDEFIV],FileLineData.linereport) if poke[TPDEFIV]<0 || poke[TPDEFIV]>31
      end
      # Speed
      if !poke[TPSPEEDIV] || poke[TPSPEEDIV]==""
        poke[TPSPEEDIV]=TPDEFAULTS[TPSPEEDIV]
      else
        poke[TPSPEEDIV]=poke[TPSPEEDIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPSPEEDIV],FileLineData.linereport) if poke[TPSPEEDIV]<0 || poke[TPSPEEDIV]>31
      end
      # Sp.Atk
      if !poke[TPSATKIV] || poke[TPSATKIV]==""
        poke[TPSATKIV]=TPDEFAULTS[TPSATKIV]
      else
        poke[TPSATKIV]=poke[TPSATKIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPSATKIV],FileLineData.linereport) if poke[TPSATKIV]<0 || poke[TPSATKIV]>31
      end
      # Sp.Def
      if !poke[TPSDEFIV] || poke[TPSDEFIV]==""
        poke[TPSDEFIV]=TPDEFAULTS[TPSDEFIV]
      else
        poke[TPSDEFIV]=poke[TPSDEFIV].to_i
        raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPSDEFIV],FileLineData.linereport) if poke[TPSDEFIV]<0 || poke[TPSDEFIV]>31
      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

Example in trainer.txt:
# See GYARADOS for example: EV - HP,ATK,DEF,SPEED,SATK,SDEF; IV - HP,ATK,DEF,SPEED,STAK,SDEF
GYARADOS,50,GYARADOSITE,AQUATAIL,EARTHQUAKE,STONEEDGE,BOUNCE,0,F,,,ADAMANT,31,,Kogasa,,,4,252,0,252,0,0,31,31,31,31,31,31

Ty ty!
 
Back
Top