Resource icon

Defining trainer Pokémon's EVs (Crosspost)

Pokémon Essentials Version
v16.2 ➖
Introduction
This is a crosspost of DoesntKnowHowToPlay's post from Pokecommunity, with his permission since 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:
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.
Author
DerxwnaKapsyla
First release
Last update
Rating
5.00 star(s) 2 ratings

More resources from DerxwnaKapsyla

Latest reviews

to VS Rival and gyms more competitive, is very cool! Ty ty!
this is awesome for when you want to make AI Trainers at their very best, like with a world championship event or something like it.
Top