#=============================================================================== # 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: -99_999, max: 99_999 }, 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 } } POSITION_EFFECTS = { # PBEffects::FutureSightCounter - too complex to be worth bothering with # PBEffects::FutureSightMove - too complex to be worth bothering with # PBEffects::FutureSightUserIndex - too complex to be worth bothering with # PBEffects::FutureSightUserPartyIndex - too complex to be worth bothering with PBEffects::HealingWish => { name: "Whether Healing Wish is waiting to apply", default: false }, PBEffects::LunarDance => { name: "Whether Lunar Dance is waiting to apply", default: false } # PBEffects::Wish - too complex to be worth bothering with # PBEffects::WishAmount - too complex to be worth bothering with # PBEffects::WishMaker - too complex to be worth bothering with } 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 case align when 1 # Right aligned x += w - width when 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 case variable_data[:default] when -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 when 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 :position @variables_data = Battle::DebugVariables::POSITION_EFFECTS @variables = @battle.positions[@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