Script a trainer battle
This guide explains how to build a trainer battle from a script, for the runtime cases Pokémon Studio's editor alone cannot cover: an opposing team that depends on the game state, assembled from existing Studio data.
To start a wild battle instead, see Start a wild battle.
Why script a trainer battle
Pokémon Studio already authors every static part of a battle. A trainer carries a full team, a bag, an AI level, prize money and dialogue, and each Pokémon can have its own form, gender, nature, IVs, EVs, held item, moves, ability and shininess. For a fixed fight, the editor is enough and a script adds nothing.
You reach for a script when the opposing side must be decided at runtime:
- A trainer whose team depends on the game state: a rival that counters the player's starter, or a "trainer tower" whose levels scale with the player.
- Simply launching a battle from your own logic instead of a map event.
Building the battle
When you need full control over the opposing side, or a team that depends on the player, you build the battle yourself with Battle::Logic::BattleInfo, the object every battle ultimately runs on.
The interface in short
bi = Battle::Logic::BattleInfo.new
bi.add_party(0, *bi.player_basic_info)
bi.add_party(1, party, name, klass, battler, bag, base_money, ai_level)
$scene.call_scene(Battle::Scene, bi)
add_party(bank, party, ...)adds a party to a bank:0for the player,1for the enemy. Onlybankandpartyare mandatory; the rest arename, klass, battler, bag, base_money, ai_level, victory_text, defeat_text.- A
nameon bank 1 is what makes it a trainer battle. Without one, the enemy side is nameless and the fight runs as a wild battle. player_basic_inforeturns the player's party, name, class, sprite and bag, ready to splat intoadd_partyon bank 0.BattleInfo.newaccepts a hash to presetvs_type,max_level,battle_bgm,victory_bgm,defeat_bgm,background_name,battle_idand more.
Hand-writing the enemy party is possible, but the high-value patterns build it from data that already exists.
Example: a scaling trainer tower
Instead of cloning a trainer a dozen times at rising levels in the editor, author it once in Studio and raise its levels at battle time:
trainer = data_trainer(:ace_trainer_gary)
target_level = $actors.sum(&:level) / $actors.size # the player's average level
party = trainer.party.map { |encounter| encounter.to_creature(target_level) }
bag = PFM::Bag.new
trainer.bag_entries.each { |entry| bag.add_item(entry[:dbSymbol], entry[:amount]) }
bi = Battle::Logic::BattleInfo.new
bi.add_party(0, *bi.player_basic_info)
bi.add_party(1, party, trainer.name, trainer.class_name, trainer.resources, bag, trainer.base_money, trainer.ai)
$scene.call_scene(Battle::Scene, bi)
data_trainer loads the Studio trainer (by db_symbol or id), and encounter.to_creature(level) builds each of its Pokémon at the level you pass, omit the argument to keep the levels set in Studio. One trainer now powers an entire tower of escalating fights.
Example: a rival that counters the player's starter
Rather than building three near-identical rivals per fight in Studio, author one and add the counter of the player's starter to its team when the battle starts:
# Replace this with however your project records the chosen starter (here a game variable holding a db_symbol).
player_starter = $game_variables[10]
counter = { bulbasaur: :charmander, charmander: :squirtle, squirtle: :bulbasaur }[player_starter]
trainer = data_trainer(:rival_route_1)
party = trainer.party.map(&:to_creature)
party << PFM::Pokemon.generate_from_hash(id: counter, level: party.map(&:level).max)
bag = PFM::Bag.new
trainer.bag_entries.each { |entry| bag.add_item(entry[:dbSymbol], entry[:amount]) }
bi = Battle::Logic::BattleInfo.new
bi.add_party(0, *bi.player_basic_info)
bi.add_party(1, party, trainer.name, trainer.class_name, trainer.resources, bag, trainer.base_money, trainer.ai)
$scene.call_scene(Battle::Scene, bi)
You author the rival once and the type matchup follows the player's choice. The same "load then modify" approach opens other ideas: a grind trainer whose team is drawn from the Pokémon the player has caught, or "ghost" trainers replaying another player's team.
Reading the outcome
Register $game_temp.battle_proc before launching the scene; it is called with the result code when the battle ends:
$game_temp.battle_proc = proc do |result|
# 0 = player won, 1 = player fled, 2 = player lost, 3 = enemy fled
case result
when 0
# handle victory
when 2
# handle defeat
end
end
$scene.call_scene(Battle::Scene, bi)
The same outcome also sets the global switches BT_Victory, BT_Player_Flee and BT_Defeat, which an event running after the battle can test.
Conclusion
- Studio authors the static data; you script a trainer battle for runtime-dependent fights, or to launch one from your own logic.
- Build a
Battle::Logic::BattleInfo, add the player on bank 0 and the trainer on bank 1, then launch with$scene.call_scene(Battle::Scene, bi). - Load existing Studio trainers with
data_trainerandto_creature(level)to reuse and modify their teams: scale a trainer tower, or counter the player's starter, without cloning trainers in the editor. - Read the result through
$game_temp.battle_proc(or theBT_Victory/BT_Defeatswitches) to branch your event. - For a wild battle, see the Start a wild battle guide.