DarkWolf13
Battle Subway Editor
- 275
- Posts
- 13
- Years
- RF HQ
- Seen Apr 30, 2025
DarkWolf13 here with some big news for Essentials users. For those wondering, the Battle Tower uses the same formula for the enemy roster, in which the Pokémon will have a random ability and an EV spread that evenly splits (255 in 2 stats, 170 in 3, 127 in 4 etc.). That sounds really unfun and non-challenging isn't it? Fret not! Thanks to [user]Vendily[/user] for guiding me and helping me to get it in, with these codes it will be possible to add competitive Pokémon sets to your Battle Tower enemy roster. And this is how it works.
It is all done in Challenge_Data so without further do..!
Find Class PBPokemon and simply replace the entire thing with this.
Once that is done, you will have to open battle_tower_pokemon.txt and edit the line accordingly. Here's an example of my code I had implemented.
Now as you see here, this Mightyena has 255 Atk and Speed EVs and its ability is set to Intimidate. This is the format:
Species ; Item ; Nature ; EV Spread ; Move 1, Move 2, Move 3, Move 4 ; Ability Index (Number, required at the end of each line else an error may occur)
For a fully optimized Mightyena, this'll be the code
Now this Mightyena has the fully optimized EV spread of 252 Attack and Speed, with the 6 remaining EVs doing into Defense with the ability set to Moxie hence the ability index set to 2, which is always the Hidden Ability.
With that said, I hope things work out for you. With this code, you'll be able to make an optimized competitive-battling experience at the Battle Tower. Hope you all enjoy this and special thanks again to [user]Vendily[/user] for making this possible.
It is all done in Challenge_Data so without further do..!
Find Class PBPokemon and simply replace the entire thing with this.
Code:
class PBPokemon
attr_accessor :species
attr_accessor :item
attr_accessor :nature
attr_accessor :move1
attr_accessor :move2
attr_accessor :move3
attr_accessor :move4
attr_accessor :ev
attr_accessor :ability
# This method is how each Pokémon is compiled from the PBS files listing
# Battle Tower/Cup Pokémon.
def self.fromInspected(str)
insp = str.gsub(/^\s+/, "").gsub(/\s+$/, "")
pieces = insp.split(/\s*;\s*/)
species = (GameData::Species.exists?(pieces[0])) ? GameData::Species.get(pieces[0]).id : nil
item = (GameData::Item.exists?(pieces[1])) ? GameData::Item.get(pieces[1]).id : nil
nature = (GameData::Nature.exists?(pieces[2])) ? GameData::Nature.get(pieces[2]).id : nil
ev = pieces[3].split(/\s*,\s*/)
ev_array = []
ev.each do |stat|
case stat.upcase
when "HP" then ev_array.push(:HP)
when "ATK" then ev_array.push(:ATTACK)
when "DEF" then ev_array.push(:DEFENSE)
when "SA", "SPATK" then ev_array.push(:SPECIAL_ATTACK)
when "SD", "SPDEF" then ev_array.push(:SPECIAL_DEFENSE)
when "SPD" then ev_array.push(:SPEED)
else ev_array.push(stat.to_i.clamp(0,Pokemon::EV_STAT_LIMIT))
end
end
moves = pieces[4].split(/\s*,\s*/)
moveid = []
Pokemon::MAX_MOVES.times do |i|
move_data = GameData::Move.try_get(moves[i])
moveid.push(move_data.id) if move_data
end
moveid.push(GameData::Move.keys.first) if moveid.length == 0 # Get any one move
ability = nil_or_empty?(pieces[5]) ? 2 : pieces[5].to_i
return self.new(species, item, nature, moveid[0], moveid[1], moveid[2], moveid[3], ev_array, ability)
end
def self.fromPokemon(pkmn)
ability_index = pkmn.ability_index
mov1 = (pkmn.moves[0]) ? pkmn.moves[0].id : nil
mov2 = (pkmn.moves[1]) ? pkmn.moves[1].id : nil
mov3 = (pkmn.moves[2]) ? pkmn.moves[2].id : nil
mov4 = (pkmn.moves[3]) ? pkmn.moves[3].id : nil
ev_array = []
GameData::Stat.each_main do |s|
ev_array.push(s.id) if pkmn.ev[s.id] > 60
end
return self.new(pkmn.species, pkmn.item_id, pkmn.nature,
mov1, mov2, mov3, mov4, ev_array, ability_index)
end
def initialize(species, item, nature, move1, move2, move3, move4, ev, ability)
@species = species
itm = GameData::Item.try_get(item)
@item = itm ? itm.id : nil
@nature = nature
@move1 = move1
@move2 = move2
@move3 = move3
@move4 = move4
@ev = ev
@ability = ability
end
def inspect
c1 = GameData::Species.get(@species).id
c2 = (@item) ? GameData::Item.get(@item).id : ""
c3 = (@nature) ? GameData::Nature.get(@nature).id : ""
evlist = ""
@ev.each do |stat|
evlist += "," if evlist != ""
evlist += stat.real_name_brief
end
c4 = (@move1) ? GameData::Move.get(@move1).id : ""
c5 = (@move2) ? GameData::Move.get(@move2).id : ""
c6 = (@move3) ? GameData::Move.get(@move3).id : ""
c7 = (@move4) ? GameData::Move.get(@move4).id : ""
c8 = (@ability)
return "#{c1};#{c2};#{c3};#{evlist};#{c4},#{c5},#{c6},#{c7};#{c8}"
end
# Unused.
def tocompact
return "#{species},#{item},#{nature},#{move1},#{move2},#{move3},#{move4},#{ev}"
end
# def _dump(depth)
# return [@species, @item, @nature, @move1, @move2, @move3, @move4, @ev].pack("vvCvvvvC")
# end
# def self._load(str)
# data = str.unpack("vvCvvvvC")
# return self.new(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7])
# end
def convertMove(move)
move = :FRUSTRATION if move == :RETURN && GameData::Move.exists?(:FRUSTRATION)
return move
end
def createPokemon(level, iv, trainer)
pkmn = Pokemon.new(@species, level, trainer, false)
pkmn.item = @item
pkmn.personalID = rand(2**16) | (rand(2**16) << 16)
pkmn.ability_index = ability
pkmn.ability = nil
pkmn.gender = rand(2)
pkmn.nature = nature
pkmn.happiness = 0
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move1)))
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move2))) if @move2
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move3))) if @move3
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move4))) if @move4
pkmn.moves.compact!
if ev.length > 0
crunched_evs = []
last_stat = nil
ev.each do |e|
if e.is_a?(Symbol)
crunched_evs.push(last_stat) if last_stat
last_stat = e
else # assigned stat
crunched_evs.push([last_stat, e])
last_stat = nil
end
end
crunched_evs.push(last_stat) if last_stat
ev_limit = Pokemon::EV_LIMIT
unassigned_evs = 0
crunched_evs.each do |stat|
if stat.is_a?(Array)
ev_limit -= stat[1]
else
unassigned_evs+=1
end
end
ev_limit = ev_limit.clamp(0, Pokemon::EV_LIMIT)
crunched_evs.each do |stat|
if stat.is_a?(Array)
pkmn.ev[stat[0]] = stat[1]
else
pkmn.ev[stat] = ev_limit / unassigned_evs
end
end
# ev.each { |stat| pkmn.ev[stat] = Pokemon::EV_LIMIT / ev.length }
end
GameData::Stat.each_main { |s| pkmn.iv[s.id] = iv }
pkmn.calc_stats
return pkmn
end
end
Once that is done, you will have to open battle_tower_pokemon.txt and edit the line accordingly. Here's an example of my code I had implemented.
Code:
MIGHTYENA;ASSAULTVEST;JOLLY;ATK,SPD;THROATCHOP,PLAYROUGH,THUNDERFANG,ICEFANG;0
Species ; Item ; Nature ; EV Spread ; Move 1, Move 2, Move 3, Move 4 ; Ability Index (Number, required at the end of each line else an error may occur)
For a fully optimized Mightyena, this'll be the code
Code:
MIGHTYENA;ASSAULTVEST;JOLLY;ATK,252,DEF,6,SPD,252;THROATCHOP,PLAYROUGH,THUNDERFANG,ICEFANG;2
With that said, I hope things work out for you. With this code, you'll be able to make an optimized competitive-battling experience at the Battle Tower. Hope you all enjoy this and special thanks again to [user]Vendily[/user] for making this possible.
Last edited: