Added battle debug menu (access with F9)

This commit is contained in:
Maruno17
2021-12-05 20:24:20 +00:00
parent 3650a078e7
commit 95916e242e
7 changed files with 1776 additions and 4 deletions

View File

@@ -169,6 +169,165 @@ module PokemonDebugMixin
end
end
#===============================================================================
#
#===============================================================================
module Battle::DebugMixin
def pbBattleDebug(battle, show_all = true)
commands = CommandMenuList.new
BattleDebugMenuCommands.each do |option, hash|
commands.add(option, hash) if show_all || hash["always_show"]
end
viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
viewport.z = 99999
sprites = {}
sprites["textbox"] = pbCreateMessageWindow
sprites["textbox"].letterbyletter = false
sprites["cmdwindow"] = Window_CommandPokemonEx.new(commands.list)
cmdwindow = sprites["cmdwindow"]
cmdwindow.x = 0
cmdwindow.y = 0
cmdwindow.height = Graphics.height - sprites["textbox"].height
cmdwindow.viewport = viewport
cmdwindow.visible = true
sprites["textbox"].text = commands.getDesc(cmdwindow.index)
ret = -1
refresh = true
loop do
loop do
oldindex = cmdwindow.index
cmdwindow.update
if refresh || cmdwindow.index != oldindex
sprites["textbox"].text = commands.getDesc(cmdwindow.index)
refresh = false
end
Graphics.update
Input.update
if Input.trigger?(Input::BACK)
parent = commands.getParent
if parent
pbPlayCancelSE
commands.currentList = parent[0]
cmdwindow.commands = commands.list
cmdwindow.index = parent[1]
refresh = true
else
ret = -1
break
end
elsif Input.trigger?(Input::USE)
ret = cmdwindow.index
break
end
end
break if ret < 0
cmd = commands.getCommand(ret)
if commands.hasSubMenu?(cmd)
pbPlayDecisionSE
commands.currentList = cmd
cmdwindow.commands = commands.list
cmdwindow.index = 0
refresh = true
else
BattleDebugMenuCommands.call("effect", cmd, battle)
end
end
pbPlayCloseMenuSE
pbDisposeMessageWindow(sprites["textbox"])
pbDisposeSpriteHash(sprites)
viewport.dispose
end
def pbBattleBattlerDebug(battler, show_all = true)
commands = CommandMenuList.new
BattlerDebugMenuCommands.each do |option, hash|
commands.add(option, hash) if show_all || hash["always_show"]
end
viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
viewport.z = 99999
sprites = {}
sprites["infowindow"] = Window_AdvancedTextPokemon.new("")
infowindow = sprites["infowindow"]
infowindow.x = 0
infowindow.y = 0
infowindow.width = Graphics.width / 2
infowindow.height = Graphics.height
infowindow.viewport = viewport
infowindow.visible = true
sprites["dummywindow"] = Window_AdvancedTextPokemon.new("")
sprites["dummywindow"].y = Graphics.height
sprites["dummywindow"].width = Graphics.width
sprites["dummywindow"].height = 0
need_refresh = true
cmd = 0
loop do
if need_refresh
help_text = ""
help_text += sprintf("[%d] %s", battler.index, battler.pbThis)
help_text += "\r\n"
help_text += _INTL("Species: {1}", GameData::Species.get(battler.species).name)
help_text += "\r\n"
help_text += _INTL("Form: {1}", battler.form)
help_text += "\r\n"
help_text += _INTL("Level {1}, {2}", battler.level,
(battler.pokemon.male?) ? "" : (battler.pokemon.female?) ? "" : "genderless")
help_text += ", " + _INTL("Shiny") if battler.pokemon.shiny?
help_text += "\r\n"
help_text += _INTL("HP: {1}/{2} ({3}%)", battler.hp, battler.totalhp, (100.0 * battler.hp / battler.totalhp).to_i)
help_text += "\r\n"
help_text += _INTL("Status: {1}", GameData::Status.get(battler.status).name)
case battler.status
when :SLEEP
help_text += " " + _INTL("({1} rounds left)", battler.statusCount)
when :POISON
if battler.statusCount > 0
help_text += " " + _INTL("(toxic, {1}/16)", battler.effects[PBEffects::Toxic])
end
end
help_text += "\r\n"
stages = []
GameData::Stat.each_battle do |stat|
next if battler.stages[stat.id] == 0
stage_text = ""
stage_text += "+" if battler.stages[stat.id] > 0
stage_text += battler.stages[stat.id].to_s
stage_text += " " + stat.name_brief
stages.push(stage_text)
end
help_text += _INTL("Stat stages: {1}", (stages.empty?) ? "-" : stages.join(", "))
help_text += "\r\n"
help_text += _INTL("Ability: {1}", (battler.ability) ? battler.abilityName : "-")
help_text += "\r\n"
help_text += _INTL("Item: {1}", (battler.item) ? battler.itemName : "-")
sprites["infowindow"].text = help_text
need_refresh = false
end
# Choose a command
cmd = Kernel.pbShowCommands(sprites["dummywindow"], commands.list, -1, cmd)
if cmd < 0 # Cancel
parent = commands.getParent
if parent # Go up a level
commands.currentList = parent[0]
cmd = parent[1]
else # Exit
break
end
else
real_cmd = commands.getCommand(cmd)
if commands.hasSubMenu?(real_cmd)
commands.currentList = real_cmd
cmd = 0
else
BattlerDebugMenuCommands.call("effect", real_cmd, battler, battler.pokemon, battler.battle)
need_refresh = true
end
end
end
pbDisposeSpriteHash(sprites)
viewport.dispose
end
end
#===============================================================================
#
#===============================================================================
@@ -183,3 +342,7 @@ end
class PokemonDebugPartyScreen
include PokemonDebugMixin
end
class Battle
include Battle::DebugMixin
end

View File

@@ -0,0 +1,372 @@
=begin
# TODO:
Positions (Battle::ActivePosition)
PBEffects::HealingWish
PBEffects::LunarDance
backdrop, backdropBase
turnCount
items (of foe trainers)
initialItems - Array of two arrays, each with one value per party index
recycleItems - Array of two arrays, each with one value per party index
belch - Array of two arrays, each with one value per party index
corrosiveGas - Array of two arrays, each with one value per party index
first_poke_ball - both for Ball Fetch
poke_ball_failed - both for Ball Fetch
View party screen for each trainer's team, be able to edit properties of Pokémon
that aren't in battle.
=end
#===============================================================================
#
#===============================================================================
module BattleDebugMenuCommands
@@commands = HandlerHashBasic.new
def self.register(option, hash)
@@commands.add(option, hash)
end
def self.registerIf(condition, hash)
@@commands.addIf(condition, hash)
end
def self.copy(option, *new_options)
@@commands.copy(option, *new_options)
end
def self.each
@@commands.each { |key, hash| yield key, hash }
end
def self.hasFunction?(option, function)
option_hash = @@commands[option]
return option_hash && option_hash.keys.include?(function)
end
def self.getFunction(option, function)
option_hash = @@commands[option]
return (option_hash && option_hash[function]) ? option_hash[function] : nil
end
def self.call(function, option, *args)
option_hash = @@commands[option]
return nil if !option_hash || !option_hash[function]
return (option_hash[function].call(*args) == true)
end
end
#===============================================================================
# Battler Options
#===============================================================================
BattleDebugMenuCommands.register("battlers", {
"parent" => "main",
"name" => _INTL("Battlers..."),
"description" => _INTL("Look at Pokémon in battle and change their properties."),
"always_show" => true
})
BattleDebugMenuCommands.register("list_player_battlers", {
"parent" => "battlers",
"name" => _INTL("Player-Side Battlers"),
"description" => _INTL("Edit Pokémon on the player's side of battle."),
"always_show" => true,
"effect" => proc { |battle|
battlers = []
cmds = []
battle.allSameSideBattlers.each do |b|
battlers.push(b)
text = "[#{b.index}] #{b.name} "
if b.pbOwnedByPlayer?
text += " (yours)"
else
text += " (ally's)"
end
cmds.push(text)
end
cmd = 0
loop do
cmd = pbMessage("\\ts[]" + _INTL("Choose a Pokémon."), cmds, -1, nil, cmd)
break if cmd < 0
battle.pbBattleBattlerDebug(battlers[cmd])
end
}
})
BattleDebugMenuCommands.register("list_foe_battlers", {
"parent" => "battlers",
"name" => _INTL("Foe-Side Battlers"),
"description" => _INTL("Edit Pokémon on the opposing side of battle."),
"always_show" => true,
"effect" => proc { |battle|
battlers = []
cmds = []
battle.allOtherSideBattlers.each do |b|
battlers.push(b)
cmds.push("[#{b.index}] #{b.name} ")
end
cmd = 0
loop do
cmd = pbMessage("\\ts[]" + _INTL("Choose a Pokémon."), cmds, -1, nil, cmd)
break if cmd < 0
battle.pbBattleBattlerDebug(battlers[cmd])
end
}
})
#===============================================================================
# Field Options
#===============================================================================
BattleDebugMenuCommands.register("field", {
"parent" => "main",
"name" => _INTL("Field Effects..."),
"description" => _INTL("Effects that apply to the whole battlefield."),
"always_show" => true
})
BattleDebugMenuCommands.register("weather", {
"parent" => "field",
"name" => _INTL("Weather"),
"description" => _INTL("Set weather and duration."),
"always_show" => true,
"effect" => proc { |battle|
weather_types = []
weather_cmds = []
GameData::BattleWeather.each do |weather|
next if weather.id == :None
weather_types.push(weather.id)
weather_cmds.push(weather.name)
end
cmd = 0
loop do
weather_data = GameData::BattleWeather.try_get(battle.field.weather)
msg = _INTL("Current weather: {1}", weather_data.name || _INTL("Unknown"))
if weather_data.id != :None
if battle.field.weatherDuration > 0
msg += "\r\n"
msg += _INTL("Duration : {1} more round(s)", battle.field.weatherDuration)
elsif battle.field.weatherDuration < 0
msg += "\r\n"
msg += _INTL("Duration : Infinite")
end
end
cmd = pbMessage("\\ts[]" + msg, [
_INTL("Change type"),
_INTL("Change duration"),
_INTL("Clear weather")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Change type
weather_cmd = weather_types.index(battle.field.weather) || 0
new_weather = pbMessage(
"\\ts[]" + _INTL("Choose the new weather type."), weather_cmds, -1, nil, weather_cmd)
if new_weather >= 0
battle.field.weather = weather_types[new_weather]
battle.field.weatherDuration = 5 if battle.field.weatherDuration == 0
end
when 1 # Change duration
if battle.field.weather == :None
pbMessage("\\ts[]" + _INTL("There is no weather."))
next
end
params = ChooseNumberParams.new
params.setRange(0, 99)
params.setInitialValue([battle.field.weatherDuration, 0].max)
params.setCancelValue([battle.field.weatherDuration, 0].max)
new_duration = pbMessageChooseNumber(
"\\ts[]" + _INTL("Choose the new weather duration (0=infinite)."), params)
if new_duration != [battle.field.weatherDuration, 0].max
battle.field.weatherDuration = (new_duration == 0) ? -1 : new_duration
end
when 2 # Clear weather
battle.field.weather = :None
battle.field.weatherDuration = 0
end
end
}
})
BattleDebugMenuCommands.register("terrain", {
"parent" => "field",
"name" => _INTL("Terrain"),
"description" => _INTL("Set terrain and duration."),
"always_show" => true,
"effect" => proc { |battle|
terrain_types = []
terrain_cmds = []
GameData::BattleTerrain.each do |terrain|
next if terrain.id == :None
terrain_types.push(terrain.id)
terrain_cmds.push(terrain.name)
end
cmd = 0
loop do
terrain_data = GameData::BattleTerrain.try_get(battle.field.terrain)
msg = _INTL("Current terrain: {1}", terrain_data.name || _INTL("Unknown"))
if terrain_data.id != :None
if battle.field.terrainDuration > 0
msg += "\r\n"
msg += _INTL("Duration : {1} more round(s)", battle.field.terrainDuration)
elsif battle.field.terrainDuration < 0
msg += "\r\n"
msg += _INTL("Duration : Infinite")
end
end
cmd = pbMessage("\\ts[]" + msg, [
_INTL("Change type"),
_INTL("Change duration"),
_INTL("Clear terrain")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Change type
terrain_cmd = terrain_types.index(battle.field.terrain) || 0
new_terrain = pbMessage(
"\\ts[]" + _INTL("Choose the new terrain type."), terrain_cmds, -1, nil, terrain_cmd)
if new_terrain >= 0
battle.field.terrain = terrain_types[new_terrain]
battle.field.terrainDuration = 5 if battle.field.terrainDuration == 0
end
when 1 # Change duration
if battle.field.terrain == :None
pbMessage("\\ts[]" + _INTL("There is no terrain."))
next
end
params = ChooseNumberParams.new
params.setRange(0, 99)
params.setInitialValue([battle.field.terrainDuration, 0].max)
params.setCancelValue([battle.field.terrainDuration, 0].max)
new_duration = pbMessageChooseNumber(
"\\ts[]" + _INTL("Choose the new terrain duration (0=infinite)."), params)
if new_duration != [battle.field.terrainDuration, 0].max
battle.field.terrainDuration = (new_duration == 0) ? -1 : new_duration
end
when 2 # Clear terrain
battle.field.terrain = :None
battle.field.terrainDuration = 0
end
end
}
})
BattleDebugMenuCommands.register("environment", {
"parent" => "field",
"name" => _INTL("Environment/Time"),
"description" => _INTL("Set the battle's environment and time of day."),
"always_show" => true,
"effect" => proc { |battle|
environment_types = []
environment_cmds = []
GameData::Environment.each do |environment|
environment_types.push(environment.id)
environment_cmds.push(environment.name)
end
cmd = 0
loop do
environment_data = GameData::Environment.try_get(battle.environment)
msg = _INTL("Environment: {1}", environment_data.name || _INTL("Unknown"))
msg += "\r\n"
msg += _INTL("Time of day: {1}", [_INTL("Day"), _INTL("Evening"), _INTL("Night")][battle.time])
cmd = pbMessage("\\ts[]" + msg, [
_INTL("Change environment"),
_INTL("Change time of day")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Change environment
environment_cmd = environment_types.index(battle.environment) || 0
new_environment = pbMessage(
"\\ts[]" + _INTL("Choose the new environment."), environment_cmds, -1, nil, environment_cmd)
if new_environment >= 0
battle.environment = environment_types[new_environment]
end
when 1 # Change time of day
new_time = pbMessage("\\ts[]" + _INTL("Choose the new time."),
[_INTL("Day"), _INTL("Evening"), _INTL("Night")], -1, nil, battle.time)
battle.time = new_time if new_time >= 0 && new_time != battle.time
end
end
}
})
BattleDebugMenuCommands.register("set_field_effects", {
"parent" => "field",
"name" => _INTL("Other Field Effects..."),
"description" => _INTL("View/set other effects that apply to the whole battlefield."),
"always_show" => true,
"effect" => proc { |battle|
editor = Battle::DebugSetEffects.new(battle, :field)
editor.update
editor.dispose
}
})
BattleDebugMenuCommands.register("player_side", {
"parent" => "field",
"name" => _INTL("Player's Side Effects..."),
"description" => _INTL("Effects that apply to the side the player is on."),
"always_show" => true,
"effect" => proc { |battle|
editor = Battle::DebugSetEffects.new(battle, :side, 0)
editor.update
editor.dispose
}
})
BattleDebugMenuCommands.register("opposing_side", {
"parent" => "field",
"name" => _INTL("Foe's Side Effects..."),
"description" => _INTL("Effects that apply to the opposing side."),
"always_show" => true,
"effect" => proc { |battle|
editor = Battle::DebugSetEffects.new(battle, :side, 1)
editor.update
editor.dispose
}
})
#===============================================================================
# Trainer Options
#===============================================================================
BattleDebugMenuCommands.register("trainers", {
"parent" => "main",
"name" => _INTL("Trainer Options..."),
"description" => _INTL("Variables that apply to trainers."),
"always_show" => true
})
BattleDebugMenuCommands.register("mega_evolution", {
"parent" => "trainers",
"name" => _INTL("Mega Evolution"),
"description" => _INTL("Whether each trainer is allowed to Mega Evolve."),
"always_show" => true,
"effect" => proc { |battle|
cmd = 0
loop do
commands = []
cmds = []
battle.megaEvolution.each_with_index do |side_values, side|
trainers = (side == 0) ? battle.player : battle.opponent
next if !trainers
side_values.each_with_index do |value, i|
next if !trainers[i]
text = (side == 0) ? "Your side:" : "Foe side:"
text += sprintf(" %d: %s", i, trainers[i].name)
text += sprintf(" [ABLE]") if value == -1
text += sprintf(" [UNABLE]") if value == -2
commands.push(text)
cmds.push([side, i])
end
end
cmd = pbMessage("\\ts[]" + _INTL("Choose trainer to toggle whether they can Mega Evolve."),
commands, -1, nil, cmd)
break if cmd < 0
real_cmd = cmds[cmd]
if battle.megaEvolution[real_cmd[0]][real_cmd[1]] == -1
battle.megaEvolution[real_cmd[0]][real_cmd[1]] = -2 # Make unable
else
battle.megaEvolution[real_cmd[0]][real_cmd[1]] = -1 # Make able
end
end
}
})

View File

@@ -0,0 +1,785 @@
=begin
# TODO:
Trigger ability (probably not)
Some stuff relating to Shadow Pokémon?
Actual stats? @attack, @defense, etc.
@turnCount
=end
#===============================================================================
#
#===============================================================================
module BattlerDebugMenuCommands
@@commands = HandlerHashBasic.new
def self.register(option, hash)
@@commands.add(option, hash)
end
def self.registerIf(condition, hash)
@@commands.addIf(condition, hash)
end
def self.copy(option, *new_options)
@@commands.copy(option, *new_options)
end
def self.each
@@commands.each { |key, hash| yield key, hash }
end
def self.hasFunction?(option, function)
option_hash = @@commands[option]
return option_hash && option_hash.keys.include?(function)
end
def self.getFunction(option, function)
option_hash = @@commands[option]
return (option_hash && option_hash[function]) ? option_hash[function] : nil
end
def self.call(function, option, *args)
option_hash = @@commands[option]
return nil if !option_hash || !option_hash[function]
return (option_hash[function].call(*args) == true)
end
end
#===============================================================================
# HP/Status options
#===============================================================================
BattlerDebugMenuCommands.register("hpstatusmenu", {
"parent" => "main",
"name" => _INTL("HP/Status..."),
"always_show" => true
})
BattlerDebugMenuCommands.register("sethp", {
"parent" => "hpstatusmenu",
"name" => _INTL("Set HP"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
elsif battler.totalhp == 1
pbMessage("\\ts[]" + _INTL("Can't change HP, {1}'s maximum HP is 1.", pkmn.name))
next
end
params = ChooseNumberParams.new
params.setRange(1, battler.totalhp)
params.setDefaultValue(battler.hp)
new_hp = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set {1}'s HP (1-{2}).", battler.pbThis(true), battler.totalhp), params)
battler.hp = new_hp if new_hp != battler.hp
}
})
BattlerDebugMenuCommands.register("setstatus", {
"parent" => "hpstatusmenu",
"name" => _INTL("Set status"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
elsif pkmn.hp <= 0
pbMessage("\\ts[]" + _INTL("{1} is fainted, can't change status.", pkmn.name))
next
end
cmd = 0
commands = [_INTL("[Cure]")]
ids = [:NONE]
GameData::Status.each do |s|
next if s.id == :NONE
commands.push(_INTL("Set {1}", s.name))
ids.push(s.id)
end
loop do
msg = _INTL("Current status: {1}", GameData::Status.get(battler.status).name)
if battler.status == :SLEEP
msg += " " + _INTL("(turns: {1})", battler.statusCount)
elsif battler.status == :POISON && battler.statusCount > 0
msg += " " + _INTL("(toxic, count: {1})", battler.statusCount)
end
cmd = pbMessage("\\ts[]" + msg, commands, -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Cure
battler.status = :NONE
else # Give status problem
case ids[cmd]
when :SLEEP
params = ChooseNumberParams.new
params.setRange(0, 99)
params.setDefaultValue((battler.status == :SLEEP) ? battler.statusCount : 3)
params.setCancelValue(-1)
count = pbMessageChooseNumber("\\ts[]" + _INTL("Set {1}'s sleep count (0-99).", battler.pbThis(true)), params)
next if count < 0
battler.statusCount = count
when :POISON
if pbConfirmMessage("\\ts[]" + _INTL("Make {1} badly poisoned (toxic)?", battler.pbThis(true)))
params = ChooseNumberParams.new
params.setRange(0, 15)
params.setDefaultValue(0)
params.setCancelValue(-1)
count = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set {1}'s toxic count (0-15).", battler.pbThis(true)), params)
next if count < 0
battler.statusCount = 1
battler.effects[PBEffects::Toxic] = count
else
battler.statusCount = 0
end
end
battler.status = ids[cmd]
end
end
}
})
BattlerDebugMenuCommands.register("fullheal", {
"parent" => "hpstatusmenu",
"name" => _INTL("Heal HP and status"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
end
battler.hp = battler.totalhp
battler.status = :NONE
}
})
#===============================================================================
# Level/stats options
#===============================================================================
BattlerDebugMenuCommands.register("levelstats", {
"parent" => "main",
"name" => _INTL("Stats/level..."),
"always_show" => true
})
BattlerDebugMenuCommands.register("setstatstages", {
"parent" => "levelstats",
"name" => _INTL("Set stat stages"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
end
cmd = 0
loop do
commands = []
stat_ids = []
GameData::Stat.each_battle do |stat|
command_name = stat.name + ": "
command_name += "+" if battler.stages[stat.id] > 0
command_name += battler.stages[stat.id].to_s
commands.push(command_name)
stat_ids.push(stat.id)
end
commands.push(_INTL("[Reset all]"))
cmd = pbMessage("\\ts[]" + _INTL("Choose a stat stage to change."), commands, -1, nil, cmd)
break if cmd < 0
if cmd < stat_ids.length # Set a stat
params = ChooseNumberParams.new
params.setRange(-6, 6)
params.setNegativesAllowed(true)
params.setDefaultValue(battler.stages[stat_ids[cmd]])
value = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set the stage for {1}.", GameData::Stat.get(stat_ids[cmd]).name), params)
battler.stages[stat_ids[cmd]] = value
else # Reset all stats
GameData::Stat.each_battle { |stat| battler.stages[stat.id] = 0 }
end
end
}
})
BattlerDebugMenuCommands.register("setlevel", {
"parent" => "levelstats",
"name" => _INTL("Set level"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
end
params = ChooseNumberParams.new
params.setRange(1, GameData::GrowthRate.max_level)
params.setDefaultValue(pkmn.level)
level = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set the Pokémon's level (max. {1}).", params.maxNumber), params)
if level != pkmn.level
pkmn.level = level
pkmn.calc_stats
battler.pbUpdate
end
}
})
BattlerDebugMenuCommands.register("setexp", {
"parent" => "levelstats",
"name" => _INTL("Set Exp"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.egg?
pbMessage("\\ts[]" + _INTL("{1} is an egg.", pkmn.name))
next
end
min_exp = pkmn.growth_rate.minimum_exp_for_level(pkmn.level)
max_exp = pkmn.growth_rate.minimum_exp_for_level(pkmn.level + 1)
if min_exp == max_exp
pbMessage("\\ts[]" + _INTL("{1} is at the maximum level.", pkmn.name))
next
end
params = ChooseNumberParams.new
params.setRange(min_exp, max_exp - 1)
params.setDefaultValue(pkmn.exp)
new_exp = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set the Pokémon's Exp (range {1}-{2}).", min_exp, max_exp - 1), params)
pkmn.exp = new_exp if new_exp != pkmn.exp
}
})
BattlerDebugMenuCommands.register("hiddenvalues", {
"parent" => "levelstats",
"name" => _INTL("EV/IV..."),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
loop do
persid = sprintf("0x%08X", pkmn.personalID)
cmd = pbMessage("\\ts[]" + _INTL("Personal ID is {1}.", persid), [
_INTL("Set EVs"),
_INTL("Set IVs")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Set EVs
cmd2 = 0
loop do
total_evs = 0
ev_commands = []
ev_id = []
GameData::Stat.each_main do |s|
ev_commands.push(s.name + " (#{pkmn.ev[s.id]})")
ev_id.push(s.id)
total_evs += pkmn.ev[s.id]
end
ev_commands.push(_INTL("Randomise all"))
ev_commands.push(_INTL("Max randomise all"))
cmd2 = pbMessage("\\ts[]" + _INTL("Change which EV?\nTotal: {1}/{2} ({3}%)",
total_evs, Pokemon::EV_LIMIT, 100 * total_evs / Pokemon::EV_LIMIT),
ev_commands, -1, nil, cmd2)
break if cmd2 < 0
if cmd2 < ev_id.length
params = ChooseNumberParams.new
upperLimit = 0
GameData::Stat.each_main { |s| upperLimit += pkmn.ev[s.id] if s.id != ev_id[cmd2] }
upperLimit = Pokemon::EV_LIMIT - upperLimit
upperLimit = [upperLimit, Pokemon::EV_STAT_LIMIT].min
thisValue = [pkmn.ev[ev_id[cmd2]], upperLimit].min
params.setRange(0, upperLimit)
params.setDefaultValue(thisValue)
params.setCancelValue(thisValue)
f = pbMessageChooseNumber("\\ts[]" + _INTL("Set the EV for {1} (max. {2}).",
GameData::Stat.get(ev_id[cmd2]).name, upperLimit), params)
if f != pkmn.ev[ev_id[cmd2]]
pkmn.ev[ev_id[cmd2]] = f
pkmn.calc_stats
battler.pbUpdate
end
else # (Max) Randomise all
evTotalTarget = Pokemon::EV_LIMIT
if cmd2 == evcommands.length - 2 # Randomize all (not max)
evTotalTarget = rand(Pokemon::EV_LIMIT)
end
GameData::Stat.each_main { |s| pkmn.ev[s.id] = 0 }
while evTotalTarget > 0
r = rand(ev_id.length)
next if pkmn.ev[ev_id[r]] >= Pokemon::EV_STAT_LIMIT
addVal = 1 + rand(Pokemon::EV_STAT_LIMIT / 4)
addVal = addVal.clamp(0, evTotalTarget)
addVal = addVal.clamp(0, Pokemon::EV_STAT_LIMIT - pkmn.ev[ev_id[r]])
next if addVal == 0
pkmn.ev[ev_id[r]] += addVal
evTotalTarget -= addVal
end
pkmn.calc_stats
battler.pbUpdate
end
end
when 1 # Set IVs
cmd2 = 0
loop do
hiddenpower = pbHiddenPower(pkmn)
totaliv = 0
ivcommands = []
iv_id = []
GameData::Stat.each_main do |s|
ivcommands.push(s.name + " (#{pkmn.iv[s.id]})")
iv_id.push(s.id)
totaliv += pkmn.iv[s.id]
end
msg = _INTL("Change which IV?\nHidden Power:\n{1}, power {2}\nTotal: {3}/{4} ({5}%)",
GameData::Type.get(hiddenpower[0]).name, hiddenpower[1], totaliv,
iv_id.length * Pokemon::IV_STAT_LIMIT, 100 * totaliv / (iv_id.length * Pokemon::IV_STAT_LIMIT))
ivcommands.push(_INTL("Randomise all"))
cmd2 = pbMessage("\\ts[]" + msg, ivcommands, -1, nil, cmd2)
break if cmd2 < 0
if cmd2 < iv_id.length
params = ChooseNumberParams.new
params.setRange(0, Pokemon::IV_STAT_LIMIT)
params.setDefaultValue(pkmn.iv[iv_id[cmd2]])
params.setCancelValue(pkmn.iv[iv_id[cmd2]])
f = pbMessageChooseNumber("\\ts[]" + _INTL("Set the IV for {1} (max. 31).",
GameData::Stat.get(iv_id[cmd2]).name), params)
if f != pkmn.iv[iv_id[cmd2]]
pkmn.iv[iv_id[cmd2]] = f
pkmn.calc_stats
battler.pbUpdate
end
else # Randomise all
GameData::Stat.each_main { |s| pkmn.iv[s.id] = rand(Pokemon::IV_STAT_LIMIT + 1) }
pkmn.calc_stats
battler.pbUpdate
end
end
end
end
}
})
BattlerDebugMenuCommands.register("sethappiness", {
"parent" => "levelstats",
"name" => _INTL("Set happiness"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
params = ChooseNumberParams.new
params.setRange(0, 255)
params.setDefaultValue(pkmn.happiness)
h = pbMessageChooseNumber("\\ts[]" + _INTL("Set the Pokémon's happiness (max. 255)."), params)
pkmn.happiness = h if h != pkmn.happiness
}
})
#===============================================================================
# Types
#===============================================================================
BattlerDebugMenuCommands.register("settypes", {
"parent" => "main",
"name" => _INTL("Set types"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
max_main_types = 2 # The most types a Pokémon can have normally
cmd = 0
loop do
commands = []
types = []
(0...max_main_types).each do |i|
type = battler.types[i]
type_name = (type) ? GameData::Type.get(type).name : "-"
commands.push(_INTL("Type {1}: {2}", i + 1, type_name))
types.push(type)
end
extra_type = battler.effects[PBEffects::Type3]
extra_type_name = (extra_type) ? GameData::Type.get(extra_type).name : "-"
commands.push(_INTL("Extra type: {1}", extra_type_name))
types.push(extra_type)
msg = _INTL("Effective types: {1}", battler.pbTypes(true).map { |t| GameData::Type.get(t).name }.join("/"))
msg += "\r\n" + _INTL("(Change a type to itself to remove it.)")
cmd = pbMessage("\\ts[]" + msg, commands, -1, nil, cmd)
break if cmd < 0
old_type = types[cmd]
new_type = pbChooseTypeList(old_type)
if new_type
if new_type == old_type
if pbConfirmMessage(_INTL("Remove this type?"))
if cmd < max_main_types
battler.types[cmd] = nil
else
battler.effects[PBEffects::Type3] = nil
end
battler.types.compact!
end
else
if cmd < max_main_types
battler.types[cmd] = new_type
else
battler.effects[PBEffects::Type3] = new_type
end
end
end
end
}
})
#===============================================================================
# Moves options
#===============================================================================
BattlerDebugMenuCommands.register("moves", {
"parent" => "main",
"name" => _INTL("Moves..."),
"always_show" => true
})
BattlerDebugMenuCommands.register("teachmove", {
"parent" => "moves",
"name" => _INTL("Teach move"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.numMoves >= Pokemon::MAX_MOVES
pbMessage("\\ts[]" + _INTL("{1} already knows {2} moves. It needs to forget one first.",
pkmn.name, pkmn.numMoves))
next
end
new_move = pbChooseMoveList
next if !new_move
move_name = GameData::Move.get(new_move).name
if pkmn.hasMove?(new_move)
pbMessage("\\ts[]" + _INTL("{1} already knows {2}.", pkmn.name, move_name))
next
end
pkmn.learn_move(new_move)
battler.moves.push(Move.from_pokemon_move(self, pkmn.moves.last)) if battler
pbMessage("\\ts[]" + _INTL("{1} learned {2}!", pkmn.name, move_name))
}
})
BattlerDebugMenuCommands.register("forgetmove", {
"parent" => "moves",
"name" => _INTL("Forget move"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
move_names = []
move_indices = []
pkmn.moves.each_with_index do |move, index|
next if !move || !move.id
if move.total_pp <= 0
move_names.push(_INTL("{1} (PP: ---)", move.name))
else
move_names.push(_INTL("{1} (PP: {2}/{3})", move.name, move.pp, move.total_pp))
end
move_indices.push(index)
end
cmd = pbMessage("\\ts[]" + _INTL("Forget which move?"), move_names, -1)
next if cmd < 0
old_move_name = pkmn.moves[move_indices[cmd]].name
pkmn.forget_move_at_index(move_indices[cmd])
battler.moves.delete_at(move_indices[cmd]) if battler
pbMessage("\\ts[]" + _INTL("{1} forgot {2}.", pkmn.name, old_move_name))
}
})
BattlerDebugMenuCommands.register("setmovepp", {
"parent" => "moves",
"name" => _INTL("Set move PP"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
loop do
move_names = []
move_indices = []
pkmn.moves.each_with_index do |move, index|
next if !move || !move.id
if move.total_pp <= 0
move_names.push(_INTL("{1} (PP: ---)", move.name))
else
move_names.push(_INTL("{1} (PP: {2}/{3})", move.name, move.pp, move.total_pp))
end
move_indices.push(index)
end
commands = move_names + [_INTL("Restore all PP")]
cmd = pbMessage("\\ts[]" + _INTL("Alter PP of which move?"), commands, -1, nil, cmd)
break if cmd < 0
if cmd >= 0 && cmd < move_names.length # Move
move = pkmn.moves[move_indices[cmd]]
move_name = move.name
if move.total_pp <= 0
pbMessage("\\ts[]" + _INTL("{1} has infinite PP.", move_name))
else
cmd2 = 0
loop do
msg = _INTL("{1}: PP {2}/{3} (PP Up {4}/3)", move_name, move.pp, move.total_pp, move.ppup)
cmd2 = pbMessage("\\ts[]" + msg, [
_INTL("Set PP"),
_INTL("Full PP"),
_INTL("Set PP Up")], -1, nil, cmd2)
break if cmd2 < 0
case cmd2
when 0 # Change PP
params = ChooseNumberParams.new
params.setRange(0, move.total_pp)
params.setDefaultValue(move.pp)
h = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set PP of {1} (max. {2}).", move_name, move.total_pp), params)
move.pp = h
if battler && battler.moves[move_indices[cmd]].id == move.id
battler.moves[move_indices[cmd]].pp = move.pp
end
when 1 # Full PP
move.pp = move.total_pp
if battler && battler.moves[move_indices[cmd]].id == move.id
battler.moves[move_indices[cmd]].pp = move.pp
end
when 2 # Change PP Up
params = ChooseNumberParams.new
params.setRange(0, 3)
params.setDefaultValue(move.ppup)
h = pbMessageChooseNumber(
"\\ts[]" + _INTL("Set PP Up of {1} (max. 3).", move_name), params)
move.ppup = h
move.pp = move.total_pp if move.pp > move.total_pp
if battler && battler.moves[move_indices[cmd]].id == move.id
battler.moves[move_indices[cmd]].pp = move.pp
end
end
end
end
elsif cmd == commands.length - 1 # Restore all PP
pkmn.heal_PP
if battler
battler.moves.each { |move| move.pp = move.total_pp }
end
end
end
}
})
#===============================================================================
# Other options
#===============================================================================
BattlerDebugMenuCommands.register("setitem", {
"parent" => "main",
"name" => _INTL("Set item"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
commands = [
_INTL("Change item"),
_INTL("Remove item")
]
loop do
msg = (pkmn.hasItem?) ? _INTL("Item is {1}.", pkmn.item.name) : _INTL("No item.")
cmd = pbMessage("\\ts[]" + msg, commands, -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Change item
item = pbChooseItemList(pkmn.item_id)
if item && item != pkmn.item_id
battler.item = item
if GameData::Item.get(item).is_mail?
pkmn.mail = Mail.new(item, _INTL("Text"), $player.name)
end
end
when 1 # Remove item
if pkmn.hasItem?
battler.item = nil
pkmn.mail = nil
end
else
break
end
end
}
})
BattlerDebugMenuCommands.register("setability", {
"parent" => "main",
"name" => _INTL("Set ability"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
commands = [
_INTL("Set ability for battler"),
_INTL("Set ability for Pokémon"),
_INTL("Reset")
]
loop do
msg = _INTL("Battler's ability is {1}. Pokémon's ability is {2}.",
battler.abilityName, pkmn.ability.name)
cmd = pbMessage("\\ts[]" + msg, commands, -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Set ability for battler
new_ability = pbChooseAbilityList(pkmn.ability_id)
if new_ability && new_ability != battler.ability_id
battler.ability = new_ability
end
when 1 # Set ability for Pokémon
new_ability = pbChooseAbilityList(pkmn.ability_id)
if new_ability && new_ability != pkmn.ability_id
pkmn.ability = new_ability
battler.ability = pkmn.ability
end
when 2 # Reset
pkmn.ability_index = nil
pkmn.ability = nil
battler.ability = pkmn.ability
end
end
}
})
BattlerDebugMenuCommands.register("setnature", {
"parent" => "main",
"name" => _INTL("Set nature"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
commands = []
ids = []
GameData::Nature.each do |nature|
if nature.stat_changes.length == 0
commands.push(_INTL("{1} (---)", nature.real_name))
else
plus_text = ""
minus_text = ""
nature.stat_changes.each do |change|
if change[1] > 0
plus_text += "/" if !plus_text.empty?
plus_text += GameData::Stat.get(change[0]).name_brief
elsif change[1] < 0
minus_text += "/" if !minus_text.empty?
minus_text += GameData::Stat.get(change[0]).name_brief
end
end
commands.push(_INTL("{1} (+{2}, -{3})", nature.real_name, plus_text, minus_text))
end
ids.push(nature.id)
end
commands.push(_INTL("[Reset]"))
cmd = ids.index(pkmn.nature_id || ids[0])
loop do
msg = _INTL("Nature is {1}.", pkmn.nature.name)
cmd = pbMessage("\\ts[]" + msg, commands, -1, nil, cmd)
break if cmd < 0
if cmd >= 0 && cmd < commands.length - 1 # Set nature
pkmn.nature = ids[cmd]
elsif cmd == commands.length - 1 # Reset
pkmn.nature = nil
end
battler.pbUpdate
end
}
})
BattlerDebugMenuCommands.register("setgender", {
"parent" => "main",
"name" => _INTL("Set gender"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
if pkmn.singleGendered?
pbMessage("\\ts[]" + _INTL("{1} is single-gendered or genderless.", pkmn.speciesName))
next
end
cmd = 0
loop do
msg = [_INTL("Gender is male."), _INTL("Gender is female.")][pkmn.male? ? 0 : 1]
cmd = pbMessage("\\ts[]" + msg, [
_INTL("Make male"),
_INTL("Make female"),
_INTL("Reset")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Make male
pkmn.makeMale
pbMessage("\\ts[]" + _INTL("{1}'s gender couldn't be changed.", pkmn.name)) if !pkmn.male?
when 1 # Make female
pkmn.makeFemale
pbMessage("\\ts[]" + _INTL("{1}'s gender couldn't be changed.", pkmn.name)) if !pkmn.female?
when 2 # Reset
pkmn.gender = nil
end
end
}
})
BattlerDebugMenuCommands.register("speciesform", {
"parent" => "main",
"name" => _INTL("Set form"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
formcmds = [[], []]
GameData::Species.each do |sp|
next if sp.species != pkmn.species
form_name = sp.form_name
form_name = _INTL("Unnamed form") if !form_name || form_name.empty?
form_name = sprintf("%d: %s", sp.form, form_name)
formcmds[0].push(sp.form)
formcmds[1].push(form_name)
cmd = formcmds[0].length - 1 if pkmn.form == sp.form
end
if formcmds[0].length <= 1
pbMessage("\\ts[]" + _INTL("Species {1} only has one form.", pkmn.speciesName))
next
end
loop do
cmd = pbMessage("\\ts[]" + _INTL("Form is {1}.", pkmn.form), formcmds[1], -1, nil, cmd)
next if cmd < 0
f = formcmds[0][cmd]
if f != pkmn.form
pkmn.forced_form = nil
if MultipleForms.hasFunction?(pkmn, "getForm")
next if !pbConfirmMessage(_INTL("This species decides its own form. Override?"))
pkmn.forced_form = f
end
pkmn.form_simple = f
end
end
}
})
#===============================================================================
# Shininess
#===============================================================================
BattlerDebugMenuCommands.register("setshininess", {
"parent" => "main",
"name" => _INTL("Set shininess"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
cmd = 0
loop do
msg_idx = pkmn.shiny? ? (pkmn.super_shiny? ? 1 : 0) : 2
msg = [_INTL("Is shiny."), _INTL("Is super shiny."), _INTL("Is normal (not shiny).")][msg_idx]
cmd = pbMessage("\\ts[]" + msg, [
_INTL("Make shiny"),
_INTL("Make super shiny"),
_INTL("Make normal"),
_INTL("Reset")], -1, nil, cmd)
break if cmd < 0
case cmd
when 0 # Make shiny
pkmn.shiny = true
pkmn.super_shiny = false
when 1 # Make super shiny
pkmn.super_shiny = true
when 2 # Make normal
pkmn.shiny = false
pkmn.super_shiny = false
when 3 # Reset
pkmn.shiny = nil
pkmn.super_shiny = nil
end
end
}
})
#===============================================================================
# Set effects
#===============================================================================
BattlerDebugMenuCommands.register("set_effects", {
"parent" => "main",
"name" => _INTL("Set effects"),
"always_show" => true,
"effect" => proc { |battler, pkmn, battle|
editor = Battle::DebugSetEffects.new(battle, :battler, battler.index)
editor.update
editor.dispose
}
})

View File

@@ -0,0 +1,436 @@
#===============================================================================
# Effect values that can be edited via the battle debug menu.
#===============================================================================
module Battle::DebugVariables
BATTLER_EFFECTS = {
PBEffects::AquaRing => {name: "Aqua Ring applies", default: false},
PBEffects::Attract => {name: "Battler that self is attracted to", default: -1}, # Battler index
PBEffects::BanefulBunker => {name: "Baneful Bunker applies this round", default: false},
# PBEffects::BeakBlast - only applies to use of specific move, not suitable for setting via debug
PBEffects::Bide => {name: "Bide number of rounds remaining", default: 0},
PBEffects::BideDamage => {name: "Bide damage accumulated", default: 0, max: 999},
PBEffects::BideTarget => {name: "Bide last battler to hurt self", default: -1}, # Battler index
PBEffects::BurnUp => {name: "Burn Up has removed self's Fire type", default: false},
PBEffects::Charge => {name: "Charge number of rounds remaining", default: 0},
PBEffects::ChoiceBand => {name: "Move locked into by Choice items", default: nil, type: :move},
PBEffects::Confusion => {name: "Confusion number of rounds remaining", default: 0},
# PBEffects::Counter - not suitable for setting via debug
# PBEffects::CounterTarget - not suitable for setting via debug
PBEffects::Curse => {name: "Curse damaging applies", default: false},
# PBEffects::Dancer - only used while Dancer is running, not suitable for setting via debug
PBEffects::DefenseCurl => {name: "Used Defense Curl", default: false},
# PBEffects::DestinyBond - not suitable for setting via debug
# PBEffects::DestinyBondPrevious - not suitable for setting via debug
# PBEffects::DestinyBondTarget - not suitable for setting via debug
PBEffects::Disable => {name: "Disable number of rounds remaining", default: 0},
PBEffects::DisableMove => {name: "Disabled move", default: nil, type: :move},
PBEffects::Electrify => {name: "Electrify making moves Electric", default: false},
PBEffects::Embargo => {name: "Embargo number of rounds remaining", default: 0},
PBEffects::Encore => {name: "Encore number of rounds remaining", default: 0},
PBEffects::EncoreMove => {name: "Encored move", default: nil, type: :move},
PBEffects::Endure => {name: "Endures all lethal damage this round", default: false},
# PBEffects::FirstPledge - only applies to use of specific move, not suitable for setting via debug
PBEffects::FlashFire => {name: "Flash Fire powering up Fire moves", default: false},
PBEffects::Flinch => {name: "Will flinch this round", default: false},
PBEffects::FocusEnergy => {name: "Focus Energy critical hit stages (0-4)", default: 0, max: 4},
# PBEffects::FocusPunch - only applies to use of specific move, not suitable for setting via debug
PBEffects::FollowMe => {name: "Follow Me drawing in attacks (if 1+)", default: 0}, # Order of use, lowest takes priority
PBEffects::RagePowder => {name: "Rage Powder applies (use with Follow Me)", default: false},
PBEffects::Foresight => {name: "Foresight applies (Ghost loses immunities)", default: false},
PBEffects::FuryCutter => {name: "Fury Cutter power multiplier 2**x (0-4)", default: 0, max: 4},
PBEffects::GastroAcid => {name: "Gastro Acid is negating self's ability", default: false},
# PBEffects::GemConsumed - only applies during use of move, not suitable for setting via debug
PBEffects::Grudge => {name: "Grudge will apply if self faints", default: false},
PBEffects::HealBlock => {name: "Heal Block number of rounds remaining", default: 0},
PBEffects::HelpingHand => {name: "Helping Hand will power up self's move", default: false},
PBEffects::HyperBeam => {name: "Hyper Beam recharge rounds remaining", default: 0},
# PBEffects::Illusion - is a Pokémon object, too complex to be worth bothering with
PBEffects::Imprison => {name: "Imprison disables others' moves known by self", default: false},
PBEffects::Ingrain => {name: "Ingrain applies", default: false},
# PBEffects::Instruct - only used while Instruct is running, not suitable for setting via debug
# PBEffects::Instructed - only used while Instruct is running, not suitable for setting via debug
PBEffects::JawLock => {name: "Battler trapping self with Jaw Lock", default: -1}, # Battler index
PBEffects::KingsShield => {name: "King's Shield applies this round", default: false},
PBEffects::LaserFocus => {name: "Laser Focus certain critial hit duration", default: 0},
PBEffects::LeechSeed => {name: "Battler that used Leech Seed on self", default: -1}, # Battler index
PBEffects::LockOn => {name: "Lock-On number of rounds remaining", default: 0},
PBEffects::LockOnPos => {name: "Battler that self is targeting with Lock-On", default: -1}, # Battler index
# PBEffects::MagicBounce - only applies during use of move, not suitable for setting via debug
# PBEffects::MagicCoat - only applies to use of specific move, not suitable for setting via debug
PBEffects::MagnetRise => {name: "Magnet Rise number of rounds remaining", default: 0},
PBEffects::MeanLook => {name: "Battler trapping self with Mean Look, etc.", default: -1}, # Battler index
# PBEffects::MeFirst - only applies to use of specific move, not suitable for setting via debug
PBEffects::Metronome => {name: "Metronome item power multiplier 1 + 0.2*x (0-5)", default: 0, max: 5},
PBEffects::MicleBerry => {name: "Micle Berry boosting next move's accuracy", default: false},
PBEffects::Minimize => {name: "Used Minimize", default: false},
PBEffects::MiracleEye => {name: "Miracle Eye applies (Dark loses immunities)", default: false},
# PBEffects::MirrorCoat - not suitable for setting via debug
# PBEffects::MirrorCoatTarget - not suitable for setting via debug
# PBEffects::MoveNext - not suitable for setting via debug
PBEffects::MudSport => {name: "Used Mud Sport (Gen 5 and older)", default: false},
PBEffects::Nightmare => {name: "Taking Nightmare damage", default: false},
PBEffects::NoRetreat => {name: "No Retreat trapping self in battle", default: false},
PBEffects::Obstruct => {name: "Obstruct applies this round", default: false},
PBEffects::Octolock => {name: "Battler trapping self with Octolock", default: -1}, # Battler index
PBEffects::Outrage => {name: "Outrage number of rounds remaining", default: 0},
# PBEffects::ParentalBond - only applies during use of move, not suitable for setting via debug
PBEffects::PerishSong => {name: "Perish Song number of rounds remaining", default: 0},
PBEffects::PerishSongUser => {name: "Battler that used Perish Song on self", default: -1}, # Battler index
PBEffects::PickupItem => {name: "Item retrievable by Pickup", default: nil, type: :item},
PBEffects::PickupUse => {name: "Pickup item consumed time (higher=more recent)", default: 0},
PBEffects::Pinch => {name: "(Battle Palace) Behavior changed at <50% HP", default: false},
PBEffects::Powder => {name: "Powder will explode self's Fire move this round", default: false},
# PBEffects::PowerTrick - doesn't actually swap the stats therefore does nothing, not suitable for setting via debug
# PBEffects::Prankster - not suitable for setting via debug
# PBEffects::PriorityAbility - not suitable for setting via debug
# PBEffects::PriorityItem - not suitable for setting via debug
PBEffects::Protect => {name: "Protect applies this round", default: false},
PBEffects::ProtectRate => {name: "Protect success chance 1/x", default: 1, max: 999},
# PBEffects::Pursuit - not suitable for setting via debug
# PBEffects::Quash - not suitable for setting via debug
# PBEffects::Rage - only applies to use of specific move, not suitable for setting via debug
PBEffects::Rollout => {name: "Rollout rounds remaining (lower=stronger)", default: 0},
PBEffects::Roost => {name: "Roost removing Flying type this round", default: false},
# PBEffects::ShellTrap - only applies to use of specific move, not suitable for setting via debug
# PBEffects::SkyDrop - only applies to use of specific move, not suitable for setting via debug
PBEffects::SlowStart => {name: "Slow Start rounds remaining", default: 0},
PBEffects::SmackDown => {name: "Smack Down is grounding self", default: false},
# PBEffects::Snatch - only applies to use of specific move, not suitable for setting via debug
PBEffects::SpikyShield => {name: "Spiky Shield applies this round", default: false},
PBEffects::Spotlight => {name: "Spotlight drawing in attacks (if 1+)", default: 0},
PBEffects::Stockpile => {name: "Stockpile count (0-3)", default: 0, max: 3},
PBEffects::StockpileDef => {name: "Def stages gained by Stockpile (0-12)", default: 0, max: 12},
PBEffects::StockpileSpDef => {name: "Sp. Def stages gained by Stockpile (0-12)", default: 0, max: 12},
PBEffects::Substitute => {name: "Substitute's HP", default: 0, max: 999},
PBEffects::TarShot => {name: "Tar Shot weakening self to Fire", default: false},
PBEffects::Taunt => {name: "Taunt number of rounds remaining", default: 0},
PBEffects::Telekinesis => {name: "Telekinesis number of rounds remaining", default: 0},
PBEffects::ThroatChop => {name: "Throat Chop number of rounds remaining", default: 0},
PBEffects::Torment => {name: "Torment preventing repeating moves", default: false},
# PBEffects::Toxic - set elsewhere
# PBEffects::Transform - too complex to be worth bothering with
# PBEffects::TransformSpecies - too complex to be worth bothering with
PBEffects::Trapping => {name: "Trapping number of rounds remaining", default: 0},
PBEffects::TrappingMove => {name: "Move that is trapping self", default: nil, type: :move},
PBEffects::TrappingUser => {name: "Battler trapping self (for Binding Band)", default: -1}, # Battler index
PBEffects::Truant => {name: "Truant will loaf around this round", default: false},
# PBEffects::TwoTurnAttack - only applies to use of specific moves, not suitable for setting via debug
# PBEffects::Type3 - set elsewhere
PBEffects::Unburden => {name: "Self lost its item (for Unburden)", default: false},
PBEffects::Uproar => {name: "Uproar number of rounds remaining", default: 0},
PBEffects::WaterSport => {name: "Used Water Sport (Gen 5 and older)", default: false},
PBEffects::WeightChange => {name: "Weight change +0.1*x kg", default: 0, min: -99999, max: 99999},
PBEffects::Yawn => {name: "Yawn rounds remaining until falling asleep", default: 0}
}
SIDE_EFFECTS = {
PBEffects::AuroraVeil => {name: "Aurora Veil duration", default: 0},
PBEffects::CraftyShield => {name: "Crafty Shield applies this round", default: false},
PBEffects::EchoedVoiceCounter => {name: "Echoed Voice rounds used (max. 5)", default: 0, max: 5},
PBEffects::EchoedVoiceUsed => {name: "Echoed Voice used this round", default: false},
PBEffects::LastRoundFainted => {name: "Round when side's battler last fainted", default: -2}, # Treated as -1, isn't a battler index
PBEffects::LightScreen => {name: "Light Screen duration", default: 0},
PBEffects::LuckyChant => {name: "Lucky Chant duration", default: 0},
PBEffects::MatBlock => {name: "Mat Block applies this round", default: false},
PBEffects::Mist => {name: "Mist duration", default: 0},
PBEffects::QuickGuard => {name: "Quick Guard applies this round", default: false},
PBEffects::Rainbow => {name: "Rainbow duration", default: 0},
PBEffects::Reflect => {name: "Reflect duration", default: 0},
PBEffects::Round => {name: "Round was used this round", default: false},
PBEffects::Safeguard => {name: "Safeguard duration", default: 0},
PBEffects::SeaOfFire => {name: "Sea Of Fire duration", default: 0},
PBEffects::Spikes => {name: "Spikes layers (0-3)", default: 0, max: 3},
PBEffects::StealthRock => {name: "Stealth Rock exists", default: false},
PBEffects::StickyWeb => {name: "Sticky Web exists", default: false},
PBEffects::Swamp => {name: "Swamp duration", default: 0},
PBEffects::Tailwind => {name: "Tailwind duration", default: 0},
PBEffects::ToxicSpikes => {name: "Toxic Spikes layers (0-2)", default: 0, max: 2},
PBEffects::WideGuard => {name: "Wide Guard applies this round", default: false}
}
FIELD_EFFECTS = {
PBEffects::AmuletCoin => {name: "Amulet Coin doubling prize money", default: false},
PBEffects::FairyLock => {name: "Fairy Lock trapping duration", default: 0},
PBEffects::FusionBolt => {name: "Fusion Bolt was used", default: false},
PBEffects::FusionFlare => {name: "Fusion Flare was used", default: false},
PBEffects::Gravity => {name: "Gravity duration", default: 0},
PBEffects::HappyHour => {name: "Happy Hour doubling prize money", default: false},
PBEffects::IonDeluge => {name: "Ion Deluge making moves Electric", default: false},
PBEffects::MagicRoom => {name: "Magic Room duration", default: 0},
PBEffects::MudSportField => {name: "Mud Sport duration (Gen 6+)", default: 0},
PBEffects::PayDay => {name: "Pay Day additional prize money", default: 0, max: Settings::MAX_MONEY},
PBEffects::TrickRoom => {name: "Trick Room duration", default: 0},
PBEffects::WaterSportField => {name: "Water Sport duration (Gen 6+)", default: 0},
PBEffects::WonderRoom => {name: "Wonder Room duration", default: 0}
}
end
#===============================================================================
# Screen for listing the above battle variables for modifying.
#===============================================================================
class SpriteWindow_DebugBattleFieldEffects < Window_DrawableCommand
BASE_TEXT_COLOR = Color.new(96, 96, 96)
RED_TEXT_COLOR = Color.new(168, 48, 56)
GREEN_TEXT_COLOR = Color.new(0, 144, 0)
TEXT_SHADOW_COLOR = Color.new(208, 208, 200)
def initialize(viewport, battle, variables, variables_data)
@battle = battle
@variables = variables
@variables_data = variables_data
super(0, 0, Graphics.width, Graphics.height, viewport)
end
def itemCount
return @variables_data.length
end
def shadowtext(x, y, w, h, t, align = 0, colors = 0)
width = self.contents.text_size(t).width
if align == 1 # Right aligned
x += w - width
elsif align == 2 # Centre aligned
x += (w - width) / 2
end
base_color = BASE_TEXT_COLOR
case colors
when 1 then base_color = RED_TEXT_COLOR
when 2 then base_color = GREEN_TEXT_COLOR
end
pbDrawShadowText(self.contents, x, y, [width, w].max, h, t, base_color, TEXT_SHADOW_COLOR)
end
def drawItem(index, _count, rect)
pbSetNarrowFont(self.contents)
variable_data = @variables_data[@variables_data.keys[index]]
variable = @variables[@variables_data.keys[index]]
# Variables which aren't their default value are colored differently
default = variable_data[:default]
default = -1 if default == -2
different = (variable || default) != default
color = (different) ? 2 : 0
# Draw cursor
rect = drawCursor(index, rect)
# Get value's text to draw
variable_text = variable.to_s
if variable_data[:default] == -1 # Battler
if variable >= 0
battler_name = @battle.battlers[variable].name
battler_name = "-" if nil_or_empty?(battler_name)
variable_text = sprintf("[%d] %s", variable, battler_name)
else
variable_text = _INTL("[None]")
end
elsif variable_data[:default] == nil # Move, item
variable_text = _INTL("[None]") if !variable
end
# Draw text
total_width = rect.width
name_width = total_width * 80 / 100
value_width = total_width * 20 / 100
self.shadowtext(rect.x, rect.y, name_width, rect.height, variable_data[:name], 0, color)
self.shadowtext(rect.x + name_width, rect.y, value_width, rect.height, variable_text, 1, color)
end
end
#===============================================================================
#
#===============================================================================
class Battle::DebugSetEffects
def initialize(battle, mode, side = 0)
@battle = battle
@mode = mode
@side = side
case @mode
when :field
@variables_data = Battle::DebugVariables::FIELD_EFFECTS
@variables = @battle.field.effects
when :side
@variables_data = Battle::DebugVariables::SIDE_EFFECTS
@variables = @battle.sides[@side].effects
when :battler
@variables_data = Battle::DebugVariables::BATTLER_EFFECTS
@variables = @battle.battlers[@side].effects
end
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport.z = 99999
@window = SpriteWindow_DebugBattleFieldEffects.new(@viewport, @battle, @variables, @variables_data)
@window.active = true
end
def dispose
@window.dispose
@viewport.dispose
end
def choose_number(default, min, max)
params = ChooseNumberParams.new
params.setRange(min, max)
params.setDefaultValue(default)
params.setNegativesAllowed(true) if min < 0
return pbMessageChooseNumber(_INTL("Set value ({1}-{2}).", min, max), params)
end
def choose_battler(default)
commands = [_INTL("[None]")]
cmds = [-1]
cmd = 0
@battle.battlers.each_with_index do |battler, i|
next if battler.nil? # Position doesn't exist
name = battler.pbThis
name = "-" if battler.fainted? || nil_or_empty?(name)
commands.push(sprintf("[%d] %s", i, name))
cmds.push(i)
cmd = cmds.length - 1 if default == i
end
cmd = pbMessage("\\ts[]" + _INTL("Choose a battler/position."), commands, -1, nil, cmd)
return (cmd >= 0) ? cmds[cmd] : default
end
def update_input_for_boolean(effect, variable_data)
if Input.trigger?(Input::USE)
pbPlayDecisionSE
@variables[effect] = !@variables[effect]
return true
elsif Input.trigger?(Input::ACTION) && @variables[effect]
pbPlayDecisionSE
@variables[effect] = false
return true
elsif Input.repeat?(Input::LEFT) && @variables[effect]
pbPlayCursorSE
@variables[effect] = false
return true
elsif Input.repeat?(Input::RIGHT) && !@variables[effect]
pbPlayCursorSE
@variables[effect] = true
return true
end
return false
end
def update_input_for_integer(effect, default, variable_data)
true_default = (default == -2) ? -1 : default
min = variable_data[:min] || true_default
max = variable_data[:max] || 99
if Input.trigger?(Input::USE)
pbPlayDecisionSE
new_value = choose_number(@variables[effect], min, max)
if new_value != @variables[effect]
@variables[effect] = new_value
return true
end
elsif Input.trigger?(Input::ACTION) && @variables[effect] != true_default
pbPlayDecisionSE
@variables[effect] = true_default
return true
elsif Input.repeat?(Input::LEFT) && @variables[effect] > min
pbPlayCursorSE
@variables[effect] -= 1
return true
elsif Input.repeat?(Input::RIGHT) && @variables[effect] < max
pbPlayCursorSE
@variables[effect] += 1
return true
end
return false
end
def update_input_for_battler_index(effect, variable_data)
if Input.trigger?(Input::USE)
pbPlayDecisionSE
new_value = choose_battler(@variables[effect])
if new_value != @variables[effect]
@variables[effect] = new_value
return true
end
elsif Input.trigger?(Input::ACTION) && @variables[effect] != -1
pbPlayDecisionSE
@variables[effect] = -1
return true
elsif Input.repeat?(Input::LEFT)
if @variables[effect] > -1
pbPlayCursorSE
loop do
@variables[effect] -= 1
break if @variables[effect] == -1 || @battle.battlers[@variables[effect]]
end
return true
end
elsif Input.repeat?(Input::RIGHT)
if @variables[effect] < @battle.battlers.length - 1
pbPlayCursorSE
loop do
@variables[effect] += 1
break if @battle.battlers[@variables[effect]]
end
return true
end
end
return false
end
def update_input_for_move(effect, variable_data)
if Input.trigger?(Input::USE)
pbPlayDecisionSE
new_value = pbChooseMoveList(@variables[effect])
if new_value && new_value != @variables[effect]
@variables[effect] = new_value
return true
end
elsif Input.trigger?(Input::ACTION) && @variables[effect]
pbPlayDecisionSE
@variables[effect] = nil
return true
end
return false
end
def update_input_for_item(effect, variable_data)
if Input.trigger?(Input::USE)
pbPlayDecisionSE
new_value = pbChooseItemList(@variables[effect])
if new_value && new_value != @variables[effect]
@variables[effect] = new_value
return true
end
elsif Input.trigger?(Input::ACTION) && @variables[effect]
pbPlayDecisionSE
@variables[effect] = nil
return true
end
return false
end
def update
loop do
Graphics.update
Input.update
@window.update
if Input.trigger?(Input::BACK)
pbPlayCancelSE
break
end
index = @window.index
effect = @variables_data.keys[index]
variable_data = @variables_data[effect]
if variable_data[:default] == false
@window.refresh if update_input_for_boolean(effect, variable_data)
elsif [0, 1, -2].include?(variable_data[:default])
@window.refresh if update_input_for_integer(effect, variable_data[:default], variable_data)
elsif variable_data[:default] == -1
@window.refresh if update_input_for_battler_index(effect, variable_data)
elsif variable_data[:default] == nil
case variable_data[:type]
when :move
@window.refresh if update_input_for_move(effect, variable_data)
when :item
@window.refresh if update_input_for_item(effect, variable_data)
else
raise "Unknown kind of variable!"
end
else
raise "Unknown kind of variable!"
end
end
end
end